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
);
20 adfs_readdir(struct file
*file
, struct dir_context
*ctx
)
22 struct inode
*inode
= file_inode(file
);
23 struct super_block
*sb
= inode
->i_sb
;
24 const struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
25 struct object_info obj
;
32 ret
= ops
->read(sb
, inode
->i_ino
, inode
->i_size
, &dir
);
37 if (!dir_emit_dot(file
, ctx
))
42 if (!dir_emit(ctx
, "..", 2, dir
.parent_id
, DT_DIR
))
47 read_lock(&adfs_dir_lock
);
49 ret
= ops
->setpos(&dir
, ctx
->pos
- 2);
52 while (ops
->getnext(&dir
, &obj
) == 0) {
53 if (!dir_emit(ctx
, obj
.name
, obj
.name_len
,
54 obj
.file_id
, DT_UNKNOWN
))
60 read_unlock(&adfs_dir_lock
);
68 adfs_dir_update(struct super_block
*sb
, struct object_info
*obj
, int wait
)
71 #ifdef CONFIG_ADFS_FS_RW
72 const struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
75 printk(KERN_INFO
"adfs_dir_update: object %06X in dir %06X\n",
76 obj
->file_id
, obj
->parent_id
);
83 ret
= ops
->read(sb
, obj
->parent_id
, 0, &dir
);
87 write_lock(&adfs_dir_lock
);
88 ret
= ops
->update(&dir
, obj
);
89 write_unlock(&adfs_dir_lock
);
92 int err
= ops
->sync(&dir
);
104 adfs_match(const struct qstr
*name
, struct object_info
*obj
)
108 if (name
->len
!= obj
->name_len
)
111 for (i
= 0; i
< name
->len
; i
++) {
117 if (c1
>= 'A' && c1
<= 'Z')
119 if (c2
>= 'A' && c2
<= 'Z')
129 adfs_dir_lookup_byname(struct inode
*inode
, const struct qstr
*name
, struct object_info
*obj
)
131 struct super_block
*sb
= inode
->i_sb
;
132 const struct adfs_dir_ops
*ops
= ADFS_SB(sb
)->s_dir
;
136 ret
= ops
->read(sb
, inode
->i_ino
, inode
->i_size
, &dir
);
140 if (ADFS_I(inode
)->parent_id
!= dir
.parent_id
) {
141 adfs_error(sb
, "parent directory changed under me! (%lx but got %x)\n",
142 ADFS_I(inode
)->parent_id
, dir
.parent_id
);
147 obj
->parent_id
= inode
->i_ino
;
149 read_lock(&adfs_dir_lock
);
151 ret
= ops
->setpos(&dir
, 0);
156 while (ops
->getnext(&dir
, obj
) == 0) {
157 if (adfs_match(name
, obj
)) {
164 read_unlock(&adfs_dir_lock
);
172 const struct file_operations adfs_dir_operations
= {
173 .read
= generic_read_dir
,
174 .llseek
= generic_file_llseek
,
175 .iterate
= adfs_readdir
,
176 .fsync
= generic_file_fsync
,
180 adfs_hash(const struct dentry
*parent
, struct qstr
*qstr
)
182 const unsigned int name_len
= ADFS_SB(parent
->d_sb
)->s_namelen
;
183 const unsigned char *name
;
187 if (qstr
->len
< name_len
)
191 * Truncate the name in place, avoids
192 * having to define a compare function.
194 qstr
->len
= i
= name_len
;
196 hash
= init_name_hash(parent
);
201 if (c
>= 'A' && c
<= 'Z')
204 hash
= partial_name_hash(c
, hash
);
206 qstr
->hash
= end_name_hash(hash
);
212 * Compare two names, taking note of the name length
213 * requirements of the underlying filesystem.
216 adfs_compare(const struct dentry
*dentry
,
217 unsigned int len
, const char *str
, const struct qstr
*name
)
221 if (len
!= name
->len
)
224 for (i
= 0; i
< name
->len
; i
++) {
230 if (a
>= 'A' && a
<= 'Z')
232 if (b
>= 'A' && b
<= 'Z')
241 const struct dentry_operations adfs_dentry_operations
= {
243 .d_compare
= adfs_compare
,
246 static struct dentry
*
247 adfs_lookup(struct inode
*dir
, struct dentry
*dentry
, unsigned int flags
)
249 struct inode
*inode
= NULL
;
250 struct object_info obj
;
253 error
= adfs_dir_lookup_byname(dir
, &dentry
->d_name
, &obj
);
256 * This only returns NULL if get_empty_inode
259 inode
= adfs_iget(dir
->i_sb
, &obj
);
261 inode
= ERR_PTR(-EACCES
);
262 } else if (error
!= -ENOENT
) {
263 inode
= ERR_PTR(error
);
265 return d_splice_alias(inode
, dentry
);
269 * directories can handle most operations...
271 const struct inode_operations adfs_dir_inode_operations
= {
272 .lookup
= adfs_lookup
,
273 .setattr
= adfs_notify_change
,