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

嵌入式Linux

开发平台:

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