Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
namei.c
Go to the documentation of this file.
1 /*
2  * linux/fs/isofs/namei.c
3  *
4  * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
5  *
6  * (C) 1991 Linus Torvalds - minix filesystem
7  */
8 
9 #include <linux/gfp.h>
10 #include "isofs.h"
11 
12 /*
13  * ok, we cannot use strncmp, as the name is not in our data space.
14  * Thus we'll have to use isofs_match. No big problem. Match also makes
15  * some sanity tests.
16  */
17 static int
18 isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
19 {
20  struct qstr qstr;
21 
22  if (!compare)
23  return 1;
24 
25  /* check special "." and ".." files */
26  if (dlen == 1) {
27  /* "." */
28  if (compare[0] == 0) {
29  if (!dentry->d_name.len)
30  return 0;
31  compare = ".";
32  } else if (compare[0] == 1) {
33  compare = "..";
34  dlen = 2;
35  }
36  }
37 
38  qstr.name = compare;
39  qstr.len = dlen;
40  return dentry->d_op->d_compare(NULL, NULL, NULL, NULL,
41  dentry->d_name.len, dentry->d_name.name, &qstr);
42 }
43 
44 /*
45  * isofs_find_entry()
46  *
47  * finds an entry in the specified directory with the wanted name. It
48  * returns the inode number of the found entry, or 0 on error.
49  */
50 static unsigned long
51 isofs_find_entry(struct inode *dir, struct dentry *dentry,
52  unsigned long *block_rv, unsigned long *offset_rv,
53  char *tmpname, struct iso_directory_record *tmpde)
54 {
55  unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
56  unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
57  unsigned long block, f_pos, offset, block_saved, offset_saved;
58  struct buffer_head *bh = NULL;
59  struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
60 
61  if (!ISOFS_I(dir)->i_first_extent)
62  return 0;
63 
64  f_pos = 0;
65  offset = 0;
66  block = 0;
67 
68  while (f_pos < dir->i_size) {
69  struct iso_directory_record *de;
70  int de_len, match, i, dlen;
71  char *dpnt;
72 
73  if (!bh) {
74  bh = isofs_bread(dir, block);
75  if (!bh)
76  return 0;
77  }
78 
79  de = (struct iso_directory_record *) (bh->b_data + offset);
80 
81  de_len = *(unsigned char *) de;
82  if (!de_len) {
83  brelse(bh);
84  bh = NULL;
85  f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
86  block = f_pos >> bufbits;
87  offset = 0;
88  continue;
89  }
90 
91  block_saved = bh->b_blocknr;
92  offset_saved = offset;
93  offset += de_len;
94  f_pos += de_len;
95 
96  /* Make sure we have a full directory entry */
97  if (offset >= bufsize) {
98  int slop = bufsize - offset + de_len;
99  memcpy(tmpde, de, slop);
100  offset &= bufsize - 1;
101  block++;
102  brelse(bh);
103  bh = NULL;
104  if (offset) {
105  bh = isofs_bread(dir, block);
106  if (!bh)
107  return 0;
108  memcpy((void *) tmpde + slop, bh->b_data, offset);
109  }
110  de = tmpde;
111  }
112 
113  dlen = de->name_len[0];
114  dpnt = de->name;
115  /* Basic sanity check, whether name doesn't exceed dir entry */
116  if (de_len < dlen + sizeof(struct iso_directory_record)) {
117  printk(KERN_NOTICE "iso9660: Corrupted directory entry"
118  " in block %lu of inode %lu\n", block,
119  dir->i_ino);
120  return 0;
121  }
122 
123  if (sbi->s_rock &&
124  ((i = get_rock_ridge_filename(de, tmpname, dir)))) {
125  dlen = i; /* possibly -1 */
126  dpnt = tmpname;
127 #ifdef CONFIG_JOLIET
128  } else if (sbi->s_joliet_level) {
129  dlen = get_joliet_filename(de, tmpname, dir);
130  dpnt = tmpname;
131 #endif
132  } else if (sbi->s_mapping == 'a') {
133  dlen = get_acorn_filename(de, tmpname, dir);
134  dpnt = tmpname;
135  } else if (sbi->s_mapping == 'n') {
136  dlen = isofs_name_translate(de, tmpname, dir);
137  dpnt = tmpname;
138  }
139 
140  /*
141  * Skip hidden or associated files unless hide or showassoc,
142  * respectively, is set
143  */
144  match = 0;
145  if (dlen > 0 &&
146  (!sbi->s_hide ||
147  (!(de->flags[-sbi->s_high_sierra] & 1))) &&
148  (sbi->s_showassoc ||
149  (!(de->flags[-sbi->s_high_sierra] & 4)))) {
150  match = (isofs_cmp(dentry, dpnt, dlen) == 0);
151  }
152  if (match) {
153  isofs_normalize_block_and_offset(de,
154  &block_saved,
155  &offset_saved);
156  *block_rv = block_saved;
157  *offset_rv = offset_saved;
158  brelse(bh);
159  return 1;
160  }
161  }
162  brelse(bh);
163  return 0;
164 }
165 
166 struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
167 {
168  int found;
169  unsigned long uninitialized_var(block);
170  unsigned long uninitialized_var(offset);
171  struct inode *inode;
172  struct page *page;
173 
174  page = alloc_page(GFP_USER);
175  if (!page)
176  return ERR_PTR(-ENOMEM);
177 
178  found = isofs_find_entry(dir, dentry,
179  &block, &offset,
180  page_address(page),
181  1024 + page_address(page));
182  __free_page(page);
183 
184  inode = found ? isofs_iget(dir->i_sb, block, offset) : NULL;
185 
186  return d_splice_alias(inode, dentry);
187 }