aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-07-04 17:08:43 +0300
committerZyX <kp-pav@yandex.ru>2017-07-04 18:37:01 +0300
commit72b3fd96642e7b2c268e17953de3b2ed995eb3b4 (patch)
tree5f53a4a2ac97f872b86d546cdba97ea8e7ebb564
parent5ab9e9f617934fae8f85ceb6db398dbf1e93471d (diff)
downloadrneovim-72b3fd96642e7b2c268e17953de3b2ed995eb3b4.tar.gz
rneovim-72b3fd96642e7b2c268e17953de3b2ed995eb3b4.tar.bz2
rneovim-72b3fd96642e7b2c268e17953de3b2ed995eb3b4.zip
os/fileio: Add ability to use os/fileio.c for file descriptors
Code imported from #6299
-rw-r--r--src/nvim/os/fileio.c46
-rw-r--r--test/unit/os/fileio_spec.lua56
2 files changed, 98 insertions, 4 deletions
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index d16746b7bf..0ed0ae87e3 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -49,7 +49,6 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int os_open_flags = 0;
- int fd;
TriState wr = kNone;
// -V:FLAG:501
#define FLAG(flags, flag, fcntl_flags, wrval, cond) \
@@ -74,14 +73,35 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true);
#endif
#undef FLAG
+ // wr is used for kFileReadOnly flag, but on
+ // QB:neovim-qb-slave-ubuntu-12-04-64bit it still errors out with
+ // `error: variable ‘wr’ set but not used [-Werror=unused-but-set-variable]`
+ (void)wr;
- fd = os_open(fname, os_open_flags, mode);
+ const int fd = os_open(fname, os_open_flags, mode);
if (fd < 0) {
return fd;
}
+ return file_open_fd(ret_fp, fd, (wr == kTrue));
+}
- ret_fp->wr = (wr == kTrue);
+/// Wrap file descriptor with FileDescriptor structure
+///
+/// @warning File descriptor wrapped like this must not be accessed by other
+/// means.
+///
+/// @param[out] ret_fp Address where information needed for reading from or
+/// writing to a file is saved
+/// @param[in] fd File descriptor to wrap.
+/// @param[in] wr True if fd is opened for writing only, false if it is read
+/// only.
+///
+/// @return Error code (@see os_strerror()) or 0. Currently always returns 0.
+int file_open_fd(FileDescriptor *const ret_fp, const int fd, const bool wr)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ ret_fp->wr = wr;
ret_fp->fd = fd;
ret_fp->eof = false;
ret_fp->rv = rbuffer_new(kRWBufferSize);
@@ -115,6 +135,26 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,
return fp;
}
+/// Like file_open_fd(), but allocate and return ret_fp
+///
+/// @param[out] error Error code, @see os_strerror(). Is set to zero on
+/// success.
+/// @param[in] fd File descriptor to wrap.
+/// @param[in] wr True if fd is opened for writing only, false if it is read
+/// only.
+///
+/// @return [allocated] Opened file or NULL in case of error.
+FileDescriptor *file_open_fd_new(int *const error, const int fd, const bool wr)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ FileDescriptor *const fp = xmalloc(sizeof(*fp));
+ if ((*error = file_open_fd(fp, fd, wr)) != 0) {
+ xfree(fp);
+ return NULL;
+ }
+ return fp;
+}
+
/// Close file and free its buffer
///
/// @param[in,out] fp File to close.
diff --git a/test/unit/os/fileio_spec.lua b/test/unit/os/fileio_spec.lua
index a33a9637ee..d9c98e8afa 100644
--- a/test/unit/os/fileio_spec.lua
+++ b/test/unit/os/fileio_spec.lua
@@ -6,8 +6,10 @@ local itp = helpers.gen_itp(it)
local eq = helpers.eq
local ffi = helpers.ffi
local cimport = helpers.cimport
+local cppimport = helpers.cppimport
-local m = cimport('./src/nvim/os/fileio.h')
+local m = cimport('./src/nvim/os/os.h', './src/nvim/os/fileio.h')
+cppimport('fcntl.h')
local fcontents = ''
for i = 0, 255 do
@@ -58,6 +60,18 @@ local function file_open_new(fname, flags, mode)
return ret1[0], ret2
end
+local function file_open_fd(fd, flags)
+ local ret2 = ffi.new('FileDescriptor')
+ local ret1 = m.file_open_fd(ret2, fd, flags)
+ return ret1, ret2
+end
+
+local function file_open_fd_new(fd, flags)
+ local ret1 = ffi.new('int[?]', 1, {0})
+ local ret2 = ffi.gc(m.file_open_fd_new(ret1, fd, flags), nil)
+ return ret1[0], ret2
+end
+
local function file_write(fp, buf)
return m.file_write(fp, buf, #buf)
end
@@ -96,6 +110,46 @@ local function file_skip(fp, size)
return m.file_skip(fp, size)
end
+describe('file_open_fd', function()
+ itp('can use file descriptor returned by os_open for reading', function()
+ local fd = m.os_open(file1, m.kO_RDONLY, 0)
+ local err, fp = file_open_fd(fd, false)
+ eq(0, err)
+ eq({#fcontents, fcontents}, {file_read(fp, #fcontents)})
+ eq(0, m.file_close(fp, false))
+ end)
+ itp('can use file descriptor returned by os_open for writing', function()
+ eq(nil, lfs.attributes(filec))
+ local fd = m.os_open(filec, m.kO_WRONLY + m.kO_CREAT, 384)
+ local err, fp = file_open_fd(fd, true)
+ eq(0, err)
+ eq(4, file_write(fp, 'test'))
+ eq(0, m.file_close(fp, false))
+ eq(4, lfs.attributes(filec).size)
+ eq('test', io.open(filec):read('*a'))
+ end)
+end)
+
+describe('file_open_fd_new', function()
+ itp('can use file descriptor returned by os_open for reading', function()
+ local fd = m.os_open(file1, m.kO_RDONLY, 0)
+ local err, fp = file_open_fd_new(fd, false)
+ eq(0, err)
+ eq({#fcontents, fcontents}, {file_read(fp, #fcontents)})
+ eq(0, m.file_free(fp, false))
+ end)
+ itp('can use file descriptor returned by os_open for writing', function()
+ eq(nil, lfs.attributes(filec))
+ local fd = m.os_open(filec, m.kO_WRONLY + m.kO_CREAT, 384)
+ local err, fp = file_open_fd_new(fd, true)
+ eq(0, err)
+ eq(4, file_write(fp, 'test'))
+ eq(0, m.file_free(fp, false))
+ eq(4, lfs.attributes(filec).size)
+ eq('test', io.open(filec):read('*a'))
+ end)
+end)
+
describe('file_open', function()
itp('can create a rwx------ file with kFileCreate', function()
local err, fp = file_open(filec, m.kFileCreate, 448)