#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 */
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);
{
/* 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;
/* 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 {
/* 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) {
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 */
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 */
}
/*===========================================================================*
- * 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. */
#include "fs.h"
#include <sys/stat.h>
#include <fcntl.h>
+#include <string.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include "buf.h"
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 *
{
/* 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;
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
/* 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
/*===========================================================================*
* 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);
}
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 */
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);
}
/* 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);
}
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);
}
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 */
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);
+}
+
* 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"
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);
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. */
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 {
}
/* 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);
+
+ 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);
+}
- /* The call to advance() succeeded. Fetch next component. */
- path = new_name;
- rip = new_ip;
+/*===========================================================================*
+ * 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);
}
/*===========================================================================*
/*===========================================================================*
* 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
* 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)); }
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;
}
}
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;
_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) );
_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) );
_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));
* 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"
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);
+}
+
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;
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) */
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];