/* * Create an fsentry-based directory listing (similar to opendir / readdir). * Dir should not contain trailing '/'. Use an empty string for the current * directory (not "."!). */ static struct fsentry *fsentry_create_list(const struct fsentry *dir) { wchar_t pattern[MAX_LONG_PATH + 2]; /* + 2 for "\*" */ WIN32_FIND_DATAW fdata; HANDLE h; int wlen; struct fsentry *list, **phead; DWORD err; /* convert name to UTF-16 and check length */ if ((wlen = xutftowcs_path_ex(pattern, dir->name, MAX_LONG_PATH, dir->len, MAX_PATH - 2, core_long_paths)) < 0) return NULL; /* * append optional '\' and wildcard '*'. Note: we need to use '\' as * Windows doesn't translate '/' to '\' for "\\?\"-prefixed paths. */ if (wlen) pattern[wlen++] = '\\'; pattern[wlen++] = '*'; pattern[wlen] = 0; /* open find handle */ h = FindFirstFileW(pattern, &fdata); if (h == INVALID_HANDLE_VALUE) { err = GetLastError(); errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); return NULL; } /* allocate object to hold directory listing */ list = fsentry_alloc(NULL, dir->name, dir->len); /* walk directory and build linked list of fsentry structures */ phead = &list->next; do { *phead = fseentry_create_entry(list, &fdata); phead = &(*phead)->next; } while (FindNextFileW(h, &fdata)); /* remember result of last FindNextFile, then close find handle */ err = GetLastError(); FindClose(h); /* return the list if we've got all the files */ if (err == ERROR_NO_MORE_FILES) return list; /* otherwise free the list and return error */ fsentry_release(list); errno = err_win_to_posix(err); return NULL; }
/* * Create an fsentry-based directory listing (similar to opendir / readdir). * Dir should not contain trailing '/'. Use an empty string for the current * directory (not "."!). */ static struct fsentry *fsentry_create_list(struct fscache *cache, const struct fsentry *dir, int *dir_not_found) { wchar_t pattern[MAX_LONG_PATH]; NTSTATUS status; IO_STATUS_BLOCK iosb; PFILE_FULL_DIR_INFORMATION di; HANDLE h; int wlen; struct fsentry *list, **phead; DWORD err; *dir_not_found = 0; /* convert name to UTF-16 and check length */ if ((wlen = xutftowcs_path_ex(pattern, dir->name, MAX_LONG_PATH, dir->len, MAX_PATH - 2, core_long_paths)) < 0) return NULL; /* handle CWD */ if (!wlen) { wlen = GetCurrentDirectoryW(ARRAY_SIZE(pattern), pattern); if (!wlen || wlen >= ARRAY_SIZE(pattern)) { errno = wlen ? ENAMETOOLONG : err_win_to_posix(GetLastError()); return NULL; } } h = CreateFileW(pattern, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (h == INVALID_HANDLE_VALUE) { err = GetLastError(); *dir_not_found = 1; /* or empty directory */ errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); trace_printf_key(&trace_fscache, "fscache: error(%d) '%.*s'\n", errno, dir->len, dir->name); return NULL; } /* allocate object to hold directory listing */ list = fsentry_alloc(cache, NULL, dir->name, dir->len); list->st_mode = S_IFDIR; /* walk directory and build linked list of fsentry structures */ phead = &list->next; status = NtQueryDirectoryFile(h, NULL, 0, 0, &iosb, cache->buffer, sizeof(cache->buffer), FileFullDirectoryInformation, FALSE, NULL, FALSE); if (!NT_SUCCESS(status)) { /* * NtQueryDirectoryFile returns STATUS_INVALID_PARAMETER when * asked to enumerate an invalid directory (ie it is a file * instead of a directory). Verify that is the actual cause * of the error. */ if (status == STATUS_INVALID_PARAMETER) { DWORD attributes = GetFileAttributesW(pattern); if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) status = ERROR_DIRECTORY; } goto Error; } di = (PFILE_FULL_DIR_INFORMATION)(cache->buffer); for (;;) { *phead = fseentry_create_entry(cache, list, di); phead = &(*phead)->next; /* If there is no offset in the entry, the buffer has been exhausted. */ if (di->NextEntryOffset == 0) { status = NtQueryDirectoryFile(h, NULL, 0, 0, &iosb, cache->buffer, sizeof(cache->buffer), FileFullDirectoryInformation, FALSE, NULL, FALSE); if (!NT_SUCCESS(status)) { if (status == STATUS_NO_MORE_FILES) break; goto Error; } di = (PFILE_FULL_DIR_INFORMATION)(cache->buffer); continue; } /* Advance to the next entry. */ di = (PFILE_FULL_DIR_INFORMATION)(((PUCHAR)di) + di->NextEntryOffset); } CloseHandle(h); return list; Error: errno = (status == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(status); trace_printf_key(&trace_fscache, "fscache: error(%d) unable to query directory contents '%.*s'\n", errno, dir->len, dir->name); CloseHandle(h); fsentry_release(list); return NULL; }