1// SPDX-License-Identifier: GPL-2.0
2/*
3 * linux/fs/minix/dir.c
4 *
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * minix directory handling functions
8 *
9 * Updated to filesystem version 3 by Daniel Aragones
10 */
11
12#include "minix.h"
13#include <linux/buffer_head.h>
14#include <linux/highmem.h>
15#include <linux/swap.h>
16
17typedef struct minix_dir_entry minix_dirent;
18typedef struct minix3_dir_entry minix3_dirent;
19
20static int minix_readdir(struct file *, struct dir_context *);
21
22const struct file_operations minix_dir_operations = {
23 .llseek = generic_file_llseek,
24 .read = generic_read_dir,
25 .iterate_shared = minix_readdir,
26 .fsync = generic_file_fsync,
27};
28
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{
36 unsigned last_byte = PAGE_SIZE;
37
38 if (page_nr == (inode->i_size >> PAGE_SHIFT))
39 last_byte = inode->i_size & (PAGE_SIZE - 1);
40 return last_byte;
41}
42
43static void dir_commit_chunk(struct page *page, loff_t pos, unsigned len)
44{
45 struct address_space *mapping = page->mapping;
46 struct inode *dir = mapping->host;
47
48 block_write_end(NULL, mapping, pos, len, len, page, NULL);
49
50 if (pos+len > dir->i_size) {
51 i_size_write(inode: dir, i_size: pos+len);
52 mark_inode_dirty(inode: dir);
53 }
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(mapping: dir->i_mapping);
62 if (!err)
63 err = sync_inode_metadata(inode: dir, wait: 1);
64 return err;
65}
66
67static void *dir_get_page(struct inode *dir, unsigned long n, struct page **p)
68{
69 struct address_space *mapping = dir->i_mapping;
70 struct page *page = read_mapping_page(mapping, index: n, NULL);
71 if (IS_ERR(ptr: page))
72 return ERR_CAST(ptr: page);
73 *p = page;
74 return kmap_local_page(page);
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
82static int minix_readdir(struct file *file, struct dir_context *ctx)
83{
84 struct inode *inode = file_inode(f: file);
85 struct super_block *sb = inode->i_sb;
86 struct minix_sb_info *sbi = minix_sb(sb);
87 unsigned chunk_size = sbi->s_dirsize;
88 unsigned long npages = dir_pages(inode);
89 unsigned long pos = ctx->pos;
90 unsigned offset;
91 unsigned long n;
92
93 ctx->pos = pos = ALIGN(pos, chunk_size);
94 if (pos >= inode->i_size)
95 return 0;
96
97 offset = pos & ~PAGE_MASK;
98 n = pos >> PAGE_SHIFT;
99
100 for ( ; n < npages; n++, offset = 0) {
101 char *p, *kaddr, *limit;
102 struct page *page;
103
104 kaddr = dir_get_page(dir: inode, n, p: &page);
105 if (IS_ERR(ptr: kaddr))
106 continue;
107 p = kaddr+offset;
108 limit = kaddr + minix_last_byte(inode, page_nr: n) - chunk_size;
109 for ( ; p <= limit; p = minix_next_entry(de: p, sbi)) {
110 const char *name;
111 __u32 inumber;
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) {
122 unsigned l = strnlen(p: name, maxlen: sbi->s_namelen);
123 if (!dir_emit(ctx, name, namelen: l,
124 ino: inumber, DT_UNKNOWN)) {
125 unmap_and_put_page(page, addr: p);
126 return 0;
127 }
128 }
129 ctx->pos += chunk_size;
130 }
131 unmap_and_put_page(page, addr: kaddr);
132 }
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(p: name, q: buffer, size: 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;
156 struct inode * dir = d_inode(dentry: dentry->d_parent);
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(inode: dir);
161 struct page *page = NULL;
162 char *p;
163
164 char *namx;
165 __u32 inumber;
166 *res_page = NULL;
167
168 for (n = 0; n < npages; n++) {
169 char *kaddr, *limit;
170
171 kaddr = dir_get_page(dir, n, p: &page);
172 if (IS_ERR(ptr: kaddr))
173 continue;
174
175 limit = kaddr + minix_last_byte(inode: dir, page_nr: n) - sbi->s_dirsize;
176 for (p = kaddr; p <= limit; p = minix_next_entry(de: 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)
187 continue;
188 if (namecompare(len: namelen, maxlen: sbi->s_namelen, name, buffer: namx))
189 goto found;
190 }
191 unmap_and_put_page(page, addr: kaddr);
192 }
193 return NULL;
194
195found:
196 *res_page = page;
197 return (minix_dirent *)p;
198}
199
200int minix_add_link(struct dentry *dentry, struct inode *inode)
201{
202 struct inode *dir = d_inode(dentry: dentry->d_parent);
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;
208 unsigned long npages = dir_pages(inode: dir);
209 unsigned long n;
210 char *kaddr, *p;
211 minix_dirent *de;
212 minix3_dirent *de3;
213 loff_t pos;
214 int err;
215 char *namx = NULL;
216 __u32 inumber;
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++) {
224 char *limit, *dir_end;
225
226 kaddr = dir_get_page(dir, n, p: &page);
227 if (IS_ERR(ptr: kaddr))
228 return PTR_ERR(ptr: kaddr);
229 lock_page(page);
230 dir_end = kaddr + minix_last_byte(inode: dir, page_nr: n);
231 limit = kaddr + PAGE_SIZE - sbi->s_dirsize;
232 for (p = kaddr; p <= limit; p = minix_next_entry(de: 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) {
243 /* We hit i_size */
244 if (sbi->s_version == MINIX_V3)
245 de3->inode = 0;
246 else
247 de->inode = 0;
248 goto got_it;
249 }
250 if (!inumber)
251 goto got_it;
252 err = -EEXIST;
253 if (namecompare(len: namelen, maxlen: sbi->s_namelen, name, buffer: namx))
254 goto out_unlock;
255 }
256 unlock_page(page);
257 unmap_and_put_page(page, addr: kaddr);
258 }
259 BUG();
260 return -EINVAL;
261
262got_it:
263 pos = page_offset(page) + offset_in_page(p);
264 err = minix_prepare_chunk(page, pos, len: sbi->s_dirsize);
265 if (err)
266 goto out_unlock;
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 }
275 dir_commit_chunk(page, pos, len: sbi->s_dirsize);
276 inode_set_mtime_to_ts(inode: dir, ts: inode_set_ctime_current(inode: dir));
277 mark_inode_dirty(inode: dir);
278 err = minix_handle_dirsync(dir);
279out_put:
280 unmap_and_put_page(page, addr: kaddr);
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{
289 struct inode *inode = page->mapping->host;
290 loff_t pos = page_offset(page) + offset_in_page(de);
291 struct minix_sb_info *sbi = minix_sb(sb: inode->i_sb);
292 unsigned len = sbi->s_dirsize;
293 int err;
294
295 lock_page(page);
296 err = minix_prepare_chunk(page, pos, len);
297 if (err) {
298 unlock_page(page);
299 return err;
300 }
301 if (sbi->s_version == MINIX_V3)
302 ((minix3_dirent *)de)->inode = 0;
303 else
304 de->inode = 0;
305 dir_commit_chunk(page, pos, len);
306 inode_set_mtime_to_ts(inode, ts: inode_set_ctime_current(inode));
307 mark_inode_dirty(inode);
308 return minix_handle_dirsync(dir: inode);
309}
310
311int minix_make_empty(struct inode *inode, struct inode *dir)
312{
313 struct page *page = grab_cache_page(mapping: inode->i_mapping, index: 0);
314 struct minix_sb_info *sbi = minix_sb(sb: inode->i_sb);
315 char *kaddr;
316 int err;
317
318 if (!page)
319 return -ENOMEM;
320 err = minix_prepare_chunk(page, pos: 0, len: 2 * sbi->s_dirsize);
321 if (err) {
322 unlock_page(page);
323 goto fail;
324 }
325
326 kaddr = kmap_local_page(page);
327 memset(kaddr, 0, PAGE_SIZE);
328
329 if (sbi->s_version == MINIX_V3) {
330 minix3_dirent *de3 = (minix3_dirent *)kaddr;
331
332 de3->inode = inode->i_ino;
333 strcpy(p: de3->name, q: ".");
334 de3 = minix_next_entry(de: de3, sbi);
335 de3->inode = dir->i_ino;
336 strcpy(p: de3->name, q: "..");
337 } else {
338 minix_dirent *de = (minix_dirent *)kaddr;
339
340 de->inode = inode->i_ino;
341 strcpy(p: de->name, q: ".");
342 de = minix_next_entry(de, sbi);
343 de->inode = dir->i_ino;
344 strcpy(p: de->name, q: "..");
345 }
346 kunmap_local(kaddr);
347
348 dir_commit_chunk(page, pos: 0, len: 2 * sbi->s_dirsize);
349 err = minix_handle_dirsync(dir: inode);
350fail:
351 put_page(page);
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(sb: inode->i_sb);
363 char *name, *kaddr;
364 __u32 inumber;
365
366 for (i = 0; i < npages; i++) {
367 char *p, *limit;
368
369 kaddr = dir_get_page(dir: inode, n: i, p: &page);
370 if (IS_ERR(ptr: kaddr))
371 continue;
372
373 limit = kaddr + minix_last_byte(inode, page_nr: i) - sbi->s_dirsize;
374 for (p = kaddr; p <= limit; p = minix_next_entry(de: 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 }
384
385 if (inumber != 0) {
386 /* check for . and .. */
387 if (name[0] != '.')
388 goto not_empty;
389 if (!name[1]) {
390 if (inumber != inode->i_ino)
391 goto not_empty;
392 } else if (name[1] != '.')
393 goto not_empty;
394 else if (name[2])
395 goto not_empty;
396 }
397 }
398 unmap_and_put_page(page, addr: kaddr);
399 }
400 return 1;
401
402not_empty:
403 unmap_and_put_page(page, addr: kaddr);
404 return 0;
405}
406
407/* Releases the page */
408int minix_set_link(struct minix_dir_entry *de, struct page *page,
409 struct inode *inode)
410{
411 struct inode *dir = page->mapping->host;
412 struct minix_sb_info *sbi = minix_sb(sb: dir->i_sb);
413 loff_t pos = page_offset(page) + offset_in_page(de);
414 int err;
415
416 lock_page(page);
417 err = minix_prepare_chunk(page, pos, len: sbi->s_dirsize);
418 if (err) {
419 unlock_page(page);
420 return err;
421 }
422 if (sbi->s_version == MINIX_V3)
423 ((minix3_dirent *)de)->inode = inode->i_ino;
424 else
425 de->inode = inode->i_ino;
426 dir_commit_chunk(page, pos, len: sbi->s_dirsize);
427 inode_set_mtime_to_ts(inode: dir, ts: inode_set_ctime_current(inode: dir));
428 mark_inode_dirty(inode: dir);
429 return minix_handle_dirsync(dir);
430}
431
432struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p)
433{
434 struct minix_sb_info *sbi = minix_sb(sb: dir->i_sb);
435 struct minix_dir_entry *de = dir_get_page(dir, n: 0, p);
436
437 if (!IS_ERR(ptr: de))
438 return minix_next_entry(de, sbi);
439 return NULL;
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, res_page: &page);
446 ino_t res = 0;
447
448 if (de) {
449 struct address_space *mapping = page->mapping;
450 struct inode *inode = mapping->host;
451 struct minix_sb_info *sbi = minix_sb(sb: inode->i_sb);
452
453 if (sbi->s_version == MINIX_V3)
454 res = ((minix3_dirent *) de)->inode;
455 else
456 res = de->inode;
457 unmap_and_put_page(page, addr: de);
458 }
459 return res;
460}
461

source code of linux/fs/minix/dir.c