aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/adfs/adfs.h14
-rw-r--r--fs/adfs/dir.c137
-rw-r--r--fs/adfs/dir_f.c43
-rw-r--r--fs/adfs/dir_fplus.c24
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 */
117static 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
129struct adfs_dir_ops { 116struct 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;
172extern const struct adfs_dir_ops adfs_f_dir_ops; 159extern const struct adfs_dir_ops adfs_f_dir_ops;
173extern const struct adfs_dir_ops adfs_fplus_dir_ops; 160extern const struct adfs_dir_ops adfs_fplus_dir_ops;
174 161
162void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj);
175extern int adfs_dir_update(struct super_block *sb, struct object_info *obj, 163extern 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 */
17static DEFINE_RWLOCK(adfs_dir_lock); 17static DEFINE_RWLOCK(adfs_dir_lock);
18 18
19void 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
19static int 63static int
20adfs_readdir(struct file *file, struct dir_context *ctx) 64adfs_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
103static int 147static unsigned char adfs_tolower(unsigned char c)
104adfs_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++) { 154static 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
128static int 169static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
129adfs_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 = {
179static int 224static int
180adfs_hash(const struct dentry *parent, struct qstr *qstr) 225adfs_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 */
215static int 248static int adfs_compare(const struct dentry *dentry, unsigned int len,
216adfs_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
241const struct dentry_operations adfs_dentry_operations = { 254const 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
50static 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
216adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj, 201adfs_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;