diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/udf/dir.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/udf/dir.c')
-rw-r--r-- | fs/udf/dir.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/fs/udf/dir.c b/fs/udf/dir.c new file mode 100644 index 000000000000..82440b731142 --- /dev/null +++ b/fs/udf/dir.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * dir.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Directory handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998-2004 Ben Fennema | ||
19 | * | ||
20 | * HISTORY | ||
21 | * | ||
22 | * 10/05/98 dgb Split directory operations into its own file | ||
23 | * Implemented directory reads via do_udf_readdir | ||
24 | * 10/06/98 Made directory operations work! | ||
25 | * 11/17/98 Rewrote directory to support ICBTAG_FLAG_AD_LONG | ||
26 | * 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading | ||
27 | * across blocks. | ||
28 | * 12/12/98 Split out the lookup code to namei.c. bulk of directory | ||
29 | * code now in directory.c:udf_fileident_read. | ||
30 | */ | ||
31 | |||
32 | #include "udfdecl.h" | ||
33 | |||
34 | #include <linux/string.h> | ||
35 | #include <linux/errno.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/smp_lock.h> | ||
39 | #include <linux/buffer_head.h> | ||
40 | |||
41 | #include "udf_i.h" | ||
42 | #include "udf_sb.h" | ||
43 | |||
44 | /* Prototypes for file operations */ | ||
45 | static int udf_readdir(struct file *, void *, filldir_t); | ||
46 | static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *); | ||
47 | |||
48 | /* readdir and lookup functions */ | ||
49 | |||
50 | struct file_operations udf_dir_operations = { | ||
51 | .read = generic_read_dir, | ||
52 | .readdir = udf_readdir, | ||
53 | .ioctl = udf_ioctl, | ||
54 | .fsync = udf_fsync_file, | ||
55 | }; | ||
56 | |||
57 | /* | ||
58 | * udf_readdir | ||
59 | * | ||
60 | * PURPOSE | ||
61 | * Read a directory entry. | ||
62 | * | ||
63 | * DESCRIPTION | ||
64 | * Optional - sys_getdents() will return -ENOTDIR if this routine is not | ||
65 | * available. | ||
66 | * | ||
67 | * Refer to sys_getdents() in fs/readdir.c | ||
68 | * sys_getdents() -> . | ||
69 | * | ||
70 | * PRE-CONDITIONS | ||
71 | * filp Pointer to directory file. | ||
72 | * buf Pointer to directory entry buffer. | ||
73 | * filldir Pointer to filldir function. | ||
74 | * | ||
75 | * POST-CONDITIONS | ||
76 | * <return> >=0 on success. | ||
77 | * | ||
78 | * HISTORY | ||
79 | * July 1, 1997 - Andrew E. Mileski | ||
80 | * Written, tested, and released. | ||
81 | */ | ||
82 | |||
83 | int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
84 | { | ||
85 | struct inode *dir = filp->f_dentry->d_inode; | ||
86 | int result; | ||
87 | |||
88 | lock_kernel(); | ||
89 | |||
90 | if ( filp->f_pos == 0 ) | ||
91 | { | ||
92 | if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) | ||
93 | { | ||
94 | unlock_kernel(); | ||
95 | return 0; | ||
96 | } | ||
97 | filp->f_pos ++; | ||
98 | } | ||
99 | |||
100 | result = do_udf_readdir(dir, filp, filldir, dirent); | ||
101 | unlock_kernel(); | ||
102 | return result; | ||
103 | } | ||
104 | |||
105 | static int | ||
106 | do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent) | ||
107 | { | ||
108 | struct udf_fileident_bh fibh; | ||
109 | struct fileIdentDesc *fi=NULL; | ||
110 | struct fileIdentDesc cfi; | ||
111 | int block, iblock; | ||
112 | loff_t nf_pos = filp->f_pos - 1; | ||
113 | int flen; | ||
114 | char fname[UDF_NAME_LEN]; | ||
115 | char *nameptr; | ||
116 | uint16_t liu; | ||
117 | uint8_t lfi; | ||
118 | loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; | ||
119 | struct buffer_head * bh = NULL, * tmp, * bha[16]; | ||
120 | kernel_lb_addr bloc, eloc; | ||
121 | uint32_t extoffset, elen, offset; | ||
122 | int i, num; | ||
123 | unsigned int dt_type; | ||
124 | |||
125 | if (nf_pos >= size) | ||
126 | return 0; | ||
127 | |||
128 | if (nf_pos == 0) | ||
129 | nf_pos = (udf_ext0_offset(dir) >> 2); | ||
130 | |||
131 | fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; | ||
132 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
133 | fibh.sbh = fibh.ebh = NULL; | ||
134 | else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2), | ||
135 | &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) | ||
136 | { | ||
137 | offset >>= dir->i_sb->s_blocksize_bits; | ||
138 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | ||
139 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) | ||
140 | { | ||
141 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT) | ||
142 | extoffset -= sizeof(short_ad); | ||
143 | else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG) | ||
144 | extoffset -= sizeof(long_ad); | ||
145 | } | ||
146 | else | ||
147 | offset = 0; | ||
148 | |||
149 | if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) | ||
150 | { | ||
151 | udf_release_data(bh); | ||
152 | return -EIO; | ||
153 | } | ||
154 | |||
155 | if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1))) | ||
156 | { | ||
157 | i = 16 >> (dir->i_sb->s_blocksize_bits - 9); | ||
158 | if (i+offset > (elen >> dir->i_sb->s_blocksize_bits)) | ||
159 | i = (elen >> dir->i_sb->s_blocksize_bits)-offset; | ||
160 | for (num=0; i>0; i--) | ||
161 | { | ||
162 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i); | ||
163 | tmp = udf_tgetblk(dir->i_sb, block); | ||
164 | if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) | ||
165 | bha[num++] = tmp; | ||
166 | else | ||
167 | brelse(tmp); | ||
168 | } | ||
169 | if (num) | ||
170 | { | ||
171 | ll_rw_block(READA, num, bha); | ||
172 | for (i=0; i<num; i++) | ||
173 | brelse(bha[i]); | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | udf_release_data(bh); | ||
180 | return -ENOENT; | ||
181 | } | ||
182 | |||
183 | while ( nf_pos < size ) | ||
184 | { | ||
185 | filp->f_pos = nf_pos + 1; | ||
186 | |||
187 | fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); | ||
188 | |||
189 | if (!fi) | ||
190 | { | ||
191 | if (fibh.sbh != fibh.ebh) | ||
192 | udf_release_data(fibh.ebh); | ||
193 | udf_release_data(fibh.sbh); | ||
194 | udf_release_data(bh); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | liu = le16_to_cpu(cfi.lengthOfImpUse); | ||
199 | lfi = cfi.lengthFileIdent; | ||
200 | |||
201 | if (fibh.sbh == fibh.ebh) | ||
202 | nameptr = fi->fileIdent + liu; | ||
203 | else | ||
204 | { | ||
205 | int poffset; /* Unpaded ending offset */ | ||
206 | |||
207 | poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi; | ||
208 | |||
209 | if (poffset >= lfi) | ||
210 | nameptr = (char *)(fibh.ebh->b_data + poffset - lfi); | ||
211 | else | ||
212 | { | ||
213 | nameptr = fname; | ||
214 | memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); | ||
215 | memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | if ( (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 ) | ||
220 | { | ||
221 | if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) ) | ||
222 | continue; | ||
223 | } | ||
224 | |||
225 | if ( (cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 ) | ||
226 | { | ||
227 | if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) ) | ||
228 | continue; | ||
229 | } | ||
230 | |||
231 | if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT ) | ||
232 | { | ||
233 | iblock = parent_ino(filp->f_dentry); | ||
234 | flen = 2; | ||
235 | memcpy(fname, "..", flen); | ||
236 | dt_type = DT_DIR; | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation); | ||
241 | |||
242 | iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0); | ||
243 | flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); | ||
244 | dt_type = DT_UNKNOWN; | ||
245 | } | ||
246 | |||
247 | if (flen) | ||
248 | { | ||
249 | if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) | ||
250 | { | ||
251 | if (fibh.sbh != fibh.ebh) | ||
252 | udf_release_data(fibh.ebh); | ||
253 | udf_release_data(fibh.sbh); | ||
254 | udf_release_data(bh); | ||
255 | return 0; | ||
256 | } | ||
257 | } | ||
258 | } /* end while */ | ||
259 | |||
260 | filp->f_pos = nf_pos + 1; | ||
261 | |||
262 | if (fibh.sbh != fibh.ebh) | ||
263 | udf_release_data(fibh.ebh); | ||
264 | udf_release_data(fibh.sbh); | ||
265 | udf_release_data(bh); | ||
266 | |||
267 | return 0; | ||
268 | } | ||