3 * BFS directory operations.
4 * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
7 #include <linux/sched.h>
8 #include <linux/string.h>
9 #include <linux/bfs_fs.h>
10 #include <linux/locks.h>
17 #define dprintf(x...) printf(x)
22 static int bfs_add_entry(struct inode
* dir
, const char * name
, int namelen
, int ino
);
23 static struct buffer_head
* bfs_find_entry(struct inode
* dir
,
24 const char * name
, int namelen
, struct bfs_dirent
** res_dir
);
26 static int bfs_readdir(struct file
* f
, void * dirent
, filldir_t filldir
)
28 struct inode
* dir
= f
->f_dentry
->d_inode
;
29 struct buffer_head
* bh
;
30 struct bfs_dirent
* de
;
31 kdev_t dev
= dir
->i_dev
;
35 if (f
->f_pos
& (BFS_DIRENT_SIZE
-1)) {
36 printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f
->f_pos
,
37 bdevname(dev
), dir
->i_ino
);
41 while (f
->f_pos
< dir
->i_size
) {
42 offset
= f
->f_pos
& (BFS_BSIZE
-1);
43 block
= dir
->iu_sblock
+ (f
->f_pos
>> BFS_BSIZE_BITS
);
44 bh
= bread(dev
, block
, BFS_BSIZE
);
46 f
->f_pos
+= BFS_BSIZE
- offset
;
50 de
= (struct bfs_dirent
*)(bh
->b_data
+ offset
);
52 int size
= strnlen(de
->name
, BFS_NAMELEN
);
53 if (filldir(dirent
, de
->name
, size
, f
->f_pos
, de
->ino
, DT_UNKNOWN
) < 0) {
58 offset
+= BFS_DIRENT_SIZE
;
59 f
->f_pos
+= BFS_DIRENT_SIZE
;
60 } while (offset
< BFS_BSIZE
&& f
->f_pos
< dir
->i_size
);
68 struct file_operations bfs_dir_operations
= {
69 read
: generic_read_dir
,
74 extern void dump_imap(const char *, struct super_block
*);
76 static int bfs_create(struct inode
* dir
, struct dentry
* dentry
, int mode
)
80 struct super_block
* s
= dir
->i_sb
;
83 inode
= get_empty_inode();
87 ino
= find_first_zero_bit(s
->su_imap
, s
->su_lasti
);
88 if (ino
> s
->su_lasti
) {
92 set_bit(ino
, s
->su_imap
);
94 inode
->i_dev
= s
->s_dev
;
95 inode
->i_uid
= current
->fsuid
;
96 inode
->i_gid
= (dir
->i_mode
& S_ISGID
) ? dir
->i_gid
: current
->fsgid
;
97 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME
;
98 inode
->i_blocks
= inode
->i_blksize
= 0;
99 inode
->i_op
= &bfs_file_inops
;
100 inode
->i_fop
= &bfs_file_operations
;
101 inode
->i_mapping
->a_ops
= &bfs_aops
;
102 inode
->i_mode
= mode
;
103 inode
->i_ino
= inode
->iu_dsk_ino
= ino
;
104 inode
->iu_sblock
= inode
->iu_eblock
= 0;
105 insert_inode_hash(inode
);
106 mark_inode_dirty(inode
);
107 dump_imap("create",s
);
109 err
= bfs_add_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, inode
->i_ino
);
112 mark_inode_dirty(inode
);
116 d_instantiate(dentry
, inode
);
120 static struct dentry
* bfs_lookup(struct inode
* dir
, struct dentry
* dentry
)
122 struct inode
* inode
= NULL
;
123 struct buffer_head
* bh
;
124 struct bfs_dirent
* de
;
126 if (dentry
->d_name
.len
> BFS_NAMELEN
)
127 return ERR_PTR(-ENAMETOOLONG
);
129 bh
= bfs_find_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, &de
);
131 unsigned long ino
= le32_to_cpu(de
->ino
);
133 inode
= iget(dir
->i_sb
, ino
);
135 return ERR_PTR(-EACCES
);
137 d_add(dentry
, inode
);
141 static int bfs_link(struct dentry
* old
, struct inode
* dir
, struct dentry
* new)
143 struct inode
* inode
= old
->d_inode
;
146 if (S_ISDIR(inode
->i_mode
))
149 err
= bfs_add_entry(dir
, new->d_name
.name
, new->d_name
.len
, inode
->i_ino
);
153 inode
->i_ctime
= CURRENT_TIME
;
154 mark_inode_dirty(inode
);
155 atomic_inc(&inode
->i_count
);
156 d_instantiate(new, inode
);
161 static int bfs_unlink(struct inode
* dir
, struct dentry
* dentry
)
164 struct inode
* inode
;
165 struct buffer_head
* bh
;
166 struct bfs_dirent
* de
;
168 inode
= dentry
->d_inode
;
169 bh
= bfs_find_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, &de
);
170 if (!bh
|| de
->ino
!= inode
->i_ino
)
173 if (!inode
->i_nlink
) {
174 printf("unlinking non-existent file %s:%lu (nlink=%d)\n", bdevname(inode
->i_dev
),
175 inode
->i_ino
, inode
->i_nlink
);
179 dir
->i_version
= ++event
;
180 mark_buffer_dirty(bh
, 0);
181 dir
->i_ctime
= dir
->i_mtime
= CURRENT_TIME
;
182 mark_inode_dirty(dir
);
184 inode
->i_ctime
= dir
->i_ctime
;
185 mark_inode_dirty(inode
);
193 static int bfs_rename(struct inode
* old_dir
, struct dentry
* old_dentry
,
194 struct inode
* new_dir
, struct dentry
* new_dentry
)
196 struct inode
* old_inode
, * new_inode
;
197 struct buffer_head
* old_bh
, * new_bh
;
198 struct bfs_dirent
* old_de
, * new_de
;
201 old_bh
= new_bh
= NULL
;
202 old_inode
= old_dentry
->d_inode
;
203 if (S_ISDIR(old_inode
->i_mode
))
206 old_bh
= bfs_find_entry(old_dir
,
207 old_dentry
->d_name
.name
,
208 old_dentry
->d_name
.len
, &old_de
);
210 if (!old_bh
|| old_de
->ino
!= old_inode
->i_ino
)
214 new_inode
= new_dentry
->d_inode
;
215 new_bh
= bfs_find_entry(new_dir
,
216 new_dentry
->d_name
.name
,
217 new_dentry
->d_name
.len
, &new_de
);
219 if (new_bh
&& !new_inode
) {
224 error
= bfs_add_entry(new_dir
,
225 new_dentry
->d_name
.name
,
226 new_dentry
->d_name
.len
, old_inode
->i_ino
);
231 old_dir
->i_ctime
= old_dir
->i_mtime
= CURRENT_TIME
;
232 old_dir
->i_version
= ++event
;
233 mark_inode_dirty(old_dir
);
235 new_inode
->i_nlink
--;
236 new_inode
->i_ctime
= CURRENT_TIME
;
237 mark_inode_dirty(new_inode
);
239 mark_buffer_dirty(old_bh
, 0);
248 struct inode_operations bfs_dir_inops
= {
256 static int bfs_add_entry(struct inode
* dir
, const char * name
, int namelen
, int ino
)
258 struct buffer_head
* bh
;
259 struct bfs_dirent
* de
;
260 int block
, sblock
, eblock
, off
;
264 dprintf("name=%s, namelen=%d\n", name
, namelen
);
268 if (namelen
> BFS_NAMELEN
)
269 return -ENAMETOOLONG
;
272 sblock
= dir
->iu_sblock
;
273 eblock
= dir
->iu_eblock
;
274 for (block
=sblock
; block
<=eblock
; block
++) {
275 bh
= bread(dev
, block
, BFS_BSIZE
);
278 for (off
=0; off
<BFS_BSIZE
; off
+=BFS_DIRENT_SIZE
) {
279 de
= (struct bfs_dirent
*)(bh
->b_data
+ off
);
281 if ((block
-sblock
)*BFS_BSIZE
+ off
>= dir
->i_size
) {
282 dir
->i_size
+= BFS_DIRENT_SIZE
;
283 dir
->i_ctime
= CURRENT_TIME
;
285 dir
->i_mtime
= CURRENT_TIME
;
286 mark_inode_dirty(dir
);
287 dir
->i_version
= ++event
;
289 for (i
=0; i
<BFS_NAMELEN
; i
++)
290 de
->name
[i
] = (i
< namelen
) ? name
[i
] : 0;
291 mark_buffer_dirty(bh
, 0);
301 static inline int bfs_namecmp(int len
, const char * name
, const char * buffer
)
303 if (len
< BFS_NAMELEN
&& buffer
[len
])
305 return !memcmp(name
, buffer
, len
);
308 static struct buffer_head
* bfs_find_entry(struct inode
* dir
,
309 const char * name
, int namelen
, struct bfs_dirent
** res_dir
)
311 unsigned long block
, offset
;
312 struct buffer_head
* bh
;
313 struct bfs_sb_info
* info
;
314 struct bfs_dirent
* de
;
317 info
= &dir
->i_sb
->u
.bfs_sb
;
318 if (namelen
> BFS_NAMELEN
)
322 while (block
* BFS_BSIZE
+ offset
< dir
->i_size
) {
324 bh
= bread(dir
->i_dev
, dir
->iu_sblock
+ block
, BFS_BSIZE
);
330 de
= (struct bfs_dirent
*)(bh
->b_data
+ offset
);
331 offset
+= BFS_DIRENT_SIZE
;
332 if (de
->ino
&& bfs_namecmp(namelen
, name
, de
->name
)) {
336 if (offset
< bh
->b_size
)