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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [udf/] [dir.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * dir.c
3
 *
4
 * PURPOSE
5
 *  Directory handling routines for the OSTA-UDF(tm) filesystem.
6
 *
7
 * COPYRIGHT
8
 *      This file is distributed under the terms of the GNU General Public
9
 *      License (GPL). Copies of the GPL can be obtained from:
10
 *              ftp://prep.ai.mit.edu/pub/gnu/GPL
11
 *      Each contributing author retains all rights to their own work.
12
 *
13
 *  (C) 1998-2004 Ben Fennema
14
 *
15
 * HISTORY
16
 *
17
 *  10/05/98 dgb  Split directory operations into its own file
18
 *                Implemented directory reads via do_udf_readdir
19
 *  10/06/98      Made directory operations work!
20
 *  11/17/98      Rewrote directory to support ICBTAG_FLAG_AD_LONG
21
 *  11/25/98 blf  Rewrote directory handling (readdir+lookup) to support reading
22
 *                across blocks.
23
 *  12/12/98      Split out the lookup code to namei.c. bulk of directory
24
 *                code now in directory.c:udf_fileident_read.
25
 */
26
 
27
#include "udfdecl.h"
28
 
29
#include <linux/string.h>
30
#include <linux/errno.h>
31
#include <linux/mm.h>
32
#include <linux/slab.h>
33
#include <linux/smp_lock.h>
34
#include <linux/buffer_head.h>
35
 
36
#include "udf_i.h"
37
#include "udf_sb.h"
38
 
39
/* Prototypes for file operations */
40
static int udf_readdir(struct file *, void *, filldir_t);
41
static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
42
 
43
/* readdir and lookup functions */
44
 
45
const struct file_operations udf_dir_operations = {
46
        .read                   = generic_read_dir,
47
        .readdir                = udf_readdir,
48
        .ioctl                  = udf_ioctl,
49
        .fsync                  = udf_fsync_file,
50
};
51
 
52
/*
53
 * udf_readdir
54
 *
55
 * PURPOSE
56
 *      Read a directory entry.
57
 *
58
 * DESCRIPTION
59
 *      Optional - sys_getdents() will return -ENOTDIR if this routine is not
60
 *      available.
61
 *
62
 *      Refer to sys_getdents() in fs/readdir.c
63
 *      sys_getdents() -> .
64
 *
65
 * PRE-CONDITIONS
66
 *      filp                    Pointer to directory file.
67
 *      buf                     Pointer to directory entry buffer.
68
 *      filldir                 Pointer to filldir function.
69
 *
70
 * POST-CONDITIONS
71
 *      <return>                >=0 on success.
72
 *
73
 * HISTORY
74
 *      July 1, 1997 - Andrew E. Mileski
75
 *      Written, tested, and released.
76
 */
77
 
78
int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
79
{
80
        struct inode *dir = filp->f_path.dentry->d_inode;
81
        int result;
82
 
83
        lock_kernel();
84
 
85
        if (filp->f_pos == 0) {
86
                if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) {
87
                        unlock_kernel();
88
                        return 0;
89
                }
90
                filp->f_pos++;
91
        }
92
 
93
        result = do_udf_readdir(dir, filp, filldir, dirent);
94
        unlock_kernel();
95
        return result;
96
}
97
 
98
static int
99
do_udf_readdir(struct inode *dir, struct file *filp, filldir_t filldir,
100
               void *dirent)
101
{
102
        struct udf_fileident_bh fibh;
103
        struct fileIdentDesc *fi = NULL;
104
        struct fileIdentDesc cfi;
105
        int block, iblock;
106
        loff_t nf_pos = filp->f_pos - 1;
107
        int flen;
108
        char fname[UDF_NAME_LEN];
109
        char *nameptr;
110
        uint16_t liu;
111
        uint8_t lfi;
112
        loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
113
        struct buffer_head *tmp, *bha[16];
114
        kernel_lb_addr eloc;
115
        uint32_t elen;
116
        sector_t offset;
117
        int i, num;
118
        unsigned int dt_type;
119
        struct extent_position epos = { NULL, 0, {0, 0} };
120
 
121
        if (nf_pos >= size)
122
                return 0;
123
 
124
        if (nf_pos == 0)
125
                nf_pos = (udf_ext0_offset(dir) >> 2);
126
 
127
        fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
128
        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
129
                fibh.sbh = fibh.ebh = NULL;
130
        } else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
131
                              &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
132
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
133
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
134
                        if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
135
                                epos.offset -= sizeof(short_ad);
136
                        else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
137
                                epos.offset -= sizeof(long_ad);
138
                } else {
139
                        offset = 0;
140
                }
141
 
142
                if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
143
                        brelse(epos.bh);
144
                        return -EIO;
145
                }
146
 
147
                if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
148
                        i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
149
                        if (i + offset > (elen >> dir->i_sb->s_blocksize_bits))
150
                                i = (elen >> dir->i_sb->s_blocksize_bits) - offset;
151
                        for (num = 0; i > 0; i--) {
152
                                block = udf_get_lb_pblock(dir->i_sb, eloc, offset + i);
153
                                tmp = udf_tgetblk(dir->i_sb, block);
154
                                if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
155
                                        bha[num++] = tmp;
156
                                else
157
                                        brelse(tmp);
158
                        }
159
                        if (num) {
160
                                ll_rw_block(READA, num, bha);
161
                                for (i = 0; i < num; i++)
162
                                        brelse(bha[i]);
163
                        }
164
                }
165
        } else {
166
                brelse(epos.bh);
167
                return -ENOENT;
168
        }
169
 
170
        while (nf_pos < size) {
171
                filp->f_pos = nf_pos + 1;
172
 
173
                fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
174
                                        &elen, &offset);
175
                if (!fi) {
176
                        if (fibh.sbh != fibh.ebh)
177
                                brelse(fibh.ebh);
178
                        brelse(fibh.sbh);
179
                        brelse(epos.bh);
180
                        return 0;
181
                }
182
 
183
                liu = le16_to_cpu(cfi.lengthOfImpUse);
184
                lfi = cfi.lengthFileIdent;
185
 
186
                if (fibh.sbh == fibh.ebh) {
187
                        nameptr = fi->fileIdent + liu;
188
                } else {
189
                        int poffset;    /* Unpaded ending offset */
190
 
191
                        poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
192
 
193
                        if (poffset >= lfi) {
194
                                nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
195
                        } else {
196
                                nameptr = fname;
197
                                memcpy(nameptr, fi->fileIdent + liu,
198
                                       lfi - poffset);
199
                                memcpy(nameptr + lfi - poffset,
200
                                       fibh.ebh->b_data, poffset);
201
                        }
202
                }
203
 
204
                if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
205
                        if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
206
                                continue;
207
                }
208
 
209
                if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
210
                        if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
211
                                continue;
212
                }
213
 
214
                if (cfi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
215
                        iblock = parent_ino(filp->f_path.dentry);
216
                        flen = 2;
217
                        memcpy(fname, "..", flen);
218
                        dt_type = DT_DIR;
219
                } else {
220
                        kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation);
221
 
222
                        iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0);
223
                        flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
224
                        dt_type = DT_UNKNOWN;
225
                }
226
 
227
                if (flen) {
228
                        if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) {
229
                                if (fibh.sbh != fibh.ebh)
230
                                        brelse(fibh.ebh);
231
                                brelse(fibh.sbh);
232
                                brelse(epos.bh);
233
                                return 0;
234
                        }
235
                }
236
        } /* end while */
237
 
238
        filp->f_pos = nf_pos + 1;
239
 
240
        if (fibh.sbh != fibh.ebh)
241
                brelse(fibh.ebh);
242
        brelse(fibh.sbh);
243
        brelse(epos.bh);
244
 
245
        return 0;
246
}

powered by: WebSVN 2.1.0

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