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