Subversion Repositories HelenOS

Rev

Blame | Last modification | View Log | Download | RSS feed

  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. */
  4.  
  5. /* Methods:
  6.  * eat_path:        the 'main' routine of the path-to-inode conversion mechanism
  7.  * last_dir:        find the final directory on a given path
  8.  * advance:     parse one component of a path name
  9.  * search_dir:      search a directory for a string and return its inode number
  10.  * search_dir_ex:   used for extended versions
  11.  */
  12.  
  13.  
  14. #include <string.h>
  15. #include "fs.h"
  16. #include "block.h"
  17. #include "file.h"
  18. #include "fproc.h"
  19. #include "inode.h"
  20. #include "super.h"
  21.  
  22.  
  23. static char *get_name(char *old_name, char *string, int string_length);
  24.  
  25. inode_t *eat_path(char *path)
  26. {
  27.    
  28.     /* Parse the path 'path' and put its inode in the inode table. If not possible,
  29.      * return NIL_INODE as function value and an error code in 'err_code'.
  30.      */
  31.    
  32.     register inode_t *ldip, *rip;
  33.     super_block_t *sp;
  34.     int name_len;
  35.     char string[name_len];        /* hold 1 path component name here */
  36.      
  37.     name_len = NAME_MAX;
  38.     if ((sp = get_super()) == NIL_SUPER)
  39.         return NIL_INODE;
  40.  
  41.     if (sp->s_extend) {
  42.         name_len = NAME_MAX_EX;
  43.     }
  44.  
  45.     /* First open the path down to the final directory. */
  46.     if ( (ldip = last_dir(path, string, name_len)) == NIL_INODE)
  47.         return NIL_INODE;      /* we couldn't open final directory */
  48.  
  49.     /* The path consisting only of "/" is a special case, check for it. */
  50.     if (string[0] == '\0')
  51.         return ldip;
  52.      
  53.     /* Get final component of the path. */
  54.     rip = advance(ldip, string, name_len);
  55.     put_inode(ldip);
  56.  
  57.     return rip;
  58. }
  59.    
  60. inode_t *last_dir(char *path, char *string, int string_length)
  61. {
  62.    
  63.     /* Given a path, 'path', located in the fs address space, parse it as
  64.      * far as the last directory, fetch the inode for the last directory into
  65.      * the inode table, and return a pointer to the inode.  In
  66.      * addition, return the final component of the path in 'string'.
  67.      * If the last directory can't be opened, return NIL_INODE and
  68.      * the reason for failure in 'err_code'.
  69.      */
  70.    
  71.     register inode_t *rip;
  72.     register char *new_name;
  73.     register inode_t *new_ip;
  74.    
  75.     /* Is the path absolute or relative?  Initialize 'rip' accordingly. */
  76.     rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir);
  77.    
  78.     /* If dir has been removed or path is empty, return FS_ENOENT. */
  79.     if (rip->i_nlinks == 0  ||  *path == '\0') {
  80.         err_code = FS_ENOENT;
  81.         return NIL_INODE;
  82.     }
  83.      
  84.     dup_inode(rip);     /* inode will be returned with put_inode */
  85.    
  86.     /* Scan the path component by component. */
  87.     while (TRUE) {
  88.         /* Extract one component. */
  89.         if ( (new_name = get_name(path, string, string_length)) == (char*) 0) {
  90.             put_inode(rip); /* bad path in user space */
  91.             return NIL_INODE;
  92.             }
  93.         if (*new_name == '\0')
  94.         {
  95.             if ( (rip->i_mode & I_TYPE) == I_DIRECTORY)
  96.                 return rip;    /* normal exit */
  97.             else {
  98.                 /* last file of path prefix is not a directory */
  99.                 put_inode(rip);
  100.                 err_code = FS_ENOTDIR;         
  101.                 return NIL_INODE;
  102.             }
  103.         }
  104.             /* There is more path.  Keep parsing. */
  105.         new_ip = advance(rip, string, string_length);
  106.         put_inode(rip);
  107.  
  108.         if (new_ip == NIL_INODE) {
  109.             return NIL_INODE;
  110.         }
  111.         /* The call to advance() succeeded.  Fetch next component. */
  112.         path = new_name;
  113.         rip = new_ip;
  114.     }
  115. }
  116.    
  117. char *get_name(char *old_name, char *string, int string_length)
  118. {
  119.    
  120.     /* Given a pointer to a path name in fs space, 'old_name', copy the next
  121.      * component to 'string' and pad with zeros.  A pointer to that part of
  122.      * the name as yet unparsed is returned.  Roughly speaking,
  123.      * 'get_name' = 'old_name' - 'string'.
  124.      *
  125.      * This routine follows the standard convention that /usr/ast, /usr//ast,
  126.      * //usr///ast and /usr/ast/ are all equivalent.
  127.      */
  128.    
  129.     register int c;
  130.     register char *np, *rnp;
  131.    
  132.     np = string;                  /* 'np' points to current position */
  133.     rnp = old_name;               /* 'rnp' points to unparsed string */
  134.     while ((c = *rnp) == '/')
  135.         rnp++;     /* skip leading slashes */
  136.    
  137.     /* Copy the unparsed path, 'old_name', to the array, 'string'. */
  138.     while ( rnp < &old_name[PATH_MAX]  &&  c != '/'   &&  c != '\0') {
  139.         if (np < &string[string_length])
  140.             *np++ = c;
  141.            
  142.         c = *++rnp;             /* advance to next character */
  143.     }
  144.    
  145.     /* To make /usr/ast/ equivalent to /usr/ast, skip trailing slashes. */
  146.     while (c == '/' && rnp < &old_name[PATH_MAX])
  147.         c = *++rnp;
  148.      
  149.     /* Padding with zeroes */
  150.     if (np < &string[string_length])
  151.         *np = '\0';       /* Terminate string */
  152.    
  153.     if (rnp >= &old_name[PATH_MAX]) {
  154.         err_code = FS_ENAMETOOLONG;
  155.         return((char *) 0);
  156.     }
  157.  
  158.     return rnp;
  159. }
  160.    
  161. inode_t *advance(inode_t *dirp, char *string, int string_length)
  162. {
  163.    
  164.     /* Given a directory and a component of a path, look up the component in
  165.      * the directory, find the inode, open it, and return a pointer to its inode
  166.      * slot.  If it can't be done, return NIL_INODE.
  167.      */
  168.    
  169.     register inode_t *rip;
  170.     int r;
  171.     ino_t numb;
  172.    
  173.     /* If 'string' is empty, yield same inode straight away. */
  174.     if (string[0] == '\0')
  175.         return get_inode((int) dirp->i_num);
  176.    
  177.     /* Check for NIL_INODE. */
  178.     if (dirp == NIL_INODE)
  179.         return NIL_INODE;
  180.    
  181.     /* If 'string' is not present in the directory, signal error. */
  182.     if (dirp->i_sp->s_extend) {
  183.         r = search_dir_ex(dirp, string, &numb, LOOK_UP);
  184.     }
  185.     else {
  186.         r = search_dir(dirp, string, &numb, LOOK_UP);
  187.     }
  188.     if (r != OK) {
  189.         err_code = r;
  190.         return NIL_INODE;
  191.     }
  192.    
  193.     /* Don't go beyond the current root directory */
  194.     if (dirp == fp->fp_rootdir && strcmp(string, "..") == 0)
  195.         return(get_inode((int) dirp->i_num));
  196.    
  197.     /* The component has been found in the directory.  Get inode. */
  198.     if ( (rip = get_inode((int) numb)) == NIL_INODE)
  199.         return NIL_INODE;
  200.      
  201.     return rip;          /* return pointer to inode's component */
  202. }
  203.    
  204. int search_dir(register inode_t *ldir_ptr, char string[NAME_MAX], ino_t *numb, int flag)
  205. {
  206.    
  207.     /* This function searches the directory whose inode is pointed to by 'ldip':
  208.      * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb';
  209.      * if (flag == IS_EMPTY) return OK if only . and .. in dir else ENOTEMPTY;
  210.      */
  211.  
  212.     register direct_t *dp;
  213.     register block_t *bp;
  214.     int r, match;
  215.     offset_t pos;
  216.     unsigned old_slots;
  217.     block_num_t b;
  218.      
  219.     /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
  220.     if ((ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY)
  221.         return FS_ENOTDIR;
  222.    
  223.     r = OK;
  224.          
  225.     /* Step through the directory one block at a time. */
  226.     old_slots = (unsigned)(ldir_ptr->i_size/DIR_ENTRY_SIZE);  
  227.     match = 0;                    /* set when a string match occurs */
  228.    
  229.     for (pos = 0; pos < ldir_ptr->i_size; pos += BLOCK_SIZE) {
  230.         b = read_map(ldir_ptr, pos);    /* get block number */
  231.    
  232.         /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
  233.         bp = get_block(b);     /* get a dir block */
  234.    
  235.         /* Search a directory block. */
  236.         for (dp = &bp->b.b__dir[0]; dp < &bp->b.b__dir[NR_DIR_ENTRIES]; dp++) {
  237.                    
  238.                     /* Match occurs if string found. */
  239.                     if (dp->d_ino != 0) {
  240.                 if (flag == IS_EMPTY) {
  241.                     /* If this test succeeds, dir is not empty. */
  242.                     if (strcmp(dp->d_name, "." ) != 0 &&
  243.                         strcmp(dp->d_name, "..") != 0)
  244.                         match = 1;
  245.                             }
  246.                 else {
  247.                     if (fs_strncmp(dp->d_name, string, NAME_MAX) == 0)
  248.                         match = 1;
  249.                 }
  250.             }
  251.    
  252.             if (match) {
  253.                 /* LOOK_UP or DELETE found what it wanted. */
  254.                 r = OK;
  255.                 if (flag == IS_EMPTY) {
  256.                     r = FS_ENOTEMPTY;
  257.                 }
  258.                 else {
  259.                     *numb =  (int) dp->d_ino;
  260.                 }
  261.                 return r;
  262.             }
  263.         }  
  264.     }
  265.    
  266.     /* The whole directory has now been searched. */
  267.     return(flag == IS_EMPTY ? OK : FS_ENOENT); 
  268. }
  269.  
  270. int search_dir_ex(register inode_t *ldir_ptr, char string[NAME_MAX_EX], ino_t *numb, int flag)
  271. {
  272.    
  273.     /* Same as above, but for extened directory etries - 30 chars in name of file. */
  274.  
  275.     register directex_t *dp;
  276.     register block_t *bp;
  277.     int r, match;
  278.     offset_t pos;
  279.     unsigned old_slots;
  280.     block_num_t b;
  281.      
  282.     /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
  283.     if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY)
  284.         return FS_ENOTDIR;
  285.    
  286.     r = OK;
  287.              
  288.     /* Step through the directory one block at a time. */
  289.     old_slots = (unsigned)(ldir_ptr->i_size/DIR_ENTRY_SIZE_EX);
  290.     match = 0;                    /* set when a string match occurs */
  291.    
  292.     for (pos = 0; pos < ldir_ptr->i_size; pos += BLOCK_SIZE) {
  293.         b = read_map(ldir_ptr, pos);    /* get block number */
  294.    
  295.         /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
  296.         bp = get_block(b);     /* get a dir block */
  297.    
  298.         /* Search a directory block. */
  299.         for (dp = &bp->b.b__direx[0]; dp < &bp->b.b__direx[NR_DIR_ENTRIES_EX]; dp++) {
  300.    
  301.             /* Match occurs if string found. */
  302.             if (dp->d_ino != 0) {
  303.                 if (flag == IS_EMPTY) {
  304.                 /* If this test succeeds, dir is not empty. */
  305.                     if (strcmp(dp->d_name, "." ) != 0 &&
  306.                         strcmp(dp->d_name, "..") != 0) match = 1;
  307.                             }
  308.                 else {
  309.                     if (fs_strncmp(dp->d_name, string, NAME_MAX_EX) == 0)
  310.                         match = 1;
  311.                 }
  312.             }
  313.    
  314.             if (match) {
  315.                 /* LOOK_UP or DELETE found what it wanted. */
  316.                 r = OK;
  317.                 if (flag == IS_EMPTY) {
  318.                     r = FS_ENOTEMPTY;
  319.                 }
  320.                 else {
  321.                     *numb =  (int)dp->d_ino;
  322.                 }
  323.                 return r;
  324.             }
  325.         }        
  326.     }
  327.    
  328.     /* The whole directory has now been searched. */
  329.     return(flag == IS_EMPTY ? OK : FS_ENOENT); 
  330. }
  331.    
  332.