OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [udf/] [dir.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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-2001 Ben Fennema
19
 *
20
 * HISTORY
21
 *
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 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
 
39
#include "udf_i.h"
40
#include "udf_sb.h"
41
 
42
/* Prototypes for file operations */
43
static int udf_readdir(struct file *, void *, filldir_t);
44
static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
45
 
46
/* readdir and lookup functions */
47
 
48
struct file_operations udf_dir_operations = {
49
        read:                   generic_read_dir,
50
        readdir:                udf_readdir,
51
        ioctl:                  udf_ioctl,
52
        fsync:                  udf_fsync_file,
53
};
54
 
55
/*
56
 * udf_readdir
57
 *
58
 * PURPOSE
59
 *      Read a directory entry.
60
 *
61
 * DESCRIPTION
62
 *      Optional - sys_getdents() will return -ENOTDIR if this routine is not
63
 *      available.
64
 *
65
 *      Refer to sys_getdents() in fs/readdir.c
66
 *      sys_getdents() -> .
67
 *
68
 * PRE-CONDITIONS
69
 *      filp                    Pointer to directory file.
70
 *      buf                     Pointer to directory entry buffer.
71
 *      filldir                 Pointer to filldir function.
72
 *
73
 * POST-CONDITIONS
74
 *      <return>                >=0 on success.
75
 *
76
 * HISTORY
77
 *      July 1, 1997 - Andrew E. Mileski
78
 *      Written, tested, and released.
79
 */
80
 
81
int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
82
{
83
        struct inode *dir = filp->f_dentry->d_inode;
84
        int result;
85
 
86
        if ( filp->f_pos == 0 )
87
        {
88
                if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0)
89
                        return 0;
90
                filp->f_pos ++;
91
        }
92
 
93
        result = do_udf_readdir(dir, filp, filldir, dirent);
94
        UPDATE_ATIME(dir);
95
        return result;
96
}
97
 
98
static int
99
do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent)
100
{
101
        struct udf_fileident_bh fibh;
102
        struct fileIdentDesc *fi=NULL;
103
        struct fileIdentDesc cfi;
104
        int block, iblock;
105
        loff_t nf_pos = filp->f_pos - 1;
106
        int flen;
107
        char fname[255];
108
        char *nameptr;
109
        uint16_t liu;
110
        uint8_t lfi;
111
        loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
112
        struct buffer_head * bh = NULL, * tmp, * bha[16];
113
        lb_addr bloc, eloc;
114
        uint32_t extoffset, elen, offset;
115
        int i, num;
116
        unsigned int dt_type;
117
 
118
        if (nf_pos >= size)
119
                return 0;
120
 
121
        if (nf_pos == 0)
122
                nf_pos = (udf_ext0_offset(dir) >> 2);
123
 
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) == (EXT_RECORDED_ALLOCATED >> 30))
127
        {
128
                offset >>= dir->i_sb->s_blocksize_bits;
129
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
130
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
131
                {
132
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
133
                                extoffset -= sizeof(short_ad);
134
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
135
                                extoffset -= sizeof(long_ad);
136
                }
137
                else
138
                        offset = 0;
139
        }
140
        else
141
        {
142
                udf_release_data(bh);
143
                return -ENOENT;
144
        }
145
 
146
        if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
147
        {
148
                udf_release_data(bh);
149
                return -EIO;
150
        }
151
 
152
        if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
153
        {
154
                i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
155
                if (i+offset > (elen >> dir->i_sb->s_blocksize_bits))
156
                        i = (elen >> dir->i_sb->s_blocksize_bits)-offset;
157
                for (num=0; i>0; i--)
158
                {
159
                        block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i);
160
                        tmp = udf_tgetblk(dir->i_sb, block);
161
                        if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
162
                                bha[num++] = tmp;
163
                        else
164
                                brelse(tmp);
165
                }
166
                if (num)
167
                {
168
                        ll_rw_block(READA, num, bha);
169
                        for (i=0; i<num; i++)
170
                                brelse(bha[i]);
171
                }
172
        }
173
 
174
        while ( nf_pos < size )
175
        {
176
                filp->f_pos = nf_pos + 1;
177
 
178
                fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
179
 
180
                if (!fi)
181
                {
182
                        if (fibh.sbh != fibh.ebh)
183
                                udf_release_data(fibh.ebh);
184
                        udf_release_data(fibh.sbh);
185
                        udf_release_data(bh);
186
                        return 0;
187
                }
188
 
189
                liu = le16_to_cpu(cfi.lengthOfImpUse);
190
                lfi = cfi.lengthFileIdent;
191
 
192
                if (fibh.sbh == fibh.ebh)
193
                        nameptr = fi->fileIdent + liu;
194
                else
195
                {
196
                        int poffset;    /* Unpaded ending offset */
197
 
198
                        poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
199
 
200
                        if (poffset >= lfi)
201
                                nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
202
                        else
203
                        {
204
                                nameptr = fname;
205
                                memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
206
                                memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset);
207
                        }
208
                }
209
 
210
                if ( (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
211
                {
212
                        if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
213
                                continue;
214
                }
215
 
216
                if ( (cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
217
                {
218
                        if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
219
                                continue;
220
                }
221
 
222
                if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT )
223
                {
224
                        iblock = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(filp->f_dentry->d_parent->d_inode), 0);
225
                        flen = 2;
226
                        memcpy(fname, "..", flen);
227
                        dt_type = DT_DIR;
228
                }
229
                else
230
                {
231
                        iblock = udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0);
232
                        flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
233
                        dt_type = DT_UNKNOWN;
234
                }
235
 
236
                if (flen)
237
                {
238
                        if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0)
239
                        {
240
                                if (fibh.sbh != fibh.ebh)
241
                                        udf_release_data(fibh.ebh);
242
                                udf_release_data(fibh.sbh);
243
                                udf_release_data(bh);
244
                                return 0;
245
                        }
246
                }
247
        } /* end while */
248
 
249
        filp->f_pos = nf_pos + 1;
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
 
256
        return 0;
257
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.