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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/isofs/dir.c
3
 *
4
 *  (C) 1992, 1993, 1994  Eric Youngdale Modified for ISO 9660 filesystem.
5
 *
6
 *  (C) 1991  Linus Torvalds - minix filesystem
7
 *
8
 *  Steve Beynon                       : Missing last directory entries fixed
9
 *  (stephen@askone.demon.co.uk)      : 21st June 1996
10
 *
11
 *  isofs directory handling functions
12
 */
13
#include <linux/errno.h>
14
#include <linux/fs.h>
15
#include <linux/iso_fs.h>
16
#include <linux/kernel.h>
17
#include <linux/stat.h>
18
#include <linux/string.h>
19
#include <linux/mm.h>
20
#include <linux/slab.h>
21
#include <linux/sched.h>
22
#include <linux/locks.h>
23
#include <linux/config.h>
24
 
25
#include <asm/uaccess.h>
26
 
27
static int isofs_readdir(struct file *, void *, filldir_t);
28
 
29
struct file_operations isofs_dir_operations =
30
{
31
        read:           generic_read_dir,
32
        readdir:        isofs_readdir,
33
};
34
 
35
/*
36
 * directories can handle most operations...
37
 */
38
struct inode_operations isofs_dir_inode_operations =
39
{
40
        lookup:         isofs_lookup,
41
};
42
 
43
int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
44
{
45
        char * old = de->name;
46
        int len = de->name_len[0];
47
        int i;
48
 
49
        for (i = 0; i < len; i++) {
50
                unsigned char c = old[i];
51
                if (!c)
52
                        break;
53
 
54
                if (c >= 'A' && c <= 'Z')
55
                        c |= 0x20;      /* lower case */
56
 
57
                /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
58
                if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
59
                        break;
60
 
61
                /* Drop trailing ';1' */
62
                if (c == ';' && i == len - 2 && old[i + 1] == '1')
63
                        break;
64
 
65
                /* Convert remaining ';' to '.' */
66
                if (c == ';')
67
                        c = '.';
68
 
69
                new[i] = c;
70
        }
71
        return i;
72
}
73
 
74
/* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
75
int get_acorn_filename(struct iso_directory_record * de,
76
                            char * retname, struct inode * inode)
77
{
78
        int std;
79
        unsigned char * chr;
80
        int retnamlen = isofs_name_translate(de, retname, inode);
81
        if (retnamlen == 0) return 0;
82
        std = sizeof(struct iso_directory_record) + de->name_len[0];
83
        if (std & 1) std++;
84
        if ((*((unsigned char *) de) - std) != 32) return retnamlen;
85
        chr = ((unsigned char *) de) + std;
86
        if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
87
        if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
88
        if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
89
                && ((chr[12] & 0xf0) == 0xf0))
90
        {
91
                retname[retnamlen] = ',';
92
                sprintf(retname+retnamlen+1, "%3.3x",
93
                        ((chr[12] & 0xf) << 8) | chr[11]);
94
                retnamlen += 4;
95
        }
96
        return retnamlen;
97
}
98
 
99
/*
100
 * This should _really_ be cleaned up some day..
101
 */
102
static int do_isofs_readdir(struct inode *inode, struct file *filp,
103
                void *dirent, filldir_t filldir,
104
                char * tmpname, struct iso_directory_record * tmpde)
105
{
106
        unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
107
        unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
108
        unsigned int block, offset;
109
        int inode_number = 0;    /* Quiet GCC */
110
        struct buffer_head *bh = NULL;
111
        int len;
112
        int map;
113
        int high_sierra;
114
        int first_de = 1;
115
        char *p = NULL;         /* Quiet GCC */
116
        struct iso_directory_record *de;
117
 
118
        offset = filp->f_pos & (bufsize - 1);
119
        block = filp->f_pos >> bufbits;
120
        high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
121
 
122
        while (filp->f_pos < inode->i_size) {
123
                int de_len;
124
 
125
                if (!bh) {
126
                        bh = isofs_bread(inode, block);
127
                        if (!bh)
128
                                return 0;
129
                }
130
 
131
                de = (struct iso_directory_record *) (bh->b_data + offset);
132
                if (first_de)
133
                        inode_number = (bh->b_blocknr << bufbits) + offset;
134
 
135
                de_len = *(unsigned char *) de;
136
 
137
                /* If the length byte is zero, we should move on to the next
138
                   CDROM sector.  If we are at the end of the directory, we
139
                   kick out of the while loop. */
140
 
141
                if (de_len == 0) {
142
                        brelse(bh);
143
                        bh = NULL;
144
                        filp->f_pos = (filp->f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
145
                        block = filp->f_pos >> bufbits;
146
                        offset = 0;
147
                        continue;
148
                }
149
 
150
                offset += de_len;
151
 
152
                /* Make sure we have a full directory entry */
153
                if (offset >= bufsize) {
154
                        int slop = bufsize - offset + de_len;
155
                        memcpy(tmpde, de, slop);
156
                        offset &= bufsize - 1;
157
                        block++;
158
                        brelse(bh);
159
                        bh = NULL;
160
                        if (offset) {
161
                                bh = isofs_bread(inode, block);
162
                                if (!bh)
163
                                        return 0;
164
                                memcpy((void *) tmpde + slop, bh->b_data, offset);
165
                        }
166
                        de = tmpde;
167
                }
168
 
169
                if (de->flags[-high_sierra] & 0x80) {
170
                        first_de = 0;
171
                        filp->f_pos += de_len;
172
                        continue;
173
                }
174
                first_de = 1;
175
 
176
                /* Handle the case of the '.' directory */
177
                if (de->name_len[0] == 1 && de->name[0] == 0) {
178
                        if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
179
                                break;
180
                        filp->f_pos += de_len;
181
                        continue;
182
                }
183
 
184
                len = 0;
185
 
186
                /* Handle the case of the '..' directory */
187
                if (de->name_len[0] == 1 && de->name[0] == 1) {
188
                        inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
189
                        if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
190
                                break;
191
                        filp->f_pos += de_len;
192
                        continue;
193
                }
194
 
195
                /* Handle everything else.  Do name translation if there
196
                   is no Rock Ridge NM field. */
197
                if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
198
                        /* Do not report hidden or associated files */
199
                        if (de->flags[-high_sierra] & 5) {
200
                                filp->f_pos += de_len;
201
                                continue;
202
                        }
203
                }
204
 
205
                map = 1;
206
                if (inode->i_sb->u.isofs_sb.s_rock) {
207
                        len = get_rock_ridge_filename(de, tmpname, inode);
208
                        if (len != 0) {          /* may be -1 */
209
                                p = tmpname;
210
                                map = 0;
211
                        }
212
                }
213
                if (map) {
214
#ifdef CONFIG_JOLIET
215
                        if (inode->i_sb->u.isofs_sb.s_joliet_level) {
216
                                len = get_joliet_filename(de, tmpname, inode);
217
                                p = tmpname;
218
                        } else
219
#endif
220
                        if (inode->i_sb->u.isofs_sb.s_mapping == 'a') {
221
                                len = get_acorn_filename(de, tmpname, inode);
222
                                p = tmpname;
223
                        } else
224
                        if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
225
                                len = isofs_name_translate(de, tmpname, inode);
226
                                p = tmpname;
227
                        } else {
228
                                p = de->name;
229
                                len = de->name_len[0];
230
                        }
231
                }
232
                if (len > 0) {
233
                        if (filldir(dirent, p, len, filp->f_pos, inode_number, DT_UNKNOWN) < 0)
234
                                break;
235
                }
236
                filp->f_pos += de_len;
237
 
238
                continue;
239
        }
240
        if (bh) brelse(bh);
241
        return 0;
242
}
243
 
244
/*
245
 * Handle allocation of temporary space for name translation and
246
 * handling split directory entries.. The real work is done by
247
 * "do_isofs_readdir()".
248
 */
249
static int isofs_readdir(struct file *filp,
250
                void *dirent, filldir_t filldir)
251
{
252
        int result;
253
        char * tmpname;
254
        struct iso_directory_record * tmpde;
255
        struct inode *inode = filp->f_dentry->d_inode;
256
 
257
        tmpname = (char *) __get_free_page(GFP_KERNEL);
258
        if (!tmpname)
259
                return -ENOMEM;
260
        tmpde = (struct iso_directory_record *) (tmpname+1024);
261
 
262
        result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
263
 
264
        free_page((unsigned long) tmpname);
265
        return result;
266
}

powered by: WebSVN 2.1.0

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