]> Zhao Yanbai Git Server - minix.git/commitdiff
Merge of minix-vmd symlink code.
authorBen Gras <ben@minix3.org>
Tue, 20 Dec 2005 14:23:44 +0000 (14:23 +0000)
committerBen Gras <ben@minix3.org>
Tue, 20 Dec 2005 14:23:44 +0000 (14:23 +0000)
. new_node() now returns inode of parent dir as argument that
  has to be put_node()d again by the caller of new_node().
  it can also return the name of the last component as last_dir()
  did.
. advance() takes a pointer to a pointer of an inode as the
  parent now. This parent can change, in which case the old
  one is put_node()d and a new one is put there.
. eat_path() replaced by more flexible parse_path()
. last_dir() replaced by call to parse_path().
. do_slink(), do_readlink(), do_lstat() and slink_traverse() added.

Also added some truncate()/ftruncate()-introduction related changes.
(e.g. renamed truncate() to truncate_inode().)

servers/fs/const.h
servers/fs/inode.c
servers/fs/link.c
servers/fs/open.c
servers/fs/path.c
servers/fs/proto.h
servers/fs/stadir.c
servers/fs/super.c
servers/fs/table.c
servers/pm/table.c

index 245360591e270a46b845c25053d741ae71bcbd4f..71d8bad45022f5079cc66ebf6cde7c8022f3cc33 100644 (file)
 #define DELETE             2 /* tells search_dir to delete entry */
 #define IS_EMPTY           3 /* tells search_dir to ret. OK or ENOTEMPTY */  
 
+#define PATH_TRANSPARENT 000   /* parse_path stops at final object */
+#define PATH_PENULTIMATE 001   /* parse_path stops at last but one name */
+#define PATH_OPAQUE      002   /* parse_path stops at final name */
+#define PATH_NONSYMBOLIC 004   /* parse_path scans final name if symbolic */
+#define PATH_STRIPDOT    010   /* parse_path strips /. from path */
+#define EAT_PATH         PATH_TRANSPARENT
+#define EAT_PATH_OPAQUE  PATH_OPAQUE 
+#define LAST_DIR         PATH_PENULTIMATE
+#define LAST_DIR_NOTDOT  PATH_PENULTIMATE | PATH_STRIPDOT
+#define LAST_DIR_EATSYM  PATH_NONSYMBOLIC
+#define SYMLOOP                16
+
 #define CLEAN              0   /* disk and memory copies identical */
 #define DIRTY              1   /* disk and memory copies differ */
 #define ATIME            002   /* set if atime field needs updating */
index a79005fcaf3be9abf4a62f9506cfb8aa13289317..a977796666ab71a455a5bca49c4642a6907024f5 100644 (file)
@@ -86,12 +86,12 @@ register struct inode *rip; /* pointer to inode to be released */
   if (--rip->i_count == 0) {   /* i_count == 0 means no one is using it now */
        if (rip->i_nlinks == 0) {
                /* i_nlinks == 0 means free the inode. */
-               truncate(rip);  /* return all the disk blocks */
+               truncate_inode(rip, 0, 0);      /* return all the disk blocks */
                rip->i_mode = I_NOT_ALLOC;      /* clear I_TYPE field */
                rip->i_dirt = DIRTY;
                free_inode(rip->i_dev, rip->i_num);
        } else {
-               if (rip->i_pipe == I_PIPE) truncate(rip);
+               if (rip->i_pipe == I_PIPE) truncate_inode(rip, 0, 0);
        }
        rip->i_pipe = NO_PIPE;  /* should always be cleared */
        if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
index 498a8095dc616dbaefeebbc76576c94afc31ebb9..bf18021c088b28833daa73102227efdbc7940d90 100644 (file)
@@ -36,7 +36,7 @@ PUBLIC int do_link()
 {
 /* Perform the link(name1, name2) system call. */
 
-  register struct inode *ip, *rip;
+  struct inode *ip, *rip;
   register int r;
   char string[NAME_MAX];
   struct inode *new_ip;
@@ -69,7 +69,7 @@ PUBLIC int do_link()
 
   /* If 'name2' exists in full (even if no space) set 'r' to error. */
   if (r == OK) {
-       if ( (new_ip = advance(ip, string)) == NIL_INODE) {
+       if ( (new_ip = advance(&ip, string)) == NIL_INODE) {
                r = err_code;
                if (r == ENOENT) r = OK;
        } else {
@@ -121,7 +121,7 @@ PUBLIC int do_unlink()
 
   /* The last directory exists.  Does the file also exist? */
   r = OK;
-  if ( (rip = advance(rldirp, string)) == NIL_INODE) r = err_code;
+  if ( (rip = advance(&rldirp, string)) == NIL_INODE) r = err_code;
 
   /* If error, return inode. */
   if (r != OK) {
@@ -178,12 +178,12 @@ PUBLIC int do_rename()
   if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
   if ( (old_dirp = last_dir(user_path, old_name))==NIL_INODE) return(err_code);
 
-  if ( (old_ip = advance(old_dirp, old_name)) == NIL_INODE) r = err_code;
+  if ( (old_ip = advance(&old_dirp, old_name)) == NIL_INODE) r = err_code;
 
   /* See if 'name2' (new name) exists.  Get dir and file inodes. */
   if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code;
   if ( (new_dirp = last_dir(user_path, new_name)) == NIL_INODE) r = err_code;
-  new_ip = advance(new_dirp, new_name);        /* not required to exist */
+  new_ip = advance(&new_dirp, new_name);       /* not required to exist */
 
   if (old_ip != NIL_INODE)
        odir = ((old_ip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE iff dir */
@@ -200,7 +200,7 @@ PUBLIC int do_rename()
                                r = EINVAL;
                                break;
                        }
-                       next_new_superdirp = advance(new_superdirp, dot2);
+                       next_new_superdirp = advance(&new_superdirp, dot2);
                        put_inode(new_superdirp);
                        if (next_new_superdirp == new_superdirp)
                                break;  /* back at system root directory */
@@ -312,10 +312,12 @@ PUBLIC int do_rename()
 }
 
 /*===========================================================================*
- *                             truncate                                     *
+ *                             truncate_inode                               *
  *===========================================================================*/
-PUBLIC void truncate(rip)
+PUBLIC void truncate_inode(rip, newsize, resetzones)
 register struct inode *rip;    /* pointer to inode to be truncated */
+off_t newsize;                 /* inode must become this size (ignored) */
+int resetzones;                        /* zone references cleared on disk (ignored) */
 {
 /* Remove all the zones from the inode 'rip' and mark it dirty. */
 
index 9052046a499210ae70f26aab937ba7c126168b37..0f64d3705f20a3f09ca6a060929ee2f0e56895e0 100644 (file)
@@ -13,6 +13,7 @@
 #include "fs.h"
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <string.h>
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include "buf.h"
@@ -29,8 +30,8 @@ PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
 
 FORWARD _PROTOTYPE( int common_open, (int oflags, mode_t omode)                );
 FORWARD _PROTOTYPE( int pipe_open, (struct inode *rip,mode_t bits,int oflags));
-FORWARD _PROTOTYPE( struct inode *new_node, (char *path, mode_t bits,
-                                                       zone_t z0)      );
+FORWARD _PROTOTYPE( struct inode *new_node, (struct inode **ldirp, 
+       char *path, mode_t bits, zone_t z0, int opaque, char *string));
 
 /*===========================================================================*
  *                             do_creat                                     *
@@ -75,7 +76,7 @@ PRIVATE int common_open(register int oflags, mode_t omode)
 {
 /* Common code from do_creat and do_open. */
 
-  register struct inode *rip;
+  struct inode *rip, *ldirp;
   int r, b, exist = TRUE;
   dev_t dev;
   mode_t bits;
@@ -92,8 +93,9 @@ PRIVATE int common_open(register int oflags, mode_t omode)
   if (oflags & O_CREAT) {
        /* Create a new inode by calling new_node(). */
         omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask);
-       rip = new_node(user_path, omode, NO_ZONE);
+       rip = new_node(&ldirp, user_path, omode, NO_ZONE, oflags&O_EXCL, NULL);
        r = err_code;
+        put_inode(ldirp);
        if (r == OK) exist = FALSE;      /* we just created the file */
        else if (r != EEXIST) return(r); /* other error */
        else exist = !(oflags & O_EXCL); /* file exists, if the O_EXCL 
@@ -119,7 +121,7 @@ PRIVATE int common_open(register int oflags, mode_t omode)
                        /* Truncate regular file if O_TRUNC. */
                        if (oflags & O_TRUNC) {
                                if ((r = forbidden(rip, W_BIT)) !=OK) break;
-                               truncate(rip);
+                               truncate_inode(rip, 0, 0);
                                wipe_inode(rip);
                                /* Send the inode from the inode cache to the
                                 * block cache, so it gets written on the next
@@ -195,29 +197,43 @@ PRIVATE int common_open(register int oflags, mode_t omode)
 /*===========================================================================*
  *                             new_node                                     *
  *===========================================================================*/
-PRIVATE struct inode *new_node(char *path, mode_t bits,        zone_t z0)
+PRIVATE struct inode *new_node(struct inode **ldirp,
+       char *path, mode_t bits, zone_t z0, int opaque, char *parsed)
 {
 /* New_node() is called by common_open(), do_mknod(), and do_mkdir().  
  * In all cases it allocates a new inode, makes a directory entry for it on 
  * the path 'path', and initializes it.  It returns a pointer to the inode if 
  * it can do this; otherwise it returns NIL_INODE.  It always sets 'err_code'
  * to an appropriate value (OK or an error code).
+ * 
+ * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
+ * has to hold at least NAME_MAX bytes.
  */
 
-  register struct inode *rlast_dir_ptr, *rip;
+  register struct inode *rip;
   register int r;
   char string[NAME_MAX];
 
-  /* See if the path can be opened down to the last directory. */
-  if ((rlast_dir_ptr = last_dir(path, string)) == NIL_INODE) return(NIL_INODE);
+  *ldirp = parse_path(path, string, opaque ? LAST_DIR : LAST_DIR_EATSYM)
+;       
+  if (*ldirp == NIL_INODE) return(NIL_INODE);
 
   /* The final directory is accessible. Get final component of the path. */
-  rip = advance(rlast_dir_ptr, string);
+  rip = advance(ldirp, string);
+
+  if (S_ISDIR(bits) && 
+      (*ldirp)->i_nlinks >= ((*ldirp)->i_sp->s_version == V1 ?
+      CHAR_MAX : SHRT_MAX)) {
+        /* New entry is a directory, alas we can't give it a ".." */
+        put_inode(rip);
+        err_code = EMLINK;
+        return(NIL_INODE);
+  }
+
   if ( rip == NIL_INODE && err_code == ENOENT) {
        /* Last path component does not exist.  Make new directory entry. */
-       if ( (rip = alloc_inode(rlast_dir_ptr->i_dev, bits)) == NIL_INODE) {
+       if ( (rip = alloc_inode((*ldirp)->i_dev, bits)) == NIL_INODE) {
                /* Can't creat new inode: out of inodes. */
-               put_inode(rlast_dir_ptr);
                return(NIL_INODE);
        }
 
@@ -230,8 +246,7 @@ PRIVATE struct inode *new_node(char *path, mode_t bits,     zone_t z0)
        rw_inode(rip, WRITING);         /* force inode to disk now */
 
        /* New inode acquired.  Try to make directory entry. */
-       if ((r = search_dir(rlast_dir_ptr, string, &rip->i_num,ENTER)) != OK) {
-               put_inode(rlast_dir_ptr);
+       if ((r = search_dir(*ldirp, string, &rip->i_num,ENTER)) != OK) {
                rip->i_nlinks--;        /* pity, have to free disk inode */
                rip->i_dirt = DIRTY;    /* dirty inodes are written out */
                put_inode(rip); /* this call frees the inode */
@@ -247,8 +262,12 @@ PRIVATE struct inode *new_node(char *path, mode_t bits,    zone_t z0)
                r = err_code;
   }
 
-  /* Return the directory inode and exit. */
-  put_inode(rlast_dir_ptr);
+  if(parsed) { /* Give the caller the parsed string if requested. */
+       strncpy(parsed, string, NAME_MAX-1);
+       parsed[NAME_MAX-1] = '\0';
+  }
+
+  /* The caller has to return the directory inode (*ldirp).  */
   err_code = r;
   return(rip);
 }
@@ -288,15 +307,16 @@ PUBLIC int do_mknod()
 /* Perform the mknod(name, mode, addr) system call. */
 
   register mode_t bits, mode_bits;
-  struct inode *ip;
+  struct inode *ip, *ldirp;
 
   /* Only the super_user may make nodes other than fifos. */
   mode_bits = (mode_t) m_in.mk_mode;           /* mode of the inode */
   if (!super_user && ((mode_bits & I_TYPE) != I_NAMED_PIPE)) return(EPERM);
   if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
   bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask);
-  ip = new_node(user_path, bits, (zone_t) m_in.mk_z0);
+  ip = new_node(&ldirp, user_path, bits, (zone_t) m_in.mk_z0, TRUE, NULL);
   put_inode(ip);
+  put_inode(ldirp);
   return(err_code);
 }
 
@@ -311,24 +331,16 @@ PUBLIC int do_mkdir()
   ino_t dot, dotdot;           /* inode numbers for . and .. */
   mode_t bits;                 /* mode bits for the new inode */
   char string[NAME_MAX];       /* last component of the new dir's path name */
-  register struct inode *rip, *ldirp;
+  struct inode *rip, *ldirp;
 
-  /* Check to see if it is possible to make another link in the parent dir. */
   if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
-  ldirp = last_dir(user_path, string); /* pointer to new dir's parent */
-  if (ldirp == NIL_INODE) return(err_code);
-  if (ldirp->i_nlinks >= (ldirp->i_sp->s_version == V1 ?
-        CHAR_MAX : SHRT_MAX)) {
-       put_inode(ldirp);       /* return parent */
-       return(EMLINK);
-  }
 
   /* Next make the inode. If that fails, return error code. */
   bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask);
-  rip = new_node(user_path, bits, (zone_t) 0);
+  rip = new_node(&ldirp, user_path, bits, (zone_t) 0, TRUE, string);
   if (rip == NIL_INODE || err_code == EEXIST) {
        put_inode(rip);         /* can't make dir: it already exists */
-       put_inode(ldirp);       /* return parent too */
+       put_inode(ldirp);
        return(err_code);
   }
 
@@ -349,8 +361,11 @@ PUBLIC int do_mkdir()
        ldirp->i_nlinks++;      /* this accounts for .. */
        ldirp->i_dirt = DIRTY;  /* mark parent's inode as dirty */
   } else {
-       /* It was not possible to enter . or .. probably disk was full. */
-       (void) search_dir(ldirp, string, (ino_t *) 0, DELETE);
+       /* It was not possible to enter . or .. probably disk was full -
+        * links counts haven't been touched.
+        */
+       if(search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK)
+               panic(__FILE__, "Dir disappeared ", rip->i_num);
        rip->i_nlinks--;        /* undo the increment done in new_node() */
   }
   rip->i_dirt = DIRTY;         /* either way, i_nlinks has changed */
@@ -471,3 +486,54 @@ PUBLIC int do_lseek()
   m_out.reply_l1 = pos;                /* insert the long into the output message */
   return(OK);
 }
+
+/*===========================================================================*
+ *                             do_slink                                     *
+ *===========================================================================*/
+PUBLIC int do_slink()
+{
+/* Perform the symlink(name1, name2) system call. */
+
+  register int r;              /* error code */
+  char string[NAME_MAX];       /* last component of the new dir's path name */
+  struct inode *sip;           /* inode containing symbolic link */
+  struct buf *bp;              /* disk buffer for link */
+  struct inode *ldirp;         /* directory containing link */
+
+  if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK)
+       return(err_code);
+
+  if (m_in.name1_length <= 1 || m_in.name1_length > _MIN_BLOCK_SIZE+1)
+       return(ENAMETOOLONG);
+
+  /* Create the inode for the symlink. */
+  sip = new_node(&ldirp, user_path, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
+                 (zone_t) 0, TRUE, string);
+
+  /* Allocate a disk block for the contents of the symlink.
+   * Copy contents of symlink (the name pointed to) into first disk block.
+   */
+  if ((r = err_code) == OK) {
+       r = (bp = new_block(sip, (off_t) 0)) == NIL_BUF
+           ? err_code
+           : ( sip->i_size = m_in.name1_length-1,
+               sys_vircopy(who, D, (vir_bytes) m_in.name1,
+                       SELF, D, (vir_bytes) bp->b_data,
+                      (vir_bytes) m_in.name1_length-1));
+  
+       put_block(bp, DIRECTORY_BLOCK);         /* put_block() accepts NIL_BUF. */
+  
+       if (r != OK) {
+               sip->i_nlinks = 0;
+               if (search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK)
+                       panic(__FILE__, "Symbolic link vanished", NO_NUM);
+       } 
+  }
+
+  /* put_inode() accepts NIL_INODE as a noop, so the below are safe. */
+  put_inode(sip);
+  put_inode(ldirp);
+
+  return(r);
+}
+
index c954a64ad8db22e60b45af9ff3950478f23a7146..514f627f25701d47ffa6e87a11e153f8f6ef51dd 100644 (file)
@@ -6,11 +6,13 @@
  *   last_dir:  find the final directory on a given path
  *   advance:   parse one component of a path name
  *   search_dir: search a directory for a string and return its inode number
+ *
  */
 
 #include "fs.h"
 #include <string.h>
 #include <minix/callnr.h>
+#include <sys/stat.h>
 #include "buf.h"
 #include "file.h"
 #include "fproc.h"
@@ -22,51 +24,30 @@ PUBLIC char dot2[3] = ".."; /* permissions for . and ..                 */
 
 FORWARD _PROTOTYPE( char *get_name, (char *old_name, char string [NAME_MAX]) );
 
-/*===========================================================================*
- *                             eat_path                                     *
- *===========================================================================*/
-PUBLIC struct inode *eat_path(path)
-char *path;                    /* the path name to be parsed */
-{
-/* Parse the path 'path' and put its inode in the inode table. If not possible,
- * return NIL_INODE as function value and an error code in 'err_code'.
- */
-
-  register struct inode *ldip, *rip;
-  char string[NAME_MAX];       /* hold 1 path component name here */
-
-  /* First open the path down to the final directory. */
-  if ( (ldip = last_dir(path, string)) == NIL_INODE) {
-       return(NIL_INODE);      /* we couldn't open final directory */
-       }
-
-  /* The path consisting only of "/" is a special case, check for it. */
-  if (string[0] == '\0') return(ldip);
-
-  /* Get final component of the path. */
-  rip = advance(ldip, string);
-  put_inode(ldip);
-  return(rip);
-}
+FORWARD _PROTOTYPE( struct inode *ltraverse, (struct inode *rip,
+                       char *path, char *suffix, struct inode *ldip)   );
 
 /*===========================================================================*
- *                             last_dir                                     *
+ *                             parse_path                                   *
  *===========================================================================*/
-PUBLIC struct inode *last_dir(path, string)
-char *path;                    /* the path name to be parsed */
-char string[NAME_MAX];         /* the final component is returned here */
+PUBLIC struct inode *parse_path(path, string, action)
+char *path;                    /* the path name to be parsed */
+char string[NAME_MAX];         /* the final component is returned here */
+int action;                    /* action on last part of path */
 {
-/* Given a path, 'path', located in the fs address space, parse it as
- * far as the last directory, fetch the inode for the last directory into
- * the inode table, and return a pointer to the inode.  In
- * addition, return the final component of the path in 'string'.
- * If the last directory can't be opened, return NIL_INODE and
- * the reason for failure in 'err_code'.
+/* This is the actual code for last_dir and eat_path. Return the inode of
+ * the last directory and the name of object within that directory, or the
+ * inode of the last object (an empty name will be returned). Names are
+ * returned in string. If string is null the name is discarded. The action
+ * code determines how "last" is defined. If an error occurs, NIL_INODE
+ * will be returned with an error code in err_code.
  */
 
-  register struct inode *rip;
-  register char *new_name;
-  register struct inode *new_ip;
+  struct inode *rip, *dir_ip;
+  char *new_name;
+  struct inode *new_ip;
+  int symloop;
+  char lstring[NAME_MAX];
 
   /* Is the path absolute or relative?  Initialize 'rip' accordingly. */
   rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir);
@@ -79,6 +60,9 @@ char string[NAME_MAX];                /* the final component is returned here */
 
   dup_inode(rip);              /* inode will be returned with put_inode */
 
+  symloop = 0;                 /* symbolic link traversal count */
+  if (string == (char *) 0) string = lstring;
+
   /* Scan the path component by component. */
   while (TRUE) {
        /* Extract one component. */
@@ -86,7 +70,7 @@ char string[NAME_MAX];                /* the final component is returned here */
                put_inode(rip); /* bad path in user space */
                return(NIL_INODE);
        }
-       if (*new_name == '\0') {
+       if (*new_name == '\0' && (action & PATH_PENULTIMATE)) {
                if ( (rip->i_mode & I_TYPE) == I_DIRECTORY) {
                        return(rip);    /* normal exit */
                } else {
@@ -98,14 +82,128 @@ char string[NAME_MAX];             /* the final component is returned here */
         }
 
        /* There is more path.  Keep parsing. */
-       new_ip = advance(rip, string);
-       put_inode(rip);         /* rip either obsolete or irrelevant */
-       if (new_ip == NIL_INODE) return(NIL_INODE);
+       dir_ip = rip;
+       rip = advance(&dir_ip, string);
+
+       if (rip == NIL_INODE) {
+               if (*new_name == '\0' && (action & PATH_NONSYMBOLIC) != 0)
+                       return(dir_ip);
+               else {
+                       put_inode(dir_ip);
+                       return(NIL_INODE);
+               }
+       }
+
+       /* The call to advance() succeeded.  Fetch next component. */
+       if (S_ISLNK(rip->i_mode)) {
+               if (*new_name != '\0' || (action & PATH_OPAQUE) == 0) {
+                       if (*new_name != '\0') new_name--;
+                       rip = ltraverse(rip, path, new_name, dir_ip);
+                       put_inode(dir_ip);
+                       if (++symloop > SYMLOOP) {
+                               err_code = ELOOP;
+                               put_inode(rip);
+                               rip = NIL_INODE;
+                       }
+                       if (rip == NIL_INODE) return(NIL_INODE);
+                       continue;
+               }
+       } else if (*new_name != '\0') {
+               put_inode(dir_ip);
+               path = new_name;
+               continue;
+       }
+      
+       /* Either last name reached or symbolic link is opaque */
+       if ((action & PATH_NONSYMBOLIC) != 0) {
+               put_inode(rip);
+               return(dir_ip);
+       } else {
+               put_inode(dir_ip);
+               return(rip);
+       }
+  }
+}
+
+/*===========================================================================*
+ *                             eat_path                                     *
+ *===========================================================================*/
+PUBLIC struct inode *eat_path(path)
+char *path;                    /* the path name to be parsed */
+{
+ /* Parse the path 'path' and put its inode in the inode table. If not possible,
+  * return NIL_INODE as function value and an error code in 'err_code'.
+  */
+  
+  return parse_path(path, (char *) 0, EAT_PATH);
+}
 
-       /* The call to advance() succeeded.  Fetch next component. */
-       path = new_name;
-       rip = new_ip;
+/*===========================================================================*
+ *                             last_dir                                      *
+ *===========================================================================*/
+PUBLIC struct inode *last_dir(path, string)
+char *path;                    /* the path name to be parsed */
+char string[NAME_MAX];         /* the final component is returned here */
+{
+/* Given a path, 'path', located in the fs address space, parse it as
+ * far as the last directory, fetch the inode for the last directory into
+ * the inode table, and return a pointer to the inode.  In
+ * addition, return the final component of the path in 'string'.
+ * If the last directory can't be opened, return NIL_INODE and
+ * the reason for failure in 'err_code'.
+ */
+  
+  return parse_path(path, string, LAST_DIR);
+}
+
+/*===========================================================================*
+ *                             ltraverse                                    *
+ *===========================================================================*/
+PRIVATE struct inode *ltraverse(rip, path, suffix, ldip)
+register struct inode *rip;    /* symbolic link */
+char *path;                    /* path containing link */
+char *suffix;                  /* suffix following link within path */
+register struct inode *ldip;   /* directory containing link */
+{
+/* Traverse a symbolic link. Copy the link text from the inode and insert
+ * the text into the path. Return the inode of base directory and the
+ * ammended path. The symbolic link inode is always freed. The inode
+ * returned is already duplicated. NIL_INODE is returned on error.
+ */
+  
+  block_t b;                   /* block containing link text */
+  struct inode *bip;           /* inode of base directory */
+  struct buf *bp;              /* buffer containing link text */
+  size_t sl;                   /* length of link */
+  size_t tl;                   /* length of suffix */
+  char *sp;                    /* start of link text */
+  char *ep;                    /* end of conditional segment */
+
+  bip = NIL_INODE;
+  bp  = NIL_BUF;
+
+  if ((b = read_map(rip, (off_t) 0)) != NO_BLOCK) {
+       bp = get_block(rip->i_dev, b, NORMAL);
+       sl = rip->i_size;
+       sp = bp->b_data;
+
+       /* Insert symbolic text into path name. */
+       tl = strlen(suffix);
+       if (sl > 0 && sl + tl <= PATH_MAX-1) {
+               memmove(path+sl, suffix, tl);
+               memmove(path, sp, sl);
+               path[sl+tl] = 0;
+               dup_inode(bip = path[0] == '/' ? fp->fp_rootdir : ldip);
+       }
+  }
+  
+  put_block(bp, DIRECTORY_BLOCK);
+  put_inode(rip);
+  if (bip == NIL_INODE)
+  {
+       err_code = ENOENT;
   }
+  return (bip);
 }
 
 /*===========================================================================*
@@ -152,8 +250,8 @@ char string[NAME_MAX];              /* component extracted from 'old_name' */
 /*===========================================================================*
  *                             advance                                      *
  *===========================================================================*/
-PUBLIC struct inode *advance(dirp, string)
-struct inode *dirp;            /* inode for directory to be searched */
+PUBLIC struct inode *advance(pdirp, string)
+struct inode **pdirp;          /* inode for directory to be searched */
 char string[NAME_MAX];         /* component name to look for */
 {
 /* Given a directory and a component of a path, look up the component in
@@ -161,13 +259,14 @@ char string[NAME_MAX];            /* component name to look for */
  * slot.  If it can't be done, return NIL_INODE.
  */
 
-  register struct inode *rip;
-  struct inode *rip2;
+  register struct inode *rip, *dirp;
   register struct super_block *sp;
   int r, inumb;
   dev_t mnt_dev;
   ino_t numb;
 
+  dirp = *pdirp;
+
   /* If 'string' is empty, yield same inode straight away. */
   if (string[0] == '\0') { return(get_inode(dirp->i_dev, (int) dirp->i_num)); }
 
@@ -189,20 +288,30 @@ char string[NAME_MAX];            /* component name to look for */
        return(NIL_INODE);
        }
 
+  /* The following test is for "mountpoint/.." where mountpoint is a
+   * mountpoint. ".." will refer to the root of the mounted filesystem,
+   * but has to become a reference to the parent of the 'mountpoint'
+   * directory.
+   *
+   * This case is recognized by the looked up name pointing to a
+   * root inode, and the directory in which it is held being a
+   * root inode, _and_ the name[1] being '.'. (This is a test for '..'
+   * and excludes '.'.)
+   */
   if (rip->i_num == ROOT_INODE)
        if (dirp->i_num == ROOT_INODE) {
            if (string[1] == '.') {
                for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++){
                        if (sp->s_dev == rip->i_dev) {
                                /* Release the root inode.  Replace by the
-                                * inode mounted on.
+                                * inode mounted on. Update parent.
                                 */
                                put_inode(rip);
+                               put_inode(dirp);
                                mnt_dev = sp->s_imount->i_dev;
                                inumb = (int) sp->s_imount->i_num;
-                               rip2 = get_inode(mnt_dev, inumb);
-                               rip = advance(rip2, string);
-                               put_inode(rip2);
+                               dirp = *pdirp = get_inode(mnt_dev, inumb);
+                               rip = advance(pdirp, string);
                                break;
                        }
                }
@@ -259,7 +368,9 @@ int flag;                    /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
   int extended = 0;
 
   /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
-  if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) return(ENOTDIR);
+  if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY)  {
+       return(ENOTDIR);
+   }
 
   r = OK;
 
index 705f4692cb236980e9109c4d77c8d89988c695ca..e3561fc09331ab3f853102cc7a808ccee4cac422 100644 (file)
@@ -74,7 +74,7 @@ _PROTOTYPE( void wipe_inode, (struct inode *rip)                      );
 _PROTOTYPE( int do_link, (void)                                                );
 _PROTOTYPE( int do_unlink, (void)                                      );
 _PROTOTYPE( int do_rename, (void)                                      );
-_PROTOTYPE( void truncate, (struct inode *rip)                         );
+_PROTOTYPE( void truncate_inode, (struct inode *rip, off_t len, int cz)        );
 
 /* lock.c */
 _PROTOTYPE( int lock_op, (struct filp *f, int req)                     );
@@ -110,13 +110,16 @@ _PROTOTYPE( int do_lseek, (void)                                  );
 _PROTOTYPE( int do_mknod, (void)                                       );
 _PROTOTYPE( int do_mkdir, (void)                                       );
 _PROTOTYPE( int do_open, (void)                                                );
+_PROTOTYPE( int do_slink, (void)                                       );
 
 /* path.c */
-_PROTOTYPE( struct inode *advance,(struct inode *dirp, char string[NAME_MAX]));
+_PROTOTYPE( struct inode *advance,(struct inode **dirp, char string[NAME_MAX]));
 _PROTOTYPE( int search_dir, (struct inode *ldir_ptr,
                        char string [NAME_MAX], ino_t *numb, int flag)  );
 _PROTOTYPE( struct inode *eat_path, (char *path)                       );
 _PROTOTYPE( struct inode *last_dir, (char *path, char string [NAME_MAX]));
+_PROTOTYPE( struct inode *parse_path, (char *path, char string[NAME_MAX], 
+                                                       int action)     );
 
 /* pipe.c */
 _PROTOTYPE( int do_pipe, (void)                                                );
@@ -155,6 +158,8 @@ _PROTOTYPE( int do_chroot, (void)                                   );
 _PROTOTYPE( int do_fstat, (void)                                       );
 _PROTOTYPE( int do_stat, (void)                                                );
 _PROTOTYPE( int do_fstatfs, (void)                                     );
+_PROTOTYPE( int do_rdlink, (void)                                      );
+_PROTOTYPE( int do_lstat, (void)                                       );
 
 /* super.c */
 _PROTOTYPE( bit_t alloc_bit, (struct super_block *sp, int map, bit_t origin));
index 4f8029c38bd7fc071285a6dd8a0b0f5a6590fbd7..1e23f837faadd3ff85f285cc7034bfba2efb26f0 100644 (file)
@@ -7,12 +7,16 @@
  *   do_stat:  perform the STAT system call
  *   do_fstat: perform the FSTAT system call
  *   do_fstatfs: perform the FSTATFS system call
+ *   do_lstat:  perform the LSTAT system call
+ *   do_rdlink: perform the RDLNK system call
  */
 
 #include "fs.h"
 #include <sys/stat.h>
 #include <sys/statfs.h>
 #include <minix/com.h>
+#include <string.h>
+#include "buf.h"
 #include "file.h"
 #include "fproc.h"
 #include "inode.h"
@@ -237,3 +241,55 @@ PUBLIC int do_fstatfs()
    return(r);
 }
 
+/*===========================================================================*
+ *                             do_lstat                                     *
+ *===========================================================================*/
+PUBLIC int do_lstat()
+{
+/* Perform the lstat(name, buf) system call. */
+
+  register int r;              /* return value */
+  register struct inode *rip;  /* target inode */
+
+  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
+  if ((rip = parse_path(user_path, (char *) 0, EAT_PATH_OPAQUE)) == NIL_INODE)
+       return(err_code);
+  r = stat_inode(rip, NIL_FILP, m_in.name2);
+  put_inode(rip);
+  return(r);
+}
+
+/*===========================================================================*
+ *                             do_rdlink                                    *
+ *===========================================================================*/
+PUBLIC int do_rdlink()
+{
+/* Perform the readlink(name, buf) system call. */
+
+  register int r;              /* return value */
+  block_t b;                   /* block containing link text */
+  struct buf *bp;              /* buffer containing link text */
+  register struct inode *rip;  /* target inode */
+
+  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
+  if ((rip = parse_path(user_path, (char *) 0, EAT_PATH_OPAQUE)) == NIL_INODE)
+       return(err_code);
+
+  r = EACCES;
+  if (S_ISLNK(rip->i_mode) && (b = read_map(rip, (off_t) 0)) != NO_BLOCK) {
+       if (m_in.name2_length <= 0) r = EINVAL;
+       else if (m_in.name2_length < rip->i_size) r = ERANGE;
+       else {
+               bp = get_block(rip->i_dev, b, NORMAL);
+               r = sys_vircopy(SELF, D, (vir_bytes) bp->b_data,
+               who, D, (vir_bytes) m_in.name2, (vir_bytes) rip->i_size);
+
+               if (r == OK) r = rip->i_size;
+               put_block(bp, DIRECTORY_BLOCK);
+       }
+  }
+
+  put_inode(rip);
+  return(r);
+}
+
index 0d295580218b833ca06f2b39f9456b66ef6e753f..4f1279fc2b4bcceaefb1acdb83f8e8dd88025ff5 100644 (file)
@@ -130,7 +130,7 @@ bit_t bit_returned;         /* number of bit to insert into the map */
   k = conv2(sp->s_native, (int) bp->b_bitmap[word]);
   if (!(k & mask)) {
        panic(__FILE__,map == IMAP ? "tried to free unused inode" :
-             "tried to free unused block", NO_NUM);
+             "tried to free unused block", bit_returned);
   }
 
   k &= ~mask;
index 052b7e34f8dc9b3e900e2b57f24e99f32f64d245..59f0c1de6b93bd6ce89238fcc5c1848e1f4ee217 100644 (file)
@@ -60,12 +60,12 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
        do_pipe,        /* 42 = pipe    */
        no_sys,         /* 43 = times   */
        no_sys,         /* 44 = (prof)  */
-       no_sys,         /* 45 = symlink */
+       do_slink,       /* 45 = symlink */
        do_set,         /* 46 = setgid  */
        no_sys,         /* 47 = getgid  */
        no_sys,         /* 48 = (signal)*/
-       no_sys,         /* 49 = readlink*/
-       no_sys,         /* 50 = lstat   */
+       do_rdlink,      /* 49 = readlink*/
+       do_lstat,       /* 50 = lstat   */
        no_sys,         /* 51 = (acct)  */
        no_sys,         /* 52 = (phys)  */
        no_sys,         /* 53 = (lock)  */
index 53e9630ebc5e416efc2768ec79758e605a8aa20d..954b45bc2936fe2970b98a760ad634f47f34fd4d 100644 (file)
@@ -109,6 +109,10 @@ _PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = {
        do_time,        /* 90 = gettimeofday */
        do_getset,      /* 91 = seteuid */
        do_getset       /* 92 = setegid */
+#if 0
+       no_sys,         /* 93 = truncate */
+       no_sys,         /* 94 = ftruncate */
+#endif
 };
 /* This should not fail with "array size is negative": */
 extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];