Merge of minix-vmd symlink code.
. 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().)
This commit is contained in:
parent
ffe192724e
commit
6a911b5284
10 changed files with 358 additions and 102 deletions
|
@ -48,6 +48,18 @@
|
|||
#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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,16 +82,130 @@ 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);
|
||||
|
||||
/* The call to advance() succeeded. Fetch next component. */
|
||||
path = new_name;
|
||||
rip = new_ip;
|
||||
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);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* get_name *
|
||||
*===========================================================================*/
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in a new issue