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:
Ben Gras 2005-12-20 14:23:44 +00:00
parent ffe192724e
commit 6a911b5284
10 changed files with 358 additions and 102 deletions

View file

@ -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 */

View 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);

View 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. */

View 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);
}

View 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,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;

View 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));

View 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);
}

View 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;

View 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) */

View 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];