/* * 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; }
static struct dirent *dirent_readdir(dirent_DIR *dir) { if (!dir) { errno = EBADF; /* No set_errno for mingw */ return NULL; } /* if first entry, dirent has already been set up by opendir */ if (dir->dd_stat) { /* get next entry and convert from WIN32_FIND_DATA to dirent */ WIN32_FIND_DATAW fdata; if (FindNextFileW(dir->dd_handle, &fdata)) { finddata2dirent(&dir->dd_dir, &fdata); } else { DWORD lasterr = GetLastError(); /* POSIX says you shouldn't set errno when readdir can't find any more files; so, if another error we leave it set. */ if (lasterr != ERROR_NO_MORE_FILES) errno = err_win_to_posix(lasterr); return NULL; } } ++dir->dd_stat; return &dir->dd_dir; }
static void die_lasterr(const char *fmt, ...) { va_list params; va_start(params, fmt); errno = err_win_to_posix(GetLastError()); die_errno(fmt, params); va_end(params); }
struct dirent *readdir(DIR *dir) { WIN32_FIND_DATAA buf; HANDLE handle; if (!dir || !dir->dd_handle) { errno = EBADF; /* No set_errno for mingw */ return NULL; } if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) { DWORD lasterr; handle = FindFirstFileA(dir->dd_name, &buf); lasterr = GetLastError(); dir->dd_handle = handle; if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { errno = err_win_to_posix(lasterr); return NULL; } } else if (dir->dd_handle == INVALID_HANDLE_VALUE) { return NULL; } else if (!FindNextFileA(dir->dd_handle, &buf)) { DWORD lasterr = GetLastError(); FindClose(dir->dd_handle); dir->dd_handle = INVALID_HANDLE_VALUE; /* POSIX says you shouldn't set errno when readdir can't find any more files; so, if another error we leave it set. */ if (lasterr != ERROR_NO_MORE_FILES) errno = err_win_to_posix(lasterr); return NULL; } /* We get here if `buf' contains valid data. */ strcpy(dir->dd_dir.d_name, buf.cFileName); ++dir->dd_stat; /* Set file type, based on WIN32_FIND_DATA */ dir->dd_dir.d_type = 0; if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) dir->dd_dir.d_type |= DT_DIR; else dir->dd_dir.d_type |= DT_REG; return &dir->dd_dir; }
int win32_pthread_join(pthread_t *thread, void **value_ptr) { DWORD result = WaitForSingleObject(thread->handle, INFINITE); switch (result) { case WAIT_OBJECT_0: if (value_ptr) *value_ptr = thread->arg; return 0; case WAIT_ABANDONED: return EINVAL; default: return err_win_to_posix(GetLastError()); } }
/* * IMPORTANT: This implementation requires that pthread_cond_signal * is called while the mutex is held that is used in the corresponding * pthread_cond_wait calls! */ int pthread_cond_signal(pthread_cond_t *cond) { int have_waiters; EnterCriticalSection(&cond->waiters_lock); have_waiters = cond->waiters > 0; LeaveCriticalSection(&cond->waiters_lock); /* * Signal only when there are waiters */ if (have_waiters) return ReleaseSemaphore(cond->sema, 1, NULL) ? 0 : err_win_to_posix(GetLastError()); else return 0; }
DIR *dirent_opendir(const char *name) { wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */ WIN32_FIND_DATAW fdata; HANDLE h; int len; dirent_DIR *dir; /* convert name to UTF-16 and check length < MAX_PATH */ if ((len = xutftowcs_canonical_path(pattern, name)) < 0) return NULL; /* * append optional '\' and wildcard '*' * note: when using "\\?\" as a prefix for long paths, * we cannot expect Windows to remap '/' to '\' for us. */ if (len && !is_dir_sep(pattern[len - 1])) pattern[len++] = '\\'; pattern[len++] = '*'; pattern[len] = 0; /* open find handle */ h = FindFirstFileW(pattern, &fdata); if (h == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); return NULL; } /* initialize DIR structure and copy first dir entry */ dir = xmalloc(sizeof(dirent_DIR)); dir->base_dir.preaddir = (struct dirent *(*)(DIR *dir)) dirent_readdir; dir->base_dir.pclosedir = (int (*)(DIR *dir)) dirent_closedir; dir->dd_dir.d_name = dir->dd_name; dir->dd_handle = h; dir->dd_stat = 0; finddata2dirent(&dir->dd_dir, &fdata); return (DIR*) dir; }
DIR *dirent_opendir(const char *name) { wchar_t pattern[MAX_LONG_PATH + 2]; /* + 2 for "\*" */ WIN32_FIND_DATAW fdata; HANDLE h; int len; dirent_DIR *dir; /* convert name to UTF-16 and check length */ if ((len = xutftowcs_path_ex(pattern, name, MAX_LONG_PATH, -1, 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 (len && !is_dir_sep(pattern[len - 1])) pattern[len++] = '\\'; pattern[len++] = '*'; pattern[len] = 0; /* open find handle */ h = FindFirstFileW(pattern, &fdata); if (h == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err); return NULL; } /* initialize DIR structure and copy first dir entry */ dir = xmalloc(sizeof(dirent_DIR)); dir->base_dir.preaddir = (struct dirent *(*)(DIR *dir)) dirent_readdir; dir->base_dir.pclosedir = (int (*)(DIR *dir)) dirent_closedir; dir->dd_dir.d_name = dir->dd_name; dir->dd_handle = h; dir->dd_stat = 0; finddata2dirent(&dir->dd_dir, &fdata); return (DIR*) dir; }
/* * 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; }