diff --git a/include/uv-unix.h b/include/uv-unix.h index 9ceae197..6230b2a7 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -159,6 +159,7 @@ typedef int uv_file; ev_child child_watcher; #define UV_FS_PRIVATE_FIELDS \ + struct stat statbuf; \ eio_req* eio; #define UV_WORK_PRIVATE_FIELDS diff --git a/src/unix/fs.c b/src/unix/fs.c index b6d9732c..e245cb90 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -24,6 +24,9 @@ #include "eio.h" #include +#include +#include +#include #include #include #include @@ -46,16 +49,59 @@ static void uv_fs_req_init(uv_fs_t* req, uv_fs_type fs_type, uv_fs_cb cb) { void uv_fs_req_cleanup(uv_fs_t* req) { + switch (req->fs_type) { + case UV_FS_READDIR: + assert(req->ptr); + free(req->ptr); + req->ptr = NULL; + break; + + case UV_FS_STAT: + req->ptr = NULL; + break; + + default: + break; + } } static int uv__fs_after(eio_req* eio) { + char* name; + int namelen; + int buflen = 0; uv_fs_t* req = eio->data; + int i; + assert(req->cb); req->result = req->eio->result; req->errorno = req->eio->errorno; + if (req->fs_type == UV_FS_READDIR) { + /* + * XXX This is pretty bad. + * We alloc and copy the large null termiated string list from libeio. + * This is done because libeio is going to free eio->ptr2 after this + * callback. We must keep it until uv_fs_req_cleanup. If we get rid of + * libeio this can be avoided. + */ + buflen = 0; + name = req->eio->ptr2; + for (i = 0; i < req->result; i++) { + namelen = strlen(name); + buflen += namelen + 1; + /* TODO check ENOMEM */ + name += namelen; + assert(*name == '\0'); + name++; + } + req->ptr = malloc(buflen); + memcpy(req->ptr, req->eio->ptr2, buflen); + } else if (req->fs_type == UV_FS_STAT) { + req->ptr = req->eio->ptr2; + } + uv_unref(); req->eio = NULL; /* Freed by libeio */ @@ -202,26 +248,145 @@ int uv_fs_write(uv_fs_t* req, uv_file file, void* buf, size_t length, int uv_fs_mkdir(uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) { - assert(0 && "implement me"); - return -1; + uv_fs_req_init(req, UV_FS_MKDIR, cb); + + if (cb) { + /* async */ + uv_ref(); + req->eio = eio_mkdir(path, mode, EIO_PRI_DEFAULT, uv__fs_after, req); + if (!req->eio) { + uv_err_new(NULL, ENOMEM); + return -1; + } + + } else { + /* sync */ + req->result = mkdir(path, mode); + + if (req->result < 0) { + uv_err_new(NULL, errno); + return -1; + } + } + + return 0; } int uv_fs_rmdir(uv_fs_t* req, const char* path, uv_fs_cb cb) { - assert(0 && "implement me"); - return -1; + uv_fs_req_init(req, UV_FS_RMDIR, cb); + + if (cb) { + /* async */ + uv_ref(); + req->eio = eio_rmdir(path, EIO_PRI_DEFAULT, uv__fs_after, req); + if (!req->eio) { + uv_err_new(NULL, ENOMEM); + return -1; + } + + } else { + /* sync */ + req->result = rmdir(path); + + if (req->result < 0) { + uv_err_new(NULL, errno); + return -1; + } + } + + return 0; } int uv_fs_readdir(uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) { - assert(0 && "implement me"); - return -1; + int r; + struct dirent* entry; + size_t size = 0; + + uv_fs_req_init(req, UV_FS_READDIR, cb); + + if (cb) { + /* async */ + uv_ref(); + req->eio = eio_readdir(path, flags, EIO_PRI_DEFAULT, uv__fs_after, req); + if (!req->eio) { + uv_err_new(NULL, ENOMEM); + return -1; + } + + } else { + /* sync */ + DIR* dir = opendir(path); + if (!dir) { + uv_err_new(NULL, errno); + return -1; + } + + while ((entry = readdir(dir))) { + req->ptr = realloc(req->ptr, size + entry->d_namlen + 1); + /* TODO check ENOMEM */ + /* TODO skip . and .. */ + memcpy((char*)req->ptr + size, entry->d_name, entry->d_namlen); + size += entry->d_namlen; + ((char*)req->ptr)[size] = '\0'; + size++; + } + + r = closedir(dir); + if (r) { + uv_err_new(NULL, errno); + return -1; + } + } + + return 0; } int uv_fs_stat(uv_fs_t* req, const char* path, uv_fs_cb cb) { - assert(0 && "implement me"); - return -1; + char* pathdup = path; + int pathlen; + + uv_fs_req_init(req, UV_FS_STAT, cb); + + /* TODO do this without duplicating the string. */ + /* TODO security */ + pathdup = strdup(path); + pathlen = strlen(path); + + if (pathlen > 0 && path[pathlen - 1] == '\\') { + /* TODO do not modify input string */ + pathdup[pathlen - 1] = '\0'; + } + + if (cb) { + /* async */ + uv_ref(); + req->eio = eio_stat(pathdup, EIO_PRI_DEFAULT, uv__fs_after, req); + + free(pathdup); + + if (!req->eio) { + uv_err_new(NULL, ENOMEM); + return -1; + } + + } else { + /* sync */ + req->result = stat(pathdup, &req->statbuf); + + free(pathdup); + + if (req->result < 0) { + uv_err_new(NULL, errno); + return -1; + } + + req->ptr = &req->statbuf; + } + + return 0; } diff --git a/test/test-fs.c b/test/test-fs.c index d2aac69a..f6929581 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -398,7 +398,7 @@ TEST_IMPL(fs_async_dir) { uv_init(); - r = uv_fs_mkdir(&mkdir_req, "test_dir", 0, mkdir_cb); + r = uv_fs_mkdir(&mkdir_req, "test_dir", 0755, mkdir_cb); ASSERT(r == 0); uv_run();