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
12 #include <linux/config.h>
13 #include <linux/errno.h>
15 #include <linux/adfs_fs.h>
16 #include <linux/time.h>
17 #include <linux/stat.h>
18 #include <linux/spinlock.h>
19 #include <linux/smp_lock.h>
20 #include <linux/buffer_head.h> /* for file_fsync() */
25 * For future. This should probably be per-directory.
27 static DEFINE_RWLOCK(adfs_dir_lock
);
30 adfs_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
32 struct inode
*inode
= filp
->f_dentry
->d_inode
;
33 struct super_block
*sb
= inode
->i_sb
;
34 struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
35 struct object_info obj
;
41 if (filp
->f_pos
>> 32)
44 ret
= ops
->read(sb
, inode
->i_ino
, inode
->i_size
, &dir
);
48 switch ((unsigned long)filp
->f_pos
) {
50 if (filldir(dirent
, ".", 1, 0, inode
->i_ino
, DT_DIR
) < 0)
55 if (filldir(dirent
, "..", 2, 1, dir
.parent_id
, DT_DIR
) < 0)
63 read_lock(&adfs_dir_lock
);
65 ret
= ops
->setpos(&dir
, filp
->f_pos
- 2);
68 while (ops
->getnext(&dir
, &obj
) == 0) {
69 if (filldir(dirent
, obj
.name
, obj
.name_len
,
70 filp
->f_pos
, obj
.file_id
, DT_UNKNOWN
) < 0)
76 read_unlock(&adfs_dir_lock
);
87 adfs_dir_update(struct super_block
*sb
, struct object_info
*obj
)
90 #ifdef CONFIG_ADFS_FS_RW
91 struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
94 printk(KERN_INFO
"adfs_dir_update: object %06X in dir %06X\n",
95 obj
->file_id
, obj
->parent_id
);
102 ret
= ops
->read(sb
, obj
->parent_id
, 0, &dir
);
106 write_lock(&adfs_dir_lock
);
107 ret
= ops
->update(&dir
, obj
);
108 write_unlock(&adfs_dir_lock
);
117 adfs_match(struct qstr
*name
, struct object_info
*obj
)
121 if (name
->len
!= obj
->name_len
)
124 for (i
= 0; i
< name
->len
; i
++) {
130 if (c1
>= 'A' && c1
<= 'Z')
132 if (c2
>= 'A' && c2
<= 'Z')
142 adfs_dir_lookup_byname(struct inode
*inode
, struct qstr
*name
, struct object_info
*obj
)
144 struct super_block
*sb
= inode
->i_sb
;
145 struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
149 ret
= ops
->read(sb
, inode
->i_ino
, inode
->i_size
, &dir
);
153 if (ADFS_I(inode
)->parent_id
!= dir
.parent_id
) {
154 adfs_error(sb
, "parent directory changed under me! (%lx but got %lx)\n",
155 ADFS_I(inode
)->parent_id
, dir
.parent_id
);
160 obj
->parent_id
= inode
->i_ino
;
163 * '.' is handled by reserved_lookup() in fs/namei.c
165 if (name
->len
== 2 && name
->name
[0] == '.' && name
->name
[1] == '.') {
167 * Currently unable to fill in the rest of 'obj',
168 * but this is better than nothing. We need to
169 * ascend one level to find it's parent.
172 obj
->file_id
= obj
->parent_id
;
176 read_lock(&adfs_dir_lock
);
178 ret
= ops
->setpos(&dir
, 0);
183 while (ops
->getnext(&dir
, obj
) == 0) {
184 if (adfs_match(name
, obj
)) {
191 read_unlock(&adfs_dir_lock
);
199 struct file_operations adfs_dir_operations
= {
200 .read
= generic_read_dir
,
201 .readdir
= adfs_readdir
,
206 adfs_hash(struct dentry
*parent
, struct qstr
*qstr
)
208 const unsigned int name_len
= ADFS_SB(parent
->d_sb
)->s_namelen
;
209 const unsigned char *name
;
213 if (qstr
->len
< name_len
)
217 * Truncate the name in place, avoids
218 * having to define a compare function.
220 qstr
->len
= i
= name_len
;
222 hash
= init_name_hash();
227 if (c
>= 'A' && c
<= 'Z')
230 hash
= partial_name_hash(c
, hash
);
232 qstr
->hash
= end_name_hash(hash
);
238 * Compare two names, taking note of the name length
239 * requirements of the underlying filesystem.
242 adfs_compare(struct dentry
*parent
, struct qstr
*entry
, struct qstr
*name
)
246 if (entry
->len
!= name
->len
)
249 for (i
= 0; i
< name
->len
; i
++) {
255 if (a
>= 'A' && a
<= 'Z')
257 if (b
>= 'A' && b
<= 'Z')
266 struct dentry_operations adfs_dentry_operations
= {
268 .d_compare
= adfs_compare
,
271 static struct dentry
*
272 adfs_lookup(struct inode
*dir
, struct dentry
*dentry
, struct nameidata
*nd
)
274 struct inode
*inode
= NULL
;
275 struct object_info obj
;
278 dentry
->d_op
= &adfs_dentry_operations
;
280 error
= adfs_dir_lookup_byname(dir
, &dentry
->d_name
, &obj
);
284 * This only returns NULL if get_empty_inode
287 inode
= adfs_iget(dir
->i_sb
, &obj
);
292 d_add(dentry
, inode
);
293 return ERR_PTR(error
);
297 * directories can handle most operations...
299 struct inode_operations adfs_dir_inode_operations
= {
300 .lookup
= adfs_lookup
,
301 .setattr
= adfs_notify_change
,