1 // SPDX-License-Identifier: GPL-2.0
4 * BFS directory operations.
5 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
6 * Made endianness-clean by Andrew Stribblehill <ads@wompom.org> 2005
9 #include <linux/time.h>
10 #include <linux/string.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 struct qstr
*child
, int ino
);
25 static struct buffer_head
*bfs_find_entry(struct inode
*dir
,
26 const struct qstr
*child
,
27 struct bfs_dirent
**res_dir
);
29 static int bfs_readdir(struct file
*f
, struct dir_context
*ctx
)
31 struct inode
*dir
= file_inode(f
);
32 struct buffer_head
*bh
;
33 struct bfs_dirent
*de
;
37 if (ctx
->pos
& (BFS_DIRENT_SIZE
- 1)) {
38 printf("Bad f_pos=%08lx for %s:%08lx\n",
39 (unsigned long)ctx
->pos
,
40 dir
->i_sb
->s_id
, dir
->i_ino
);
44 while (ctx
->pos
< dir
->i_size
) {
45 offset
= ctx
->pos
& (BFS_BSIZE
- 1);
46 block
= BFS_I(dir
)->i_sblock
+ (ctx
->pos
>> BFS_BSIZE_BITS
);
47 bh
= sb_bread(dir
->i_sb
, block
);
49 ctx
->pos
+= BFS_BSIZE
- offset
;
53 de
= (struct bfs_dirent
*)(bh
->b_data
+ offset
);
55 int size
= strnlen(de
->name
, BFS_NAMELEN
);
56 if (!dir_emit(ctx
, de
->name
, size
,
63 offset
+= BFS_DIRENT_SIZE
;
64 ctx
->pos
+= BFS_DIRENT_SIZE
;
65 } while ((offset
< BFS_BSIZE
) && (ctx
->pos
< dir
->i_size
));
71 const struct file_operations bfs_dir_operations
= {
72 .read
= generic_read_dir
,
73 .iterate_shared
= bfs_readdir
,
74 .fsync
= generic_file_fsync
,
75 .llseek
= generic_file_llseek
,
78 static int bfs_create(struct inode
*dir
, struct dentry
*dentry
, umode_t mode
,
83 struct super_block
*s
= dir
->i_sb
;
84 struct bfs_sb_info
*info
= BFS_SB(s
);
90 mutex_lock(&info
->bfs_lock
);
91 ino
= find_first_zero_bit(info
->si_imap
, info
->si_lasti
+ 1);
92 if (ino
> info
->si_lasti
) {
93 mutex_unlock(&info
->bfs_lock
);
97 set_bit(ino
, info
->si_imap
);
99 inode_init_owner(inode
, dir
, mode
);
100 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= current_time(inode
);
102 inode
->i_op
= &bfs_file_inops
;
103 inode
->i_fop
= &bfs_file_operations
;
104 inode
->i_mapping
->a_ops
= &bfs_aops
;
106 BFS_I(inode
)->i_dsk_ino
= ino
;
107 BFS_I(inode
)->i_sblock
= 0;
108 BFS_I(inode
)->i_eblock
= 0;
109 insert_inode_hash(inode
);
110 mark_inode_dirty(inode
);
111 bfs_dump_imap("create", s
);
113 err
= bfs_add_entry(dir
, &dentry
->d_name
, inode
->i_ino
);
115 inode_dec_link_count(inode
);
116 mutex_unlock(&info
->bfs_lock
);
120 mutex_unlock(&info
->bfs_lock
);
121 d_instantiate(dentry
, inode
);
125 static struct dentry
*bfs_lookup(struct inode
*dir
, struct dentry
*dentry
,
128 struct inode
*inode
= NULL
;
129 struct buffer_head
*bh
;
130 struct bfs_dirent
*de
;
131 struct bfs_sb_info
*info
= BFS_SB(dir
->i_sb
);
133 if (dentry
->d_name
.len
> BFS_NAMELEN
)
134 return ERR_PTR(-ENAMETOOLONG
);
136 mutex_lock(&info
->bfs_lock
);
137 bh
= bfs_find_entry(dir
, &dentry
->d_name
, &de
);
139 unsigned long ino
= (unsigned long)le16_to_cpu(de
->ino
);
141 inode
= bfs_iget(dir
->i_sb
, ino
);
143 mutex_unlock(&info
->bfs_lock
);
144 return d_splice_alias(inode
, dentry
);
147 static int bfs_link(struct dentry
*old
, struct inode
*dir
,
150 struct inode
*inode
= d_inode(old
);
151 struct bfs_sb_info
*info
= BFS_SB(inode
->i_sb
);
154 mutex_lock(&info
->bfs_lock
);
155 err
= bfs_add_entry(dir
, &new->d_name
, inode
->i_ino
);
157 mutex_unlock(&info
->bfs_lock
);
161 inode
->i_ctime
= current_time(inode
);
162 mark_inode_dirty(inode
);
164 d_instantiate(new, inode
);
165 mutex_unlock(&info
->bfs_lock
);
169 static int bfs_unlink(struct inode
*dir
, struct dentry
*dentry
)
172 struct inode
*inode
= d_inode(dentry
);
173 struct buffer_head
*bh
;
174 struct bfs_dirent
*de
;
175 struct bfs_sb_info
*info
= BFS_SB(inode
->i_sb
);
177 mutex_lock(&info
->bfs_lock
);
178 bh
= bfs_find_entry(dir
, &dentry
->d_name
, &de
);
179 if (!bh
|| (le16_to_cpu(de
->ino
) != inode
->i_ino
))
182 if (!inode
->i_nlink
) {
183 printf("unlinking non-existent file %s:%lu (nlink=%d)\n",
184 inode
->i_sb
->s_id
, inode
->i_ino
,
189 mark_buffer_dirty_inode(bh
, dir
);
190 dir
->i_ctime
= dir
->i_mtime
= current_time(dir
);
191 mark_inode_dirty(dir
);
192 inode
->i_ctime
= dir
->i_ctime
;
193 inode_dec_link_count(inode
);
198 mutex_unlock(&info
->bfs_lock
);
202 static int bfs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
203 struct inode
*new_dir
, struct dentry
*new_dentry
,
206 struct inode
*old_inode
, *new_inode
;
207 struct buffer_head
*old_bh
, *new_bh
;
208 struct bfs_dirent
*old_de
, *new_de
;
209 struct bfs_sb_info
*info
;
212 if (flags
& ~RENAME_NOREPLACE
)
215 old_bh
= new_bh
= NULL
;
216 old_inode
= d_inode(old_dentry
);
217 if (S_ISDIR(old_inode
->i_mode
))
220 info
= BFS_SB(old_inode
->i_sb
);
222 mutex_lock(&info
->bfs_lock
);
223 old_bh
= bfs_find_entry(old_dir
, &old_dentry
->d_name
, &old_de
);
225 if (!old_bh
|| (le16_to_cpu(old_de
->ino
) != old_inode
->i_ino
))
229 new_inode
= d_inode(new_dentry
);
230 new_bh
= bfs_find_entry(new_dir
, &new_dentry
->d_name
, &new_de
);
232 if (new_bh
&& !new_inode
) {
237 error
= bfs_add_entry(new_dir
, &new_dentry
->d_name
,
243 old_dir
->i_ctime
= old_dir
->i_mtime
= current_time(old_dir
);
244 mark_inode_dirty(old_dir
);
246 new_inode
->i_ctime
= current_time(new_inode
);
247 inode_dec_link_count(new_inode
);
249 mark_buffer_dirty_inode(old_bh
, old_dir
);
253 mutex_unlock(&info
->bfs_lock
);
259 const struct inode_operations bfs_dir_inops
= {
260 .create
= bfs_create
,
261 .lookup
= bfs_lookup
,
263 .unlink
= bfs_unlink
,
264 .rename
= bfs_rename
,
267 static int bfs_add_entry(struct inode
*dir
, const struct qstr
*child
, int ino
)
269 const unsigned char *name
= child
->name
;
270 int namelen
= child
->len
;
271 struct buffer_head
*bh
;
272 struct bfs_dirent
*de
;
273 int block
, sblock
, eblock
, off
, pos
;
276 dprintf("name=%s, namelen=%d\n", name
, namelen
);
280 if (namelen
> BFS_NAMELEN
)
281 return -ENAMETOOLONG
;
283 sblock
= BFS_I(dir
)->i_sblock
;
284 eblock
= BFS_I(dir
)->i_eblock
;
285 for (block
= sblock
; block
<= eblock
; block
++) {
286 bh
= sb_bread(dir
->i_sb
, block
);
289 for (off
= 0; off
< BFS_BSIZE
; off
+= BFS_DIRENT_SIZE
) {
290 de
= (struct bfs_dirent
*)(bh
->b_data
+ off
);
292 pos
= (block
- sblock
) * BFS_BSIZE
+ off
;
293 if (pos
>= dir
->i_size
) {
294 dir
->i_size
+= BFS_DIRENT_SIZE
;
295 dir
->i_ctime
= current_time(dir
);
297 dir
->i_mtime
= current_time(dir
);
298 mark_inode_dirty(dir
);
299 de
->ino
= cpu_to_le16((u16
)ino
);
300 for (i
= 0; i
< BFS_NAMELEN
; i
++)
302 (i
< namelen
) ? name
[i
] : 0;
303 mark_buffer_dirty_inode(bh
, dir
);
313 static inline int bfs_namecmp(int len
, const unsigned char *name
,
316 if ((len
< BFS_NAMELEN
) && buffer
[len
])
318 return !memcmp(name
, buffer
, len
);
321 static struct buffer_head
*bfs_find_entry(struct inode
*dir
,
322 const struct qstr
*child
,
323 struct bfs_dirent
**res_dir
)
325 unsigned long block
= 0, offset
= 0;
326 struct buffer_head
*bh
= NULL
;
327 struct bfs_dirent
*de
;
328 const unsigned char *name
= child
->name
;
329 int namelen
= child
->len
;
332 if (namelen
> BFS_NAMELEN
)
335 while (block
* BFS_BSIZE
+ offset
< dir
->i_size
) {
337 bh
= sb_bread(dir
->i_sb
, BFS_I(dir
)->i_sblock
+ block
);
343 de
= (struct bfs_dirent
*)(bh
->b_data
+ offset
);
344 offset
+= BFS_DIRENT_SIZE
;
345 if (le16_to_cpu(de
->ino
) &&
346 bfs_namecmp(namelen
, name
, de
->name
)) {
350 if (offset
< bh
->b_size
)