Giovanni's symlink patches.
This commit is contained in:
parent
a3752a3a51
commit
fa76dcb8c1
5 changed files with 273 additions and 28 deletions
|
@ -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 **/
|
||||
|
|
|
@ -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 */
|
||||
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 */
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
old_workdir_ip = fp->fp_workdir; /* save the current working directory */
|
||||
|
||||
/* The path consisting only of "/" is a special case, check for it. */
|
||||
if (string[0] == '\0') return(ldip);
|
||||
do {
|
||||
slink_found = FALSE;
|
||||
|
||||
/* Get final component of the path. */
|
||||
rip = advance(ldip, string);
|
||||
put_inode(ldip);
|
||||
/* 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 **/
|
||||
|
|
|
@ -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) );
|
||||
|
||||
|
|
|
@ -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 **/
|
||||
|
|
|
@ -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) */
|
||||
|
|
Loading…
Reference in a new issue