PageRenderTime 193ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/fs/fat/dir.c

https://github.com/empeg/empeg-hijack
C | 655 lines | 551 code | 46 blank | 58 comment | 194 complexity | bfe7b7328502562270fe0c075cfd63bc MD5 | raw file
  1. /*
  2. * linux/fs/fat/dir.c
  3. *
  4. * directory handling functions for fat-based filesystems
  5. *
  6. * Written 1992,1993 by Werner Almesberger
  7. *
  8. * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
  9. *
  10. * VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
  11. * Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
  12. * Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV
  13. */
  14. #define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
  15. #include <linux/version.h>
  16. #include <linux/fs.h>
  17. #include <linux/msdos_fs.h>
  18. #include <linux/nls.h>
  19. #include <linux/kernel.h>
  20. #include <linux/errno.h>
  21. #include <linux/stat.h>
  22. #include <linux/string.h>
  23. #include <linux/ioctl.h>
  24. #include <linux/dirent.h>
  25. #include <linux/mm.h>
  26. #include <linux/ctype.h>
  27. #include <asm/uaccess.h>
  28. #include "msbuffer.h"
  29. #define PRINTK(X)
  30. static ssize_t fat_dir_read(struct file * filp, char * buf,
  31. size_t count, loff_t *ppos)
  32. {
  33. return -EISDIR;
  34. }
  35. struct file_operations fat_dir_operations = {
  36. NULL, /* lseek - default */
  37. fat_dir_read, /* read */
  38. NULL, /* write - bad */
  39. fat_readdir, /* readdir */
  40. NULL, /* select v2.0.x/poll v2.1.x - default */
  41. fat_dir_ioctl, /* ioctl - default */
  42. NULL, /* mmap */
  43. NULL, /* no special open code */
  44. NULL, /* flush */
  45. NULL, /* no special release code */
  46. file_fsync /* fsync */
  47. };
  48. /*
  49. * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
  50. * If uni_xlate is enabled and we
  51. * can't get a 1:1 conversion, use a colon as an escape character since
  52. * it is normally invalid on the vfat filesystem. The following three
  53. * characters are a sort of uuencoded 16 bit Unicode value. This lets
  54. * us do a full dump and restore of Unicode filenames. We could get
  55. * into some trouble with long Unicode names, but ignore that right now.
  56. * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
  57. */
  58. static int
  59. uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
  60. struct nls_table *nls)
  61. {
  62. unsigned char *ip, *op;
  63. unsigned char ch, cl;
  64. unsigned char *uni_page;
  65. unsigned short val;
  66. ip = uni;
  67. op = ascii;
  68. while (*ip || ip[1]) {
  69. int len;
  70. nls->uni2char(ip[1], ip[0], op, 20, &len);
  71. if (uni_xlate == 1 && len == 1 && op[0] == '?'){
  72. *op++ = ':';
  73. val = (ip[0] << 8) + ip[1];
  74. op[2] = fat_uni2esc[val & 0x3f];
  75. val >>= 6;
  76. op[1] = fat_uni2esc[val & 0x3f];
  77. val >>= 6;
  78. op[0] = fat_uni2esc[val & 0x3f];
  79. op += 3;
  80. }
  81. else{
  82. ip += 2;
  83. op += len;
  84. }
  85. /* We have some slack there, so it's OK */
  86. if (op>ascii+256) {
  87. op = ascii + 256;
  88. break;
  89. }
  90. }
  91. *op = 0;
  92. return (op - ascii);
  93. }
  94. #if 0
  95. static void dump_de(struct msdos_dir_entry *de)
  96. {
  97. int i;
  98. unsigned char *p = (unsigned char *) de;
  99. printk("[");
  100. for (i = 0; i < 32; i++, p++) {
  101. printk("%02x ", *p);
  102. }
  103. printk("]\n");
  104. }
  105. #endif
  106. static int memicmp(const char *s1, const char *s2, int len) {
  107. while(len--) if (tolower(*s1++)!=tolower(*s2++)) return 1;
  108. return 0;
  109. }
  110. /*
  111. * Return values: negative -> error, 0 -> not found, positive -> found,
  112. * value is the total amount of slots, including the shortname entry.
  113. */
  114. int fat_search_long(
  115. struct inode *inode, const char *name, int name_len, int anycase,
  116. loff_t *spos, loff_t *lpos)
  117. {
  118. struct super_block *sb = inode->i_sb;
  119. int ino,i,i2,last;
  120. char c;
  121. struct buffer_head *bh = NULL;
  122. struct msdos_dir_entry *de;
  123. loff_t cpos = MSDOS_I(inode)->i_last_pos;
  124. loff_t barrier = 0;
  125. char bufname[14];
  126. unsigned char long_slots;
  127. int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
  128. int utf8 = MSDOS_SB(sb)->options.utf8;
  129. unsigned char *unicode = NULL;
  130. struct nls_table *nls = MSDOS_SB(sb)->nls_io;
  131. int res = 0;
  132. while(1) {
  133. if (barrier && cpos>=barrier)
  134. goto EODir;
  135. rescan:
  136. if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
  137. goto EODir;
  138. parse_record:
  139. long_slots = 0;
  140. if (de->name[0] == (__s8) DELETED_FLAG)
  141. continue;
  142. if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
  143. continue;
  144. if (de->attr != ATTR_EXT && IS_FREE(de->name))
  145. continue;
  146. if (de->attr == ATTR_EXT) {
  147. struct msdos_dir_slot *ds;
  148. int offset;
  149. unsigned char id;
  150. unsigned char slot;
  151. unsigned char slots;
  152. unsigned char sum;
  153. unsigned char alias_checksum;
  154. if (!unicode) {
  155. unicode = (unsigned char *)
  156. __get_free_page(GFP_KERNEL);
  157. if (!unicode) {
  158. fat_brelse(sb, bh);
  159. return -ENOMEM;
  160. }
  161. }
  162. parse_long:
  163. slots = 0;
  164. offset = 0;
  165. ds = (struct msdos_dir_slot *) de;
  166. id = ds->id;
  167. if (!(id & 0x40))
  168. continue;
  169. slots = id & ~0x40;
  170. if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
  171. continue;
  172. long_slots = slots;
  173. alias_checksum = ds->alias_checksum;
  174. slot = slots;
  175. while (1) {
  176. slot--;
  177. offset = slot * 26;
  178. memcpy(&unicode[offset], ds->name0_4, 10);
  179. memcpy(&unicode[offset+10], ds->name5_10, 12);
  180. memcpy(&unicode[offset+22], ds->name11_12, 4);
  181. offset += 26;
  182. if (ds->id & 0x40) {
  183. unicode[offset] = 0;
  184. unicode[offset+1] = 0;
  185. }
  186. if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)
  187. goto EODir;
  188. if (slot == 0)
  189. break;
  190. ds = (struct msdos_dir_slot *) de;
  191. if (ds->attr != ATTR_EXT)
  192. goto parse_record;
  193. if ((ds->id & ~0x40) != slot)
  194. goto parse_long;
  195. if (ds->alias_checksum != alias_checksum)
  196. goto parse_long;
  197. }
  198. if (de->name[0] == (__s8) DELETED_FLAG)
  199. continue;
  200. if (de->attr == ATTR_EXT)
  201. goto parse_long;
  202. if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
  203. continue;
  204. for (sum = 0, i = 0; i < 11; i++)
  205. sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
  206. if (sum != alias_checksum)
  207. long_slots = 0;
  208. }
  209. for (i = 0, last = 0; i < 8;) {
  210. if (!(c = de->name[i])) break;
  211. if (c >= 'A' && c <= 'Z') c += 32;
  212. if (c == 0x05) c = 0xE5;
  213. if ((bufname[i++] = c) != ' ')
  214. last = i;
  215. }
  216. i = last;
  217. bufname[i++] = '.';
  218. for (i2 = 0; i2 < 3; i2++) {
  219. if (!(c = de->ext[i2])) break;
  220. if (c >= 'A' && c <= 'Z') c += 32;
  221. if ((bufname[i++] = c) != ' ')
  222. last = i;
  223. }
  224. if (!last)
  225. continue;
  226. if (last==name_len)
  227. if ((!anycase && !memcmp(name, bufname, last)) ||
  228. (anycase && !memicmp(name, bufname, last)))
  229. goto Found;
  230. if (long_slots) {
  231. char longname[260]; /* 256 + 4 */
  232. unsigned char long_len;
  233. long_len = utf8
  234. ?utf8_wcstombs(longname, (__u16 *) unicode, 260)
  235. :uni16_to_x8(longname, unicode, uni_xlate, nls);
  236. if (long_len != name_len)
  237. continue;
  238. if ((!anycase && !memcmp(name, longname, long_len)) ||
  239. (anycase && !memicmp(name, longname, long_len)))
  240. goto Found;
  241. }
  242. }
  243. Found:
  244. res = long_slots + 1;
  245. *spos = cpos - sizeof(struct msdos_dir_entry);
  246. *lpos = cpos - res*sizeof(struct msdos_dir_entry);
  247. MSDOS_I(inode)->i_last_pos = cpos;
  248. exit:
  249. fat_brelse(sb, bh);
  250. if (unicode) {
  251. free_page((unsigned long) unicode);
  252. }
  253. return res;
  254. EODir:
  255. if (!MSDOS_I(inode)->i_last_pos)
  256. goto exit;
  257. if (barrier) {
  258. MSDOS_I(inode)->i_last_pos = 0;
  259. goto exit;
  260. }
  261. barrier = MSDOS_I(inode)->i_last_pos;
  262. cpos = 0;
  263. goto rescan;
  264. }
  265. static int fat_readdirx(
  266. struct inode *inode,
  267. struct file *filp,
  268. void *dirent,
  269. filldir_t filldir,
  270. int shortnames,
  271. int both)
  272. {
  273. struct super_block *sb = inode->i_sb;
  274. int ino,inum,i,i2,last;
  275. char c;
  276. struct buffer_head *bh;
  277. struct msdos_dir_entry *de;
  278. unsigned long lpos;
  279. loff_t cpos;
  280. unsigned char long_slots;
  281. int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
  282. int utf8 = MSDOS_SB(sb)->options.utf8;
  283. unsigned char *unicode = NULL;
  284. struct nls_table *nls = MSDOS_SB(sb)->nls_io;
  285. char bufname[14];
  286. char *ptname = bufname;
  287. int dotoffset = 0;
  288. unsigned long *furrfu = &lpos;
  289. unsigned long dummy;
  290. cpos = filp->f_pos;
  291. /* Fake . and .. for the root directory. */
  292. if (inode->i_ino == MSDOS_ROOT_INO) {
  293. while (cpos < 2) {
  294. if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO) < 0)
  295. return 0;
  296. cpos++;
  297. filp->f_pos++;
  298. }
  299. if (cpos == 2) {
  300. dummy = 2;
  301. furrfu = &dummy;
  302. cpos = 0;
  303. }
  304. }
  305. if (cpos & (sizeof(struct msdos_dir_entry)-1))
  306. return -ENOENT;
  307. bh = NULL;
  308. GetNew:
  309. long_slots = 0;
  310. if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
  311. goto EODir;
  312. /* Check for long filename entry */
  313. if (MSDOS_SB(sb)->options.isvfat) {
  314. if (de->name[0] == (__s8) DELETED_FLAG)
  315. goto RecEnd;
  316. if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
  317. goto RecEnd;
  318. if (de->attr != ATTR_EXT && IS_FREE(de->name))
  319. goto RecEnd;
  320. } else {
  321. if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))
  322. goto RecEnd;
  323. }
  324. if (MSDOS_SB(sb)->options.isvfat && de->attr == ATTR_EXT) {
  325. struct msdos_dir_slot *ds;
  326. int offset;
  327. unsigned char id;
  328. unsigned char slot;
  329. unsigned char slots;
  330. unsigned char sum;
  331. unsigned char alias_checksum;
  332. if (!unicode) {
  333. unicode = (unsigned char *)
  334. __get_free_page(GFP_KERNEL);
  335. if (!unicode) {
  336. filp->f_pos = cpos;
  337. fat_brelse(sb, bh);
  338. return -ENOMEM;
  339. }
  340. }
  341. ParseLong:
  342. slots = 0;
  343. offset = 0;
  344. ds = (struct msdos_dir_slot *) de;
  345. id = ds->id;
  346. if (!(id & 0x40))
  347. goto RecEnd;
  348. slots = id & ~0x40;
  349. if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
  350. goto RecEnd;
  351. long_slots = slots;
  352. alias_checksum = ds->alias_checksum;
  353. slot = slots;
  354. while (1) {
  355. slot--;
  356. offset = slot * 26;
  357. memcpy(&unicode[offset], ds->name0_4, 10);
  358. memcpy(&unicode[offset+10], ds->name5_10, 12);
  359. memcpy(&unicode[offset+22], ds->name11_12, 4);
  360. offset += 26;
  361. if (ds->id & 0x40) {
  362. unicode[offset] = 0;
  363. unicode[offset+1] = 0;
  364. }
  365. if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
  366. goto EODir;
  367. if (slot == 0)
  368. break;
  369. ds = (struct msdos_dir_slot *) de;
  370. if (ds->attr != ATTR_EXT)
  371. goto RecEnd; /* XXX */
  372. if ((ds->id & ~0x40) != slot)
  373. goto ParseLong;
  374. if (ds->alias_checksum != alias_checksum)
  375. goto ParseLong;
  376. }
  377. if (de->name[0] == (__s8) DELETED_FLAG)
  378. goto RecEnd;
  379. if (de->attr == ATTR_EXT)
  380. goto ParseLong;
  381. if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
  382. goto RecEnd;
  383. for (sum = 0, i = 0; i < 11; i++)
  384. sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
  385. if (sum != alias_checksum)
  386. long_slots = 0;
  387. }
  388. if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
  389. *ptname++ = '.';
  390. dotoffset = 1;
  391. }
  392. for (i = 0, last = 0; i < 8;) {
  393. if (!(c = de->name[i])) break;
  394. if (c >= 'A' && c <= 'Z') c += 32;
  395. /* see namei.c, msdos_format_name */
  396. if (c == 0x05) c = 0xE5;
  397. if ((ptname[i++] = c) != ' ')
  398. last = i;
  399. }
  400. i = last;
  401. ptname[i++] = '.';
  402. for (i2 = 0; i2 < 3; i2++) {
  403. if (!(c = de->ext[i2])) break;
  404. if (c >= 'A' && c <= 'Z') c += 32;
  405. if ((ptname[i++] = c) != ' ')
  406. last = i;
  407. }
  408. if (!last)
  409. goto RecEnd;
  410. i = last + dotoffset;
  411. lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
  412. if (!memcmp(de->name,MSDOS_DOT,11))
  413. inum = inode->i_ino;
  414. else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
  415. /* inum = fat_parent_ino(inode,0); */
  416. inum = filp->f_dentry->d_parent->d_inode->i_ino;
  417. } else {
  418. struct inode *tmp = fat_iget(sb, ino);
  419. if (tmp) {
  420. inum = tmp->i_ino;
  421. iput(tmp);
  422. } else
  423. inum = iunique(sb, MSDOS_ROOT_INO);
  424. }
  425. if (!long_slots||shortnames) {
  426. if (both)
  427. bufname[i] = '\0';
  428. if (filldir(dirent, bufname, i, *furrfu, inum) < 0)
  429. goto FillFailed;
  430. } else {
  431. char longname[275];
  432. unsigned char long_len = utf8
  433. ? utf8_wcstombs(longname, (__u16 *) unicode, 275)
  434. : uni16_to_x8(longname, unicode, uni_xlate, nls);
  435. if (both) {
  436. memcpy(&longname[long_len+1], bufname, i);
  437. long_len += i;
  438. }
  439. if (filldir(dirent, longname, long_len, *furrfu, inum) < 0)
  440. goto FillFailed;
  441. }
  442. RecEnd:
  443. furrfu = &lpos;
  444. filp->f_pos = cpos;
  445. goto GetNew;
  446. EODir:
  447. filp->f_pos = cpos;
  448. FillFailed:
  449. if (bh)
  450. fat_brelse(sb, bh);
  451. if (unicode) {
  452. free_page((unsigned long) unicode);
  453. }
  454. return 0;
  455. }
  456. int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
  457. {
  458. struct inode *inode = filp->f_dentry->d_inode;
  459. return fat_readdirx(inode, filp, dirent, filldir, 0, 0);
  460. }
  461. static int vfat_ioctl_fill(
  462. void * buf,
  463. const char * name,
  464. int name_len,
  465. off_t offset,
  466. ino_t ino)
  467. {
  468. struct dirent *d1 = (struct dirent *)buf;
  469. struct dirent *d2 = d1 + 1;
  470. int len, slen;
  471. int dotdir;
  472. get_user(len, &d1->d_reclen);
  473. if (len != 0) {
  474. return -1;
  475. }
  476. if ((name_len == 1 && name[0] == '.') ||
  477. (name_len == 2 && name[0] == '.' && name[1] == '.')) {
  478. dotdir = 1;
  479. len = name_len;
  480. } else {
  481. dotdir = 0;
  482. len = strlen(name);
  483. }
  484. if (len != name_len) {
  485. copy_to_user(d2->d_name, name, len);
  486. put_user(0, d2->d_name + len);
  487. put_user(len, &d2->d_reclen);
  488. put_user(ino, &d2->d_ino);
  489. put_user(offset, &d2->d_off);
  490. slen = name_len - len;
  491. copy_to_user(d1->d_name, name+len+1, slen);
  492. put_user(0, d1->d_name+slen);
  493. put_user(slen, &d1->d_reclen);
  494. } else {
  495. put_user(0, d2->d_name);
  496. put_user(0, &d2->d_reclen);
  497. copy_to_user(d1->d_name, name, len);
  498. put_user(0, d1->d_name+len);
  499. put_user(len, &d1->d_reclen);
  500. }
  501. PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
  502. d1, d2, len, name_len));
  503. return 0;
  504. }
  505. int fat_dir_ioctl(struct inode * inode, struct file * filp,
  506. unsigned int cmd, unsigned long arg)
  507. {
  508. int err;
  509. /*
  510. * We want to provide an interface for Samba to be able
  511. * to get the short filename for a given long filename.
  512. * Samba should use this ioctl instead of readdir() to
  513. * get the information it needs.
  514. */
  515. switch (cmd) {
  516. case VFAT_IOCTL_READDIR_BOTH: {
  517. struct dirent *d1 = (struct dirent *)arg;
  518. err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
  519. if (err)
  520. return err;
  521. put_user(0, &d1->d_reclen);
  522. return fat_readdirx(inode,filp,(void *)arg,
  523. vfat_ioctl_fill, 0, 1);
  524. }
  525. case VFAT_IOCTL_READDIR_SHORT: {
  526. struct dirent *d1 = (struct dirent *)arg;
  527. put_user(0, &d1->d_reclen);
  528. err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
  529. if (err)
  530. return err;
  531. return fat_readdirx(inode,filp,(void *)arg,
  532. vfat_ioctl_fill, 1, 1);
  533. }
  534. default:
  535. /* forward ioctl to CVF extension */
  536. if (MSDOS_SB(inode->i_sb)->cvf_format &&
  537. MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl)
  538. return MSDOS_SB(inode->i_sb)->cvf_format
  539. ->cvf_dir_ioctl(inode,filp,cmd,arg);
  540. return -EINVAL;
  541. }
  542. return 0;
  543. }
  544. /***** See if directory is empty */
  545. int fat_dir_empty(struct inode *dir)
  546. {
  547. loff_t pos;
  548. struct buffer_head *bh;
  549. struct msdos_dir_entry *de;
  550. int ino,result = 0;
  551. pos = 0;
  552. bh = NULL;
  553. while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) {
  554. /* Ignore vfat longname entries */
  555. if (de->attr == ATTR_EXT)
  556. continue;
  557. if (!IS_FREE(de->name) &&
  558. strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
  559. strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
  560. result = -ENOTEMPTY;
  561. break;
  562. }
  563. }
  564. if (bh)
  565. fat_brelse(dir->i_sb, bh);
  566. return result;
  567. }
  568. /* This assumes that size of cluster is above the 32*slots */
  569. int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
  570. struct msdos_dir_entry **de, int *ino)
  571. {
  572. struct super_block *sb = dir->i_sb;
  573. loff_t offset, curr;
  574. int row;
  575. int res;
  576. offset = curr = 0;
  577. *bh = NULL;
  578. row = 0;
  579. while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
  580. if (IS_FREE((*de)->name)) {
  581. if (++row == slots)
  582. return offset;
  583. } else {
  584. row = 0;
  585. offset = curr;
  586. }
  587. }
  588. if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
  589. return -ENOSPC;
  590. if ((res = fat_add_cluster(dir)) < 0) return res;
  591. do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
  592. return offset;
  593. }
  594. /*
  595. * Overrides for Emacs so that we follow Linus's tabbing style.
  596. * Emacs will notice this stuff at the end of the file and automatically
  597. * adjust the settings for this buffer only. This must remain at the end
  598. * of the file.
  599. * ---------------------------------------------------------------------------
  600. * Local variables:
  601. * c-indent-level: 8
  602. * c-brace-imaginary-offset: 0
  603. * c-brace-offset: -8
  604. * c-argdecl-indent: 8
  605. * c-label-offset: -8
  606. * c-continued-statement-offset: 8
  607. * c-continued-brace-offset: 0
  608. * End:
  609. */