emd.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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