Subversion Repositories HelenOS

Rev

Rev 2376 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2376 konopa 1
/* This file contains the procedures that look up path names in the directory
2
* system and determine the inode number that goes with a given path name.
3
*/
2404 konopa 4
/*
5
 * Copyright (c) 1987,1997, Prentice Hall
6
 * All rights reserved.
7
 *
8
 * Redistribution and use of the MINIX operating system in source and
9
 * binary forms, with or without modification, are permitted provided
10
 * that the following conditions are met:
2376 konopa 11
 
2404 konopa 12
 * - Redistributions of source code must retain the above copyright
13
 *   notice, this list of conditions and the following disclaimer.
14
 
15
 * - Redistributions in binary form must reproduce the above
16
 *   copyright notice, this list of conditions and the following
17
 *   disclaimer in the documentation and/or other materials provided
18
 *   with the distribution.
19
 
20
 * - Neither the name of Prentice Hall nor the names of the software
21
 *   authors or contributors may be used to endorse or promote
22
 *   products derived from this software without specific prior
23
 *   written permission.
24
 
25
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
26
 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
27
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29
 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
30
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
33
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
35
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37
 */
38
 
39
 
2376 konopa 40
/* Methods:
41
 * eat_path:        the 'main' routine of the path-to-inode conversion mechanism
42
 * last_dir:        find the final directory on a given path
43
 * advance:     parse one component of a path name
44
 * search_dir:      search a directory for a string and return its inode number
45
 * search_dir_ex:   used for extended versions
46
 */
47
 
48
 
49
#include <string.h>
50
#include "fs.h"
51
#include "block.h"
52
#include "file.h"
53
#include "fproc.h"
54
#include "inode.h"
55
#include "super.h"
56
 
57
 
58
static char *get_name(char *old_name, char *string, int string_length);
59
 
60
inode_t *eat_path(char *path)
61
{
62
 
63
    /* Parse the path 'path' and put its inode in the inode table. If not possible,
64
     * return NIL_INODE as function value and an error code in 'err_code'.
65
     */
66
 
67
    register inode_t *ldip, *rip;
68
    super_block_t *sp;
69
    int name_len;
70
    char string[name_len];        /* hold 1 path component name here */
71
 
72
    name_len = NAME_MAX;
73
    if ((sp = get_super()) == NIL_SUPER)
74
        return NIL_INODE;
75
 
76
    if (sp->s_extend) {
77
        name_len = NAME_MAX_EX;
78
    }
2404 konopa 79
 
2376 konopa 80
    /* First open the path down to the final directory. */
81
    if ( (ldip = last_dir(path, string, name_len)) == NIL_INODE)
82
        return NIL_INODE;      /* we couldn't open final directory */
2404 konopa 83
 
84
 
2376 konopa 85
    /* The path consisting only of "/" is a special case, check for it. */
86
    if (string[0] == '\0')
87
        return ldip;
2404 konopa 88
 
2376 konopa 89
    /* Get final component of the path. */
90
    rip = advance(ldip, string, name_len);
91
    put_inode(ldip);
2404 konopa 92
 
2376 konopa 93
    return rip;
94
}
95
 
96
inode_t *last_dir(char *path, char *string, int string_length)
97
{
98
 
99
    /* Given a path, 'path', located in the fs address space, parse it as
100
     * far as the last directory, fetch the inode for the last directory into
101
     * the inode table, and return a pointer to the inode.  In
102
     * addition, return the final component of the path in 'string'.
103
     * If the last directory can't be opened, return NIL_INODE and
104
     * the reason for failure in 'err_code'.
105
     */
106
 
107
    register inode_t *rip;
108
    register char *new_name;
109
    register inode_t *new_ip;
110
 
111
    /* Is the path absolute or relative?  Initialize 'rip' accordingly. */
112
    rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir);
113
 
114
    /* If dir has been removed or path is empty, return FS_ENOENT. */
115
    if (rip->i_nlinks == 0  ||  *path == '\0') {
116
        err_code = FS_ENOENT;
117
        return NIL_INODE;
118
    }
119
 
120
    dup_inode(rip);     /* inode will be returned with put_inode */
121
 
122
    /* Scan the path component by component. */
123
    while (TRUE) {
124
        /* Extract one component. */
125
        if ( (new_name = get_name(path, string, string_length)) == (char*) 0) {
126
            put_inode(rip); /* bad path in user space */
2404 konopa 127
 
2376 konopa 128
            return NIL_INODE;
129
            }
130
        if (*new_name == '\0')
131
        {
132
            if ( (rip->i_mode & I_TYPE) == I_DIRECTORY)
133
                return rip;    /* normal exit */
134
            else {
135
                /* last file of path prefix is not a directory */
136
                put_inode(rip);
137
                err_code = FS_ENOTDIR;         
138
                return NIL_INODE;
139
            }
140
        }
141
            /* There is more path.  Keep parsing. */
142
        new_ip = advance(rip, string, string_length);
143
        put_inode(rip);
144
 
145
        if (new_ip == NIL_INODE) {
146
            return NIL_INODE;
147
        }
148
        /* The call to advance() succeeded.  Fetch next component. */
149
        path = new_name;
150
        rip = new_ip;
151
    }
152
}
153
 
154
char *get_name(char *old_name, char *string, int string_length)
155
{
156
 
157
    /* Given a pointer to a path name in fs space, 'old_name', copy the next
158
     * component to 'string' and pad with zeros.  A pointer to that part of
159
     * the name as yet unparsed is returned.  Roughly speaking,
160
     * 'get_name' = 'old_name' - 'string'.
161
     *
162
     * This routine follows the standard convention that /usr/ast, /usr//ast,
163
     * //usr///ast and /usr/ast/ are all equivalent.
164
     */
165
 
166
    register int c;
167
    register char *np, *rnp;
168
 
169
    np = string;                  /* 'np' points to current position */
170
    rnp = old_name;               /* 'rnp' points to unparsed string */
171
    while ((c = *rnp) == '/')
172
        rnp++;     /* skip leading slashes */
173
 
174
    /* Copy the unparsed path, 'old_name', to the array, 'string'. */
175
    while ( rnp < &old_name[PATH_MAX]  &&  c != '/'   &&  c != '\0') {
176
        if (np < &string[string_length])
177
            *np++ = c;
178
 
179
        c = *++rnp;             /* advance to next character */
180
    }
181
 
182
    /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */
183
    while (c == '/' && rnp < &old_name[PATH_MAX])
184
        c = *++rnp;
185
 
186
    /* Padding with zeroes */
187
    if (np < &string[string_length])
188
        *np = '\0';       /* Terminate string */
189
 
190
    if (rnp >= &old_name[PATH_MAX]) {
191
        err_code = FS_ENAMETOOLONG;
192
        return((char *) 0);
193
    }
194
 
195
    return rnp;
196
}
197
 
198
inode_t *advance(inode_t *dirp, char *string, int string_length)
199
{
200
 
201
    /* Given a directory and a component of a path, look up the component in
202
     * the directory, find the inode, open it, and return a pointer to its inode
203
     * slot.  If it can't be done, return NIL_INODE.
204
     */
205
 
206
    register inode_t *rip;
207
    int r;
208
    ino_t numb;
209
 
210
    /* If 'string' is empty, yield same inode straight away. */
211
    if (string[0] == '\0')
212
        return get_inode((int) dirp->i_num);
213
 
214
    /* Check for NIL_INODE. */
215
    if (dirp == NIL_INODE)
216
        return NIL_INODE;
217
 
218
    /* If 'string' is not present in the directory, signal error. */
219
    if (dirp->i_sp->s_extend) {
220
        r = search_dir_ex(dirp, string, &numb, LOOK_UP);
221
    }
222
    else {
223
        r = search_dir(dirp, string, &numb, LOOK_UP);
224
    }
225
    if (r != OK) {
226
        err_code = r;
227
        return NIL_INODE;
228
    }
229
 
230
    /* Don't go beyond the current root directory */
231
    if (dirp == fp->fp_rootdir && strcmp(string, "..") == 0)
232
        return(get_inode((int) dirp->i_num));
233
 
234
    /* The component has been found in the directory.  Get inode. */
235
    if ( (rip = get_inode((int) numb)) == NIL_INODE)
236
        return NIL_INODE;
237
 
238
    return rip;          /* return pointer to inode's component */
239
}
240
 
241
int search_dir(register inode_t *ldir_ptr, char string[NAME_MAX], ino_t *numb, int flag)
242
{
243
 
244
    /* This function searches the directory whose inode is pointed to by 'ldip':
245
     * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb';
246
     * if (flag == IS_EMPTY) return OK if only . and .. in dir else ENOTEMPTY;
247
     */
248
 
249
    register direct_t *dp;
250
    register block_t *bp;
251
    int r, match;
252
    offset_t pos;
253
    unsigned old_slots;
254
    block_num_t b;
255
 
256
    /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
2404 konopa 257
    if ((ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) {
2376 konopa 258
        return FS_ENOTDIR;
2404 konopa 259
    }
2376 konopa 260
    r = OK;
261
 
262
    /* Step through the directory one block at a time. */
263
    old_slots = (unsigned)(ldir_ptr->i_size/DIR_ENTRY_SIZE);  
264
    match = 0;                    /* set when a string match occurs */
265
 
266
    for (pos = 0; pos < ldir_ptr->i_size; pos += BLOCK_SIZE) {
267
        b = read_map(ldir_ptr, pos);    /* get block number */
268
 
269
        /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
270
        bp = get_block(b);     /* get a dir block */
271
 
272
        /* Search a directory block. */
273
        for (dp = &bp->b.b__dir[0]; dp < &bp->b.b__dir[NR_DIR_ENTRIES]; dp++) {
274
 
275
                    /* Match occurs if string found. */
276
                    if (dp->d_ino != 0) {
277
                if (flag == IS_EMPTY) {
278
                    /* If this test succeeds, dir is not empty. */
279
                    if (strcmp(dp->d_name, "." ) != 0 &&
280
                        strcmp(dp->d_name, "..") != 0)
281
                        match = 1;
282
                            }
283
                else {
2404 konopa 284
                    if (fs_strncmp(dp->d_name, string, NAME_MAX) == 0) {
2376 konopa 285
                        match = 1;
2404 konopa 286
                    }
2376 konopa 287
                }
288
            }
289
 
290
            if (match) {
291
                /* LOOK_UP or DELETE found what it wanted. */
292
                r = OK;
293
                if (flag == IS_EMPTY) {
294
                    r = FS_ENOTEMPTY;
295
                }
296
                else {
297
                    *numb =  (int) dp->d_ino;
298
                }
299
                return r;
300
            }
301
        }  
302
    }
303
 
304
    /* The whole directory has now been searched. */
305
    return(flag == IS_EMPTY ? OK : FS_ENOENT); 
306
}
307
 
308
int search_dir_ex(register inode_t *ldir_ptr, char string[NAME_MAX_EX], ino_t *numb, int flag)
309
{
310
 
311
    /* Same as above, but for extened directory etries - 30 chars in name of file. */
312
 
313
    register directex_t *dp;
314
    register block_t *bp;
315
    int r, match;
316
    offset_t pos;
317
    unsigned old_slots;
318
    block_num_t b;
319
 
320
    /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
2404 konopa 321
    if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) { 
2376 konopa 322
        return FS_ENOTDIR;
2404 konopa 323
    }
2376 konopa 324
    r = OK;
325
 
326
    /* Step through the directory one block at a time. */
327
    old_slots = (unsigned)(ldir_ptr->i_size/DIR_ENTRY_SIZE_EX);
328
    match = 0;                    /* set when a string match occurs */
329
 
330
    for (pos = 0; pos < ldir_ptr->i_size; pos += BLOCK_SIZE) {
331
        b = read_map(ldir_ptr, pos);    /* get block number */
332
 
333
        /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
334
        bp = get_block(b);     /* get a dir block */
335
 
336
        /* Search a directory block. */
337
        for (dp = &bp->b.b__direx[0]; dp < &bp->b.b__direx[NR_DIR_ENTRIES_EX]; dp++) {
338
 
339
            /* Match occurs if string found. */
340
            if (dp->d_ino != 0) {
341
                if (flag == IS_EMPTY) {
342
                /* If this test succeeds, dir is not empty. */
343
                    if (strcmp(dp->d_name, "." ) != 0 &&
344
                        strcmp(dp->d_name, "..") != 0) match = 1;
345
                            }
346
                else {
2404 konopa 347
                    if (fs_strncmp(dp->d_name, string, NAME_MAX_EX) == 0) {
2376 konopa 348
                        match = 1;
2404 konopa 349
                    }
350
 
2376 konopa 351
                }
352
            }
353
 
354
            if (match) {
355
                /* LOOK_UP or DELETE found what it wanted. */
356
                r = OK;
357
                if (flag == IS_EMPTY) {
358
                    r = FS_ENOTEMPTY;
359
                }
360
                else {
361
                    *numb =  (int)dp->d_ino;
362
                }
363
                return r;
364
            }
365
        }        
366
    }
367
 
368
    /* The whole directory has now been searched. */
369
    return(flag == IS_EMPTY ? OK : FS_ENOENT); 
370
}
371