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

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [fs/] [isofs/] [namei.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/fs/isofs/namei.c
3
 *
4
 *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
5
 *
6
 *  (C) 1991  Linus Torvalds - minix filesystem
7
 */
8
 
9
#include <linux/sched.h>
10
#include <linux/iso_fs.h>
11
#include <linux/kernel.h>
12
#include <linux/string.h>
13
#include <linux/stat.h>
14
#include <linux/fcntl.h>
15
#include <asm/segment.h>
16
#include <linux/malloc.h>
17
 
18
#include <linux/errno.h>
19
 
20
/*
21
 * ok, we cannot use strncmp, as the name is not in our data space.
22
 * Thus we'll have to use isofs_match. No big problem. Match also makes
23
 * some sanity tests.
24
 *
25
 * NOTE! unlike strncmp, isofs_match returns 1 for success, 0 for failure.
26
 */
27
static int isofs_match(int len,const char * name, const char * compare, int dlen)
28
{
29
        if (!compare)
30
                return 0;
31
 
32
        /* check special "." and ".." files */
33
        if (dlen == 1) {
34
                /* "." */
35
                if (compare[0] == 0) {
36
                        if (!len)
37
                                return 1;
38
                        compare = ".";
39
                } else if (compare[0] == 1) {
40
                        compare = "..";
41
                        dlen = 2;
42
                }
43
        }
44
#if 0
45
        if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
46
#endif
47
 
48
        if (dlen != len)
49
                return 0;
50
        return !memcmp(name, compare, len);
51
}
52
 
53
/*
54
 *      isofs_find_entry()
55
 *
56
 * finds an entry in the specified directory with the wanted name. It
57
 * returns the cache buffer in which the entry was found, and the entry
58
 * itself (as an inode number). It does NOT read the inode of the
59
 * entry - you'll have to do that yourself if you want to.
60
 */
61
static struct buffer_head *
62
isofs_find_entry(struct inode * dir, const char * name, int namelen,
63
                 unsigned long * ino, unsigned long * ino_back)
64
{
65
        unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
66
        unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
67
        unsigned int block, i, f_pos, offset, inode_number;
68
        struct buffer_head * bh;
69
        void * cpnt = NULL;
70
        unsigned int old_offset;
71
        unsigned int backlink;
72
        int dlen, match;
73
        char * dpnt;
74
        unsigned char *page = NULL;
75
        struct iso_directory_record * de;
76
        char c;
77
 
78
        *ino = 0;
79
        if (!dir) return NULL;
80
 
81
        if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
82
 
83
        f_pos = 0;
84
 
85
        offset = f_pos & (bufsize - 1);
86
        block = isofs_bmap(dir,f_pos >> bufbits);
87
 
88
        if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
89
 
90
        while (f_pos < dir->i_size) {
91
                de = (struct iso_directory_record *) (bh->b_data + offset);
92
                backlink = dir->i_ino;
93
                inode_number = (block << bufbits) + (offset & (bufsize - 1));
94
 
95
                /* If byte is zero, this is the end of file, or time to move to
96
                   the next sector. Usually 2048 byte boundaries. */
97
 
98
                if (*((unsigned char *) de) == 0) {
99
                        brelse(bh);
100
                        offset = 0;
101
                        f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
102
                                 + ISOFS_BLOCK_SIZE);
103
                        block = isofs_bmap(dir,f_pos>>bufbits);
104
                        if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
105
                                return NULL;
106
                        continue; /* Will kick out if past end of directory */
107
                }
108
 
109
                old_offset = offset;
110
                offset += *((unsigned char *) de);
111
                f_pos += *((unsigned char *) de);
112
 
113
                /* Handle case where the directory entry spans two blocks.
114
                   Usually 1024 byte boundaries */
115
                if (offset >= bufsize) {
116
                        unsigned int frag1;
117
                        frag1 = bufsize - old_offset;
118
                        cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
119
                        if (!cpnt) return NULL;
120
                        memcpy(cpnt, bh->b_data + old_offset, frag1);
121
 
122
                        de = (struct iso_directory_record *) cpnt;
123
                        brelse(bh);
124
                        offset = f_pos & (bufsize - 1);
125
                        block = isofs_bmap(dir,f_pos>>bufbits);
126
                        if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
127
                                kfree(cpnt);
128
                                return NULL;
129
                        };
130
                        memcpy((char *)cpnt+frag1, bh->b_data, offset);
131
                }
132
 
133
                dlen = de->name_len[0];
134
                dpnt = de->name;
135
 
136
                /* Handle the '.' case */
137
 
138
                if (*dpnt==0 && dlen==1) {
139
                        inode_number = dir->i_ino;
140
                        backlink = 0;
141
                }
142
 
143
                /* Handle the '..' case */
144
 
145
                else if (*dpnt==1 && dlen==1) {
146
#if 0
147
                        printk("Doing .. (%d %d)",
148
                               dir->i_sb->s_firstdatazone,
149
                               dir->i_ino);
150
#endif
151
                        if((dir->i_sb->u.isofs_sb.s_firstdatazone) != dir->i_ino)
152
                                inode_number = dir->u.isofs_i.i_backlink;
153
                        else
154
                                inode_number = dir->i_ino;
155
                        backlink = 0;
156
                } else {
157
                        if (dir->i_sb->u.isofs_sb.s_rock ||
158
                            dir->i_sb->u.isofs_sb.s_joliet_level) {
159
                                page = (unsigned char *)
160
                                        __get_free_page(GFP_KERNEL);
161
                                if (!page) return NULL;
162
                        }
163
                        if (dir->i_sb->u.isofs_sb.s_rock &&
164
                            ((i = get_rock_ridge_filename(de, page, dir)))){
165
                                if (i == -1)
166
                                        goto out;/* Relocated deep directory */
167
                                dlen = i;
168
                                dpnt = page;
169
                        } else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
170
                                dlen = get_joliet_filename(de, dir, page);
171
                                dpnt = page;
172
                        } else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
173
                                for (i = 0; i < dlen; i++) {
174
                                        c = dpnt[i];
175
                                        /* lower case */
176
                                        if (c >= 'A' && c <= 'Z') c |= 0x20;
177
                                        if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
178
                                                dlen -= 2;
179
                                                break;
180
                                        }
181
                                        if (c == ';') c = '.';
182
                                        dpnt[i] = c;
183
                                }
184
                                /* This allows us to match with and without
185
                                 * a trailing period. */
186
                                if(dpnt[dlen-1] == '.' && namelen == dlen-1)
187
                                        dlen--;
188
                        }
189
                }
190
                /*
191
                 * Skip hidden or associated files unless unhide is set
192
                 */
193
                match = 0;
194
                if(   !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
195
                   || dir->i_sb->u.isofs_sb.s_unhide == 'y' )
196
                {
197
                        match = isofs_match(namelen,name,dpnt,dlen);
198
                }
199
 
200
                if (cpnt)
201
                {
202
                        kfree(cpnt);
203
                        cpnt = NULL;
204
                }
205
 
206
                if (page) free_page((unsigned long) page);
207
                if (match) {
208
                        if(inode_number == -1) {
209
                                /* Should only happen for the '..' entry */
210
                                inode_number =
211
                                        isofs_lookup_grandparent(dir,
212
                                           find_rock_ridge_relocation(de,dir));
213
                                if(inode_number == -1){
214
                                        /* Should never happen */
215
                                        printk("Backlink not properly set %x %lx.\n",
216
                                               isonum_733(de->extent),
217
                                               dir->i_ino);
218
                                        goto out;
219
                                }
220
                        }
221
                        *ino = inode_number;
222
                        *ino_back = backlink;
223
                        return bh;
224
                }
225
        }
226
 out:
227
        if (cpnt)
228
                kfree(cpnt);
229
        brelse(bh);
230
        return NULL;
231
}
232
 
233
int isofs_lookup(struct inode * dir,const char * name, int len,
234
        struct inode ** result)
235
{
236
        unsigned long ino, ino_back;
237
        struct buffer_head * bh;
238
 
239
#ifdef DEBUG
240
        printk("lookup: %x %d\n",dir->i_ino, len);
241
#endif
242
        *result = NULL;
243
        if (!dir)
244
                return -ENOENT;
245
 
246
        if (!S_ISDIR(dir->i_mode)) {
247
                iput(dir);
248
                return -ENOENT;
249
        }
250
 
251
        ino = 0;
252
 
253
        if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
254
 
255
 
256
        if (!ino) {
257
                char *lcname;
258
 
259
                /* First try the original name. If that doesn't work and the fs
260
                 * was mounted with check=relaxed, convert the name to lower
261
                 * case and try again.
262
                 */
263
                if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))
264
                    && dir->i_sb->u.isofs_sb.s_name_check == 'r'
265
                    && (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
266
                        int i;
267
                        char c;
268
 
269
                        for (i=0; i<len; i++) {
270
                                c = name[i];
271
                                if (c >= 'A' && c <= 'Z') c |= 0x20;
272
                                lcname[i] = c;
273
                        }
274
                        bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
275
                        kfree(lcname);
276
                }
277
 
278
                if (!bh) {
279
                        iput(dir);
280
                        return -ENOENT;
281
                }
282
                if (ino_back == dir->i_ino) {
283
                        dcache_add(dir, name, len, ino);
284
                }
285
                brelse(bh);
286
        }
287
 
288
        if (!(*result = iget(dir->i_sb,ino))) {
289
                iput(dir);
290
                return -EACCES;
291
        }
292
 
293
        /* We need this backlink for the ".." entry unless the name that we
294
           are looking up traversed a mount point (in which case the inode
295
           may not even be on an iso9660 filesystem, and writing to
296
           u.isofs_i would only cause memory corruption).
297
        */
298
 
299
        if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
300
                (*result)->u.isofs_i.i_backlink = ino_back;
301
        }
302
 
303
        iput(dir);
304
        return 0;
305
}

powered by: WebSVN 2.1.0

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