Esempio n. 1
0
int
nt_get_filename_info(const char *pszPath, char *pszFull, size_t cchFull)
{
    static char                     abBuf[8192];
    PMY_FILE_NAME_INFORMATION       pFileNameInfo = (PMY_FILE_NAME_INFORMATION)abBuf;
    PMY_FILE_FS_VOLUME_INFORMATION  pFsVolInfo = (PMY_FILE_FS_VOLUME_INFORMATION)abBuf;
    MY_IO_STATUS_BLOCK              Ios;
    LONG                            rcNt;
    HANDLE                      hFile;
    int                             cchOut;
    char                           *psz;
    int                             iDrv;
    int                             rc;

    /*
     * Check for NtQueryInformationFile the first time around.
     */
    if (!g_fInitialized)
    {
        g_fInitialized = TRUE;
        if (!getenv("KMK_DONT_USE_NT_QUERY_INFORMATION_FILE"))
        {
            *(FARPROC *)&g_pfnNtQueryInformationFile =
                GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryInformationFile");
            *(FARPROC *)&g_pfnNtQueryVolumeInformationFile =
                GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryVolumeInformationFile");
        }
        if (    g_pfnNtQueryInformationFile
            &&  g_pfnNtQueryVolumeInformationFile)
        {
            unsigned i;
            for (i = 0; i < sizeof(g_afNtfsDrives) / sizeof(g_afNtfsDrives[0]); i++ )
                g_afNtfsDrives[i] = -1;
        }
        else
        {
            g_pfnNtQueryVolumeInformationFile = NULL;
            g_pfnNtQueryInformationFile = NULL;
        }
    }
    if (!g_pfnNtQueryInformationFile)
        return -1;

    /*
     * The FileNameInformation we get is relative to where the volume is mounted,
     * so we have to extract the driveletter prefix ourselves.
     *
     * FIXME: This will probably not work for volumes mounted in NTFS sub-directories.
     */
    psz = pszFull;
    if (pszPath[0] == '\\' || pszPath[0] == '/')
    {
        /* unc or root of volume */
        if (    (pszPath[1] == '\\' || pszPath[1] == '/')
            &&  (pszPath[2] != '\\' || pszPath[2] == '/'))
        {
#if 0 /* don't bother with unc yet. */
            /* unc - we get the server + name back */
            *psz++ = '\\';
#endif
            return -1;
        }
        /* root slash */
        *psz++ = _getdrive() + 'A' - 1;
        *psz++ = ':';
    }
    else if (pszPath[1] == ':' && isalpha(pszPath[0]))
    {
        /* drive letter */
        *psz++ = toupper(pszPath[0]);
        *psz++ = ':';
    }
    else
    {
        /* relative */
        *psz++ = _getdrive() + 'A' - 1;
        *psz++ = ':';
    }
    iDrv = *pszFull - 'A';

    /*
     * Fat32 doesn't return filenames with the correct case, so restrict it
     * to NTFS volumes for now.
     */
    if (g_afNtfsDrives[iDrv] == -1)
    {
        /* FSCTL_GET_REPARSE_POINT? Enumerate mount points? */
        g_afNtfsDrives[iDrv] = 0;
        psz[0] = '\\';
        psz[1] = '\0';
#if 1
        hFile = CreateFile(pszFull,
                           GENERIC_READ,
                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                           NULL,
                           OPEN_EXISTING,
                           FILE_FLAG_BACKUP_SEMANTICS,
                           NULL);
        if (hFile != INVALID_HANDLE_VALUE)
        {
            PMY_FILE_FS_ATTRIBUTE_INFORMATION pFsAttrInfo = (PMY_FILE_FS_ATTRIBUTE_INFORMATION)abBuf;

            memset(&Ios, 0, sizeof(Ios));
            rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, abBuf, sizeof(abBuf),
                                                     MY_FileFsAttributeInformation);
            if (    rcNt >= 0
                //&&  pFsAttrInfo->FileSystemNameLength == 4
                &&  pFsAttrInfo->FileSystemName[0] == 'N'
                &&  pFsAttrInfo->FileSystemName[1] == 'T'
                &&  pFsAttrInfo->FileSystemName[2] == 'F'
                &&  pFsAttrInfo->FileSystemName[3] == 'S'
                &&  pFsAttrInfo->FileSystemName[4] == '\0')
            {
                memset(&Ios, 0, sizeof(Ios));
                rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, &g_aVolumeInfo[iDrv],
                                                         sizeof(MY_FILE_FS_VOLUME_INFORMATION),
                                                         MY_FileFsVolumeInformation);
                if (rcNt >= 0)
                {
                    DWORD dwDriveType = GetDriveType(pszFull);
                    if (    dwDriveType == DRIVE_FIXED
                        ||  dwDriveType == DRIVE_RAMDISK)
                        g_afNtfsDrives[iDrv] = 1;
                }
            }
            CloseHandle(hFile);
        }
#else
        {
            char szFSName[32];
            if (    GetVolumeInformation(pszFull,
                                         NULL, 0,   /* volume name */
                                         NULL,      /* serial number */
                                         NULL,      /* max component */
                                         NULL,      /* volume attribs */
                                         szFSName,
                                         sizeof(szFSName))
                &&  !strcmp(szFSName, "NTFS"))
            {
                g_afNtfsDrives[iDrv] = 1;
            }
        }
#endif
    }
    if (!g_afNtfsDrives[iDrv])
        return -1;

    /*
     * Try open the path and query its file name information.
     */
    hFile = CreateFile(pszPath,
                       GENERIC_READ,
                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                       NULL,
                       OPEN_EXISTING,
                       FILE_FLAG_BACKUP_SEMANTICS,
                       NULL);
    if (hFile != INVALID_HANDLE_VALUE)
    {
        /* check that the driver letter is correct first (reparse / symlink issues). */
        memset(&Ios, 0, sizeof(Ios));
        rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pFsVolInfo, sizeof(*pFsVolInfo), MY_FileFsVolumeInformation);
        if (rcNt >= 0)
        {
            /** @todo do a quick search and try correct the drive letter? */
            if (    pFsVolInfo->VolumeCreationTime.QuadPart == g_aVolumeInfo[iDrv].VolumeCreationTime.QuadPart
                &&  pFsVolInfo->VolumeSerialNumber == g_aVolumeInfo[iDrv].VolumeSerialNumber)
            {
                memset(&Ios, 0, sizeof(Ios));
                rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), MY_FileNameInformation);
                if (rcNt >= 0)
                {
                    cchOut = WideCharToMultiByte(CP_ACP, 0,
                                                 pFileNameInfo->FileName, pFileNameInfo->FileNameLength / sizeof(WCHAR),
                                                 psz, (int)(cchFull - (psz - pszFull) - 2), NULL, NULL);
                    if (cchOut > 0)
                    {
                        const char *pszEnd;
#if 0
                        /* upper case the server and share */
                        if (fUnc)
                        {
                            for (psz++; *psz != '/' && *psz != '\\'; psz++)
                                *psz = toupper(*psz);
                            for (psz++; *psz != '/' && *psz != '\\'; psz++)
                                *psz = toupper(*psz);
                        }
#endif
                        /* add trailing slash on directories if input has it. */
                        pszEnd = strchr(pszPath, '\0');
                        if (    (pszEnd[-1] == '/' || pszEnd[-1] == '\\')
                            &&  psz[cchOut - 1] != '\\'
                            &&  psz[cchOut - 1] != '//')
                            psz[cchOut++] = '\\';

                        /* make sure it's terminated */
                        psz[cchOut] = '\0';
                        rc = 0;
                    }
                    else
                        rc = -3;
                }
                else
                    rc = -4;
            }
            else
                rc = -5;
        }
        else
            rc = -6;
        CloseHandle(hFile);
    }
    else
        rc = -7;
    return rc;
}
Esempio n. 2
0
static int birdDirReadMore(BirdDir_T *pDir)
{
    MY_NTSTATUS         rcNt;
    MY_IO_STATUS_BLOCK  Ios;
    int                 fFirst;

    /*
     * Retrieve the volume serial number + creation time and create the
     * device number the first time around.  Also allocate a buffer.
     */
    fFirst = pDir->fFirst;
    if (fFirst)
    {
        union
        {
            MY_FILE_FS_VOLUME_INFORMATION VolInfo;
            unsigned char abBuf[1024];
        } uBuf;

        Ios.Information = 0;
        Ios.u.Status    = -1;
        rcNt = g_pfnNtQueryVolumeInformationFile((HANDLE)pDir->pvHandle, &Ios, &uBuf, sizeof(uBuf), MyFileFsVolumeInformation);
        if (MY_NT_SUCCESS(rcNt))
            rcNt = Ios.u.Status;
        if (MY_NT_SUCCESS(rcNt))
            pDir->uDev = uBuf.VolInfo.VolumeSerialNumber
                       | (uBuf.VolInfo.VolumeCreationTime.QuadPart << 32);
        else
            pDir->uDev = 0;

        /*
         * Allocate a buffer.
         */
        pDir->cbBuf = 0x20000;
        pDir->pabBuf = birdMemAlloc(pDir->cbBuf);
        if (!pDir->pabBuf)
            return birdSetErrnoToNoMem();

        pDir->fFirst = 0;
    }

    /*
     * Read another buffer full.
     */
    Ios.Information = 0;
    Ios.u.Status    = -1;

    rcNt = g_pfnNtQueryDirectoryFile((HANDLE)pDir->pvHandle,
                                     NULL,      /* hEvent */
                                     NULL,      /* pfnApcComplete */
                                     NULL,      /* pvApcCompleteCtx */
                                     &Ios,
                                     pDir->pabBuf,
                                     pDir->cbBuf,
                                     (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass,
                                     FALSE,     /* fReturnSingleEntry */
                                     NULL,      /* Filter / restart pos. */
                                     FALSE);    /* fRestartScan */
    if (!MY_NT_SUCCESS(rcNt))
    {
        int rc;
        if (rcNt == MY_STATUS_NO_MORE_FILES)
            rc = 0;
        else
            rc = birdSetErrnoFromNt(rcNt);
        pDir->fHaveData = 0;
        pDir->offBuf    = pDir->cbBuf;
        return rc;
    }

    pDir->offBuf    = 0;
    pDir->fHaveData = 1;

    return 0;
}