fs: introduce uv_readdir_next() and report types
Introduce:
int uv_fs_readdir_next(uv_fs_t* req, uv_dirent_t* ent);
`uv_fs_readdir()` is not returning a file names list in `req->ptr`
anymore, the proper way to gather them is to call `uv_fs_readdir_next()`
in a callback.
This commit is contained in:
parent
7bdcf3dc7e
commit
ab2c4425a5
@ -25,6 +25,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
@ -155,6 +156,10 @@ typedef pthread_barrier_t uv_barrier_t;
|
||||
typedef gid_t uv_gid_t;
|
||||
typedef uid_t uv_uid_t;
|
||||
|
||||
typedef struct dirent uv__dirent_t;
|
||||
|
||||
#define UV__DT_DIR DT_DIR
|
||||
|
||||
/* Platform-specific definitions for uv_dlopen support. */
|
||||
#define UV_DYNAMIC /* empty */
|
||||
|
||||
|
||||
@ -289,6 +289,14 @@ typedef struct uv_once_s {
|
||||
typedef unsigned char uv_uid_t;
|
||||
typedef unsigned char uv_gid_t;
|
||||
|
||||
typedef struct uv__dirent_s {
|
||||
int d_type;
|
||||
char d_name[1];
|
||||
} uv__dirent_t;
|
||||
|
||||
#define UV__DT_DIR UV_DIRENT_DIR
|
||||
#define UV__DT_FILE UV_DIRENT_FILE
|
||||
|
||||
/* Platform-specific definitions for uv_dlopen support. */
|
||||
#define UV_DYNAMIC FAR WINAPI
|
||||
typedef struct {
|
||||
|
||||
20
include/uv.h
20
include/uv.h
@ -227,6 +227,7 @@ typedef struct uv_work_s uv_work_t;
|
||||
/* None of the above. */
|
||||
typedef struct uv_cpu_info_s uv_cpu_info_t;
|
||||
typedef struct uv_interface_address_s uv_interface_address_t;
|
||||
typedef struct uv_dirent_s uv_dirent_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
@ -1786,6 +1787,16 @@ struct uv_interface_address_s {
|
||||
} netmask;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_DIRENT_FILE,
|
||||
UV_DIRENT_DIR
|
||||
} uv_dirent_type_t;
|
||||
|
||||
struct uv_dirent_s {
|
||||
const char* name;
|
||||
uv_dirent_type_t type;
|
||||
};
|
||||
|
||||
UV_EXTERN char** uv_setup_args(int argc, char** argv);
|
||||
UV_EXTERN int uv_get_process_title(char* buffer, size_t size);
|
||||
UV_EXTERN int uv_set_process_title(const char* title);
|
||||
@ -1931,6 +1942,15 @@ UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
UV_EXTERN int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req,
|
||||
const char* path, int flags, uv_fs_cb cb);
|
||||
|
||||
/*
|
||||
* Call this after `uv_fs_readdir` cb's invocation, this function should be
|
||||
* called until it returns `UV_EOF`.
|
||||
*
|
||||
* The data that is put into `ent` is managed by libuv and should not be
|
||||
* deallocated by the user.
|
||||
*/
|
||||
UV_EXTERN int uv_fs_readdir_next(uv_fs_t* req, uv_dirent_t* ent);
|
||||
|
||||
UV_EXTERN int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
uv_fs_cb cb);
|
||||
|
||||
|
||||
@ -38,7 +38,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <utime.h>
|
||||
@ -296,9 +295,9 @@ done:
|
||||
|
||||
|
||||
#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8))
|
||||
static int uv__fs_readdir_filter(struct dirent* dent) {
|
||||
static int uv__fs_readdir_filter(uv__dirent_t* dent) {
|
||||
#else
|
||||
static int uv__fs_readdir_filter(const struct dirent* dent) {
|
||||
static int uv__fs_readdir_filter(const uv__dirent_t* dent) {
|
||||
#endif
|
||||
return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
|
||||
}
|
||||
@ -306,12 +305,8 @@ static int uv__fs_readdir_filter(const struct dirent* dent) {
|
||||
|
||||
/* This should have been called uv__fs_scandir(). */
|
||||
static ssize_t uv__fs_readdir(uv_fs_t* req) {
|
||||
struct dirent **dents;
|
||||
uv__dirent_t **dents;
|
||||
int saved_errno;
|
||||
size_t off;
|
||||
size_t len;
|
||||
char *buf;
|
||||
int i;
|
||||
int n;
|
||||
|
||||
dents = NULL;
|
||||
@ -322,32 +317,17 @@ static ssize_t uv__fs_readdir(uv_fs_t* req) {
|
||||
else if (n == -1)
|
||||
return n;
|
||||
|
||||
len = 0;
|
||||
/* NOTE: We will use nbufs as an index field */
|
||||
req->ptr = dents;
|
||||
req->nbufs = 0;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
len += strlen(dents[i]->d_name) + 1;
|
||||
|
||||
buf = malloc(len);
|
||||
|
||||
if (buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
n = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
off = 0;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
len = strlen(dents[i]->d_name) + 1;
|
||||
memcpy(buf + off, dents[i]->d_name, len);
|
||||
off += len;
|
||||
}
|
||||
|
||||
req->ptr = buf;
|
||||
return n;
|
||||
|
||||
out:
|
||||
saved_errno = errno;
|
||||
if (dents != NULL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
free(dents[i]);
|
||||
free(dents);
|
||||
@ -1184,6 +1164,9 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
req->path = NULL;
|
||||
req->new_path = NULL;
|
||||
|
||||
if (req->fs_type == UV_FS_READDIR && req->ptr != NULL)
|
||||
uv__fs_readdir_cleanup(req);
|
||||
|
||||
if (req->ptr != &req->statbuf)
|
||||
free(req->ptr);
|
||||
req->ptr = NULL;
|
||||
|
||||
@ -449,3 +449,43 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_readdir_cleanup(uv_fs_t* req) {
|
||||
uv__dirent_t** dents;
|
||||
|
||||
dents = req->ptr;
|
||||
if (req->nbufs > 0 && req->nbufs != (unsigned int) req->result)
|
||||
req->nbufs--;
|
||||
for (; req->nbufs < (unsigned int) req->result; req->nbufs++)
|
||||
free(dents[req->nbufs]);
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_readdir_next(uv_fs_t* req, uv_dirent_t* ent) {
|
||||
uv__dirent_t** dents;
|
||||
uv__dirent_t* dent;
|
||||
|
||||
dents = req->ptr;
|
||||
|
||||
/* Free previous entity */
|
||||
if (req->nbufs > 0)
|
||||
free(dents[req->nbufs - 1]);
|
||||
|
||||
/* End was already reached */
|
||||
if (req->nbufs == (unsigned int) req->result) {
|
||||
free(dents);
|
||||
req->ptr = NULL;
|
||||
return UV_EOF;
|
||||
}
|
||||
|
||||
dent = dents[req->nbufs++];
|
||||
|
||||
ent->name = dent->d_name;
|
||||
if (dent->d_type == UV__DT_DIR)
|
||||
ent->type = UV_DIRENT_DIR;
|
||||
else
|
||||
ent->type = UV_DIRENT_FILE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -109,6 +109,8 @@ size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
|
||||
|
||||
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
|
||||
|
||||
void uv__fs_readdir_cleanup(uv_fs_t* req);
|
||||
|
||||
#define uv__has_active_reqs(loop) \
|
||||
(QUEUE_EMPTY(&(loop)->active_reqs) == 0)
|
||||
|
||||
|
||||
120
src/win/fs.c
120
src/win/fs.c
@ -43,6 +43,8 @@
|
||||
#define UV_FS_FREE_PTR 0x0008
|
||||
#define UV_FS_CLEANEDUP 0x0010
|
||||
|
||||
static const int uv__fs_dirent_slide = 0x20;
|
||||
|
||||
|
||||
#define QUEUE_FS_TP_JOB(loop, req) \
|
||||
do { \
|
||||
@ -784,13 +786,14 @@ void fs__mkdtemp(uv_fs_t* req) {
|
||||
void fs__readdir(uv_fs_t* req) {
|
||||
WCHAR* pathw = req->pathw;
|
||||
size_t len = wcslen(pathw);
|
||||
int result, size;
|
||||
WCHAR* buf = NULL, *ptr, *name;
|
||||
int result;
|
||||
WCHAR* name;
|
||||
HANDLE dir;
|
||||
WIN32_FIND_DATAW ent = { 0 };
|
||||
size_t buf_char_len = 4096;
|
||||
WCHAR* path2;
|
||||
const WCHAR* fmt;
|
||||
uv__dirent_t** dents;
|
||||
int dent_size;
|
||||
|
||||
if (len == 0) {
|
||||
fmt = L"./*";
|
||||
@ -809,7 +812,8 @@ void fs__readdir(uv_fs_t* req) {
|
||||
|
||||
path2 = (WCHAR*)malloc(sizeof(WCHAR) * (len + 4));
|
||||
if (!path2) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
_snwprintf(path2, len + 3, fmt, pathw);
|
||||
@ -822,71 +826,79 @@ void fs__readdir(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
result = 0;
|
||||
dents = NULL;
|
||||
dent_size = 0;
|
||||
|
||||
do {
|
||||
uv__dirent_t* dent;
|
||||
int utf8_len;
|
||||
|
||||
name = ent.cFileName;
|
||||
|
||||
if (name[0] != L'.' || (name[1] && (name[1] != L'.' || name[2]))) {
|
||||
len = wcslen(name);
|
||||
if (!(name[0] != L'.' || (name[1] && (name[1] != L'.' || name[2]))))
|
||||
continue;
|
||||
|
||||
if (!buf) {
|
||||
buf = (WCHAR*)malloc(buf_char_len * sizeof(WCHAR));
|
||||
if (!buf) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
||||
}
|
||||
/* Grow dents buffer, if needed */
|
||||
if (result >= dent_size) {
|
||||
uv__dirent_t** tmp;
|
||||
|
||||
ptr = buf;
|
||||
dent_size += uv__fs_dirent_slide;
|
||||
tmp = realloc(dents, dent_size * sizeof(*dents));
|
||||
if (tmp == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
goto fatal;
|
||||
}
|
||||
|
||||
while ((ptr - buf) + len + 1 > buf_char_len) {
|
||||
buf_char_len *= 2;
|
||||
path2 = buf;
|
||||
buf = (WCHAR*)realloc(buf, buf_char_len * sizeof(WCHAR));
|
||||
if (!buf) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "realloc");
|
||||
}
|
||||
|
||||
ptr = buf + (ptr - path2);
|
||||
}
|
||||
|
||||
wcscpy(ptr, name);
|
||||
ptr += len + 1;
|
||||
result++;
|
||||
dents = tmp;
|
||||
}
|
||||
|
||||
/* Allocate enough space to fit utf8 encoding of file name */
|
||||
len = wcslen(name);
|
||||
utf8_len = uv_utf16_to_utf8(name, len, NULL, 0);
|
||||
if (!utf8_len) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
goto fatal;
|
||||
}
|
||||
|
||||
dent = malloc(sizeof(*dent) + utf8_len + 1);
|
||||
if (dent == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
goto fatal;
|
||||
}
|
||||
|
||||
/* Copy file name */
|
||||
utf8_len = uv_utf16_to_utf8(name, len, dent->d_name, utf8_len);
|
||||
if (!utf8_len) {
|
||||
free(dent);
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
goto fatal;
|
||||
}
|
||||
dent->d_name[utf8_len] = '\0';
|
||||
|
||||
/* Copy file type */
|
||||
if ((ent.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
dent->d_type = UV__DT_DIR;
|
||||
else
|
||||
dent->d_type = UV__DT_FILE;
|
||||
|
||||
dents[result++] = dent;
|
||||
} while(FindNextFileW(dir, &ent));
|
||||
|
||||
FindClose(dir);
|
||||
|
||||
if (buf) {
|
||||
/* Convert result to UTF8. */
|
||||
size = uv_utf16_to_utf8(buf, buf_char_len, NULL, 0);
|
||||
if (!size) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
req->ptr = (char*)malloc(size + 1);
|
||||
if (!req->ptr) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
||||
}
|
||||
|
||||
size = uv_utf16_to_utf8(buf, buf_char_len, (char*)req->ptr, size);
|
||||
if (!size) {
|
||||
free(buf);
|
||||
free(req->ptr);
|
||||
req->ptr = NULL;
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
((char*)req->ptr)[size] = '\0';
|
||||
if (dents != NULL)
|
||||
req->flags |= UV_FS_FREE_PTR;
|
||||
} else {
|
||||
req->ptr = NULL;
|
||||
}
|
||||
|
||||
/* NOTE: nbufs will be used as index */
|
||||
req->nbufs = 0;
|
||||
req->ptr = dents;
|
||||
SET_REQ_RESULT(req, result);
|
||||
return;
|
||||
|
||||
fatal:
|
||||
/* Deallocate dents */
|
||||
for (result--; result >= 0; result--)
|
||||
free(dents[result]);
|
||||
free(dents);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -417,12 +417,16 @@ static void rmdir_cb(uv_fs_t* req) {
|
||||
|
||||
|
||||
static void readdir_cb(uv_fs_t* req) {
|
||||
uv_dirent_t dent;
|
||||
ASSERT(req == &readdir_req);
|
||||
ASSERT(req->fs_type == UV_FS_READDIR);
|
||||
ASSERT(req->result == 2);
|
||||
ASSERT(req->ptr);
|
||||
ASSERT(memcmp(req->ptr, "file1\0file2\0", 12) == 0
|
||||
|| memcmp(req->ptr, "file2\0file1\0", 12) == 0);
|
||||
|
||||
while (UV_EOF != uv_fs_readdir_next(req, &dent)) {
|
||||
ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
|
||||
ASSERT(dent.type == UV_DIRENT_FILE);
|
||||
}
|
||||
readdir_cb_count++;
|
||||
ASSERT(req->path);
|
||||
ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
|
||||
@ -802,6 +806,7 @@ TEST_IMPL(fs_file_write_null_buffer) {
|
||||
|
||||
TEST_IMPL(fs_async_dir) {
|
||||
int r;
|
||||
uv_dirent_t dent;
|
||||
|
||||
/* Setup */
|
||||
unlink("test_dir/file1");
|
||||
@ -844,8 +849,10 @@ TEST_IMPL(fs_async_dir) {
|
||||
ASSERT(r == 2);
|
||||
ASSERT(readdir_req.result == 2);
|
||||
ASSERT(readdir_req.ptr);
|
||||
ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0
|
||||
|| memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0);
|
||||
while (UV_EOF != uv_fs_readdir_next(&readdir_req, &dent)) {
|
||||
ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
|
||||
ASSERT(dent.type == UV_DIRENT_FILE);
|
||||
}
|
||||
uv_fs_req_cleanup(&readdir_req);
|
||||
ASSERT(!readdir_req.ptr);
|
||||
|
||||
@ -1521,6 +1528,7 @@ TEST_IMPL(fs_symlink_dir) {
|
||||
uv_fs_t req;
|
||||
int r;
|
||||
char* test_dir;
|
||||
uv_dirent_t dent;
|
||||
|
||||
/* set-up */
|
||||
unlink("test_dir/file1");
|
||||
@ -1597,8 +1605,10 @@ TEST_IMPL(fs_symlink_dir) {
|
||||
ASSERT(r == 2);
|
||||
ASSERT(readdir_req.result == 2);
|
||||
ASSERT(readdir_req.ptr);
|
||||
ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0
|
||||
|| memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0);
|
||||
while (UV_EOF != uv_fs_readdir_next(&readdir_req, &dent)) {
|
||||
ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
|
||||
ASSERT(dent.type == UV_DIRENT_FILE);
|
||||
}
|
||||
uv_fs_req_cleanup(&readdir_req);
|
||||
ASSERT(!readdir_req.ptr);
|
||||
|
||||
@ -1615,8 +1625,10 @@ TEST_IMPL(fs_symlink_dir) {
|
||||
ASSERT(r == 2);
|
||||
ASSERT(readdir_req.result == 2);
|
||||
ASSERT(readdir_req.ptr);
|
||||
ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0
|
||||
|| memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0);
|
||||
while (UV_EOF != uv_fs_readdir_next(&readdir_req, &dent)) {
|
||||
ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
|
||||
ASSERT(dent.type == UV_DIRENT_FILE);
|
||||
}
|
||||
uv_fs_req_cleanup(&readdir_req);
|
||||
ASSERT(!readdir_req.ptr);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user