Alien-uv
view release on metacpan or search on metacpan
libuv/src/win/fs.c view on Meta::CPAN
error:
SET_REQ_WIN32_ERROR(req, GetLastError());
for (i = 0; i < dirent_idx; ++i) {
uv__free((char*) dirents[i].name);
dirents[i].name = NULL;
}
}
void fs__closedir(uv_fs_t* req) {
uv_dir_t* dir;
dir = req->ptr;
FindClose(dir->dir_handle);
uv__free(req->ptr);
SET_REQ_RESULT(req, 0);
}
INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
int do_lstat) {
FILE_ALL_INFORMATION file_info;
FILE_FS_VOLUME_INFORMATION volume_info;
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
nt_status = pNtQueryInformationFile(handle,
&io_status,
&file_info,
sizeof file_info,
FileAllInformation);
/* Buffer overflow (a warning status code) is expected here. */
if (NT_ERROR(nt_status)) {
SetLastError(pRtlNtStatusToDosError(nt_status));
return -1;
}
nt_status = pNtQueryVolumeInformationFile(handle,
&io_status,
&volume_info,
sizeof volume_info,
FileFsVolumeInformation);
/* Buffer overflow (a warning status code) is expected here. */
if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
statbuf->st_dev = 0;
} else if (NT_ERROR(nt_status)) {
SetLastError(pRtlNtStatusToDosError(nt_status));
return -1;
} else {
statbuf->st_dev = volume_info.VolumeSerialNumber;
}
/* Todo: st_mode should probably always be 0666 for everyone. We might also
* want to report 0777 if the file is a .exe or a directory.
*
* Currently it's based on whether the 'readonly' attribute is set, which
* makes little sense because the semantics are so different: the 'read-only'
* flag is just a way for a user to protect against accidental deletion, and
* serves no security purpose. Windows uses ACLs for that.
*
* Also people now use uv_fs_chmod() to take away the writable bit for good
* reasons. Windows however just makes the file read-only, which makes it
* impossible to delete the file afterwards, since read-only files can't be
* deleted.
*
* IOW it's all just a clusterfuck and we should think of something that
* makes slightly more sense.
*
* And uv_fs_chmod should probably just fail on windows or be a total no-op.
* There's nothing sensible it can do anyway.
*/
statbuf->st_mode = 0;
/*
* On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism
* by which filesystem drivers can intercept and alter file system requests.
*
* The only reparse points we care about are symlinks and mount points, both
* of which are treated as POSIX symlinks. Further, we only care when
* invoked via lstat, which seeks information about the link instead of its
* target. Otherwise, reparse points must be treated as regular files.
*/
if (do_lstat &&
(file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
/*
* If reading the link fails, the reparse point is not a symlink and needs
* to be treated as a regular file. The higher level lstat function will
* detect this failure and retry without do_lstat if appropriate.
*/
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
return -1;
statbuf->st_mode |= S_IFLNK;
}
if (statbuf->st_mode == 0) {
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
statbuf->st_mode |= _S_IFDIR;
statbuf->st_size = 0;
} else {
statbuf->st_mode |= _S_IFREG;
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
}
}
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
else
statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
((_S_IREAD | _S_IWRITE) >> 6);
FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
/* st_blocks contains the on-disk allocation size in 512-byte units. */
statbuf->st_blocks =
(uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9;
statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
/* The st_blksize is supposed to be the 'optimal' number of bytes for reading
* and writing to the disk. That is, for any definition of 'optimal' - it's
* supposed to at least avoid read-update-write behavior when writing to the
* disk.
*
* However nobody knows this and even fewer people actually use this value,
libuv/src/win/fs.c view on Meta::CPAN
if (offset != -1) {
result_offset = _lseeki64(fd_in, offset, SEEK_SET);
}
if (result_offset == -1) {
result = -1;
} else {
while (length > 0) {
n = _read(fd_in, buf, length < buf_size ? length : buf_size);
if (n == 0) {
break;
} else if (n == -1) {
result = -1;
break;
}
length -= n;
n = _write(fd_out, buf, n);
if (n == -1) {
result = -1;
break;
}
result += n;
}
}
uv__free(buf);
SET_REQ_RESULT(req, result);
}
static void fs__access(uv_fs_t* req) {
DWORD attr = GetFileAttributesW(req->file.pathw);
if (attr == INVALID_FILE_ATTRIBUTES) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
/*
* Access is possible if
* - write access wasn't requested,
* - or the file isn't read-only,
* - or it's a directory.
* (Directories cannot be read-only on Windows.)
*/
if (!(req->fs.info.mode & W_OK) ||
!(attr & FILE_ATTRIBUTE_READONLY) ||
(attr & FILE_ATTRIBUTE_DIRECTORY)) {
SET_REQ_RESULT(req, 0);
} else {
SET_REQ_WIN32_ERROR(req, UV_EPERM);
}
}
static void fs__chmod(uv_fs_t* req) {
int result = _wchmod(req->file.pathw, req->fs.info.mode);
SET_REQ_RESULT(req, result);
}
static void fs__fchmod(uv_fs_t* req) {
int fd = req->file.fd;
int clear_archive_flag;
HANDLE handle;
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
FILE_BASIC_INFORMATION file_info;
VERIFY_FD(fd, req);
handle = ReOpenFile(uv__get_osfhandle(fd), FILE_WRITE_ATTRIBUTES, 0, 0);
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
nt_status = pNtQueryInformationFile(handle,
&io_status,
&file_info,
sizeof file_info,
FileBasicInformation);
if (!NT_SUCCESS(nt_status)) {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
goto fchmod_cleanup;
}
/* Test if the Archive attribute is cleared */
if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) {
/* Set Archive flag, otherwise setting or clearing the read-only
flag will not work */
file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
nt_status = pNtSetInformationFile(handle,
&io_status,
&file_info,
sizeof file_info,
FileBasicInformation);
if (!NT_SUCCESS(nt_status)) {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
goto fchmod_cleanup;
}
/* Remeber to clear the flag later on */
clear_archive_flag = 1;
} else {
clear_archive_flag = 0;
}
if (req->fs.info.mode & _S_IWRITE) {
file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
} else {
file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
}
nt_status = pNtSetInformationFile(handle,
&io_status,
&file_info,
sizeof file_info,
FileBasicInformation);
if (!NT_SUCCESS(nt_status)) {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
goto fchmod_cleanup;
}
if (clear_archive_flag) {
file_info.FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
if (file_info.FileAttributes == 0) {
file_info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
}
nt_status = pNtSetInformationFile(handle,
&io_status,
&file_info,
sizeof file_info,
FileBasicInformation);
if (!NT_SUCCESS(nt_status)) {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
goto fchmod_cleanup;
}
}
SET_REQ_SUCCESS(req);
fchmod_cleanup:
CloseHandle(handle);
}
INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
FILETIME filetime_a, filetime_m;
TIME_T_TO_FILETIME(atime, &filetime_a);
TIME_T_TO_FILETIME(mtime, &filetime_m);
if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
return -1;
}
return 0;
}
static void fs__utime(uv_fs_t* req) {
HANDLE handle;
handle = CreateFileW(req->file.pathw,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
CloseHandle(handle);
return;
}
CloseHandle(handle);
req->result = 0;
}
static void fs__futime(uv_fs_t* req) {
int fd = req->file.fd;
HANDLE handle;
VERIFY_FD(fd, req);
handle = uv__get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
return;
}
if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
SET_REQ_WIN32_ERROR(req, GetLastError());
libuv/src/win/fs.c view on Meta::CPAN
handle = CreateFileW(req->file.pathw,
0,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
CloseHandle(handle);
SET_REQ_WIN32_ERROR(req, GetLastError());
return;
}
CloseHandle(handle);
req->flags |= UV_FS_FREE_PTR;
SET_REQ_RESULT(req, 0);
}
static void fs__chown(uv_fs_t* req) {
req->result = 0;
}
static void fs__fchown(uv_fs_t* req) {
req->result = 0;
}
static void fs__lchown(uv_fs_t* req) {
req->result = 0;
}
static void uv__fs_work(struct uv__work* w) {
uv_fs_t* req;
req = container_of(w, uv_fs_t, work_req);
assert(req->type == UV_FS);
#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
switch (req->fs_type) {
XX(OPEN, open)
XX(CLOSE, close)
XX(READ, read)
XX(WRITE, write)
XX(COPYFILE, copyfile)
XX(SENDFILE, sendfile)
XX(STAT, stat)
XX(LSTAT, lstat)
XX(FSTAT, fstat)
XX(FTRUNCATE, ftruncate)
XX(UTIME, utime)
XX(FUTIME, futime)
XX(ACCESS, access)
XX(CHMOD, chmod)
XX(FCHMOD, fchmod)
XX(FSYNC, fsync)
XX(FDATASYNC, fdatasync)
XX(UNLINK, unlink)
XX(RMDIR, rmdir)
XX(MKDIR, mkdir)
XX(MKDTEMP, mkdtemp)
XX(RENAME, rename)
XX(SCANDIR, scandir)
XX(READDIR, readdir)
XX(OPENDIR, opendir)
XX(CLOSEDIR, closedir)
XX(LINK, link)
XX(SYMLINK, symlink)
XX(READLINK, readlink)
XX(REALPATH, realpath)
XX(CHOWN, chown)
XX(FCHOWN, fchown);
XX(LCHOWN, lchown);
default:
assert(!"bad uv_fs_type");
}
}
static void uv__fs_done(struct uv__work* w, int status) {
uv_fs_t* req;
req = container_of(w, uv_fs_t, work_req);
uv__req_unregister(req->loop, req);
if (status == UV_ECANCELED) {
assert(req->result == 0);
req->result = UV_ECANCELED;
}
req->cb(req);
}
void uv_fs_req_cleanup(uv_fs_t* req) {
if (req == NULL)
return;
if (req->flags & UV_FS_CLEANEDUP)
return;
if (req->flags & UV_FS_FREE_PATHS)
uv__free(req->file.pathw);
if (req->flags & UV_FS_FREE_PTR) {
if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
uv__fs_scandir_cleanup(req);
else if (req->fs_type == UV_FS_READDIR)
uv__fs_readdir_cleanup(req);
else
uv__free(req->ptr);
}
if (req->fs.info.bufs != req->fs.info.bufsml)
uv__free(req->fs.info.bufs);
libuv/src/win/fs.c view on Meta::CPAN
req->file.fd = fd;
req->fs.info.offset = offset;
POST;
}
int uv_fs_copyfile(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
const char* new_path,
int flags,
uv_fs_cb cb) {
int err;
INIT(UV_FS_COPYFILE);
if (flags & ~(UV_FS_COPYFILE_EXCL |
UV_FS_COPYFILE_FICLONE |
UV_FS_COPYFILE_FICLONE_FORCE)) {
return UV_EINVAL;
}
err = fs__capture_path(req, path, new_path, cb != NULL);
if (err)
return uv_translate_sys_error(err);
req->fs.info.file_flags = flags;
POST;
}
int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
INIT(UV_FS_SENDFILE);
req->file.fd = fd_in;
req->fs.info.fd_out = fd_out;
req->fs.info.offset = in_offset;
req->fs.info.bufsml[0].len = length;
POST;
}
int uv_fs_access(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
int flags,
uv_fs_cb cb) {
int err;
INIT(UV_FS_ACCESS);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err)
return uv_translate_sys_error(err);
req->fs.info.mode = flags;
POST;
}
int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
uv_fs_cb cb) {
int err;
INIT(UV_FS_CHMOD);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.info.mode = mode;
POST;
}
int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
uv_fs_cb cb) {
INIT(UV_FS_FCHMOD);
req->file.fd = fd;
req->fs.info.mode = mode;
POST;
}
int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
double mtime, uv_fs_cb cb) {
int err;
INIT(UV_FS_UTIME);
err = fs__capture_path(req, path, NULL, cb != NULL);
if (err) {
return uv_translate_sys_error(err);
}
req->fs.time.atime = atime;
req->fs.time.mtime = mtime;
POST;
}
int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
double mtime, uv_fs_cb cb) {
INIT(UV_FS_FUTIME);
req->file.fd = fd;
req->fs.time.atime = atime;
req->fs.time.mtime = mtime;
POST;
}
( run in 0.617 second using v1.01-cache-2.11-cpan-0068ddc7af1 )