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-2000 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 struct file_operations udf_dir_operations
= {
52 read
: generic_read_dir
,
62 * Read a directory entry.
65 * Optional - sys_getdents() will return -ENOTDIR if this routine is not
68 * Refer to sys_getdents() in fs/readdir.c
72 * filp Pointer to directory file.
73 * buf Pointer to directory entry buffer.
74 * filldir Pointer to filldir function.
77 * <return> >=0 on success.
80 * July 1, 1997 - Andrew E. Mileski
81 * Written, tested, and released.
84 int udf_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
86 struct inode
*dir
= filp
->f_dentry
->d_inode
;
89 if ( filp
->f_pos
== 0 )
91 if (filldir(dirent
, ".", 1, filp
->f_pos
, dir
->i_ino
, DT_DIR
))
95 result
= do_udf_readdir(dir
, filp
, filldir
, dirent
);
101 do_udf_readdir(struct inode
* dir
, struct file
*filp
, filldir_t filldir
, void *dirent
)
103 struct udf_fileident_bh fibh
;
104 struct FileIdentDesc
*fi
=NULL
;
105 struct FileIdentDesc cfi
;
107 loff_t nf_pos
= filp
->f_pos
;
113 loff_t size
= (udf_ext0_offset(dir
) + dir
->i_size
) >> 2;
114 struct buffer_head
* bh
= NULL
;
116 Uint32 extoffset
, elen
, offset
;
122 nf_pos
= (udf_ext0_offset(dir
) >> 2);
124 fibh
.soffset
= fibh
.eoffset
= (nf_pos
& ((dir
->i_sb
->s_blocksize
- 1) >> 2)) << 2;
125 if (inode_bmap(dir
, nf_pos
>> (dir
->i_sb
->s_blocksize_bits
- 2),
126 &bloc
, &extoffset
, &eloc
, &elen
, &offset
, &bh
) == EXTENT_RECORDED_ALLOCATED
)
128 block
= udf_get_lb_pblock(dir
->i_sb
, eloc
, offset
);
129 if ((++offset
<< dir
->i_sb
->s_blocksize_bits
) < elen
)
131 if (UDF_I_ALLOCTYPE(dir
) == ICB_FLAG_AD_SHORT
)
132 extoffset
-= sizeof(short_ad
);
133 else if (UDF_I_ALLOCTYPE(dir
) == ICB_FLAG_AD_LONG
)
134 extoffset
-= sizeof(long_ad
);
141 udf_release_data(bh
);
145 if (!(fibh
.sbh
= fibh
.ebh
= udf_tread(dir
->i_sb
, block
, dir
->i_sb
->s_blocksize
)))
147 udf_release_data(bh
);
151 while ( nf_pos
< size
)
153 filp
->f_pos
= nf_pos
;
155 fi
= udf_fileident_read(dir
, &nf_pos
, &fibh
, &cfi
, &bloc
, &extoffset
, &eloc
, &elen
, &offset
, &bh
);
159 if (fibh
.sbh
!= fibh
.ebh
)
160 udf_release_data(fibh
.ebh
);
161 udf_release_data(fibh
.sbh
);
162 udf_release_data(bh
);
166 liu
= le16_to_cpu(cfi
.lengthOfImpUse
);
167 lfi
= cfi
.lengthFileIdent
;
169 if (fibh
.sbh
== fibh
.ebh
)
170 nameptr
= fi
->fileIdent
+ liu
;
173 int poffset
; /* Unpaded ending offset */
175 poffset
= fibh
.soffset
+ sizeof(struct FileIdentDesc
) + liu
+ lfi
;
178 nameptr
= (char *)(fibh
.ebh
->b_data
+ poffset
- lfi
);
182 memcpy(nameptr
, fi
->fileIdent
+ liu
, lfi
- poffset
);
183 memcpy(nameptr
+ lfi
- poffset
, fibh
.ebh
->b_data
, poffset
);
187 if ( (cfi
.fileCharacteristics
& FILE_DELETED
) != 0 )
189 if ( !UDF_QUERY_FLAG(dir
->i_sb
, UDF_FLAG_UNDELETE
) )
193 if ( (cfi
.fileCharacteristics
& FILE_HIDDEN
) != 0 )
195 if ( !UDF_QUERY_FLAG(dir
->i_sb
, UDF_FLAG_UNHIDE
) )
199 iblock
= udf_get_lb_pblock(dir
->i_sb
, lelb_to_cpu(cfi
.icb
.extLocation
), 0);
201 if (!lfi
) /* parent directory */
203 if (filldir(dirent
, "..", 2, filp
->f_pos
, filp
->f_dentry
->d_parent
->d_inode
->i_ino
, DT_DIR
))
205 if (fibh
.sbh
!= fibh
.ebh
)
206 udf_release_data(fibh
.ebh
);
207 udf_release_data(fibh
.sbh
);
208 udf_release_data(bh
);
214 if ((flen
= udf_get_filename(nameptr
, fname
, lfi
)))
216 if (filldir(dirent
, fname
, flen
, filp
->f_pos
, iblock
, DT_UNKNOWN
))
218 if (fibh
.sbh
!= fibh
.ebh
)
219 udf_release_data(fibh
.ebh
);
220 udf_release_data(fibh
.sbh
);
221 udf_release_data(bh
);
222 return 1; /* halt enum */
228 filp
->f_pos
= nf_pos
;
230 if (fibh
.sbh
!= fibh
.ebh
)
231 udf_release_data(fibh
.ebh
);
232 udf_release_data(fibh
.sbh
);
233 udf_release_data(bh
);
235 if ( filp
->f_pos
>= size
)