Subversion Repositories HelenOS

Rev

Rev 2404 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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:
  8.  
  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.  */
  35.  
  36. /** @addtogroup FileSystemImpl
  37. * @{
  38. */
  39.  
  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. */
  45.  
  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.  
  58. /**
  59.  * The 'main' routine of the path-to-inode conversion mechanism
  60.  */
  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.     }
  80.    
  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 */
  84.    
  85.    
  86.     /* The path consisting only of "/" is a special case, check for it. */
  87.     if (string[0] == '\0')
  88.         return ldip;
  89.    
  90.     /* Get final component of the path. */
  91.     rip = advance(ldip, string, name_len);
  92.     put_inode(ldip);
  93.    
  94.     return rip;
  95. }
  96.  
  97. /**
  98.  * Find the final directory on a given path
  99.  */
  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 */
  131.  
  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.    
  158. /**
  159.  * Parse one component of a path name
  160.  */
  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. }
  204.  
  205. /**
  206.  *
  207.  */
  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.    
  251. /**
  252.  * Search a directory for a string and return its inode number
  253.  */
  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. */
  270.     if ((ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) {
  271.         return FS_ENOTDIR;
  272.     }
  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 {
  297.                     if (fs_strncmp(dp->d_name, string, NAME_MAX) == 0) {
  298.                         match = 1;
  299.                     }
  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.  
  321. /**
  322.  * Used for extended versions
  323.  */
  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. */
  337.     if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) { 
  338.         return FS_ENOTDIR;
  339.     }
  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 {
  363.                     if (fs_strncmp(dp->d_name, string, NAME_MAX_EX) == 0) {
  364.                         match = 1;
  365.                     }
  366.                    
  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.    
  388.  
  389. /**
  390.  * }
  391.  */
  392.  
  393.