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 |