1/* 2 * linux/fs/umsdos/emd.c 3 * 4 * Written 1993 by Jacques Gelinas 5 * 6 * Extended MS-DOS directory handling functions 7 */ 8 9#include <linux/types.h> 10#include <linux/fcntl.h> 11#include <linux/kernel.h> 12#include <linux/sched.h> 13#include <linux/errno.h> 14#include <linux/string.h> 15#include <linux/msdos_fs.h> 16#include <linux/umsdos_fs.h> 17#include <linux/dcache.h> 18#include <linux/pagemap.h> 19#include <linux/delay.h> 20 21void put_entry (struct umsdos_dirent *p, struct umsdos_dirent *q) 22{ 23 p->name_len = q->name_len; 24 p->flags = q->flags; 25 p->nlink = cpu_to_le16(q->nlink); 26 p->uid = cpu_to_le16(q->uid); 27 p->gid = cpu_to_le16(q->gid); 28 p->atime = cpu_to_le32(q->atime); 29 p->mtime = cpu_to_le32(q->mtime); 30 p->ctime = cpu_to_le32(q->ctime); 31 p->rdev = cpu_to_le16(q->rdev); 32 p->mode = cpu_to_le16(q->mode); 33} 34 35static void get_entry(struct umsdos_dirent *p, struct umsdos_dirent *q) 36{ 37 p->name_len = q->name_len; 38 p->name[p->name_len]='\0'; 39 p->flags = q->flags; 40 p->nlink = le16_to_cpu (q->nlink); 41 p->uid = le16_to_cpu (q->uid); 42 p->gid = le16_to_cpu (q->gid); 43 p->atime = le32_to_cpu (q->atime); 44 p->mtime = le32_to_cpu (q->mtime); 45 p->ctime = le32_to_cpu (q->ctime); 46 p->rdev = le16_to_cpu (q->rdev); 47 p->mode = le16_to_cpu (q->mode); 48} 49 50/* 51 * Lookup the EMD dentry for a directory. 52 * 53 * Note: the caller must hold a lock on the parent directory. 54 */ 55struct dentry *umsdos_get_emd_dentry(struct dentry *parent) 56{ 57 struct dentry *demd; 58 59 demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE, 60 UMSDOS_EMD_NAMELEN, 1); 61 return demd; 62} 63 64/* 65 * Check whether a directory has an EMD file. 66 * 67 * Note: the caller must hold a lock on the parent directory. 68 */ 69int umsdos_have_emd(struct dentry *dir) 70{ 71 struct dentry *demd = umsdos_get_emd_dentry (dir); 72 int found = 0; 73 74 if (!IS_ERR(demd)) { 75 if (demd->d_inode) 76 found = 1; 77 dput(demd); 78 } 79 return found; 80} 81 82/* 83 * Create the EMD file for a directory if it doesn't 84 * already exist. Returns 0 or an error code. 85 * 86 * Note: the caller must hold a lock on the parent directory. 87 */ 88int umsdos_make_emd(struct dentry *parent) 89{ 90 struct dentry *demd = umsdos_get_emd_dentry(parent); 91 int err = PTR_ERR(demd); 92 93 if (IS_ERR(demd)) { 94 printk("umsdos_make_emd: can't get dentry in %s, err=%d\n", 95 parent->d_name.name, err); 96 goto out; 97 } 98 99 /* already created? */ 100 err = 0; 101 if (demd->d_inode) 102 goto out_set; 103 104Printk(("umsdos_make_emd: creating EMD %s/%s\n", 105parent->d_name.name, demd->d_name.name)); 106 107 err = msdos_create(parent->d_inode, demd, S_IFREG | 0777); 108 if (err) { 109 printk (KERN_WARNING 110 "umsdos_make_emd: create %s/%s failed, err=%d\n", 111 parent->d_name.name, demd->d_name.name, err); 112 } 113out_set: 114 dput(demd); 115out: 116 return err; 117} 118 119 120/* 121 * Read an entry from the EMD file. 122 * Support variable length record. 123 * Return -EIO if error, 0 if OK. 124 * 125 * does not change {d,i}_count 126 */ 127 128int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_dirent *entry) 129{ 130 struct address_space *mapping = demd->d_inode->i_mapping; 131 struct page *page; 132 struct umsdos_dirent *p; 133 int offs = *pos & ~PAGE_CACHE_MASK; 134 int recsize; 135 int ret = 0; 136 137 page = read_cache_page(mapping, *pos>>PAGE_CACHE_SHIFT, 138 (filler_t*)mapping->a_ops->readpage, NULL); 139 if (IS_ERR(page)) 140 goto sync_fail; 141 wait_on_page(page); 142 if (!Page_Uptodate(page)) 143 goto async_fail; 144 p = (struct umsdos_dirent*)(kmap(page)+offs); 145 146 /* if this is an invalid entry (invalid name length), ignore it */ 147 if( p->name_len > UMSDOS_MAXNAME ) 148 { 149 printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len); 150 p->name_len = 0; 151 ret = -ENAMETOOLONG; /* notify umssync(8) code that something is wrong */ 152 } 153 154 recsize = umsdos_evalrecsize(p->name_len); 155 if (offs + recsize > PAGE_CACHE_SIZE) { 156 struct page *page2; 157 int part = (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare; 158 page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT), 159 (filler_t*)mapping->a_ops->readpage, NULL); 160 if (IS_ERR(page2)) { 161 kunmap(page); 162 page_cache_release(page); 163 page = page2; 164 goto sync_fail; 165 } 166 wait_on_page(page2); 167 if (!Page_Uptodate(page2)) { 168 kunmap(page); 169 page_cache_release(page2); 170 goto async_fail; 171 } 172 memcpy(entry->spare,p->spare,part); 173 memcpy(entry->spare+part,kmap(page2), 174 recsize+offs-PAGE_CACHE_SIZE); 175 kunmap(page2); 176 page_cache_release(page2); 177 } else 178 memcpy(entry->spare,p->spare,((char*)p+recsize)-p->spare); 179 get_entry(entry, p); 180 kunmap(page); 181 page_cache_release(page); 182 *pos += recsize; 183 return ret; 184async_fail: 185 page_cache_release(page); 186 page = ERR_PTR(-EIO); 187sync_fail: 188 return PTR_ERR(page); 189} 190 191 192/* 193 * Write an entry in the EMD file. 194 * Return 0 if OK, -EIO if some error. 195 * 196 * Note: the caller must hold a lock on the parent directory. 197 */ 198int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, 199 int free_entry) 200{ 201 struct inode *dir = parent->d_inode; 202 struct umsdos_dirent *entry = &info->entry; 203 struct dentry *emd_dentry; 204 int ret; 205 struct umsdos_dirent entry0,*p; 206 struct address_space *mapping; 207 struct page *page, *page2 = NULL; 208 int offs; 209 210 emd_dentry = umsdos_get_emd_dentry(parent); 211 ret = PTR_ERR(emd_dentry); 212 if (IS_ERR(emd_dentry)) 213 goto out; 214 /* make sure there's an EMD file */ 215 ret = -EIO; 216 if (!emd_dentry->d_inode) { 217 printk(KERN_WARNING 218 "umsdos_writeentry: no EMD file in %s/%s\n", 219 parent->d_parent->d_name.name, parent->d_name.name); 220 goto out_dput; 221 } 222 223 if (free_entry) { 224 /* #Specification: EMD file / empty entries 225 * Unused entries in the EMD file are identified 226 * by the name_len field equal to 0. However to 227 * help future extension (or bug correction :-( ), 228 * empty entries are filled with 0. 229 */ 230 memset (&entry0, 0, sizeof (entry0)); 231 entry = &entry0; 232 } else if (entry->name_len > 0) { 233 memset (entry->name + entry->name_len, '\0', 234 sizeof (entry->name) - entry->name_len); 235 /* #Specification: EMD file / spare bytes 236 * 10 bytes are unused in each record of the EMD. They 237 * are set to 0 all the time, so it will be possible 238 * to do new stuff and rely on the state of those 239 * bytes in old EMD files. 240 */ 241 memset (entry->spare, 0, sizeof (entry->spare)); 242 } 243 244 /* write the entry and update the parent timestamps */ 245 mapping = emd_dentry->d_inode->i_mapping; 246 offs = info->f_pos & ~PAGE_CACHE_MASK; 247 ret = -ENOMEM; 248 page = grab_cache_page(mapping, info->f_pos>>PAGE_CACHE_SHIFT); 249 if (!page) 250 goto out_dput; 251 p = (struct umsdos_dirent *) (page_address(page) + offs); 252 if (offs + info->recsize > PAGE_CACHE_SIZE) { 253 ret = mapping->a_ops->prepare_write(NULL,page,offs, 254 PAGE_CACHE_SIZE); 255 if (ret) 256 goto out_unlock; 257 page2 = grab_cache_page(mapping, 258 (info->f_pos>>PAGE_CACHE_SHIFT)+1); 259 if (!page2) 260 goto out_unlock2; 261 ret = mapping->a_ops->prepare_write(NULL,page2,0, 262 offs+info->recsize-PAGE_CACHE_SIZE); 263 if (ret) 264 goto out_unlock3; 265 put_entry (p, entry); 266 memcpy(p->spare,entry->spare, 267 (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare); 268 memcpy(page_address(page2), 269 ((char*)entry)+PAGE_CACHE_SIZE-offs, 270 offs+info->recsize-PAGE_CACHE_SIZE); 271 ret = mapping->a_ops->commit_write(NULL,page2,0, 272 offs+info->recsize-PAGE_CACHE_SIZE); 273 if (ret) 274 goto out_unlock3; 275 ret = mapping->a_ops->commit_write(NULL,page,offs, 276 PAGE_CACHE_SIZE); 277 UnlockPage(page2); 278 page_cache_release(page2); 279 if (ret) 280 goto out_unlock; 281 } else { 282 ret = mapping->a_ops->prepare_write(NULL,page,offs, 283 offs + info->recsize); 284 if (ret) 285 goto out_unlock; 286 put_entry (p, entry); 287 memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare); 288 ret = mapping->a_ops->commit_write(NULL,page,offs, 289 offs + info->recsize); 290 if (ret) 291 goto out_unlock; 292 } 293 UnlockPage(page); 294 page_cache_release(page); 295 296 dir->i_ctime = dir->i_mtime = CURRENT_TIME; 297 mark_inode_dirty(dir); 298 299out_dput: 300 dput(emd_dentry); 301out: 302 Printk (("umsdos_writeentry /mn/: returning %d...\n", ret)); 303 return ret; 304out_unlock3: 305 UnlockPage(page2); 306 page_cache_release(page2); 307out_unlock2: 308 ClearPageUptodate(page); 309 kunmap(page); 310out_unlock: 311 UnlockPage(page); 312 page_cache_release(page); 313 printk ("UMSDOS: problem with EMD file: can't write\n"); 314 goto out_dput; 315} 316 317/* 318 * General search, locate a name in the EMD file or an empty slot to 319 * store it. if info->entry.name_len == 0, search the first empty 320 * slot (of the proper size). 321 * 322 * Return 0 if found, -ENOENT if not found, another error code if 323 * other problem. 324 * 325 * So this routine is used to either find an existing entry or to 326 * create a new one, while making sure it is a new one. After you 327 * get -ENOENT, you make sure the entry is stuffed correctly and 328 * call umsdos_writeentry(). 329 * 330 * To delete an entry, you find it, zero out the entry (memset) 331 * and call umsdos_writeentry(). 332 * 333 * All this to say that umsdos_writeentry must be called after this 334 * function since it relies on the f_pos field of info. 335 * 336 * Note: the caller must hold a lock on the parent directory. 337 */ 338/* #Specification: EMD file structure 339 * The EMD file uses a fairly simple layout. It is made of records 340 * (UMSDOS_REC_SIZE == 64). When a name can't be written in a single 341 * record, multiple contiguous records are allocated. 342 */ 343 344static int umsdos_find (struct dentry *demd, struct umsdos_info *info) 345{ 346 struct umsdos_dirent *entry = &info->entry; 347 int recsize = info->recsize; 348 struct inode *emd_dir; 349 int ret = -ENOENT; 350 struct { 351 off_t posok; /* Position available to store the entry */ 352 off_t one; /* One empty position -> maybe <- large enough */ 353 } empty; 354 int found = 0; 355 int empty_size = 0; 356 struct address_space *mapping; 357 filler_t *readpage; 358 struct page *page = NULL; 359 int index = -1; 360 int offs = PAGE_CACHE_SIZE,max_offs = PAGE_CACHE_SIZE; 361 char *p = NULL; 362 loff_t pos = 0; 363 364 /* make sure there's an EMD file ... */ 365 ret = -ENOENT; 366 emd_dir = demd->d_inode; 367 if (!emd_dir) 368 goto out_dput; 369 mapping = emd_dir->i_mapping; 370 readpage = (filler_t*)mapping->a_ops->readpage; 371 372 empty.posok = emd_dir->i_size; 373 while (1) { 374 struct umsdos_dirent *rentry; 375 int entry_size; 376 377 if (offs >= max_offs) { 378 if (page) { 379 kunmap(page); 380 page_cache_release(page); 381 page = NULL; 382 } 383 if (pos >= emd_dir->i_size) { 384 info->f_pos = empty.posok; 385 break; 386 } 387 if (++index == (emd_dir->i_size>>PAGE_CACHE_SHIFT)) 388 max_offs = emd_dir->i_size & ~PAGE_CACHE_MASK; 389 offs -= PAGE_CACHE_SIZE; 390 page = read_cache_page(mapping,index,readpage,NULL); 391 if (IS_ERR(page)) 392 goto sync_fail; 393 wait_on_page(page); 394 if (!Page_Uptodate(page)) 395 goto async_fail; 396 p = kmap(page); 397 } 398 399 rentry = (struct umsdos_dirent *)(p+offs); 400 401 if (rentry->name_len == 0) { 402 /* We are looking for an empty section at least */ 403 /* as large as recsize. */ 404 if (entry->name_len == 0) { 405 info->f_pos = pos; 406 ret = 0; 407 break; 408 } 409 offs += UMSDOS_REC_SIZE; 410 pos += UMSDOS_REC_SIZE; 411 if (found) 412 continue; 413 if (!empty_size) 414 empty.one = pos-UMSDOS_REC_SIZE; 415 empty_size += UMSDOS_REC_SIZE; 416 if (empty_size == recsize) { 417 /* Here is a large enough section. */ 418 empty.posok = empty.one; 419 found = 1; 420 } 421 continue; 422 } 423 424 entry_size = umsdos_evalrecsize(rentry->name_len); 425 if (entry_size > PAGE_CACHE_SIZE) 426 goto async_fail; 427 empty_size = 0; 428 if (entry->name_len != rentry->name_len) 429 goto skip_it; 430 431 if (entry_size + offs > PAGE_CACHE_SIZE) { 432 /* Sucker spans the page boundary */ 433 int len = (p+PAGE_CACHE_SIZE)-rentry->name; 434 struct page *next_page; 435 char *q; 436 next_page = read_cache_page(mapping,index+1,readpage,NULL); 437 if (IS_ERR(next_page)) { 438 page_cache_release(page); 439 page = next_page; 440 goto sync_fail; 441 } 442 wait_on_page(next_page); 443 if (!Page_Uptodate(next_page)) { 444 page_cache_release(page); 445 page = next_page; 446 goto async_fail; 447 } 448 q = kmap(next_page); 449 if (memcmp(entry->name, rentry->name, len) || 450 memcmp(entry->name+len, q, entry->name_len-len)) { 451 kunmap(next_page); 452 page_cache_release(next_page); 453 goto skip_it; 454 } 455 kunmap(next_page); 456 page_cache_release(next_page); 457 } else if (memcmp (entry->name, rentry->name, entry->name_len)) 458 goto skip_it; 459 460 info->f_pos = pos; 461 get_entry(entry, rentry); 462 ret = 0; 463 break; 464skip_it: 465 offs+=entry_size; 466 pos+=entry_size; 467 } 468 if (page) { 469 kunmap(page); 470 page_cache_release(page); 471 } 472 umsdos_manglename (info); 473 474out_dput: 475 dput(demd); 476 return ret; 477 478async_fail: 479 page_cache_release(page); 480 page = ERR_PTR(-EIO); 481sync_fail: 482 return PTR_ERR(page); 483} 484 485 486/* 487 * Add a new entry in the EMD file. 488 * Return 0 if OK or a negative error code. 489 * Return -EEXIST if the entry already exists. 490 * 491 * Complete the information missing in info. 492 * 493 * N.B. What if the EMD file doesn't exist? 494 */ 495 496int umsdos_newentry (struct dentry *parent, struct umsdos_info *info) 497{ 498 int err, ret = -EEXIST; 499 struct dentry *demd = umsdos_get_emd_dentry(parent); 500 501 ret = PTR_ERR(demd); 502 if (IS_ERR(demd)) 503 goto out; 504 err = umsdos_find (demd, info); 505 if (err && err == -ENOENT) { 506 ret = umsdos_writeentry (parent, info, 0); 507 Printk (("umsdos_writeentry EMD ret = %d\n", ret)); 508 } 509out: 510 return ret; 511} 512 513 514/* 515 * Create a new hidden link. 516 * Return 0 if OK, an error code if not. 517 */ 518 519/* #Specification: hard link / hidden name 520 * When a hard link is created, the original file is renamed 521 * to a hidden name. The name is "..LINKNNN" where NNN is a 522 * number define from the entry offset in the EMD file. 523 */ 524int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info) 525{ 526 int ret; 527 struct dentry *demd = umsdos_get_emd_dentry(parent); 528 ret = PTR_ERR(demd); 529 if (IS_ERR(demd)) 530 goto out; 531 532 umsdos_parse ("..LINK", 6, info); 533 info->entry.name_len = 0; 534 ret = umsdos_find (demd, info); 535 if (ret == -ENOENT || ret == 0) { 536 info->entry.name_len = sprintf (info->entry.name, 537 "..LINK%ld", info->f_pos); 538 ret = 0; 539 } 540out: 541 return ret; 542} 543 544 545/* 546 * Remove an entry from the EMD file. 547 * Return 0 if OK, a negative error code otherwise. 548 * 549 * Complete the information missing in info. 550 */ 551 552int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir) 553{ 554 int ret; 555 struct dentry *demd = umsdos_get_emd_dentry(parent); 556 557 ret = PTR_ERR(demd); 558 if (IS_ERR(demd)) 559 goto out; 560 ret = umsdos_find (demd, info); 561 if (ret) 562 goto out; 563 if (info->entry.name_len == 0) 564 goto out; 565 566 if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) { 567 if (S_ISDIR (info->entry.mode)) { 568 ret = -EISDIR; 569 } else { 570 ret = -ENOTDIR; 571 } 572 goto out; 573 } 574 ret = umsdos_writeentry (parent, info, 1); 575 576out: 577 return ret; 578} 579 580 581/* 582 * Verify that an EMD directory is empty. 583 * Return: 584 * 0 if not empty, 585 * 1 if empty (except for EMD file), 586 * 2 if empty or no EMD file. 587 */ 588 589int umsdos_isempty (struct dentry *dentry) 590{ 591 struct dentry *demd; 592 int ret = 2; 593 loff_t pos = 0; 594 595 demd = umsdos_get_emd_dentry(dentry); 596 if (IS_ERR(demd)) 597 goto out; 598 /* If the EMD file does not exist, it is certainly empty. :-) */ 599 if (!demd->d_inode) 600 goto out_dput; 601 602 ret = 1; 603 while (pos < demd->d_inode->i_size) { 604 struct umsdos_dirent entry; 605 606 if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) { 607 ret = 0; 608 break; 609 } 610 if (entry.name_len != 0) { 611 ret = 0; 612 break; 613 } 614 } 615 616out_dput: 617 dput(demd); 618out: 619 return ret; 620} 621 622/* 623 * Locate an entry in a EMD directory. 624 * Return 0 if OK, error code if not, generally -ENOENT. 625 * 626 * expect argument: 627 * 0: anything 628 * 1: file 629 * 2: directory 630 */ 631 632int umsdos_findentry (struct dentry *parent, struct umsdos_info *info, 633 int expect) 634{ 635 int ret; 636 struct dentry *demd = umsdos_get_emd_dentry(parent); 637 638 ret = PTR_ERR(demd); 639 if (IS_ERR(demd)) 640 goto out; 641 ret = umsdos_find (demd, info); 642 if (ret) 643 goto out; 644 645 switch (expect) { 646 case 1: 647 if (S_ISDIR (info->entry.mode)) 648 ret = -EISDIR; 649 break; 650 case 2: 651 if (!S_ISDIR (info->entry.mode)) 652 ret = -ENOTDIR; 653 } 654 655out: 656 Printk (("umsdos_findentry: returning %d\n", ret)); 657 return ret; 658} 659