Subversion Repositories HelenOS

Rev

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

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