5 * Directory handling routines for the OSTA-UDF(tm) filesystem.
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@hootie.lvld.hp.com
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.
18 * (C) 1998-1999 Ben Fennema
22 * 10/05/98 dgb Split directory operations into it's 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 ICB_FLAG_AD_LONG
26 * 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading
28 * 12/12/98 Split out the lookup code to namei.c. bulk of directory
29 * code now in directory.c:udf_fileident_read.
34 #if defined(__linux__) && defined(__KERNEL__)
35 #include <linux/version.h>
38 #include <linux/string.h>
39 #include <linux/errno.h>
41 #include <linux/malloc.h>
42 #include <linux/udf_fs.h>
45 /* Prototypes for file operations */
46 static int udf_readdir(struct file
*, void *, filldir_t
);
47 static int do_udf_readdir(struct inode
*, struct file
*, filldir_t
, void *);
49 /* readdir and lookup functions */
51 static struct file_operations udf_dir_operations
= {
55 udf_readdir
, /* readdir */
57 udf_ioctl
, /* ioctl */
62 udf_sync_file
, /* fsync */
64 NULL
, /* check_media_change */
65 NULL
, /* revalidate */
69 struct inode_operations udf_dir_inode_operations
= {
72 udf_create
, /* create */
76 udf_lookup
, /* lookup */
79 udf_unlink
, /* unlink */
80 udf_symlink
, /* symlink */
81 udf_mkdir
, /* mkdir */
82 udf_rmdir
, /* rmdir */
83 udf_mknod
, /* mknod */
84 udf_rename
, /* rename */
95 NULL
, /* follow_link */
101 NULL
, /* permission */
103 NULL
/* revalidate */
110 * Read a directory entry.
113 * Optional - sys_getdents() will return -ENOTDIR if this routine is not
116 * Refer to sys_getdents() in fs/readdir.c
117 * sys_getdents() -> .
120 * filp Pointer to directory file.
121 * buf Pointer to directory entry buffer.
122 * filldir Pointer to filldir function.
125 * <return> >=0 on success.
128 * July 1, 1997 - Andrew E. Mileski
129 * Written, tested, and released.
132 int udf_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
134 struct inode
*dir
= filp
->f_dentry
->d_inode
;
140 if (!S_ISDIR(dir
->i_mode
))
143 if ( filp
->f_pos
== 0 )
145 if (filldir(dirent
, ".", 1, filp
->f_pos
, dir
->i_ino
) < 0)
149 result
= do_udf_readdir(dir
, filp
, filldir
, dirent
);
155 do_udf_readdir(struct inode
* dir
, struct file
*filp
, filldir_t filldir
, void *dirent
)
157 struct udf_fileident_bh fibh
;
158 struct FileIdentDesc
*fi
=NULL
;
159 struct FileIdentDesc cfi
;
161 int nf_pos
= filp
->f_pos
;
167 int size
= (UDF_I_EXT0OFFS(dir
) + dir
->i_size
) >> 2;
168 struct buffer_head
* bh
= NULL
;
170 Uint32 extoffset
, elen
, offset
;
176 nf_pos
= (UDF_I_EXT0OFFS(dir
) >> 2);
178 fibh
.soffset
= fibh
.eoffset
= (nf_pos
& ((dir
->i_sb
->s_blocksize
- 1) >> 2)) << 2;
179 if (inode_bmap(dir
, nf_pos
>> (dir
->i_sb
->s_blocksize_bits
- 2),
180 &bloc
, &extoffset
, &eloc
, &elen
, &offset
, &bh
) == EXTENT_RECORDED_ALLOCATED
)
182 block
= udf_get_lb_pblock(dir
->i_sb
, eloc
, offset
);
183 if ((++offset
<< dir
->i_sb
->s_blocksize_bits
) < elen
)
185 if (UDF_I_ALLOCTYPE(dir
) == ICB_FLAG_AD_SHORT
)
186 extoffset
-= sizeof(short_ad
);
187 else if (UDF_I_ALLOCTYPE(dir
) == ICB_FLAG_AD_LONG
)
188 extoffset
-= sizeof(long_ad
);
195 udf_release_data(bh
);
199 if (!(fibh
.sbh
= fibh
.ebh
= udf_tread(dir
->i_sb
, block
, dir
->i_sb
->s_blocksize
)))
201 udf_release_data(bh
);
205 while ( nf_pos
< size
)
207 filp
->f_pos
= nf_pos
;
209 fi
= udf_fileident_read(dir
, &nf_pos
, &fibh
, &cfi
, &bloc
, &extoffset
, &offset
, &bh
);
213 if (fibh
.sbh
!= fibh
.ebh
)
214 udf_release_data(fibh
.ebh
);
215 udf_release_data(fibh
.sbh
);
216 udf_release_data(bh
);
220 liu
= le16_to_cpu(cfi
.lengthOfImpUse
);
221 lfi
= cfi
.lengthFileIdent
;
223 if (fibh
.sbh
== fibh
.ebh
)
224 nameptr
= fi
->fileIdent
+ liu
;
227 int poffset
; /* Unpaded ending offset */
229 poffset
= fibh
.soffset
+ sizeof(struct FileIdentDesc
) + liu
+ lfi
;
232 nameptr
= (char *)(fibh
.ebh
->b_data
+ poffset
- lfi
);
236 memcpy(nameptr
, fi
->fileIdent
+ liu
, lfi
- poffset
);
237 memcpy(nameptr
+ lfi
- poffset
, fibh
.ebh
->b_data
, poffset
);
241 if ( (cfi
.fileCharacteristics
& FILE_DELETED
) != 0 )
243 if ( !IS_UNDELETE(dir
->i_sb
) )
247 if ( (cfi
.fileCharacteristics
& FILE_HIDDEN
) != 0 )
249 if ( !IS_UNHIDE(dir
->i_sb
) )
253 iblock
= udf_get_lb_pblock(dir
->i_sb
, lelb_to_cpu(cfi
.icb
.extLocation
), 0);
255 if (!lfi
) /* parent directory */
257 if (filldir(dirent
, "..", 2, filp
->f_pos
, filp
->f_dentry
->d_parent
->d_inode
->i_ino
) < 0)
259 if (fibh
.sbh
!= fibh
.ebh
)
260 udf_release_data(fibh
.ebh
);
261 udf_release_data(fibh
.sbh
);
262 udf_release_data(bh
);
268 if ((flen
= udf_get_filename(nameptr
, fname
, lfi
)))
270 if (filldir(dirent
, fname
, flen
, filp
->f_pos
, iblock
) < 0)
272 if (fibh
.sbh
!= fibh
.ebh
)
273 udf_release_data(fibh
.ebh
);
274 udf_release_data(fibh
.sbh
);
275 udf_release_data(bh
);
276 return 1; /* halt enum */
281 udf_debug("size=%d, nf_pos=%d, liu=%d, lfi=%d\n", size
, nf_pos
, liu
, lfi
);
286 filp
->f_pos
= nf_pos
;
288 if (fibh
.sbh
!= fibh
.ebh
)
289 udf_release_data(fibh
.ebh
);
290 udf_release_data(fibh
.sbh
);
291 udf_release_data(bh
);
293 if ( filp
->f_pos
>= size
)