def setattr(self, inode, attr, fields, fh, ctx):
assert self._initialized
inode = self.forest.inodes.get_by_value(inode)
de = inode.direntry
pending_changes = {}
mode_filter = 0
if fields.update_uid:
now_st_uid = de.data['st_uid']
if attr.st_uid >= 0 and attr.st_uid != now_st_uid:
assert_or_errno(not ctx.uid, EPERM, 'nonroot setting uid')
# Non-root can only do nop uid change
pending_changes['st_uid'] = attr.st_uid
if fields.update_gid:
# Non-root can change gid to one he has, if he owns the file
now_st_uid = de.data['st_uid']
now_st_gid = de.data['st_gid']
if attr.st_gid >= 0 and attr.st_gid != now_st_gid:
assert_or_errno(not ctx.uid
or (ctx.uid == now_st_uid
and self._ctx_has_gid(ctx, attr.st_gid)),
EPERM, 'nonroot setting gid')
pending_changes['st_gid'] = attr.st_gid
if ctx.uid:
mode_filter = stat.S_ISUID | stat.S_ISGID
# Non-root setuid/gid should reset setuid/gid
if fields.update_mode:
# TBD: use S_IFMT + S_IMODE to filter this or not?
pending_changes['st_mode'] = attr.st_mode & ~mode_filter
elif mode_filter:
pending_changes['st_mode'] = de.data['st_mode'] & ~mode_filter
if fields.update_mtime:
_debug('%s mtime set to %s', inode, attr.st_mtime_ns)
pending_changes['st_mtime_ns'] = attr.st_mtime_ns
if fields.update_size:
pending_changes['st_size'] = attr.st_size
pending_changes = {k: v for k, v in pending_changes.items()
if k not in de.data or de.data[k] != v}
if pending_changes:
for k, v in pending_changes.items():
assert_or_errno(self.access(inode.value, os.W_OK, ctx,
or_own=True),
EPERM, 'setattr-file write')
if k == 'st_size':
inode.set_size(v)
else:
de.set_data(k, v)
inode.change_ctime()
return self._inode_attributes(inode)
评论列表
文章目录