4 * Copyright (C) 1999-2000 Russell King
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Common directory handling for ADFS
15 * For future. This should probably be per-directory.
17 static DEFINE_RWLOCK(adfs_dir_lock
);
19 void adfs_object_fixup(struct adfs_dir
*dir
, struct object_info
*obj
)
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.)
32 for (i
= dots
= 0; i
< obj
->name_len
; i
++)
33 if (obj
->name
[i
] == '/') {
38 if (obj
->name_len
<= 2 && dots
== obj
->name_len
)
44 * object is a file and is filetyped and timestamped?
45 * RISC OS 12-bit filetype is stored in load_address[19:8]
47 if ((0 == (obj
->attr
& ADFS_NDA_DIRECTORY
)) &&
48 (0xfff00000 == (0xfff00000 & obj
->loadaddr
))) {
49 obj
->filetype
= (__u16
) ((0x000fff00 & obj
->loadaddr
) >> 8);
51 /* optionally append the ,xyz hex filetype suffix */
52 if (ADFS_SB(dir
->sb
)->s_ftsuffix
) {
53 __u16 filetype
= obj
->filetype
;
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);
64 adfs_readdir(struct file
*file
, struct dir_context
*ctx
)
66 struct inode
*inode
= file_inode(file
);
67 struct super_block
*sb
= inode
->i_sb
;
68 const struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
69 struct object_info obj
;
76 ret
= ops
->read(sb
, inode
->i_ino
, inode
->i_size
, &dir
);
81 if (!dir_emit_dot(file
, ctx
))
86 if (!dir_emit(ctx
, "..", 2, dir
.parent_id
, DT_DIR
))
91 read_lock(&adfs_dir_lock
);
93 ret
= ops
->setpos(&dir
, ctx
->pos
- 2);
96 while (ops
->getnext(&dir
, &obj
) == 0) {
97 if (!dir_emit(ctx
, obj
.name
, obj
.name_len
,
98 obj
.file_id
, DT_UNKNOWN
))
104 read_unlock(&adfs_dir_lock
);
112 adfs_dir_update(struct super_block
*sb
, struct object_info
*obj
, int wait
)
115 #ifdef CONFIG_ADFS_FS_RW
116 const struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
119 printk(KERN_INFO
"adfs_dir_update: object %06X in dir %06X\n",
120 obj
->file_id
, obj
->parent_id
);
127 ret
= ops
->read(sb
, obj
->parent_id
, 0, &dir
);
131 write_lock(&adfs_dir_lock
);
132 ret
= ops
->update(&dir
, obj
);
133 write_unlock(&adfs_dir_lock
);
136 int err
= ops
->sync(&dir
);
147 static unsigned char adfs_tolower(unsigned char c
)
149 if (c
>= 'A' && c
<= 'Z')
154 static int __adfs_compare(const unsigned char *qstr
, u32 qlen
,
155 const char *str
, u32 len
)
162 for (i
= 0; i
< qlen
; i
++)
163 if (adfs_tolower(qstr
[i
]) != adfs_tolower(str
[i
]))
169 static int adfs_dir_lookup_byname(struct inode
*inode
, const struct qstr
*qstr
,
170 struct object_info
*obj
)
172 struct super_block
*sb
= inode
->i_sb
;
173 const struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
174 const unsigned char *name
;
179 ret
= ops
->read(sb
, inode
->i_ino
, inode
->i_size
, &dir
);
183 if (ADFS_I(inode
)->parent_id
!= dir
.parent_id
) {
184 adfs_error(sb
, "parent directory changed under me! (%lx but got %x)\n",
185 ADFS_I(inode
)->parent_id
, dir
.parent_id
);
190 obj
->parent_id
= inode
->i_ino
;
192 read_lock(&adfs_dir_lock
);
194 ret
= ops
->setpos(&dir
, 0);
200 name_len
= qstr
->len
;
201 while (ops
->getnext(&dir
, obj
) == 0) {
202 if (!__adfs_compare(name
, name_len
, obj
->name
, obj
->name_len
)) {
209 read_unlock(&adfs_dir_lock
);
217 const struct file_operations adfs_dir_operations
= {
218 .read
= generic_read_dir
,
219 .llseek
= generic_file_llseek
,
220 .iterate
= adfs_readdir
,
221 .fsync
= generic_file_fsync
,
225 adfs_hash(const struct dentry
*parent
, struct qstr
*qstr
)
227 const unsigned char *name
;
231 if (qstr
->len
> ADFS_SB(parent
->d_sb
)->s_namelen
)
232 return -ENAMETOOLONG
;
236 hash
= init_name_hash(parent
);
238 hash
= partial_name_hash(adfs_tolower(*name
++), hash
);
239 qstr
->hash
= end_name_hash(hash
);
245 * Compare two names, taking note of the name length
246 * requirements of the underlying filesystem.
248 static int adfs_compare(const struct dentry
*dentry
, unsigned int len
,
249 const char *str
, const struct qstr
*qstr
)
251 return __adfs_compare(qstr
->name
, qstr
->len
, str
, len
);
254 const struct dentry_operations adfs_dentry_operations
= {
256 .d_compare
= adfs_compare
,
259 static struct dentry
*
260 adfs_lookup(struct inode
*dir
, struct dentry
*dentry
, unsigned int flags
)
262 struct inode
*inode
= NULL
;
263 struct object_info obj
;
266 error
= adfs_dir_lookup_byname(dir
, &dentry
->d_name
, &obj
);
269 * This only returns NULL if get_empty_inode
272 inode
= adfs_iget(dir
->i_sb
, &obj
);
274 inode
= ERR_PTR(-EACCES
);
275 } else if (error
!= -ENOENT
) {
276 inode
= ERR_PTR(error
);
278 return d_splice_alias(inode
, dentry
);
282 * directories can handle most operations...
284 const struct inode_operations adfs_dir_inode_operations
= {
285 .lookup
= adfs_lookup
,
286 .setattr
= adfs_notify_change
,