new libunwind, updated to netbsd b1f513eedd
[minix3.git] / servers / iso9660fs / path.c
blob73c55a2fb16d156bb6a174dcca10b8158de079db
1 #include "inc.h"
2 #include <string.h>
3 #include <minix/com.h>
4 #include <minix/vfsif.h>
6 #include "buf.h"
8 static char *get_name(char *name, char string[NAME_MAX+1]);
9 static int parse_path(ino_t dir_ino, ino_t root_ino, int flags, struct
10 dir_record **res_inop, size_t *offsetp);
13 /*===========================================================================*
14 * fs_lookup *
15 *===========================================================================*/
16 int fs_lookup() {
17 cp_grant_id_t grant;
18 int r, len, flags;
19 size_t offset;
20 ino_t dir_ino, root_ino;
21 struct dir_record *dir;
23 grant = fs_m_in.m_vfs_fs_lookup.grant_path;
24 len = fs_m_in.m_vfs_fs_lookup.path_len; /* including terminating nul */
25 dir_ino = fs_m_in.m_vfs_fs_lookup.dir_ino;
26 root_ino = fs_m_in.m_vfs_fs_lookup.root_ino;
27 flags = fs_m_in.m_vfs_fs_lookup.flags;
28 caller_uid = fs_m_in.m_vfs_fs_lookup.uid;
29 caller_gid = fs_m_in.m_vfs_fs_lookup.gid;
31 /* Check length. */
32 if(len > sizeof(user_path)) return(E2BIG); /* too big for buffer */
33 if(len < 1) return(EINVAL); /* too small */
35 /* Copy the pathname and set up caller's user and group id */
36 r = sys_safecopyfrom(VFS_PROC_NR, grant, 0, (vir_bytes) user_path,
37 (phys_bytes) len);
38 if (r != OK) {
39 printf("ISOFS %s:%d sys_safecopyfrom failed: %d\n",
40 __FILE__, __LINE__, r);
41 return(r);
44 /* Verify this is a null-terminated path. */
45 if(user_path[len-1] != '\0') return(EINVAL);
47 /* Lookup inode */
48 dir = NULL;
49 offset = 0;
50 r = parse_path(dir_ino, root_ino, flags, &dir, &offset);
52 if (r == ELEAVEMOUNT) {
53 /* Report offset and the error */
54 fs_m_out.m_fs_vfs_lookup.offset = offset;
55 fs_m_out.m_fs_vfs_lookup.symloop = 0;
56 return(r);
59 if (r != OK && r != EENTERMOUNT) return(r);
61 fs_m_out.m_fs_vfs_lookup.inode = ID_DIR_RECORD(dir);
62 fs_m_out.m_fs_vfs_lookup.mode = dir->d_mode;
63 fs_m_out.m_fs_vfs_lookup.file_size = dir->d_file_size;
64 fs_m_out.m_fs_vfs_lookup.symloop = 0;
65 fs_m_out.m_fs_vfs_lookup.uid = SYS_UID; /* root */
66 fs_m_out.m_fs_vfs_lookup.gid = SYS_GID; /* operator */
68 if (r == EENTERMOUNT) {
69 fs_m_out.m_fs_vfs_lookup.offset = offset;
70 release_dir_record(dir);
73 return(r);
76 /* The search dir actually performs the operation of searching for the
77 * compoent ``string" in ldir_ptr. It returns the response and the number of
78 * the inode in numb. */
79 /*===========================================================================*
80 * search_dir *
81 *===========================================================================*/
82 int search_dir(
83 register struct dir_record *ldir_ptr, /* dir record parent */
84 char string[NAME_MAX], /* component to search for */
85 ino_t *numb /* pointer to new dir record */
86 ) {
87 struct dir_record *dir_tmp;
88 register struct buf *bp;
89 int pos;
90 char* comma_pos = NULL;
91 char tmp_string[NAME_MAX];
93 /* This function search a particular element (in string) in a inode and
94 * return its number */
96 /* Initialize the tmp array */
97 memset(tmp_string,'\0',NAME_MAX);
99 if ((ldir_ptr->d_mode & I_TYPE) != I_DIRECTORY) {
100 return(ENOTDIR);
103 if (strcmp(string,".") == 0) {
104 *numb = ID_DIR_RECORD(ldir_ptr);
105 return OK;
108 if (strcmp(string,"..") == 0 && ldir_ptr->loc_extent_l == v_pri.dir_rec_root->loc_extent_l) {
109 *numb = ROOT_INO_NR;
110 /* *numb = ID_DIR_RECORD(ldir_ptr); */
111 return OK;
114 /* Read the dir's content */
115 pos = ldir_ptr->ext_attr_rec_length;
116 bp = get_block(ldir_ptr->loc_extent_l);
118 if (bp == NULL)
119 return EINVAL;
121 while (pos < v_pri.logical_block_size_l) {
122 if ((dir_tmp = get_free_dir_record()) == NULL) {
123 put_block(bp);
124 return EINVAL;
127 if (create_dir_record(dir_tmp,b_data(bp) + pos,
128 ldir_ptr->loc_extent_l*v_pri.logical_block_size_l + pos) == EINVAL)
129 return EINVAL;
131 if (dir_tmp->length == 0) {
132 release_dir_record(dir_tmp);
133 put_block(bp);
134 return EINVAL;
137 memcpy(tmp_string,dir_tmp->file_id,dir_tmp->length_file_id);
138 comma_pos = strchr(tmp_string,';');
139 if (comma_pos != NULL)
140 *comma_pos = 0;
141 else
142 tmp_string[dir_tmp->length_file_id] = 0;
143 if (tmp_string[strlen(tmp_string) - 1] == '.')
144 tmp_string[strlen(tmp_string) - 1] = '\0';
146 if (strcmp(tmp_string,string) == 0 ||
147 (dir_tmp->file_id[0] == 1 && strcmp(string,"..") == 0)) {
149 /* If the element is found or we are searchig for... */
151 if (dir_tmp->loc_extent_l == dir_records->loc_extent_l) {
152 /* In this case the inode is a root because the parent
153 * points to the same location than the inode. */
154 *numb = 1;
155 release_dir_record(dir_tmp);
156 put_block(bp);
157 return OK;
160 if (dir_tmp->ext_attr_rec_length != 0) {
161 dir_tmp->ext_attr = get_free_ext_attr();
162 create_ext_attr(dir_tmp->ext_attr,b_data(bp));
165 *numb = ID_DIR_RECORD(dir_tmp);
166 release_dir_record(dir_tmp);
167 put_block(bp);
169 return OK;
172 pos += dir_tmp->length;
173 release_dir_record(dir_tmp);
176 put_block(bp);
177 return EINVAL;
181 /*===========================================================================*
182 * parse_path *
183 *===========================================================================*/
184 static int parse_path(
185 ino_t dir_ino,
186 ino_t root_ino,
187 int flags,
188 struct dir_record **res_inop,
189 size_t *offsetp
191 int r;
192 char string[NAME_MAX+1];
193 char *cp, *ncp;
194 struct dir_record *start_dir, *old_dir;
196 /* Find starting inode inode according to the request message */
197 if ((start_dir = get_dir_record(dir_ino)) == NULL) {
198 printf("ISOFS: couldn't find starting inode %llu\n", dir_ino);
199 return(ENOENT);
202 cp = user_path;
204 /* Scan the path component by component. */
205 while (TRUE) {
206 if (cp[0] == '\0') {
207 /* Empty path */
208 *res_inop= start_dir;
209 *offsetp += cp-user_path;
211 /* Return EENTERMOUNT if we are at a mount point */
212 if (start_dir->d_mountpoint)
213 return EENTERMOUNT;
215 return OK;
218 if (cp[0] == '/') {
219 /* Special case code. If the remaining path consists of just
220 * slashes, we need to look up '.'
222 while(cp[0] == '/')
223 cp++;
224 if (cp[0] == '\0') {
225 strlcpy(string, ".", NAME_MAX + 1);
226 ncp = cp;
228 else
229 ncp = get_name(cp, string);
230 } else
231 /* Just get the first component */
232 ncp = get_name(cp, string);
234 /* Special code for '..'. A process is not allowed to leave a chrooted
235 * environment. A lookup of '..' at the root of a mounted filesystem
236 * has to return ELEAVEMOUNT.
238 if (strcmp(string, "..") == 0) {
240 /* This condition is not necessary since it will never be the root filesystem */
241 /* if (start_dir == dir_records) { */
242 /* cp = ncp; */
243 /* continue; /\* Just ignore the '..' at a process' */
244 /* * root. */
245 /* *\/ */
246 /* } */
248 if (start_dir == dir_records) {
249 /* Climbing up mountpoint */
250 release_dir_record(start_dir);
251 *res_inop = NULL;
252 *offsetp += cp-user_path;
253 return ELEAVEMOUNT;
255 } else {
256 /* Only check for a mount point if we are not looking for '..'. */
257 if (start_dir->d_mountpoint) {
258 *res_inop= start_dir;
259 *offsetp += cp-user_path;
260 return EENTERMOUNT;
264 /* There is more path. Keep parsing. */
265 old_dir = start_dir;
267 r = advance(old_dir, string, &start_dir);
269 if (r != OK) {
270 release_dir_record(old_dir);
271 return r;
274 release_dir_record(old_dir);
275 cp = ncp;
280 /*===========================================================================*
281 * advance *
282 *===========================================================================*/
283 int advance(dirp, string, resp)
284 struct dir_record *dirp; /* inode for directory to be searched */
285 char string[NAME_MAX]; /* component name to look for */
286 struct dir_record **resp; /* resulting inode */
288 /* Given a directory and a component of a path, look up the component in
289 * the directory, find the inode, open it, and return a pointer to its inode
290 * slot.
293 register struct dir_record *rip = NULL;
294 int r;
295 ino_t numb;
297 /* If 'string' is empty, yield same inode straight away. */
298 if (string[0] == '\0') {
299 return ENOENT;
302 /* Check for NULL. */
303 if (dirp == NULL) {
304 return EINVAL;
307 /* If 'string' is not present in the directory, signal error. */
308 if ( (r = search_dir(dirp, string, &numb)) != OK) {
309 return r;
312 /* The component has been found in the directory. Get inode. */
313 if ( (rip = get_dir_record((int) numb)) == NULL) {
314 return(err_code);
317 *resp= rip;
318 return OK;
322 /*===========================================================================*
323 * get_name *
324 *===========================================================================*/
325 static char *get_name(path_name, string)
326 char *path_name; /* path name to parse */
327 char string[NAME_MAX+1]; /* component extracted from 'old_name' */
329 /* Given a pointer to a path name in fs space, 'path_name', copy the first
330 * component to 'string' (truncated if necessary, always nul terminated).
331 * A pointer to the string after the first component of the name as yet
332 * unparsed is returned. Roughly speaking,
333 * 'get_name' = 'path_name' - 'string'.
335 * This routine follows the standard convention that /usr/ast, /usr//ast,
336 * //usr///ast and /usr/ast/ are all equivalent.
338 size_t len;
339 char *cp, *ep;
341 cp= path_name;
343 /* Skip leading slashes */
344 while (cp[0] == '/')
345 cp++;
347 /* Find the end of the first component */
348 ep= cp;
349 while(ep[0] != '\0' && ep[0] != '/')
350 ep++;
352 len= ep-cp;
354 /* Truncate the amount to be copied if it exceeds NAME_MAX */
355 if (len > NAME_MAX)
356 len= NAME_MAX;
358 /* Special case of the string at cp is empty */
359 if (len == 0)
361 /* Return "." */
362 strlcpy(string, ".", NAME_MAX + 1);
364 else
366 memcpy(string, cp, len);
367 string[len]= '\0';
370 return ep;