]> Zhao Yanbai Git Server - minix.git/commitdiff
Giovanni's symlink patches.
authorBen Gras <ben@minix3.org>
Tue, 1 Nov 2005 13:19:40 +0000 (13:19 +0000)
committerBen Gras <ben@minix3.org>
Tue, 1 Nov 2005 13:19:40 +0000 (13:19 +0000)
servers/fs/open.c
servers/fs/path.c
servers/fs/proto.h
servers/fs/stadir.c
servers/fs/table.c

index 9052046a499210ae70f26aab937ba7c126168b37..87ccd8c0cf8f51934862ff782c3cdd095427b540 100644 (file)
@@ -2,16 +2,18 @@
  * seeking on files.
  *
  * The entry points into this file are
- *   do_creat: perform the CREAT system call
- *   do_open:  perform the OPEN system call
- *   do_mknod: perform the MKNOD system call
- *   do_mkdir: perform the MKDIR system call
- *   do_close: perform the CLOSE system call
- *   do_lseek:  perform the LSEEK system call
+ *   do_creat:         perform the CREAT system call
+ *   do_open:          perform the OPEN system call
+ *   do_mknod:         perform the MKNOD system call
+ *   do_mkdir:         perform the MKDIR system call
+ *   do_close:         perform the CLOSE system call
+ *   do_lseek:         perform the LSEEK system call
+ *   do_symlink:       perform the LSEEK system call
  */
 
 #include "fs.h"
 #include <sys/stat.h>
+#include <string.h>
 #include <fcntl.h>
 #include <minix/callnr.h>
 #include <minix/com.h>
@@ -205,14 +207,37 @@ PRIVATE struct inode *new_node(char *path, mode_t bits,   zone_t z0)
  */
 
   register struct inode *rlast_dir_ptr, *rip;
+  struct inode *old_workdir_ip;
   register int r;
+  int slink_found, loops = 0;
   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);
+  old_workdir_ip = fp->fp_workdir; /* Save the current working directory */
+
+  do {
+       slink_found = FALSE;
+       /* See if the path can be opened down to the last directory. */
+       if ((rlast_dir_ptr = last_dir(path, string)) == NIL_INODE) {
+               fp->fp_workdir = old_workdir_ip; /* Restore cwd */
+               return(NIL_INODE);
+       }
+
+       /* The final directory is accessible. Get final component of the path. */
+       rip = advance(rlast_dir_ptr, string);
+       if (rip != NIL_INODE && (rip->i_mode & I_TYPE) == I_SYMBOLIC_LINK) {
+               if (++loops > MAX_SYM_LOOPS) {
+                       fp->fp_workdir = old_workdir_ip;
+                       put_inode(rlast_dir_ptr);
+                       err_code = ELOOP;
+                       return(NIL_INODE);
+               }
+               rip = slink_traverse(rip, path, string, rlast_dir_ptr);
+               slink_found = TRUE;
+               put_inode(rlast_dir_ptr);
+               fp->fp_workdir = rip; /* cd to symlink target dir */
+       }
+  } while (slink_found);
 
-  /* The final directory is accessible. Get final component of the path. */
-  rip = advance(rlast_dir_ptr, string);
   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) {
@@ -471,3 +496,67 @@ PUBLIC int do_lseek()
   m_out.reply_l1 = pos;                /* insert the long into the output message */
   return(OK);
 }
+
+
+/*===========================================================================*
+ *                            do_symlink                                   *
+ *===========================================================================*/
+PUBLIC int do_symlink()
+{
+/* perform the symlink(name1, name2) system call */
+
+  register struct inode *ip;
+  register int r;
+  char string[NAME_MAX];
+  register struct inode *new_ip;
+  struct buf *bp;
+
+  if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK)
+       return(err_code);
+
+  /* Does the final directory of 'name2' exist? */
+  if ( (ip = last_dir(user_path, string)) == NIL_INODE)
+       return(err_code);
+
+  r = OK;
+  /* if name2 exists in full set 'r' to error */
+  if ( (new_ip = advance(ip, string)) == NIL_INODE) {
+       r = err_code;
+       if (r == ENOENT) r = OK;
+  } else {
+       put_inode(new_ip);
+       r = EEXIST;
+  }
+  put_inode(ip);
+  if (r != OK) return(r);
+
+  if ( (new_ip = new_node(user_path, (mode_t)(I_SYMBOLIC_LINK | 0777),
+                      (off_t)0)) == NIL_INODE) {
+       put_inode(new_ip);
+       return(err_code);
+  }
+
+  truncate(new_ip);
+  wipe_inode(new_ip);
+  new_ip->i_size = m_in.name1_length;
+
+  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) {
+       put_inode(new_ip);
+       return(err_code);
+  }
+  /* allocate disk block for name1 */
+  if ( (bp = new_block(new_ip, 0)) == NIL_BUF) {
+       put_inode(new_ip);
+       return(err_code);
+  }
+  /* stuff pathname into diskblock and set immediate writing */
+  memcpy(bp->b_data, user_path, m_in.name1_length);
+  bp->b_dirt = DIRTY;
+  put_block(bp, INODE_BLOCK);
+  new_ip->i_dirt = DIRTY;
+  rw_inode(new_ip, WRITING);
+  put_inode(new_ip);
+  return(err_code);
+}
+
+/** open.c **/
index c954a64ad8db22e60b45af9ff3950478f23a7146..03f8e092d93cf13bdbbf7414ff46bf3bf0e9e64d 100644 (file)
@@ -32,20 +32,44 @@ char *path;                 /* the path name to be parsed */
  * 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);
+  register struct inode *ldip, *rip, *old_workdir_ip;
+  char string[NAME_MAX];      /* hold 1 path component name here */
+  int slink_found;
+  int loops = 0;             /* count symlink traversals */
+
+  old_workdir_ip = fp->fp_workdir; /* save the current working directory */
+
+  do {
+      slink_found = FALSE;
+
+      /* First open the path down to the final directory. */
+      if ( (ldip = last_dir(path, string)) == NIL_INODE) {
+              fp->fp_workdir = old_workdir_ip;
+              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);
+
+      if (rip != NIL_INODE && (rip->i_mode & I_TYPE) == I_SYMBOLIC_LINK) {
+              if (++loops > MAX_SYM_LOOPS) {
+                      put_inode(rip);
+                      put_inode(ldip);
+                      fp->fp_workdir = old_workdir_ip;
+                      err_code = ELOOP;
+                      return(NIL_INODE);
+              }
+              rip = slink_traverse(rip, path, string, ldip);
+              slink_found = TRUE;
+              fp->fp_workdir = rip; /* cd to link's starting dir */
+              put_inode(rip);
+      }
+      put_inode(ldip);
+  } while (slink_found);
+  fp->fp_workdir = old_workdir_ip;
   return(rip);
 }
 
@@ -67,6 +91,7 @@ char string[NAME_MAX];                /* the final component is returned here */
   register struct inode *rip;
   register char *new_name;
   register struct inode *new_ip;
+  int loops = 0;       /* count symlink traversals */
 
   /* Is the path absolute or relative?  Initialize 'rip' accordingly. */
   rip = (*path == '/' ? fp->fp_rootdir : fp->fp_workdir);
@@ -99,11 +124,24 @@ 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);
-
+       if (new_ip == NIL_INODE) {
+               put_inode(rip);
+               return(NIL_INODE);
+       }
+       
        /* The call to advance() succeeded.  Fetch next component. */
-       path = new_name;
+       if ((new_ip->i_mode & I_TYPE) == I_SYMBOLIC_LINK) {
+               if (++loops > MAX_SYM_LOOPS) {
+                       err_code = ELOOP;
+                       put_inode(rip);
+                       put_inode(new_ip);
+                       return(NIL_INODE);
+               }
+               new_ip = slink_traverse(new_ip, path, string, rip);
+       } else
+               path = new_name;
+       
+       put_inode(rip);         /* rip either obsolete or irrelevant */
        rip = new_ip;
   }
 }
@@ -376,3 +414,43 @@ int flag;                   /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
   }
   return(OK);
 }
+
+
+/*===========================================================================*
+ *                            slink_traverse                               *
+ *===========================================================================*/
+PUBLIC struct inode *slink_traverse(rip, path, string, ldip)
+register struct inode *rip;
+char *path;
+char *string;
+register struct inode *ldip;
+{
+
+  /* copy path out of symlink's disk block -- return inode pointer to
+   * the directory that the path infers */
+
+  register char *p, *q;
+  char temp[PATH_MAX];
+  struct buf *bp;
+  block_t b;
+
+  b = read_map(rip, 0);
+  bp = get_block(rip->i_dev, b, NORMAL); /* get the pathname block */
+  memcpy(temp, bp->b_data, rip->i_size);
+  temp[rip->i_size] = '\0';
+  put_block(bp, NORMAL);
+
+  q = strstr(path, string);
+  if ((p = strchr(q, '/')) != NULL && (q + strlen(string)) == p) {
+       strcat(temp, p);
+  }
+  strcpy(path, temp);
+
+  put_inode(rip);
+  rip = (*path == '/') ?  fp->fp_rootdir : ldip;
+
+  dup_inode(rip);
+  return (rip);
+}
+
+/** path.c **/
index 705f4692cb236980e9109c4d77c8d89988c695ca..0971df558cef0b54feb805582d77a2decba84bf5 100644 (file)
@@ -110,6 +110,7 @@ _PROTOTYPE( int do_lseek, (void)                                    );
 _PROTOTYPE( int do_mknod, (void)                                       );
 _PROTOTYPE( int do_mkdir, (void)                                       );
 _PROTOTYPE( int do_open, (void)                                                );
+_PROTOTYPE( int do_symlink, (void)                                     );
 
 /* path.c */
 _PROTOTYPE( struct inode *advance,(struct inode *dirp, char string[NAME_MAX]));
@@ -117,6 +118,8 @@ _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 *slink_traverse, (struct inode *rip, char *path,
+                       char string[NAME_MAX], struct inode *ldip)      );
 
 /* pipe.c */
 _PROTOTYPE( int do_pipe, (void)                                                );
@@ -153,6 +156,8 @@ _PROTOTYPE( int do_chdir, (void)                                    );
 _PROTOTYPE( int do_fchdir, (void)                                      );
 _PROTOTYPE( int do_chroot, (void)                                      );
 _PROTOTYPE( int do_fstat, (void)                                       );
+_PROTOTYPE( int do_lstat, (void)                                       );
+_PROTOTYPE( int do_rdlink, (void)                                      );
 _PROTOTYPE( int do_stat, (void)                                                );
 _PROTOTYPE( int do_fstatfs, (void)                                     );
 
index 4f8029c38bd7fc071285a6dd8a0b0f5a6590fbd7..003f8701682ed15d1e67716f7b390ebcb3a58376 100644 (file)
@@ -6,10 +6,13 @@
  *   do_chroot:        perform the CHROOT system call
  *   do_stat:  perform the STAT system call
  *   do_fstat: perform the FSTAT system call
+ *   do_rdlink:        perform the RDLINK system call
+ *   do_lstat: perform the LSTAT system call
  *   do_fstatfs: perform the FSTATFS system call
  */
 
 #include "fs.h"
+#include "buf.h"
 #include <sys/stat.h>
 #include <sys/statfs.h>
 #include <minix/com.h>
@@ -216,6 +219,75 @@ char *user_addr;           /* user space address where stat buf goes */
   return(r);
 }
 
+/*===========================================================================*
+ *                            do_rdlink                                    *
+ *===========================================================================*/
+PUBLIC int do_rdlink()
+{
+/* Perform the readlink(name, buf, bufsiz) system call. */
+
+  register struct inode *ldip, *rip;
+  register int r;
+  char string[NAME_MAX];
+  register char *p;
+  vir_bytes v;
+  block_t b;
+  struct buf *bp;
+
+  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
+  if ( (ldip = last_dir(user_path, string)) == NIL_INODE) return(err_code);
+
+  /* Get final component of the path. */
+  rip = advance(ldip, string);
+  put_inode(ldip);
+
+  if (rip == NIL_INODE) return(err_code);
+
+  if ((rip->i_mode & I_TYPE) == I_SYMBOLIC_LINK) {
+#define bufsiz m1_i2
+       int len = MIN(rip->i_size, m_in.bufsiz);
+       b = read_map(rip, 0);
+       bp = get_block(rip->i_dev, b, NORMAL);
+       /* Copy the name to user space. */
+       r = sys_datacopy(FS_PROC_NR, (phys_bytes) bp->b_data,
+               who, (phys_bytes) m_in.name2, (phys_bytes) len);
+       put_block(bp, NORMAL);
+       r = rip->i_size;
+  } else 
+       r = EINVAL;
+  put_inode(rip);             /* release the inode */
+  return(r);
+}
+
+/*===========================================================================*
+ *                             do_lstat                                     *
+ *===========================================================================*/
+PUBLIC int do_lstat()
+{
+/* Perform the lstat(name, buf) system call. */
+
+  register struct inode *ldip, *rip;
+  register int r;
+  char string[NAME_MAX];
+  register char *p;
+
+  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
+
+  /* Can't use eat_path() since it will traverse the link */
+  if ( (ldip = last_dir(user_path, string)) == NIL_INODE) return(err_code);
+
+  /* Get final component of the path. */
+  rip = advance(ldip, string);
+  put_inode(ldip);
+
+  if (rip == NIL_INODE) return(err_code);
+
+  r = stat_inode(rip, NIL_FILP, m_in.name2); /* Work just like stat */
+
+  put_inode(rip);             /* Release the inode */
+  return(r);
+}
+
 /*===========================================================================*
  *                             do_fstatfs                                   *
  *===========================================================================*/
@@ -237,3 +309,4 @@ PUBLIC int do_fstatfs()
    return(r);
 }
 
+/** stadir.c **/
index 45ebd1c70bcb46b177715c1da49834e2bb5122f4..41dda3c7aecb12244a56fa751bd1e789ada4a204 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 = unused  */
+       do_symlink,     /* 45 = symlink */
        do_set,         /* 46 = setgid  */
        no_sys,         /* 47 = getgid  */
        no_sys,         /* 48 = (signal)*/
-       no_sys,         /* 49 = unused  */
-       no_sys,         /* 50 = unused  */
+       do_rdlink,      /* 49 = readlink*/
+       do_lstat,       /* 50 = lstat   */
        no_sys,         /* 51 = (acct)  */
        no_sys,         /* 52 = (phys)  */
        no_sys,         /* 53 = (lock)  */