MFS: use libfsdriver

Change-Id: Ib658c7dea47b81a417755b0554a75288117b431a
This commit is contained in:
David van Moolenbroek 2014-08-24 10:06:03 +00:00
parent ad80a203db
commit ccaeedb267
24 changed files with 464 additions and 1601 deletions

View file

@ -46,6 +46,7 @@
#include <minix/config.h> #include <minix/config.h>
#include <minix/const.h> #include <minix/const.h>
#include <minix/type.h> #include <minix/type.h>
#include <minix/ipc.h>
#include "mfs/const.h" #include "mfs/const.h"
#include "mfs/inode.h" #include "mfs/inode.h"
#include "mfs/type.h" #include "mfs/type.h"

View file

@ -5,8 +5,8 @@ SRCS= cache.c link.c \
stadir.c stats.c table.c time.c utility.c \ stadir.c stats.c table.c time.c utility.c \
write.c inode.c main.c path.c super.c write.c inode.c main.c path.c super.c
DPADD+= ${LIBMINIXFS} ${LIBBDEV} ${LIBSYS} DPADD+= ${LIBMINIXFS} ${LIBFSDRIVER} ${LIBBDEV} ${LIBSYS}
LDADD+= -lminixfs -lbdev -lsys LDADD+= -lminixfs -lfsdriver -lbdev -lsys
CPPFLAGS+= -DDEFAULT_NR_BUFS=1024 CPPFLAGS+= -DDEFAULT_NR_BUFS=1024

View file

@ -18,12 +18,6 @@
#define MFS_NAME_MAX MFS_DIRSIZ #define MFS_NAME_MAX MFS_DIRSIZ
/* The type of sizeof may be (unsigned) long. Use the following macro for
* taking the sizes of small objects so that there are no surprises like
* (small) long constants being passed to routines expecting an int.
*/
#define usizeof(t) ((unsigned) sizeof(t))
/* File system types. */ /* File system types. */
#define SUPER_MAGIC 0x137F /* magic number contained in super-block */ #define SUPER_MAGIC 0x137F /* magic number contained in super-block */
#define SUPER_REV 0x7F13 /* magic # when 68000 disk read on PC or vv */ #define SUPER_REV 0x7F13 /* magic # when 68000 disk read on PC or vv */
@ -35,8 +29,6 @@
#define V3 3 /* version number of V3 file systems */ #define V3 3 /* version number of V3 file systems */
/* Miscellaneous constants */ /* Miscellaneous constants */
#define SU_UID ((uid_t) 0) /* super_user's uid_t */
#define NO_BIT ((bit_t) 0) /* returned by alloc_bit() to signal failure */ #define NO_BIT ((bit_t) 0) /* returned by alloc_bit() to signal failure */
#define LOOK_UP 0 /* tells search_dir to lookup string */ #define LOOK_UP 0 /* tells search_dir to lookup string */
@ -47,39 +39,30 @@
/* write_map() args */ /* write_map() args */
#define WMAP_FREE (1 << 0) #define WMAP_FREE (1 << 0)
#define IGN_PERM 0
#define CHK_PERM 1
#define IN_CLEAN 0 /* in-block inode and memory copies identical */ #define IN_CLEAN 0 /* in-block inode and memory copies identical */
#define IN_DIRTY 1 /* in-block inode and memory copies differ */ #define IN_DIRTY 1 /* in-block inode and memory copies differ */
#define ATIME 002 /* set if atime field needs updating */ #define ATIME 002 /* set if atime field needs updating */
#define CTIME 004 /* set if ctime field needs updating */ #define CTIME 004 /* set if ctime field needs updating */
#define MTIME 010 /* set if mtime field needs updating */ #define MTIME 010 /* set if mtime field needs updating */
#define BYTE_SWAP 0 /* tells conv2/conv4 to swap bytes */
#define END_OF_FILE (-104) /* eof detected */
#define ROOT_INODE ((ino_t) 1) /* inode number for root directory */ #define ROOT_INODE ((ino_t) 1) /* inode number for root directory */
#define BOOT_BLOCK ((block_t) 0) /* block number of boot block */ #define BOOT_BLOCK ((block_t) 0) /* block number of boot block */
#define SUPER_BLOCK_BYTES (1024) /* bytes offset */ #define SUPER_BLOCK_BYTES (1024) /* bytes offset */
#define START_BLOCK ((block_t) 2) /* first block of FS (not counting SB) */ #define START_BLOCK ((block_t) 2) /* first block of FS (not counting SB) */
#define DIR_ENTRY_SIZE usizeof (struct direct) /* # bytes/dir entry */ #define DIR_ENTRY_SIZE sizeof (struct direct) /* # bytes/dir entry */
#define NR_DIR_ENTRIES(b) ((b)/DIR_ENTRY_SIZE) /* # dir entries/blk */ #define NR_DIR_ENTRIES(b) ((b)/DIR_ENTRY_SIZE) /* # dir entries/blk */
#define SUPER_SIZE usizeof (struct super_block) /* super_block size */ #define SUPER_SIZE sizeof (struct super_block) /* super_block size */
#define FS_BITMAP_CHUNKS(b) ((b)/usizeof (bitchunk_t))/* # map chunks/blk */ #define FS_BITMAP_CHUNKS(b) ((b)/sizeof (bitchunk_t))/* # map chunks/blk */
#define FS_BITCHUNK_BITS (usizeof(bitchunk_t) * CHAR_BIT) #define FS_BITCHUNK_BITS (sizeof(bitchunk_t) * CHAR_BIT)
#define FS_BITS_PER_BLOCK(b) (FS_BITMAP_CHUNKS(b) * FS_BITCHUNK_BITS) #define FS_BITS_PER_BLOCK(b) (FS_BITMAP_CHUNKS(b) * FS_BITCHUNK_BITS)
/* Derived sizes pertaining to the V2 file system. */ /* Derived sizes pertaining to the V2 file system. */
#define V2_ZONE_NUM_SIZE usizeof (zone_t) /* # bytes in V2 zone */ #define V2_ZONE_NUM_SIZE sizeof (zone_t) /* # bytes in V2 zone */
#define V2_INODE_SIZE usizeof (d2_inode) /* bytes in V2 dsk ino */ #define V2_INODE_SIZE sizeof (d2_inode) /* bytes in V2 dsk ino */
#define V2_INDIRECTS(b) ((b)/V2_ZONE_NUM_SIZE) /* # zones/indir block */ #define V2_INDIRECTS(b) ((b)/V2_ZONE_NUM_SIZE) /* # zones/indir block */
#define V2_INODES_PER_BLOCK(b) ((b)/V2_INODE_SIZE)/* # V2 dsk inodes/blk */ #define V2_INODES_PER_BLOCK(b) ((b)/V2_INODE_SIZE)/* # V2 dsk inodes/blk */
#define NUL(str,l,m) mfs_nul_f(__FILE__,__LINE__,(str), (l), (m))
#endif #endif

View file

@ -13,16 +13,16 @@
#include <sys/types.h> #include <sys/types.h>
#include <minix/const.h> #include <minix/const.h>
#include <minix/type.h> #include <minix/type.h>
#include <minix/dmap.h>
#include <lib.h> #include <lib.h>
#include <limits.h> #include <limits.h>
#include <errno.h> #include <errno.h>
#include <minix/vfsif.h>
#include <minix/syslib.h> #include <minix/syslib.h>
#include <minix/sysutil.h> #include <minix/sysutil.h>
#include <minix/fsdriver.h>
#include "mfsdir.h" #include "mfsdir.h"
#include "const.h" #include "const.h"
#include "type.h" #include "type.h"

View file

@ -7,35 +7,14 @@
#define EXTERN #define EXTERN
#endif #endif
#include <minix/vfsif.h>
/* The following variables are used for returning results to the caller. */ /* The following variables are used for returning results to the caller. */
EXTERN int err_code; /* temporary storage for error number */ EXTERN int err_code; /* temporary storage for error number */
EXTERN int cch[NR_INODES]; EXTERN int cch[NR_INODES];
extern char dot1[2]; /* dot1 (&dot1[0]) and dot2 (&dot2[0]) have a special */
extern char dot2[3]; /* meaning to search_dir: no access permission check. */
extern int(*fs_call_vec[]) (void);
EXTERN message fs_m_in;
EXTERN message fs_m_out;
EXTERN vfs_ucred_t credentials;
EXTERN uid_t caller_uid;
EXTERN gid_t caller_gid;
EXTERN int req_nr;
EXTERN char user_path[PATH_MAX]; /* pathname to be processed */
EXTERN dev_t fs_dev; /* The device that is handled by this FS proc. EXTERN dev_t fs_dev; /* The device that is handled by this FS proc.
*/ */
EXTERN char fs_dev_label[16]; /* Name of the device driver that is handled
* by this FS proc. extern struct fsdriver mfs_table;
*/
EXTERN int unmountdone;
EXTERN int exitsignaled;
#endif #endif

View file

@ -35,27 +35,21 @@ static void wipe_inode(struct inode *rip);
/*===========================================================================* /*===========================================================================*
* fs_putnode * * fs_putnode *
*===========================================================================*/ *===========================================================================*/
int fs_putnode(void) int fs_putnode(ino_t ino_nr, unsigned int count)
{ {
/* Find the inode specified by the request message and decrease its counter.*/ /* Find the inode specified by the request message and decrease its counter.*/
struct inode *rip; struct inode *rip;
int count;
rip = find_inode(fs_dev, fs_m_in.m_vfs_fs_putnode.inode); rip = find_inode(fs_dev, ino_nr);
if(!rip) { if(!rip) {
printf("%s:%d put_inode: inode #%llu dev: %llx not found\n", __FILE__, printf("%s:%d put_inode: inode #%llu dev: %llx not found\n", __FILE__,
__LINE__, fs_m_in.m_vfs_fs_putnode.inode, fs_dev); __LINE__, ino_nr, fs_dev);
panic("fs_putnode failed"); panic("fs_putnode failed");
} }
count = fs_m_in.m_vfs_fs_putnode.count; if (count > rip->i_count) {
if (count <= 0) {
printf("%s:%d put_inode: bad value for count: %d\n", __FILE__,
__LINE__, count);
panic("fs_putnode failed");
} else if(count > rip->i_count) {
printf("%s:%d put_inode: count too high: %d > %d\n", __FILE__, printf("%s:%d put_inode: count too high: %d > %d\n", __FILE__,
__LINE__, count, rip->i_count); __LINE__, count, rip->i_count);
panic("fs_putnode failed"); panic("fs_putnode failed");
@ -255,7 +249,7 @@ register struct inode *rip; /* pointer to inode to be released */
/*===========================================================================* /*===========================================================================*
* alloc_inode * * alloc_inode *
*===========================================================================*/ *===========================================================================*/
struct inode *alloc_inode(dev_t dev, mode_t bits) struct inode *alloc_inode(dev_t dev, mode_t bits, uid_t uid, gid_t gid)
{ {
/* Allocate a free inode on 'dev', and return a pointer to it. */ /* Allocate a free inode on 'dev', and return a pointer to it. */
@ -290,8 +284,8 @@ struct inode *alloc_inode(dev_t dev, mode_t bits)
/* An inode slot is available. Put the inode just allocated into it. */ /* An inode slot is available. Put the inode just allocated into it. */
rip->i_mode = bits; /* set up RWX bits */ rip->i_mode = bits; /* set up RWX bits */
rip->i_nlinks = NO_LINK; /* initial no links */ rip->i_nlinks = NO_LINK; /* initial no links */
rip->i_uid = caller_uid; /* file's uid is owner's */ rip->i_uid = uid; /* file's uid is owner's */
rip->i_gid = caller_gid; /* ditto group id */ rip->i_gid = gid; /* ditto group id */
rip->i_dev = dev; /* mark which device it is on */ rip->i_dev = dev; /* mark which device it is on */
rip->i_ndzones = sp->s_ndzones; /* number of direct zones */ rip->i_ndzones = sp->s_ndzones; /* number of direct zones */
rip->i_nindirs = sp->s_nindirs; /* number of indirect zones per blk*/ rip->i_nindirs = sp->s_nindirs; /* number of indirect zones per blk*/

View file

@ -29,25 +29,16 @@ static void zerozone_range(struct inode *rip, off_t pos, off_t len);
/*===========================================================================* /*===========================================================================*
* fs_link * * fs_link *
*===========================================================================*/ *===========================================================================*/
int fs_link() int fs_link(ino_t dir_nr, char *name, ino_t ino_nr)
{ {
/* Perform the link(name1, name2) system call. */ /* Perform the link(name1, name2) system call. */
struct inode *ip, *rip; struct inode *ip, *rip;
register int r; register int r;
char string[MFS_NAME_MAX];
struct inode *new_ip; struct inode *new_ip;
phys_bytes len;
len = min(fs_m_in.m_vfs_fs_link.path_len, sizeof(string));
/* Copy the link name's last component */
r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_link.grant,
(vir_bytes) 0, (vir_bytes) string, (size_t) len);
if (r != OK) return r;
NUL(string, len, sizeof(string));
/* Temporarily open the file. */ /* Temporarily open the file. */
if( (rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_link.inode)) == NULL) if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
/* Check to see if the file has maximum number of links already. */ /* Check to see if the file has maximum number of links already. */
@ -55,9 +46,9 @@ int fs_link()
if(rip->i_nlinks >= LINK_MAX) if(rip->i_nlinks >= LINK_MAX)
r = EMLINK; r = EMLINK;
/* Only super_user may link to directories. */ /* Linking to directories is too dangerous to allow. */
if(r == OK) if(r == OK)
if( (rip->i_mode & I_TYPE) == I_DIRECTORY && caller_uid != SU_UID) if( (rip->i_mode & I_TYPE) == I_DIRECTORY)
r = EPERM; r = EPERM;
/* If error with 'name', return the inode. */ /* If error with 'name', return the inode. */
@ -67,7 +58,7 @@ int fs_link()
} }
/* Temporarily open the last dir */ /* Temporarily open the last dir */
if( (ip = get_inode(fs_dev, fs_m_in.m_vfs_fs_link.dir_ino)) == NULL) { if( (ip = get_inode(fs_dev, dir_nr)) == NULL) {
put_inode(rip); put_inode(rip);
return(EINVAL); return(EINVAL);
} }
@ -79,7 +70,7 @@ int fs_link()
} }
/* If 'name2' exists in full (even if no space) set 'r' to error. */ /* If 'name2' exists in full (even if no space) set 'r' to error. */
if((new_ip = advance(ip, string, IGN_PERM)) == NULL) { if((new_ip = advance(ip, name)) == NULL) {
r = err_code; r = err_code;
if(r == ENOENT) if(r == ENOENT)
r = OK; r = OK;
@ -90,7 +81,7 @@ int fs_link()
/* Try to link. */ /* Try to link. */
if(r == OK) if(r == OK)
r = search_dir(ip, string, &rip->i_num, ENTER, IGN_PERM); r = search_dir(ip, name, &rip->i_num, ENTER);
/* If success, register the linking. */ /* If success, register the linking. */
if(r == OK) { if(r == OK) {
@ -109,56 +100,43 @@ int fs_link()
/*===========================================================================* /*===========================================================================*
* fs_unlink * * fs_unlink *
*===========================================================================*/ *===========================================================================*/
int fs_unlink() int fs_unlink(ino_t dir_nr, char *name, int call)
{ {
/* Perform the unlink(name) or rmdir(name) system call. The code for these two /* Perform the unlink(name) or rmdir(name) system call. The code for these two
* is almost the same. They differ only in some condition testing. Unlink() * is almost the same. They differ only in some condition testing.
* may be used by the superuser to do dangerous things; rmdir() may not.
*/ */
register struct inode *rip; register struct inode *rip;
struct inode *rldirp; struct inode *rldirp;
int r; int r;
char string[MFS_NAME_MAX];
phys_bytes len;
/* Copy the last component */
len = min(fs_m_in.m_vfs_fs_unlink.path_len, sizeof(string));
r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_unlink.grant,
(vir_bytes) 0, (vir_bytes) string, (size_t) len);
if (r != OK) return r;
NUL(string, len, sizeof(string));
/* Temporarily open the dir. */ /* Temporarily open the dir. */
if((rldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_unlink.inode)) == NULL) if((rldirp = get_inode(fs_dev, dir_nr)) == NULL)
return(EINVAL); return(EINVAL);
/* The last directory exists. Does the file also exist? */ /* The last directory exists. Does the file also exist? */
rip = advance(rldirp, string, IGN_PERM); rip = advance(rldirp, name);
r = err_code; r = err_code;
/* If error, return inode. */ /* If error, return inode. */
if(r != OK) { if(r != OK) {
/* Mount point? */
if (r == EENTERMOUNT || r == ELEAVEMOUNT) {
put_inode(rip);
r = EBUSY;
}
put_inode(rldirp); put_inode(rldirp);
return(r); return(r);
} }
if (rip->i_mountpoint) {
put_inode(rip);
put_inode(rldirp);
return(EBUSY);
}
if(rip->i_sp->s_rd_only) { if(rip->i_sp->s_rd_only) {
r = EROFS; r = EROFS;
} else if(fs_m_in.m_type == REQ_UNLINK) { } else if (call == FSC_UNLINK) {
/* Now test if the call is allowed, separately for unlink() and rmdir(). */
/* Only the su may unlink directories, but the su can unlink any
* dir.*/
if( (rip->i_mode & I_TYPE) == I_DIRECTORY) r = EPERM; if( (rip->i_mode & I_TYPE) == I_DIRECTORY) r = EPERM;
/* Actually try to unlink the file; fails if parent is mode 0 etc. */ /* Actually try to unlink the file; fails if parent is mode 0 etc. */
if (r == OK) r = unlink_file(rldirp, rip, string); if (r == OK) r = unlink_file(rldirp, rip, name);
} else { } else {
r = remove_dir(rldirp, rip, string); /* call is RMDIR */ r = remove_dir(rldirp, rip, name); /* call is RMDIR */
} }
/* If unlink was possible, it has been done, otherwise it has not. */ /* If unlink was possible, it has been done, otherwise it has not. */
@ -171,17 +149,14 @@ int fs_unlink()
/*===========================================================================* /*===========================================================================*
* fs_rdlink * * fs_rdlink *
*===========================================================================*/ *===========================================================================*/
int fs_rdlink() ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes)
{ {
struct buf *bp; /* buffer containing link text */ struct buf *bp; /* buffer containing link text */
register struct inode *rip; /* target inode */ register struct inode *rip; /* target inode */
register int r; /* return value */ register int r; /* return value */
size_t copylen;
copylen = min(fs_m_in.m_vfs_fs_rdlink.mem_size, UMAX_FILE_POS);
/* Temporarily open the file. */ /* Temporarily open the file. */
if( (rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_rdlink.inode)) == NULL) if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
if(!S_ISLNK(rip->i_mode)) if(!S_ISLNK(rip->i_mode))
@ -190,15 +165,12 @@ int fs_rdlink()
if(!(bp = get_block_map(rip, 0))) if(!(bp = get_block_map(rip, 0)))
return EIO; return EIO;
/* Passed all checks */ /* Passed all checks */
/* We can safely cast to unsigned, because copylen is guaranteed to be if (bytes > rip->i_size)
below max file size */ bytes = rip->i_size;
copylen = min( copylen, (unsigned) rip->i_size); r = fsdriver_copyout(data, 0, b_data(bp), bytes);
r = sys_safecopyto(VFS_PROC_NR, fs_m_in.m_vfs_fs_rdlink.grant,
(vir_bytes) 0, (vir_bytes) b_data(bp),
(size_t) copylen);
put_block(bp, DIRECTORY_BLOCK); put_block(bp, DIRECTORY_BLOCK);
if (r == OK) if (r == OK)
fs_m_out.m_fs_vfs_rdlink.nbytes = copylen; r = bytes;
} }
put_inode(rip); put_inode(rip);
@ -224,10 +196,9 @@ char dir_name[MFS_NAME_MAX]; /* name of directory to be removed */
int r; int r;
/* search_dir checks that rip is a directory too. */ /* search_dir checks that rip is a directory too. */
if ((r = search_dir(rip, "", NULL, IS_EMPTY, IGN_PERM)) != OK) if ((r = search_dir(rip, "", NULL, IS_EMPTY)) != OK)
return(r); return(r);
if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL);
if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */ if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */
/* Actually try to unlink the file; fails if parent is mode 0 etc. */ /* Actually try to unlink the file; fails if parent is mode 0 etc. */
@ -236,8 +207,8 @@ char dir_name[MFS_NAME_MAX]; /* name of directory to be removed */
/* Unlink . and .. from the dir. The super user can link and unlink any dir, /* Unlink . and .. from the dir. The super user can link and unlink any dir,
* so don't make too many assumptions about them. * so don't make too many assumptions about them.
*/ */
(void) unlink_file(rip, NULL, dot1); (void) unlink_file(rip, NULL, ".");
(void) unlink_file(rip, NULL, dot2); (void) unlink_file(rip, NULL, "..");
return(OK); return(OK);
} }
@ -258,14 +229,14 @@ char file_name[MFS_NAME_MAX]; /* name of file to be removed */
/* If rip is not NULL, it is used to get faster access to the inode. */ /* If rip is not NULL, it is used to get faster access to the inode. */
if (rip == NULL) { if (rip == NULL) {
/* Search for file in directory and try to get its inode. */ /* Search for file in directory and try to get its inode. */
err_code = search_dir(dirp, file_name, &numb, LOOK_UP, IGN_PERM); err_code = search_dir(dirp, file_name, &numb, LOOK_UP);
if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb); if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb);
if (err_code != OK || rip == NULL) return(err_code); if (err_code != OK || rip == NULL) return(err_code);
} else { } else {
dup_inode(rip); /* inode will be returned with put_inode */ dup_inode(rip); /* inode will be returned with put_inode */
} }
r = search_dir(dirp, file_name, NULL, DELETE, IGN_PERM); r = search_dir(dirp, file_name, NULL, DELETE);
if (r == OK) { if (r == OK) {
rip->i_nlinks--; /* entry deleted from parent's dir */ rip->i_nlinks--; /* entry deleted from parent's dir */
@ -281,7 +252,8 @@ char file_name[MFS_NAME_MAX]; /* name of file to be removed */
/*===========================================================================* /*===========================================================================*
* fs_rename * * fs_rename *
*===========================================================================*/ *===========================================================================*/
int fs_rename() int fs_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
char *new_name)
{ {
/* Perform the rename(name1, name2) system call. */ /* Perform the rename(name1, name2) system call. */
struct inode *old_dirp, *old_ip; /* ptrs to old dir, file inodes */ struct inode *old_dirp, *old_ip; /* ptrs to old dir, file inodes */
@ -290,45 +262,28 @@ int fs_rename()
int r = OK; /* error flag; initially no error */ int r = OK; /* error flag; initially no error */
int odir, ndir; /* TRUE iff {old|new} file is dir */ int odir, ndir; /* TRUE iff {old|new} file is dir */
int same_pdir; /* TRUE iff parent dirs are the same */ int same_pdir; /* TRUE iff parent dirs are the same */
char old_name[MFS_NAME_MAX], new_name[MFS_NAME_MAX];
ino_t numb; ino_t numb;
phys_bytes len;
/* Copy the last component of the old name */
len = min( (unsigned) fs_m_in.m_vfs_fs_rename.len_old, sizeof(old_name));
r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_rename.grant_old,
(vir_bytes) 0, (vir_bytes) old_name, (size_t) len);
if (r != OK) return r;
NUL(old_name, len, sizeof(old_name));
/* Copy the last component of the new name */
len = min( (unsigned) fs_m_in.m_vfs_fs_rename.len_new, sizeof(new_name));
r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_rename.grant_new,
(vir_bytes) 0, (vir_bytes) new_name, (size_t) len);
if (r != OK) return r;
NUL(new_name, len, sizeof(new_name));
/* Get old dir inode */ /* Get old dir inode */
if ((old_dirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_rename.dir_old)) == NULL) if ((old_dirp = get_inode(fs_dev, old_dir_nr)) == NULL)
return(err_code); return(err_code);
old_ip = advance(old_dirp, old_name, IGN_PERM); old_ip = advance(old_dirp, old_name);
r = err_code; r = err_code;
if (r == EENTERMOUNT || r == ELEAVEMOUNT) {
put_inode(old_ip);
old_ip = NULL;
if (r == EENTERMOUNT) r = EXDEV; /* should this fail at all? */
else if (r == ELEAVEMOUNT) r = EINVAL; /* rename on dot-dot */
}
if (old_ip == NULL) { if (old_ip == NULL) {
put_inode(old_dirp); put_inode(old_dirp);
return(r); return(r);
} }
if (old_ip->i_mountpoint) {
put_inode(old_ip);
put_inode(old_dirp);
return(EBUSY);
}
/* Get new dir inode */ /* Get new dir inode */
if ((new_dirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_rename.dir_new)) == NULL){ if ((new_dirp = get_inode(fs_dev, new_dir_nr)) == NULL) {
put_inode(old_ip); put_inode(old_ip);
put_inode(old_dirp); put_inode(old_dirp);
return(err_code); return(err_code);
@ -341,11 +296,10 @@ int fs_rename()
} }
} }
new_ip = advance(new_dirp, new_name, IGN_PERM); /* not required to exist */ new_ip = advance(new_dirp, new_name); /* not required to exist */
/* However, if the check failed because the file does exist, don't continue. /* If the node does exist, make sure it's not a mountpoint. */
* Note that ELEAVEMOUNT is covered by the dot-dot check later. */ if (new_ip != NULL && new_ip->i_mountpoint) {
if(err_code == EENTERMOUNT) {
put_inode(new_ip); put_inode(new_ip);
new_ip = NULL; new_ip = NULL;
r = EBUSY; r = EBUSY;
@ -366,17 +320,14 @@ int fs_rename()
r = EINVAL; r = EINVAL;
break; break;
} }
next_new_superdirp = advance(new_superdirp, dot2, next_new_superdirp = advance(new_superdirp, "..");
IGN_PERM);
put_inode(new_superdirp); put_inode(new_superdirp);
if(next_new_superdirp == new_superdirp) { if(next_new_superdirp == new_superdirp) {
put_inode(new_superdirp); put_inode(new_superdirp);
break; break;
} }
if(err_code == ELEAVEMOUNT) { if(next_new_superdirp->i_num == ROOT_INODE) {
/* imitate that we are back at the root,
* cross device checked already on VFS */
put_inode(next_new_superdirp); put_inode(next_new_superdirp);
err_code = OK; err_code = OK;
break; break;
@ -390,18 +341,8 @@ int fs_rename()
} }
} }
/* The old or new name must not be . or .. */
if(strcmp(old_name, ".") == 0 || strcmp(old_name, "..") == 0 ||
strcmp(new_name, ".") == 0 || strcmp(new_name, "..") == 0) {
r = EINVAL;
}
/* Both parent directories must be on the same device.
if(old_dirp->i_dev != new_dirp->i_dev) r = EXDEV; */
/* Some tests apply only if the new path exists. */ /* Some tests apply only if the new path exists. */
if(new_ip == NULL) { if(new_ip == NULL) {
/* don't rename a file with a file system mounted on it.
if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;*/
if (odir && new_dirp->i_nlinks >= LINK_MAX && if (odir && new_dirp->i_nlinks >= LINK_MAX &&
!same_pdir && r == OK) { !same_pdir && r == OK) {
r = EMLINK; r = EMLINK;
@ -448,16 +389,14 @@ int fs_rename()
numb = old_ip->i_num; /* inode number of old file */ numb = old_ip->i_num; /* inode number of old file */
if(same_pdir) { if(same_pdir) {
r = search_dir(old_dirp, old_name, NULL, DELETE, IGN_PERM); r = search_dir(old_dirp, old_name, NULL, DELETE);
/* shouldn't go wrong. */ /* shouldn't go wrong. */
if(r == OK) if(r == OK)
(void) search_dir(old_dirp, new_name, &numb, ENTER, (void) search_dir(old_dirp, new_name, &numb, ENTER);
IGN_PERM);
} else { } else {
r = search_dir(new_dirp, new_name, &numb, ENTER, IGN_PERM); r = search_dir(new_dirp, new_name, &numb, ENTER);
if(r == OK) if(r == OK)
(void) search_dir(old_dirp, old_name, NULL, DELETE, (void) search_dir(old_dirp, old_name, NULL, DELETE);
IGN_PERM);
} }
} }
/* If r is OK, the ctime and mtime of old_dirp and new_dirp have been marked /* If r is OK, the ctime and mtime of old_dirp and new_dirp have been marked
@ -466,8 +405,8 @@ int fs_rename()
if(r == OK && odir && !same_pdir) { if(r == OK && odir && !same_pdir) {
/* Update the .. entry in the directory (still points to old_dirp).*/ /* Update the .. entry in the directory (still points to old_dirp).*/
numb = new_dirp->i_num; numb = new_dirp->i_num;
(void) unlink_file(old_ip, NULL, dot2); (void) unlink_file(old_ip, NULL, "..");
if(search_dir(old_ip, dot2, &numb, ENTER, IGN_PERM) == OK) { if(search_dir(old_ip, "..", &numb, ENTER) == OK) {
/* New link created. */ /* New link created. */
new_dirp->i_nlinks++; new_dirp->i_nlinks++;
IN_MARKDIRTY(new_dirp); IN_MARKDIRTY(new_dirp);
@ -484,23 +423,19 @@ int fs_rename()
/*===========================================================================* /*===========================================================================*
* fs_ftrunc * * fs_trunc *
*===========================================================================*/ *===========================================================================*/
int fs_ftrunc(void) int fs_trunc(ino_t ino_nr, off_t start, off_t end)
{ {
struct inode *rip; struct inode *rip;
off_t start, end;
int r; int r;
if( (rip = find_inode(fs_dev, fs_m_in.m_vfs_fs_ftrunc.inode)) == NULL) if( (rip = find_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
if(rip->i_sp->s_rd_only) { if(rip->i_sp->s_rd_only) {
r = EROFS; r = EROFS;
} else { } else {
start = fs_m_in.m_vfs_fs_ftrunc.trc_start;
end = fs_m_in.m_vfs_fs_ftrunc.trc_end;
if (end == 0) if (end == 0)
r = truncate_inode(rip, start); r = truncate_inode(rip, start);
else else

View file

@ -1,20 +1,8 @@
#include "fs.h" #include "fs.h"
#include <assert.h>
#include <minix/callnr.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <minix/dmap.h>
#include <minix/endpoint.h>
#include <minix/vfsif.h>
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
/* Declare some local functions. */
static void get_work(message *m_in);
static void reply(endpoint_t who, message *m_out);
/* SEF functions and variables. */ /* SEF functions and variables. */
static void sef_local_startup(void); static void sef_local_startup(void);
static int sef_cb_init_fresh(int type, sef_init_info_t *info); static int sef_cb_init_fresh(int type, sef_init_info_t *info);
@ -25,60 +13,16 @@ static void sef_cb_signal_handler(int signo);
*===========================================================================*/ *===========================================================================*/
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
/* This is the main routine of this service. The main loop consists of /* This is the main routine of this service. */
* three major activities: getting new work, processing the work, and
* sending the reply. The loop never terminates, unless a panic occurs.
*/
int error = OK, ind, transid;
/* SEF local startup. */ /* SEF local startup. */
env_setargs(argc, argv); env_setargs(argc, argv);
sef_local_startup(); sef_local_startup();
while(!unmountdone || !exitsignaled) { /* The fsdriver library does the actual work here. */
endpoint_t src; fsdriver_task(&mfs_table);
/* Wait for request message. */ return(0);
get_work(&fs_m_in);
transid = TRNS_GET_ID(fs_m_in.m_type);
fs_m_in.m_type = TRNS_DEL_ID(fs_m_in.m_type);
if (fs_m_in.m_type == 0) {
assert(!IS_VFS_FS_TRANSID(transid));
fs_m_in.m_type = transid; /* Backwards compat. */
transid = 0;
} else
assert(IS_VFS_FS_TRANSID(transid));
src = fs_m_in.m_source;
caller_uid = INVAL_UID; /* To trap errors */
caller_gid = INVAL_GID;
req_nr = fs_m_in.m_type;
if (req_nr < FS_BASE) {
fs_m_in.m_type += FS_BASE;
req_nr = fs_m_in.m_type;
}
ind = req_nr - FS_BASE;
if (ind < 0 || ind >= NREQS) {
printf("MFS: bad request %d from %d\n", req_nr, src);
printf("ind = %d\n", ind);
error = EINVAL;
} else {
error = (*fs_call_vec[ind])();
/*cch_check();*/
}
fs_m_out.m_type = error;
if (IS_VFS_FS_TRANSID(transid)) {
/* If a transaction ID was set, reset it */
fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type, transid);
}
reply(src, &fs_m_out);
}
return(OK);
} }
/*===========================================================================* /*===========================================================================*
@ -130,53 +74,9 @@ static void sef_cb_signal_handler(int signo)
/* Only check for termination signal, ignore anything else. */ /* Only check for termination signal, ignore anything else. */
if (signo != SIGTERM) return; if (signo != SIGTERM) return;
exitsignaled = 1; fs_sync();
(void) fs_sync();
/* If unmounting has already been performed, exit immediately. fsdriver_terminate();
* We might not get another message.
*/
if (unmountdone) exit(0);
}
/*===========================================================================*
* get_work *
*===========================================================================*/
static void get_work(m_in)
message *m_in; /* pointer to message */
{
int r, srcok = 0;
endpoint_t src;
do {
if ((r = sef_receive(ANY, m_in)) != OK) /* wait for message */
panic("sef_receive failed: %d", r);
src = m_in->m_source;
if(src == VFS_PROC_NR) {
if(unmountdone)
printf("MFS: unmounted: unexpected message from FS\n");
else
srcok = 1; /* Normal FS request. */
} else
printf("MFS: unexpected source %d\n", src);
} while(!srcok);
assert((src == VFS_PROC_NR && !unmountdone));
}
/*===========================================================================*
* reply *
*===========================================================================*/
static void reply(
endpoint_t who,
message *m_out /* report result */
)
{
if (OK != ipc_send(who, m_out)) /* send the message */
printf("MFS(%d) was unable to send reply\n", sef_self());
} }

View file

@ -1,14 +1,12 @@
#include "fs.h" #include "fs.h"
#include <assert.h>
#include <minix/vfsif.h>
#include <minix/bdev.h>
#include "inode.h" #include "inode.h"
#include "clean.h" #include "clean.h"
#include <assert.h>
/*===========================================================================* /*===========================================================================*
* fs_sync * * fs_sync *
*===========================================================================*/ *===========================================================================*/
int fs_sync() void fs_sync(void)
{ {
/* Perform the sync() system call. Flush all the tables. /* Perform the sync() system call. Flush all the tables.
* The order in which the various tables are flushed is critical. The * The order in which the various tables are flushed is critical. The
@ -25,62 +23,4 @@ int fs_sync()
/* Write all the dirty blocks to the disk. */ /* Write all the dirty blocks to the disk. */
lmfs_flushall(); lmfs_flushall();
return(OK); /* sync() can't fail */
}
/*===========================================================================*
* fs_flush *
*===========================================================================*/
int fs_flush()
{
/* Flush the blocks of a device from the cache after writing any dirty blocks
* to disk.
*/
dev_t dev = fs_m_in.m_vfs_fs_flush.device;
if(dev == fs_dev && lmfs_bufs_in_use() > 0) return(EBUSY);
lmfs_flushall();
lmfs_invalidate(dev);
return(OK);
}
/*===========================================================================*
* fs_new_driver *
*===========================================================================*/
int fs_new_driver(void)
{
/* Set a new driver endpoint for this device. */
dev_t dev;
cp_grant_id_t label_gid;
size_t label_len;
char label[sizeof(fs_dev_label)];
int r;
dev = fs_m_in.m_vfs_fs_new_driver.device;
label_gid = fs_m_in.m_vfs_fs_new_driver.grant;
label_len = fs_m_in.m_vfs_fs_new_driver.path_len;
if (label_len > sizeof(label))
return(EINVAL);
r = sys_safecopyfrom(fs_m_in.m_source, label_gid, (vir_bytes) 0,
(vir_bytes) label, label_len);
if (r != OK) {
printf("MFS: fs_new_driver safecopyfrom failed (%d)\n", r);
return(EINVAL);
}
bdev_driver(dev, label);
return(OK);
}
int fs_bpeek(void)
{
return lmfs_do_bpeek(&fs_m_in);
} }

View file

@ -4,44 +4,20 @@
#include <minix/vfsif.h> #include <minix/vfsif.h>
#include <minix/bdev.h> #include <minix/bdev.h>
static int cleanmount = 1;
/*===========================================================================* /*===========================================================================*
* fs_readsuper * * fs_mount *
*===========================================================================*/ *===========================================================================*/
int fs_readsuper() int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
unsigned int *res_flags)
{ {
/* This function reads the superblock of the partition, gets the root inode /* This function reads the superblock of the partition, gets the root inode
* and sends back the details of them. Note, that the FS process does not * and sends back the details of them.
* know the index of the vmnt object which refers to it, whenever the pathname
* lookup leaves a partition an ELEAVEMOUNT error is transferred back
* so that the VFS knows that it has to find the vnode on which this FS
* process' partition is mounted on.
*/ */
struct inode *root_ip; struct inode *root_ip;
cp_grant_id_t label_gid; int r, readonly;
size_t label_len;
int r;
int readonly, isroot;
fs_dev = fs_m_in.m_vfs_fs_readsuper.device; fs_dev = dev;
label_gid = fs_m_in.m_vfs_fs_readsuper.grant; readonly = (flags & REQ_RDONLY) ? 1 : 0;
label_len = fs_m_in.m_vfs_fs_readsuper.path_len;
readonly = (fs_m_in.m_vfs_fs_readsuper.flags & REQ_RDONLY) ? 1 : 0;
isroot = (fs_m_in.m_vfs_fs_readsuper.flags & REQ_ISROOT) ? 1 : 0;
if (label_len > sizeof(fs_dev_label))
return(EINVAL);
r = sys_safecopyfrom(fs_m_in.m_source, label_gid, (vir_bytes) 0,
(vir_bytes) fs_dev_label, label_len);
if (r != OK) {
printf("MFS %s:%d safecopyfrom failed: %d\n", __FILE__, __LINE__, r);
return(EINVAL);
}
/* Map the driver label for this major. */
bdev_driver(fs_dev, fs_dev_label);
/* Open the device the file system lives on. */ /* Open the device the file system lives on. */
if (bdev_open(fs_dev, readonly ? BDEV_R_BIT : (BDEV_R_BIT|BDEV_W_BIT) ) != if (bdev_open(fs_dev, readonly ? BDEV_R_BIT : (BDEV_R_BIT|BDEV_W_BIT) ) !=
@ -60,12 +36,6 @@ int fs_readsuper()
return(r); return(r);
} }
/* Remember whether we were mounted cleanly so we know what to
* do at unmount time
*/
if(superblock.s_flags & MFSFLAG_CLEAN)
cleanmount = 1;
/* clean check: if rw and not clean, switch to readonly */ /* clean check: if rw and not clean, switch to readonly */
if(!(superblock.s_flags & MFSFLAG_CLEAN) && !readonly) { if(!(superblock.s_flags & MFSFLAG_CLEAN) && !readonly) {
if(bdev_close(fs_dev) != OK) if(bdev_close(fs_dev) != OK)
@ -98,15 +68,16 @@ int fs_readsuper()
} }
superblock.s_rd_only = readonly; superblock.s_rd_only = readonly;
superblock.s_is_root = isroot;
/* Root inode properties */ /* Root inode properties */
fs_m_out.m_fs_vfs_readsuper.inode = root_ip->i_num; root_node->fn_ino_nr = root_ip->i_num;
fs_m_out.m_fs_vfs_readsuper.mode = root_ip->i_mode; root_node->fn_mode = root_ip->i_mode;
fs_m_out.m_fs_vfs_readsuper.file_size = root_ip->i_size; root_node->fn_size = root_ip->i_size;
fs_m_out.m_fs_vfs_readsuper.uid = root_ip->i_uid; root_node->fn_uid = root_ip->i_uid;
fs_m_out.m_fs_vfs_readsuper.gid = root_ip->i_gid; root_node->fn_gid = root_ip->i_gid;
fs_m_out.m_fs_vfs_readsuper.flags = RES_HASPEEK; root_node->fn_dev = NO_DEV;
*res_flags = RES_NOFLAGS;
/* Mark it dirty */ /* Mark it dirty */
if(!superblock.s_rd_only) { if(!superblock.s_rd_only) {
@ -120,9 +91,9 @@ int fs_readsuper()
/*===========================================================================* /*===========================================================================*
* fs_mountpoint * * fs_mountpt *
*===========================================================================*/ *===========================================================================*/
int fs_mountpoint() int fs_mountpt(ino_t ino_nr)
{ {
/* This function looks up the mount point, it checks the condition whether /* This function looks up the mount point, it checks the condition whether
* the partition can be mounted on the inode or not. * the partition can be mounted on the inode or not.
@ -132,10 +103,9 @@ int fs_mountpoint()
mode_t bits; mode_t bits;
/* Temporarily open the file. */ /* Temporarily open the file. */
if( (rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_mountpoint.inode)) == NULL) if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
if(rip->i_mountpoint) r = EBUSY; if(rip->i_mountpoint) r = EBUSY;
/* It may not be special. */ /* It may not be special. */
@ -153,33 +123,32 @@ int fs_mountpoint()
/*===========================================================================* /*===========================================================================*
* fs_unmount * * fs_unmount *
*===========================================================================*/ *===========================================================================*/
int fs_unmount() void fs_unmount(void)
{ {
/* Unmount a file system by device number. */ /* Unmount a file system. */
int count; int count;
struct inode *rip, *root_ip; struct inode *rip, *root_ip;
if(superblock.s_dev != fs_dev) return(EINVAL);
/* See if the mounted device is busy. Only 1 inode using it should be /* See if the mounted device is busy. Only 1 inode using it should be
* open --the root inode-- and that inode only 1 time. */ * open --the root inode-- and that inode only 1 time. This is an integrity
* check only: VFS expects the unmount to succeed either way.
*/
count = 0; count = 0;
for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
if (rip->i_count > 0 && rip->i_dev == fs_dev) count += rip->i_count; if (rip->i_count > 0 && rip->i_dev == fs_dev) count += rip->i_count;
if (count != 1)
printf("MFS: file system has %d in-use inodes!\n", count);
if ((root_ip = find_inode(fs_dev, ROOT_INODE)) == NULL) { if ((root_ip = find_inode(fs_dev, ROOT_INODE)) == NULL)
panic("MFS: couldn't find root inode\n"); panic("MFS: couldn't find root inode\n");
return(EINVAL);
}
if (count > 1) return(EBUSY); /* can't umount a busy file system */
put_inode(root_ip); put_inode(root_ip);
/* force any cached blocks out of memory */ /* force any cached blocks out of memory */
(void) fs_sync(); fs_sync();
/* Mark it clean if we're allowed to write _and_ it was clean originally. */ /* Mark it clean if we're allowed to write _and_ it was clean originally. */
if(cleanmount && !superblock.s_rd_only) { if (!superblock.s_rd_only) {
superblock.s_flags |= MFSFLAG_CLEAN; superblock.s_flags |= MFSFLAG_CLEAN;
write_super(&superblock); write_super(&superblock);
} }
@ -192,8 +161,5 @@ int fs_unmount()
/* Finish off the unmount. */ /* Finish off the unmount. */
superblock.s_dev = NO_DEV; superblock.s_dev = NO_DEV;
unmountdone = TRUE;
return(OK);
} }

View file

@ -1,47 +1,31 @@
#include "fs.h" #include "fs.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <string.h> #include <string.h>
#include <minix/com.h>
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include <minix/vfsif.h>
static struct inode *new_node(struct inode *ldirp, char *string, mode_t static struct inode *new_node(struct inode *ldirp, char *string, mode_t
bits, zone_t z0); bits, uid_t uid, gid_t gid, zone_t z0);
/*===========================================================================* /*===========================================================================*
* fs_create * * fs_create *
*===========================================================================*/ *===========================================================================*/
int fs_create() int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
struct fsdriver_node *node)
{ {
size_t len;
int r; int r;
struct inode *ldirp; struct inode *ldirp;
struct inode *rip; struct inode *rip;
mode_t omode;
char lastc[MFS_NAME_MAX];
/* Read request message */
omode = fs_m_in.m_vfs_fs_create.mode;
caller_uid = fs_m_in.m_vfs_fs_create.uid;
caller_gid = fs_m_in.m_vfs_fs_create.gid;
/* Try to make the file. */ /* Try to make the file. */
/* Copy the last component (i.e., file name) */
len = min(fs_m_in.m_vfs_fs_create.path_len, sizeof(lastc));
err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_create.grant,
(vir_bytes) 0, (vir_bytes) lastc, len);
if (err_code != OK) return err_code;
NUL(lastc, len, sizeof(lastc));
/* Get last directory inode (i.e., directory that will hold the new inode) */ /* Get last directory inode (i.e., directory that will hold the new inode) */
if ((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_create.inode)) == NULL) if ((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
return(ENOENT); return(EINVAL);
/* Create a new inode by calling new_node(). */ /* Create a new inode by calling new_node(). */
rip = new_node(ldirp, lastc, omode, NO_ZONE); rip = new_node(ldirp, name, mode, uid, gid, NO_ZONE);
r = err_code; r = err_code;
/* If an error occurred, release inode. */ /* If an error occurred, release inode. */
@ -52,13 +36,12 @@ int fs_create()
} }
/* Reply message */ /* Reply message */
fs_m_out.m_fs_vfs_create.inode = rip->i_num; node->fn_ino_nr = rip->i_num;
fs_m_out.m_fs_vfs_create.mode = rip->i_mode; node->fn_mode = rip->i_mode;
fs_m_out.m_fs_vfs_create.file_size = rip->i_size; node->fn_size = rip->i_size;
node->fn_uid = rip->i_uid;
/* These values are needed for the execution */ node->fn_gid = rip->i_gid;
fs_m_out.m_fs_vfs_create.uid = rip->i_uid; node->fn_dev = NO_DEV;
fs_m_out.m_fs_vfs_create.gid = rip->i_gid;
/* Drop parent dir */ /* Drop parent dir */
put_inode(ldirp); put_inode(ldirp);
@ -70,29 +53,17 @@ int fs_create()
/*===========================================================================* /*===========================================================================*
* fs_mknod * * fs_mknod *
*===========================================================================*/ *===========================================================================*/
int fs_mknod() int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
dev_t dev)
{ {
struct inode *ip, *ldirp; struct inode *ip, *ldirp;
char lastc[MFS_NAME_MAX];
phys_bytes len;
/* Copy the last component and set up caller's user and group id */
len = min(fs_m_in.m_vfs_fs_mknod.path_len, sizeof(lastc));
err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mknod.grant,
(vir_bytes) 0, (vir_bytes) lastc, (size_t) len);
if (err_code != OK) return err_code;
NUL(lastc, len, sizeof(lastc));
caller_uid = fs_m_in.m_vfs_fs_mknod.uid;
caller_gid = fs_m_in.m_vfs_fs_mknod.gid;
/* Get last directory inode */ /* Get last directory inode */
if((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_mknod.inode)) == NULL) if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
return(ENOENT); return(EINVAL);
/* Try to create the new node */ /* Try to create the new node */
ip = new_node(ldirp, lastc, fs_m_in.m_vfs_fs_mknod.mode, ip = new_node(ldirp, name, mode, uid, gid, (zone_t) dev);
(zone_t) fs_m_in.m_vfs_fs_mknod.device);
put_inode(ip); put_inode(ip);
put_inode(ldirp); put_inode(ldirp);
@ -103,30 +74,18 @@ int fs_mknod()
/*===========================================================================* /*===========================================================================*
* fs_mkdir * * fs_mkdir *
*===========================================================================*/ *===========================================================================*/
int fs_mkdir() int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
{ {
int r1, r2; /* status codes */ int r1, r2; /* status codes */
ino_t dot, dotdot; /* inode numbers for . and .. */ ino_t dot, dotdot; /* inode numbers for . and .. */
struct inode *rip, *ldirp; struct inode *rip, *ldirp;
char lastc[MFS_NAME_MAX]; /* last component */
phys_bytes len;
/* Copy the last component and set up caller's user and group id */
len = min(fs_m_in.m_vfs_fs_mkdir.path_len, sizeof(lastc));
err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mkdir.grant,
(vir_bytes) 0, (vir_bytes) lastc, (size_t) len);
if(err_code != OK) return(err_code);
NUL(lastc, len, sizeof(lastc));
caller_uid = fs_m_in.m_vfs_fs_mkdir.uid;
caller_gid = fs_m_in.m_vfs_fs_mkdir.gid;
/* Get last directory inode */ /* Get last directory inode */
if((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_mkdir.inode)) == NULL) if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
return(ENOENT); return(EINVAL);
/* Next make the inode. If that fails, return error code. */ /* Next make the inode. If that fails, return error code. */
rip = new_node(ldirp, lastc, fs_m_in.m_vfs_fs_mkdir.mode, (zone_t) 0); rip = new_node(ldirp, name, mode, uid, gid, (zone_t) 0);
if(rip == NULL || err_code == EEXIST) { if(rip == NULL || err_code == EEXIST) {
put_inode(rip); /* can't make dir: it already exists */ put_inode(rip); /* can't make dir: it already exists */
@ -139,11 +98,8 @@ int fs_mkdir()
dot = rip->i_num; /* inode number of the new dir itself */ dot = rip->i_num; /* inode number of the new dir itself */
/* Now make dir entries for . and .. unless the disk is completely full. */ /* Now make dir entries for . and .. unless the disk is completely full. */
/* Use dot1 and dot2, so the mode of the directory isn't important. */ r1 = search_dir(rip, ".", &dot, ENTER); /* enter . in the new dir */
rip->i_mode = fs_m_in.m_vfs_fs_mkdir.mode; /* set mode */ r2 = search_dir(rip, "..", &dotdot, ENTER); /* enter .. in the new dir */
r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM);/* enter . in the new dir*/
r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM); /* enter .. in the new
dir */
/* If both . and .. were successfully entered, increment the link counts. */ /* If both . and .. were successfully entered, increment the link counts. */
if (r1 == OK && r2 == OK) { if (r1 == OK && r2 == OK) {
@ -154,7 +110,7 @@ int fs_mkdir()
} else { } else {
/* It was not possible to enter . or .. probably disk was full - /* It was not possible to enter . or .. probably disk was full -
* links counts haven't been touched. */ * links counts haven't been touched. */
if(search_dir(ldirp, lastc, NULL, DELETE, IGN_PERM) != OK) if(search_dir(ldirp, name, NULL, DELETE) != OK)
panic("Dir disappeared: %llu", rip->i_num); panic("Dir disappeared: %llu", rip->i_num);
rip->i_nlinks--; /* undo the increment done in new_node() */ rip->i_nlinks--; /* undo the increment done in new_node() */
} }
@ -169,54 +125,39 @@ int fs_mkdir()
/*===========================================================================* /*===========================================================================*
* fs_slink * * fs_slink *
*===========================================================================*/ *===========================================================================*/
int fs_slink() int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
struct fsdriver_data *data, size_t bytes)
{ {
phys_bytes len;
struct inode *sip; /* inode containing symbolic link */ struct inode *sip; /* inode containing symbolic link */
struct inode *ldirp; /* directory containing link */ struct inode *ldirp; /* directory containing link */
register int r; /* error code */ register int r; /* error code */
char string[MFS_NAME_MAX]; /* last component of the new dir's path name */
struct buf *bp; /* disk buffer for link */ struct buf *bp; /* disk buffer for link */
caller_uid = fs_m_in.m_vfs_fs_slink.uid;
caller_gid = fs_m_in.m_vfs_fs_slink.gid;
/* Copy the link name's last component */
len = min( (unsigned) fs_m_in.m_vfs_fs_slink.path_len, sizeof(string));
r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_slink.grant_path,
(vir_bytes) 0, (vir_bytes) string, (size_t) len);
if (r != OK) return(r);
NUL(string, len, sizeof(string));
/* Temporarily open the dir. */ /* Temporarily open the dir. */
if( (ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_slink.inode)) == NULL) if( (ldirp = get_inode(fs_dev, dir_nr)) == NULL)
return(EINVAL); return(EINVAL);
/* Create the inode for the symlink. */ /* Create the inode for the symlink. */
sip = new_node(ldirp, string, (I_SYMBOLIC_LINK | RWX_MODES), 0); sip = new_node(ldirp, name, (I_SYMBOLIC_LINK | RWX_MODES), uid, gid, 0);
/* Allocate a disk block for the contents of the symlink. /* Allocate a disk block for the contents of the symlink.
* Copy contents of symlink (the name pointed to) into first disk block. */ * Copy contents of symlink (the name pointed to) into first disk block. */
if( (r = err_code) == OK) { if( (r = err_code) == OK) {
size_t namelen = fs_m_in.m_vfs_fs_slink.mem_size;
bp = new_block(sip, (off_t) 0); bp = new_block(sip, (off_t) 0);
if (bp == NULL) if (bp == NULL)
r = err_code; r = err_code;
else { else {
if(get_block_size(sip->i_dev) <= namelen) { if(get_block_size(sip->i_dev) <= bytes) {
r = ENAMETOOLONG; r = ENAMETOOLONG;
} else { } else {
r = sys_safecopyfrom(VFS_PROC_NR, r = fsdriver_copyin(data, 0, b_data(bp), bytes);
fs_m_in.m_vfs_fs_slink.grant_target, b_data(bp)[bytes] = '\0';
(vir_bytes) 0, (vir_bytes) b_data(bp),
namelen);
b_data(bp)[namelen] = '\0';
} }
} }
if(bp != NULL && r == OK) { if(bp != NULL && r == OK) {
sip->i_size = (off_t) strlen(b_data(bp)); sip->i_size = (off_t) strlen(b_data(bp));
if(sip->i_size != fs_m_in.m_vfs_fs_slink.mem_size) { if(sip->i_size != bytes) {
/* This can happen if the user provides a buffer /* This can happen if the user provides a buffer
* with a \0 in it. This can cause a lot of trouble * with a \0 in it. This can cause a lot of trouble
* when the symlink is used later. We could just use * when the symlink is used later. We could just use
@ -233,7 +174,7 @@ int fs_slink()
if(r != OK) { if(r != OK) {
sip->i_nlinks = NO_LINK; sip->i_nlinks = NO_LINK;
if(search_dir(ldirp, string, NULL, DELETE, IGN_PERM) != OK) if(search_dir(ldirp, name, NULL, DELETE) != OK)
panic("Symbolic link vanished"); panic("Symbolic link vanished");
} }
} }
@ -249,7 +190,7 @@ int fs_slink()
* new_node * * new_node *
*===========================================================================*/ *===========================================================================*/
static struct inode *new_node(struct inode *ldirp, static struct inode *new_node(struct inode *ldirp,
char *string, mode_t bits, zone_t z0) char *string, mode_t bits, uid_t uid, gid_t gid, zone_t z0)
{ {
/* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir(). /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
* In all cases it allocates a new inode, makes a directory entry for it in * In all cases it allocates a new inode, makes a directory entry for it in
@ -261,7 +202,6 @@ static struct inode *new_node(struct inode *ldirp,
* The parsed path rest is returned in 'parsed' if parsed is nonzero. It * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
* has to hold at least MFS_NAME_MAX bytes. * has to hold at least MFS_NAME_MAX bytes.
*/ */
register struct inode *rip; register struct inode *rip;
register int r; register int r;
@ -270,19 +210,18 @@ static struct inode *new_node(struct inode *ldirp,
return(NULL); return(NULL);
} }
/* Get final component of the path. */
rip = advance(ldirp, string, IGN_PERM);
if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) { if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) {
/* New entry is a directory, alas we can't give it a ".." */ /* New entry is a directory, alas we can't give it a ".." */
put_inode(rip);
err_code = EMLINK; err_code = EMLINK;
return(NULL); return(NULL);
} }
/* Get final component of the path. */
rip = advance(ldirp, string);
if ( rip == NULL && err_code == ENOENT) { if ( rip == NULL && err_code == ENOENT) {
/* Last path component does not exist. Make new directory entry. */ /* Last path component does not exist. Make new directory entry. */
if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NULL) { if ( (rip = alloc_inode((ldirp)->i_dev, bits, uid, gid)) == NULL) {
/* Can't creat new inode: out of inodes. */ /* Can't creat new inode: out of inodes. */
return(NULL); return(NULL);
} }
@ -296,7 +235,7 @@ static struct inode *new_node(struct inode *ldirp,
rw_inode(rip, WRITING); /* force inode to disk now */ rw_inode(rip, WRITING); /* force inode to disk now */
/* New inode acquired. Try to make directory entry. */ /* New inode acquired. Try to make directory entry. */
if((r=search_dir(ldirp, string, &rip->i_num, ENTER, IGN_PERM)) != OK) { if((r=search_dir(ldirp, string, &rip->i_num, ENTER)) != OK) {
rip->i_nlinks--; /* pity, have to free disk inode */ rip->i_nlinks--; /* pity, have to free disk inode */
IN_MARKDIRTY(rip); /* dirty inodes are written out */ IN_MARKDIRTY(rip); /* dirty inodes are written out */
put_inode(rip); /* this call frees the inode */ put_inode(rip); /* this call frees the inode */
@ -304,8 +243,6 @@ static struct inode *new_node(struct inode *ldirp,
return(NULL); return(NULL);
} }
} else if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) {
r = EEXIST;
} else { } else {
/* Either last component exists, or there is some problem. */ /* Either last component exists, or there is some problem. */
if (rip != NULL) if (rip != NULL)
@ -321,18 +258,13 @@ static struct inode *new_node(struct inode *ldirp,
/*===========================================================================* /*===========================================================================*
* fs_inhibread * * fs_seek *
*===========================================================================*/ *===========================================================================*/
int fs_inhibread() void fs_seek(ino_t ino_nr)
{ {
struct inode *rip; struct inode *rip;
if((rip = find_inode(fs_dev, fs_m_in.m_vfs_fs_inhibread.inode)) == NULL)
return(EINVAL);
/* inhibit read ahead */ /* inhibit read ahead */
if ((rip = find_inode(fs_dev, ino_nr)) != NULL)
rip->i_seek = ISEEK; rip->i_seek = ISEEK;
return(OK);
} }

View file

@ -1,355 +1,53 @@
/* This file contains the procedures that look up path names in the directory /* This file contains the procedures that look up path names in the directory
* system and determine the inode number that goes with a given path name. * system and determine the inode number that goes with a given path name.
*
* The entry points into this file are
* eat_path: the 'main' routine of the path-to-inode conversion mechanism
* 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 "fs.h"
#include "assert.h" #include <assert.h>
#include <string.h> #include <string.h>
#include <minix/endpoint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include <minix/vfsif.h>
#include <minix/libminixfs.h>
char dot1[2] = "."; /* used for search_dir to bypass the access */
char dot2[3] = ".."; /* permissions for . and .. */
static char *get_name(char *name, char string[MFS_NAME_MAX+1]);
static int ltraverse(struct inode *rip, char *suffix);
static int parse_path(ino_t dir_ino, ino_t root_ino, int flags, struct
inode **res_inop, size_t *offsetp, int *symlinkp);
/*===========================================================================* /*===========================================================================*
* fs_lookup * * fs_lookup *
*===========================================================================*/ *===========================================================================*/
int fs_lookup() int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
int *is_mountpt)
{ {
cp_grant_id_t grant; struct inode *dirp, *rip;
int r, r1, flags, symlinks;
unsigned int len;
size_t offset = 0, path_size;
ino_t dir_ino, root_ino;
struct inode *rip;
grant = fs_m_in.m_vfs_fs_lookup.grant_path; /* Find the starting inode. */
path_size = fs_m_in.m_vfs_fs_lookup.path_size; /* Size of the buffer */ if ((dirp = find_inode(fs_dev, dir_nr)) == NULL)
len = fs_m_in.m_vfs_fs_lookup.path_len; /* including terminating nul */ return EINVAL;
dir_ino = fs_m_in.m_vfs_fs_lookup.dir_ino;
root_ino = fs_m_in.m_vfs_fs_lookup.root_ino;
flags = fs_m_in.m_vfs_fs_lookup.flags;
/* Check length. */ /* Look up the directory entry. */
if(len > sizeof(user_path)) return(E2BIG); /* too big for buffer */ if ((rip = advance(dirp, name)) == NULL)
if(len == 0) return(EINVAL); /* too small */ return err_code;
/* Copy the pathname and set up caller's user and group id */
r = sys_safecopyfrom(VFS_PROC_NR, grant, /*offset*/ (vir_bytes) 0,
(vir_bytes) user_path, (size_t) len);
if(r != OK) return(r);
/* Verify this is a null-terminated path. */
if(user_path[len - 1] != '\0') return(EINVAL);
memset(&credentials, 0, sizeof(credentials));
if(!(flags & PATH_GET_UCRED)) { /* Do we have to copy uid/gid credentials? */
caller_uid = fs_m_in.m_vfs_fs_lookup.uid;
caller_gid = fs_m_in.m_vfs_fs_lookup.gid;
} else {
if((r=fs_lookup_credentials(&credentials,
&caller_uid, &caller_gid,
fs_m_in.m_vfs_fs_lookup.grant_ucred,
fs_m_in.m_vfs_fs_lookup.ucred_size)) != OK)
return r;
}
/* Lookup inode */
rip = NULL;
r = parse_path(dir_ino, root_ino, flags, &rip, &offset, &symlinks);
if(symlinks != 0 && (r == ELEAVEMOUNT || r == EENTERMOUNT || r == ESYMLINK)){
len = strlen(user_path)+1;
if(len > path_size) return(ENAMETOOLONG);
r1 = sys_safecopyto(VFS_PROC_NR, grant, (vir_bytes) 0,
(vir_bytes) user_path, (size_t) len);
if(r1 != OK) return(r1);
}
if(r == ELEAVEMOUNT || r == ESYMLINK) {
/* Report offset and the error */
fs_m_out.m_fs_vfs_lookup.offset = offset;
fs_m_out.m_fs_vfs_lookup.symloop = symlinks;
return(r);
}
if (r != OK && r != EENTERMOUNT) return(r);
fs_m_out.m_fs_vfs_lookup.inode = rip->i_num;
fs_m_out.m_fs_vfs_lookup.mode = rip->i_mode;
fs_m_out.m_fs_vfs_lookup.file_size = rip->i_size;
fs_m_out.m_fs_vfs_lookup.symloop = symlinks;
fs_m_out.m_fs_vfs_lookup.uid = rip->i_uid;
fs_m_out.m_fs_vfs_lookup.gid = rip->i_gid;
/* On success, leave the resulting inode open and return its details. */
node->fn_ino_nr = rip->i_num;
node->fn_mode = rip->i_mode;
node->fn_size = rip->i_size;
node->fn_uid = rip->i_uid;
node->fn_gid = rip->i_gid;
/* This is only valid for block and character specials. But it doesn't /* This is only valid for block and character specials. But it doesn't
* cause any harm to always set the device field. */ * cause any harm to always set the device field. */
fs_m_out.m_fs_vfs_lookup.device = (dev_t) rip->i_zone[0]; node->fn_dev = (dev_t) rip->i_zone[0];
if(r == EENTERMOUNT) { *is_mountpt = rip->i_mountpoint;
fs_m_out.m_fs_vfs_lookup.offset = offset;
put_inode(rip); /* Only return a reference to the final object */
}
return(r); return OK;
}
/*===========================================================================*
* parse_path *
*===========================================================================*/
static int parse_path(
ino_t dir_ino,
ino_t root_ino,
int flags,
struct inode **res_inop,
size_t *offsetp,
int *symlinkp
) {
/* Parse the path in user_path, starting at dir_ino. If the path is the empty
* string, just return dir_ino. It is upto the caller to treat an empty
* path in a special way. Otherwise, if the path consists of just one or
* more slash ('/') characters, the path is replaced with ".". Otherwise,
* just look up the first (or only) component in path after skipping any
* leading slashes.
*/
int r, leaving_mount;
struct inode *rip, *dir_ip;
char *cp, *next_cp; /* component and next component */
char component[MFS_NAME_MAX+1];
/* Start parsing path at the first component in user_path */
cp = user_path;
/* No symlinks encountered yet */
*symlinkp = 0;
/* Find starting inode inode according to the request message */
if((rip = find_inode(fs_dev, dir_ino)) == NULL)
return(ENOENT);
/* If dir has been removed return ENOENT. */
if (rip->i_nlinks == NO_LINK) return(ENOENT);
dup_inode(rip);
/* If the given start inode is a mountpoint, we must be here because the file
* system mounted on top returned an ELEAVEMOUNT error. In this case, we must
* only accept ".." as the first path component.
*/
leaving_mount = rip->i_mountpoint; /* True iff rip is a mountpoint */
/* Scan the path component by component. */
while (TRUE) {
if(cp[0] == '\0') {
/* We're done; either the path was empty or we've parsed all
components of the path */
*res_inop = rip;
*offsetp += cp - user_path;
/* Return EENTERMOUNT if we are at a mount point */
if (rip->i_mountpoint) return(EENTERMOUNT);
return(OK);
}
while(cp[0] == '/') cp++;
next_cp = get_name(cp, component);
/* Special code for '..'. A process is not allowed to leave a chrooted
* environment. A lookup of '..' at the root of a mounted filesystem
* has to return ELEAVEMOUNT. In both cases, the caller needs search
* permission for the current inode, as it is used as directory.
*/
if(strcmp(component, "..") == 0) {
/* 'rip' is now accessed as directory */
if ((r = forbidden(rip, X_BIT)) != OK) {
put_inode(rip);
return(r);
}
if (rip->i_num == root_ino) {
cp = next_cp;
continue; /* Ignore the '..' at a process' root
and move on to the next component */
}
if (rip->i_num == ROOT_INODE && !rip->i_sp->s_is_root) {
/* Climbing up to parent FS */
put_inode(rip);
*offsetp += cp - user_path;
return(ELEAVEMOUNT);
}
}
/* Only check for a mount point if we are not coming from one. */
if (!leaving_mount && rip->i_mountpoint) {
/* Going to enter a child FS */
*res_inop = rip;
*offsetp += cp - user_path;
return(EENTERMOUNT);
}
/* There is more path. Keep parsing.
* If we're leaving a mountpoint, skip directory permission checks.
*/
dir_ip = rip;
rip = advance(dir_ip, leaving_mount ? dot2 : component, CHK_PERM);
if(err_code == ELEAVEMOUNT || err_code == EENTERMOUNT)
err_code = OK;
if (err_code != OK) {
put_inode(dir_ip);
return(err_code);
}
leaving_mount = 0;
/* The call to advance() succeeded. Fetch next component. */
if (S_ISLNK(rip->i_mode)) {
if (next_cp[0] == '\0' && (flags & PATH_RET_SYMLINK)) {
put_inode(dir_ip);
*res_inop = rip;
*offsetp += next_cp - user_path;
return(OK);
}
/* Extract path name from the symlink file */
r = ltraverse(rip, next_cp);
next_cp = user_path;
*offsetp = 0;
/* Symloop limit reached? */
if (++(*symlinkp) > _POSIX_SYMLOOP_MAX)
r = ELOOP;
if (r != OK) {
put_inode(dir_ip);
put_inode(rip);
return(r);
}
if (next_cp[0] == '/') {
put_inode(dir_ip);
put_inode(rip);
return(ESYMLINK);
}
put_inode(rip);
dup_inode(dir_ip);
rip = dir_ip;
}
put_inode(dir_ip);
cp = next_cp; /* Process subsequent component in next round */
}
}
/*===========================================================================*
* ltraverse *
*===========================================================================*/
static int ltraverse(rip, suffix)
register struct inode *rip; /* symbolic link */
char *suffix; /* current remaining path. Has to point in the
* user_path buffer
*/
{
/* Traverse a symbolic link. Copy the link text from the inode and insert
* the text into the path. Return error code or report success. Base
* directory has to be determined according to the first character of the
* new pathname.
*/
size_t llen; /* length of link */
size_t slen; /* length of suffix */
struct buf *bp; /* buffer containing link text */
char *sp; /* start of link text */
if(!(bp = get_block_map(rip, 0)))
return(EIO);
llen = (size_t) rip->i_size;
sp = b_data(bp);
slen = strlen(suffix);
/* The path we're parsing looks like this:
* /already/processed/path/<link> or
* /already/processed/path/<link>/not/yet/processed/path
* After expanding the <link>, the path will look like
* <expandedlink> or
* <expandedlink>/not/yet/processed
* In both cases user_path must have enough room to hold <expandedlink>.
* However, in the latter case we have to move /not/yet/processed to the
* right place first, before we expand <link>. When strlen(<expandedlink>) is
* smaller than strlen(/already/processes/path), we move the suffix to the
* left. Is strlen(<expandedlink>) greater then we move it to the right. Else
* we do nothing.
*/
if (slen > 0) { /* Do we have path after the link? */
/* For simplicity we require that suffix starts with a slash */
if (suffix[0] != '/') {
panic("ltraverse: suffix does not start with a slash");
}
/* To be able to expand the <link>, we have to move the 'suffix'
* to the right place.
*/
if (slen + llen + 1 > sizeof(user_path))
return(ENAMETOOLONG);/* <expandedlink>+suffix+\0 does not fit*/
if ((unsigned) (suffix-user_path) != llen) {
/* Move suffix left or right */
memmove(&user_path[llen], suffix, slen+1);
}
} else {
if (llen + 1 > sizeof(user_path))
return(ENAMETOOLONG); /* <expandedlink> + \0 does not fix */
/* Set terminating nul */
user_path[llen]= '\0';
}
/* Everything is set, now copy the expanded link to user_path */
memmove(user_path, sp, llen);
put_block(bp, DIRECTORY_BLOCK);
return(OK);
} }
/*===========================================================================* /*===========================================================================*
* advance * * advance *
*===========================================================================*/ *===========================================================================*/
struct inode *advance(dirp, string, chk_perm) struct inode *advance(dirp, string)
struct inode *dirp; /* inode for directory to be searched */ struct inode *dirp; /* inode for directory to be searched */
char string[MFS_NAME_MAX]; /* component name to look for */ const char *string; /* component name to look for */
int chk_perm; /* check permissions when string is looked up*/
{ {
/* Given a directory and a component of a path, look up the component in /* Given a directory and a component of a path, look up the component in
* the directory, find the inode, open it, and return a pointer to its inode * the directory, find the inode, open it, and return a pointer to its inode
@ -358,114 +56,44 @@ int chk_perm; /* check permissions when string is looked up*/
ino_t numb; ino_t numb;
struct inode *rip; struct inode *rip;
assert(dirp != NULL);
/* If 'string' is empty, return an error. */ /* If 'string' is empty, return an error. */
if (string[0] == '\0') { if (string[0] == '\0') {
err_code = ENOENT; err_code = ENOENT;
return(NULL); return(NULL);
} }
/* Check for NULL. */ /* If dir has been removed return ENOENT. */
if (dirp == NULL) return(NULL); if (dirp->i_nlinks == NO_LINK) {
err_code = ENOENT;
return(NULL);
}
/* If 'string' is not present in the directory, signal error. */ /* If 'string' is not present in the directory, signal error. */
if ( (err_code = search_dir(dirp, string, &numb, LOOK_UP, chk_perm)) != OK) { if ( (err_code = search_dir(dirp, string, &numb, LOOK_UP)) != OK) {
return(NULL); return(NULL);
} }
/* The component has been found in the directory. Get inode. */ /* The component has been found in the directory. Get inode. */
if ( (rip = get_inode(dirp->i_dev, (int) numb)) == NULL) { if ( (rip = get_inode(dirp->i_dev, (int) numb)) == NULL) {
assert(err_code != OK);
return(NULL); return(NULL);
} }
/* The following test is for "mountpoint/.." where mountpoint is a assert(err_code == OK);
* 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] == '.') {
if (!rip->i_sp->s_is_root) {
/* Climbing up mountpoint */
err_code = ELEAVEMOUNT;
}
}
}
}
/* See if the inode is mounted on. If so, switch to root directory of the
* mounted file system. The super_block provides the linkage between the
* inode mounted on and the root directory of the mounted file system.
*/
if (rip->i_mountpoint) {
/* Mountpoint encountered, report it */
err_code = EENTERMOUNT;
}
return(rip); return(rip);
} }
/*===========================================================================*
* get_name *
*===========================================================================*/
static char *get_name(path_name, string)
char *path_name; /* path name to parse */
char string[MFS_NAME_MAX+1]; /* component extracted from 'old_name' */
{
/* Given a pointer to a path name in fs space, 'path_name', copy the first
* component to 'string' (truncated if necessary, always nul terminated).
* A pointer to the string after the first component of the name as yet
* unparsed is returned. Roughly speaking,
* 'get_name' = 'path_name' - 'string'.
*
* This routine follows the standard convention that /usr/ast, /usr//ast,
* //usr///ast and /usr/ast/ are all equivalent.
*/
size_t len;
char *cp, *ep;
cp = path_name;
/* Skip leading slashes */
while (cp[0] == '/') cp++;
/* Find the end of the first component */
ep = cp;
while(ep[0] != '\0' && ep[0] != '/')
ep++;
len = (size_t) (ep - cp);
/* Truncate the amount to be copied if it exceeds MFS_NAME_MAX */
if (len > MFS_NAME_MAX) len = MFS_NAME_MAX;
/* Special case of the string at cp is empty */
if (len == 0)
strlcpy(string, ".", MFS_NAME_MAX + 1); /* Return "." */
else {
memcpy(string, cp, len);
string[len]= '\0';
}
return(ep);
}
/*===========================================================================* /*===========================================================================*
* search_dir * * search_dir *
*===========================================================================*/ *===========================================================================*/
int search_dir(ldir_ptr, string, numb, flag, check_permissions) int search_dir(ldir_ptr, string, numb, flag)
register struct inode *ldir_ptr; /* ptr to inode for dir to search */ register struct inode *ldir_ptr; /* ptr to inode for dir to search */
char string[MFS_NAME_MAX]; /* component to search for */ const char *string; /* component to search for */
ino_t *numb; /* pointer to inode number */ ino_t *numb; /* pointer to inode number */
int flag; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */ int flag; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
int check_permissions; /* check permissions when flag is !IS_EMPTY */
{ {
/* This function searches the directory whose inode is pointed to by 'ldip': /* This function searches the directory whose inode is pointed to by 'ldip':
* if (flag == ENTER) enter 'string' in the directory with inode # '*numb'; * if (flag == ENTER) enter 'string' in the directory with inode # '*numb';
@ -473,13 +101,12 @@ int check_permissions; /* check permissions when flag is !IS_EMPTY */
* if (flag == LOOK_UP) search for 'string' and return inode # in 'numb'; * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb';
* if (flag == IS_EMPTY) return OK if only . and .. in dir else ENOTEMPTY; * if (flag == IS_EMPTY) return OK if only . and .. in dir else ENOTEMPTY;
* *
* if 'string' is dot1 or dot2, no access permissions are checked. * This function, and this function alone, implements name truncation,
* by simply considering only the first MFS_NAME_MAX bytes from 'string'.
*/ */
register struct direct *dp = NULL; register struct direct *dp = NULL;
register struct buf *bp = NULL; register struct buf *bp = NULL;
int i, r, e_hit, t, match; int i, r, e_hit, t, match;
mode_t bits;
off_t pos; off_t pos;
unsigned new_slots, old_slots; unsigned new_slots, old_slots;
struct super_block *sp; struct super_block *sp;
@ -493,20 +120,6 @@ int check_permissions; /* check permissions when flag is !IS_EMPTY */
if((flag == DELETE || flag == ENTER) && ldir_ptr->i_sp->s_rd_only) if((flag == DELETE || flag == ENTER) && ldir_ptr->i_sp->s_rd_only)
return EROFS; return EROFS;
r = OK;
if (flag != IS_EMPTY) {
bits = (flag == LOOK_UP ? X_BIT : W_BIT | X_BIT);
if (string == dot1 || string == dot2) {
if (flag != LOOK_UP) r = read_only(ldir_ptr);
/* only a writable device is required. */
} else if(check_permissions) {
r = forbidden(ldir_ptr, bits); /* check access permissions */
}
}
if (r != OK) return(r);
/* Step through the directory one block at a time. */ /* Step through the directory one block at a time. */
old_slots = (unsigned) (ldir_ptr->i_size/DIR_ENTRY_SIZE); old_slots = (unsigned) (ldir_ptr->i_size/DIR_ENTRY_SIZE);
new_slots = 0; new_slots = 0;
@ -543,7 +156,8 @@ int check_permissions; /* check permissions when flag is !IS_EMPTY */
if (flag == IS_EMPTY) { if (flag == IS_EMPTY) {
/* If this test succeeds, dir is not empty. */ /* If this test succeeds, dir is not empty. */
if (strcmp(dp->mfs_d_name, "." ) != 0 && if (strcmp(dp->mfs_d_name, "." ) != 0 &&
strcmp(dp->mfs_d_name, "..") != 0) match = 1; strcmp(dp->mfs_d_name, "..") != 0)
match = 1;
} else { } else {
if (strncmp(dp->mfs_d_name, string, if (strncmp(dp->mfs_d_name, string,
sizeof(dp->mfs_d_name)) == 0){ sizeof(dp->mfs_d_name)) == 0){

View file

@ -1 +0,0 @@

View file

@ -1,25 +1,18 @@
#include "fs.h" #include "fs.h"
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include <minix/vfsif.h>
static int in_group(gid_t grp);
/*===========================================================================* /*===========================================================================*
* fs_chmod * * fs_chmod *
*===========================================================================*/ *===========================================================================*/
int fs_chmod() int fs_chmod(ino_t ino_nr, mode_t *mode)
{ {
/* Perform the chmod(name, mode) system call. */ /* Perform the chmod(name, mode) system call. */
register struct inode *rip; register struct inode *rip;
mode_t mode;
mode = fs_m_in.m_vfs_fs_chmod.mode;
/* Temporarily open the file. */ /* Temporarily open the file. */
if( (rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_chmod.inode)) == NULL) if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
if(rip->i_sp->s_rd_only) { if(rip->i_sp->s_rd_only) {
@ -28,12 +21,12 @@ int fs_chmod()
} }
/* Now make the change. Clear setgid bit if file is not in caller's grp */ /* Now make the change. Clear setgid bit if file is not in caller's grp */
rip->i_mode = (rip->i_mode & ~ALL_MODES) | (mode & ALL_MODES); rip->i_mode = (rip->i_mode & ~ALL_MODES) | (*mode & ALL_MODES);
rip->i_update |= CTIME; rip->i_update |= CTIME;
IN_MARKDIRTY(rip); IN_MARKDIRTY(rip);
/* Return full new mode to caller. */ /* Return full new mode to caller. */
fs_m_out.m_fs_vfs_chmod.mode = rip->i_mode; *mode = rip->i_mode;
put_inode(rip); put_inode(rip);
return(OK); return(OK);
@ -43,116 +36,23 @@ int fs_chmod()
/*===========================================================================* /*===========================================================================*
* fs_chown * * fs_chown *
*===========================================================================*/ *===========================================================================*/
int fs_chown() int fs_chown(ino_t ino_nr, uid_t uid, gid_t gid, mode_t *mode)
{ {
register struct inode *rip; register struct inode *rip;
register int r;
/* Temporarily open the file. */ /* Temporarily open the file. */
if( (rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_chown.inode)) == NULL) if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
/* Not permitted to change the owner of a file on a read-only file sys. */ rip->i_uid = uid;
r = read_only(rip); rip->i_gid = gid;
if (r == OK) {
rip->i_uid = fs_m_in.m_vfs_fs_chown.uid;
rip->i_gid = fs_m_in.m_vfs_fs_chown.gid;
rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT); rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
rip->i_update |= CTIME; rip->i_update |= CTIME;
IN_MARKDIRTY(rip); IN_MARKDIRTY(rip);
}
/* Update caller on current mode, as it may have changed. */ /* Update caller on current mode, as it may have changed. */
fs_m_out.m_fs_vfs_chown.mode = rip->i_mode; *mode = rip->i_mode;
put_inode(rip); put_inode(rip);
return(r);
}
/*===========================================================================*
* forbidden *
*===========================================================================*/
int forbidden(struct inode *rip, mode_t access_desired)
{
/* Given a pointer to an inode, 'rip', and the access desired, determine
* if the access is allowed, and if not why not. The routine looks up the
* caller's uid in the 'fproc' table. If access is allowed, OK is returned
* if it is forbidden, EACCES is returned.
*/
register struct inode *old_rip = rip;
mode_t bits, perm_bits;
int r, shift;
/* Isolate the relevant rwx bits from the mode. */
bits = rip->i_mode;
if (caller_uid == SU_UID) {
/* Grant read and write permission. Grant search permission for
* directories. Grant execute permission (for non-directories) if
* and only if one of the 'X' bits is set.
*/
if ( (bits & I_TYPE) == I_DIRECTORY ||
bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
perm_bits = R_BIT | W_BIT | X_BIT;
else
perm_bits = R_BIT | W_BIT;
} else {
if (caller_uid == rip->i_uid) shift = 6; /* owner */
else if (caller_gid == rip->i_gid) shift = 3; /* group */
else if (in_group(rip->i_gid) == OK) shift = 3; /* other groups */
else shift = 0; /* other */
perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
}
/* If access desired is not a subset of what is allowed, it is refused. */
r = OK;
if ((perm_bits | access_desired) != perm_bits) r = EACCES;
/* Check to see if someone is trying to write on a file system that is
* mounted read-only.
*/
if (r == OK)
if (access_desired & W_BIT)
r = read_only(rip);
if (rip != old_rip) put_inode(rip);
return(r);
}
/*===========================================================================*
* in_group *
*===========================================================================*/
static int in_group(gid_t grp)
{
int i;
if (credentials.vu_ngroups > NGROUPS_MAX)
return(EINVAL);
for (i = 0; i < credentials.vu_ngroups; i++)
if (credentials.vu_sgroups[i] == grp)
return(OK); return(OK);
return(EINVAL);
} }
/*===========================================================================*
* read_only *
*===========================================================================*/
int read_only(ip)
struct inode *ip; /* ptr to inode whose file sys is to be cked */
{
/* Check to see if the file system on which the inode 'ip' resides is mounted
* read only. If so, return EROFS, else return OK.
*/
register struct super_block *sp;
sp = ip->i_sp;
return(sp->s_rd_only ? EROFS : OK);
}

View file

@ -13,16 +13,15 @@ struct filp;
struct inode; struct inode;
struct super_block; struct super_block;
/* cache.c */ /* cache.c */
zone_t alloc_zone(dev_t dev, zone_t z); zone_t alloc_zone(dev_t dev, zone_t z);
void free_zone(dev_t dev, zone_t numb); void free_zone(dev_t dev, zone_t numb);
/* inode.c */ /* inode.c */
struct inode *alloc_inode(dev_t dev, mode_t bits); struct inode *alloc_inode(dev_t dev, mode_t bits, uid_t uid, gid_t gid);
void dup_inode(struct inode *ip); void dup_inode(struct inode *ip);
struct inode *find_inode(dev_t dev, ino_t numb); struct inode *find_inode(dev_t dev, ino_t numb);
int fs_putnode(void); int fs_putnode(ino_t ino_nr, unsigned int count);
void init_inode_cache(void); void init_inode_cache(void);
struct inode *get_inode(dev_t dev, ino_t numb); struct inode *get_inode(dev_t dev, ino_t numb);
void put_inode(struct inode *rip); void put_inode(struct inode *rip);
@ -30,57 +29,56 @@ void update_times(struct inode *rip);
void rw_inode(struct inode *rip, int rw_flag); void rw_inode(struct inode *rip, int rw_flag);
/* link.c */ /* link.c */
int fs_ftrunc(void); int fs_trunc(ino_t ino_nr, off_t start, off_t end);
int fs_link(void); int fs_link(ino_t dir_nr, char *name, ino_t ino_nr);
int fs_rdlink(void); ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes);
int fs_rename(void); int fs_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
int fs_unlink(void); char *new_name);
int fs_unlink(ino_t dir_nr, char *name, int call);
int truncate_inode(struct inode *rip, off_t len); int truncate_inode(struct inode *rip, off_t len);
/* misc.c */ /* misc.c */
int fs_flush(void); void fs_sync(void);
int fs_sync(void);
int fs_new_driver(void);
int fs_bpeek(void);
/* mount.c */ /* mount.c */
int fs_mountpoint(void); int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
int fs_readsuper(void); unsigned int *res_flags);
int fs_unmount(void); void fs_unmount(void);
int fs_mountpt(ino_t ino_nr);
/* open.c */ /* open.c */
int fs_create(void); int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
int fs_inhibread(void); struct fsdriver_node *node);
int fs_mkdir(void); int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid);
int fs_mknod(void); int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
int fs_slink(void); dev_t dev);
int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
struct fsdriver_data *data, size_t bytes);
void fs_seek(ino_t ino_nr);
/* path.c */ /* path.c */
int fs_lookup(void); int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
struct inode *advance(struct inode *dirp, char string[MFS_NAME_MAX], int int *is_mountpt);
chk_perm); struct inode *advance(struct inode *dirp, const char *string);
int search_dir(struct inode *ldir_ptr, char string [MFS_NAME_MAX], ino_t int search_dir(struct inode *ldir_ptr, const char *string, ino_t *numb,
*numb, int flag, int check_permissions); int flag);
/* protect.c */ /* protect.c */
int fs_chmod(void); int fs_chmod(ino_t ino, mode_t *mode);
int fs_chown(void); int fs_chown(ino_t ino, uid_t uid, gid_t gid, mode_t *mode);
int fs_getdents(void);
int forbidden(struct inode *rip, mode_t access_desired);
int read_only(struct inode *ip);
/* read.c */ /* read.c */
int fs_breadwrite(void); ssize_t fs_readwrite(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
int fs_readwrite(void); off_t pos, int call);
void read_ahead(void);
block_t read_map(struct inode *rip, off_t pos, int opportunistic); block_t read_map(struct inode *rip, off_t pos, int opportunistic);
struct buf *get_block_map(register struct inode *rip, u64_t position); struct buf *get_block_map(register struct inode *rip, u64_t position);
zone_t rd_indir(struct buf *bp, int index); zone_t rd_indir(struct buf *bp, int index);
ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
off_t *posp);
/* stadir.c */ /* stadir.c */
int fs_stat(void); int fs_stat(ino_t ino_nr, struct stat *statbuf);
int fs_statvfs(void); int fs_statvfs(struct statvfs *st);
/* super.c */ /* super.c */
bit_t alloc_bit(struct super_block *sp, int map, bit_t origin); bit_t alloc_bit(struct super_block *sp, int map, bit_t origin);
@ -95,17 +93,11 @@ u32_t get_used_blocks(struct super_block *sp);
bit_t count_free_bits(struct super_block *sp, int map); bit_t count_free_bits(struct super_block *sp, int map);
/* time.c */ /* time.c */
int fs_utime(void); int fs_utime(ino_t ino_t, struct timespec *atime, struct timespec *mtime);
/* utility.c */ /* utility.c */
unsigned conv2(int norm, int w); unsigned conv2(int norm, int w);
long conv4(int norm, long x); long conv4(int norm, long x);
void mfs_nul_f(char *file, int line, char *str, unsigned int len,
unsigned int maxlen);
int min(unsigned int l, unsigned int r);
int no_sys(void);
void sanitycheck(char *file, int line);
#define SANITYCHECK sanitycheck(__FILE__, __LINE__)
/* write.c */ /* write.c */
void clear_zone(struct inode *rip, off_t pos, int flag); void clear_zone(struct inode *rip, off_t pos, int flag);

View file

@ -2,13 +2,9 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <minix/com.h>
#include <minix/u64.h>
#include "buf.h" #include "buf.h"
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include <minix/vfsif.h>
#include <minix/minlib.h>
#include <sys/param.h> #include <sys/param.h>
#include <assert.h> #include <assert.h>
@ -16,59 +12,41 @@
static struct buf *rahead(struct inode *rip, block_t baseblock, u64_t static struct buf *rahead(struct inode *rip, block_t baseblock, u64_t
position, unsigned bytes_ahead); position, unsigned bytes_ahead);
static int rw_chunk(struct inode *rip, u64_t position, unsigned off, static int rw_chunk(struct inode *rip, u64_t position, unsigned off,
size_t chunk, unsigned left, int rw_flag, cp_grant_id_t gid, unsigned size_t chunk, unsigned left, int call, struct fsdriver_data *data,
buf_off, unsigned int block_size, int *completed); unsigned buf_off, unsigned int block_size, int *completed);
/*===========================================================================* /*===========================================================================*
* fs_readwrite * * fs_readwrite *
*===========================================================================*/ *===========================================================================*/
int fs_readwrite(void) ssize_t fs_readwrite(ino_t ino_nr, struct fsdriver_data *data, size_t nrbytes,
off_t position, int call)
{ {
int r, rw_flag, block_spec; int r;
int regular; int regular;
cp_grant_id_t gid; off_t f_size, bytes_left;
off_t position, f_size, bytes_left; size_t off, cum_io, block_size, chunk;
unsigned int off, cum_io, block_size, chunk;
mode_t mode_word; mode_t mode_word;
int completed; int completed;
struct inode *rip; struct inode *rip;
size_t nrbytes;
r = OK; r = OK;
/* Find the inode referred */ /* Find the inode referred */
if ((rip = find_inode(fs_dev, fs_m_in.m_vfs_fs_readwrite.inode)) == NULL) if ((rip = find_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
mode_word = rip->i_mode & I_TYPE; mode_word = rip->i_mode & I_TYPE;
regular = (mode_word == I_REGULAR || mode_word == I_NAMED_PIPE); regular = (mode_word == I_REGULAR);
block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0);
/* Determine blocksize */ /* Determine blocksize */
if (block_spec) {
block_size = get_block_size( (dev_t) rip->i_zone[0]);
f_size = MAX_FILE_POS;
} else {
block_size = rip->i_sp->s_block_size; block_size = rip->i_sp->s_block_size;
f_size = rip->i_size; f_size = rip->i_size;
}
/* Get the values from the request message */
switch(fs_m_in.m_type) {
case REQ_READ: rw_flag = READING; break;
case REQ_WRITE: rw_flag = WRITING; break;
case REQ_PEEK: rw_flag = PEEKING; break;
default: panic("odd request");
}
gid = fs_m_in.m_vfs_fs_readwrite.grant;
position = fs_m_in.m_vfs_fs_readwrite.seek_pos;
nrbytes = fs_m_in.m_vfs_fs_readwrite.nbytes;
lmfs_reset_rdwt_err(); lmfs_reset_rdwt_err();
/* If this is file i/o, check we can write */ /* If this is file i/o, check we can write */
if (rw_flag == WRITING && !block_spec) { if (call == FSC_WRITE) {
if(rip->i_sp->s_rd_only) if(rip->i_sp->s_rd_only)
return EROFS; return EROFS;
@ -83,18 +61,15 @@ int fs_readwrite(void)
if(position > f_size) clear_zone(rip, f_size, 0); if(position > f_size) clear_zone(rip, f_size, 0);
} }
/* If this is block i/o, check we can write */
if(block_spec && rw_flag == WRITING &&
(dev_t) rip->i_zone[0] == superblock.s_dev && superblock.s_rd_only)
return EROFS;
cum_io = 0; cum_io = 0;
/* Split the transfer into chunks that don't span two blocks. */ /* Split the transfer into chunks that don't span two blocks. */
while (nrbytes > 0) { while (nrbytes > 0) {
off = ((unsigned int) position) % block_size; /* offset in blk*/ off = ((unsigned int) position) % block_size; /* offset in blk*/
chunk = min(nrbytes, block_size - off); chunk = block_size - off;
if (chunk > nrbytes)
chunk = nrbytes;
if (rw_flag == READING) { if (call == FSC_READ) {
bytes_left = f_size - position; bytes_left = f_size - position;
if (position >= f_size) break; /* we are beyond EOF */ if (position >= f_size) break; /* we are beyond EOF */
if (chunk > (unsigned int) bytes_left) chunk = bytes_left; if (chunk > (unsigned int) bytes_left) chunk = bytes_left;
@ -102,7 +77,7 @@ int fs_readwrite(void)
/* Read or write 'chunk' bytes. */ /* Read or write 'chunk' bytes. */
r = rw_chunk(rip, ((u64_t)((unsigned long)position)), off, chunk, r = rw_chunk(rip, ((u64_t)((unsigned long)position)), off, chunk,
nrbytes, rw_flag, gid, cum_io, block_size, &completed); nrbytes, call, data, cum_io, block_size, &completed);
if (r != OK) break; /* EOF reached */ if (r != OK) break; /* EOF reached */
if (lmfs_rdwt_err() < 0) break; if (lmfs_rdwt_err() < 0) break;
@ -113,12 +88,8 @@ int fs_readwrite(void)
position += (off_t) chunk; /* position within the file */ position += (off_t) chunk; /* position within the file */
} }
fs_m_out.m_fs_vfs_readwrite.seek_pos = position; /* It might change later and
the VFS has to know this
value */
/* On write, update file size and access time. */ /* On write, update file size and access time. */
if (rw_flag == WRITING) { if (call == FSC_WRITE) {
if (regular || mode_word == I_DIRECTORY) { if (regular || mode_word == I_DIRECTORY) {
if (position > f_size) rip->i_size = position; if (position > f_size) rip->i_size = position;
} }
@ -129,101 +100,35 @@ int fs_readwrite(void)
if (lmfs_rdwt_err() != OK) r = lmfs_rdwt_err(); /* check for disk error */ if (lmfs_rdwt_err() != OK) r = lmfs_rdwt_err(); /* check for disk error */
if (lmfs_rdwt_err() == END_OF_FILE) r = OK; if (lmfs_rdwt_err() == END_OF_FILE) r = OK;
if (r != OK)
return r;
/* even on a ROFS, writing to a device node on it is fine, /* even on a ROFS, writing to a device node on it is fine,
* just don't update the inode stats for it. And dito for reading. * just don't update the inode stats for it. And dito for reading.
*/ */
if (r == OK && !rip->i_sp->s_rd_only) { if (!rip->i_sp->s_rd_only) {
if (rw_flag == READING) rip->i_update |= ATIME; if (call == FSC_READ) rip->i_update |= ATIME;
if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; if (call == FSC_WRITE) rip->i_update |= CTIME | MTIME;
IN_MARKDIRTY(rip); /* inode is thus now dirty */ IN_MARKDIRTY(rip); /* inode is thus now dirty */
} }
fs_m_out.m_fs_vfs_readwrite.nbytes = cum_io; return cum_io;
return(r);
}
/*===========================================================================*
* fs_breadwrite *
*===========================================================================*/
int fs_breadwrite(void)
{
int r, rw_flag, completed;
cp_grant_id_t gid;
u64_t position;
unsigned int off, cum_io, chunk, block_size;
size_t nrbytes;
dev_t target_dev;
/* Pseudo inode for rw_chunk */
struct inode rip;
r = OK;
target_dev = fs_m_in.m_vfs_fs_breadwrite.device;
/* Get the values from the request message */
rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING);
gid = fs_m_in.m_vfs_fs_breadwrite.grant;
position = fs_m_in.m_vfs_fs_breadwrite.seek_pos;
nrbytes = fs_m_in.m_vfs_fs_breadwrite.nbytes;
block_size = get_block_size(target_dev);
/* Don't block-write to a RO-mounted filesystem. */
if(superblock.s_dev == target_dev && superblock.s_rd_only)
return EROFS;
rip.i_zone[0] = (zone_t) target_dev;
rip.i_mode = I_BLOCK_SPECIAL;
rip.i_size = 0;
lmfs_reset_rdwt_err();
cum_io = 0;
/* Split the transfer into chunks that don't span two blocks. */
while (nrbytes > 0) {
off = (unsigned int)(position % block_size); /* offset in blk*/
chunk = min(nrbytes, block_size - off);
/* Read or write 'chunk' bytes. */
r = rw_chunk(&rip, position, off, chunk, nrbytes, rw_flag, gid,
cum_io, block_size, &completed);
if (r != OK) break; /* EOF reached */
if (lmfs_rdwt_err() < 0) break;
/* Update counters and pointers. */
nrbytes -= chunk; /* bytes yet to be read */
cum_io += chunk; /* bytes read so far */
position += chunk; /* position within the file */
}
fs_m_out.m_fs_vfs_breadwrite.seek_pos = position;
if (lmfs_rdwt_err() != OK) r = lmfs_rdwt_err(); /* check for disk error */
if (lmfs_rdwt_err() == END_OF_FILE) r = OK;
fs_m_out.m_fs_vfs_breadwrite.nbytes = cum_io;
return(r);
} }
/*===========================================================================* /*===========================================================================*
* rw_chunk * * rw_chunk *
*===========================================================================*/ *===========================================================================*/
static int rw_chunk(rip, position, off, chunk, left, rw_flag, gid, static int rw_chunk(rip, position, off, chunk, left, call, data, buf_off,
buf_off, block_size, completed) block_size, completed)
register struct inode *rip; /* pointer to inode for file to be rd/wr */ register struct inode *rip; /* pointer to inode for file to be rd/wr */
u64_t position; /* position within file to read or write */ u64_t position; /* position within file to read or write */
unsigned off; /* off within the current block */ unsigned off; /* off within the current block */
unsigned int chunk; /* number of bytes to read or write */ size_t chunk; /* number of bytes to read or write */
unsigned left; /* max number of bytes wanted after position */ unsigned left; /* max number of bytes wanted after position */
int rw_flag; /* READING, WRITING or PEEKING */ int call; /* FSC_READ, FSC_WRITE, or FSC_PEEK */
cp_grant_id_t gid; /* grant */ struct fsdriver_data *data; /* structure for (remote) user buffer */
unsigned buf_off; /* offset in grant */ unsigned buf_off; /* offset in user buffer */
unsigned int block_size; /* block size of FS operating on */ unsigned int block_size; /* block size of FS operating on */
int *completed; /* number of bytes copied */ int *completed; /* number of bytes copied */
{ {
@ -231,41 +136,27 @@ int *completed; /* number of bytes copied */
register struct buf *bp = NULL; register struct buf *bp = NULL;
register int r = OK; register int r = OK;
int n, block_spec; int n;
block_t b; block_t b;
dev_t dev; dev_t dev;
ino_t ino = VMC_NO_INODE; ino_t ino = VMC_NO_INODE;
u64_t ino_off = rounddown(position, block_size); u64_t ino_off = rounddown(position, block_size);
/* rw_flag:
* READING: read from FS, copy to user
* WRITING: copy from user, write to FS
* PEEKING: try to get all the blocks into the cache, no copying
*/
*completed = 0; *completed = 0;
block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
if (block_spec) {
b = (unsigned long)(position / block_size);
dev = (dev_t) rip->i_zone[0];
} else {
if (ex64hi(position) != 0) if (ex64hi(position) != 0)
panic("rw_chunk: position too high"); panic("rw_chunk: position too high");
b = read_map(rip, (off_t) ex64lo(position), 0); b = read_map(rip, (off_t) ex64lo(position), 0);
dev = rip->i_dev; dev = rip->i_dev;
ino = rip->i_num; ino = rip->i_num;
assert(ino != VMC_NO_INODE); assert(ino != VMC_NO_INODE);
}
if (!block_spec && b == NO_BLOCK) { if (b == NO_BLOCK) {
if (rw_flag == READING) { if (call == FSC_READ) {
/* Reading from a nonexistent block. Must read as all zeros.*/ /* Reading from a nonexistent block. Must read as all zeros.*/
r = sys_safememset(VFS_PROC_NR, gid, (vir_bytes) buf_off, r = fsdriver_zero(data, buf_off, chunk);
0, (size_t) chunk);
if(r != OK) { if(r != OK) {
printf("MFS: sys_safememset failed\n"); printf("MFS: fsdriver_zero failed\n");
} }
return r; return r;
} else { } else {
@ -275,7 +166,7 @@ int *completed; /* number of bytes copied */
if ((bp = new_block(rip, (off_t) ex64lo(position))) == NULL) if ((bp = new_block(rip, (off_t) ex64lo(position))) == NULL)
return(err_code); return(err_code);
} }
} else if (rw_flag == READING || rw_flag == PEEKING) { } else if (call != FSC_WRITE) {
/* Read and read ahead if convenient. */ /* Read and read ahead if convenient. */
bp = rahead(rip, b, position, left); bp = rahead(rip, b, position, left);
} else { } else {
@ -284,34 +175,27 @@ int *completed; /* number of bytes copied */
* the cache, acquire it, otherwise just acquire a free buffer. * the cache, acquire it, otherwise just acquire a free buffer.
*/ */
n = (chunk == block_size ? NO_READ : NORMAL); n = (chunk == block_size ? NO_READ : NORMAL);
if (!block_spec && off == 0 && (off_t) ex64lo(position) >= rip->i_size) if (off == 0 && (off_t) ex64lo(position) >= rip->i_size)
n = NO_READ; n = NO_READ;
if(block_spec) {
assert(ino == VMC_NO_INODE);
bp = get_block(dev, b, n);
} else {
assert(ino != VMC_NO_INODE); assert(ino != VMC_NO_INODE);
assert(!(ino_off % block_size)); assert(!(ino_off % block_size));
bp = lmfs_get_block_ino(dev, b, n, ino, ino_off); bp = lmfs_get_block_ino(dev, b, n, ino, ino_off);
} }
}
/* In all cases, bp now points to a valid buffer. */ /* In all cases, bp now points to a valid buffer. */
assert(bp != NULL); assert(bp != NULL);
if (rw_flag == WRITING && chunk != block_size && !block_spec && if (call == FSC_WRITE && chunk != block_size &&
(off_t) ex64lo(position) >= rip->i_size && off == 0) { (off_t) ex64lo(position) >= rip->i_size && off == 0) {
zero_block(bp); zero_block(bp);
} }
if (rw_flag == READING) { if (call == FSC_READ) {
/* Copy a chunk from the block buffer to user space. */ /* Copy a chunk from the block buffer to user space. */
r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) buf_off, r = fsdriver_copyout(data, buf_off, b_data(bp)+off, chunk);
(vir_bytes) (b_data(bp)+off), (size_t) chunk); } else if (call == FSC_WRITE) {
} else if(rw_flag == WRITING) {
/* Copy a chunk from user space to the block buffer. */ /* Copy a chunk from user space to the block buffer. */
r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) buf_off, r = fsdriver_copyin(data, buf_off, b_data(bp)+off, chunk);
(vir_bytes) (b_data(bp)+off), (size_t) chunk);
MARKDIRTY(bp); MARKDIRTY(bp);
} }
@ -461,7 +345,7 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
/* Minimum number of blocks to prefetch. */ /* Minimum number of blocks to prefetch. */
int nr_bufs = lmfs_nr_bufs(); int nr_bufs = lmfs_nr_bufs();
# define BLOCKS_MINIMUM (nr_bufs < 50 ? 18 : 32) # define BLOCKS_MINIMUM (nr_bufs < 50 ? 18 : 32)
int block_spec, scale, read_q_size; int scale, read_q_size;
unsigned int blocks_ahead, fragment, block_size; unsigned int blocks_ahead, fragment, block_size;
block_t block, blocks_left; block_t block, blocks_left;
off_t ind1_pos; off_t ind1_pos;
@ -482,12 +366,7 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
readqsize = nr_bufs; readqsize = nr_bufs;
} }
block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
if (block_spec)
dev = (dev_t) rip->i_zone[0];
else
dev = rip->i_dev; dev = rip->i_dev;
assert(dev != NO_DEV); assert(dev != NO_DEV);
block_size = get_block_size(dev); block_size = get_block_size(dev);
@ -500,11 +379,7 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
bytes_ahead += fragment; bytes_ahead += fragment;
blocks_ahead = (bytes_ahead + block_size - 1) / block_size; blocks_ahead = (bytes_ahead + block_size - 1) / block_size;
if(block_spec)
bp = get_block(dev, block, PREFETCH);
else
bp = lmfs_get_block_ino(dev, block, PREFETCH, rip->i_num, position); bp = lmfs_get_block_ino(dev, block, PREFETCH, rip->i_num, position);
assert(bp != NULL); assert(bp != NULL);
assert(bp->lmfs_count > 0); assert(bp->lmfs_count > 0);
if (lmfs_dev(bp) != NO_DEV) return(bp); if (lmfs_dev(bp) != NO_DEV) return(bp);
@ -529,23 +404,16 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
* indirect blocks (but don't call read_map!). * indirect blocks (but don't call read_map!).
*/ */
if (block_spec && rip->i_size == 0) {
blocks_left = (block_t) NR_IOREQS;
} else {
blocks_left = (block_t) (rip->i_size-ex64lo(position)+(block_size-1)) / blocks_left = (block_t) (rip->i_size-ex64lo(position)+(block_size-1)) /
block_size; block_size;
/* Go for the first indirect block if we are in its neighborhood. */ /* Go for the first indirect block if we are in its neighborhood. */
if (!block_spec) {
scale = rip->i_sp->s_log_zone_size; scale = rip->i_sp->s_log_zone_size;
ind1_pos = (off_t) rip->i_ndzones * (block_size << scale); ind1_pos = (off_t) rip->i_ndzones * (block_size << scale);
if ((off_t) ex64lo(position) <= ind1_pos && if ((off_t) ex64lo(position) <= ind1_pos && rip->i_size > ind1_pos) {
rip->i_size > ind1_pos) {
blocks_ahead++; blocks_ahead++;
blocks_left++; blocks_left++;
} }
}
}
/* No more than the maximum request. */ /* No more than the maximum request. */
if (blocks_ahead > NR_IOREQS) blocks_ahead = NR_IOREQS; if (blocks_ahead > NR_IOREQS) blocks_ahead = NR_IOREQS;
@ -573,9 +441,10 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
block++; block++;
position_running += block_size; position_running += block_size;
if(!block_spec && thisblock = read_map(rip, (off_t) ex64lo(position_running), 1);
(thisblock = read_map(rip, (off_t) ex64lo(position_running), 1)) != NO_BLOCK) { if (thisblock != NO_BLOCK) {
bp = lmfs_get_block_ino(dev, thisblock, PREFETCH, rip->i_num, position_running); bp = lmfs_get_block_ino(dev, thisblock, PREFETCH, rip->i_num,
position_running);
} else { } else {
bp = get_block(dev, block, PREFETCH); bp = get_block(dev, block, PREFETCH);
} }
@ -591,8 +460,6 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
assert(inuse_before == lmfs_bufs_in_use()); assert(inuse_before == lmfs_bufs_in_use());
if(block_spec)
return get_block(dev, baseblock, NORMAL);
return(lmfs_get_block_ino(dev, baseblock, NORMAL, rip->i_num, position)); return(lmfs_get_block_ino(dev, baseblock, NORMAL, rip->i_num, position));
} }
@ -600,33 +467,27 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
/*===========================================================================* /*===========================================================================*
* fs_getdents * * fs_getdents *
*===========================================================================*/ *===========================================================================*/
int fs_getdents(void) ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
off_t *posp)
{ {
#define GETDENTS_BUFSIZE (sizeof(struct dirent) + MFS_NAME_MAX + 1) #define GETDENTS_BUFSIZE (sizeof(struct dirent) + MFS_NAME_MAX + 1)
#define GETDENTS_ENTRIES 8 #define GETDENTS_ENTRIES 8
static char getdents_buf[GETDENTS_BUFSIZE * GETDENTS_ENTRIES]; static char getdents_buf[GETDENTS_BUFSIZE * GETDENTS_ENTRIES];
register struct inode *rip; struct fsdriver_dentry fsdentry;
int o, r, done; struct inode *rip, *entrip;
unsigned int block_size, len, reclen; int r, done;
ino_t ino; unsigned int block_size, len, type;
cp_grant_id_t gid;
size_t size, tmpbuf_off, userbuf_off;
off_t pos, off, block_pos, new_pos, ent_pos; off_t pos, off, block_pos, new_pos, ent_pos;
struct buf *bp; struct buf *bp;
struct direct *dp; struct direct *dp;
struct dirent *dep;
char *cp; char *cp;
ino = fs_m_in.m_vfs_fs_getdents.inode;
gid = fs_m_in.m_vfs_fs_getdents.grant;
size = fs_m_in.m_vfs_fs_getdents.mem_size;
pos = fs_m_in.m_vfs_fs_getdents.seek_pos;
/* Check whether the position is properly aligned */ /* Check whether the position is properly aligned */
pos = *posp;
if( (unsigned int) pos % DIR_ENTRY_SIZE) if( (unsigned int) pos % DIR_ENTRY_SIZE)
return(ENOENT); return(ENOENT);
if( (rip = get_inode(fs_dev, ino)) == NULL) if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
block_size = rip->i_sp->s_block_size; block_size = rip->i_sp->s_block_size;
@ -634,14 +495,15 @@ int fs_getdents(void)
block_pos = pos - off; block_pos = pos - off;
done = FALSE; /* Stop processing directory blocks when done is set */ done = FALSE; /* Stop processing directory blocks when done is set */
tmpbuf_off = 0; /* Offset in getdents_buf */ fsdriver_dentry_init(&fsdentry, data, bytes, getdents_buf,
memset(getdents_buf, '\0', sizeof(getdents_buf)); /* Avoid leaking any data */ sizeof(getdents_buf));
userbuf_off = 0; /* Offset in the user's buffer */
/* The default position for the next request is EOF. If the user's buffer /* The default position for the next request is EOF. If the user's buffer
* fills up before EOF, new_pos will be modified. */ * fills up before EOF, new_pos will be modified. */
new_pos = rip->i_size; new_pos = rip->i_size;
r = 0;
for(; block_pos < rip->i_size; block_pos += block_size) { for(; block_pos < rip->i_size; block_pos += block_size) {
/* Since directories don't have holes, 'bp' cannot be NULL. */ /* Since directories don't have holes, 'bp' cannot be NULL. */
bp = get_block_map(rip, block_pos); /* get a dir block */ bp = get_block_map(rip, block_pos); /* get a dir block */
@ -663,14 +525,24 @@ int fs_getdents(void)
else else
len = cp - (dp->mfs_d_name); len = cp - (dp->mfs_d_name);
/* Compute record length; also does alignment. */
reclen = _DIRENT_RECLEN(dep, len);
/* Need the position of this entry in the directory */ /* Need the position of this entry in the directory */
ent_pos = block_pos + ((char *) dp - (char *) bp->data); ent_pos = block_pos + ((char *) dp - (char *) bp->data);
if (userbuf_off + tmpbuf_off + reclen >= size) { /* We also need(?) the file type of the target inode. */
/* The user has no space for one more record */ if (!(entrip = get_inode(fs_dev, (ino_t) dp->mfs_d_ino)))
panic("unexpected get_inode failure");
type = IFTODT(entrip->i_mode);
put_inode(entrip);
/* MFS does not store file types in its directory entries, and
* fetching the mode from the inode is seriously expensive.
* Userland should always be prepared to receive DT_UNKNOWN.
*/
r = fsdriver_dentry_add(&fsdentry, (ino_t) dp->mfs_d_ino,
dp->mfs_d_name, len, type);
/* If the user buffer is full, or an error occurred, stop. */
if (r <= 0) {
done = TRUE; done = TRUE;
/* Record the position of this entry, it is the /* Record the position of this entry, it is the
@ -680,35 +552,6 @@ int fs_getdents(void)
new_pos = ent_pos; new_pos = ent_pos;
break; break;
} }
if (tmpbuf_off + reclen >= GETDENTS_BUFSIZE*GETDENTS_ENTRIES) {
r = sys_safecopyto(VFS_PROC_NR, gid,
(vir_bytes) userbuf_off,
(vir_bytes) getdents_buf,
(size_t) tmpbuf_off);
if (r != OK) {
put_inode(rip);
return(r);
}
userbuf_off += tmpbuf_off;
tmpbuf_off = 0;
}
dep = (struct dirent *) &getdents_buf[tmpbuf_off];
dep->d_fileno = (ino_t) dp->mfs_d_ino;
dep->d_reclen = (unsigned short) reclen;
dep->d_namlen = len;
memcpy(dep->d_name, dp->mfs_d_name, len);
{
struct inode *entrip;
if(!(entrip = get_inode(fs_dev, dep->d_fileno)))
panic("unexpected get_inode failure");
dep->d_type = fs_mode_to_type(entrip->i_mode);
put_inode(entrip);
}
dep->d_name[len] = '\0';
tmpbuf_off += reclen;
} }
put_block(bp, DIRECTORY_BLOCK); put_block(bp, DIRECTORY_BLOCK);
@ -716,30 +559,14 @@ int fs_getdents(void)
break; break;
} }
if (tmpbuf_off != 0) { if (r >= 0 && (r = fsdriver_dentry_finish(&fsdentry)) >= 0) {
r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) userbuf_off, *posp = new_pos;
(vir_bytes) getdents_buf, (size_t) tmpbuf_off);
if (r != OK) {
put_inode(rip);
return(r);
}
userbuf_off += tmpbuf_off;
}
if (done && userbuf_off == 0)
r = EINVAL; /* The user's buffer is too small */
else {
fs_m_out.m_fs_vfs_getdents.nbytes = userbuf_off;
fs_m_out.m_fs_vfs_getdents.seek_pos = new_pos;
if(!rip->i_sp->s_rd_only) { if(!rip->i_sp->s_rd_only) {
rip->i_update |= ATIME; rip->i_update |= ATIME;
IN_MARKDIRTY(rip); IN_MARKDIRTY(rip);
} }
r = OK;
} }
put_inode(rip); /* release the inode */ put_inode(rip); /* release the inode */
return(r); return(r);
} }

View file

@ -5,7 +5,6 @@
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
#include <minix/vfsif.h>
/*===========================================================================* /*===========================================================================*
* estimate_blocks * * estimate_blocks *
@ -38,20 +37,18 @@ static blkcnt_t estimate_blocks(struct inode *rip)
return (zones + sindirs + dindirs) * (blkcnt_t) (zone_size / 512); return (zones + sindirs + dindirs) * (blkcnt_t) (zone_size / 512);
} }
/*===========================================================================*
* stat_inode *
*===========================================================================*/
static int stat_inode(
register struct inode *rip, /* pointer to inode to stat */
endpoint_t who_e, /* Caller endpoint */
cp_grant_id_t gid /* grant for the stat buf */
)
{
/* Common code for stat and fstat system calls. */
struct stat statbuf; /*===========================================================================*
* fs_stat *
*===========================================================================*/
int fs_stat(ino_t ino_nr, struct stat *statbuf)
{
struct inode *rip;
mode_t mo; mode_t mo;
int r, s; int s;
if ((rip = get_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL);
/* Update the atime, ctime, and mtime fields in the inode, if need be. */ /* Update the atime, ctime, and mtime fields in the inode, if need be. */
if (rip->i_update) update_times(rip); if (rip->i_update) update_times(rip);
@ -62,76 +59,49 @@ static int stat_inode(
/* true iff special */ /* true iff special */
s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL); s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL);
memset(&statbuf, 0, sizeof(struct stat)); statbuf->st_dev = rip->i_dev;
statbuf->st_ino = (ino_t) rip->i_num;
statbuf->st_mode = (mode_t) rip->i_mode;
statbuf->st_nlink = (nlink_t) rip->i_nlinks;
statbuf->st_uid = rip->i_uid;
statbuf->st_gid = rip->i_gid;
statbuf->st_rdev = (s ? (dev_t)rip->i_zone[0] : NO_DEV);
statbuf->st_size = rip->i_size;
statbuf->st_atime = rip->i_atime;
statbuf->st_mtime = rip->i_mtime;
statbuf->st_ctime = rip->i_ctime;
statbuf->st_blksize = lmfs_fs_block_size();
statbuf->st_blocks = estimate_blocks(rip);
statbuf.st_dev = rip->i_dev; put_inode(rip); /* release the inode */
statbuf.st_ino = (ino_t) rip->i_num;
statbuf.st_mode = (mode_t) rip->i_mode;
statbuf.st_nlink = (nlink_t) rip->i_nlinks;
statbuf.st_uid = rip->i_uid;
statbuf.st_gid = rip->i_gid;
statbuf.st_rdev = (s ? (dev_t)rip->i_zone[0] : NO_DEV);
statbuf.st_size = rip->i_size;
statbuf.st_atime = rip->i_atime;
statbuf.st_mtime = rip->i_mtime;
statbuf.st_ctime = rip->i_ctime;
statbuf.st_blksize = lmfs_fs_block_size();
statbuf.st_blocks = estimate_blocks(rip);
/* Copy the struct to user space. */ return(OK);
r = sys_safecopyto(who_e, gid, (vir_bytes) 0, (vir_bytes) &statbuf,
(size_t) sizeof(statbuf));
return(r);
} }
/*===========================================================================* /*===========================================================================*
* fs_statvfs * * fs_statvfs *
*===========================================================================*/ *===========================================================================*/
int fs_statvfs() int fs_statvfs(struct statvfs *st)
{ {
struct statvfs st;
struct super_block *sp; struct super_block *sp;
int r, scale; int scale;
u64_t used; u64_t used;
sp = get_super(fs_dev); sp = get_super(fs_dev);
scale = sp->s_log_zone_size; scale = sp->s_log_zone_size;
memset(&st, 0, sizeof(st)); fs_blockstats(&st->f_blocks, &st->f_bfree, &used);
st->f_bavail = st->f_bfree;
fs_blockstats(&st.f_blocks, &st.f_bfree, &used); st->f_bsize = sp->s_block_size << scale;
st.f_bavail = st.f_bfree; st->f_frsize = sp->s_block_size;
st->f_iosize = st->f_frsize;
st->f_files = sp->s_ninodes;
st->f_ffree = count_free_bits(sp, IMAP);
st->f_favail = st->f_ffree;
st->f_namemax = MFS_DIRSIZ;
st.f_bsize = sp->s_block_size << scale; return(OK);
st.f_frsize = sp->s_block_size;
st.f_iosize = st.f_frsize;
st.f_files = sp->s_ninodes;
st.f_ffree = count_free_bits(sp, IMAP);
st.f_favail = st.f_ffree;
st.f_namemax = MFS_DIRSIZ;
/* Copy the struct to user space. */
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_statvfs.grant, 0,
(vir_bytes) &st, (phys_bytes) sizeof(st));
return(r);
} }
/*===========================================================================*
* fs_stat *
*===========================================================================*/
int fs_stat()
{
register int r; /* return value */
register struct inode *rip; /* target inode */
if ((rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_stat.inode)) == NULL)
return(EINVAL);
r = stat_inode(rip, fs_m_in.m_source, fs_m_in.m_vfs_fs_stat.grant);
put_inode(rip); /* release the inode */
return(r);
}

View file

@ -193,7 +193,6 @@ unsigned int get_block_size(dev_t dev)
static int rw_super(struct super_block *sp, int writing) static int rw_super(struct super_block *sp, int writing)
{ {
/* Read/write a superblock. */ /* Read/write a superblock. */
int r;
dev_t save_dev = sp->s_dev; dev_t save_dev = sp->s_dev;
struct buf *bp; struct buf *bp;
char *sbbuf; char *sbbuf;

View file

@ -57,7 +57,6 @@ EXTERN struct super_block {
int s_nindirs; /* # indirect zones per indirect block */ int s_nindirs; /* # indirect zones per indirect block */
bit_t s_isearch; /* inodes below this bit number are in use */ bit_t s_isearch; /* inodes below this bit number are in use */
bit_t s_zsearch; /* all zones below this bit number are in use*/ bit_t s_zsearch; /* all zones below this bit number are in use*/
char s_is_root;
} superblock; } superblock;
#define IMAP 0 /* operating on the inode bit map */ #define IMAP 0 /* operating on the inode bit map */

View file

@ -1,10 +1,8 @@
/* This file contains the table used to map system call numbers onto the /* This file contains the table used to map file system calls onto the
* routines that perform them. * routines that perform them.
*/ */
#include <minix/libminixfs.h>
#define _TABLE #define _TABLE
#include "fs.h" #include "fs.h"
@ -12,40 +10,36 @@
#include "buf.h" #include "buf.h"
#include "super.h" #include "super.h"
int (*fs_call_vec[])(void) = { struct fsdriver mfs_table = {
no_sys, /* 0 not used */ .fdr_mount = fs_mount,
no_sys, /* 1 */ /* Was: fs_getnode */ .fdr_unmount = fs_unmount,
fs_putnode, /* 2 */ .fdr_lookup = fs_lookup,
fs_slink, /* 3 */ .fdr_putnode = fs_putnode,
fs_ftrunc, /* 4 */ .fdr_read = fs_readwrite,
fs_chown, /* 5 */ .fdr_write = fs_readwrite,
fs_chmod, /* 6 */ .fdr_peek = fs_readwrite,
fs_inhibread, /* 7 */ .fdr_getdents = fs_getdents,
fs_stat, /* 8 */ .fdr_trunc = fs_trunc,
fs_utime, /* 9 */ .fdr_seek = fs_seek,
fs_statvfs, /* 10 */ .fdr_create = fs_create,
fs_breadwrite, /* 11 */ .fdr_mkdir = fs_mkdir,
fs_breadwrite, /* 12 */ .fdr_mknod = fs_mknod,
fs_unlink, /* 13 */ .fdr_link = fs_link,
fs_unlink, /* 14 */ .fdr_unlink = fs_unlink,
fs_unmount, /* 15 */ .fdr_rmdir = fs_unlink,
fs_sync, /* 16 */ .fdr_rename = fs_rename,
fs_new_driver, /* 17 */ .fdr_slink = fs_slink,
fs_flush, /* 18 */ .fdr_rdlink = fs_rdlink,
fs_readwrite, /* 19 */ .fdr_stat = fs_stat,
fs_readwrite, /* 20 */ .fdr_chown = fs_chown,
fs_mknod, /* 21 */ .fdr_chmod = fs_chmod,
fs_mkdir, /* 22 */ .fdr_utime = fs_utime,
fs_create, /* 23 */ .fdr_mountpt = fs_mountpt,
fs_link, /* 24 */ .fdr_statvfs = fs_statvfs,
fs_rename, /* 25 */ .fdr_sync = fs_sync,
fs_lookup, /* 26 */ .fdr_driver = lmfs_driver,
fs_mountpoint, /* 27 */ .fdr_bread = lmfs_bio,
fs_readsuper, /* 28 */ .fdr_bwrite = lmfs_bio,
no_sys, /* 29 */ /* Was: fs_newnode */ .fdr_bpeek = lmfs_bio,
fs_rdlink, /* 30 */ .fdr_bflush = lmfs_bflush
fs_getdents, /* 31 */
fs_readwrite, /* 32 */
fs_bpeek, /* 33 */
}; };

View file

@ -1,72 +1,49 @@
#include "fs.h" #include "fs.h"
#include "inode.h" #include "inode.h"
#include <sys/time.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <minix/vfsif.h>
/*===========================================================================* /*===========================================================================*
* fs_utime * * fs_utime *
*===========================================================================*/ *===========================================================================*/
int fs_utime() int fs_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime)
{ {
register struct inode *rip; register struct inode *rip;
register int r;
/* Temporarily open the file. */ /* Temporarily open the file. */
if( (rip = get_inode(fs_dev, fs_m_in.m_vfs_fs_utime.inode)) == NULL) if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
return(EINVAL); return(EINVAL);
/*
* Only the owner of a file or the super_user can change the timestamps.
* Here we assume VFS did that check before.
*/
r = OK;
if(read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */
if(r == OK) {
rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */ rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */
switch(fs_m_in.m_vfs_fs_utime.acnsec) {
switch (atime->tv_nsec) {
case UTIME_NOW: case UTIME_NOW:
rip->i_update |= ATIME; rip->i_update |= ATIME;
break; break;
case UTIME_OMIT: /* do not touch */ case UTIME_OMIT: /* do not touch */
break; break;
default: default:
/* /* MFS does not support subsecond resolution, so we round down. */
* cases fs_m_in.m_vfs_fs_utime.acnsec < 0 || fs_m_in.m_vfs_fs_utime.acnsec >= 1E9 rip->i_atime = atime->tv_sec;
* are caught by VFS to cooperate with old instances of MFS
*/
rip->i_atime = fs_m_in.m_vfs_fs_utime.actime;
/*
* MFS does not support better than second resolution,
* so we discard ACNSEC to round down
*/
break; break;
} }
switch(fs_m_in.m_vfs_fs_utime.modnsec) { switch (mtime->tv_nsec) {
case UTIME_NOW: case UTIME_NOW:
rip->i_update |= MTIME; rip->i_update |= MTIME;
break; break;
case UTIME_OMIT: /* do not touch */ case UTIME_OMIT: /* do not touch */
break; break;
default: default:
/* /* MFS does not support subsecond resolution, so we round down. */
* cases fs_m_in.m_vfs_fs_utime.modnsec < 0 || fs_m_in.m_vfs_fs_utime.modnsec >= 1E9 rip->i_mtime = mtime->tv_sec;
* are caught by VFS to cooperate with old instances of MFS
*/
rip->i_mtime = fs_m_in.m_vfs_fs_utime.modtime;
/*
* MFS does not support better than second resolution,
* so we discard MODNSEC to round down
*/
break; break;
} }
IN_MARKDIRTY(rip); IN_MARKDIRTY(rip);
}
put_inode(rip); put_inode(rip);
return(r); return(OK);
} }

View file

@ -4,17 +4,6 @@
#include "super.h" #include "super.h"
/*===========================================================================*
* no_sys *
*===========================================================================*/
int no_sys()
{
/* Somebody has used an illegal system call number */
printf("no_sys: invalid call %d\n", req_nr);
return(EINVAL);
}
/*===========================================================================* /*===========================================================================*
* conv2 * * conv2 *
*===========================================================================*/ *===========================================================================*/
@ -45,31 +34,3 @@ long x; /* 32-bit long to be byte swapped */
l = ( (long) lo <<16) | hi; l = ( (long) lo <<16) | hi;
return(l); return(l);
} }
/*===========================================================================*
* mfs_min *
*===========================================================================*/
int min(unsigned int l, unsigned int r)
{
if(r >= l) return(l);
return(r);
}
/*===========================================================================*
* mfs_nul *
*===========================================================================*/
void mfs_nul_f(char *file, int line, char *str, unsigned int len,
unsigned int maxlen)
{
if(len < maxlen && str[len-1] != '\0') {
printf("MFS %s:%d string (length %d, maxlen %d) not null-terminated\n",
file, line, len, maxlen);
}
}
#define MYASSERT(c) if(!(c)) { printf("MFS:%s:%d: sanity check: %s failed\n", \
file, line, #c); panic("sanity check " #c " failed: %d", __LINE__); }

View file

@ -233,8 +233,8 @@ struct super_block *sb; /* superblock of device block resides on */
*===========================================================================*/ *===========================================================================*/
void clear_zone(rip, pos, flag) void clear_zone(rip, pos, flag)
register struct inode *rip; /* inode to clear */ register struct inode *rip; /* inode to clear */
off_t pos; /* points to block to clear */ off_t __unused pos; /* points to block to clear */
int flag; /* 1 if called by new_block, 0 otherwise */ int __unused flag; /* 1 if called by new_block, 0 otherwise */
{ {
/* Zero a zone, possibly starting in the middle. The parameter 'pos' gives /* Zero a zone, possibly starting in the middle. The parameter 'pos' gives
* a byte in the first block to be zeroed. Clearzone() is called from * a byte in the first block to be zeroed. Clearzone() is called from

View file

@ -10,6 +10,7 @@
#include <minix/type.h> /* for unshort :-( */ #include <minix/type.h> /* for unshort :-( */
#include <minix/sysutil.h> #include <minix/sysutil.h>
#include <minix/minlib.h> #include <minix/minlib.h>
#include <minix/ipc.h>
#include "mfs/const.h" /* depends of -I flag in Makefile */ #include "mfs/const.h" /* depends of -I flag in Makefile */
#include "mfs/type.h" /* ditto */ #include "mfs/type.h" /* ditto */
#include "mfs/inode.h" /* ditto */ #include "mfs/inode.h" /* ditto */