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 17 typedef struct minix_dir_entry minix_dirent; 18 typedef struct minix3_dir_entry minix3_dirent; 19 20 static int minix_readdir(struct file *, struct dir_context *); 21 22 const 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 */ 33 static unsigned 34 minix_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 43 static 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(dir, pos+len); 52 mark_inode_dirty(dir); 53 } 54 unlock_page(page); 55 } 56 57 static 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); 64 return err; 65 } 66 67 static 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, n, NULL); 71 if (IS_ERR(page)) 72 return ERR_CAST(page); 73 *p = page; 74 return kmap_local_page(page); 75 } 76 77 static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi) 78 { 79 return (void*)((char*)de + sbi->s_dirsize); 80 } 81 82 static int minix_readdir(struct file *file, struct dir_context *ctx) 83 { 84 struct inode *inode = file_inode(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(inode, n, &page); 105 if (IS_ERR(kaddr)) 106 continue; 107 p = kaddr+offset; 108 limit = kaddr + minix_last_byte(inode, n) - chunk_size; 109 for ( ; p <= limit; p = minix_next_entry(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(name, sbi->s_namelen); 123 if (!dir_emit(ctx, name, l, 124 inumber, DT_UNKNOWN)) { 125 unmap_and_put_page(page, p); 126 return 0; 127 } 128 } 129 ctx->pos += chunk_size; 130 } 131 unmap_and_put_page(page, kaddr); 132 } 133 return 0; 134 } 135 136 static 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 */ 152 minix_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->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(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, &page); 172 if (IS_ERR(kaddr)) 173 continue; 174 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) 187 continue; 188 if (namecompare(namelen, sbi->s_namelen, name, namx)) 189 goto found; 190 } 191 unmap_and_put_page(page, kaddr); 192 } 193 return NULL; 194 195 found: 196 *res_page = page; 197 return (minix_dirent *)p; 198 } 199 200 int minix_add_link(struct dentry *dentry, struct inode *inode) 201 { 202 struct inode *dir = d_inode(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(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, &page); 227 if (IS_ERR(kaddr)) 228 return PTR_ERR(kaddr); 229 lock_page(page); 230 dir_end = kaddr + minix_last_byte(dir, n); 231 limit = kaddr + PAGE_SIZE - sbi->s_dirsize; 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) { 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(namelen, sbi->s_namelen, name, namx)) 254 goto out_unlock; 255 } 256 unlock_page(page); 257 unmap_and_put_page(page, kaddr); 258 } 259 BUG(); 260 return -EINVAL; 261 262 got_it: 263 pos = page_offset(page) + offset_in_page(p); 264 err = minix_prepare_chunk(page, pos, 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, sbi->s_dirsize); 276 inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); 277 mark_inode_dirty(dir); 278 err = minix_handle_dirsync(dir); 279 out_put: 280 unmap_and_put_page(page, kaddr); 281 return err; 282 out_unlock: 283 unlock_page(page); 284 goto out_put; 285 } 286 287 int 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(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, inode_set_ctime_current(inode)); 307 mark_inode_dirty(inode); 308 return minix_handle_dirsync(inode); 309 } 310 311 int minix_make_empty(struct inode *inode, struct inode *dir) 312 { 313 struct page *page = grab_cache_page(inode->i_mapping, 0); 314 struct minix_sb_info *sbi = minix_sb(inode->i_sb); 315 char *kaddr; 316 int err; 317 318 if (!page) 319 return -ENOMEM; 320 err = minix_prepare_chunk(page, 0, 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(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 } 346 kunmap_local(kaddr); 347 348 dir_commit_chunk(page, 0, 2 * sbi->s_dirsize); 349 err = minix_handle_dirsync(inode); 350 fail: 351 put_page(page); 352 return err; 353 } 354 355 /* 356 * routine to check that the specified directory is empty (for rmdir) 357 */ 358 int 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); 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(inode, i, &page); 370 if (IS_ERR(kaddr)) 371 continue; 372 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 } 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, kaddr); 399 } 400 return 1; 401 402 not_empty: 403 unmap_and_put_page(page, kaddr); 404 return 0; 405 } 406 407 /* Releases the page */ 408 int 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(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, 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, sbi->s_dirsize); 427 inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); 428 mark_inode_dirty(dir); 429 return minix_handle_dirsync(dir); 430 } 431 432 struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p) 433 { 434 struct minix_sb_info *sbi = minix_sb(dir->i_sb); 435 struct minix_dir_entry *de = dir_get_page(dir, 0, p); 436 437 if (!IS_ERR(de)) 438 return minix_next_entry(de, sbi); 439 return NULL; 440 } 441 442 ino_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) { 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; 457 unmap_and_put_page(page, de); 458 } 459 return res; 460 } 461
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.