Beispiel #1
0
/*
 * 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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
}
Beispiel #4
0
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;
}
Beispiel #5
0
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());
	}
}
Beispiel #6
0
/*
 * 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;
}
Beispiel #7
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
/*
 * 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;
}