diff options
| -rw-r--r-- | fs/adfs/adfs.h | 14 | ||||
| -rw-r--r-- | fs/adfs/dir.c | 137 | ||||
| -rw-r--r-- | fs/adfs/dir_f.c | 43 | ||||
| -rw-r--r-- | fs/adfs/dir_fplus.c | 24 |
4 files changed, 89 insertions, 129 deletions
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h index c76db75f02aa..804c6a77c5db 100644 --- a/fs/adfs/adfs.h +++ b/fs/adfs/adfs.h | |||
| @@ -113,19 +113,6 @@ struct object_info { | |||
| 113 | __u16 filetype; | 113 | __u16 filetype; |
| 114 | }; | 114 | }; |
| 115 | 115 | ||
| 116 | /* RISC OS 12-bit filetype converts to ,xyz hex filename suffix */ | ||
| 117 | static inline int append_filetype_suffix(char *buf, __u16 filetype) | ||
| 118 | { | ||
| 119 | if (filetype == 0xffff) /* no explicit 12-bit file type was set */ | ||
| 120 | return 0; | ||
| 121 | |||
| 122 | *buf++ = ','; | ||
| 123 | *buf++ = hex_asc_lo(filetype >> 8); | ||
| 124 | *buf++ = hex_asc_lo(filetype >> 4); | ||
| 125 | *buf++ = hex_asc_lo(filetype >> 0); | ||
| 126 | return 4; | ||
| 127 | } | ||
| 128 | |||
| 129 | struct adfs_dir_ops { | 116 | struct adfs_dir_ops { |
| 130 | int (*read)(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir); | 117 | int (*read)(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir); |
| 131 | int (*setpos)(struct adfs_dir *dir, unsigned int fpos); | 118 | int (*setpos)(struct adfs_dir *dir, unsigned int fpos); |
| @@ -172,6 +159,7 @@ extern const struct dentry_operations adfs_dentry_operations; | |||
| 172 | extern const struct adfs_dir_ops adfs_f_dir_ops; | 159 | extern const struct adfs_dir_ops adfs_f_dir_ops; |
| 173 | extern const struct adfs_dir_ops adfs_fplus_dir_ops; | 160 | extern const struct adfs_dir_ops adfs_fplus_dir_ops; |
| 174 | 161 | ||
| 162 | void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj); | ||
| 175 | extern int adfs_dir_update(struct super_block *sb, struct object_info *obj, | 163 | extern int adfs_dir_update(struct super_block *sb, struct object_info *obj, |
| 176 | int wait); | 164 | int wait); |
| 177 | 165 | ||
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index e18eff854e1a..fe39310c1a0a 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c | |||
| @@ -16,6 +16,50 @@ | |||
| 16 | */ | 16 | */ |
| 17 | static DEFINE_RWLOCK(adfs_dir_lock); | 17 | static DEFINE_RWLOCK(adfs_dir_lock); |
| 18 | 18 | ||
| 19 | void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj) | ||
| 20 | { | ||
| 21 | unsigned int dots, i; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * RISC OS allows the use of '/' in directory entry names, so we need | ||
| 25 | * to fix these up. '/' is typically used for FAT compatibility to | ||
| 26 | * represent '.', so do the same conversion here. In any case, '.' | ||
| 27 | * will never be in a RISC OS name since it is used as the pathname | ||
| 28 | * separator. Handle the case where we may generate a '.' or '..' | ||
| 29 | * name, replacing the first character with '^' (the RISC OS "parent | ||
| 30 | * directory" character.) | ||
| 31 | */ | ||
| 32 | for (i = dots = 0; i < obj->name_len; i++) | ||
| 33 | if (obj->name[i] == '/') { | ||
| 34 | obj->name[i] = '.'; | ||
| 35 | dots++; | ||
| 36 | } | ||
| 37 | |||
| 38 | if (obj->name_len <= 2 && dots == obj->name_len) | ||
| 39 | obj->name[0] = '^'; | ||
| 40 | |||
| 41 | obj->filetype = -1; | ||
| 42 | |||
| 43 | /* | ||
| 44 | * object is a file and is filetyped and timestamped? | ||
| 45 | * RISC OS 12-bit filetype is stored in load_address[19:8] | ||
| 46 | */ | ||
| 47 | if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) && | ||
| 48 | (0xfff00000 == (0xfff00000 & obj->loadaddr))) { | ||
| 49 | obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8); | ||
| 50 | |||
| 51 | /* optionally append the ,xyz hex filetype suffix */ | ||
| 52 | if (ADFS_SB(dir->sb)->s_ftsuffix) { | ||
| 53 | __u16 filetype = obj->filetype; | ||
| 54 | |||
| 55 | obj->name[obj->name_len++] = ','; | ||
| 56 | obj->name[obj->name_len++] = hex_asc_lo(filetype >> 8); | ||
| 57 | obj->name[obj->name_len++] = hex_asc_lo(filetype >> 4); | ||
| 58 | obj->name[obj->name_len++] = hex_asc_lo(filetype >> 0); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 19 | static int | 63 | static int |
| 20 | adfs_readdir(struct file *file, struct dir_context *ctx) | 64 | adfs_readdir(struct file *file, struct dir_context *ctx) |
| 21 | { | 65 | { |
| @@ -100,37 +144,36 @@ out: | |||
| 100 | return ret; | 144 | return ret; |
| 101 | } | 145 | } |
| 102 | 146 | ||
| 103 | static int | 147 | static unsigned char adfs_tolower(unsigned char c) |
| 104 | adfs_match(const struct qstr *name, struct object_info *obj) | ||
| 105 | { | 148 | { |
| 106 | int i; | 149 | if (c >= 'A' && c <= 'Z') |
| 107 | 150 | c += 'a' - 'A'; | |
| 108 | if (name->len != obj->name_len) | 151 | return c; |
| 109 | return 0; | 152 | } |
| 110 | 153 | ||
| 111 | for (i = 0; i < name->len; i++) { | 154 | static int __adfs_compare(const unsigned char *qstr, u32 qlen, |
| 112 | char c1, c2; | 155 | const char *str, u32 len) |
| 156 | { | ||
| 157 | u32 i; | ||
| 113 | 158 | ||
| 114 | c1 = name->name[i]; | 159 | if (qlen != len) |
| 115 | c2 = obj->name[i]; | 160 | return 1; |
| 116 | 161 | ||
| 117 | if (c1 >= 'A' && c1 <= 'Z') | 162 | for (i = 0; i < qlen; i++) |
| 118 | c1 += 'a' - 'A'; | 163 | if (adfs_tolower(qstr[i]) != adfs_tolower(str[i])) |
| 119 | if (c2 >= 'A' && c2 <= 'Z') | 164 | return 1; |
| 120 | c2 += 'a' - 'A'; | ||
| 121 | 165 | ||
| 122 | if (c1 != c2) | 166 | return 0; |
| 123 | return 0; | ||
| 124 | } | ||
| 125 | return 1; | ||
| 126 | } | 167 | } |
| 127 | 168 | ||
| 128 | static int | 169 | static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr, |
| 129 | adfs_dir_lookup_byname(struct inode *inode, const struct qstr *name, struct object_info *obj) | 170 | struct object_info *obj) |
| 130 | { | 171 | { |
| 131 | struct super_block *sb = inode->i_sb; | 172 | struct super_block *sb = inode->i_sb; |
| 132 | const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir; | 173 | const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir; |
| 174 | const unsigned char *name; | ||
| 133 | struct adfs_dir dir; | 175 | struct adfs_dir dir; |
| 176 | u32 name_len; | ||
| 134 | int ret; | 177 | int ret; |
| 135 | 178 | ||
| 136 | ret = ops->read(sb, inode->i_ino, inode->i_size, &dir); | 179 | ret = ops->read(sb, inode->i_ino, inode->i_size, &dir); |
| @@ -153,8 +196,10 @@ adfs_dir_lookup_byname(struct inode *inode, const struct qstr *name, struct obje | |||
| 153 | goto unlock_out; | 196 | goto unlock_out; |
| 154 | 197 | ||
| 155 | ret = -ENOENT; | 198 | ret = -ENOENT; |
| 199 | name = qstr->name; | ||
| 200 | name_len = qstr->len; | ||
| 156 | while (ops->getnext(&dir, obj) == 0) { | 201 | while (ops->getnext(&dir, obj) == 0) { |
| 157 | if (adfs_match(name, obj)) { | 202 | if (!__adfs_compare(name, name_len, obj->name, obj->name_len)) { |
| 158 | ret = 0; | 203 | ret = 0; |
| 159 | break; | 204 | break; |
| 160 | } | 205 | } |
| @@ -179,30 +224,18 @@ const struct file_operations adfs_dir_operations = { | |||
| 179 | static int | 224 | static int |
| 180 | adfs_hash(const struct dentry *parent, struct qstr *qstr) | 225 | adfs_hash(const struct dentry *parent, struct qstr *qstr) |
| 181 | { | 226 | { |
| 182 | const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen; | ||
| 183 | const unsigned char *name; | 227 | const unsigned char *name; |
| 184 | unsigned long hash; | 228 | unsigned long hash; |
| 185 | int i; | 229 | u32 len; |
| 186 | 230 | ||
| 187 | if (qstr->len < name_len) | 231 | if (qstr->len > ADFS_SB(parent->d_sb)->s_namelen) |
| 188 | return 0; | 232 | return -ENAMETOOLONG; |
| 189 | 233 | ||
| 190 | /* | 234 | len = qstr->len; |
| 191 | * Truncate the name in place, avoids | ||
| 192 | * having to define a compare function. | ||
| 193 | */ | ||
| 194 | qstr->len = i = name_len; | ||
| 195 | name = qstr->name; | 235 | name = qstr->name; |
| 196 | hash = init_name_hash(parent); | 236 | hash = init_name_hash(parent); |
| 197 | while (i--) { | 237 | while (len--) |
| 198 | char c; | 238 | hash = partial_name_hash(adfs_tolower(*name++), hash); |
| 199 | |||
| 200 | c = *name++; | ||
| 201 | if (c >= 'A' && c <= 'Z') | ||
| 202 | c += 'a' - 'A'; | ||
| 203 | |||
| 204 | hash = partial_name_hash(c, hash); | ||
| 205 | } | ||
| 206 | qstr->hash = end_name_hash(hash); | 239 | qstr->hash = end_name_hash(hash); |
| 207 | 240 | ||
| 208 | return 0; | 241 | return 0; |
| @@ -212,30 +245,10 @@ adfs_hash(const struct dentry *parent, struct qstr *qstr) | |||
| 212 | * Compare two names, taking note of the name length | 245 | * Compare two names, taking note of the name length |
| 213 | * requirements of the underlying filesystem. | 246 | * requirements of the underlying filesystem. |
| 214 | */ | 247 | */ |
| 215 | static int | 248 | static int adfs_compare(const struct dentry *dentry, unsigned int len, |
| 216 | adfs_compare(const struct dentry *dentry, | 249 | const char *str, const struct qstr *qstr) |
| 217 | unsigned int len, const char *str, const struct qstr *name) | ||
| 218 | { | 250 | { |
| 219 | int i; | 251 | return __adfs_compare(qstr->name, qstr->len, str, len); |
| 220 | |||
| 221 | if (len != name->len) | ||
| 222 | return 1; | ||
| 223 | |||
| 224 | for (i = 0; i < name->len; i++) { | ||
| 225 | char a, b; | ||
| 226 | |||
| 227 | a = str[i]; | ||
| 228 | b = name->name[i]; | ||
| 229 | |||
| 230 | if (a >= 'A' && a <= 'Z') | ||
| 231 | a += 'a' - 'A'; | ||
| 232 | if (b >= 'A' && b <= 'Z') | ||
| 233 | b += 'a' - 'A'; | ||
| 234 | |||
| 235 | if (a != b) | ||
| 236 | return 1; | ||
| 237 | } | ||
| 238 | return 0; | ||
| 239 | } | 252 | } |
| 240 | 253 | ||
| 241 | const struct dentry_operations adfs_dentry_operations = { | 254 | const struct dentry_operations adfs_dentry_operations = { |
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c index 382c9d7ad375..693f69ed3de3 100644 --- a/fs/adfs/dir_f.c +++ b/fs/adfs/dir_f.c | |||
| @@ -47,21 +47,6 @@ static inline void adfs_writeval(unsigned char *p, int len, unsigned int val) | |||
| 47 | } | 47 | } |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static inline int adfs_readname(char *buf, char *ptr, int maxlen) | ||
| 51 | { | ||
| 52 | char *old_buf = buf; | ||
| 53 | |||
| 54 | while ((unsigned char)*ptr >= ' ' && maxlen--) { | ||
| 55 | if (*ptr == '/') | ||
| 56 | *buf++ = '.'; | ||
| 57 | else | ||
| 58 | *buf++ = *ptr; | ||
| 59 | ptr++; | ||
| 60 | } | ||
| 61 | |||
| 62 | return buf - old_buf; | ||
| 63 | } | ||
| 64 | |||
| 65 | #define ror13(v) ((v >> 13) | (v << 19)) | 50 | #define ror13(v) ((v >> 13) | (v << 19)) |
| 66 | 51 | ||
| 67 | #define dir_u8(idx) \ | 52 | #define dir_u8(idx) \ |
| @@ -216,29 +201,23 @@ static inline void | |||
| 216 | adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj, | 201 | adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj, |
| 217 | struct adfs_direntry *de) | 202 | struct adfs_direntry *de) |
| 218 | { | 203 | { |
| 219 | obj->name_len = adfs_readname(obj->name, de->dirobname, ADFS_F_NAME_LEN); | 204 | unsigned int name_len; |
| 205 | |||
| 206 | for (name_len = 0; name_len < ADFS_F_NAME_LEN; name_len++) { | ||
| 207 | if (de->dirobname[name_len] < ' ') | ||
| 208 | break; | ||
| 209 | |||
| 210 | obj->name[name_len] = de->dirobname[name_len]; | ||
| 211 | } | ||
| 212 | |||
| 213 | obj->name_len = name_len; | ||
| 220 | obj->file_id = adfs_readval(de->dirinddiscadd, 3); | 214 | obj->file_id = adfs_readval(de->dirinddiscadd, 3); |
| 221 | obj->loadaddr = adfs_readval(de->dirload, 4); | 215 | obj->loadaddr = adfs_readval(de->dirload, 4); |
| 222 | obj->execaddr = adfs_readval(de->direxec, 4); | 216 | obj->execaddr = adfs_readval(de->direxec, 4); |
| 223 | obj->size = adfs_readval(de->dirlen, 4); | 217 | obj->size = adfs_readval(de->dirlen, 4); |
| 224 | obj->attr = de->newdiratts; | 218 | obj->attr = de->newdiratts; |
| 225 | obj->filetype = -1; | ||
| 226 | 219 | ||
| 227 | /* | 220 | adfs_object_fixup(dir, obj); |
| 228 | * object is a file and is filetyped and timestamped? | ||
| 229 | * RISC OS 12-bit filetype is stored in load_address[19:8] | ||
| 230 | */ | ||
| 231 | if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) && | ||
| 232 | (0xfff00000 == (0xfff00000 & obj->loadaddr))) { | ||
| 233 | obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8); | ||
| 234 | |||
| 235 | /* optionally append the ,xyz hex filetype suffix */ | ||
| 236 | if (ADFS_SB(dir->sb)->s_ftsuffix) | ||
| 237 | obj->name_len += | ||
| 238 | append_filetype_suffix( | ||
| 239 | &obj->name[obj->name_len], | ||
| 240 | obj->filetype); | ||
| 241 | } | ||
| 242 | } | 221 | } |
| 243 | 222 | ||
| 244 | /* | 223 | /* |
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c index c92cfb638c18..97b9f28f459b 100644 --- a/fs/adfs/dir_fplus.c +++ b/fs/adfs/dir_fplus.c | |||
| @@ -169,7 +169,7 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj) | |||
| 169 | (struct adfs_bigdirheader *) dir->bh_fplus[0]->b_data; | 169 | (struct adfs_bigdirheader *) dir->bh_fplus[0]->b_data; |
| 170 | struct adfs_bigdirentry bde; | 170 | struct adfs_bigdirentry bde; |
| 171 | unsigned int offset; | 171 | unsigned int offset; |
| 172 | int i, ret = -ENOENT; | 172 | int ret = -ENOENT; |
| 173 | 173 | ||
| 174 | if (dir->pos >= le32_to_cpu(h->bigdirentries)) | 174 | if (dir->pos >= le32_to_cpu(h->bigdirentries)) |
| 175 | goto out; | 175 | goto out; |
| @@ -193,27 +193,7 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj) | |||
| 193 | offset += le32_to_cpu(bde.bigdirobnameptr); | 193 | offset += le32_to_cpu(bde.bigdirobnameptr); |
| 194 | 194 | ||
| 195 | dir_memcpy(dir, offset, obj->name, obj->name_len); | 195 | dir_memcpy(dir, offset, obj->name, obj->name_len); |
| 196 | for (i = 0; i < obj->name_len; i++) | 196 | adfs_object_fixup(dir, obj); |
| 197 | if (obj->name[i] == '/') | ||
| 198 | obj->name[i] = '.'; | ||
| 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 | 197 | ||
| 218 | dir->pos += 1; | 198 | dir->pos += 1; |
| 219 | ret = 0; | 199 | ret = 0; |
