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; }
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; }