Commit 26acd8b0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull affs fix from David Sterba:
 "One fix to make permissions work the same way as on AmigaOS"

* tag 'affs-for-5.9-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  affs: fix basic permission bits to actually work
parents 0fdf68c7 d3a84a8d
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -110,13 +110,15 @@ The Amiga protection flags RWEDRWEDHSPARWED are handled as follows:

  - R maps to r for user, group and others. On directories, R implies x.

  - If both W and D are allowed, w will be set.
  - W maps to w.

  - E maps to x.

  - H and P are always retained and ignored under Linux.
  - D is ignored.

  - A is always reset when a file is written to.
  - H, S and P are always retained and ignored under Linux.

  - A is cleared when a file is written to.

User id and group id will be used unless set[gu]id are given as mount
options. Since most of the Amiga file systems are single user systems
@@ -128,11 +130,13 @@ Linux -> Amiga:

The Linux rwxrwxrwx file mode is handled as follows:

  - r permission will set R for user, group and others.
  - r permission will allow R for user, group and others.

  - w permission will allow W for user, group and others.

  - w permission will set W and D for user, group and others.
  - x permission of the user will allow E for plain files.

  - x permission of the user will set E for plain files.
  - D will be allowed for user, group and others.

  - All other flags (suid, sgid, ...) are ignored and will
    not be retained.
+27 −0
Original line number Diff line number Diff line
@@ -420,24 +420,51 @@ affs_mode_to_prot(struct inode *inode)
	u32 prot = AFFS_I(inode)->i_protect;
	umode_t mode = inode->i_mode;

	/*
	 * First, clear all RWED bits for owner, group, other.
	 * Then, recalculate them afresh.
	 *
	 * We'll always clear the delete-inhibit bit for the owner, as that is
	 * the classic single-user mode AmigaOS protection bit and we need to
	 * stay compatible with all scenarios.
	 *
	 * Since multi-user AmigaOS is an extension, we'll only set the
	 * delete-allow bit if any of the other bits in the same user class
	 * (group/other) are used.
	 */
	prot &= ~(FIBF_NOEXECUTE | FIBF_NOREAD
		  | FIBF_NOWRITE | FIBF_NODELETE
		  | FIBF_GRP_EXECUTE | FIBF_GRP_READ
		  | FIBF_GRP_WRITE   | FIBF_GRP_DELETE
		  | FIBF_OTR_EXECUTE | FIBF_OTR_READ
		  | FIBF_OTR_WRITE   | FIBF_OTR_DELETE);

	/* Classic single-user AmigaOS flags. These are inverted. */
	if (!(mode & 0100))
		prot |= FIBF_NOEXECUTE;
	if (!(mode & 0400))
		prot |= FIBF_NOREAD;
	if (!(mode & 0200))
		prot |= FIBF_NOWRITE;

	/* Multi-user extended flags. Not inverted. */
	if (mode & 0010)
		prot |= FIBF_GRP_EXECUTE;
	if (mode & 0040)
		prot |= FIBF_GRP_READ;
	if (mode & 0020)
		prot |= FIBF_GRP_WRITE;
	if (mode & 0070)
		prot |= FIBF_GRP_DELETE;

	if (mode & 0001)
		prot |= FIBF_OTR_EXECUTE;
	if (mode & 0004)
		prot |= FIBF_OTR_READ;
	if (mode & 0002)
		prot |= FIBF_OTR_WRITE;
	if (mode & 0007)
		prot |= FIBF_OTR_DELETE;

	AFFS_I(inode)->i_protect = prot;
}
+25 −1
Original line number Diff line number Diff line
@@ -429,6 +429,24 @@ static int affs_write_begin(struct file *file, struct address_space *mapping,
	return ret;
}

static int affs_write_end(struct file *file, struct address_space *mapping,
			  loff_t pos, unsigned int len, unsigned int copied,
			  struct page *page, void *fsdata)
{
	struct inode *inode = mapping->host;
	int ret;

	ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);

	/* Clear Archived bit on file writes, as AmigaOS would do */
	if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
		AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
		mark_inode_dirty(inode);
	}

	return ret;
}

static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
{
	return generic_block_bmap(mapping,block,affs_get_block);
@@ -438,7 +456,7 @@ const struct address_space_operations affs_aops = {
	.readpage = affs_readpage,
	.writepage = affs_writepage,
	.write_begin = affs_write_begin,
	.write_end = generic_write_end,
	.write_end = affs_write_end,
	.direct_IO = affs_direct_IO,
	.bmap = _affs_bmap
};
@@ -795,6 +813,12 @@ done:
	if (tmp > inode->i_size)
		inode->i_size = AFFS_I(inode)->mmu_private = tmp;

	/* Clear Archived bit on file writes, as AmigaOS would do */
	if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
		AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
		mark_inode_dirty(inode);
	}

err_first_bh:
	unlock_page(page);
	put_page(page);