namei.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:15k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/msdos/namei.c
  3.  *
  4.  *  Written 1992,1993 by Werner Almesberger
  5.  *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
  6.  *  Rewritten for constant inumbers 1999 by Al Viro
  7.  */
  8. #define __NO_VERSION__
  9. #include <linux/module.h>
  10. #include <linux/sched.h>
  11. #include <linux/msdos_fs.h>
  12. #include <linux/errno.h>
  13. #include <linux/string.h>
  14. #include <asm/uaccess.h>
  15. #define MSDOS_DEBUG 0
  16. #define PRINTK(x)
  17. /* MS-DOS "device special files" */
  18. static const char *reserved_names[] = {
  19.     "CON     ","PRN     ","NUL     ","AUX     ",
  20.     "LPT1    ","LPT2    ","LPT3    ","LPT4    ",
  21.     "COM1    ","COM2    ","COM3    ","COM4    ",
  22.     NULL };
  23. /* Characters that are undesirable in an MS-DOS file name */
  24.   
  25. static char bad_chars[] = "*?<>|"";
  26. static char bad_if_strict_pc[] = "+=,; ";
  27. static char bad_if_strict_atari[] = " "; /* GEMDOS is less restrictive */
  28. #define bad_if_strict(opts) ((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc)
  29. /* Must die */
  30. void msdos_put_super(struct super_block *sb)
  31. {
  32. fat_put_super(sb);
  33. }
  34. /***** Formats an MS-DOS file name. Rejects invalid names. */
  35. static int msdos_format_name(const char *name,int len,
  36. char *res,struct fat_mount_options *opts)
  37. /* name is the proposed name, len is its length, res is
  38.  * the resulting name, opts->name_check is either (r)elaxed,
  39.  * (n)ormal or (s)trict, opts->dotsOK allows dots at the
  40.  * beginning of name (for hidden files)
  41.  */
  42. {
  43. char *walk;
  44. const char **reserved;
  45. unsigned char c;
  46. int space;
  47. if (name[0] == '.') {  /* dotfile because . and .. already done */
  48. if (opts->dotsOK) {
  49. /* Get rid of dot - test for it elsewhere */
  50. name++; len--;
  51. }
  52. else if (!opts->atari) return -EINVAL;
  53. }
  54. /* disallow names that _really_ start with a dot for MS-DOS, GEMDOS does
  55.  * not care */
  56. space = !opts->atari;
  57. c = 0;
  58. for (walk = res; len && walk-res < 8; walk++) {
  59.      c = *name++;
  60. len--;
  61. if (opts->name_check != 'r' && strchr(bad_chars,c))
  62. return -EINVAL;
  63. if (opts->name_check == 's' && strchr(bad_if_strict(opts),c))
  64. return -EINVAL;
  65.    if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
  66. return -EINVAL;
  67. if (c < ' ' || c == ':' || c == '\') return -EINVAL;
  68. /*  0xE5 is legal as a first character, but we must substitute 0x05     */
  69. /*  because 0xE5 marks deleted files.  Yes, DOS really does this.       */
  70. /*  It seems that Microsoft hacked DOS to support non-US characters     */
  71. /*  after the 0xE5 character was already in use to mark deleted files.  */
  72. if((res==walk) && (c==0xE5)) c=0x05;
  73. if (c == '.') break;
  74. space = (c == ' ');
  75. *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c-32 : c;
  76. }
  77. if (space) return -EINVAL;
  78. if (opts->name_check == 's' && len && c != '.') {
  79. c = *name++;
  80. len--;
  81. if (c != '.') return -EINVAL;
  82. }
  83. while (c != '.' && len--) c = *name++;
  84. if (c == '.') {
  85. while (walk-res < 8) *walk++ = ' ';
  86. while (len > 0 && walk-res < MSDOS_NAME) {
  87. c = *name++;
  88. len--;
  89. if (opts->name_check != 'r' && strchr(bad_chars,c))
  90. return -EINVAL;
  91. if (opts->name_check == 's' &&
  92.     strchr(bad_if_strict(opts),c))
  93. return -EINVAL;
  94. if (c < ' ' || c == ':' || c == '\')
  95. return -EINVAL;
  96. if (c == '.') {
  97. if (opts->name_check == 's')
  98. return -EINVAL;
  99. break;
  100. }
  101. if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
  102. return -EINVAL;
  103. space = c == ' ';
  104. *walk++ = (!opts->nocase && c >= 'a' && c <= 'z') ? c-32 : c;
  105. }
  106. if (space) return -EINVAL;
  107. if (opts->name_check == 's' && len) return -EINVAL;
  108. }
  109. while (walk-res < MSDOS_NAME) *walk++ = ' ';
  110. if (!opts->atari)
  111. /* GEMDOS is less stupid and has no reserved names */
  112. for (reserved = reserved_names; *reserved; reserved++)
  113. if (!strncmp(res,*reserved,8)) return -EINVAL;
  114. return 0;
  115. }
  116. /***** Locates a directory entry.  Uses unformatted name. */
  117. static int msdos_find(struct inode *dir,const char *name,int len,
  118.     struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
  119. {
  120. int res;
  121. char dotsOK;
  122. char msdos_name[MSDOS_NAME];
  123. dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
  124. res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options);
  125. if (res < 0)
  126. return -ENOENT;
  127. res = fat_scan(dir,msdos_name,bh,de,ino);
  128. if (!res && dotsOK) {
  129. if (name[0]=='.') {
  130. if (!((*de)->attr & ATTR_HIDDEN))
  131. res = -ENOENT;
  132. } else {
  133. if ((*de)->attr & ATTR_HIDDEN)
  134. res = -ENOENT;
  135. }
  136. }
  137. return res;
  138. }
  139. /*
  140.  * Compute the hash for the msdos name corresponding to the dentry.
  141.  * Note: if the name is invalid, we leave the hash code unchanged so
  142.  * that the existing dentry can be used. The msdos fs routines will
  143.  * return ENOENT or EINVAL as appropriate.
  144.  */
  145. static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
  146. {
  147. struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
  148. int error;
  149. char msdos_name[MSDOS_NAME];
  150. error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
  151. if (!error)
  152. qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
  153. return 0;
  154. }
  155. /*
  156.  * Compare two msdos names. If either of the names are invalid,
  157.  * we fall back to doing the standard name comparison.
  158.  */
  159. static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
  160. {
  161. struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
  162. int error;
  163. char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
  164. error = msdos_format_name(a->name, a->len, a_msdos_name, options);
  165. if (error)
  166. goto old_compare;
  167. error = msdos_format_name(b->name, b->len, b_msdos_name, options);
  168. if (error)
  169. goto old_compare;
  170. error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
  171. out:
  172. return error;
  173. old_compare:
  174. error = 1;
  175. if (a->len == b->len)
  176. error = memcmp(a->name, b->name, a->len);
  177. goto out;
  178. }
  179. static struct dentry_operations msdos_dentry_operations = {
  180. d_hash: msdos_hash,
  181. d_compare: msdos_cmp,
  182. };
  183. /*
  184.  * AV. Wrappers for FAT sb operations. Is it wise?
  185.  */
  186. /***** Get inode using directory and name */
  187. struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
  188. {
  189. struct super_block *sb = dir->i_sb;
  190. struct inode *inode = NULL;
  191. struct msdos_dir_entry *de;
  192. struct buffer_head *bh = NULL;
  193. int ino,res;
  194. PRINTK (("msdos_lookupn"));
  195. dentry->d_op = &msdos_dentry_operations;
  196. res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
  197. &de, &ino);
  198. if (res == -ENOENT)
  199. goto add;
  200. if (res < 0)
  201. goto out;
  202. inode = fat_build_inode(sb, de, ino, &res);
  203. if (res)
  204. goto out;
  205. add:
  206. d_add(dentry, inode);
  207. res = 0;
  208. out:
  209. if (bh)
  210. fat_brelse(sb, bh);
  211. return ERR_PTR(res);
  212. }
  213. /***** Creates a directory entry (name is already formatted). */
  214. static int msdos_add_entry(struct inode *dir, const char *name,
  215.    struct buffer_head **bh,
  216.    struct msdos_dir_entry **de,
  217.    int *ino,
  218.    int is_dir, int is_hid)
  219. {
  220. struct super_block *sb = dir->i_sb;
  221. int res;
  222. if ((res = fat_add_entries(dir, 1, bh, de, ino))<0)
  223. return res;
  224. /*
  225.  * XXX all times should be set by caller upon successful completion.
  226.  */
  227. dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  228. mark_inode_dirty(dir);
  229. memcpy((*de)->name,name,MSDOS_NAME);
  230. (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
  231. if (is_hid)
  232. (*de)->attr |= ATTR_HIDDEN;
  233. (*de)->start = 0;
  234. (*de)->starthi = 0;
  235. fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);
  236. (*de)->size = 0;
  237. fat_mark_buffer_dirty(sb, *bh);
  238. return 0;
  239. }
  240. /*
  241.  * AV. Huh??? It's exported. Oughtta check usage.
  242.  */
  243. /***** Create a file */
  244. int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
  245. {
  246. struct super_block *sb = dir->i_sb;
  247. struct buffer_head *bh;
  248. struct msdos_dir_entry *de;
  249. struct inode *inode;
  250. int ino,res,is_hid;
  251. char msdos_name[MSDOS_NAME];
  252. res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
  253. msdos_name, &MSDOS_SB(sb)->options);
  254. if (res < 0)
  255. return res;
  256. is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
  257. /* Have to do it due to foo vs. .foo conflicts */
  258. if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
  259. fat_brelse(sb, bh);
  260. return -EINVAL;
  261.   }
  262. inode = NULL;
  263. res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 0, is_hid);
  264. if (res)
  265. return res;
  266. inode = fat_build_inode(dir->i_sb, de, ino, &res);
  267. fat_brelse(sb, bh);
  268. if (!inode)
  269. return res;
  270. inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
  271. mark_inode_dirty(inode);
  272. d_instantiate(dentry, inode);
  273. return 0;
  274. }
  275. /***** Remove a directory */
  276. int msdos_rmdir(struct inode *dir, struct dentry *dentry)
  277. {
  278. struct super_block *sb = dir->i_sb;
  279. struct inode *inode = dentry->d_inode;
  280. int res,ino;
  281. struct buffer_head *bh;
  282. struct msdos_dir_entry *de;
  283. bh = NULL;
  284. res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
  285. &bh, &de, &ino);
  286. if (res < 0)
  287. goto rmdir_done;
  288. /*
  289.  * Check whether the directory is not in use, then check
  290.  * whether it is empty.
  291.  */
  292. res = fat_dir_empty(inode);
  293. if (res)
  294. goto rmdir_done;
  295. de->name[0] = DELETED_FLAG;
  296. fat_mark_buffer_dirty(sb, bh);
  297. fat_detach(inode);
  298. inode->i_nlink = 0;
  299. inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  300. dir->i_nlink--;
  301. mark_inode_dirty(inode);
  302. mark_inode_dirty(dir);
  303. res = 0;
  304. rmdir_done:
  305. fat_brelse(sb, bh);
  306. return res;
  307. }
  308. /***** Make a directory */
  309. int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
  310. {
  311. struct super_block *sb = dir->i_sb;
  312. struct buffer_head *bh;
  313. struct msdos_dir_entry *de;
  314. struct inode *inode;
  315. int res,is_hid;
  316. char msdos_name[MSDOS_NAME];
  317. int ino;
  318. res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
  319. msdos_name, &MSDOS_SB(sb)->options);
  320. if (res < 0)
  321. return res;
  322. is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
  323. /* foo vs .foo situation */
  324. if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0)
  325. goto out_exist;
  326. res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid);
  327. if (res)
  328. goto out_unlock;
  329. inode = fat_build_inode(dir->i_sb, de, ino, &res);
  330. if (!inode) {
  331. fat_brelse(sb, bh);
  332. goto out_unlock;
  333. }
  334. res = 0;
  335. dir->i_nlink++;
  336. inode->i_nlink = 2; /* no need to mark them dirty */
  337. res = fat_new_dir(inode, dir, 0);
  338. if (res)
  339. goto mkdir_error;
  340. fat_brelse(sb, bh);
  341. d_instantiate(dentry, inode);
  342. res = 0;
  343. out_unlock:
  344. return res;
  345. mkdir_error:
  346. printk(KERN_WARNING "msdos_mkdir: error=%d, attempting cleanupn", res);
  347. inode->i_nlink = 0;
  348. inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  349. dir->i_nlink--;
  350. mark_inode_dirty(inode);
  351. mark_inode_dirty(dir);
  352. de->name[0] = DELETED_FLAG;
  353. fat_mark_buffer_dirty(sb, bh);
  354. fat_brelse(sb, bh);
  355. fat_detach(inode);
  356. iput(inode);
  357. goto out_unlock;
  358. out_exist:
  359. fat_brelse(sb, bh);
  360. res = -EINVAL;
  361. goto out_unlock;
  362. }
  363. /***** Unlink a file */
  364. int msdos_unlink( struct inode *dir, struct dentry *dentry)
  365. {
  366. struct super_block *sb = dir->i_sb;
  367. struct inode *inode = dentry->d_inode;
  368. int res,ino;
  369. struct buffer_head *bh;
  370. struct msdos_dir_entry *de;
  371. bh = NULL;
  372. res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
  373. &bh, &de, &ino);
  374. if (res < 0)
  375. goto unlink_done;
  376. de->name[0] = DELETED_FLAG;
  377. fat_mark_buffer_dirty(sb, bh);
  378. fat_detach(inode);
  379. fat_brelse(sb, bh);
  380. inode->i_nlink = 0;
  381. inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  382. mark_inode_dirty(inode);
  383. mark_inode_dirty(dir);
  384. res = 0;
  385. unlink_done:
  386. return res;
  387. }
  388. static int do_msdos_rename(struct inode *old_dir, char *old_name,
  389.     struct dentry *old_dentry,
  390.     struct inode *new_dir,char *new_name, struct dentry *new_dentry,
  391.     struct buffer_head *old_bh,
  392.     struct msdos_dir_entry *old_de, int old_ino, int is_hid)
  393. {
  394. struct super_block *sb = old_dir->i_sb;
  395. struct buffer_head *new_bh=NULL,*dotdot_bh=NULL;
  396. struct msdos_dir_entry *new_de,*dotdot_de;
  397. struct inode *old_inode,*new_inode;
  398. int new_ino,dotdot_ino;
  399. int error;
  400. int is_dir;
  401. old_inode = old_dentry->d_inode;
  402. new_inode = new_dentry->d_inode;
  403. is_dir = S_ISDIR(old_inode->i_mode);
  404. if (fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)>=0 &&!new_inode)
  405. goto degenerate_case;
  406. if (is_dir) {
  407. if (new_inode) {
  408. error = fat_dir_empty(new_inode);
  409. if (error)
  410. goto out;
  411. }
  412. error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
  413. &dotdot_de, &dotdot_ino);
  414. if (error < 0) {
  415. printk(KERN_WARNING
  416. "MSDOS: %s/%s, get dotdot failed, ret=%dn",
  417. old_dentry->d_parent->d_name.name,
  418. old_dentry->d_name.name, error);
  419. goto out;
  420. }
  421. }
  422. if (!new_bh) {
  423. error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
  424. &new_ino, is_dir, is_hid);
  425. if (error)
  426. goto out;
  427. }
  428. new_dir->i_version = ++event;
  429. /* There we go */
  430. if (new_inode)
  431. fat_detach(new_inode);
  432. old_de->name[0] = DELETED_FLAG;
  433. fat_mark_buffer_dirty(sb, old_bh);
  434. fat_detach(old_inode);
  435. fat_attach(old_inode, new_ino);
  436. if (is_hid)
  437. MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
  438. else
  439. MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
  440. mark_inode_dirty(old_inode);
  441. old_dir->i_version = ++event;
  442. old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
  443. mark_inode_dirty(old_dir);
  444. if (new_inode) {
  445. new_inode->i_nlink--;
  446. new_inode->i_ctime = CURRENT_TIME;
  447. mark_inode_dirty(new_inode);
  448. }
  449. if (dotdot_bh) {
  450. dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
  451. dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
  452. fat_mark_buffer_dirty(sb, dotdot_bh);
  453. old_dir->i_nlink--;
  454. mark_inode_dirty(old_dir);
  455. if (new_inode) {
  456. new_inode->i_nlink--;
  457. mark_inode_dirty(new_inode);
  458. } else {
  459. new_dir->i_nlink++;
  460. mark_inode_dirty(new_dir);
  461. }
  462. }
  463. error = 0;
  464. out:
  465. fat_brelse(sb, new_bh);
  466. fat_brelse(sb, dotdot_bh);
  467. return error;
  468. degenerate_case:
  469. error = -EINVAL;
  470. if (new_de!=old_de)
  471. goto out;
  472. if (is_hid)
  473. MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
  474. else
  475. MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
  476. mark_inode_dirty(old_inode);
  477. old_dir->i_version = ++event;
  478. old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
  479. mark_inode_dirty(old_dir);
  480. return 0;
  481. }
  482. /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
  483. int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
  484.  struct inode *new_dir,struct dentry *new_dentry)
  485. {
  486. struct super_block *sb = old_dir->i_sb;
  487. struct buffer_head *old_bh;
  488. struct msdos_dir_entry *old_de;
  489. int old_ino, error;
  490. int is_hid,old_hid; /* if new file and old file are hidden */
  491. char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
  492. error = msdos_format_name(old_dentry->d_name.name,
  493.   old_dentry->d_name.len,old_msdos_name,
  494.   &MSDOS_SB(old_dir->i_sb)->options);
  495. if (error < 0)
  496. goto rename_done;
  497. error = msdos_format_name(new_dentry->d_name.name,
  498.   new_dentry->d_name.len,new_msdos_name,
  499.   &MSDOS_SB(new_dir->i_sb)->options);
  500. if (error < 0)
  501. goto rename_done;
  502. is_hid  = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
  503. old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
  504. error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_ino);
  505. if (error < 0)
  506. goto rename_done;
  507. error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
  508. new_dir, new_msdos_name, new_dentry,
  509. old_bh, old_de, (ino_t)old_ino, is_hid);
  510. fat_brelse(sb, old_bh);
  511. rename_done:
  512. return error;
  513. }
  514. /* The public inode operations for the msdos fs */
  515. struct inode_operations msdos_dir_inode_operations = {
  516. create: msdos_create,
  517. lookup: msdos_lookup,
  518. unlink: msdos_unlink,
  519. mkdir: msdos_mkdir,
  520. rmdir: msdos_rmdir,
  521. rename: msdos_rename,
  522. setattr: fat_notify_change,
  523. };
  524. struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
  525. {
  526. struct super_block *res;
  527. MSDOS_SB(sb)->options.isvfat = 0;
  528. res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
  529. if (res)
  530. sb->s_root->d_op = &msdos_dentry_operations;
  531. return res;
  532. }