Fixed extern declaration from pointer to array
[minix.git] / servers / iso9660fs / path.c
blob8cbf1d70cc1bb318b9983e2365778c94d57c1732
1 #include "inc.h"
2 #include <string.h>
3 #include <minix/com.h>
4 #include <minix/vfsif.h>
6 #include "buf.h"
8 FORWARD _PROTOTYPE( char *get_name, (char *name, char string[NAME_MAX+1]) );
9 FORWARD _PROTOTYPE( int parse_path, (ino_t dir_ino, ino_t root_ino, int flags,
10 struct dir_record **res_inop,
11 size_t *offsetp) );
14 /*===========================================================================*
15 * fs_lookup *
16 *===========================================================================*/
17 PUBLIC int fs_lookup() {
18 cp_grant_id_t grant;
19 int r, r1, len, flags;
20 size_t offset, size;
21 ino_t dir_ino, root_ino;
22 struct dir_record *dir;
24 grant = fs_m_in.REQ_GRANT;
25 size = fs_m_in.REQ_PATH_SIZE; /* Size of the buffer */
26 len = fs_m_in.REQ_PATH_LEN; /* including terminating nul */
27 dir_ino = fs_m_in.REQ_DIR_INO;
28 root_ino = fs_m_in.REQ_ROOT_INO;
29 flags = fs_m_in.REQ_FLAGS;
30 caller_uid = fs_m_in.REQ_UID;
31 caller_gid = fs_m_in.REQ_GID;
33 /* Check length. */
34 if(len > sizeof(user_path)) return(E2BIG); /* too big for buffer */
35 if(len < 1) return(EINVAL); /* too small */
37 /* Copy the pathname and set up caller's user and group id */
38 r = sys_safecopyfrom(FS_PROC_NR, grant, 0, (vir_bytes) user_path,
39 (phys_bytes) len, D);
40 if (r != OK) {
41 printf("ISOFS %s:%d sys_safecopyfrom failed: %d\n",
42 __FILE__, __LINE__, r);
43 return(r);
46 /* Verify this is a null-terminated path. */
47 if(user_path[len-1] != '\0') return(EINVAL);
49 /* Lookup inode */
50 dir = NULL;
51 offset = 0;
52 r = parse_path(dir_ino, root_ino, flags, &dir, &offset);
54 if (r == ELEAVEMOUNT) {
55 /* Report offset and the error */
56 fs_m_out.RES_OFFSET = offset;
57 fs_m_out.RES_SYMLOOP = 0;
58 return(r);
61 if (r != OK && r != EENTERMOUNT) return(r);
63 fs_m_out.RES_INODE_NR = ID_DIR_RECORD(dir);
64 fs_m_out.RES_MODE = dir->d_mode;
65 fs_m_out.RES_FILE_SIZE_LO = dir->d_file_size;
66 fs_m_out.RES_SYMLOOP = 0;
67 fs_m_out.RES_UID = SYS_UID; /* root */
68 fs_m_out.RES_GID = SYS_GID; /* operator */
71 if (r == EENTERMOUNT) {
72 fs_m_out.RES_OFFSET = offset;
73 release_dir_record(dir);
76 return(r);
79 /* The search dir actually performs the operation of searching for the
80 * compoent ``string" in ldir_ptr. It returns the response and the number of
81 * the inode in numb. */
82 /*===========================================================================*
83 * search_dir *
84 *===========================================================================*/
85 PUBLIC int search_dir(ldir_ptr,string,numb)
86 register struct dir_record *ldir_ptr; /* dir record parent */
87 char string[NAME_MAX]; /* component to search for */
88 ino_t *numb; /* pointer to new dir record */
90 struct dir_record *dir_tmp;
91 register struct buf *bp,*bp2;
92 int pos,r,len;
93 char* comma_pos = NULL;
94 char tmp_string[NAME_MAX];
96 /* This function search a particular element (in string) in a inode and
97 * return its number */
99 /* Initialize the tmp array */
100 memset(tmp_string,'\0',NAME_MAX);
102 if ((ldir_ptr->d_mode & I_TYPE) != I_DIRECTORY) {
103 return(ENOTDIR);
106 r = OK;
108 if (strcmp(string,".") == 0) {
109 *numb = ID_DIR_RECORD(ldir_ptr);
110 return OK;
113 if (strcmp(string,"..") == 0 && ldir_ptr->loc_extent_l == v_pri.dir_rec_root->loc_extent_l) {
114 *numb = ROOT_INO_NR;
115 /* *numb = ID_DIR_RECORD(ldir_ptr); */
116 return OK;
119 /* Read the dir's content */
120 pos = ldir_ptr->ext_attr_rec_length;
121 bp = get_block(ldir_ptr->loc_extent_l);
123 if (bp == NIL_BUF)
124 return EINVAL;
126 while (pos < v_pri.logical_block_size_l) {
127 if ((dir_tmp = get_free_dir_record()) == NULL) {
128 put_block(bp);
129 return EINVAL;
132 if (create_dir_record(dir_tmp,bp->b_data + pos,
133 ldir_ptr->loc_extent_l*v_pri.logical_block_size_l + pos) == EINVAL)
134 return EINVAL;
136 if (dir_tmp->length == 0) {
137 release_dir_record(dir_tmp);
138 put_block(bp);
139 return EINVAL;
142 memcpy(tmp_string,dir_tmp->file_id,dir_tmp->length_file_id);
143 comma_pos = strchr(tmp_string,';');
144 if (comma_pos != NULL)
145 *comma_pos = 0;
146 else
147 tmp_string[dir_tmp->length_file_id] = 0;
148 if (tmp_string[strlen(tmp_string) - 1] == '.')
149 tmp_string[strlen(tmp_string) - 1] = '\0';
151 if (strcmp(tmp_string,string) == 0 ||
152 (dir_tmp->file_id[0] == 1 && strcmp(string,"..") == 0)) {
154 /* If the element is found or we are searchig for... */
156 if (dir_tmp->loc_extent_l == dir_records->loc_extent_l) {
157 /* In this case the inode is a root because the parent
158 * points to the same location than the inode. */
159 *numb = 1;
160 release_dir_record(dir_tmp);
161 put_block(bp);
162 return OK;
165 if (dir_tmp->ext_attr_rec_length != 0) {
166 dir_tmp->ext_attr = get_free_ext_attr();
167 create_ext_attr(dir_tmp->ext_attr,bp->b_data);
170 *numb = ID_DIR_RECORD(dir_tmp);
171 release_dir_record(dir_tmp);
172 put_block(bp);
174 return OK;
177 pos += dir_tmp->length;
178 release_dir_record(dir_tmp);
181 put_block(bp);
182 return EINVAL;
186 /*===========================================================================*
187 * parse_path *
188 *===========================================================================*/
189 PRIVATE int parse_path(dir_ino, root_ino, flags, res_inop, offsetp)
190 ino_t dir_ino;
191 ino_t root_ino;
192 int flags;
193 struct dir_record **res_inop;
194 size_t *offsetp;
196 int r;
197 char string[NAME_MAX+1];
198 char *cp, *ncp;
199 struct dir_record *start_dir, *old_dir;
201 /* Find starting inode inode according to the request message */
202 if ((start_dir = get_dir_record(dir_ino)) == NULL) {
203 printf("ISOFS: couldn't find starting inode %d\n", dir_ino);
204 return(ENOENT);
207 cp = user_path;
209 /* Scan the path component by component. */
210 while (TRUE) {
211 if (cp[0] == '\0') {
212 /* Empty path */
213 *res_inop= start_dir;
214 *offsetp += cp-user_path;
216 /* Return EENTERMOUNT if we are at a mount point */
217 if (start_dir->d_mountpoint)
218 return EENTERMOUNT;
220 return OK;
223 if (cp[0] == '/') {
224 /* Special case code. If the remaining path consists of just
225 * slashes, we need to look up '.'
227 while(cp[0] == '/')
228 cp++;
229 if (cp[0] == '\0') {
230 strcpy(string, ".");
231 ncp = cp;
233 else
234 ncp = get_name(cp, string);
235 } else
236 /* Just get the first component */
237 ncp = get_name(cp, string);
239 /* Special code for '..'. A process is not allowed to leave a chrooted
240 * environment. A lookup of '..' at the root of a mounted filesystem
241 * has to return ELEAVEMOUNT.
243 if (strcmp(string, "..") == 0) {
245 /* This condition is not necessary since it will never be the root filesystem */
246 /* if (start_dir == dir_records) { */
247 /* cp = ncp; */
248 /* continue; /\* Just ignore the '..' at a process' */
249 /* * root. */
250 /* *\/ */
251 /* } */
253 if (start_dir == dir_records) {
254 /* Climbing up mountpoint */
255 release_dir_record(start_dir);
256 *res_inop = NULL;
257 *offsetp += cp-user_path;
258 return ELEAVEMOUNT;
260 } else {
261 /* Only check for a mount point if we are not looking for '..'. */
262 if (start_dir->d_mountpoint) {
263 *res_inop= start_dir;
264 *offsetp += cp-user_path;
265 return EENTERMOUNT;
269 /* There is more path. Keep parsing. */
270 old_dir = start_dir;
272 r = advance(old_dir, string, &start_dir);
274 if (r != OK) {
275 release_dir_record(old_dir);
276 return r;
279 release_dir_record(old_dir);
280 cp = ncp;
285 /*===========================================================================*
286 * advance *
287 *===========================================================================*/
288 PUBLIC int advance(dirp, string, resp)
289 struct dir_record *dirp; /* inode for directory to be searched */
290 char string[NAME_MAX]; /* component name to look for */
291 struct dir_record **resp; /* resulting inode */
293 /* Given a directory and a component of a path, look up the component in
294 * the directory, find the inode, open it, and return a pointer to its inode
295 * slot.
298 register struct dir_record *rip = NULL;
299 int r, inumb;
300 dev_t mnt_dev;
301 ino_t numb;
303 /* If 'string' is empty, yield same inode straight away. */
304 if (string[0] == '\0') {
305 return ENOENT;
308 /* Check for NULL. */
309 if (dirp == NULL) {
310 return EINVAL;
313 /* If 'string' is not present in the directory, signal error. */
314 if ( (r = search_dir(dirp, string, &numb)) != OK) {
315 return r;
318 /* The component has been found in the directory. Get inode. */
319 if ( (rip = get_dir_record((int) numb)) == NULL) {
320 return(err_code);
323 *resp= rip;
324 return OK;
328 /*===========================================================================*
329 * get_name *
330 *===========================================================================*/
331 PRIVATE char *get_name(path_name, string)
332 char *path_name; /* path name to parse */
333 char string[NAME_MAX+1]; /* component extracted from 'old_name' */
335 /* Given a pointer to a path name in fs space, 'path_name', copy the first
336 * component to 'string' (truncated if necessary, always nul terminated).
337 * A pointer to the string after the first component of the name as yet
338 * unparsed is returned. Roughly speaking,
339 * 'get_name' = 'path_name' - 'string'.
341 * This routine follows the standard convention that /usr/ast, /usr//ast,
342 * //usr///ast and /usr/ast/ are all equivalent.
344 size_t len;
345 char *cp, *ep;
347 cp= path_name;
349 /* Skip leading slashes */
350 while (cp[0] == '/')
351 cp++;
353 /* Find the end of the first component */
354 ep= cp;
355 while(ep[0] != '\0' && ep[0] != '/')
356 ep++;
358 len= ep-cp;
360 /* Truncate the amount to be copied if it exceeds NAME_MAX */
361 if (len > NAME_MAX)
362 len= NAME_MAX;
364 /* Special case of the string at cp is empty */
365 if (len == 0)
367 /* Return "." */
368 strcpy(string, ".");
370 else
372 memcpy(string, cp, len);
373 string[len]= '\0';
376 return ep;