Blame view

fs/isofs/namei.c 4.07 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   *  linux/fs/isofs/namei.c
   *
   *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
   *
   *  (C) 1991  Linus Torvalds - minix filesystem
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/smp_lock.h>
94f2f7157   Al Viro   [PATCH] isofs inc...
9
  #include "isofs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
  
  /*
   * ok, we cannot use strncmp, as the name is not in our data space.
   * Thus we'll have to use isofs_match. No big problem. Match also makes
   * some sanity tests.
   */
  static int
c3ed85a36   Dave Jones   isofs: fix up Cod...
17
  isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  {
  	struct qstr qstr;
  
  	if (!compare)
  		return 1;
  
  	/* check special "." and ".." files */
  	if (dlen == 1) {
  		/* "." */
  		if (compare[0] == 0) {
  			if (!dentry->d_name.len)
  				return 0;
  			compare = ".";
  		} else if (compare[0] == 1) {
  			compare = "..";
  			dlen = 2;
  		}
  	}
  
  	qstr.name = compare;
  	qstr.len = dlen;
  	return dentry->d_op->d_compare(dentry, &dentry->d_name, &qstr);
  }
  
  /*
   *	isofs_find_entry()
   *
   * finds an entry in the specified directory with the wanted name. It
   * returns the inode number of the found entry, or 0 on error.
   */
  static unsigned long
  isofs_find_entry(struct inode *dir, struct dentry *dentry,
c3ed85a36   Dave Jones   isofs: fix up Cod...
50
51
  	unsigned long *block_rv, unsigned long *offset_rv,
  	char *tmpname, struct iso_directory_record *tmpde)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
  {
  	unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
  	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
  	unsigned long block, f_pos, offset, block_saved, offset_saved;
c3ed85a36   Dave Jones   isofs: fix up Cod...
56
  	struct buffer_head *bh = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
  	struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
  
  	if (!ISOFS_I(dir)->i_first_extent)
  		return 0;
c3ed85a36   Dave Jones   isofs: fix up Cod...
61

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
  	f_pos = 0;
  	offset = 0;
  	block = 0;
  
  	while (f_pos < dir->i_size) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
67
  		struct iso_directory_record *de;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  		int de_len, match, i, dlen;
  		char *dpnt;
  
  		if (!bh) {
  			bh = isofs_bread(dir, block);
  			if (!bh)
  				return 0;
  		}
  
  		de = (struct iso_directory_record *) (bh->b_data + offset);
  
  		de_len = *(unsigned char *) de;
  		if (!de_len) {
  			brelse(bh);
  			bh = NULL;
  			f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
  			block = f_pos >> bufbits;
  			offset = 0;
  			continue;
  		}
  
  		block_saved = bh->b_blocknr;
  		offset_saved = offset;
  		offset += de_len;
  		f_pos += de_len;
  
  		/* Make sure we have a full directory entry */
  		if (offset >= bufsize) {
  			int slop = bufsize - offset + de_len;
  			memcpy(tmpde, de, slop);
  			offset &= bufsize - 1;
  			block++;
  			brelse(bh);
  			bh = NULL;
  			if (offset) {
  				bh = isofs_bread(dir, block);
  				if (!bh)
  					return 0;
  				memcpy((void *) tmpde + slop, bh->b_data, offset);
  			}
  			de = tmpde;
  		}
  
  		dlen = de->name_len[0];
  		dpnt = de->name;
  
  		if (sbi->s_rock &&
  		    ((i = get_rock_ridge_filename(de, tmpname, dir)))) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
116
  			dlen = i;	/* possibly -1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  			dpnt = tmpname;
  #ifdef CONFIG_JOLIET
  		} else if (sbi->s_joliet_level) {
  			dlen = get_joliet_filename(de, tmpname, dir);
  			dpnt = tmpname;
  #endif
  		} else if (sbi->s_mapping == 'a') {
  			dlen = get_acorn_filename(de, tmpname, dir);
  			dpnt = tmpname;
  		} else if (sbi->s_mapping == 'n') {
  			dlen = isofs_name_translate(de, tmpname, dir);
  			dpnt = tmpname;
  		}
  
  		/*
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
132
133
  		 * Skip hidden or associated files unless hide or showassoc,
  		 * respectively, is set
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
  		 */
  		match = 0;
  		if (dlen > 0 &&
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
137
138
139
140
141
  			(sbi->s_hide =='n' ||
  				(!(de->flags[-sbi->s_high_sierra] & 1))) &&
  			(sbi->s_showassoc =='y' ||
  				(!(de->flags[-sbi->s_high_sierra] & 4)))) {
  			match = (isofs_cmp(dentry, dpnt, dlen) == 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
  		}
  		if (match) {
  			isofs_normalize_block_and_offset(de,
  							 &block_saved,
  							 &offset_saved);
c3ed85a36   Dave Jones   isofs: fix up Cod...
147
148
  			*block_rv = block_saved;
  			*offset_rv = offset_saved;
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
149
  			brelse(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
  			return 1;
  		}
  	}
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
153
  	brelse(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
  	return 0;
  }
c3ed85a36   Dave Jones   isofs: fix up Cod...
156
  struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  {
  	int found;
  	unsigned long block, offset;
  	struct inode *inode;
  	struct page *page;
  
  	dentry->d_op = dir->i_sb->s_root->d_op;
  
  	page = alloc_page(GFP_USER);
  	if (!page)
  		return ERR_PTR(-ENOMEM);
  
  	lock_kernel();
  	found = isofs_find_entry(dir, dentry,
c3ed85a36   Dave Jones   isofs: fix up Cod...
171
172
173
  				&block, &offset,
  				page_address(page),
  				1024 + page_address(page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
181
182
183
184
  	__free_page(page);
  
  	inode = NULL;
  	if (found) {
  		inode = isofs_iget(dir->i_sb, block, offset);
  		if (!inode) {
  			unlock_kernel();
  			return ERR_PTR(-EACCES);
  		}
  	}
  	unlock_kernel();
2ff6b1c25   Pekka Enberg   [PATCH] isofs: re...
185
  	return d_splice_alias(inode, dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  }