3 * BFS directory operations.
4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
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
;
86 ino
= find_first_zero_bit(s
->su_imap
, s
->su_lasti
);
87 if (ino
> s
->su_lasti
) {
91 set_bit(ino
, s
->su_imap
);
93 inode
->i_uid
= current
->fsuid
;
94 inode
->i_gid
= (dir
->i_mode
& S_ISGID
) ? dir
->i_gid
: current
->fsgid
;
95 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME
;
96 inode
->i_blocks
= inode
->i_blksize
= 0;
97 inode
->i_op
= &bfs_file_inops
;
98 inode
->i_fop
= &bfs_file_operations
;
99 inode
->i_mapping
->a_ops
= &bfs_aops
;
100 inode
->i_mode
= mode
;
101 inode
->i_ino
= inode
->iu_dsk_ino
= ino
;
102 inode
->iu_sblock
= inode
->iu_eblock
= 0;
103 insert_inode_hash(inode
);
104 mark_inode_dirty(inode
);
105 dump_imap("create",s
);
107 err
= bfs_add_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, inode
->i_ino
);
110 mark_inode_dirty(inode
);
114 d_instantiate(dentry
, inode
);
118 static struct dentry
* bfs_lookup(struct inode
* dir
, struct dentry
* dentry
)
120 struct inode
* inode
= NULL
;
121 struct buffer_head
* bh
;
122 struct bfs_dirent
* de
;
124 if (dentry
->d_name
.len
> BFS_NAMELEN
)
125 return ERR_PTR(-ENAMETOOLONG
);
127 bh
= bfs_find_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, &de
);
129 unsigned long ino
= le32_to_cpu(de
->ino
);
131 inode
= iget(dir
->i_sb
, ino
);
133 return ERR_PTR(-EACCES
);
135 d_add(dentry
, inode
);
139 static int bfs_link(struct dentry
* old
, struct inode
* dir
, struct dentry
* new)
141 struct inode
* inode
= old
->d_inode
;
144 if (S_ISDIR(inode
->i_mode
))
147 err
= bfs_add_entry(dir
, new->d_name
.name
, new->d_name
.len
, inode
->i_ino
);
151 inode
->i_ctime
= CURRENT_TIME
;
152 mark_inode_dirty(inode
);
153 atomic_inc(&inode
->i_count
);
154 d_instantiate(new, inode
);
159 static int bfs_unlink(struct inode
* dir
, struct dentry
* dentry
)
162 struct inode
* inode
;
163 struct buffer_head
* bh
;
164 struct bfs_dirent
* de
;
166 inode
= dentry
->d_inode
;
167 bh
= bfs_find_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
, &de
);
168 if (!bh
|| de
->ino
!= inode
->i_ino
)
171 if (!inode
->i_nlink
) {
172 printf("unlinking non-existent file %s:%lu (nlink=%d)\n", bdevname(inode
->i_dev
),
173 inode
->i_ino
, inode
->i_nlink
);
177 dir
->i_version
= ++event
;
178 mark_buffer_dirty(bh
);
179 dir
->i_ctime
= dir
->i_mtime
= CURRENT_TIME
;
180 mark_inode_dirty(dir
);
182 inode
->i_ctime
= dir
->i_ctime
;
183 mark_inode_dirty(inode
);
191 static int bfs_rename(struct inode
* old_dir
, struct dentry
* old_dentry
,
192 struct inode
* new_dir
, struct dentry
* new_dentry
)
194 struct inode
* old_inode
, * new_inode
;
195 struct buffer_head
* old_bh
, * new_bh
;
196 struct bfs_dirent
* old_de
, * new_de
;
199 old_bh
= new_bh
= NULL
;
200 old_inode
= old_dentry
->d_inode
;
201 if (S_ISDIR(old_inode
->i_mode
))
204 old_bh
= bfs_find_entry(old_dir
,
205 old_dentry
->d_name
.name
,
206 old_dentry
->d_name
.len
, &old_de
);
208 if (!old_bh
|| old_de
->ino
!= old_inode
->i_ino
)
212 new_inode
= new_dentry
->d_inode
;
213 new_bh
= bfs_find_entry(new_dir
,
214 new_dentry
->d_name
.name
,
215 new_dentry
->d_name
.len
, &new_de
);
217 if (new_bh
&& !new_inode
) {
222 error
= bfs_add_entry(new_dir
,
223 new_dentry
->d_name
.name
,
224 new_dentry
->d_name
.len
, old_inode
->i_ino
);
229 old_dir
->i_ctime
= old_dir
->i_mtime
= CURRENT_TIME
;
230 old_dir
->i_version
= ++event
;
231 mark_inode_dirty(old_dir
);
233 new_inode
->i_nlink
--;
234 new_inode
->i_ctime
= CURRENT_TIME
;
235 mark_inode_dirty(new_inode
);
237 mark_buffer_dirty(old_bh
);
246 struct inode_operations bfs_dir_inops
= {
254 static int bfs_add_entry(struct inode
* dir
, const char * name
, int namelen
, int ino
)
256 struct buffer_head
* bh
;
257 struct bfs_dirent
* de
;
258 int block
, sblock
, eblock
, off
;
262 dprintf("name=%s, namelen=%d\n", name
, namelen
);
266 if (namelen
> BFS_NAMELEN
)
267 return -ENAMETOOLONG
;
270 sblock
= dir
->iu_sblock
;
271 eblock
= dir
->iu_eblock
;
272 for (block
=sblock
; block
<=eblock
; block
++) {
273 bh
= bread(dev
, block
, BFS_BSIZE
);
276 for (off
=0; off
<BFS_BSIZE
; off
+=BFS_DIRENT_SIZE
) {
277 de
= (struct bfs_dirent
*)(bh
->b_data
+ off
);
279 if ((block
-sblock
)*BFS_BSIZE
+ off
>= dir
->i_size
) {
280 dir
->i_size
+= BFS_DIRENT_SIZE
;
281 dir
->i_ctime
= CURRENT_TIME
;
283 dir
->i_mtime
= CURRENT_TIME
;
284 mark_inode_dirty(dir
);
285 dir
->i_version
= ++event
;
287 for (i
=0; i
<BFS_NAMELEN
; i
++)
288 de
->name
[i
] = (i
< namelen
) ? name
[i
] : 0;
289 mark_buffer_dirty(bh
);
299 static inline int bfs_namecmp(int len
, const char * name
, const char * buffer
)
301 if (len
< BFS_NAMELEN
&& buffer
[len
])
303 return !memcmp(name
, buffer
, len
);
306 static struct buffer_head
* bfs_find_entry(struct inode
* dir
,
307 const char * name
, int namelen
, struct bfs_dirent
** res_dir
)
309 unsigned long block
, offset
;
310 struct buffer_head
* bh
;
311 struct bfs_sb_info
* info
;
312 struct bfs_dirent
* de
;
315 info
= &dir
->i_sb
->u
.bfs_sb
;
316 if (namelen
> BFS_NAMELEN
)
320 while (block
* BFS_BSIZE
+ offset
< dir
->i_size
) {
322 bh
= bread(dir
->i_dev
, dir
->iu_sblock
+ block
, BFS_BSIZE
);
328 de
= (struct bfs_dirent
*)(bh
->b_data
+ offset
);
329 offset
+= BFS_DIRENT_SIZE
;
330 if (de
->ino
&& bfs_namecmp(namelen
, name
, de
->name
)) {
334 if (offset
< bh
->b_size
)