Subversion Repositories HelenOS

Rev

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