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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/umsdos/namei.c
  3.  *
  4.  *      Written 1993 by Jacques Gelinas 
  5.  *      Inspired from linux/fs/msdos/... by Werner Almesberger
  6.  *
  7.  * Maintain and access the --linux alternate directory file.
  8.  */
  9.  /*
  10.   * You are in the maze of twisted functions - half of them shouldn't
  11.   * be here...
  12.   */
  13. #include <linux/errno.h>
  14. #include <linux/kernel.h>
  15. #include <linux/sched.h>
  16. #include <linux/types.h>
  17. #include <linux/fcntl.h>
  18. #include <linux/stat.h>
  19. #include <linux/string.h>
  20. #include <linux/msdos_fs.h>
  21. #include <linux/umsdos_fs.h>
  22. #include <linux/slab.h>
  23. #define UMSDOS_DIR_LOCK
  24. #ifdef UMSDOS_DIR_LOCK
  25. static inline void u_sleep_on (struct inode *dir)
  26. {
  27. sleep_on (&dir->u.umsdos_i.dir_info.p);
  28. }
  29. static inline void u_wake_up (struct inode *dir)
  30. {
  31.      wake_up (&dir->u.umsdos_i.dir_info.p);
  32. }
  33. /*
  34.  * Wait for creation exclusivity.
  35.  * Return 0 if the dir was already available.
  36.  * Return 1 if a wait was necessary.
  37.  * When 1 is return, it means a wait was done. It does not
  38.  * mean the directory is available.
  39.  */
  40. static int umsdos_waitcreate (struct inode *dir)
  41. {
  42. int ret = 0;
  43. if (dir->u.umsdos_i.dir_info.creating
  44.     && dir->u.umsdos_i.dir_info.pid != current->pid) {
  45.      PRINTK (("creating && dir_info.pid=%lu, current->pid=%un", dir->u.umsdos_i.dir_info.pid, current->pid));
  46.      u_sleep_on (dir);
  47. ret = 1;
  48. }
  49. return ret;
  50. }
  51. /*
  52.  * Wait for any lookup process to finish
  53.  */
  54. static void umsdos_waitlookup (struct inode *dir)
  55. {
  56. while (dir->u.umsdos_i.dir_info.looking) {
  57.      u_sleep_on (dir);
  58. }
  59. }
  60. /*
  61.  * Lock all other process out of this directory.
  62.  */
  63. /* #Specification: file creation / not atomic
  64.  * File creation is a two step process. First we create (allocate)
  65.  * an entry in the EMD file and then (using the entry offset) we
  66.  * build a unique name for MSDOS. We create this name in the msdos
  67.  * space.
  68.  * 
  69.  * We have to use semaphore (sleep_on/wake_up) to prevent lookup
  70.  * into a directory when we create a file or directory and to
  71.  * prevent creation while a lookup is going on. Since many lookup
  72.  * may happen at the same time, the semaphore is a counter.
  73.  * 
  74.  * Only one creation is allowed at the same time. This protection
  75.  * may not be necessary. The problem arise mainly when a lookup
  76.  * or a readdir is done while a file is partially created. The
  77.  * lookup process see that as a "normal" problem and silently
  78.  * erase the file from the EMD file. Normal because a file
  79.  * may be erased during a MSDOS session, but not removed from
  80.  * the EMD file.
  81.  * 
  82.  * The locking is done on a directory per directory basis. Each
  83.  * directory inode has its wait_queue.
  84.  * 
  85.  * For some operation like hard link, things even get worse. Many
  86.  * creation must occur at once (atomic). To simplify the design
  87.  * a process is allowed to recursively lock the directory for
  88.  * creation. The pid of the locking process is kept along with
  89.  * a counter so a second level of locking is granted or not.
  90.  */
  91. void umsdos_lockcreate (struct inode *dir)
  92. {
  93. /*
  94.  * Wait for any creation process to finish except
  95.  * if we (the process) own the lock
  96.  */
  97. while (umsdos_waitcreate (dir) != 0);
  98. dir->u.umsdos_i.dir_info.creating++;
  99. dir->u.umsdos_i.dir_info.pid = current->pid;
  100. umsdos_waitlookup (dir);
  101. }
  102. /*
  103.  * Lock all other process out of those two directories.
  104.  */
  105. static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
  106. {
  107. /*
  108.  * We must check that both directory are available before
  109.  * locking anyone of them. This is to avoid some deadlock.
  110.  * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
  111.  * this to me.
  112.  */
  113. while (1) {
  114. if (umsdos_waitcreate (dir1) == 0
  115.     && umsdos_waitcreate (dir2) == 0) {
  116. /* We own both now */
  117. dir1->u.umsdos_i.dir_info.creating++;
  118. dir1->u.umsdos_i.dir_info.pid = current->pid;
  119. dir2->u.umsdos_i.dir_info.creating++;
  120. dir2->u.umsdos_i.dir_info.pid = current->pid;
  121. break;
  122. }
  123. }
  124. umsdos_waitlookup (dir1);
  125. umsdos_waitlookup (dir2);
  126. }
  127. /*
  128.  * Wait until creation is finish in this directory.
  129.  */
  130. void umsdos_startlookup (struct inode *dir)
  131. {
  132. while (umsdos_waitcreate (dir) != 0);
  133. dir->u.umsdos_i.dir_info.looking++;
  134. }
  135. /*
  136.  * Unlock the directory.
  137.  */
  138. void umsdos_unlockcreate (struct inode *dir)
  139. {
  140. dir->u.umsdos_i.dir_info.creating--;
  141. if (dir->u.umsdos_i.dir_info.creating < 0) {
  142. printk ("UMSDOS: dir->u.umsdos_i.dir_info.creating < 0: %d"
  143. ,dir->u.umsdos_i.dir_info.creating);
  144. }
  145.      u_wake_up (dir);
  146. }
  147. /*
  148.  * Tell directory lookup is over.
  149.  */
  150. void umsdos_endlookup (struct inode *dir)
  151. {
  152. dir->u.umsdos_i.dir_info.looking--;
  153. if (dir->u.umsdos_i.dir_info.looking < 0) {
  154. printk ("UMSDOS: dir->u.umsdos_i.dir_info.looking < 0: %d"
  155. ,dir->u.umsdos_i.dir_info.looking);
  156. }
  157.      u_wake_up (dir);
  158. }
  159. #else
  160. static void umsdos_lockcreate (struct inode *dir)
  161. {
  162. }
  163. static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
  164. {
  165. }
  166. void umsdos_startlookup (struct inode *dir)
  167. {
  168. }
  169. static void umsdos_unlockcreate (struct inode *dir)
  170. {
  171. }
  172. void umsdos_endlookup (struct inode *dir)
  173. {
  174. }
  175. #endif
  176. static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
  177. int errcod)
  178. {
  179. int ret = 0;
  180. if (umsdos_is_pseudodos (dir, dentry)) {
  181. /* #Specification: pseudo root / any file creation /DOS
  182.  * The pseudo sub-directory /DOS can't be created!
  183.  * EEXIST is returned.
  184.  * 
  185.  * The pseudo sub-directory /DOS can't be removed!
  186.  * EPERM is returned.
  187.  */
  188. ret = errcod;
  189. }
  190. return ret;
  191. }
  192. /*
  193.  * Add a new file (ordinary or special) into the alternate directory.
  194.  * The file is added to the real MSDOS directory. If successful, it
  195.  * is then added to the EMD file.
  196.  * 
  197.  * Return the status of the operation. 0 mean success.
  198.  *
  199.  * #Specification: create / file exists in DOS
  200.  * Here is a situation: we are trying to create a file with
  201.  * UMSDOS. The file is unknown to UMSDOS but already
  202.  * exists in the DOS directory.
  203.  * 
  204.  * Here is what we are NOT doing:
  205.  * 
  206.  * We could silently assume that everything is fine
  207.  * and allows the creation to succeed.
  208.  * 
  209.  * It is possible not all files in the partition
  210.  * are meant to be visible from linux. By trying to create
  211.  * those file in some directory, one user may get access
  212.  * to those file without proper permissions. Looks like
  213.  * a security hole to me. Off course sharing a file system
  214.  * with DOS is some kind of security hole :-)
  215.  * 
  216.  * So ?
  217.  * 
  218.  * We return EEXIST in this case.
  219.  * The same is true for directory creation.
  220.  */
  221. static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
  222. int mode, int rdev, char flags)
  223. {
  224. struct dentry *fake;
  225. struct inode *inode;
  226. int ret;
  227. struct umsdos_info info;
  228. ret = umsdos_nevercreat (dir, dentry, -EEXIST);
  229. if (ret)
  230. goto out;
  231. ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  232. if (ret)
  233. goto out;
  234. info.entry.mode = mode;
  235. info.entry.rdev = rdev;
  236. info.entry.flags = flags;
  237. info.entry.uid = current->fsuid;
  238. info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
  239. info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
  240. info.entry.nlink = 1;
  241. ret = umsdos_newentry (dentry->d_parent, &info);
  242. if (ret)
  243. goto out;
  244. /* do a real lookup to get the short name dentry */
  245. fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
  246. ret = PTR_ERR(fake);
  247. if (IS_ERR(fake))
  248. goto out_remove;
  249. /* should not exist yet ... */
  250. ret = -EEXIST;
  251. if (fake->d_inode)
  252. goto out_remove_dput;
  253. ret = msdos_create (dir, fake, S_IFREG | 0777);
  254. if (ret)
  255. goto out_remove_dput;
  256. inode = fake->d_inode;
  257. atomic_inc(&inode->i_count);
  258. d_instantiate (dentry, inode);
  259. dput(fake);
  260. if (atomic_read(&inode->i_count) > 1) {
  261. printk(KERN_WARNING
  262. "umsdos_create_any: %s/%s, ino=%ld, icount=%d??n",
  263. dentry->d_parent->d_name.name, dentry->d_name.name,
  264. inode->i_ino, atomic_read(&inode->i_count));
  265. }
  266. umsdos_lookup_patch_new(dentry, &info);
  267. out:
  268. return ret;
  269. /* Creation failed ... remove the EMD entry */
  270. out_remove_dput:
  271. dput(fake);
  272. out_remove:
  273. if (ret == -EEXIST)
  274. printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%sn",
  275. dentry->d_parent->d_name.name, info.fake.fname);
  276. umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
  277. goto out;
  278. }
  279. /*
  280.  * Add a new file into the alternate directory.
  281.  * The file is added to the real MSDOS directory. If successful, it
  282.  * is then added to the EMD file.
  283.  * 
  284.  * Return the status of the operation. 0 mean success.
  285.  */
  286. int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
  287. {
  288. return umsdos_create_any (dir, dentry, mode, 0, 0);
  289. }
  290. /*
  291.  * Initialise the new_entry from the old for a rename operation.
  292.  * (Only useful for umsdos_rename_f() below).
  293.  */
  294. static void umsdos_ren_init (struct umsdos_info *new_info,
  295.      struct umsdos_info *old_info)
  296. {
  297. new_info->entry.mode = old_info->entry.mode;
  298. new_info->entry.rdev = old_info->entry.rdev;
  299. new_info->entry.uid = old_info->entry.uid;
  300. new_info->entry.gid = old_info->entry.gid;
  301. new_info->entry.ctime = old_info->entry.ctime;
  302. new_info->entry.atime = old_info->entry.atime;
  303. new_info->entry.mtime = old_info->entry.mtime;
  304. new_info->entry.flags = old_info->entry.flags;
  305. new_info->entry.nlink = old_info->entry.nlink;
  306. }
  307. /*
  308.  * Rename a file (move) in the file system.
  309.  */
  310.  
  311. static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
  312.     struct inode *new_dir, struct dentry *new_dentry,
  313.     int flags)
  314. {
  315. struct inode *old_inode = old_dentry->d_inode;
  316. struct dentry *old, *new, *old_emd;
  317. int err, ret;
  318. struct umsdos_info old_info;
  319. struct umsdos_info new_info;
  320.   ret = -EPERM;
  321. err = umsdos_parse (old_dentry->d_name.name,
  322. old_dentry->d_name.len, &old_info);
  323. if (err)
  324. goto out;
  325. err = umsdos_parse (new_dentry->d_name.name,
  326. new_dentry->d_name.len, &new_info);
  327. if (err)
  328. goto out;
  329. /* Get the EMD dentry for the old parent */
  330. old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
  331. ret = PTR_ERR(old_emd);
  332. if (IS_ERR(old_emd))
  333. goto out;
  334. umsdos_lockcreate2 (old_dir, new_dir);
  335. ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
  336. if (ret)
  337. goto out_unlock;
  338. err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
  339. if (err == 0) {
  340. /* check whether it _really_ exists ... */
  341. ret = -EEXIST;
  342. if (new_dentry->d_inode)
  343. goto out_unlock;
  344. /* bogus lookup? complain and fix up the EMD ... */
  345. printk(KERN_WARNING
  346. "umsdos_rename_f: entry %s/%s exists, inode NULL??n",
  347. new_dentry->d_parent->d_name.name, new_info.entry.name);
  348. err = umsdos_delentry(new_dentry->d_parent, &new_info,
  349. S_ISDIR(new_info.entry.mode));
  350. }
  351. umsdos_ren_init (&new_info, &old_info);
  352. if (flags)
  353. new_info.entry.flags = flags;
  354. ret = umsdos_newentry (new_dentry->d_parent, &new_info);
  355. if (ret)
  356. goto out_unlock;
  357. /* If we're moving a hardlink, drop it first */
  358. if (old_info.entry.flags & UMSDOS_HLINK) {
  359. d_drop(old_dentry);
  360. }
  361. old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname, 
  362. old_info.fake.len);
  363. ret = PTR_ERR(old);
  364. if (IS_ERR(old))
  365. goto out_unlock;
  366. /* make sure it's the same inode! */
  367. ret = -ENOENT;
  368. /*
  369.  * note: for hardlinks they will be different!
  370.  *  old_inode will contain inode of .LINKxxx file containing data, and
  371.  *  old->d_inode will contain inode of file containing path to .LINKxxx file
  372.  */
  373. if (!(old_info.entry.flags & UMSDOS_HLINK)) {
  374.   if (old->d_inode != old_inode)
  375.   goto out_dput;
  376. }
  377. new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, 
  378. new_info.fake.len);
  379. ret = PTR_ERR(new);
  380. if (IS_ERR(new))
  381. goto out_dput;
  382. /* Do the msdos-level rename */
  383. ret = msdos_rename (old_dir, old, new_dir, new);
  384. dput(new);
  385. /* If the rename failed, remove the new EMD entry */
  386. if (ret != 0) {
  387. umsdos_delentry (new_dentry->d_parent, &new_info,
  388.  S_ISDIR (new_info.entry.mode));
  389. goto out_dput;
  390. }
  391. /*
  392.  * Rename successful ... remove the old name from the EMD.
  393.  * Note that we use the EMD parent here, as the old dentry
  394.  * may have moved to a new parent ...
  395.  */
  396. err = umsdos_delentry (old_emd->d_parent, &old_info,
  397. S_ISDIR (old_info.entry.mode));
  398. if (err) {
  399. /* Failed? Complain a bit, but don't fail the operation */
  400. printk(KERN_WARNING 
  401. "umsdos_rename_f: delentry %s/%s failed, error=%dn",
  402. old_emd->d_parent->d_name.name, old_info.entry.name,
  403. err);
  404. }
  405. /*
  406.  * Update f_pos so notify_change will succeed
  407.  * if the file was already in use.
  408.  */
  409. umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
  410. /* dput() the dentry if we haven't already */
  411. out_dput:
  412. dput(old);
  413. out_unlock:
  414. dput(old_emd);
  415. umsdos_unlockcreate (old_dir);
  416. umsdos_unlockcreate (new_dir);
  417. out:
  418. Printk ((" _ret=%dn", ret));
  419. return ret;
  420. }
  421. /*
  422.  * Setup a Symbolic link or a (pseudo) hard link
  423.  * Return a negative error code or 0 if OK.
  424.  */
  425. /* #Specification: symbolic links / strategy
  426.  * A symbolic link is simply a file which holds a path. It is
  427.  * implemented as a normal MSDOS file (not very space efficient :-()
  428.  * 
  429.  * I see two different ways to do this: One is to place the link data
  430.  * in unused entries of the EMD file; the other is to have a separate
  431.  * file dedicated to hold all symbolic links data.
  432.  * 
  433.  * Let's go for simplicity...
  434.  */
  435. /*
  436.  * AV. Should be called with dir->i_sem down.
  437.  */
  438. static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
  439. const char *symname, int mode, char flags)
  440. {
  441. int ret, len;
  442. ret = umsdos_create_any (dir, dentry, mode, 0, flags);
  443. if (ret) {
  444. printk(KERN_WARNING
  445. "umsdos_symlink: create failed, ret=%dn", ret);
  446. goto out;
  447. }
  448. len = strlen (symname) + 1;
  449. ret = block_symlink(dentry->d_inode, symname, len);
  450. if (ret < 0)
  451. goto out_unlink;
  452. out:
  453. return ret;
  454. out_unlink:
  455. printk(KERN_WARNING "umsdos_symlink: write failed, unlinkingn");
  456. UMSDOS_unlink (dir, dentry);
  457. d_drop(dentry);
  458. goto out;
  459. }
  460. /*
  461.  * Setup a Symbolic link.
  462.  * Return a negative error code or 0 if OK.
  463.  */
  464. int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
  465.  const char *symname)
  466. {
  467. return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
  468. }
  469. /*
  470.  * Add a link to an inode in a directory
  471.  */
  472. int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
  473.  struct dentry *dentry)
  474. {
  475. struct inode *oldinode = olddentry->d_inode;
  476. struct inode *olddir = olddentry->d_parent->d_inode;
  477. struct dentry *temp;
  478. char *path;
  479. unsigned long buffer;
  480. int ret;
  481. struct umsdos_info old_info;
  482. struct umsdos_info hid_info;
  483. #ifdef UMSDOS_DEBUG_VERBOSE
  484. printk("umsdos_link: new %s/%s -> %s/%sn",
  485. dentry->d_parent->d_name.name, dentry->d_name.name, 
  486. olddentry->d_parent->d_name.name, olddentry->d_name.name);
  487. #endif
  488.  
  489. ret = -EPERM;
  490. if (S_ISDIR (oldinode->i_mode))
  491. goto out;
  492. ret = umsdos_nevercreat (dir, dentry, -EPERM);
  493. if (ret)
  494. goto out;
  495. ret = -ENOMEM;
  496. buffer = get_free_page(GFP_KERNEL);
  497. if (!buffer)
  498. goto out;
  499. /*
  500.  * Lock the link parent if it's not the same directory.
  501.  */
  502. ret = -EDEADLOCK;
  503. if (olddir != dir) {
  504. if (atomic_read(&olddir->i_sem.count) < 1)
  505. goto out_free;
  506. down(&olddir->i_sem);
  507. }
  508. /*
  509.  * Parse the name and get the visible directory entry.
  510.  */
  511. ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len,
  512. &old_info);
  513. if (ret)
  514. goto out_unlock;
  515. ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
  516. if (ret) {
  517. printk("UMSDOS_link: %s/%s not in EMD, ret=%dn",
  518. olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
  519. goto out_unlock;
  520. }
  521. /*
  522.  * If the visible dentry is a pseudo-hardlink, the original
  523.  * file must be already hidden.
  524.  */
  525. if (!(old_info.entry.flags & UMSDOS_HLINK)) {
  526. int err;
  527. /* create a hidden link name */
  528. ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
  529. if (ret) {
  530. printk("umsdos_link: can't make hidden %s/%s, ret=%dn",
  531. olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
  532. goto out_unlock;
  533. }
  534. /*
  535.  * Make a dentry and rename the original file ...
  536.  */
  537. temp = umsdos_lookup_dentry(olddentry->d_parent,
  538. hid_info.entry.name,
  539. hid_info.entry.name_len, 0); 
  540. ret = PTR_ERR(temp);
  541. if (IS_ERR(temp)) {
  542. printk("umsdos_link: lookup %s/%s failed, ret=%dn",
  543. dentry->d_parent->d_name.name, hid_info.entry.name, ret);
  544. goto cleanup;
  545. }
  546. /* rename the link to the hidden location ... */
  547. ret = umsdos_rename_f(olddir, olddentry, olddir, temp,
  548. UMSDOS_HIDDEN);
  549. d_move(olddentry, temp);
  550. dput(temp);
  551. if (ret) {
  552. printk("umsdos_link: rename to %s/%s failed, ret=%dn",
  553. temp->d_parent->d_name.name, temp->d_name.name, ret);
  554. goto cleanup;
  555. }
  556. /* mark the inode as a hardlink */
  557. oldinode->u.umsdos_i.i_is_hlink = 1;
  558. /*
  559.  * Capture the path to the hidden link.
  560.  */
  561. path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
  562. Printk(("umsdos_link: hidden link path=%sn", path));
  563. /*
  564.  * Recreate a dentry for the original name and symlink it,
  565.  * then symlink the new dentry. Don't give up if one fails,
  566.  * or we'll lose the file completely!
  567.  *
  568.  * Note: this counts as the "original" reference, so we 
  569.  * don't increment i_nlink for this one.
  570.  */ 
  571. temp = umsdos_lookup_dentry(olddentry->d_parent,
  572. old_info.entry.name,
  573. old_info.entry.name_len, 0); 
  574. ret = PTR_ERR(temp);
  575. if (!IS_ERR(temp)) {
  576. ret = umsdos_symlink_x (olddir, temp, path, 
  577. S_IFREG | 0777, UMSDOS_HLINK);
  578. dput(temp);
  579. }
  580. /* This symlink increments i_nlink (see below.) */
  581. err = umsdos_symlink_x (dir, dentry, path,
  582. S_IFREG | 0777, UMSDOS_HLINK);
  583. /* fold the two errors */
  584. if (!ret)
  585. ret = err;
  586. goto out_unlock;
  587. /* creation failed ... remove the link entry */
  588. cleanup:
  589. printk("umsdos_link: link failed, ret=%d, removing %s/%sn",
  590. ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
  591. err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
  592. goto out_unlock;
  593. }
  594. Printk(("UMSDOS_link: %s/%s already hiddenn",
  595. olddentry->d_parent->d_name.name, olddentry->d_name.name));
  596. /*
  597.  * The original file is already hidden, and we need to get 
  598.  * the dentry for its real name, not the visible name.
  599.  * N.B. make sure it's the hidden inode ...
  600.  */
  601. if (!oldinode->u.umsdos_i.i_is_hlink)
  602. printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??n",
  603. olddentry->d_parent->d_name.name,
  604. olddentry->d_name.name, oldinode->i_ino);
  605. /*
  606.  * In order to get the correct (real) inode, we just drop
  607.  * the original dentry.
  608.  */ 
  609. d_drop(olddentry);
  610. Printk(("UMSDOS_link: hard link %s/%s, fake=%sn",
  611. olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
  612. /* Do a real lookup to get the short name dentry */
  613. temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, 
  614. old_info.fake.len);
  615. ret = PTR_ERR(temp);
  616. if (IS_ERR(temp))
  617. goto out_unlock;
  618. /* now resolve the link ... */
  619. temp = umsdos_solve_hlink(temp);
  620. ret = PTR_ERR(temp);
  621. if (IS_ERR(temp))
  622. goto out_unlock;
  623. path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
  624. dput(temp);
  625. Printk(("umsdos_link: %s/%s already hidden, path=%sn",
  626. olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
  627. /* finally we can symlink it ... */
  628. ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
  629. out_unlock:
  630. /* remain locked for the call to notify_change ... */
  631. if (ret == 0) {
  632. struct iattr newattrs;
  633. /* Do a real lookup to get the short name dentry */
  634. temp = umsdos_covered(olddentry->d_parent,
  635. old_info.fake.fname,
  636. old_info.fake.len);
  637. ret = PTR_ERR(temp);
  638. if (IS_ERR(temp))
  639. goto out_unlock2;
  640. /* now resolve the link ... */
  641. temp = umsdos_solve_hlink(temp);
  642. ret = PTR_ERR(temp);
  643. if (IS_ERR(temp))
  644. goto out_unlock2;
  645. #ifdef UMSDOS_PARANOIA
  646. if (!oldinode->u.umsdos_i.i_is_hlink)
  647. printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!n",
  648. olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
  649. #endif
  650. temp->d_inode->i_nlink++;
  651. Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%dn",
  652. olddentry->d_parent->d_name.name, olddentry->d_name.name,
  653. oldinode->i_ino, oldinode->i_nlink));
  654. newattrs.ia_valid = 0;
  655. ret = umsdos_notify_change_locked(temp, &newattrs);
  656.   if (ret == 0)
  657. mark_inode_dirty(temp->d_inode);
  658. dput(temp);
  659. out_unlock2:
  660. if (ret == 0)
  661. mark_inode_dirty(olddentry->d_inode);
  662. }
  663. if (olddir != dir)
  664. up(&olddir->i_sem);
  665. out_free:
  666. free_page(buffer);
  667. out:
  668. Printk (("umsdos_link %dn", ret));
  669. return ret;
  670. }
  671. /*
  672.  * Add a sub-directory in a directory
  673.  */
  674. /* #Specification: mkdir / Directory already exist in DOS
  675.  * We do the same thing as for file creation.
  676.  * For all user it is an error.
  677.  */
  678. /* #Specification: mkdir / umsdos directory / create EMD
  679.  * When we created a new sub-directory in a UMSDOS
  680.  * directory (one with full UMSDOS semantics), we
  681.  * create immediately an EMD file in the new
  682.  * sub-directory so it inherits UMSDOS semantics.
  683.  */
  684. int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
  685. {
  686. struct dentry *temp;
  687. struct inode *inode;
  688. int ret, err;
  689. struct umsdos_info info;
  690. ret = umsdos_nevercreat (dir, dentry, -EEXIST);
  691. if (ret)
  692. goto out;
  693. ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  694. if (ret)
  695. goto out;
  696. info.entry.mode = mode | S_IFDIR;
  697. info.entry.rdev = 0;
  698. info.entry.uid = current->fsuid;
  699. info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
  700. info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
  701. info.entry.flags = 0;
  702. info.entry.nlink = 1;
  703. ret = umsdos_newentry (dentry->d_parent, &info);
  704. if (ret)
  705. goto out;
  706. /* lookup the short name dentry */
  707. temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
  708. ret = PTR_ERR(temp);
  709. if (IS_ERR(temp))
  710. goto out_remove;
  711. /* Make sure the short name doesn't exist */
  712. ret = -EEXIST;
  713. if (temp->d_inode) {
  714. printk("umsdos_mkdir: short name %s/%s existsn",
  715. dentry->d_parent->d_name.name, info.fake.fname);
  716. goto out_remove_dput;
  717. }
  718. ret = msdos_mkdir (dir, temp, mode);
  719. if (ret)
  720. goto out_remove_dput;
  721. /*
  722.  * Lock the inode to protect the EMD creation ...
  723.  */
  724. inode = temp->d_inode;
  725. down(&inode->i_sem);
  726. atomic_inc(&inode->i_count);
  727. d_instantiate(dentry, inode);
  728. /* N.B. this should have an option to create the EMD ... */
  729. umsdos_lookup_patch_new(dentry, &info);
  730. /* 
  731.  * Create the EMD file, and set up the dir so it is
  732.  * promoted to EMD with the EMD file invisible.
  733.  *
  734.  * N.B. error return if EMD fails?
  735.  */
  736. err = umsdos_make_emd(dentry);
  737. umsdos_setup_dir(dentry);
  738. up(&inode->i_sem);
  739. dput(temp);
  740. out:
  741. Printk(("umsdos_mkdir: %s/%s, ret=%dn",
  742. dentry->d_parent->d_name.name, dentry->d_name.name, ret));
  743. return ret;
  744. /* an error occurred ... remove EMD entry. */
  745. out_remove_dput:
  746. dput(temp);
  747. out_remove:
  748. umsdos_delentry (dentry->d_parent, &info, 1);
  749. goto out;
  750. }
  751. /*
  752.  * Add a new device special file into a directory.
  753.  *
  754.  * #Specification: Special files / strategy
  755.  * Device special file, pipes, etc ... are created like normal
  756.  * file in the msdos file system. Of course they remain empty.
  757.  * 
  758.  * One strategy was to create those files only in the EMD file
  759.  * since they were not important for MSDOS. The problem with
  760.  * that, is that there were not getting inode number allocated.
  761.  * The MSDOS filesystems is playing a nice game to fake inode
  762.  * number, so why not use it.
  763.  * 
  764.  * The absence of inode number compatible with those allocated
  765.  * for ordinary files was causing major trouble with hard link
  766.  * in particular and other parts of the kernel I guess.
  767.  */
  768. int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
  769.  int mode, int rdev)
  770. {
  771. return umsdos_create_any (dir, dentry, mode, rdev, 0);
  772. }
  773. /*
  774.  * Remove a sub-directory.
  775.  */
  776. int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
  777. {
  778. struct dentry *temp;
  779. int ret, err, empty;
  780. struct umsdos_info info;
  781. ret = umsdos_nevercreat (dir, dentry, -EPERM);
  782. if (ret)
  783. goto out;
  784. ret = -EBUSY;
  785. if (!d_unhashed(dentry))
  786. goto out;
  787. /* check whether the EMD is empty */
  788. ret = -ENOTEMPTY;
  789. empty = umsdos_isempty (dentry);
  790. /* Have to remove the EMD file? */
  791. if (empty == 1) {
  792. struct dentry *demd;
  793. demd = umsdos_get_emd_dentry(dentry);
  794. if (!IS_ERR(demd)) {
  795. err = -ENOENT;
  796. if (demd->d_inode)
  797. err = msdos_unlink (dentry->d_inode, demd);
  798. Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
  799. #ifdef UMSDOS_PARANOIA
  800. if (err)
  801. printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%dn",
  802. demd->d_parent->d_name.name, demd->d_name.name, err);
  803. #endif
  804. if (!err) {
  805. d_delete(demd);
  806. ret = 0;
  807. }
  808. dput(demd);
  809. }
  810. } else if (empty == 2)
  811. ret = 0;
  812. if (ret)
  813. goto out;
  814. umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  815. /* Call findentry to complete the mangling */
  816. umsdos_findentry (dentry->d_parent, &info, 2);
  817. temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
  818. ret = PTR_ERR(temp);
  819. if (IS_ERR(temp))
  820. goto out;
  821. /*
  822.  * Attempt to remove the msdos name.
  823.  */
  824. ret = msdos_rmdir (dir, temp);
  825. if (ret && ret != -ENOENT)
  826. goto out_dput;
  827. d_delete(temp);
  828. /* OK so far ... remove the name from the EMD */
  829. ret = umsdos_delentry (dentry->d_parent, &info, 1);
  830. #ifdef UMSDOS_PARANOIA
  831. if (ret)
  832. printk("umsdos_rmdir: delentry %s failed, ret=%dn", info.entry.name, ret);
  833. #endif
  834. /* dput() temp if we didn't do it above */
  835. out_dput:
  836. dput(temp);
  837. out:
  838. Printk (("umsdos_rmdir %dn", ret));
  839. return ret;
  840. }
  841. /*
  842.  * Remove a file from the directory.
  843.  *
  844.  * #Specification: hard link / deleting a link
  845.  * When we delete a file and this file is a link,
  846.  * we must subtract 1 from the nlink field of the
  847.  * hidden link.
  848.  * 
  849.  * If the count goes to 0, we delete this hidden
  850.  * link too.
  851.  */
  852. int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
  853. {
  854. struct dentry *temp, *link = NULL;
  855. struct inode *inode;
  856. int ret;
  857. struct umsdos_info info;
  858. Printk(("UMSDOS_unlink: entering %s/%sn",
  859. dentry->d_parent->d_name.name, dentry->d_name.name));
  860. ret = umsdos_nevercreat (dir, dentry, -EPERM);
  861. if (ret)
  862. goto out;
  863. ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  864. if (ret)
  865. goto out;
  866. umsdos_lockcreate (dir);
  867. ret = umsdos_findentry (dentry->d_parent, &info, 1);
  868. if (ret) {
  869. printk("UMSDOS_unlink: %s/%s not in EMD, ret=%dn",
  870. dentry->d_parent->d_name.name, dentry->d_name.name, ret);
  871. goto out_unlock;
  872. }
  873. Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
  874. /*
  875.  * Note! If this is a hardlink and the names are aliased,
  876.  * the short-name lookup will return the hardlink dentry.
  877.  * In order to get the correct (real) inode, we just drop
  878.  * the original dentry.
  879.  */ 
  880. if (info.entry.flags & UMSDOS_HLINK) {
  881. d_drop(dentry);
  882. }
  883. /* Do a real lookup to get the short name dentry */
  884. temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
  885. ret = PTR_ERR(temp);
  886. if (IS_ERR(temp))
  887. goto out_unlock;
  888. /*
  889.  * Resolve hardlinks now, but defer processing until later.
  890.  */
  891. if (info.entry.flags & UMSDOS_HLINK) {
  892. link = umsdos_solve_hlink(dget(temp));
  893. }
  894. /* Delete the EMD entry */
  895. ret = umsdos_delentry (dentry->d_parent, &info, 0);
  896. if (ret && ret != -ENOENT) {
  897. printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%dn",
  898. info.entry.name, ret);
  899. goto out_dput;
  900. }
  901. ret = msdos_unlink(dir, temp);
  902. if (!ret)
  903. d_delete(temp);
  904. #ifdef UMSDOS_PARANOIA
  905. if (ret)
  906. printk("umsdos_unlink: %s/%s unlink failed, ret=%dn",
  907. temp->d_parent->d_name.name, temp->d_name.name, ret);
  908. #endif
  909. /* dput() temp if we didn't do it above */
  910. out_dput:
  911. dput(temp);
  912. out_unlock:
  913. umsdos_unlockcreate (dir);
  914. /*
  915.  * Now check for deferred handling of a hardlink.
  916.  */
  917. if (!link)
  918. goto out;
  919. if (IS_ERR(link)) {
  920. printk("umsdos_unlink: failed to resolve %s/%sn",
  921. dentry->d_parent->d_name.name, dentry->d_name.name);
  922. if (!ret)
  923. ret = PTR_ERR(link);
  924. goto out;
  925. }
  926. Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%dn",
  927. link->d_parent->d_name.name, link->d_name.name, ret));
  928. /* already have an error? */
  929. if (ret)
  930. goto out_cleanup;
  931. /* make sure the link exists ... */
  932. inode = link->d_inode;
  933. if (!inode) {
  934. printk(KERN_WARNING "umsdos_unlink: hard link not foundn");
  935. goto out_cleanup;
  936. }
  937. /*
  938.  * If this was the last linked reference, delete it now.
  939.  *
  940.  * N.B. Deadlock problem? We should be holding the lock
  941.  * for the hardlink's parent, but another process might
  942.  * be holding that lock waiting for us to finish ...
  943.  */
  944. if (inode->i_nlink <= 1) {
  945. ret = UMSDOS_unlink (link->d_parent->d_inode, link);
  946. if (ret) {
  947. printk(KERN_WARNING
  948. "umsdos_unlink: link removal failed, ret=%dn",
  949.  ret);
  950. } else
  951. d_delete(link);
  952. } else {
  953. struct iattr newattrs;
  954. inode->i_nlink--;
  955. newattrs.ia_valid = 0;
  956. ret = umsdos_notify_change_locked(link, &newattrs);
  957. if (!ret)
  958. mark_inode_dirty(link->d_inode);
  959. }
  960. out_cleanup:
  961. d_drop(link);
  962. dput(link);
  963. out:
  964. Printk (("umsdos_unlink %dn", ret));
  965. return ret;
  966. }
  967. /*
  968.  * Rename (move) a file.
  969.  */
  970. int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
  971.    struct inode *new_dir, struct dentry *new_dentry)
  972. {
  973. int ret;
  974. ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
  975. if (ret)
  976. return ret;
  977. /*
  978.  * If the target already exists, delete it first.
  979.  */
  980. if (new_dentry->d_inode) {
  981. dget(new_dentry);
  982. if (S_ISDIR(old_dentry->d_inode->i_mode))
  983. ret = UMSDOS_rmdir (new_dir, new_dentry);
  984. else
  985. ret = UMSDOS_unlink (new_dir, new_dentry);
  986. if (!ret)
  987. d_drop(new_dentry);
  988. dput(new_dentry);
  989. if (ret)
  990. return ret;
  991. }
  992. ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
  993. return ret;
  994. }