unix fs_async_dir works

This commit is contained in:
Ryan Dahl 2011-08-29 22:08:51 -07:00
parent cf08c168ea
commit 0e81406bfb
3 changed files with 175 additions and 9 deletions

View File

@ -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

View File

@ -24,6 +24,9 @@
#include "eio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@ -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;
}

View File

@ -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();