]> Git Repo - linux.git/blame - fs/minix/dir.c
Merge tag 'i3c/for-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
[linux.git] / fs / minix / dir.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
1da177e4
LT
2/*
3 * linux/fs/minix/dir.c
4 *
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * minix directory handling functions
939b00df
AB
8 *
9 * Updated to filesystem version 3 by Daniel Aragones
1da177e4
LT
10 */
11
12#include "minix.h"
4a66af9e 13#include <linux/buffer_head.h>
1da177e4 14#include <linux/highmem.h>
4a66af9e 15#include <linux/swap.h>
1da177e4
LT
16
17typedef struct minix_dir_entry minix_dirent;
939b00df 18typedef struct minix3_dir_entry minix3_dirent;
1da177e4 19
80886298 20static int minix_readdir(struct file *, struct dir_context *);
1da177e4 21
4b6f5d20 22const struct file_operations minix_dir_operations = {
cc46759a 23 .llseek = generic_file_llseek,
1da177e4 24 .read = generic_read_dir,
3b0a3c1a 25 .iterate_shared = minix_readdir,
1b061d92 26 .fsync = generic_file_fsync,
1da177e4
LT
27};
28
1da177e4
LT
29/*
30 * Return the offset into page `page_nr' of the last valid
31 * byte in that page, plus one.
32 */
33static unsigned
34minix_last_byte(struct inode *inode, unsigned long page_nr)
35{
09cbfeaf 36 unsigned last_byte = PAGE_SIZE;
1da177e4 37
09cbfeaf
KS
38 if (page_nr == (inode->i_size >> PAGE_SHIFT))
39 last_byte = inode->i_size & (PAGE_SIZE - 1);
1da177e4
LT
40 return last_byte;
41}
42
f556e776 43static void dir_commit_chunk(struct page *page, loff_t pos, unsigned len)
1da177e4 44{
4a66af9e
NP
45 struct address_space *mapping = page->mapping;
46 struct inode *dir = mapping->host;
f556e776 47
4a66af9e
NP
48 block_write_end(NULL, mapping, pos, len, len, page, NULL);
49
50 if (pos+len > dir->i_size) {
51 i_size_write(dir, pos+len);
52 mark_inode_dirty(dir);
53 }
f556e776
CH
54 unlock_page(page);
55}
56
57static int minix_handle_dirsync(struct inode *dir)
58{
59 int err;
60
61 err = filemap_write_and_wait(dir->i_mapping);
62 if (!err)
63 err = sync_inode_metadata(dir, 1);
1da177e4
LT
64 return err;
65}
66
ee0d27c9 67static void *dir_get_page(struct inode *dir, unsigned long n, struct page **p)
1da177e4
LT
68{
69 struct address_space *mapping = dir->i_mapping;
090d2b18 70 struct page *page = read_mapping_page(mapping, n, NULL);
ee0d27c9
AV
71 if (IS_ERR(page))
72 return ERR_CAST(page);
ee0d27c9 73 *p = page;
41e9a7fa 74 return kmap_local_page(page);
1da177e4
LT
75}
76
77static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi)
78{
79 return (void*)((char*)de + sbi->s_dirsize);
80}
81
80886298 82static int minix_readdir(struct file *file, struct dir_context *ctx)
1da177e4 83{
80886298 84 struct inode *inode = file_inode(file);
1da177e4 85 struct super_block *sb = inode->i_sb;
1da177e4
LT
86 struct minix_sb_info *sbi = minix_sb(sb);
87 unsigned chunk_size = sbi->s_dirsize;
80886298
AV
88 unsigned long npages = dir_pages(inode);
89 unsigned long pos = ctx->pos;
90 unsigned offset;
91 unsigned long n;
1da177e4 92
642b704c 93 ctx->pos = pos = ALIGN(pos, chunk_size);
1da177e4 94 if (pos >= inode->i_size)
80886298
AV
95 return 0;
96
09cbfeaf
KS
97 offset = pos & ~PAGE_MASK;
98 n = pos >> PAGE_SHIFT;
1da177e4
LT
99
100 for ( ; n < npages; n++, offset = 0) {
101 char *p, *kaddr, *limit;
ee0d27c9 102 struct page *page;
1da177e4 103
ee0d27c9
AV
104 kaddr = dir_get_page(inode, n, &page);
105 if (IS_ERR(kaddr))
1da177e4 106 continue;
1da177e4
LT
107 p = kaddr+offset;
108 limit = kaddr + minix_last_byte(inode, n) - chunk_size;
939b00df 109 for ( ; p <= limit; p = minix_next_entry(p, sbi)) {
80886298
AV
110 const char *name;
111 __u32 inumber;
939b00df
AB
112 if (sbi->s_version == MINIX_V3) {
113 minix3_dirent *de3 = (minix3_dirent *)p;
114 name = de3->name;
115 inumber = de3->inode;
116 } else {
117 minix_dirent *de = (minix_dirent *)p;
118 name = de->name;
119 inumber = de->inode;
120 }
121 if (inumber) {
939b00df 122 unsigned l = strnlen(name, sbi->s_namelen);
80886298
AV
123 if (!dir_emit(ctx, name, l,
124 inumber, DT_UNKNOWN)) {
41e9a7fa 125 unmap_and_put_page(page, p);
80886298 126 return 0;
1da177e4
LT
127 }
128 }
80886298 129 ctx->pos += chunk_size;
1da177e4 130 }
41e9a7fa 131 unmap_and_put_page(page, kaddr);
1da177e4 132 }
1da177e4
LT
133 return 0;
134}
135
136static inline int namecompare(int len, int maxlen,
137 const char * name, const char * buffer)
138{
139 if (len < maxlen && buffer[len])
140 return 0;
141 return !memcmp(name, buffer, len);
142}
143
144/*
145 * minix_find_entry()
146 *
147 * finds an entry in the specified directory with the wanted name. It
148 * returns the cache buffer in which the entry was found, and the entry
149 * itself (as a parameter - res_dir). It does NOT read the inode of the
150 * entry - you'll have to do that yourself if you want to.
151 */
152minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page)
153{
154 const char * name = dentry->d_name.name;
155 int namelen = dentry->d_name.len;
2b0143b5 156 struct inode * dir = d_inode(dentry->d_parent);
1da177e4
LT
157 struct super_block * sb = dir->i_sb;
158 struct minix_sb_info * sbi = minix_sb(sb);
159 unsigned long n;
160 unsigned long npages = dir_pages(dir);
161 struct page *page = NULL;
939b00df 162 char *p;
1da177e4 163
939b00df
AB
164 char *namx;
165 __u32 inumber;
1da177e4
LT
166 *res_page = NULL;
167
168 for (n = 0; n < npages; n++) {
939b00df
AB
169 char *kaddr, *limit;
170
ee0d27c9
AV
171 kaddr = dir_get_page(dir, n, &page);
172 if (IS_ERR(kaddr))
1da177e4
LT
173 continue;
174
939b00df
AB
175 limit = kaddr + minix_last_byte(dir, n) - sbi->s_dirsize;
176 for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
177 if (sbi->s_version == MINIX_V3) {
178 minix3_dirent *de3 = (minix3_dirent *)p;
179 namx = de3->name;
180 inumber = de3->inode;
181 } else {
182 minix_dirent *de = (minix_dirent *)p;
183 namx = de->name;
184 inumber = de->inode;
185 }
186 if (!inumber)
1da177e4 187 continue;
939b00df 188 if (namecompare(namelen, sbi->s_namelen, name, namx))
1da177e4
LT
189 goto found;
190 }
41e9a7fa 191 unmap_and_put_page(page, kaddr);
1da177e4
LT
192 }
193 return NULL;
194
195found:
196 *res_page = page;
939b00df 197 return (minix_dirent *)p;
1da177e4
LT
198}
199
200int minix_add_link(struct dentry *dentry, struct inode *inode)
201{
2b0143b5 202 struct inode *dir = d_inode(dentry->d_parent);
1da177e4
LT
203 const char * name = dentry->d_name.name;
204 int namelen = dentry->d_name.len;
205 struct super_block * sb = dir->i_sb;
206 struct minix_sb_info * sbi = minix_sb(sb);
207 struct page *page = NULL;
1da177e4
LT
208 unsigned long npages = dir_pages(dir);
209 unsigned long n;
939b00df
AB
210 char *kaddr, *p;
211 minix_dirent *de;
212 minix3_dirent *de3;
4a66af9e 213 loff_t pos;
1da177e4 214 int err;
939b00df
AB
215 char *namx = NULL;
216 __u32 inumber;
1da177e4
LT
217
218 /*
219 * We take care of directory expansion in the same loop
220 * This code plays outside i_size, so it locks the page
221 * to protect that region.
222 */
223 for (n = 0; n <= npages; n++) {
939b00df 224 char *limit, *dir_end;
1da177e4 225
ee0d27c9
AV
226 kaddr = dir_get_page(dir, n, &page);
227 if (IS_ERR(kaddr))
228 return PTR_ERR(kaddr);
1da177e4 229 lock_page(page);
1da177e4 230 dir_end = kaddr + minix_last_byte(dir, n);
09cbfeaf 231 limit = kaddr + PAGE_SIZE - sbi->s_dirsize;
939b00df
AB
232 for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
233 de = (minix_dirent *)p;
234 de3 = (minix3_dirent *)p;
235 if (sbi->s_version == MINIX_V3) {
236 namx = de3->name;
237 inumber = de3->inode;
238 } else {
239 namx = de->name;
240 inumber = de->inode;
241 }
242 if (p == dir_end) {
1da177e4 243 /* We hit i_size */
939b00df
AB
244 if (sbi->s_version == MINIX_V3)
245 de3->inode = 0;
246 else
247 de->inode = 0;
1da177e4
LT
248 goto got_it;
249 }
939b00df 250 if (!inumber)
1da177e4
LT
251 goto got_it;
252 err = -EEXIST;
939b00df 253 if (namecompare(namelen, sbi->s_namelen, name, namx))
1da177e4 254 goto out_unlock;
1da177e4
LT
255 }
256 unlock_page(page);
41e9a7fa 257 unmap_and_put_page(page, kaddr);
1da177e4
LT
258 }
259 BUG();
260 return -EINVAL;
261
262got_it:
4812509e 263 pos = page_offset(page) + offset_in_page(p);
f4e420dc 264 err = minix_prepare_chunk(page, pos, sbi->s_dirsize);
1da177e4
LT
265 if (err)
266 goto out_unlock;
939b00df
AB
267 memcpy (namx, name, namelen);
268 if (sbi->s_version == MINIX_V3) {
269 memset (namx + namelen, 0, sbi->s_dirsize - namelen - 4);
270 de3->inode = inode->i_ino;
271 } else {
272 memset (namx + namelen, 0, sbi->s_dirsize - namelen - 2);
273 de->inode = inode->i_ino;
274 }
f556e776 275 dir_commit_chunk(page, pos, sbi->s_dirsize);
06475f4b 276 inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
1da177e4 277 mark_inode_dirty(dir);
f556e776 278 err = minix_handle_dirsync(dir);
1da177e4 279out_put:
41e9a7fa 280 unmap_and_put_page(page, kaddr);
1da177e4
LT
281 return err;
282out_unlock:
283 unlock_page(page);
284 goto out_put;
285}
286
287int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
288{
f4e420dc 289 struct inode *inode = page->mapping->host;
4812509e 290 loff_t pos = page_offset(page) + offset_in_page(de);
9f6c1333
DG
291 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
292 unsigned len = sbi->s_dirsize;
1da177e4
LT
293 int err;
294
295 lock_page(page);
f4e420dc 296 err = minix_prepare_chunk(page, pos, len);
b61d15d5 297 if (err) {
1da177e4 298 unlock_page(page);
b61d15d5 299 return err;
1da177e4 300 }
b61d15d5
CH
301 if (sbi->s_version == MINIX_V3)
302 ((minix3_dirent *)de)->inode = 0;
303 else
304 de->inode = 0;
f556e776 305 dir_commit_chunk(page, pos, len);
06475f4b 306 inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
1da177e4 307 mark_inode_dirty(inode);
f556e776 308 return minix_handle_dirsync(inode);
1da177e4
LT
309}
310
311int minix_make_empty(struct inode *inode, struct inode *dir)
312{
f4e420dc 313 struct page *page = grab_cache_page(inode->i_mapping, 0);
939b00df 314 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
1da177e4
LT
315 char *kaddr;
316 int err;
317
318 if (!page)
319 return -ENOMEM;
f4e420dc 320 err = minix_prepare_chunk(page, 0, 2 * sbi->s_dirsize);
1da177e4
LT
321 if (err) {
322 unlock_page(page);
323 goto fail;
324 }
325
41e9a7fa 326 kaddr = kmap_local_page(page);
09cbfeaf 327 memset(kaddr, 0, PAGE_SIZE);
1da177e4 328
939b00df
AB
329 if (sbi->s_version == MINIX_V3) {
330 minix3_dirent *de3 = (minix3_dirent *)kaddr;
331
332 de3->inode = inode->i_ino;
333 strcpy(de3->name, ".");
334 de3 = minix_next_entry(de3, sbi);
335 de3->inode = dir->i_ino;
336 strcpy(de3->name, "..");
337 } else {
338 minix_dirent *de = (minix_dirent *)kaddr;
339
340 de->inode = inode->i_ino;
341 strcpy(de->name, ".");
342 de = minix_next_entry(de, sbi);
343 de->inode = dir->i_ino;
344 strcpy(de->name, "..");
345 }
41e9a7fa 346 kunmap_local(kaddr);
1da177e4 347
f556e776
CH
348 dir_commit_chunk(page, 0, 2 * sbi->s_dirsize);
349 err = minix_handle_dirsync(inode);
1da177e4 350fail:
09cbfeaf 351 put_page(page);
1da177e4
LT
352 return err;
353}
354
355/*
356 * routine to check that the specified directory is empty (for rmdir)
357 */
358int minix_empty_dir(struct inode * inode)
359{
360 struct page *page = NULL;
361 unsigned long i, npages = dir_pages(inode);
362 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
41e9a7fa 363 char *name, *kaddr;
939b00df 364 __u32 inumber;
1da177e4
LT
365
366 for (i = 0; i < npages; i++) {
41e9a7fa 367 char *p, *limit;
1da177e4 368
ee0d27c9
AV
369 kaddr = dir_get_page(inode, i, &page);
370 if (IS_ERR(kaddr))
1da177e4
LT
371 continue;
372
939b00df
AB
373 limit = kaddr + minix_last_byte(inode, i) - sbi->s_dirsize;
374 for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
375 if (sbi->s_version == MINIX_V3) {
376 minix3_dirent *de3 = (minix3_dirent *)p;
377 name = de3->name;
378 inumber = de3->inode;
379 } else {
380 minix_dirent *de = (minix_dirent *)p;
381 name = de->name;
382 inumber = de->inode;
383 }
1da177e4 384
939b00df 385 if (inumber != 0) {
1da177e4 386 /* check for . and .. */
939b00df 387 if (name[0] != '.')
1da177e4 388 goto not_empty;
939b00df
AB
389 if (!name[1]) {
390 if (inumber != inode->i_ino)
1da177e4 391 goto not_empty;
939b00df 392 } else if (name[1] != '.')
1da177e4 393 goto not_empty;
939b00df 394 else if (name[2])
1da177e4
LT
395 goto not_empty;
396 }
1da177e4 397 }
41e9a7fa 398 unmap_and_put_page(page, kaddr);
1da177e4
LT
399 }
400 return 1;
401
402not_empty:
41e9a7fa 403 unmap_and_put_page(page, kaddr);
1da177e4
LT
404 return 0;
405}
406
407/* Releases the page */
2d1a9d59
CH
408int minix_set_link(struct minix_dir_entry *de, struct page *page,
409 struct inode *inode)
1da177e4 410{
f4e420dc 411 struct inode *dir = page->mapping->host;
1da177e4 412 struct minix_sb_info *sbi = minix_sb(dir->i_sb);
4812509e 413 loff_t pos = page_offset(page) + offset_in_page(de);
1da177e4
LT
414 int err;
415
416 lock_page(page);
f4e420dc 417 err = minix_prepare_chunk(page, pos, sbi->s_dirsize);
2d1a9d59 418 if (err) {
1da177e4 419 unlock_page(page);
2d1a9d59 420 return err;
1da177e4 421 }
2d1a9d59
CH
422 if (sbi->s_version == MINIX_V3)
423 ((minix3_dirent *)de)->inode = inode->i_ino;
424 else
425 de->inode = inode->i_ino;
f556e776 426 dir_commit_chunk(page, pos, sbi->s_dirsize);
06475f4b 427 inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
1da177e4 428 mark_inode_dirty(dir);
f556e776 429 return minix_handle_dirsync(dir);
1da177e4
LT
430}
431
432struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p)
433{
1da177e4 434 struct minix_sb_info *sbi = minix_sb(dir->i_sb);
ee0d27c9 435 struct minix_dir_entry *de = dir_get_page(dir, 0, p);
1da177e4 436
ee0d27c9
AV
437 if (!IS_ERR(de))
438 return minix_next_entry(de, sbi);
439 return NULL;
1da177e4
LT
440}
441
442ino_t minix_inode_by_name(struct dentry *dentry)
443{
444 struct page *page;
445 struct minix_dir_entry *de = minix_find_entry(dentry, &page);
446 ino_t res = 0;
447
448 if (de) {
9f6c1333
DG
449 struct address_space *mapping = page->mapping;
450 struct inode *inode = mapping->host;
451 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
452
453 if (sbi->s_version == MINIX_V3)
454 res = ((minix3_dirent *) de)->inode;
455 else
456 res = de->inode;
41e9a7fa 457 unmap_and_put_page(page, de);
1da177e4
LT
458 }
459 return res;
460}
This page took 1.224928 seconds and 4 git commands to generate.