win: add UV_FS_O_FILEMAP
Reading and writing files using a memory file mapping can be significantly faster on Windows. PR-URL: https://github.com/libuv/libuv/pull/2295 Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com>
This commit is contained in:
parent
dabc737d78
commit
2c279504f9
1
.gitignore
vendored
1
.gitignore
vendored
@ -51,6 +51,7 @@ Makefile.in
|
||||
/test/run-benchmarks
|
||||
/test/run-benchmarks.exe
|
||||
/test/run-benchmarks.dSYM
|
||||
test_file_*
|
||||
|
||||
*.sln
|
||||
*.sln.cache
|
||||
|
||||
@ -53,6 +53,8 @@ set(uv_test_sources
|
||||
test/test-fs-poll.c
|
||||
test/test-fs.c
|
||||
test/test-fs-readdir.c
|
||||
test/test-fs-fd-hash.c
|
||||
test/test-fs-open-flags.c
|
||||
test/test-get-currentexe.c
|
||||
test/test-get-loadavg.c
|
||||
test/test-get-memory.c
|
||||
|
||||
@ -184,6 +184,8 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-fs-poll.c \
|
||||
test/test-fs.c \
|
||||
test/test-fs-readdir.c \
|
||||
test/test-fs-fd-hash.c \
|
||||
test/test-fs-open-flags.c \
|
||||
test/test-fork.c \
|
||||
test/test-getters-setters.c \
|
||||
test/test-get-currentexe.c \
|
||||
|
||||
@ -534,6 +534,14 @@ File open constants
|
||||
|
||||
.. versionchanged:: 1.17.0 support is added for Windows.
|
||||
|
||||
.. c:macro:: UV_FS_O_FILEMAP
|
||||
|
||||
Use a memory file mapping to access the file. When using this flag, the
|
||||
file cannot be open multiple times concurrently.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_FILEMAP` is only supported on Windows.
|
||||
|
||||
.. c:macro:: UV_FS_O_NOATIME
|
||||
|
||||
Do not update the file access time when the file is read.
|
||||
|
||||
@ -481,6 +481,7 @@ typedef struct {
|
||||
#endif
|
||||
|
||||
/* fs open() flags supported on other platforms: */
|
||||
#define UV_FS_O_FILEMAP 0
|
||||
#define UV_FS_O_RANDOM 0
|
||||
#define UV_FS_O_SHORT_LIVED 0
|
||||
#define UV_FS_O_SEQUENTIAL 0
|
||||
|
||||
@ -668,6 +668,7 @@ typedef struct {
|
||||
#define UV_FS_O_APPEND _O_APPEND
|
||||
#define UV_FS_O_CREAT _O_CREAT
|
||||
#define UV_FS_O_EXCL _O_EXCL
|
||||
#define UV_FS_O_FILEMAP 0x20000000
|
||||
#define UV_FS_O_RANDOM _O_RANDOM
|
||||
#define UV_FS_O_RDONLY _O_RDONLY
|
||||
#define UV_FS_O_RDWR _O_RDWR
|
||||
|
||||
@ -204,6 +204,9 @@ static void uv_init(void) {
|
||||
/* Initialize winsock */
|
||||
uv_winsock_init();
|
||||
|
||||
/* Initialize FS */
|
||||
uv_fs_init();
|
||||
|
||||
/* Initialize signal stuff */
|
||||
uv_signals_init();
|
||||
|
||||
|
||||
178
src/win/fs-fd-hash-inl.h
Normal file
178
src/win/fs-fd-hash-inl.h
Normal file
@ -0,0 +1,178 @@
|
||||
#ifndef UV_WIN_FS_FD_HASH_INL_H_
|
||||
#define UV_WIN_FS_FD_HASH_INL_H_
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Files are only inserted in uv__fd_hash when the UV_FS_O_FILEMAP flag is
|
||||
* specified. Thus, when uv__fd_hash_get returns true, the file mapping in the
|
||||
* info structure should be used for read/write operations.
|
||||
*
|
||||
* If the file is empty, the mapping field will be set to
|
||||
* INVALID_HANDLE_VALUE. This is not an issue since the file mapping needs to
|
||||
* be created anyway when the file size changes.
|
||||
*
|
||||
* Since file descriptors are sequential integers, the modulo operator is used
|
||||
* as hashing function. For each bucket, a single linked list of arrays is
|
||||
* kept to minimize allocations. A statically allocated memory buffer is kept
|
||||
* for the first array in each bucket. */
|
||||
|
||||
|
||||
#define UV__FD_HASH_SIZE 256
|
||||
#define UV__FD_HASH_GROUP_SIZE 16
|
||||
|
||||
struct uv__fd_info_s {
|
||||
int flags;
|
||||
BOOLEAN is_directory;
|
||||
HANDLE mapping;
|
||||
LARGE_INTEGER size;
|
||||
LARGE_INTEGER current_pos;
|
||||
};
|
||||
|
||||
struct uv__fd_hash_entry_s {
|
||||
uv_file fd;
|
||||
struct uv__fd_info_s info;
|
||||
};
|
||||
|
||||
struct uv__fd_hash_entry_group_s {
|
||||
struct uv__fd_hash_entry_s entries[UV__FD_HASH_GROUP_SIZE];
|
||||
struct uv__fd_hash_entry_group_s* next;
|
||||
};
|
||||
|
||||
struct uv__fd_hash_bucket_s {
|
||||
size_t size;
|
||||
struct uv__fd_hash_entry_group_s* data;
|
||||
};
|
||||
|
||||
|
||||
static uv_mutex_t uv__fd_hash_mutex;
|
||||
|
||||
static struct uv__fd_hash_entry_group_s
|
||||
uv__fd_hash_entry_initial[UV__FD_HASH_SIZE * UV__FD_HASH_GROUP_SIZE];
|
||||
static struct uv__fd_hash_bucket_s uv__fd_hash[UV__FD_HASH_SIZE];
|
||||
|
||||
|
||||
INLINE static void uv__fd_hash_init(void) {
|
||||
int i, err;
|
||||
|
||||
err = uv_mutex_init(&uv__fd_hash_mutex);
|
||||
if (err) {
|
||||
uv_fatal_error(err, "uv_mutex_init");
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uv__fd_hash); ++i) {
|
||||
uv__fd_hash[i].size = 0;
|
||||
uv__fd_hash[i].data =
|
||||
uv__fd_hash_entry_initial + i * UV__FD_HASH_GROUP_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
#define FIND_COMMON_VARIABLES \
|
||||
unsigned i; \
|
||||
unsigned bucket = fd % ARRAY_SIZE(uv__fd_hash); \
|
||||
struct uv__fd_hash_entry_s* entry_ptr = NULL; \
|
||||
struct uv__fd_hash_entry_group_s* group_ptr; \
|
||||
struct uv__fd_hash_bucket_s* bucket_ptr = &uv__fd_hash[bucket];
|
||||
|
||||
#define FIND_IN_GROUP_PTR(group_size) \
|
||||
do { \
|
||||
for (i = 0; i < group_size; ++i) { \
|
||||
if (group_ptr->entries[i].fd == fd) { \
|
||||
entry_ptr = &group_ptr->entries[i]; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FIND_IN_BUCKET_PTR() \
|
||||
do { \
|
||||
size_t first_group_size = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE; \
|
||||
if (bucket_ptr->size != 0 && first_group_size == 0) \
|
||||
first_group_size = UV__FD_HASH_GROUP_SIZE; \
|
||||
group_ptr = bucket_ptr->data; \
|
||||
FIND_IN_GROUP_PTR(first_group_size); \
|
||||
for (group_ptr = group_ptr->next; \
|
||||
group_ptr != NULL && entry_ptr == NULL; \
|
||||
group_ptr = group_ptr->next) \
|
||||
FIND_IN_GROUP_PTR(UV__FD_HASH_GROUP_SIZE); \
|
||||
} while (0)
|
||||
|
||||
INLINE static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
|
||||
FIND_IN_BUCKET_PTR();
|
||||
|
||||
if (entry_ptr != NULL) {
|
||||
*info = entry_ptr->info;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&uv__fd_hash_mutex);
|
||||
return entry_ptr != NULL;
|
||||
}
|
||||
|
||||
INLINE static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
|
||||
FIND_IN_BUCKET_PTR();
|
||||
|
||||
if (entry_ptr == NULL) {
|
||||
i = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE;
|
||||
|
||||
if (bucket_ptr->size != 0 && i == 0) {
|
||||
struct uv__fd_hash_entry_group_s* new_group_ptr =
|
||||
uv__malloc(sizeof(*new_group_ptr));
|
||||
if (new_group_ptr == NULL) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
new_group_ptr->next = bucket_ptr->data;
|
||||
bucket_ptr->data = new_group_ptr;
|
||||
}
|
||||
|
||||
bucket_ptr->size += 1;
|
||||
entry_ptr = &bucket_ptr->data->entries[i];
|
||||
entry_ptr->fd = fd;
|
||||
}
|
||||
|
||||
entry_ptr->info = *info;
|
||||
|
||||
uv_mutex_unlock(&uv__fd_hash_mutex);
|
||||
}
|
||||
|
||||
INLINE static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
|
||||
FIND_IN_BUCKET_PTR();
|
||||
|
||||
if (entry_ptr != NULL) {
|
||||
*info = entry_ptr->info;
|
||||
|
||||
bucket_ptr->size -= 1;
|
||||
|
||||
i = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE;
|
||||
if (entry_ptr != &bucket_ptr->data->entries[i]) {
|
||||
*entry_ptr = bucket_ptr->data->entries[i];
|
||||
}
|
||||
|
||||
if (bucket_ptr->size != 0 &&
|
||||
bucket_ptr->size % UV__FD_HASH_GROUP_SIZE == 0) {
|
||||
struct uv__fd_hash_entry_group_s* old_group_ptr = bucket_ptr->data;
|
||||
bucket_ptr->data = old_group_ptr->next;
|
||||
uv__free(old_group_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&uv__fd_hash_mutex);
|
||||
return entry_ptr != NULL;
|
||||
}
|
||||
|
||||
#undef FIND_COMMON_VARIABLES
|
||||
#undef FIND_IN_GROUP_PTR
|
||||
#undef FIND_IN_BUCKET_PTR
|
||||
|
||||
#endif /* UV_WIN_FS_FD_HASH_INL_H_ */
|
||||
387
src/win/fs.c
387
src/win/fs.c
@ -34,6 +34,7 @@
|
||||
#include "internal.h"
|
||||
#include "req-inl.h"
|
||||
#include "handle-inl.h"
|
||||
#include "fs-fd-hash-inl.h"
|
||||
|
||||
#include <wincrypt.h>
|
||||
|
||||
@ -126,6 +127,8 @@
|
||||
#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
|
||||
((c) >= L'A' && (c) <= L'Z'))
|
||||
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
|
||||
const WCHAR JUNCTION_PREFIX_LEN = 4;
|
||||
|
||||
@ -137,6 +140,18 @@ const WCHAR UNC_PATH_PREFIX_LEN = 8;
|
||||
|
||||
static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
|
||||
|
||||
static DWORD uv__allocation_granularity;
|
||||
|
||||
|
||||
void uv_fs_init(void) {
|
||||
SYSTEM_INFO system_info;
|
||||
|
||||
GetSystemInfo(&system_info);
|
||||
uv__allocation_granularity = system_info.dwAllocationGranularity;
|
||||
|
||||
uv__fd_hash_init();
|
||||
}
|
||||
|
||||
|
||||
INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
|
||||
const char* new_path, const int copy_path) {
|
||||
@ -410,6 +425,27 @@ void fs__open(uv_fs_t* req) {
|
||||
HANDLE file;
|
||||
int fd, current_umask;
|
||||
int flags = req->fs.info.file_flags;
|
||||
struct uv__fd_info_s fd_info;
|
||||
|
||||
/* Adjust flags to be compatible with the memory file mapping. Save the
|
||||
* original flags to emulate the correct behavior. */
|
||||
if (flags & UV_FS_O_FILEMAP) {
|
||||
fd_info.flags = flags;
|
||||
fd_info.current_pos.QuadPart = 0;
|
||||
|
||||
if ((flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) ==
|
||||
UV_FS_O_WRONLY) {
|
||||
/* CreateFileMapping always needs read access */
|
||||
flags = (flags & ~UV_FS_O_WRONLY) | UV_FS_O_RDWR;
|
||||
}
|
||||
|
||||
if (flags & UV_FS_O_APPEND) {
|
||||
/* Clear the append flag and ensure RDRW mode */
|
||||
flags &= ~UV_FS_O_APPEND;
|
||||
flags &= ~(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
|
||||
flags |= UV_FS_O_RDWR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Obtain the active umask. umask() never fails and returns the previous
|
||||
* umask. */
|
||||
@ -440,7 +476,8 @@ void fs__open(uv_fs_t* req) {
|
||||
* Here is where we deviate significantly from what CRT's _open()
|
||||
* does. We indiscriminately use all the sharing modes, to match
|
||||
* UNIX semantics. In particular, this ensures that the file can
|
||||
* be deleted even whilst it's open, fixing issue #1449.
|
||||
* be deleted even whilst it's open, fixing issue
|
||||
* https://github.com/nodejs/node-v0.x-archive/issues/1449.
|
||||
* We still support exclusive sharing mode, since it is necessary
|
||||
* for opening raw block devices, otherwise Windows will prevent
|
||||
* any attempt to write past the master boot record.
|
||||
@ -579,11 +616,55 @@ void fs__open(uv_fs_t* req) {
|
||||
else if (GetLastError() != ERROR_SUCCESS)
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
else
|
||||
SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
|
||||
SET_REQ_WIN32_ERROR(req, (DWORD) UV_UNKNOWN);
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & UV_FS_O_FILEMAP) {
|
||||
FILE_STANDARD_INFO file_info;
|
||||
if (!GetFileInformationByHandleEx(file,
|
||||
FileStandardInfo,
|
||||
&file_info,
|
||||
sizeof file_info)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
fd_info.is_directory = file_info.Directory;
|
||||
|
||||
if (fd_info.is_directory) {
|
||||
fd_info.size.QuadPart = 0;
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
if (!GetFileSizeEx(file, &fd_info.size)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd_info.size.QuadPart == 0) {
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
DWORD flProtect = (fd_info.flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY |
|
||||
UV_FS_O_RDWR)) == UV_FS_O_RDONLY ? PAGE_READONLY : PAGE_READWRITE;
|
||||
fd_info.mapping = CreateFileMapping(file,
|
||||
NULL,
|
||||
flProtect,
|
||||
fd_info.size.HighPart,
|
||||
fd_info.size.LowPart,
|
||||
NULL);
|
||||
if (fd_info.mapping == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uv__fd_hash_add(fd, &fd_info);
|
||||
}
|
||||
|
||||
SET_REQ_RESULT(req, fd);
|
||||
return;
|
||||
|
||||
@ -594,9 +675,16 @@ void fs__open(uv_fs_t* req) {
|
||||
void fs__close(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
int result;
|
||||
struct uv__fd_info_s fd_info;
|
||||
|
||||
VERIFY_FD(fd, req);
|
||||
|
||||
if (uv__fd_hash_remove(fd, &fd_info)) {
|
||||
if (fd_info.mapping != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(fd_info.mapping);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd > 2)
|
||||
result = _close(fd);
|
||||
else
|
||||
@ -614,6 +702,119 @@ void fs__close(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
LONG fs__filemap_ex_filter(LONG excode, PEXCEPTION_POINTERS pep,
|
||||
int* perror) {
|
||||
if (excode != EXCEPTION_IN_PAGE_ERROR) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
assert(perror != NULL);
|
||||
if (pep != NULL && pep->ExceptionRecord != NULL &&
|
||||
pep->ExceptionRecord->NumberParameters >= 3) {
|
||||
NTSTATUS status = (NTSTATUS)pep->ExceptionRecord->ExceptionInformation[3];
|
||||
*perror = pRtlNtStatusToDosError(status);
|
||||
if (*perror != ERROR_SUCCESS) {
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
}
|
||||
*perror = UV_UNKNOWN;
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
|
||||
void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) {
|
||||
int fd = req->file.fd; /* VERIFY_FD done in fs__read */
|
||||
int rw_flags = fd_info->flags &
|
||||
(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
|
||||
size_t read_size, done_read;
|
||||
unsigned int index;
|
||||
LARGE_INTEGER pos, end_pos;
|
||||
size_t view_offset;
|
||||
LARGE_INTEGER view_base;
|
||||
void* view;
|
||||
|
||||
if (rw_flags == UV_FS_O_WRONLY) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
if (fd_info->is_directory) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FUNCTION);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->fs.info.offset == -1) {
|
||||
pos = fd_info->current_pos;
|
||||
} else {
|
||||
pos.QuadPart = req->fs.info.offset;
|
||||
}
|
||||
|
||||
/* Make sure we wont read past EOF. */
|
||||
if (pos.QuadPart >= fd_info->size.QuadPart) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
read_size = 0;
|
||||
for (index = 0; index < req->fs.info.nbufs; ++index) {
|
||||
read_size += req->fs.info.bufs[index].len;
|
||||
}
|
||||
read_size = (size_t) MIN((LONGLONG) read_size,
|
||||
fd_info->size.QuadPart - pos.QuadPart);
|
||||
if (read_size == 0) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
end_pos.QuadPart = pos.QuadPart + read_size;
|
||||
|
||||
view_offset = pos.QuadPart % uv__allocation_granularity;
|
||||
view_base.QuadPart = pos.QuadPart - view_offset;
|
||||
view = MapViewOfFile(fd_info->mapping,
|
||||
FILE_MAP_READ,
|
||||
view_base.HighPart,
|
||||
view_base.LowPart,
|
||||
view_offset + read_size);
|
||||
if (view == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
done_read = 0;
|
||||
for (index = 0;
|
||||
index < req->fs.info.nbufs && done_read < read_size;
|
||||
++index) {
|
||||
int err = 0;
|
||||
size_t this_read_size = MIN(req->fs.info.bufs[index].len,
|
||||
read_size - done_read);
|
||||
__try {
|
||||
memcpy(req->fs.info.bufs[index].base,
|
||||
(char*)view + view_offset + done_read,
|
||||
this_read_size);
|
||||
}
|
||||
__except (fs__filemap_ex_filter(GetExceptionCode(),
|
||||
GetExceptionInformation(), &err)) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
UnmapViewOfFile(view);
|
||||
return;
|
||||
}
|
||||
done_read += this_read_size;
|
||||
}
|
||||
assert(done_read == read_size);
|
||||
|
||||
if (!UnmapViewOfFile(view)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->fs.info.offset == -1) {
|
||||
fd_info->current_pos = end_pos;
|
||||
uv__fd_hash_add(fd, fd_info);
|
||||
}
|
||||
|
||||
SET_REQ_RESULT(req, read_size);
|
||||
return;
|
||||
}
|
||||
|
||||
void fs__read(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
int64_t offset = req->fs.info.offset;
|
||||
@ -627,9 +828,15 @@ void fs__read(uv_fs_t* req) {
|
||||
LARGE_INTEGER original_position;
|
||||
LARGE_INTEGER zero_offset;
|
||||
int restore_position;
|
||||
struct uv__fd_info_s fd_info;
|
||||
|
||||
VERIFY_FD(fd, req);
|
||||
|
||||
if (uv__fd_hash_get(fd, &fd_info)) {
|
||||
fs__read_filemap(req, &fd_info);
|
||||
return;
|
||||
}
|
||||
|
||||
zero_offset.QuadPart = 0;
|
||||
restore_position = 0;
|
||||
handle = uv__get_osfhandle(fd);
|
||||
@ -686,6 +893,127 @@ void fs__read(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
void fs__write_filemap(uv_fs_t* req, HANDLE file,
|
||||
struct uv__fd_info_s* fd_info) {
|
||||
int fd = req->file.fd; /* VERIFY_FD done in fs__write */
|
||||
int force_append = fd_info->flags & UV_FS_O_APPEND;
|
||||
int rw_flags = fd_info->flags &
|
||||
(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
|
||||
size_t write_size, done_write;
|
||||
unsigned int index;
|
||||
LARGE_INTEGER zero, pos, end_pos;
|
||||
size_t view_offset;
|
||||
LARGE_INTEGER view_base;
|
||||
void* view;
|
||||
FILETIME ft;
|
||||
|
||||
if (rw_flags == UV_FS_O_RDONLY) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
if (fd_info->is_directory) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FUNCTION);
|
||||
return;
|
||||
}
|
||||
|
||||
write_size = 0;
|
||||
for (index = 0; index < req->fs.info.nbufs; ++index) {
|
||||
write_size += req->fs.info.bufs[index].len;
|
||||
}
|
||||
|
||||
if (write_size == 0) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
zero.QuadPart = 0;
|
||||
if (force_append) {
|
||||
pos = fd_info->size;
|
||||
} else if (req->fs.info.offset == -1) {
|
||||
pos = fd_info->current_pos;
|
||||
} else {
|
||||
pos.QuadPart = req->fs.info.offset;
|
||||
}
|
||||
|
||||
end_pos.QuadPart = pos.QuadPart + write_size;
|
||||
|
||||
/* Recreate the mapping to enlarge the file if needed */
|
||||
if (end_pos.QuadPart > fd_info->size.QuadPart) {
|
||||
if (fd_info->mapping != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(fd_info->mapping);
|
||||
}
|
||||
|
||||
fd_info->mapping = CreateFileMapping(file,
|
||||
NULL,
|
||||
PAGE_READWRITE,
|
||||
end_pos.HighPart,
|
||||
end_pos.LowPart,
|
||||
NULL);
|
||||
if (fd_info->mapping == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(file);
|
||||
fd_info->mapping = INVALID_HANDLE_VALUE;
|
||||
fd_info->size.QuadPart = 0;
|
||||
fd_info->current_pos.QuadPart = 0;
|
||||
uv__fd_hash_add(fd, fd_info);
|
||||
return;
|
||||
}
|
||||
|
||||
fd_info->size = end_pos;
|
||||
uv__fd_hash_add(fd, fd_info);
|
||||
}
|
||||
|
||||
view_offset = pos.QuadPart % uv__allocation_granularity;
|
||||
view_base.QuadPart = pos.QuadPart - view_offset;
|
||||
view = MapViewOfFile(fd_info->mapping,
|
||||
FILE_MAP_WRITE,
|
||||
view_base.HighPart,
|
||||
view_base.LowPart,
|
||||
view_offset + write_size);
|
||||
if (view == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
done_write = 0;
|
||||
for (index = 0; index < req->fs.info.nbufs; ++index) {
|
||||
int err = 0;
|
||||
__try {
|
||||
memcpy((char*)view + view_offset + done_write,
|
||||
req->fs.info.bufs[index].base,
|
||||
req->fs.info.bufs[index].len);
|
||||
}
|
||||
__except (fs__filemap_ex_filter(GetExceptionCode(),
|
||||
GetExceptionInformation(), &err)) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
UnmapViewOfFile(view);
|
||||
return;
|
||||
}
|
||||
done_write += req->fs.info.bufs[index].len;
|
||||
}
|
||||
assert(done_write == write_size);
|
||||
|
||||
if (!FlushViewOfFile(view, 0)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
UnmapViewOfFile(view);
|
||||
return;
|
||||
}
|
||||
if (!UnmapViewOfFile(view)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->fs.info.offset == -1) {
|
||||
fd_info->current_pos = end_pos;
|
||||
uv__fd_hash_add(fd, fd_info);
|
||||
}
|
||||
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
SetFileTime(file, NULL, NULL, &ft);
|
||||
|
||||
SET_REQ_RESULT(req, done_write);
|
||||
}
|
||||
|
||||
void fs__write(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
int64_t offset = req->fs.info.offset;
|
||||
@ -698,6 +1026,7 @@ void fs__write(uv_fs_t* req) {
|
||||
LARGE_INTEGER original_position;
|
||||
LARGE_INTEGER zero_offset;
|
||||
int restore_position;
|
||||
struct uv__fd_info_s fd_info;
|
||||
|
||||
VERIFY_FD(fd, req);
|
||||
|
||||
@ -709,6 +1038,11 @@ void fs__write(uv_fs_t* req) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uv__fd_hash_get(fd, &fd_info)) {
|
||||
fs__write_filemap(req, handle, &fd_info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset != -1) {
|
||||
memset(&overlapped, 0, sizeof overlapped);
|
||||
overlapped_ptr = &overlapped;
|
||||
@ -1532,6 +1866,7 @@ static void fs__fdatasync(uv_fs_t* req) {
|
||||
static void fs__ftruncate(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
HANDLE handle;
|
||||
struct uv__fd_info_s fd_info = { 0 };
|
||||
NTSTATUS status;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
FILE_END_OF_FILE_INFORMATION eof_info;
|
||||
@ -1540,6 +1875,17 @@ static void fs__ftruncate(uv_fs_t* req) {
|
||||
|
||||
handle = uv__get_osfhandle(fd);
|
||||
|
||||
if (uv__fd_hash_get(fd, &fd_info)) {
|
||||
if (fd_info.is_directory) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd_info.mapping != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(fd_info.mapping);
|
||||
}
|
||||
}
|
||||
|
||||
eof_info.EndOfFile.QuadPart = req->fs.info.offset;
|
||||
|
||||
status = pNtSetInformationFile(handle,
|
||||
@ -1552,6 +1898,43 @@ static void fs__ftruncate(uv_fs_t* req) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
} else {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
|
||||
|
||||
if (fd_info.flags) {
|
||||
CloseHandle(handle);
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
fd_info.size.QuadPart = 0;
|
||||
fd_info.current_pos.QuadPart = 0;
|
||||
uv__fd_hash_add(fd, &fd_info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_info.flags) {
|
||||
fd_info.size = eof_info.EndOfFile;
|
||||
|
||||
if (fd_info.size.QuadPart == 0) {
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
DWORD flProtect = (fd_info.flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY |
|
||||
UV_FS_O_RDWR)) == UV_FS_O_RDONLY ? PAGE_READONLY : PAGE_READWRITE;
|
||||
fd_info.mapping = CreateFileMapping(handle,
|
||||
NULL,
|
||||
flProtect,
|
||||
fd_info.size.HighPart,
|
||||
fd_info.size.LowPart,
|
||||
NULL);
|
||||
if (fd_info.mapping == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(handle);
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
fd_info.size.QuadPart = 0;
|
||||
fd_info.current_pos.QuadPart = 0;
|
||||
uv__fd_hash_add(fd, &fd_info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uv__fd_hash_add(fd, &fd_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -240,6 +240,12 @@ void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
|
||||
int uv_translate_sys_error(int sys_errno);
|
||||
|
||||
|
||||
/*
|
||||
* FS
|
||||
*/
|
||||
void uv_fs_init(void);
|
||||
|
||||
|
||||
/*
|
||||
* FS Event
|
||||
*/
|
||||
|
||||
133
test/test-fs-fd-hash.c
Normal file
133
test/test-fs-fd-hash.c
Normal file
@ -0,0 +1,133 @@
|
||||
/* Copyright libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && !defined(USING_UV_SHARED)
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "../src/win/fs-fd-hash-inl.h"
|
||||
|
||||
|
||||
#define HASH_MAX 1000000000
|
||||
#define HASH_INC (1000 * UV__FD_HASH_SIZE + 2)
|
||||
#define BUCKET_MAX (UV__FD_HASH_SIZE * UV__FD_HASH_GROUP_SIZE * 10)
|
||||
#define BUCKET_INC UV__FD_HASH_SIZE
|
||||
#define FD_DIFF 9
|
||||
|
||||
|
||||
void assert_nonexistent(int fd) {
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
ASSERT(!uv__fd_hash_get(fd, &info));
|
||||
ASSERT(!uv__fd_hash_remove(fd, &info));
|
||||
}
|
||||
|
||||
void assert_existent(int fd) {
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
ASSERT(uv__fd_hash_get(fd, &info));
|
||||
ASSERT(info.flags == fd + FD_DIFF);
|
||||
}
|
||||
|
||||
void assert_insertion(int fd) {
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
assert_nonexistent(fd);
|
||||
info.flags = fd + FD_DIFF;
|
||||
uv__fd_hash_add(fd, &info);
|
||||
assert_existent(fd);
|
||||
}
|
||||
|
||||
void assert_removal(int fd) {
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
assert_existent(fd);
|
||||
uv__fd_hash_remove(fd, &info);
|
||||
ASSERT(info.flags == fd + FD_DIFF);
|
||||
assert_nonexistent(fd);
|
||||
}
|
||||
|
||||
|
||||
/* Run a function for a set of values up to a very high number */
|
||||
#define RUN_HASH(function) \
|
||||
do { \
|
||||
for (fd = 0; fd < HASH_MAX; fd += HASH_INC) { \
|
||||
function(fd); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Run a function for a set of values that will cause many collisions */
|
||||
#define RUN_COLLISIONS(function) \
|
||||
do { \
|
||||
for (fd = 1; fd < BUCKET_MAX; fd += BUCKET_INC) { \
|
||||
function(fd); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
TEST_IMPL(fs_fd_hash) {
|
||||
int fd;
|
||||
|
||||
uv__fd_hash_init();
|
||||
|
||||
/* Empty table */
|
||||
RUN_HASH(assert_nonexistent);
|
||||
RUN_COLLISIONS(assert_nonexistent);
|
||||
|
||||
/* Fill up */
|
||||
RUN_HASH(assert_insertion);
|
||||
RUN_COLLISIONS(assert_insertion);
|
||||
|
||||
/* Full */
|
||||
RUN_HASH(assert_existent);
|
||||
RUN_COLLISIONS(assert_existent);
|
||||
|
||||
/* Update */
|
||||
{
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
info.flags = FD_DIFF + FD_DIFF;
|
||||
uv__fd_hash_add(0, &info);
|
||||
}
|
||||
{
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
ASSERT(uv__fd_hash_get(0, &info));
|
||||
ASSERT(info.flags == FD_DIFF + FD_DIFF);
|
||||
}
|
||||
{
|
||||
/* Leave as it was, will be again tested below */
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
info.flags = FD_DIFF;
|
||||
uv__fd_hash_add(0, &info);
|
||||
}
|
||||
|
||||
/* Remove all */
|
||||
RUN_HASH(assert_removal);
|
||||
RUN_COLLISIONS(assert_removal);
|
||||
|
||||
/* Empty table */
|
||||
RUN_HASH(assert_nonexistent);
|
||||
RUN_COLLISIONS(assert_nonexistent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
|
||||
|
||||
#endif /* ifndef _WIN32 */
|
||||
435
test/test-fs-open-flags.c
Normal file
435
test/test-fs-open-flags.c
Normal file
@ -0,0 +1,435 @@
|
||||
/* Copyright libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#if defined(__unix__) || defined(__POSIX__) || \
|
||||
defined(__APPLE__) || defined(__sun) || \
|
||||
defined(_AIX) || defined(__MVS__) || \
|
||||
defined(__HAIKU__)
|
||||
# include <unistd.h> /* unlink, rmdir */
|
||||
#else
|
||||
# include <direct.h>
|
||||
# define rmdir _rmdir
|
||||
# define unlink _unlink
|
||||
#endif
|
||||
|
||||
static int flags;
|
||||
|
||||
static uv_fs_t close_req;
|
||||
static uv_fs_t mkdir_req;
|
||||
static uv_fs_t open_req;
|
||||
static uv_fs_t read_req;
|
||||
static uv_fs_t rmdir_req;
|
||||
static uv_fs_t unlink_req;
|
||||
static uv_fs_t write_req;
|
||||
|
||||
static char buf[32];
|
||||
static uv_buf_t iov;
|
||||
|
||||
/* Opening the same file multiple times quickly can cause uv_fs_open to fail
|
||||
* with EBUSY, so append an identifier to the file name for each operation */
|
||||
static int sid = 0;
|
||||
|
||||
#define FILE_NAME_SIZE 128
|
||||
static char absent_file[FILE_NAME_SIZE];
|
||||
static char empty_file[FILE_NAME_SIZE];
|
||||
static char dummy_file[FILE_NAME_SIZE];
|
||||
static char empty_dir[] = "empty_dir";
|
||||
|
||||
static void setup() {
|
||||
int r;
|
||||
|
||||
/* empty_dir */
|
||||
r = uv_fs_rmdir(NULL, &rmdir_req, empty_dir, NULL);
|
||||
ASSERT(r == 0 || r == UV_ENOENT);
|
||||
ASSERT(rmdir_req.result == 0 || rmdir_req.result == UV_ENOENT);
|
||||
uv_fs_req_cleanup(&rmdir_req);
|
||||
|
||||
r = uv_fs_mkdir(NULL, &mkdir_req, empty_dir, 0755, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(mkdir_req.result == 0);
|
||||
uv_fs_req_cleanup(&mkdir_req);
|
||||
}
|
||||
|
||||
static void refresh() {
|
||||
int r;
|
||||
|
||||
/* absent_file */
|
||||
sprintf(absent_file, "test_file_%d", sid++);
|
||||
|
||||
r = uv_fs_unlink(NULL, &unlink_req, absent_file, NULL);
|
||||
ASSERT(r == 0 || r == UV_ENOENT);
|
||||
ASSERT(unlink_req.result == 0 || unlink_req.result == UV_ENOENT);
|
||||
uv_fs_req_cleanup(&unlink_req);
|
||||
|
||||
/* empty_file */
|
||||
sprintf(empty_file, "test_file_%d", sid++);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req, empty_file,
|
||||
UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req);
|
||||
|
||||
r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
/* dummy_file */
|
||||
sprintf(dummy_file, "test_file_%d", sid++);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req, dummy_file,
|
||||
UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req);
|
||||
|
||||
iov = uv_buf_init("a", 1);
|
||||
r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 1);
|
||||
ASSERT(write_req.result == 1);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
}
|
||||
|
||||
static void cleanup() {
|
||||
unlink(absent_file);
|
||||
unlink(empty_file);
|
||||
unlink(dummy_file);
|
||||
}
|
||||
|
||||
static void openFail(char *file, int error) {
|
||||
int r;
|
||||
|
||||
refresh();
|
||||
|
||||
r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r == error);
|
||||
ASSERT(open_req.result == error);
|
||||
uv_fs_req_cleanup(&open_req);
|
||||
|
||||
/* Ensure the first call does not create the file */
|
||||
r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r == error);
|
||||
ASSERT(open_req.result == error);
|
||||
uv_fs_req_cleanup(&open_req);
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
static void refreshOpen(char *file) {
|
||||
int r;
|
||||
|
||||
refresh();
|
||||
|
||||
r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req);
|
||||
}
|
||||
|
||||
static void writeExpect(char *file, char *expected, int size) {
|
||||
int r;
|
||||
|
||||
refreshOpen(file);
|
||||
|
||||
iov = uv_buf_init("b", 1);
|
||||
r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 1);
|
||||
ASSERT(write_req.result == 1);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
iov = uv_buf_init("c", 1);
|
||||
r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 1);
|
||||
ASSERT(write_req.result == 1);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
/* Check contents */
|
||||
r = uv_fs_open(NULL, &open_req, file, UV_FS_O_RDONLY, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == size);
|
||||
ASSERT(read_req.result == size);
|
||||
ASSERT(strncmp(buf, expected, size) == 0);
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
static void writeFail(char *file, int error) {
|
||||
int r;
|
||||
|
||||
refreshOpen(file);
|
||||
|
||||
iov = uv_buf_init("z", 1);
|
||||
r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == error);
|
||||
ASSERT(write_req.result == error);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
iov = uv_buf_init("z", 1);
|
||||
r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == error);
|
||||
ASSERT(write_req.result == error);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
static void readExpect(char *file, char *expected, int size) {
|
||||
int r;
|
||||
|
||||
refreshOpen(file);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == size);
|
||||
ASSERT(read_req.result == size);
|
||||
ASSERT(strncmp(buf, expected, size) == 0);
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
static void readFail(char *file, int error) {
|
||||
int r;
|
||||
|
||||
refreshOpen(file);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == error);
|
||||
ASSERT(read_req.result == error);
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == error);
|
||||
ASSERT(read_req.result == error);
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
static void fs_open_flags(int add_flags) {
|
||||
/* Follow the order from
|
||||
* https://github.com/nodejs/node/blob/1a96abe849/lib/internal/fs/utils.js#L329-L354
|
||||
*/
|
||||
|
||||
/* r */
|
||||
flags = add_flags | UV_FS_O_RDONLY;
|
||||
openFail(absent_file, UV_ENOENT);
|
||||
writeFail(empty_file, UV_EPERM);
|
||||
readExpect(empty_file, "", 0);
|
||||
writeFail(dummy_file, UV_EPERM);
|
||||
readExpect(dummy_file, "a", 1);
|
||||
writeFail(empty_dir, UV_EPERM);
|
||||
readFail(empty_dir, UV_EISDIR);
|
||||
|
||||
/* rs */
|
||||
flags = add_flags | UV_FS_O_RDONLY | UV_FS_O_SYNC;
|
||||
openFail(absent_file, UV_ENOENT);
|
||||
writeFail(empty_file, UV_EPERM);
|
||||
readExpect(empty_file, "", 0);
|
||||
writeFail(dummy_file, UV_EPERM);
|
||||
readExpect(dummy_file, "a", 1);
|
||||
writeFail(empty_dir, UV_EPERM);
|
||||
readFail(empty_dir, UV_EISDIR);
|
||||
|
||||
/* r+ */
|
||||
flags = add_flags | UV_FS_O_RDWR;
|
||||
openFail(absent_file, UV_ENOENT);
|
||||
writeExpect(empty_file, "bc", 2);
|
||||
readExpect(empty_file, "", 0);
|
||||
writeExpect(dummy_file, "bc", 2);
|
||||
readExpect(dummy_file, "a", 1);
|
||||
writeFail(empty_dir, UV_EISDIR);
|
||||
readFail(empty_dir, UV_EISDIR);
|
||||
|
||||
/* rs+ */
|
||||
flags = add_flags | UV_FS_O_RDWR | UV_FS_O_SYNC;
|
||||
openFail(absent_file, UV_ENOENT);
|
||||
writeExpect(empty_file, "bc", 2);
|
||||
readExpect(empty_file, "", 0);
|
||||
writeExpect(dummy_file, "bc", 2);
|
||||
readExpect(dummy_file, "a", 1);
|
||||
writeFail(empty_dir, UV_EISDIR);
|
||||
readFail(empty_dir, UV_EISDIR);
|
||||
|
||||
/* w */
|
||||
flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readFail(absent_file, UV_EPERM);
|
||||
writeExpect(empty_file, "bc", 2);
|
||||
readFail(empty_file, UV_EPERM);
|
||||
writeExpect(dummy_file, "bc", 2);
|
||||
readFail(dummy_file, UV_EPERM);
|
||||
openFail(empty_dir, UV_EISDIR);
|
||||
|
||||
/* wx */
|
||||
flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY |
|
||||
UV_FS_O_EXCL;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readFail(absent_file, UV_EPERM);
|
||||
openFail(empty_file, UV_EEXIST);
|
||||
openFail(dummy_file, UV_EEXIST);
|
||||
openFail(empty_dir, UV_EEXIST);
|
||||
|
||||
/* w+ */
|
||||
flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readExpect(absent_file, "", 0);
|
||||
writeExpect(empty_file, "bc", 2);
|
||||
readExpect(empty_file, "", 0);
|
||||
writeExpect(dummy_file, "bc", 2);
|
||||
readExpect(dummy_file, "", 0);
|
||||
openFail(empty_dir, UV_EISDIR);
|
||||
|
||||
/* wx+ */
|
||||
flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR |
|
||||
UV_FS_O_EXCL;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readExpect(absent_file, "", 0);
|
||||
openFail(empty_file, UV_EEXIST);
|
||||
openFail(dummy_file, UV_EEXIST);
|
||||
openFail(empty_dir, UV_EEXIST);
|
||||
|
||||
/* a */
|
||||
flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readFail(absent_file, UV_EPERM);
|
||||
writeExpect(empty_file, "bc", 2);
|
||||
readFail(empty_file, UV_EPERM);
|
||||
writeExpect(dummy_file, "abc", 3);
|
||||
readFail(dummy_file, UV_EPERM);
|
||||
writeFail(empty_dir, UV_EISDIR);
|
||||
readFail(empty_dir, UV_EPERM);
|
||||
|
||||
/* ax */
|
||||
flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY |
|
||||
UV_FS_O_EXCL;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readFail(absent_file, UV_EPERM);
|
||||
openFail(empty_file, UV_EEXIST);
|
||||
openFail(dummy_file, UV_EEXIST);
|
||||
openFail(empty_dir, UV_EEXIST);
|
||||
|
||||
/* as */
|
||||
flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY |
|
||||
UV_FS_O_SYNC;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readFail(absent_file, UV_EPERM);
|
||||
writeExpect(empty_file, "bc", 2);
|
||||
readFail(empty_file, UV_EPERM);
|
||||
writeExpect(dummy_file, "abc", 3);
|
||||
readFail(dummy_file, UV_EPERM);
|
||||
writeFail(empty_dir, UV_EISDIR);
|
||||
readFail(empty_dir, UV_EPERM);
|
||||
|
||||
/* a+ */
|
||||
flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readExpect(absent_file, "", 0);
|
||||
writeExpect(empty_file, "bc", 2);
|
||||
readExpect(empty_file, "", 0);
|
||||
writeExpect(dummy_file, "abc", 3);
|
||||
readExpect(dummy_file, "a", 1);
|
||||
writeFail(empty_dir, UV_EISDIR);
|
||||
readFail(empty_dir, UV_EISDIR);
|
||||
|
||||
/* ax+ */
|
||||
flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR |
|
||||
UV_FS_O_EXCL;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readExpect(absent_file, "", 0);
|
||||
openFail(empty_file, UV_EEXIST);
|
||||
openFail(dummy_file, UV_EEXIST);
|
||||
openFail(empty_dir, UV_EEXIST);
|
||||
|
||||
/* as+ */
|
||||
flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR |
|
||||
UV_FS_O_SYNC;
|
||||
writeExpect(absent_file, "bc", 2);
|
||||
readExpect(absent_file, "", 0);
|
||||
writeExpect(empty_file, "bc", 2);
|
||||
readExpect(empty_file, "", 0);
|
||||
writeExpect(dummy_file, "abc", 3);
|
||||
readExpect(dummy_file, "a", 1);
|
||||
writeFail(empty_dir, UV_EISDIR);
|
||||
readFail(empty_dir, UV_EISDIR);
|
||||
}
|
||||
TEST_IMPL(fs_open_flags) {
|
||||
setup();
|
||||
|
||||
fs_open_flags(0);
|
||||
fs_open_flags(UV_FS_O_FILEMAP);
|
||||
|
||||
/* Cleanup. */
|
||||
rmdir(empty_dir);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
|
||||
|
||||
#endif /* ifndef _WIN32 */
|
||||
263
test/test-fs.c
263
test/test-fs.c
@ -847,7 +847,7 @@ TEST_IMPL(fs_file_async) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_file_sync) {
|
||||
static void fs_file_sync(int add_flags) {
|
||||
int r;
|
||||
|
||||
/* Setup. */
|
||||
@ -856,8 +856,8 @@ TEST_IMPL(fs_file_sync) {
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
|
||||
S_IWUSR | S_IRUSR, NULL);
|
||||
r = uv_fs_open(loop, &open_req1, "test_file",
|
||||
O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -873,7 +873,7 @@ TEST_IMPL(fs_file_sync) {
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | add_flags, 0, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -900,7 +900,8 @@ TEST_IMPL(fs_file_sync) {
|
||||
ASSERT(rename_req.result == 0);
|
||||
uv_fs_req_cleanup(&rename_req);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY | add_flags, 0,
|
||||
NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -926,13 +927,17 @@ TEST_IMPL(fs_file_sync) {
|
||||
/* Cleanup */
|
||||
unlink("test_file");
|
||||
unlink("test_file2");
|
||||
}
|
||||
TEST_IMPL(fs_file_sync) {
|
||||
fs_file_sync(0);
|
||||
fs_file_sync(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_file_write_null_buffer) {
|
||||
static void fs_file_write_null_buffer(int add_flags) {
|
||||
int r;
|
||||
|
||||
/* Setup. */
|
||||
@ -940,8 +945,8 @@ TEST_IMPL(fs_file_write_null_buffer) {
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
|
||||
S_IWUSR | S_IRUSR, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file",
|
||||
O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -958,6 +963,10 @@ TEST_IMPL(fs_file_write_null_buffer) {
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
unlink("test_file");
|
||||
}
|
||||
TEST_IMPL(fs_file_write_null_buffer) {
|
||||
fs_file_write_null_buffer(0);
|
||||
fs_file_write_null_buffer(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
@ -1470,7 +1479,7 @@ TEST_IMPL(fs_chmod) {
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(fchmod_cb_count == 1);
|
||||
|
||||
close(file);
|
||||
uv_fs_close(loop, &req, file, NULL);
|
||||
|
||||
/*
|
||||
* Run the loop just to check we don't have make any extraneous uv_ref()
|
||||
@ -1513,7 +1522,7 @@ TEST_IMPL(fs_unlink_readonly) {
|
||||
ASSERT(req.result == sizeof(test_buf));
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
close(file);
|
||||
uv_fs_close(loop, &req, file, NULL);
|
||||
|
||||
/* Make the file read-only */
|
||||
r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
|
||||
@ -1572,7 +1581,7 @@ TEST_IMPL(fs_unlink_archive_readonly) {
|
||||
ASSERT(req.result == sizeof(test_buf));
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
close(file);
|
||||
uv_fs_close(loop, &req, file, NULL);
|
||||
|
||||
/* Make the file read-only and clear archive flag */
|
||||
r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY);
|
||||
@ -1722,7 +1731,7 @@ TEST_IMPL(fs_link) {
|
||||
ASSERT(req.result == sizeof(test_buf));
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
close(file);
|
||||
uv_fs_close(loop, &req, file, NULL);
|
||||
|
||||
/* sync link */
|
||||
r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
|
||||
@ -1764,7 +1773,7 @@ TEST_IMPL(fs_link) {
|
||||
ASSERT(req.result >= 0);
|
||||
ASSERT(strcmp(buf, test_buf) == 0);
|
||||
|
||||
close(link);
|
||||
uv_fs_close(loop, &req, link, NULL);
|
||||
|
||||
/*
|
||||
* Run the loop just to check we don't have make any extraneous uv_ref()
|
||||
@ -1871,7 +1880,7 @@ TEST_IMPL(fs_symlink) {
|
||||
ASSERT(req.result == sizeof(test_buf));
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
close(file);
|
||||
uv_fs_close(loop, &req, file, NULL);
|
||||
|
||||
/* sync symlink */
|
||||
r = uv_fs_symlink(NULL, &req, "test_file", "test_file_symlink", 0, NULL);
|
||||
@ -1909,7 +1918,7 @@ TEST_IMPL(fs_symlink) {
|
||||
ASSERT(req.result >= 0);
|
||||
ASSERT(strcmp(buf, test_buf) == 0);
|
||||
|
||||
close(link);
|
||||
uv_fs_close(loop, &req, link, NULL);
|
||||
|
||||
r = uv_fs_symlink(NULL,
|
||||
&req,
|
||||
@ -1971,7 +1980,7 @@ TEST_IMPL(fs_symlink) {
|
||||
ASSERT(req.result >= 0);
|
||||
ASSERT(strcmp(buf, test_buf) == 0);
|
||||
|
||||
close(link);
|
||||
uv_fs_close(loop, &req, link, NULL);
|
||||
|
||||
r = uv_fs_symlink(NULL,
|
||||
&req,
|
||||
@ -2293,7 +2302,7 @@ TEST_IMPL(fs_utime) {
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(req.result >= 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
close(r);
|
||||
uv_fs_close(loop, &req, r, NULL);
|
||||
|
||||
atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
|
||||
|
||||
@ -2388,7 +2397,7 @@ TEST_IMPL(fs_futime) {
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(req.result >= 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
close(r);
|
||||
uv_fs_close(loop, &req, r, NULL);
|
||||
|
||||
atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
|
||||
|
||||
@ -2583,7 +2592,7 @@ TEST_IMPL(fs_open_dir) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_file_open_append) {
|
||||
static void fs_file_open_append(int add_flags) {
|
||||
int r;
|
||||
|
||||
/* Setup. */
|
||||
@ -2591,8 +2600,8 @@ TEST_IMPL(fs_file_open_append) {
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
|
||||
S_IWUSR | S_IRUSR, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file",
|
||||
O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -2608,7 +2617,8 @@ TEST_IMPL(fs_file_open_append) {
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | O_APPEND, 0, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file",
|
||||
O_RDWR | O_APPEND | add_flags, 0, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -2624,7 +2634,8 @@ TEST_IMPL(fs_file_open_append) {
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, S_IRUSR, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags,
|
||||
S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -2646,6 +2657,10 @@ TEST_IMPL(fs_file_open_append) {
|
||||
|
||||
/* Cleanup */
|
||||
unlink("test_file");
|
||||
}
|
||||
TEST_IMPL(fs_file_open_append) {
|
||||
fs_file_open_append(0);
|
||||
fs_file_open_append(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
@ -2721,13 +2736,13 @@ TEST_IMPL(fs_rename_to_existing_file) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_read_bufs) {
|
||||
static void fs_read_bufs(int add_flags) {
|
||||
char scratch[768];
|
||||
uv_buf_t bufs[4];
|
||||
|
||||
ASSERT(0 <= uv_fs_open(NULL, &open_req1,
|
||||
"test/fixtures/lorem_ipsum.txt",
|
||||
O_RDONLY, 0, NULL));
|
||||
O_RDONLY | add_flags, 0, NULL));
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
|
||||
@ -2769,13 +2784,17 @@ TEST_IMPL(fs_read_bufs) {
|
||||
ASSERT(0 == uv_fs_close(NULL, &close_req, open_req1.result, NULL));
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
}
|
||||
TEST_IMPL(fs_read_bufs) {
|
||||
fs_read_bufs(0);
|
||||
fs_read_bufs(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_read_file_eof) {
|
||||
static void fs_read_file_eof(int add_flags) {
|
||||
#if defined(__CYGWIN__) || defined(__MSYS__)
|
||||
RETURN_SKIP("Cygwin pread at EOF may (incorrectly) return data!");
|
||||
#endif
|
||||
@ -2786,8 +2805,8 @@ TEST_IMPL(fs_read_file_eof) {
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
|
||||
S_IWUSR | S_IRUSR, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file",
|
||||
O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -2803,7 +2822,8 @@ TEST_IMPL(fs_read_file_eof) {
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0,
|
||||
NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -2830,13 +2850,17 @@ TEST_IMPL(fs_read_file_eof) {
|
||||
|
||||
/* Cleanup */
|
||||
unlink("test_file");
|
||||
}
|
||||
TEST_IMPL(fs_read_file_eof) {
|
||||
fs_read_file_eof(0);
|
||||
fs_read_file_eof(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_write_multiple_bufs) {
|
||||
static void fs_write_multiple_bufs(int add_flags) {
|
||||
uv_buf_t iovs[2];
|
||||
int r;
|
||||
|
||||
@ -2845,8 +2869,8 @@ TEST_IMPL(fs_write_multiple_bufs) {
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
|
||||
S_IWUSR | S_IRUSR, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file",
|
||||
O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -2863,7 +2887,8 @@ TEST_IMPL(fs_write_multiple_bufs) {
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0,
|
||||
NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
@ -2919,13 +2944,17 @@ TEST_IMPL(fs_write_multiple_bufs) {
|
||||
|
||||
/* Cleanup */
|
||||
unlink("test_file");
|
||||
}
|
||||
TEST_IMPL(fs_write_multiple_bufs) {
|
||||
fs_write_multiple_bufs(0);
|
||||
fs_write_multiple_bufs(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_write_alotof_bufs) {
|
||||
static void fs_write_alotof_bufs(int add_flags) {
|
||||
size_t iovcount;
|
||||
size_t iovmax;
|
||||
uv_buf_t* iovs;
|
||||
@ -2947,7 +2976,7 @@ TEST_IMPL(fs_write_alotof_bufs) {
|
||||
r = uv_fs_open(NULL,
|
||||
&open_req1,
|
||||
"test_file",
|
||||
O_RDWR | O_CREAT,
|
||||
O_RDWR | O_CREAT | add_flags,
|
||||
S_IWUSR | S_IRUSR,
|
||||
NULL);
|
||||
ASSERT(r >= 0);
|
||||
@ -2976,7 +3005,17 @@ TEST_IMPL(fs_write_alotof_bufs) {
|
||||
iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
|
||||
sizeof(test_buf));
|
||||
|
||||
ASSERT(lseek(open_req1.result, 0, SEEK_SET) == 0);
|
||||
r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0,
|
||||
NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
|
||||
r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, -1, NULL);
|
||||
if (iovcount > iovmax)
|
||||
iovcount = iovmax;
|
||||
@ -3012,13 +3051,17 @@ TEST_IMPL(fs_write_alotof_bufs) {
|
||||
/* Cleanup */
|
||||
unlink("test_file");
|
||||
free(iovs);
|
||||
}
|
||||
TEST_IMPL(fs_write_alotof_bufs) {
|
||||
fs_write_alotof_bufs(0);
|
||||
fs_write_alotof_bufs(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_write_alotof_bufs_with_offset) {
|
||||
static void fs_write_alotof_bufs_with_offset(int add_flags) {
|
||||
size_t iovcount;
|
||||
size_t iovmax;
|
||||
uv_buf_t* iovs;
|
||||
@ -3045,7 +3088,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) {
|
||||
r = uv_fs_open(NULL,
|
||||
&open_req1,
|
||||
"test_file",
|
||||
O_RDWR | O_CREAT,
|
||||
O_RDWR | O_CREAT | add_flags,
|
||||
S_IWUSR | S_IRUSR,
|
||||
NULL);
|
||||
ASSERT(r >= 0);
|
||||
@ -3124,6 +3167,10 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) {
|
||||
/* Cleanup */
|
||||
unlink("test_file");
|
||||
free(iovs);
|
||||
}
|
||||
TEST_IMPL(fs_write_alotof_bufs_with_offset) {
|
||||
fs_write_alotof_bufs_with_offset(0);
|
||||
fs_write_alotof_bufs_with_offset(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
@ -3539,6 +3586,146 @@ TEST_IMPL(fs_file_pos_after_op_with_offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static void fs_file_pos_common() {
|
||||
int r;
|
||||
|
||||
iov = uv_buf_init("abc", 3);
|
||||
r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 3);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
/* Read with offset should not change the position */
|
||||
iov = uv_buf_init(buf, 1);
|
||||
r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 1, NULL);
|
||||
ASSERT(r == 1);
|
||||
ASSERT(buf[0] == 'b');
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
/* Write without offset should change the position */
|
||||
iov = uv_buf_init("d", 1);
|
||||
r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 1);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
}
|
||||
|
||||
static void fs_file_pos_close_check(const char *contents, int size) {
|
||||
int r;
|
||||
|
||||
/* Close */
|
||||
r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
/* Confirm file contents */
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == size);
|
||||
ASSERT(strncmp(buf, contents, size) == 0);
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
/* Cleanup */
|
||||
unlink("test_file");
|
||||
}
|
||||
|
||||
static void fs_file_pos_write(int add_flags) {
|
||||
int r;
|
||||
|
||||
/* Setup. */
|
||||
unlink("test_file");
|
||||
|
||||
r = uv_fs_open(NULL,
|
||||
&open_req1,
|
||||
"test_file",
|
||||
O_TRUNC | O_CREAT | O_RDWR | add_flags,
|
||||
S_IWUSR | S_IRUSR,
|
||||
NULL);
|
||||
ASSERT(r > 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
|
||||
fs_file_pos_common();
|
||||
|
||||
/* Write with offset should not change the position */
|
||||
iov = uv_buf_init("e", 1);
|
||||
r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL);
|
||||
ASSERT(r == 1);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
fs_file_pos_close_check("aecd", 4);
|
||||
}
|
||||
TEST_IMPL(fs_file_pos_write) {
|
||||
fs_file_pos_write(0);
|
||||
fs_file_pos_write(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fs_file_pos_append(int add_flags) {
|
||||
int r;
|
||||
|
||||
/* Setup. */
|
||||
unlink("test_file");
|
||||
|
||||
r = uv_fs_open(NULL,
|
||||
&open_req1,
|
||||
"test_file",
|
||||
O_APPEND | O_CREAT | O_RDWR | add_flags,
|
||||
S_IWUSR | S_IRUSR,
|
||||
NULL);
|
||||
ASSERT(r > 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
|
||||
fs_file_pos_common();
|
||||
|
||||
/* Write with offset appends (ignoring offset)
|
||||
* but does not change the position */
|
||||
iov = uv_buf_init("e", 1);
|
||||
r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL);
|
||||
ASSERT(r == 1);
|
||||
uv_fs_req_cleanup(&write_req);
|
||||
|
||||
iov = uv_buf_init(buf, sizeof(buf));
|
||||
r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
|
||||
ASSERT(r == 1);
|
||||
ASSERT(buf[0] == 'e');
|
||||
uv_fs_req_cleanup(&read_req);
|
||||
|
||||
fs_file_pos_close_check("abcde", 5);
|
||||
}
|
||||
TEST_IMPL(fs_file_pos_append) {
|
||||
fs_file_pos_append(0);
|
||||
fs_file_pos_append(UV_FS_O_FILEMAP);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_IMPL(fs_null_req) {
|
||||
/* Verify that all fs functions return UV_EINVAL when the request is NULL. */
|
||||
int r;
|
||||
|
||||
@ -321,6 +321,10 @@ TEST_DECLARE (fs_symlink_dir)
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (fs_symlink_junction)
|
||||
TEST_DECLARE (fs_non_symlink_reparse_point)
|
||||
TEST_DECLARE (fs_open_flags)
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(USING_UV_SHARED)
|
||||
TEST_DECLARE (fs_fd_hash)
|
||||
#endif
|
||||
TEST_DECLARE (fs_utime)
|
||||
TEST_DECLARE (fs_futime)
|
||||
@ -370,6 +374,8 @@ TEST_DECLARE (fs_file_pos_after_op_with_offset)
|
||||
TEST_DECLARE (fs_null_req)
|
||||
TEST_DECLARE (fs_read_dir)
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (fs_file_pos_write)
|
||||
TEST_DECLARE (fs_file_pos_append)
|
||||
TEST_DECLARE (fs_exclusive_sharing_mode)
|
||||
TEST_DECLARE (fs_file_flag_no_buffering)
|
||||
TEST_DECLARE (fs_open_readonly_acl)
|
||||
@ -912,6 +918,10 @@ TASK_LIST_START
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (fs_symlink_junction)
|
||||
TEST_ENTRY (fs_non_symlink_reparse_point)
|
||||
TEST_ENTRY (fs_open_flags)
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(USING_UV_SHARED)
|
||||
TEST_ENTRY (fs_fd_hash)
|
||||
#endif
|
||||
TEST_ENTRY (fs_stat_missing_path)
|
||||
TEST_ENTRY (fs_read_bufs)
|
||||
@ -957,6 +967,8 @@ TASK_LIST_START
|
||||
TEST_ENTRY (fs_null_req)
|
||||
TEST_ENTRY (fs_read_dir)
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (fs_file_pos_write)
|
||||
TEST_ENTRY (fs_file_pos_append)
|
||||
TEST_ENTRY (fs_exclusive_sharing_mode)
|
||||
TEST_ENTRY (fs_file_flag_no_buffering)
|
||||
TEST_ENTRY (fs_open_readonly_acl)
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
'test-fs-readdir.c',
|
||||
'test-fs-copyfile.c',
|
||||
'test-fs-event.c',
|
||||
'test-fs-fd-hash.c',
|
||||
'test-fs-open-flags.c',
|
||||
'test-fs-poll.c',
|
||||
'test-getters-setters.c',
|
||||
'test-get-currentexe.c',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user