3 * BFS directory operations.
4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
5 * Made endianness-clean by Andrew Stribblehill <ads@wompom.org> 2005
8 #include <linux/time.h>
9 #include <linux/string.h>
11 #include <linux/smp_lock.h>
12 #include <linux/buffer_head.h>
13 #include <linux/sched.h>
19 #define dprintf(x...) printf(x)
24 static int bfs_add_entry(struct inode
* dir
, const unsigned char * name
, int namelen
, int ino
);
25 static struct buffer_head
* bfs_find_entry(struct inode
* dir
,
26 const unsigned char * name
, int namelen
, struct bfs_dirent
** res_dir
);
28 static int bfs_readdir(struct file
* f
, void * dirent
, filldir_t filldir
)
30 struct inode
* dir
= f
->f_dentry
->d_inode
;
31 struct buffer_head
* bh
;
32 struct bfs_dirent
* de
;
38 if (f
->f_pos
& (BFS_DIRENT_SIZE
-1)) {
39 printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f
->f_pos
,
40 dir
->i_sb
->s_id
, dir
->i_ino
);
45 while (f
->f_pos
< dir
->i_size
) {
46 offset
= f
->f_pos
& (BFS_BSIZE
-1);
47 block
= BFS_I(dir
)->i_sblock
+ (f
->f_pos
>> BFS_BSIZE_BITS
);
48 bh
= sb_bread(dir
->i_sb
, block
);
50 f
->f_pos
+= BFS_BSIZE
- offset
;
54 de
= (struct bfs_dirent
*)(bh
->b_data
+ offset
);
56 int size
= strnlen(de
->name
, BFS_NAMELEN
);
57 if (filldir(dirent
, de
->name
, size
, f
->f_pos
, le16_to_cpu(de
->ino
), DT_UNKNOWN
) < 0) {
63 offset
+= BFS_DIRENT_SIZE
;
64 f
->f_pos
+= BFS_DIRENT_SIZE
;
65 } while (offset
< BFS_BSIZE
&& f
->f_pos
< dir
->i_size
);
73 struct file_operations bfs_dir_operations
= {
74 .read
= generic_read_dir
,
75 .readdir
= bfs_readdir
,
79 extern void dump_imap(const char *, struct super_block
*);
81 static int bfs_create(struct inode
* dir
, struct dentry
* dentry
, int mode
,
86 struct super_block
* s
= dir
->i_sb
;
87 struct bfs_sb_info
* info
= BFS_SB(s
);
94 ino
= find_first_zero_bit(info
->si_imap
, info
->si_lasti
);
95 if (ino
> info
->si_lasti
) {
100 set_bit(ino
, info
->si_imap
);
102 inode
->i_uid
= current
->fsuid
;
103 inode
->i_gid
= (dir
->i_mode
& S_ISGID
) ? dir
->i_gid
: current
->fsgid
;
104 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME_SEC
;
105 inode
->i_blocks
= inode
->i_blksize
= 0;
106 inode
->i_op
= &bfs_file_inops
;
107 inode
->i_fop
= &bfs_file_operations
;
108 inode
->i_mapping
->a_ops
= &bfs_aops
;
109 inode
->i_mode
= mode
;
111 BFS_I(inode
)->i_dsk_ino
= ino
;
112 BFS_I(inode
)->i_sblock
= 0;
113 BFS_I(inode
)->i_eblock
= 0;
114 insert_inode_hash(inode
);
115 mark_inode_dirty(inode
);
116 dump_imap("create",s
);
118 err
= bfs_add_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, inode
->i_ino
);
121 mark_inode_dirty(inode
);
127 d_instantiate(dentry
, inode
);
131 static struct dentry
* bfs_lookup(struct inode
* dir
, struct dentry
* dentry
, struct nameidata
*nd
)
133 struct inode
* inode
= NULL
;
134 struct buffer_head
* bh
;
135 struct bfs_dirent
* de
;
137 if (dentry
->d_name
.len
> BFS_NAMELEN
)
138 return ERR_PTR(-ENAMETOOLONG
);
141 bh
= bfs_find_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, &de
);
143 unsigned long ino
= (unsigned long)le16_to_cpu(de
->ino
);
145 inode
= iget(dir
->i_sb
, ino
);
148 return ERR_PTR(-EACCES
);
152 d_add(dentry
, inode
);
156 static int bfs_link(struct dentry
* old
, struct inode
* dir
, struct dentry
* new)
158 struct inode
* inode
= old
->d_inode
;
162 err
= bfs_add_entry(dir
, new->d_name
.name
, new->d_name
.len
, inode
->i_ino
);
168 inode
->i_ctime
= CURRENT_TIME_SEC
;
169 mark_inode_dirty(inode
);
170 atomic_inc(&inode
->i_count
);
171 d_instantiate(new, inode
);
177 static int bfs_unlink(struct inode
* dir
, struct dentry
* dentry
)
180 struct inode
* inode
;
181 struct buffer_head
* bh
;
182 struct bfs_dirent
* de
;
184 inode
= dentry
->d_inode
;
186 bh
= bfs_find_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, &de
);
187 if (!bh
|| le16_to_cpu(de
->ino
) != inode
->i_ino
)
190 if (!inode
->i_nlink
) {
191 printf("unlinking non-existent file %s:%lu (nlink=%d)\n", inode
->i_sb
->s_id
,
192 inode
->i_ino
, inode
->i_nlink
);
196 mark_buffer_dirty(bh
);
197 dir
->i_ctime
= dir
->i_mtime
= CURRENT_TIME_SEC
;
198 mark_inode_dirty(dir
);
200 inode
->i_ctime
= dir
->i_ctime
;
201 mark_inode_dirty(inode
);
210 static int bfs_rename(struct inode
* old_dir
, struct dentry
* old_dentry
,
211 struct inode
* new_dir
, struct dentry
* new_dentry
)
213 struct inode
* old_inode
, * new_inode
;
214 struct buffer_head
* old_bh
, * new_bh
;
215 struct bfs_dirent
* old_de
, * new_de
;
218 old_bh
= new_bh
= NULL
;
219 old_inode
= old_dentry
->d_inode
;
220 if (S_ISDIR(old_inode
->i_mode
))
224 old_bh
= bfs_find_entry(old_dir
,
225 old_dentry
->d_name
.name
,
226 old_dentry
->d_name
.len
, &old_de
);
228 if (!old_bh
|| le16_to_cpu(old_de
->ino
) != old_inode
->i_ino
)
232 new_inode
= new_dentry
->d_inode
;
233 new_bh
= bfs_find_entry(new_dir
,
234 new_dentry
->d_name
.name
,
235 new_dentry
->d_name
.len
, &new_de
);
237 if (new_bh
&& !new_inode
) {
242 error
= bfs_add_entry(new_dir
,
243 new_dentry
->d_name
.name
,
244 new_dentry
->d_name
.len
, old_inode
->i_ino
);
249 old_dir
->i_ctime
= old_dir
->i_mtime
= CURRENT_TIME_SEC
;
250 mark_inode_dirty(old_dir
);
252 new_inode
->i_nlink
--;
253 new_inode
->i_ctime
= CURRENT_TIME_SEC
;
254 mark_inode_dirty(new_inode
);
256 mark_buffer_dirty(old_bh
);
266 struct inode_operations bfs_dir_inops
= {
267 .create
= bfs_create
,
268 .lookup
= bfs_lookup
,
270 .unlink
= bfs_unlink
,
271 .rename
= bfs_rename
,
274 static int bfs_add_entry(struct inode
* dir
, const unsigned char * name
, int namelen
, int ino
)
276 struct buffer_head
* bh
;
277 struct bfs_dirent
* de
;
278 int block
, sblock
, eblock
, off
, eoff
;
281 dprintf("name=%s, namelen=%d\n", name
, namelen
);
285 if (namelen
> BFS_NAMELEN
)
286 return -ENAMETOOLONG
;
288 sblock
= BFS_I(dir
)->i_sblock
;
289 eblock
= BFS_I(dir
)->i_eblock
;
290 eoff
= dir
->i_size
% BFS_BSIZE
;
291 for (block
=sblock
; block
<=eblock
; block
++) {
292 bh
= sb_bread(dir
->i_sb
, block
);
295 for (off
=0; off
<BFS_BSIZE
; off
+=BFS_DIRENT_SIZE
) {
296 de
= (struct bfs_dirent
*)(bh
->b_data
+ off
);
297 if (block
==eblock
&& off
>=eoff
) {
298 /* Do not read/interpret the garbage in the end of eblock. */
302 if ((block
-sblock
)*BFS_BSIZE
+ off
>= dir
->i_size
) {
303 dir
->i_size
+= BFS_DIRENT_SIZE
;
304 dir
->i_ctime
= CURRENT_TIME_SEC
;
306 dir
->i_mtime
= CURRENT_TIME_SEC
;
307 mark_inode_dirty(dir
);
308 de
->ino
= cpu_to_le16((u16
)ino
);
309 for (i
=0; i
<BFS_NAMELEN
; i
++)
310 de
->name
[i
] = (i
< namelen
) ? name
[i
] : 0;
311 mark_buffer_dirty(bh
);
321 static inline int bfs_namecmp(int len
, const unsigned char * name
, const char * buffer
)
323 if (len
< BFS_NAMELEN
&& buffer
[len
])
325 return !memcmp(name
, buffer
, len
);
328 static struct buffer_head
* bfs_find_entry(struct inode
* dir
,
329 const unsigned char * name
, int namelen
, struct bfs_dirent
** res_dir
)
331 unsigned long block
, offset
;
332 struct buffer_head
* bh
;
333 struct bfs_dirent
* de
;
336 if (namelen
> BFS_NAMELEN
)
340 while (block
* BFS_BSIZE
+ offset
< dir
->i_size
) {
342 bh
= sb_bread(dir
->i_sb
, BFS_I(dir
)->i_sblock
+ block
);
348 de
= (struct bfs_dirent
*)(bh
->b_data
+ offset
);
349 offset
+= BFS_DIRENT_SIZE
;
350 if (le16_to_cpu(de
->ino
) && bfs_namecmp(namelen
, name
, de
->name
)) {
354 if (offset
< bh
->b_size
)