VirtualBox

Changeset 1127 in kBuild


Ignore:
Timestamp:
Sep 26, 2007 10:16:47 PM (17 years ago)
Author:
bird
Message:

Use NtQueryInformationFile + FileNameInformation to figure out the correctly cased names.

Location:
trunk/src/kmk/w32
Files:
2 added
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/w32/pathstuff.c

    r911 r1127  
    8282}
    8383
     84#if 1 /* bird */
    8485/*
    8586 * Corrects the case of a path.
     
    257258}
    258259
     260#define MY_FileNameInformation 9
     261
     262typedef struct _MY_FILE_NAME_INFORMATION
     263{
     264    ULONG FileNameLength;
     265    WCHAR FileName[1];
     266} MY_FILE_NAME_INFORMATION, *PMY_FILE_NAME_INFORMATION;
     267
     268typedef struct _IO_STATUS_BLOCK
     269{
     270    union
     271    {
     272        LONG Status;
     273        PVOID Pointer;
     274    };
     275    ULONG_PTR Information;
     276} MY_IO_STATUS_BLOCK, *PMY_IO_STATUS_BLOCK;
     277
     278static BOOL g_fInitialized = FALSE;
     279static LONG (NTAPI *g_pfnNtQueryInformationFile)(HANDLE FileHandle,
     280    PMY_IO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, 
     281    ULONG Length, ULONG FileInformationClass);
     282
     283
     284int
     285nt_get_filename_info(const char *pszPath, char *pszFull, size_t cchFull)
     286{
     287    static char                 abBuf[8192];
     288    PMY_FILE_NAME_INFORMATION   pFileNameInfo = (PMY_FILE_NAME_INFORMATION)abBuf;
     289    MY_IO_STATUS_BLOCK          Ios;
     290    LONG                        rcNt;
     291    HANDLE                      hFile;
     292
     293    /*
     294     * Check for NtQueryInformationFile the first time around.
     295     */
     296    if (!g_fInitialized)
     297    {
     298        g_fInitialized = TRUE;
     299        if (!getenv("KMK_DONT_USE_NT_QUERY_INFORMATION_FILE"))
     300            *(FARPROC *)&g_pfnNtQueryInformationFile =
     301                GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryInformationFile");
     302    }
     303    if (!g_pfnNtQueryInformationFile)
     304        return -1;
     305
     306    /*
     307     * Try open the path and query its file name information.
     308     */
     309    hFile = CreateFile(pszPath,
     310                       GENERIC_READ,
     311                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     312                       NULL,
     313                       OPEN_EXISTING,
     314                       FILE_FLAG_BACKUP_SEMANTICS,
     315                       NULL);
     316    if (hFile)
     317    {
     318        memset(&Ios, 0, sizeof(Ios));
     319        rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), MY_FileNameInformation);
     320        CloseHandle(hFile);
     321        if (rcNt >= 0)
     322        {
     323            /*
     324             * The FileNameInformation we get is relative to where the volume is mounted,
     325             * so we have to extract the driveletter prefix ourselves.
     326             *
     327             * FIXME: This will probably not work for volumes mounted in NTFS sub-directories.
     328             */
     329            int cchOut;
     330            int fUnc = 0;
     331            char *psz = pszFull;
     332            if (pszPath[0] == '\\' || pszPath[0] == '/')
     333            {
     334                /* unc or root of volume */
     335                if (    (pszPath[1] == '\\' || pszPath[1] == '/')
     336                    &&  (pszPath[2] != '\\' || pszPath[2] == '/'))
     337                {
     338                    /* unc - we get the server + name back */
     339                    *psz++ = '\\';
     340                    fUnc = 1;
     341                }
     342                else
     343                {
     344                    /* root slash */
     345                    *psz++ = _getdrive() + 'A' - 1;
     346                    *psz++ = ':';
     347                }
     348            }
     349            else if (pszPath[1] == ':' && isalpha(pszPath[0]))
     350            {
     351                /* drive letter */
     352                *psz++ = toupper(pszPath[0]);
     353                *psz++ = ':';
     354            }
     355            else
     356            {
     357                /* relative */
     358                *psz++ = _getdrive() + 'A' - 1;
     359                *psz++ = ':';
     360            }
     361
     362            cchOut = WideCharToMultiByte(CP_ACP, 0,
     363                                         pFileNameInfo->FileName, pFileNameInfo->FileNameLength / sizeof(WCHAR),
     364                                         psz, cchFull - (psz - pszFull) - 2, NULL, NULL);
     365            if (cchOut > 0)
     366            {
     367                const char *pszEnd;
     368
     369                /* upper case the server and share */
     370                if (fUnc)
     371                {
     372                    for (psz++; *psz != '/' && *psz != '\\'; psz++)
     373                        *psz = toupper(*psz);
     374                    for (psz++; *psz != '/' && *psz != '\\'; psz++)
     375                        *psz = toupper(*psz);
     376                }
     377
     378                /* add trailing slash on directories if input has it. */
     379                pszEnd = strchr(pszPath, '\0');
     380                if (    (pszEnd[-1] == '/' || pszEnd[-1] == '\\')
     381                    &&  psz[cchOut - 1] != '\\'
     382                    &&  psz[cchOut - 1] != '//')
     383                    psz[cchOut++] = '\\';
     384
     385                /* make sure it's terminated */
     386                psz[cchOut] = '\0';
     387                return 0;
     388            }
     389            return -3;
     390        }
     391    }
     392    return -2;
     393}
     394
     395void
     396nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull)
     397{
     398#if 0
     399    static int s_cHits = 0;
     400    static int s_cFallbacks = 0;
     401#endif
     402
     403    /*
     404     * The simple case, the file / dir / whatever exists and can be
     405     * queried without problems.
     406     */
     407    if (nt_get_filename_info(pszPath, pszFull, cchFull) == 0)
     408    {
     409#if 0
     410        fprintf(stderr, "nt #%d - %s\n", ++s_cHits, pszFull);
     411#endif
     412        return;
     413    }
     414    if (g_pfnNtQueryInformationFile)
     415    {
     416        /* do _fullpath and drop off path elements until we get a hit... - later */
     417    }
     418   
     419    /*
     420     * For now, simply fall back on the old method.
     421     */
     422    _fullpath(pszFull, pszPath, cchFull);
     423    w32_fixcase(pszFull);
     424#if 0
     425    fprintf(stderr, "fb #%d - %s\n", ++s_cFallbacks, pszFull);
     426#endif
     427}
     428
     429#endif /* bird */
     430
     431
    259432/*
    260433 * Convert to forward slashes. Resolve to full pathname optionally
     
    267440
    268441    if (resolve) {
     442#if 1 /* bird */
     443# if 1
     444        nt_fullpath(filename, w32_path, sizeof(w32_path));
     445# else
     446        _fullpath(w32_path, filename, sizeof(w32_path));
     447        w32_fixcase(w32_path);
     448# endif
     449#else   /* !bird */
    269450        _fullpath(w32_path, filename, sizeof (w32_path));
    270         w32_fixcase(w32_path); /* bird */
     451#endif  /* !bird */
    271452    } else
    272453        strncpy(w32_path, filename, sizeof (w32_path));
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette