dir.c 6.5 KB

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