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/config.h>
36 #include <linux/version.h>
39 #include <linux/string.h>
40 #include <linux/errno.h>
42 #include <linux/malloc.h>
43 #include <linux/udf_fs.h>
46 /* Prototypes for file operations */
47 static int udf_readdir(struct file
*, void *, filldir_t
);
48 static int do_udf_readdir(struct inode
*, struct file
*, filldir_t
, void *);
50 /* readdir and lookup functions */
52 struct file_operations udf_dir_operations
= {
53 read
: generic_read_dir
,
63 * Read a directory entry.
66 * Optional - sys_getdents() will return -ENOTDIR if this routine is not
69 * Refer to sys_getdents() in fs/readdir.c
73 * filp Pointer to directory file.
74 * buf Pointer to directory entry buffer.
75 * filldir Pointer to filldir function.
78 * <return> >=0 on success.
81 * July 1, 1997 - Andrew E. Mileski
82 * Written, tested, and released.
85 int udf_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
87 struct inode
*dir
= filp
->f_dentry
->d_inode
;
93 if (!S_ISDIR(dir
->i_mode
))
96 if ( filp
->f_pos
== 0 )
98 if (filldir(dirent
, ".", 1, filp
->f_pos
, dir
->i_ino
))
102 result
= do_udf_readdir(dir
, filp
, filldir
, dirent
);
108 do_udf_readdir(struct inode
* dir
, struct file
*filp
, filldir_t filldir
, void *dirent
)
110 struct udf_fileident_bh fibh
;
111 struct FileIdentDesc
*fi
=NULL
;
112 struct FileIdentDesc cfi
;
114 loff_t nf_pos
= filp
->f_pos
;
120 loff_t size
= (udf_ext0_offset(dir
) + dir
->i_size
) >> 2;
121 struct buffer_head
* bh
= NULL
;
123 Uint32 extoffset
, elen
, offset
;
129 nf_pos
= (udf_ext0_offset(dir
) >> 2);
131 fibh
.soffset
= fibh
.eoffset
= (nf_pos
& ((dir
->i_sb
->s_blocksize
- 1) >> 2)) << 2;
132 if (inode_bmap(dir
, nf_pos
>> (dir
->i_sb
->s_blocksize_bits
- 2),
133 &bloc
, &extoffset
, &eloc
, &elen
, &offset
, &bh
) == EXTENT_RECORDED_ALLOCATED
)
135 block
= udf_get_lb_pblock(dir
->i_sb
, eloc
, offset
);
136 if ((++offset
<< dir
->i_sb
->s_blocksize_bits
) < elen
)
138 if (UDF_I_ALLOCTYPE(dir
) == ICB_FLAG_AD_SHORT
)
139 extoffset
-= sizeof(short_ad
);
140 else if (UDF_I_ALLOCTYPE(dir
) == ICB_FLAG_AD_LONG
)
141 extoffset
-= sizeof(long_ad
);
148 udf_release_data(bh
);
152 if (!(fibh
.sbh
= fibh
.ebh
= udf_tread(dir
->i_sb
, block
, dir
->i_sb
->s_blocksize
)))
154 udf_release_data(bh
);
158 while ( nf_pos
< size
)
160 filp
->f_pos
= nf_pos
;
162 fi
= udf_fileident_read(dir
, &nf_pos
, &fibh
, &cfi
, &bloc
, &extoffset
, &offset
, &bh
);
166 if (fibh
.sbh
!= fibh
.ebh
)
167 udf_release_data(fibh
.ebh
);
168 udf_release_data(fibh
.sbh
);
169 udf_release_data(bh
);
173 liu
= le16_to_cpu(cfi
.lengthOfImpUse
);
174 lfi
= cfi
.lengthFileIdent
;
176 if (fibh
.sbh
== fibh
.ebh
)
177 nameptr
= fi
->fileIdent
+ liu
;
180 int poffset
; /* Unpaded ending offset */
182 poffset
= fibh
.soffset
+ sizeof(struct FileIdentDesc
) + liu
+ lfi
;
185 nameptr
= (char *)(fibh
.ebh
->b_data
+ poffset
- lfi
);
189 memcpy(nameptr
, fi
->fileIdent
+ liu
, lfi
- poffset
);
190 memcpy(nameptr
+ lfi
- poffset
, fibh
.ebh
->b_data
, poffset
);
194 if ( (cfi
.fileCharacteristics
& FILE_DELETED
) != 0 )
196 if ( !IS_UNDELETE(dir
->i_sb
) )
200 if ( (cfi
.fileCharacteristics
& FILE_HIDDEN
) != 0 )
202 if ( !IS_UNHIDE(dir
->i_sb
) )
206 iblock
= udf_get_lb_pblock(dir
->i_sb
, lelb_to_cpu(cfi
.icb
.extLocation
), 0);
208 if (!lfi
) /* parent directory */
210 if (filldir(dirent
, "..", 2, filp
->f_pos
, filp
->f_dentry
->d_parent
->d_inode
->i_ino
))
212 if (fibh
.sbh
!= fibh
.ebh
)
213 udf_release_data(fibh
.ebh
);
214 udf_release_data(fibh
.sbh
);
215 udf_release_data(bh
);
221 if ((flen
= udf_get_filename(nameptr
, fname
, lfi
)))
223 if (filldir(dirent
, fname
, flen
, filp
->f_pos
, iblock
))
225 if (fibh
.sbh
!= fibh
.ebh
)
226 udf_release_data(fibh
.ebh
);
227 udf_release_data(fibh
.sbh
);
228 udf_release_data(bh
);
229 return 1; /* halt enum */
235 filp
->f_pos
= nf_pos
;
237 if (fibh
.sbh
!= fibh
.ebh
)
238 udf_release_data(fibh
.ebh
);
239 udf_release_data(fibh
.sbh
);
240 udf_release_data(bh
);
242 if ( filp
->f_pos
>= size
)