unix,win: add fs open flags, map O_DIRECT|O_DSYNC
Define stable cross-platform file open constants so that users can pass `UV_FS_O_RDWR` rather than `_O_RDWR` (win) or `O_RDWR` (unix). Map `UV_FS_O_DIRECT`, `UV_FS_O_DSYNC` and `UV_FS_O_SYNC` to `FILE_FLAG_NO_BUFFERING` and `FILE_FLAG_WRITE_THROUGH` (win). Fixes: https://github.com/libuv/libuv/issues/1550 PR-URL: https://github.com/libuv/libuv/pull/1567 Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com>
This commit is contained in:
parent
5a2b5e84d0
commit
4b666bd2d8
151
docs/src/fs.rst
151
docs/src/fs.rst
@ -353,3 +353,154 @@ Helper functions
|
||||
any attempts to close it or to use it after closing the fd may lead to malfunction.
|
||||
|
||||
.. versionadded:: 1.12.0
|
||||
|
||||
File open constants
|
||||
-------------------
|
||||
|
||||
.. c:macro:: UV_FS_O_APPEND
|
||||
|
||||
The file is opened in append mode. Before each write, the file offset is
|
||||
positioned at the end of the file.
|
||||
|
||||
.. c:macro:: UV_FS_O_CREAT
|
||||
|
||||
The file is created if it does not already exist.
|
||||
|
||||
.. c:macro:: UV_FS_O_DIRECT
|
||||
|
||||
File I/O is done directly to and from user-space buffers, which must be
|
||||
aligned. Buffer size and address should be a multiple of the physical sector
|
||||
size of the block device.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_DIRECT` is supported on Linux, and on Windows via
|
||||
`FILE_FLAG_NO_BUFFERING <https://msdn.microsoft.com/en-us/library/windows/desktop/cc644950.aspx>`_.
|
||||
`UV_FS_O_DIRECT` is not supported on macOS.
|
||||
|
||||
.. c:macro:: UV_FS_O_DIRECTORY
|
||||
|
||||
If the path is not a directory, fail the open.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_DIRECTORY` is not supported on Windows.
|
||||
|
||||
.. c:macro:: UV_FS_O_DSYNC
|
||||
|
||||
The file is opened for synchronous I/O. Write operations will complete once
|
||||
all data and a minimum of metadata are flushed to disk.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_DSYNC` is supported on Windows via
|
||||
`FILE_FLAG_WRITE_THROUGH <https://msdn.microsoft.com/en-us/library/windows/desktop/cc644950.aspx>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_EXCL
|
||||
|
||||
If the `O_CREAT` flag is set and the file already exists, fail the open.
|
||||
|
||||
.. note::
|
||||
In general, the behavior of `O_EXCL` is undefined if it is used without
|
||||
`O_CREAT`. There is one exception: on Linux 2.6 and later, `O_EXCL` can
|
||||
be used without `O_CREAT` if pathname refers to a block device. If the
|
||||
block device is in use by the system (e.g., mounted), the open will fail
|
||||
with the error `EBUSY`.
|
||||
|
||||
.. c:macro:: UV_FS_O_EXLOCK
|
||||
|
||||
Atomically obtain an exclusive lock.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_EXLOCK` is only supported on macOS.
|
||||
|
||||
.. c:macro:: UV_FS_O_NOATIME
|
||||
|
||||
Do not update the file access time when the file is read.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_NOATIME` is not supported on Windows.
|
||||
|
||||
.. c:macro:: UV_FS_O_NOCTTY
|
||||
|
||||
If the path identifies a terminal device, opening the path will not cause
|
||||
that terminal to become the controlling terminal for the process (if the
|
||||
process does not already have one).
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_NOCTTY` is not supported on Windows.
|
||||
|
||||
.. c:macro:: UV_FS_O_NOFOLLOW
|
||||
|
||||
If the path is a symbolic link, fail the open.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_NOFOLLOW` is not supported on Windows.
|
||||
|
||||
.. c:macro:: UV_FS_O_NONBLOCK
|
||||
|
||||
Open the file in nonblocking mode if possible.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_NONBLOCK` is not supported on Windows.
|
||||
|
||||
.. c:macro:: UV_FS_O_RANDOM
|
||||
|
||||
Access is intended to be random. The system can use this as a hint to
|
||||
optimize file caching.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_RANDOM` is only supported on Windows via
|
||||
`FILE_FLAG_RANDOM_ACCESS <https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_RDONLY
|
||||
|
||||
Open the file for read-only access.
|
||||
|
||||
.. c:macro:: UV_FS_O_RDWR
|
||||
|
||||
Open the file for read-write access.
|
||||
|
||||
.. c:macro:: UV_FS_O_SEQUENTIAL
|
||||
|
||||
Access is intended to be sequential from beginning to end. The system can
|
||||
use this as a hint to optimize file caching.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_SEQUENTIAL` is only supported on Windows via
|
||||
`FILE_FLAG_SEQUENTIAL_SCAN <https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_SHORT_LIVED
|
||||
|
||||
The file is temporary and should not be flushed to disk if possible.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_SHORT_LIVED` is only supported on Windows via
|
||||
`FILE_ATTRIBUTE_TEMPORARY <https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_SYMLINK
|
||||
|
||||
Open the symbolic link itself rather than the resource it points to.
|
||||
|
||||
.. c:macro:: UV_FS_O_SYNC
|
||||
|
||||
The file is opened for synchronous I/O. Write operations will complete once
|
||||
all data and all metadata are flushed to disk.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_SYNC` is supported on Windows via
|
||||
`FILE_FLAG_WRITE_THROUGH <https://msdn.microsoft.com/en-us/library/windows/desktop/cc644950.aspx>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_TEMPORARY
|
||||
|
||||
The file is temporary and should not be flushed to disk if possible.
|
||||
|
||||
.. note::
|
||||
`UV_FS_O_TEMPORARY` is only supported on Windows via
|
||||
`FILE_ATTRIBUTE_TEMPORARY <https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx>`_.
|
||||
|
||||
.. c:macro:: UV_FS_O_TRUNC
|
||||
|
||||
If the file exists and is a regular file, and the file is opened
|
||||
successfully for write access, its length shall be truncated to zero.
|
||||
|
||||
.. c:macro:: UV_FS_O_WRONLY
|
||||
|
||||
Open the file for write-only access.
|
||||
|
||||
@ -365,4 +365,97 @@ typedef struct {
|
||||
uv_fs_event_cb cb; \
|
||||
UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
|
||||
/* fs open() flags supported on this platform: */
|
||||
#if defined(O_APPEND)
|
||||
# define UV_FS_O_APPEND O_APPEND
|
||||
#else
|
||||
# define UV_FS_O_APPEND 0
|
||||
#endif
|
||||
#if defined(O_CREAT)
|
||||
# define UV_FS_O_CREAT O_CREAT
|
||||
#else
|
||||
# define UV_FS_O_CREAT 0
|
||||
#endif
|
||||
#if defined(O_DIRECT)
|
||||
# define UV_FS_O_DIRECT O_DIRECT
|
||||
#else
|
||||
# define UV_FS_O_DIRECT 0
|
||||
#endif
|
||||
#if defined(O_DIRECTORY)
|
||||
# define UV_FS_O_DIRECTORY O_DIRECTORY
|
||||
#else
|
||||
# define UV_FS_O_DIRECTORY 0
|
||||
#endif
|
||||
#if defined(O_DSYNC)
|
||||
# define UV_FS_O_DSYNC O_DSYNC
|
||||
#else
|
||||
# define UV_FS_O_DSYNC 0
|
||||
#endif
|
||||
#if defined(O_EXCL)
|
||||
# define UV_FS_O_EXCL O_EXCL
|
||||
#else
|
||||
# define UV_FS_O_EXCL 0
|
||||
#endif
|
||||
#if defined(O_EXLOCK)
|
||||
# define UV_FS_O_EXLOCK O_EXLOCK
|
||||
#else
|
||||
# define UV_FS_O_EXLOCK 0
|
||||
#endif
|
||||
#if defined(O_NOATIME)
|
||||
# define UV_FS_O_NOATIME O_NOATIME
|
||||
#else
|
||||
# define UV_FS_O_NOATIME 0
|
||||
#endif
|
||||
#if defined(O_NOCTTY)
|
||||
# define UV_FS_O_NOCTTY O_NOCTTY
|
||||
#else
|
||||
# define UV_FS_O_NOCTTY 0
|
||||
#endif
|
||||
#if defined(O_NOFOLLOW)
|
||||
# define UV_FS_O_NOFOLLOW O_NOFOLLOW
|
||||
#else
|
||||
# define UV_FS_O_NOFOLLOW 0
|
||||
#endif
|
||||
#if defined(O_NONBLOCK)
|
||||
# define UV_FS_O_NONBLOCK O_NONBLOCK
|
||||
#else
|
||||
# define UV_FS_O_NONBLOCK 0
|
||||
#endif
|
||||
#if defined(O_RDONLY)
|
||||
# define UV_FS_O_RDONLY O_RDONLY
|
||||
#else
|
||||
# define UV_FS_O_RDONLY 0
|
||||
#endif
|
||||
#if defined(O_RDWR)
|
||||
# define UV_FS_O_RDWR O_RDWR
|
||||
#else
|
||||
# define UV_FS_O_RDWR 0
|
||||
#endif
|
||||
#if defined(O_SYMLINK)
|
||||
# define UV_FS_O_SYMLINK O_SYMLINK
|
||||
#else
|
||||
# define UV_FS_O_SYMLINK 0
|
||||
#endif
|
||||
#if defined(O_SYNC)
|
||||
# define UV_FS_O_SYNC O_SYNC
|
||||
#else
|
||||
# define UV_FS_O_SYNC 0
|
||||
#endif
|
||||
#if defined(O_TRUNC)
|
||||
# define UV_FS_O_TRUNC O_TRUNC
|
||||
#else
|
||||
# define UV_FS_O_TRUNC 0
|
||||
#endif
|
||||
#if defined(O_WRONLY)
|
||||
# define UV_FS_O_WRONLY O_WRONLY
|
||||
#else
|
||||
# define UV_FS_O_WRONLY 0
|
||||
#endif
|
||||
|
||||
/* fs open() flags supported on other platforms: */
|
||||
#define UV_FS_O_RANDOM 0
|
||||
#define UV_FS_O_SHORT_LIVED 0
|
||||
#define UV_FS_O_SEQUENTIAL 0
|
||||
#define UV_FS_O_TEMPORARY 0
|
||||
|
||||
#endif /* UV_UNIX_H */
|
||||
|
||||
@ -648,3 +648,28 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
#ifndef X_OK
|
||||
#define X_OK 1
|
||||
#endif
|
||||
|
||||
/* fs open() flags supported on this platform: */
|
||||
#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_RANDOM _O_RANDOM
|
||||
#define UV_FS_O_RDONLY _O_RDONLY
|
||||
#define UV_FS_O_RDWR _O_RDWR
|
||||
#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL
|
||||
#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED
|
||||
#define UV_FS_O_TEMPORARY _O_TEMPORARY
|
||||
#define UV_FS_O_TRUNC _O_TRUNC
|
||||
#define UV_FS_O_WRONLY _O_WRONLY
|
||||
|
||||
/* fs open() flags supported on other platforms (or mapped on this platform): */
|
||||
#define UV_FS_O_DIRECT 0x2000000 /* FILE_FLAG_NO_BUFFERING */
|
||||
#define UV_FS_O_DIRECTORY 0
|
||||
#define UV_FS_O_DSYNC 0x4000000 /* FILE_FLAG_WRITE_THROUGH */
|
||||
#define UV_FS_O_EXLOCK 0
|
||||
#define UV_FS_O_NOATIME 0
|
||||
#define UV_FS_O_NOCTTY 0
|
||||
#define UV_FS_O_NOFOLLOW 0
|
||||
#define UV_FS_O_NONBLOCK 0
|
||||
#define UV_FS_O_SYMLINK 0
|
||||
#define UV_FS_O_SYNC 0x8000000 /* FILE_FLAG_WRITE_THROUGH */
|
||||
|
||||
59
src/win/fs.c
59
src/win/fs.c
@ -415,21 +415,21 @@ void fs__open(uv_fs_t* req) {
|
||||
umask(current_umask);
|
||||
|
||||
/* convert flags and mode to CreateFile parameters */
|
||||
switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
|
||||
case _O_RDONLY:
|
||||
switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) {
|
||||
case UV_FS_O_RDONLY:
|
||||
access = FILE_GENERIC_READ;
|
||||
break;
|
||||
case _O_WRONLY:
|
||||
case UV_FS_O_WRONLY:
|
||||
access = FILE_GENERIC_WRITE;
|
||||
break;
|
||||
case _O_RDWR:
|
||||
case UV_FS_O_RDWR:
|
||||
access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
|
||||
break;
|
||||
default:
|
||||
goto einval;
|
||||
}
|
||||
|
||||
if (flags & _O_APPEND) {
|
||||
if (flags & UV_FS_O_APPEND) {
|
||||
access &= ~FILE_WRITE_DATA;
|
||||
access |= FILE_APPEND_DATA;
|
||||
}
|
||||
@ -442,23 +442,23 @@ void fs__open(uv_fs_t* req) {
|
||||
*/
|
||||
share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
|
||||
switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
|
||||
switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) {
|
||||
case 0:
|
||||
case _O_EXCL:
|
||||
case UV_FS_O_EXCL:
|
||||
disposition = OPEN_EXISTING;
|
||||
break;
|
||||
case _O_CREAT:
|
||||
case UV_FS_O_CREAT:
|
||||
disposition = OPEN_ALWAYS;
|
||||
break;
|
||||
case _O_CREAT | _O_EXCL:
|
||||
case _O_CREAT | _O_TRUNC | _O_EXCL:
|
||||
case UV_FS_O_CREAT | UV_FS_O_EXCL:
|
||||
case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL:
|
||||
disposition = CREATE_NEW;
|
||||
break;
|
||||
case _O_TRUNC:
|
||||
case _O_TRUNC | _O_EXCL:
|
||||
case UV_FS_O_TRUNC:
|
||||
case UV_FS_O_TRUNC | UV_FS_O_EXCL:
|
||||
disposition = TRUNCATE_EXISTING;
|
||||
break;
|
||||
case _O_CREAT | _O_TRUNC:
|
||||
case UV_FS_O_CREAT | UV_FS_O_TRUNC:
|
||||
disposition = CREATE_ALWAYS;
|
||||
break;
|
||||
default:
|
||||
@ -466,34 +466,49 @@ void fs__open(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
attributes |= FILE_ATTRIBUTE_NORMAL;
|
||||
if (flags & _O_CREAT) {
|
||||
if (flags & UV_FS_O_CREAT) {
|
||||
if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
|
||||
attributes |= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & _O_TEMPORARY ) {
|
||||
if (flags & UV_FS_O_TEMPORARY ) {
|
||||
attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
|
||||
access |= DELETE;
|
||||
}
|
||||
|
||||
if (flags & _O_SHORT_LIVED) {
|
||||
if (flags & UV_FS_O_SHORT_LIVED) {
|
||||
attributes |= FILE_ATTRIBUTE_TEMPORARY;
|
||||
}
|
||||
|
||||
switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
|
||||
switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) {
|
||||
case 0:
|
||||
break;
|
||||
case _O_SEQUENTIAL:
|
||||
case UV_FS_O_SEQUENTIAL:
|
||||
attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
break;
|
||||
case _O_RANDOM:
|
||||
case UV_FS_O_RANDOM:
|
||||
attributes |= FILE_FLAG_RANDOM_ACCESS;
|
||||
break;
|
||||
default:
|
||||
goto einval;
|
||||
}
|
||||
|
||||
if (flags & UV_FS_O_DIRECT) {
|
||||
attributes |= FILE_FLAG_NO_BUFFERING;
|
||||
}
|
||||
|
||||
switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) {
|
||||
case 0:
|
||||
break;
|
||||
case UV_FS_O_DSYNC:
|
||||
case UV_FS_O_SYNC:
|
||||
attributes |= FILE_FLAG_WRITE_THROUGH;
|
||||
break;
|
||||
default:
|
||||
goto einval;
|
||||
}
|
||||
|
||||
/* Setting this flag makes it possible to open a directory. */
|
||||
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
|
||||
|
||||
@ -506,9 +521,9 @@ void fs__open(uv_fs_t* req) {
|
||||
NULL);
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
|
||||
!(flags & _O_EXCL)) {
|
||||
/* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
|
||||
if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
|
||||
!(flags & UV_FS_O_EXCL)) {
|
||||
/* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */
|
||||
/* specified, it means the path referred to a directory. */
|
||||
SET_REQ_UV_ERROR(req, UV_EISDIR, error);
|
||||
} else {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user