Skip to content

Commit d3a84a8

Browse files
Max Staudtkdave
authored andcommitted
affs: fix basic permission bits to actually work
The basic permission bits (protection bits in AmigaOS) have been broken in Linux' AFFS - it would only set bits, but never delete them. Also, contrary to the documentation, the Archived bit was not handled. Let's fix this for good, and set the bits such that Linux and classic AmigaOS can coexist in the most peaceful manner. Also, update the documentation to represent the current state of things. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: [email protected] Signed-off-by: Max Staudt <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent f75aef3 commit d3a84a8

File tree

3 files changed

+62
-7
lines changed

3 files changed

+62
-7
lines changed

Documentation/filesystems/affs.rst

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,15 @@ The Amiga protection flags RWEDRWEDHSPARWED are handled as follows:
110110

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

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

115115
- E maps to x.
116116

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

119-
- A is always reset when a file is written to.
119+
- H, S and P are always retained and ignored under Linux.
120+
121+
- A is cleared when a file is written to.
120122

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

129131
The Linux rwxrwxrwx file mode is handled as follows:
130132

131-
- r permission will set R for user, group and others.
133+
- r permission will allow R for user, group and others.
134+
135+
- w permission will allow W for user, group and others.
132136

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

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

137141
- All other flags (suid, sgid, ...) are ignored and will
138142
not be retained.

fs/affs/amigaffs.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,24 +420,51 @@ affs_mode_to_prot(struct inode *inode)
420420
u32 prot = AFFS_I(inode)->i_protect;
421421
umode_t mode = inode->i_mode;
422422

423+
/*
424+
* First, clear all RWED bits for owner, group, other.
425+
* Then, recalculate them afresh.
426+
*
427+
* We'll always clear the delete-inhibit bit for the owner, as that is
428+
* the classic single-user mode AmigaOS protection bit and we need to
429+
* stay compatible with all scenarios.
430+
*
431+
* Since multi-user AmigaOS is an extension, we'll only set the
432+
* delete-allow bit if any of the other bits in the same user class
433+
* (group/other) are used.
434+
*/
435+
prot &= ~(FIBF_NOEXECUTE | FIBF_NOREAD
436+
| FIBF_NOWRITE | FIBF_NODELETE
437+
| FIBF_GRP_EXECUTE | FIBF_GRP_READ
438+
| FIBF_GRP_WRITE | FIBF_GRP_DELETE
439+
| FIBF_OTR_EXECUTE | FIBF_OTR_READ
440+
| FIBF_OTR_WRITE | FIBF_OTR_DELETE);
441+
442+
/* Classic single-user AmigaOS flags. These are inverted. */
423443
if (!(mode & 0100))
424444
prot |= FIBF_NOEXECUTE;
425445
if (!(mode & 0400))
426446
prot |= FIBF_NOREAD;
427447
if (!(mode & 0200))
428448
prot |= FIBF_NOWRITE;
449+
450+
/* Multi-user extended flags. Not inverted. */
429451
if (mode & 0010)
430452
prot |= FIBF_GRP_EXECUTE;
431453
if (mode & 0040)
432454
prot |= FIBF_GRP_READ;
433455
if (mode & 0020)
434456
prot |= FIBF_GRP_WRITE;
457+
if (mode & 0070)
458+
prot |= FIBF_GRP_DELETE;
459+
435460
if (mode & 0001)
436461
prot |= FIBF_OTR_EXECUTE;
437462
if (mode & 0004)
438463
prot |= FIBF_OTR_READ;
439464
if (mode & 0002)
440465
prot |= FIBF_OTR_WRITE;
466+
if (mode & 0007)
467+
prot |= FIBF_OTR_DELETE;
441468

442469
AFFS_I(inode)->i_protect = prot;
443470
}

fs/affs/file.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,24 @@ static int affs_write_begin(struct file *file, struct address_space *mapping,
429429
return ret;
430430
}
431431

432+
static int affs_write_end(struct file *file, struct address_space *mapping,
433+
loff_t pos, unsigned int len, unsigned int copied,
434+
struct page *page, void *fsdata)
435+
{
436+
struct inode *inode = mapping->host;
437+
int ret;
438+
439+
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
440+
441+
/* Clear Archived bit on file writes, as AmigaOS would do */
442+
if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
443+
AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
444+
mark_inode_dirty(inode);
445+
}
446+
447+
return ret;
448+
}
449+
432450
static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
433451
{
434452
return generic_block_bmap(mapping,block,affs_get_block);
@@ -438,7 +456,7 @@ const struct address_space_operations affs_aops = {
438456
.readpage = affs_readpage,
439457
.writepage = affs_writepage,
440458
.write_begin = affs_write_begin,
441-
.write_end = generic_write_end,
459+
.write_end = affs_write_end,
442460
.direct_IO = affs_direct_IO,
443461
.bmap = _affs_bmap
444462
};
@@ -795,6 +813,12 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
795813
if (tmp > inode->i_size)
796814
inode->i_size = AFFS_I(inode)->mmu_private = tmp;
797815

816+
/* Clear Archived bit on file writes, as AmigaOS would do */
817+
if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
818+
AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
819+
mark_inode_dirty(inode);
820+
}
821+
798822
err_first_bh:
799823
unlock_page(page);
800824
put_page(page);

0 commit comments

Comments
 (0)