Skip to content

Commit

Permalink
Support for O_TRUNC in the open() syscall (s3ql#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
d--j authored Sep 16, 2020
1 parent 9b2ea62 commit 32a1c4d
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Changes.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
UNRELEASED CHANGES

* The open() syscall supports the O_TRUNC flag now.

2020-09-04, S3QL 3.5.1

* `s3qlctrl upload-meta` now works properly again (previously, only the first
Expand Down
32 changes: 29 additions & 3 deletions src/s3ql/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@
ACL_ERRNO = errno.EOPNOTSUPP


class _TruncSetattrFields:
"""A private class used for O_TRUNC.
This is needed because pyfuse3.SetattrFields fields are read only"""
def __getattr__(self, name):
"""Only return ``True`` for ``update_size`` and ``update_mtime`.
Anything else will return ``False``"""
return name in ('update_size', 'update_mtime')


"""We only need a single instance of this read-only class"""
_TruncSetattrFields = _TruncSetattrFields()


class Operations(pyfuse3.Operations):
"""A full-featured file system for online data storage
Expand Down Expand Up @@ -814,7 +828,7 @@ async def setattr(self, id_, attr, fields, fh, ctx):
inode.ctime_ns = now_ns

# This needs to go last, because the call to cache.remove and cache.get
# are asynchorouns and may thus evict the *inode* object from the cache.
# are asynchronous and may thus evict the *inode* object from the cache.
if fields.update_size:
len_ = attr.st_size

Expand Down Expand Up @@ -933,8 +947,20 @@ async def open(self, id_, flags, ctx):
raise FUSEError(errno.EPERM)

if flags & os.O_TRUNC:
log.warning('open() with O_TRUNC is not yet supported.')
raise FUSEError(errno.ENOTSUP)
if not (flags & os.O_RDWR or flags & os.O_WRONLY):
# behaviour is not defined in POSIX, we opt for an error
raise FUSEError(errno.EINVAL)
attr = await self.getattr(id_, ctx)
if stat.S_ISREG(attr.st_mode):
attr.st_mtime_ns = time_ns()
attr.st_size = 0
await self.setattr(id_, attr, _TruncSetattrFields, None, ctx)
elif stat.S_ISFIFO(attr.st_mode) or stat.S_ISBLK(attr.st_mode):
# silently ignore O_TRUNC when FIFO or terminal block device
pass
else:
# behaviour is not defined in POSIX, we opt for an error
raise FUSEError(errno.EINVAL)

return pyfuse3.FileInfo(fh=id_, keep_cache=True)

Expand Down
30 changes: 29 additions & 1 deletion tests/t3_fs_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,13 @@ async def test_truncate_0(ctx):
attr.st_size = 0
await ctx.server.setattr(inode.st_ino, attr, SetattrFields(update_size=True),
fh, some_ctx)
await ctx.server.write(fh, 0, random_data(len2))
data = random_data(len2)
await ctx.server.write(fh, 0, data)
await ctx.server.release(fh)
ctx.server.inodes.flush()
fi = await ctx.server.open(inode.st_ino, os.O_RDONLY, some_ctx)
fh = fi.fh
assert await ctx.server.read(fh, 0, len2 + 1) == data
await ctx.server.release(fh)
await ctx.server.forget([(inode.st_ino, 1)])
await fsck(ctx)
Expand Down Expand Up @@ -816,6 +822,28 @@ async def test_create_open(ctx):

await fsck(ctx)

async def test_open_truncate(ctx):
(fi, inode) = await ctx.server.create(ROOT_INODE, newname(ctx), file_mode(),
os.O_RDWR, some_ctx)
fh = fi.fh
await ctx.server.write(fh, 0, random_data(int(1.5 * ctx.max_obj_size)))
await ctx.server.release(fh)
ctx.server.inodes.flush()

data = b'this data overwrites the previous data'
fi = await ctx.server.open(inode.st_ino, os.O_RDWR | os.O_TRUNC, some_ctx)
fh = fi.fh
await ctx.server.write(fh, 0, data)
await ctx.server.release(fh)
ctx.server.inodes.flush()

fi = await ctx.server.open(inode.st_ino, os.O_RDONLY, some_ctx)
fh = fi.fh
assert await ctx.server.read(fh, 0, len(data) + 1) == data
await ctx.server.release(fh)
await ctx.server.forget([(inode.st_ino, 1)])
await fsck(ctx)

async def test_edit(ctx):
len_ = ctx.max_obj_size
data = random_data(len_)
Expand Down

0 comments on commit 32a1c4d

Please sign in to comment.