dir.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * linux/fs/isofs/dir.c
  3. *
  4. * (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO 9660 filesystem.
  5. *
  6. * (C) 1991 Linus Torvalds - minix filesystem
  7. *
  8. * Steve Beynon : Missing last directory entries fixed
  9. * (stephen@askone.demon.co.uk) : 21st June 1996
  10. *
  11. * isofs directory handling functions
  12. */
  13. #include <linux/gfp.h>
  14. #include "isofs.h"
  15. int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
  16. {
  17. char * old = de->name;
  18. int len = de->name_len[0];
  19. int i;
  20. for (i = 0; i < len; i++) {
  21. unsigned char c = old[i];
  22. if (!c)
  23. break;
  24. if (c >= 'A' && c <= 'Z')
  25. c |= 0x20; /* lower case */
  26. /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
  27. if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
  28. break;
  29. /* Drop trailing ';1' */
  30. if (c == ';' && i == len - 2 && old[i + 1] == '1')
  31. break;
  32. /* Convert remaining ';' to '.' */
  33. /* Also '/' to '.' (broken Acorn-generated ISO9660 images) */
  34. if (c == ';' || c == '/')
  35. c = '.';
  36. new[i] = c;
  37. }
  38. return i;
  39. }
  40. /* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
  41. int get_acorn_filename(struct iso_directory_record *de,
  42. char *retname, struct inode *inode)
  43. {
  44. int std;
  45. unsigned char *chr;
  46. int retnamlen = isofs_name_translate(de, retname, inode);
  47. if (retnamlen == 0)
  48. return 0;
  49. std = sizeof(struct iso_directory_record) + de->name_len[0];
  50. if (std & 1)
  51. std++;
  52. if ((*((unsigned char *) de) - std) != 32)
  53. return retnamlen;
  54. chr = ((unsigned char *) de) + std;
  55. if (strncmp(chr, "ARCHIMEDES", 10))
  56. return retnamlen;
  57. if ((*retname == '_') && ((chr[19] & 1) == 1))
  58. *retname = '!';
  59. if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
  60. && ((chr[12] & 0xf0) == 0xf0)) {
  61. retname[retnamlen] = ',';
  62. sprintf(retname+retnamlen+1, "%3.3x",
  63. ((chr[12] & 0xf) << 8) | chr[11]);
  64. retnamlen += 4;
  65. }
  66. return retnamlen;
  67. }
  68. /*
  69. * This should _really_ be cleaned up some day..
  70. */
  71. static int do_isofs_readdir(struct inode *inode, struct file *file,
  72. struct dir_context *ctx,
  73. char *tmpname, struct iso_directory_record *tmpde)
  74. {
  75. unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
  76. unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
  77. unsigned long block, offset, block_saved, offset_saved;
  78. unsigned long inode_number = 0; /* Quiet GCC */
  79. struct buffer_head *bh = NULL;
  80. int len;
  81. int map;
  82. int first_de = 1;
  83. char *p = NULL; /* Quiet GCC */
  84. struct iso_directory_record *de;
  85. struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
  86. offset = ctx->pos & (bufsize - 1);
  87. block = ctx->pos >> bufbits;
  88. while (ctx->pos < inode->i_size) {
  89. int de_len;
  90. if (!bh) {
  91. bh = isofs_bread(inode, block);
  92. if (!bh)
  93. return 0;
  94. }
  95. de = (struct iso_directory_record *) (bh->b_data + offset);
  96. de_len = *(unsigned char *)de;
  97. /*
  98. * If the length byte is zero, we should move on to the next
  99. * CDROM sector. If we are at the end of the directory, we
  100. * kick out of the while loop.
  101. */
  102. if (de_len == 0) {
  103. brelse(bh);
  104. bh = NULL;
  105. ctx->pos = (ctx->pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
  106. block = ctx->pos >> bufbits;
  107. offset = 0;
  108. continue;
  109. }
  110. block_saved = block;
  111. offset_saved = offset;
  112. offset += de_len;
  113. /* Make sure we have a full directory entry */
  114. if (offset >= bufsize) {
  115. int slop = bufsize - offset + de_len;
  116. memcpy(tmpde, de, slop);
  117. offset &= bufsize - 1;
  118. block++;
  119. brelse(bh);
  120. bh = NULL;
  121. if (offset) {
  122. bh = isofs_bread(inode, block);
  123. if (!bh)
  124. return 0;
  125. memcpy((void *) tmpde + slop, bh->b_data, offset);
  126. }
  127. de = tmpde;
  128. }
  129. /* Basic sanity check, whether name doesn't exceed dir entry */
  130. if (de_len < de->name_len[0] +
  131. sizeof(struct iso_directory_record)) {
  132. printk(KERN_NOTICE "iso9660: Corrupted directory entry"
  133. " in block %lu of inode %lu\n", block,
  134. inode->i_ino);
  135. return -EIO;
  136. }
  137. if (first_de) {
  138. isofs_normalize_block_and_offset(de,
  139. &block_saved,
  140. &offset_saved);
  141. inode_number = isofs_get_ino(block_saved,
  142. offset_saved, bufbits);
  143. }
  144. if (de->flags[-sbi->s_high_sierra] & 0x80) {
  145. first_de = 0;
  146. ctx->pos += de_len;
  147. continue;
  148. }
  149. first_de = 1;
  150. /* Handle the case of the '.' directory */
  151. if (de->name_len[0] == 1 && de->name[0] == 0) {
  152. if (!dir_emit_dot(file, ctx))
  153. break;
  154. ctx->pos += de_len;
  155. continue;
  156. }
  157. len = 0;
  158. /* Handle the case of the '..' directory */
  159. if (de->name_len[0] == 1 && de->name[0] == 1) {
  160. if (!dir_emit_dotdot(file, ctx))
  161. break;
  162. ctx->pos += de_len;
  163. continue;
  164. }
  165. /* Handle everything else. Do name translation if there
  166. is no Rock Ridge NM field. */
  167. /*
  168. * Do not report hidden files if so instructed, or associated
  169. * files unless instructed to do so
  170. */
  171. if ((sbi->s_hide && (de->flags[-sbi->s_high_sierra] & 1)) ||
  172. (!sbi->s_showassoc &&
  173. (de->flags[-sbi->s_high_sierra] & 4))) {
  174. ctx->pos += de_len;
  175. continue;
  176. }
  177. map = 1;
  178. if (sbi->s_rock) {
  179. len = get_rock_ridge_filename(de, tmpname, inode);
  180. if (len != 0) { /* may be -1 */
  181. p = tmpname;
  182. map = 0;
  183. }
  184. }
  185. if (map) {
  186. #ifdef CONFIG_JOLIET
  187. if (sbi->s_joliet_level) {
  188. len = get_joliet_filename(de, tmpname, inode);
  189. p = tmpname;
  190. } else
  191. #endif
  192. if (sbi->s_mapping == 'a') {
  193. len = get_acorn_filename(de, tmpname, inode);
  194. p = tmpname;
  195. } else
  196. if (sbi->s_mapping == 'n') {
  197. len = isofs_name_translate(de, tmpname, inode);
  198. p = tmpname;
  199. } else {
  200. p = de->name;
  201. len = de->name_len[0];
  202. }
  203. }
  204. if (len > 0) {
  205. if (!dir_emit(ctx, p, len, inode_number, DT_UNKNOWN))
  206. break;
  207. }
  208. ctx->pos += de_len;
  209. continue;
  210. }
  211. if (bh)
  212. brelse(bh);
  213. return 0;
  214. }
  215. /*
  216. * Handle allocation of temporary space for name translation and
  217. * handling split directory entries.. The real work is done by
  218. * "do_isofs_readdir()".
  219. */
  220. static int isofs_readdir(struct file *file, struct dir_context *ctx)
  221. {
  222. int result;
  223. char *tmpname;
  224. struct iso_directory_record *tmpde;
  225. struct inode *inode = file_inode(file);
  226. tmpname = (char *)__get_free_page(GFP_KERNEL);
  227. if (tmpname == NULL)
  228. return -ENOMEM;
  229. tmpde = (struct iso_directory_record *) (tmpname+1024);
  230. result = do_isofs_readdir(inode, file, ctx, tmpname, tmpde);
  231. free_page((unsigned long) tmpname);
  232. return result;
  233. }
  234. const struct file_operations isofs_dir_operations =
  235. {
  236. .llseek = generic_file_llseek,
  237. .read = generic_read_dir,
  238. .iterate = isofs_readdir,
  239. };
  240. /*
  241. * directories can handle most operations...
  242. */
  243. const struct inode_operations isofs_dir_inode_operations =
  244. {
  245. .lookup = isofs_lookup,
  246. };