dir.c 6.6 KB

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