[comp.os.minix] Correction to symlink code

rommel@Informatik.TU-Muenchen.DE (Kai-Uwe Rommel) (06/23/91)

I have fixed a serious bug in the symlink package posted here recently.
I know there is a better implementation but it is not (yet) available
and I want at least to fix the code posted here in case anyone uses it. 
The two diffs below replace two files in the original posting.

Kai Uwe Rommel

/* Kai Uwe Rommel, Munich ----- rommel@lan.informatik.tu-muenchen.dbp.de */

DOS ... is still a real mode only non-reentrant interrupt
handler, and always will be.                -Russell Williams

- inode.c.cdif
*** inode.orig	Sun May 26 19:57:02 1991
--- inode.c	Sun May 26 19:56:40 1991
***************
*** 78,83 ****
--- 78,84 ----

    if (rip == NIL_INODE) return;	/* checking here is easier than in caller */
    if (--rip->i_count == 0) {	/* i_count == 0 means no one is using it now */
+ 	if ((rip->i_mode & I_TYPE) != I_SLINK) { /* don't truncate symbolic links */
  	    if ((rip->i_nlinks & BYTE) == 0) {
  		/* i_nlinks == 0 means free the inode. */
  		truncate(rip);	/* return all the disk blocks */
***************
*** 86,91 ****
--- 87,93 ----
  	    }
  	    else if (rip->i_pipe == I_PIPE) truncate(rip);
  	    rip->i_pipe = NO_PIPE;  /* should always be cleared */
+ 	}

  	if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
    }

- stadir.c.cdif
*** stadir.orig	Sun May 26 19:57:06 1991
--- stadir.c	Sun May 26 19:57:40 1991
***************
*** 6,11 ****
--- 6,13 ----
   *   do_chroot:	perform the CHROOT system call
   *   do_stat:	perform the STAT system call
   *   do_fstat:	perform the FSTAT system call
+  *   do_lstat:	perform the LSTAT system call
+  *   do_rdlink: perform the RDLNK system call
   */

  #include "fs.h"
***************
*** 114,119 ****
--- 116,189 ----
    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(name1, 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, name2); /* work just like stat */
+
+   put_inode(rip);		/* release the inode */
+   return(r);
+ }
+
+
+ /*===========================================================================*
+  *				do_rdlink				     *
+  *===========================================================================*/
+ PUBLIC int do_rdlink()
+ {
+ /* Perform the readlink(name, buf) system call. */
+
+   register struct inode *ldip, *rip;
+   register int r;
+   char string[NAME_MAX];
+   register char *p;
+   vir_bytes v;
+
+   if (fetch_name(name1, 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_SLINK) {
+       /* copy last 30 bytes from inode into buf */
+ 	p = (char *) rip;
+ 	p += 2;
+
+ 	v = (vir_bytes) name2;
+
+ 	/* Copy the name pointed to into user space. */
+ 	r = rw_user(D, who, v, (vir_bytes) 30, p, TO_USER);
+   } else {
+ 	r = ENOTSLNK;
+   }
+   put_inode(rip);		/* release the inode */
+   return(r);
+ }

  /*===========================================================================*
   *				do_fstat				     *

/* Kai Uwe Rommel, Munich ----- rommel@lan.informatik.tu-muenchen.dbp.de */

DOS ... is still a real mode only non-reentrant interrupt
handler, and always will be.                -Russell Williams