diff options
| -rw-r--r-- | Documentation/filesystems/adfs.txt | 18 | ||||
| -rw-r--r-- | fs/adfs/adfs.h | 21 | ||||
| -rw-r--r-- | fs/adfs/dir_f.c | 23 | ||||
| -rw-r--r-- | fs/adfs/dir_fplus.c | 18 | ||||
| -rw-r--r-- | fs/adfs/inode.c | 22 | ||||
| -rw-r--r-- | fs/adfs/super.c | 23 |
6 files changed, 99 insertions, 26 deletions
diff --git a/Documentation/filesystems/adfs.txt b/Documentation/filesystems/adfs.txt index 9e8811f92b8..5949766353f 100644 --- a/Documentation/filesystems/adfs.txt +++ b/Documentation/filesystems/adfs.txt | |||
| @@ -9,6 +9,9 @@ Mount options for ADFS | |||
| 9 | will be nnn. Default 0700. | 9 | will be nnn. Default 0700. |
| 10 | othmask=nnn The permission mask for ADFS 'other' permissions | 10 | othmask=nnn The permission mask for ADFS 'other' permissions |
| 11 | will be nnn. Default 0077. | 11 | will be nnn. Default 0077. |
| 12 | ftsuffix=n When ftsuffix=0, no file type suffix will be applied. | ||
| 13 | When ftsuffix=1, a hexadecimal suffix corresponding to | ||
| 14 | the RISC OS file type will be added. Default 0. | ||
| 12 | 15 | ||
| 13 | Mapping of ADFS permissions to Linux permissions | 16 | Mapping of ADFS permissions to Linux permissions |
| 14 | ------------------------------------------------ | 17 | ------------------------------------------------ |
| @@ -55,3 +58,18 @@ Mapping of ADFS permissions to Linux permissions | |||
| 55 | 58 | ||
| 56 | You can therefore tailor the permission translation to whatever you | 59 | You can therefore tailor the permission translation to whatever you |
| 57 | desire the permissions should be under Linux. | 60 | desire the permissions should be under Linux. |
| 61 | |||
| 62 | RISC OS file type suffix | ||
| 63 | ------------------------ | ||
| 64 | |||
| 65 | RISC OS file types are stored in bits 19..8 of the file load address. | ||
| 66 | |||
| 67 | To enable non-RISC OS systems to be used to store files without losing | ||
| 68 | file type information, a file naming convention was devised (initially | ||
| 69 | for use with NFS) such that a hexadecimal suffix of the form ,xyz | ||
| 70 | denoted the file type: e.g. BasicFile,ffb is a BASIC (0xffb) file. This | ||
| 71 | naming convention is now also used by RISC OS emulators such as RPCEmu. | ||
| 72 | |||
| 73 | Mounting an ADFS disc with option ftsuffix=1 will cause appropriate file | ||
| 74 | type suffixes to be appended to file names read from a directory. If the | ||
| 75 | ftsuffix option is zero or omitted, no file type suffixes will be added. | ||
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h index 58588ddb178..a8a58d864f9 100644 --- a/fs/adfs/adfs.h +++ b/fs/adfs/adfs.h | |||
| @@ -50,6 +50,7 @@ struct adfs_sb_info { | |||
| 50 | gid_t s_gid; /* owner gid */ | 50 | gid_t s_gid; /* owner gid */ |
| 51 | umode_t s_owner_mask; /* ADFS owner perm -> unix perm */ | 51 | umode_t s_owner_mask; /* ADFS owner perm -> unix perm */ |
| 52 | umode_t s_other_mask; /* ADFS other perm -> unix perm */ | 52 | umode_t s_other_mask; /* ADFS other perm -> unix perm */ |
| 53 | int s_ftsuffix; /* ,xyz hex filetype suffix option */ | ||
| 53 | 54 | ||
| 54 | __u32 s_ids_per_zone; /* max. no ids in one zone */ | 55 | __u32 s_ids_per_zone; /* max. no ids in one zone */ |
| 55 | __u32 s_idlen; /* length of ID in map */ | 56 | __u32 s_idlen; /* length of ID in map */ |
| @@ -93,7 +94,7 @@ struct adfs_dir { | |||
| 93 | /* | 94 | /* |
| 94 | * This is the overall maximum name length | 95 | * This is the overall maximum name length |
| 95 | */ | 96 | */ |
| 96 | #define ADFS_MAX_NAME_LEN 256 | 97 | #define ADFS_MAX_NAME_LEN (256 + 4) /* +4 for ,xyz hex filetype suffix */ |
| 97 | struct object_info { | 98 | struct object_info { |
| 98 | __u32 parent_id; /* parent object id */ | 99 | __u32 parent_id; /* parent object id */ |
| 99 | __u32 file_id; /* object id */ | 100 | __u32 file_id; /* object id */ |
| @@ -101,10 +102,26 @@ struct object_info { | |||
| 101 | __u32 execaddr; /* execution address */ | 102 | __u32 execaddr; /* execution address */ |
| 102 | __u32 size; /* size */ | 103 | __u32 size; /* size */ |
| 103 | __u8 attr; /* RISC OS attributes */ | 104 | __u8 attr; /* RISC OS attributes */ |
| 104 | unsigned char name_len; /* name length */ | 105 | unsigned int name_len; /* name length */ |
| 105 | char name[ADFS_MAX_NAME_LEN];/* file name */ | 106 | char name[ADFS_MAX_NAME_LEN];/* file name */ |
| 107 | |||
| 108 | /* RISC OS file type (12-bit: derived from loadaddr) */ | ||
| 109 | __u16 filetype; | ||
| 106 | }; | 110 | }; |
| 107 | 111 | ||
| 112 | /* RISC OS 12-bit filetype converts to ,xyz hex filename suffix */ | ||
| 113 | static inline int append_filetype_suffix(char *buf, __u16 filetype) | ||
| 114 | { | ||
| 115 | if (filetype == -1) | ||
| 116 | return 0; | ||
| 117 | |||
| 118 | *buf++ = ','; | ||
| 119 | *buf++ = hex_asc_lo(filetype >> 8); | ||
| 120 | *buf++ = hex_asc_lo(filetype >> 4); | ||
| 121 | *buf++ = hex_asc_lo(filetype >> 0); | ||
| 122 | return 4; | ||
| 123 | } | ||
| 124 | |||
| 108 | struct adfs_dir_ops { | 125 | struct adfs_dir_ops { |
| 109 | int (*read)(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir); | 126 | int (*read)(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir); |
| 110 | int (*setpos)(struct adfs_dir *dir, unsigned int fpos); | 127 | int (*setpos)(struct adfs_dir *dir, unsigned int fpos); |
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c index bafc71222e2..4bbe853ee50 100644 --- a/fs/adfs/dir_f.c +++ b/fs/adfs/dir_f.c | |||
| @@ -52,7 +52,6 @@ static inline int adfs_readname(char *buf, char *ptr, int maxlen) | |||
| 52 | *buf++ = *ptr; | 52 | *buf++ = *ptr; |
| 53 | ptr++; | 53 | ptr++; |
| 54 | } | 54 | } |
| 55 | *buf = '\0'; | ||
| 56 | 55 | ||
| 57 | return buf - old_buf; | 56 | return buf - old_buf; |
| 58 | } | 57 | } |
| @@ -208,7 +207,8 @@ release_buffers: | |||
| 208 | * convert a disk-based directory entry to a Linux ADFS directory entry | 207 | * convert a disk-based directory entry to a Linux ADFS directory entry |
| 209 | */ | 208 | */ |
| 210 | static inline void | 209 | static inline void |
| 211 | adfs_dir2obj(struct object_info *obj, struct adfs_direntry *de) | 210 | adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj, |
| 211 | struct adfs_direntry *de) | ||
| 212 | { | 212 | { |
| 213 | obj->name_len = adfs_readname(obj->name, de->dirobname, ADFS_F_NAME_LEN); | 213 | obj->name_len = adfs_readname(obj->name, de->dirobname, ADFS_F_NAME_LEN); |
| 214 | obj->file_id = adfs_readval(de->dirinddiscadd, 3); | 214 | obj->file_id = adfs_readval(de->dirinddiscadd, 3); |
| @@ -216,6 +216,23 @@ adfs_dir2obj(struct object_info *obj, struct adfs_direntry *de) | |||
| 216 | obj->execaddr = adfs_readval(de->direxec, 4); | 216 | obj->execaddr = adfs_readval(de->direxec, 4); |
| 217 | obj->size = adfs_readval(de->dirlen, 4); | 217 | obj->size = adfs_readval(de->dirlen, 4); |
| 218 | obj->attr = de->newdiratts; | 218 | obj->attr = de->newdiratts; |
| 219 | obj->filetype = -1; | ||
| 220 | |||
| 221 | /* | ||
| 222 | * object is a file and is filetyped and timestamped? | ||
| 223 | * RISC OS 12-bit filetype is stored in load_address[19:8] | ||
| 224 | */ | ||
| 225 | if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) && | ||
| 226 | (0xfff00000 == (0xfff00000 & obj->loadaddr))) { | ||
| 227 | obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8); | ||
| 228 | |||
| 229 | /* optionally append the ,xyz hex filetype suffix */ | ||
| 230 | if (ADFS_SB(dir->sb)->s_ftsuffix) | ||
| 231 | obj->name_len += | ||
| 232 | append_filetype_suffix( | ||
| 233 | &obj->name[obj->name_len], | ||
| 234 | obj->filetype); | ||
| 235 | } | ||
| 219 | } | 236 | } |
| 220 | 237 | ||
| 221 | /* | 238 | /* |
| @@ -260,7 +277,7 @@ __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj) | |||
| 260 | if (!de.dirobname[0]) | 277 | if (!de.dirobname[0]) |
| 261 | return -ENOENT; | 278 | return -ENOENT; |
| 262 | 279 | ||
| 263 | adfs_dir2obj(obj, &de); | 280 | adfs_dir2obj(dir, obj, &de); |
| 264 | 281 | ||
| 265 | return 0; | 282 | return 0; |
| 266 | } | 283 | } |
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c index a7f41da8115..d9e3bee4e65 100644 --- a/fs/adfs/dir_fplus.c +++ b/fs/adfs/dir_fplus.c | |||
| @@ -197,6 +197,24 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj) | |||
| 197 | if (obj->name[i] == '/') | 197 | if (obj->name[i] == '/') |
| 198 | obj->name[i] = '.'; | 198 | obj->name[i] = '.'; |
| 199 | 199 | ||
| 200 | obj->filetype = -1; | ||
| 201 | |||
| 202 | /* | ||
| 203 | * object is a file and is filetyped and timestamped? | ||
| 204 | * RISC OS 12-bit filetype is stored in load_address[19:8] | ||
| 205 | */ | ||
| 206 | if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) && | ||
| 207 | (0xfff00000 == (0xfff00000 & obj->loadaddr))) { | ||
| 208 | obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8); | ||
| 209 | |||
| 210 | /* optionally append the ,xyz hex filetype suffix */ | ||
| 211 | if (ADFS_SB(dir->sb)->s_ftsuffix) | ||
| 212 | obj->name_len += | ||
| 213 | append_filetype_suffix( | ||
| 214 | &obj->name[obj->name_len], | ||
| 215 | obj->filetype); | ||
| 216 | } | ||
| 217 | |||
| 200 | dir->pos += 1; | 218 | dir->pos += 1; |
| 201 | ret = 0; | 219 | ret = 0; |
| 202 | out: | 220 | out: |
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index 16d7ef2dffe..92444e94f84 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c | |||
| @@ -78,26 +78,13 @@ static const struct address_space_operations adfs_aops = { | |||
| 78 | .bmap = _adfs_bmap | 78 | .bmap = _adfs_bmap |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | static inline unsigned int | ||
| 82 | adfs_filetype(struct inode *inode) | ||
| 83 | { | ||
| 84 | unsigned int type; | ||
| 85 | |||
| 86 | if (ADFS_I(inode)->stamped) | ||
| 87 | type = (ADFS_I(inode)->loadaddr >> 8) & 0xfff; | ||
| 88 | else | ||
| 89 | type = (unsigned int) -1; | ||
| 90 | |||
| 91 | return type; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* | 81 | /* |
| 95 | * Convert ADFS attributes and filetype to Linux permission. | 82 | * Convert ADFS attributes and filetype to Linux permission. |
| 96 | */ | 83 | */ |
| 97 | static umode_t | 84 | static umode_t |
| 98 | adfs_atts2mode(struct super_block *sb, struct inode *inode) | 85 | adfs_atts2mode(struct super_block *sb, struct inode *inode) |
| 99 | { | 86 | { |
| 100 | unsigned int filetype, attr = ADFS_I(inode)->attr; | 87 | unsigned int attr = ADFS_I(inode)->attr; |
| 101 | umode_t mode, rmask; | 88 | umode_t mode, rmask; |
| 102 | struct adfs_sb_info *asb = ADFS_SB(sb); | 89 | struct adfs_sb_info *asb = ADFS_SB(sb); |
| 103 | 90 | ||
| @@ -106,9 +93,7 @@ adfs_atts2mode(struct super_block *sb, struct inode *inode) | |||
| 106 | return S_IFDIR | S_IXUGO | mode; | 93 | return S_IFDIR | S_IXUGO | mode; |
| 107 | } | 94 | } |
| 108 | 95 | ||
| 109 | filetype = adfs_filetype(inode); | 96 | switch (ADFS_I(inode)->filetype) { |
| 110 | |||
| 111 | switch (filetype) { | ||
| 112 | case 0xfc0: /* LinkFS */ | 97 | case 0xfc0: /* LinkFS */ |
| 113 | return S_IFLNK|S_IRWXUGO; | 98 | return S_IFLNK|S_IRWXUGO; |
| 114 | 99 | ||
| @@ -277,7 +262,8 @@ adfs_iget(struct super_block *sb, struct object_info *obj) | |||
| 277 | ADFS_I(inode)->loadaddr = obj->loadaddr; | 262 | ADFS_I(inode)->loadaddr = obj->loadaddr; |
| 278 | ADFS_I(inode)->execaddr = obj->execaddr; | 263 | ADFS_I(inode)->execaddr = obj->execaddr; |
| 279 | ADFS_I(inode)->attr = obj->attr; | 264 | ADFS_I(inode)->attr = obj->attr; |
| 280 | ADFS_I(inode)->stamped = ((obj->loadaddr & 0xfff00000) == 0xfff00000); | 265 | ADFS_I(inode)->filetype = obj->filetype; |
| 266 | ADFS_I(inode)->stamped = ((obj->loadaddr & 0xfff00000) == 0xfff00000); | ||
| 281 | 267 | ||
| 282 | inode->i_mode = adfs_atts2mode(sb, inode); | 268 | inode->i_mode = adfs_atts2mode(sb, inode); |
| 283 | adfs_adfs2unix_time(&inode->i_mtime, inode); | 269 | adfs_adfs2unix_time(&inode->i_mtime, inode); |
diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 06d7388b477..c8bf36a1996 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c | |||
| @@ -138,17 +138,20 @@ static int adfs_show_options(struct seq_file *seq, struct vfsmount *mnt) | |||
| 138 | seq_printf(seq, ",ownmask=%o", asb->s_owner_mask); | 138 | seq_printf(seq, ",ownmask=%o", asb->s_owner_mask); |
| 139 | if (asb->s_other_mask != ADFS_DEFAULT_OTHER_MASK) | 139 | if (asb->s_other_mask != ADFS_DEFAULT_OTHER_MASK) |
| 140 | seq_printf(seq, ",othmask=%o", asb->s_other_mask); | 140 | seq_printf(seq, ",othmask=%o", asb->s_other_mask); |
| 141 | if (asb->s_ftsuffix != 0) | ||
| 142 | seq_printf(seq, ",ftsuffix=%u", asb->s_ftsuffix); | ||
| 141 | 143 | ||
| 142 | return 0; | 144 | return 0; |
| 143 | } | 145 | } |
| 144 | 146 | ||
| 145 | enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_err}; | 147 | enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_ftsuffix, Opt_err}; |
| 146 | 148 | ||
| 147 | static const match_table_t tokens = { | 149 | static const match_table_t tokens = { |
| 148 | {Opt_uid, "uid=%u"}, | 150 | {Opt_uid, "uid=%u"}, |
| 149 | {Opt_gid, "gid=%u"}, | 151 | {Opt_gid, "gid=%u"}, |
| 150 | {Opt_ownmask, "ownmask=%o"}, | 152 | {Opt_ownmask, "ownmask=%o"}, |
| 151 | {Opt_othmask, "othmask=%o"}, | 153 | {Opt_othmask, "othmask=%o"}, |
| 154 | {Opt_ftsuffix, "ftsuffix=%u"}, | ||
| 152 | {Opt_err, NULL} | 155 | {Opt_err, NULL} |
| 153 | }; | 156 | }; |
| 154 | 157 | ||
| @@ -189,6 +192,11 @@ static int parse_options(struct super_block *sb, char *options) | |||
| 189 | return -EINVAL; | 192 | return -EINVAL; |
| 190 | asb->s_other_mask = option; | 193 | asb->s_other_mask = option; |
| 191 | break; | 194 | break; |
| 195 | case Opt_ftsuffix: | ||
| 196 | if (match_int(args, &option)) | ||
| 197 | return -EINVAL; | ||
| 198 | asb->s_ftsuffix = option; | ||
| 199 | break; | ||
| 192 | default: | 200 | default: |
| 193 | printk("ADFS-fs: unrecognised mount option \"%s\" " | 201 | printk("ADFS-fs: unrecognised mount option \"%s\" " |
| 194 | "or missing value\n", p); | 202 | "or missing value\n", p); |
| @@ -366,6 +374,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 366 | asb->s_gid = 0; | 374 | asb->s_gid = 0; |
| 367 | asb->s_owner_mask = ADFS_DEFAULT_OWNER_MASK; | 375 | asb->s_owner_mask = ADFS_DEFAULT_OWNER_MASK; |
| 368 | asb->s_other_mask = ADFS_DEFAULT_OTHER_MASK; | 376 | asb->s_other_mask = ADFS_DEFAULT_OTHER_MASK; |
| 377 | asb->s_ftsuffix = 0; | ||
| 369 | 378 | ||
| 370 | if (parse_options(sb, data)) | 379 | if (parse_options(sb, data)) |
| 371 | goto error; | 380 | goto error; |
| @@ -445,11 +454,13 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 445 | 454 | ||
| 446 | root_obj.parent_id = root_obj.file_id = le32_to_cpu(dr->root); | 455 | root_obj.parent_id = root_obj.file_id = le32_to_cpu(dr->root); |
| 447 | root_obj.name_len = 0; | 456 | root_obj.name_len = 0; |
| 448 | root_obj.loadaddr = 0; | 457 | /* Set root object date as 01 Jan 1987 00:00:00 */ |
| 449 | root_obj.execaddr = 0; | 458 | root_obj.loadaddr = 0xfff0003f; |
| 459 | root_obj.execaddr = 0xec22c000; | ||
| 450 | root_obj.size = ADFS_NEWDIR_SIZE; | 460 | root_obj.size = ADFS_NEWDIR_SIZE; |
| 451 | root_obj.attr = ADFS_NDA_DIRECTORY | ADFS_NDA_OWNER_READ | | 461 | root_obj.attr = ADFS_NDA_DIRECTORY | ADFS_NDA_OWNER_READ | |
| 452 | ADFS_NDA_OWNER_WRITE | ADFS_NDA_PUBLIC_READ; | 462 | ADFS_NDA_OWNER_WRITE | ADFS_NDA_PUBLIC_READ; |
| 463 | root_obj.filetype = -1; | ||
| 453 | 464 | ||
| 454 | /* | 465 | /* |
| 455 | * If this is a F+ disk with variable length directories, | 466 | * If this is a F+ disk with variable length directories, |
| @@ -463,6 +474,12 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 463 | asb->s_dir = &adfs_f_dir_ops; | 474 | asb->s_dir = &adfs_f_dir_ops; |
| 464 | asb->s_namelen = ADFS_F_NAME_LEN; | 475 | asb->s_namelen = ADFS_F_NAME_LEN; |
| 465 | } | 476 | } |
| 477 | /* | ||
| 478 | * ,xyz hex filetype suffix may be added by driver | ||
| 479 | * to files that have valid RISC OS filetype | ||
| 480 | */ | ||
| 481 | if (asb->s_ftsuffix) | ||
| 482 | asb->s_namelen += 4; | ||
| 466 | 483 | ||
| 467 | sb->s_d_op = &adfs_dentry_operations; | 484 | sb->s_d_op = &adfs_dentry_operations; |
| 468 | root = adfs_iget(sb, &root_obj); | 485 | root = adfs_iget(sb, &root_obj); |
