ext2: use libfsdriver
- fix panic on truncating files with holes; - remove block-based readahead, to match MFS. Change-Id: I385552f8019e9c013a6cb937bcc8e4e7181a4a50
This commit is contained in:
parent
ccaeedb267
commit
970d95ecd5
20 changed files with 458 additions and 1657 deletions
|
@ -5,8 +5,8 @@ SRCS= balloc.c link.c \
|
||||||
stadir.c table.c time.c utility.c \
|
stadir.c table.c time.c utility.c \
|
||||||
write.c ialloc.c inode.c main.c path.c \
|
write.c ialloc.c inode.c main.c path.c \
|
||||||
super.c
|
super.c
|
||||||
DPADD+= ${LIBMINIXFS} ${LIBBDEV} ${LIBSYS}
|
DPADD+= ${LIBMINIXFS} ${LIBFSDRIVER} ${LIBBDEV} ${LIBSYS}
|
||||||
LDADD+= -lminixfs -lbdev -lsys
|
LDADD+= -lminixfs -lfsdriver -lbdev -lsys
|
||||||
|
|
||||||
WARNS=3
|
WARNS=3
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,6 @@
|
||||||
#define INODE_HASH_SIZE ((unsigned long)1<<INODE_HASH_LOG2)
|
#define INODE_HASH_SIZE ((unsigned long)1<<INODE_HASH_LOG2)
|
||||||
#define INODE_HASH_MASK (((unsigned long)1<<INODE_HASH_LOG2)-1)
|
#define INODE_HASH_MASK (((unsigned long)1<<INODE_HASH_LOG2)-1)
|
||||||
|
|
||||||
|
|
||||||
/* 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))
|
|
||||||
|
|
||||||
#define SUPER_MAGIC 0xEF53 /* magic number contained in super-block */
|
#define SUPER_MAGIC 0xEF53 /* magic number contained in super-block */
|
||||||
|
|
||||||
#define EXT2_NAME_MAX 255
|
#define EXT2_NAME_MAX 255
|
||||||
|
@ -40,19 +33,12 @@
|
||||||
/* 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 /* inode disk and memory copies identical */
|
#define IN_CLEAN 0 /* inode disk and memory copies identical */
|
||||||
#define IN_DIRTY 1 /* inode disk and memory copies differ */
|
#define IN_DIRTY 1 /* inode disk 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 SUPER_BLOCK_BYTES (1024) /* bytes offset */
|
#define SUPER_BLOCK_BYTES (1024) /* bytes offset */
|
||||||
|
|
||||||
#define ROOT_INODE ((ino_t) 2) /* inode number for root directory */
|
#define ROOT_INODE ((ino_t) 2) /* inode number for root directory */
|
||||||
|
@ -60,7 +46,7 @@
|
||||||
#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 BLOCK_ADDRESS_BYTES 4 /* bytes per address */
|
#define BLOCK_ADDRESS_BYTES 4 /* bytes per address */
|
||||||
|
|
||||||
#define SUPER_SIZE usizeof (struct super_block) /* sb size in RAM */
|
#define SUPER_SIZE sizeof (struct super_block) /* sb size in RAM */
|
||||||
#define SUPER_SIZE_D (1024) /* max size of superblock stored on disk */
|
#define SUPER_SIZE_D (1024) /* max size of superblock stored on disk */
|
||||||
|
|
||||||
/* Directories related macroses */
|
/* Directories related macroses */
|
||||||
|
@ -93,8 +79,8 @@
|
||||||
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
|
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
|
||||||
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
|
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
|
||||||
|
|
||||||
#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)
|
||||||
|
|
||||||
/* Inodes */
|
/* Inodes */
|
||||||
|
@ -114,8 +100,6 @@
|
||||||
#define MAX_FAST_SYMLINK_LENGTH \
|
#define MAX_FAST_SYMLINK_LENGTH \
|
||||||
( sizeof(((d_inode *)0)->i_block[0]) * EXT2_N_BLOCKS )
|
( sizeof(((d_inode *)0)->i_block[0]) * EXT2_N_BLOCKS )
|
||||||
|
|
||||||
#define NUL(str,l,m) mfs_nul_f(__FILE__,__LINE__,(str), (l), (m))
|
|
||||||
|
|
||||||
/* FS states */
|
/* FS states */
|
||||||
#define EXT2_VALID_FS 0x0001 /* Cleanly unmounted */
|
#define EXT2_VALID_FS 0x0001 /* Cleanly unmounted */
|
||||||
#define EXT2_ERROR_FS 0x0002 /* Errors detected */
|
#define EXT2_ERROR_FS 0x0002 /* Errors detected */
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#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>
|
||||||
|
@ -22,6 +21,8 @@
|
||||||
#include <minix/syslib.h>
|
#include <minix/syslib.h>
|
||||||
#include <minix/sysutil.h>
|
#include <minix/sysutil.h>
|
||||||
|
|
||||||
|
#include <minix/fsdriver.h>
|
||||||
|
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
|
|
@ -8,37 +8,13 @@
|
||||||
#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 rdwt_err; /* status of last disk i/o request */
|
|
||||||
|
|
||||||
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+1]; /* 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 int unmountdone;
|
|
||||||
EXTERN int exitsignaled;
|
|
||||||
|
|
||||||
/* Little hack for syncing group descriptors. */
|
/* Little hack for syncing group descriptors. */
|
||||||
EXTERN int group_descriptors_dirty;
|
EXTERN int group_descriptors_dirty;
|
||||||
|
@ -49,4 +25,6 @@ EXTERN struct opt opt; /* global options */
|
||||||
* care about byte swapping, when have BE CPU. */
|
* care about byte swapping, when have BE CPU. */
|
||||||
EXTERN int le_CPU; /* little/big endian, if TRUE do not swap bytes */
|
EXTERN int le_CPU; /* little/big endian, if TRUE do not swap bytes */
|
||||||
|
|
||||||
|
extern struct fsdriver ext2_table;
|
||||||
|
|
||||||
#endif /* EXT2_GLO_H */
|
#endif /* EXT2_GLO_H */
|
||||||
|
|
|
@ -29,7 +29,8 @@ static void wipe_inode(struct inode *rip);
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* alloc_inode *
|
* alloc_inode *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
struct inode *alloc_inode(struct inode *parent, mode_t bits)
|
struct inode *alloc_inode(struct inode *parent, mode_t bits, uid_t uid,
|
||||||
|
gid_t gid)
|
||||||
{
|
{
|
||||||
/* Allocate a free inode on parent's dev, and return a pointer to it. */
|
/* Allocate a free inode on parent's dev, and return a pointer to it. */
|
||||||
|
|
||||||
|
@ -67,8 +68,8 @@ struct inode *alloc_inode(struct inode *parent, 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_links_count = NO_LINK; /* initial no links */
|
rip->i_links_count = 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 = parent->i_dev; /* mark which device it is on */
|
rip->i_dev = parent->i_dev; /* mark which device it is on */
|
||||||
rip->i_sp = sp; /* pointer to super block */
|
rip->i_sp = sp; /* pointer to super block */
|
||||||
|
|
||||||
|
|
|
@ -31,27 +31,21 @@ static void unhash_inode(struct inode *node);
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* 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");
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
#define SAME 1000
|
#define SAME 1000
|
||||||
|
|
||||||
static int freesp_inode(struct inode *rip, off_t st, off_t end);
|
static int freesp_inode(struct inode *rip, off_t st, off_t end);
|
||||||
static int remove_dir(struct inode *rldirp, struct inode *rip, char
|
static int remove_dir(struct inode *rldirp, struct inode *rip,
|
||||||
dir_name[NAME_MAX + 1]);
|
const char *dir_name);
|
||||||
static int unlink_file(struct inode *dirp, struct inode *rip, char
|
static int unlink_file(struct inode *dirp, struct inode *rip,
|
||||||
file_name[NAME_MAX + 1]);
|
const char *file_name);
|
||||||
static off_t nextblock(off_t pos, int blocksize);
|
static off_t nextblock(off_t pos, int blocksize);
|
||||||
static void zeroblock_half(struct inode *i, off_t p, int l);
|
static void zeroblock_half(struct inode *i, off_t p, int l);
|
||||||
static void zeroblock_range(struct inode *i, off_t p, off_t h);
|
static void zeroblock_range(struct inode *i, off_t p, off_t h);
|
||||||
|
@ -31,28 +31,16 @@ static void zeroblock_range(struct inode *i, off_t p, off_t h);
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* 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[NAME_MAX + 1];
|
|
||||||
struct inode *new_ip;
|
struct inode *new_ip;
|
||||||
phys_bytes len;
|
|
||||||
|
|
||||||
/* Copy the link name's last component */
|
|
||||||
len = fs_m_in.m_vfs_fs_link.path_len; /* including trailing '\0' */
|
|
||||||
if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1)
|
|
||||||
return(ENAMETOOLONG);
|
|
||||||
|
|
||||||
r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_link.grant, 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. */
|
||||||
|
@ -62,9 +50,9 @@ int fs_link()
|
||||||
if(rip->i_links_count >= LINK_MAX)
|
if(rip->i_links_count >= 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. */
|
||||||
|
@ -74,7 +62,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);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +74,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;
|
||||||
|
@ -97,8 +85,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, rip->i_mode & I_TYPE);
|
||||||
rip->i_mode & I_TYPE);
|
|
||||||
|
|
||||||
/* If success, register the linking. */
|
/* If success, register the linking. */
|
||||||
if(r == OK) {
|
if(r == OK) {
|
||||||
|
@ -117,57 +104,42 @@ 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[NAME_MAX + 1];
|
|
||||||
phys_bytes len;
|
|
||||||
|
|
||||||
/* Copy the last component */
|
|
||||||
len = fs_m_in.m_vfs_fs_unlink.path_len; /* including trailing '\0' */
|
|
||||||
if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1)
|
|
||||||
return(ENAMETOOLONG);
|
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
/* Now test if the call is allowed, separately for unlink() and rmdir(). */
|
/* Now test if the call is allowed, separately for unlink() and rmdir(). */
|
||||||
if(fs_m_in.m_type == REQ_UNLINK) {
|
if (call == FSC_UNLINK) {
|
||||||
/* 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. */
|
||||||
|
@ -180,18 +152,15 @@ 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 = NULL; /* buffer containing link text */
|
struct buf *bp = NULL; /* buffer containing link text */
|
||||||
char* link_text; /* either bp->b_data or rip->i_block */
|
char* link_text; /* either bp->b_data or rip->i_block */
|
||||||
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 (rip->i_size >= MAX_FAST_SYMLINK_LENGTH) {
|
if (rip->i_size >= MAX_FAST_SYMLINK_LENGTH) {
|
||||||
|
@ -208,16 +177,13 @@ int fs_rdlink()
|
||||||
r = OK;
|
r = OK;
|
||||||
}
|
}
|
||||||
if (r == OK) {
|
if (r == OK) {
|
||||||
/* 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, link_text, bytes);
|
||||||
r = sys_safecopyto(VFS_PROC_NR, fs_m_in.m_vfs_fs_rdlink.grant,
|
|
||||||
(vir_bytes) 0, (vir_bytes) link_text,
|
|
||||||
(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);
|
||||||
|
@ -231,7 +197,7 @@ int fs_rdlink()
|
||||||
static int remove_dir(rldirp, rip, dir_name)
|
static int remove_dir(rldirp, rip, dir_name)
|
||||||
struct inode *rldirp; /* parent directory */
|
struct inode *rldirp; /* parent directory */
|
||||||
struct inode *rip; /* directory to be removed */
|
struct inode *rip; /* directory to be removed */
|
||||||
char dir_name[NAME_MAX + 1]; /* name of directory to be removed */
|
const char *dir_name; /* name of directory to be removed */
|
||||||
{
|
{
|
||||||
/* A directory file has to be removed. Five conditions have to met:
|
/* A directory file has to be removed. Five conditions have to met:
|
||||||
* - The file must be a directory
|
* - The file must be a directory
|
||||||
|
@ -243,10 +209,9 @@ char dir_name[NAME_MAX + 1]; /* 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, 0)) != OK)
|
if ((r = search_dir(rip, "", NULL, IS_EMPTY, 0)) != 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. */
|
||||||
|
@ -255,8 +220,8 @@ char dir_name[NAME_MAX + 1]; /* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +232,7 @@ char dir_name[NAME_MAX + 1]; /* name of directory to be removed */
|
||||||
static int unlink_file(dirp, rip, file_name)
|
static int unlink_file(dirp, rip, file_name)
|
||||||
struct inode *dirp; /* parent directory of file */
|
struct inode *dirp; /* parent directory of file */
|
||||||
struct inode *rip; /* inode of file, may be NULL too. */
|
struct inode *rip; /* inode of file, may be NULL too. */
|
||||||
char file_name[NAME_MAX + 1]; /* name of file to be removed */
|
const char *file_name; /* name of file to be removed */
|
||||||
{
|
{
|
||||||
/* Unlink 'file_name'; rip must be the inode of 'file_name' or NULL. */
|
/* Unlink 'file_name'; rip must be the inode of 'file_name' or NULL. */
|
||||||
|
|
||||||
|
@ -277,14 +242,14 @@ char file_name[NAME_MAX + 1]; /* 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, 0);
|
err_code = search_dir(dirp, file_name, &numb, LOOK_UP, 0);
|
||||||
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, 0);
|
r = search_dir(dirp, file_name, NULL, DELETE, 0);
|
||||||
|
|
||||||
if (r == OK) {
|
if (r == OK) {
|
||||||
rip->i_links_count--; /* entry deleted from parent's dir */
|
rip->i_links_count--; /* entry deleted from parent's dir */
|
||||||
|
@ -300,7 +265,8 @@ char file_name[NAME_MAX + 1]; /* 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 */
|
||||||
|
@ -309,48 +275,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 = 0; /* TRUE iff parent dirs are the same */
|
int same_pdir = 0; /* TRUE iff parent dirs are the same */
|
||||||
char old_name[NAME_MAX + 1], new_name[NAME_MAX + 1];
|
|
||||||
ino_t numb;
|
ino_t numb;
|
||||||
phys_bytes len;
|
|
||||||
|
|
||||||
/* Copy the last component of the old name */
|
|
||||||
len = fs_m_in.m_vfs_fs_rename.len_old; /* including trailing '\0' */
|
|
||||||
if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1)
|
|
||||||
return(ENAMETOOLONG);
|
|
||||||
|
|
||||||
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 = fs_m_in.m_vfs_fs_rename.len_new; /* including trailing '\0' */
|
|
||||||
if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1)
|
|
||||||
return(ENAMETOOLONG);
|
|
||||||
|
|
||||||
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) {
|
if (old_ip == NULL) {
|
||||||
|
put_inode(old_dirp);
|
||||||
|
return(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_ip->i_mountpoint) {
|
||||||
put_inode(old_ip);
|
put_inode(old_ip);
|
||||||
old_ip = NULL;
|
put_inode(old_dirp);
|
||||||
if (r == EENTERMOUNT) r = EXDEV; /* should this fail at all? */
|
return(EBUSY);
|
||||||
else if (r == ELEAVEMOUNT) r = EINVAL; /* rename on dot-dot */
|
|
||||||
} else if (old_ip == NULL) {
|
|
||||||
return(err_code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
||||||
|
@ -363,11 +309,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;
|
||||||
|
@ -391,15 +336,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,
|
/* imitate that we are back at the root,
|
||||||
* cross device checked already on VFS */
|
* cross device checked already on VFS */
|
||||||
put_inode(next_new_superdirp);
|
put_inode(next_new_superdirp);
|
||||||
|
@ -415,18 +359,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_links_count >= SHRT_MAX ||
|
if(odir && (new_dirp->i_links_count >= SHRT_MAX ||
|
||||||
new_dirp->i_links_count >= LINK_MAX) &&
|
new_dirp->i_links_count >= LINK_MAX) &&
|
||||||
!same_pdir && r == OK) {
|
!same_pdir && r == OK) {
|
||||||
|
@ -474,17 +408,17 @@ 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, 0);
|
r = search_dir(old_dirp,old_name, NULL, DELETE, 0);
|
||||||
/* shouldn't go wrong. */
|
/* shouldn't go wrong. */
|
||||||
if(r == OK)
|
if(r == OK)
|
||||||
(void) search_dir(old_dirp, new_name, &numb, ENTER, IGN_PERM,
|
(void) search_dir(old_dirp, new_name, &numb, ENTER,
|
||||||
old_ip->i_mode & I_TYPE);
|
old_ip->i_mode & I_TYPE);
|
||||||
} else {
|
} else {
|
||||||
r = search_dir(new_dirp, new_name, &numb, ENTER, IGN_PERM,
|
r = search_dir(new_dirp, new_name, &numb, ENTER,
|
||||||
old_ip->i_mode & I_TYPE);
|
old_ip->i_mode & I_TYPE);
|
||||||
if(r == OK) {
|
if(r == OK) {
|
||||||
(void) search_dir(old_dirp, old_name, NULL,
|
(void) search_dir(old_dirp, old_name, NULL,
|
||||||
DELETE, IGN_PERM, 0);
|
DELETE, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,8 +428,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, I_DIRECTORY) == OK) {
|
if(search_dir(old_ip, "..", &numb, ENTER, I_DIRECTORY) == OK) {
|
||||||
/* New link created. */
|
/* New link created. */
|
||||||
new_dirp->i_links_count++;
|
new_dirp->i_links_count++;
|
||||||
new_dirp->i_dirt = IN_DIRTY;
|
new_dirp->i_dirt = IN_DIRTY;
|
||||||
|
@ -512,20 +446,16 @@ 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);
|
||||||
|
|
||||||
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
|
||||||
|
@ -716,7 +646,7 @@ off_t len;
|
||||||
|
|
||||||
if (!len) return; /* no zeroing to be done. */
|
if (!len) return; /* no zeroing to be done. */
|
||||||
if (!(bp = get_block_map(rip, rounddown(pos, rip->i_sp->s_block_size))))
|
if (!(bp = get_block_map(rip, rounddown(pos, rip->i_sp->s_block_size))))
|
||||||
panic("zeroblock_range: no block");
|
return; /* skip holes */
|
||||||
offset = pos % rip->i_sp->s_block_size;
|
offset = pos % rip->i_sp->s_block_size;
|
||||||
if (offset + len > rip->i_sp->s_block_size)
|
if (offset + len > rip->i_sp->s_block_size)
|
||||||
panic("zeroblock_range: len too long: %lld", len);
|
panic("zeroblock_range: len too long: %lld", len);
|
||||||
|
|
|
@ -1,20 +1,8 @@
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include <assert.h>
|
|
||||||
#include <minix/callnr.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <minix/dmap.h>
|
|
||||||
#include <minix/endpoint.h>
|
|
||||||
#include <minix/vfsif.h>
|
|
||||||
#include <minix/optset.h>
|
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
#include "inode.h"
|
#include "inode.h"
|
||||||
|
#include <string.h>
|
||||||
/* Declare some local functions. */
|
#include <minix/optset.h>
|
||||||
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);
|
||||||
|
@ -32,7 +20,7 @@ static struct optset optset_table[] = {
|
||||||
{ "reserved", OPT_BOOL, &opt.use_reserved_blocks, TRUE },
|
{ "reserved", OPT_BOOL, &opt.use_reserved_blocks, TRUE },
|
||||||
{ "prealloc", OPT_BOOL, &opt.use_prealloc, TRUE },
|
{ "prealloc", OPT_BOOL, &opt.use_prealloc, TRUE },
|
||||||
{ "noprealloc", OPT_BOOL, &opt.use_prealloc, FALSE },
|
{ "noprealloc", OPT_BOOL, &opt.use_prealloc, FALSE },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -40,11 +28,7 @@ static struct optset optset_table[] = {
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
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;
|
|
||||||
unsigned short test_endian = 1;
|
unsigned short test_endian = 1;
|
||||||
|
|
||||||
/* SEF local startup. */
|
/* SEF local startup. */
|
||||||
|
@ -56,50 +40,8 @@ int main(int argc, char *argv[])
|
||||||
/* Server isn't tested on big endian CPU */
|
/* Server isn't tested on big endian CPU */
|
||||||
ASSERT(le_CPU == 1);
|
ASSERT(le_CPU == 1);
|
||||||
|
|
||||||
while(!unmountdone || !exitsignaled) {
|
/* The fsdriver library does the actual work here. */
|
||||||
endpoint_t src;
|
fsdriver_task(&ext2_table);
|
||||||
|
|
||||||
/* Wait for request message. */
|
|
||||||
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\n", req_nr);
|
|
||||||
printf("ind = %d\n", ind);
|
|
||||||
error = EINVAL;
|
|
||||||
} else {
|
|
||||||
error = (*fs_call_vec[ind])();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (error == OK)
|
|
||||||
read_ahead(); /* do block read ahead */
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -166,51 +108,7 @@ 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("ext2: unmounted: unexpected message from FS\n");
|
|
||||||
else
|
|
||||||
srcok = 1; /* Normal FS request. */
|
|
||||||
|
|
||||||
} else
|
|
||||||
printf("ext2: 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("ext2(%d) was unable to send reply\n", sef_self());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include <assert.h>
|
|
||||||
#include <minix/vfsif.h>
|
|
||||||
#include <minix/bdev.h>
|
|
||||||
#include "inode.h"
|
#include "inode.h"
|
||||||
#include "super.h"
|
#include "super.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
|
||||||
|
@ -24,7 +22,7 @@ int fs_sync()
|
||||||
assert(lmfs_nr_bufs() > 0);
|
assert(lmfs_nr_bufs() > 0);
|
||||||
|
|
||||||
if (superblock->s_rd_only)
|
if (superblock->s_rd_only)
|
||||||
return(OK); /* nothing to sync */
|
return; /* nothing to sync */
|
||||||
|
|
||||||
/* Write all the dirty inodes to the disk. */
|
/* Write all the dirty inodes to the disk. */
|
||||||
for(rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
|
for(rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
|
||||||
|
@ -36,63 +34,4 @@ int fs_sync()
|
||||||
superblock->s_wtime = clock_time(NULL);
|
superblock->s_wtime = clock_time(NULL);
|
||||||
write_super(superblock);
|
write_super(superblock);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) 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("ext2: 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -3,56 +3,29 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <minix/com.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
#include "inode.h"
|
#include "inode.h"
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
|
#include <stdlib.h>
|
||||||
#include <minix/vfsif.h>
|
#include <minix/vfsif.h>
|
||||||
#include <minix/bdev.h>
|
#include <minix/bdev.h>
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* 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 = OK;
|
|
||||||
int readonly, isroot;
|
|
||||||
u32_t mask;
|
u32_t mask;
|
||||||
|
|
||||||
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, 0,
|
|
||||||
(vir_bytes)fs_dev_label, label_len);
|
|
||||||
if (r != OK) {
|
|
||||||
printf("%s:%d fs_readsuper: 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)) !=
|
||||||
|
@ -115,7 +88,6 @@ int fs_readsuper()
|
||||||
return(EINVAL);
|
return(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
lmfs_set_blocksize(superblock->s_block_size, major(fs_dev));
|
lmfs_set_blocksize(superblock->s_block_size, major(fs_dev));
|
||||||
|
|
||||||
/* Get the root inode of the mounted file system. */
|
/* Get the root inode of the mounted file system. */
|
||||||
|
@ -144,7 +116,6 @@ int fs_readsuper()
|
||||||
}
|
}
|
||||||
|
|
||||||
superblock->s_rd_only = readonly;
|
superblock->s_rd_only = readonly;
|
||||||
superblock->s_is_root = isroot;
|
|
||||||
|
|
||||||
if (!readonly) {
|
if (!readonly) {
|
||||||
superblock->s_state = EXT2_ERROR_FS;
|
superblock->s_state = EXT2_ERROR_FS;
|
||||||
|
@ -154,21 +125,23 @@ int fs_readsuper()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
||||||
return(r);
|
return(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* 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.
|
||||||
|
@ -178,10 +151,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. */
|
||||||
|
@ -199,25 +171,24 @@ 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 by device number. */
|
||||||
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("ext2: 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)
|
||||||
printf("ext2: couldn't find root inode. Unmount failed.\n");
|
|
||||||
panic("ext2: couldn't find root inode");
|
panic("ext2: couldn't find root inode");
|
||||||
return(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sync fs data before checking count. In some cases VFS can force unmounting
|
/* Sync fs data before checking count. In some cases VFS can force unmounting
|
||||||
* and it will damage unsynced FS. We don't sync before checking root_ip since
|
* and it will damage unsynced FS. We don't sync before checking root_ip since
|
||||||
|
@ -226,11 +197,9 @@ int fs_unmount()
|
||||||
*/
|
*/
|
||||||
if (!superblock->s_rd_only) {
|
if (!superblock->s_rd_only) {
|
||||||
/* force any cached blocks out of memory */
|
/* force any cached blocks out of memory */
|
||||||
(void) fs_sync();
|
fs_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count > 1) return(EBUSY); /* can't umount a busy file system */
|
|
||||||
|
|
||||||
put_inode(root_ip);
|
put_inode(root_ip);
|
||||||
|
|
||||||
if (!superblock->s_rd_only) {
|
if (!superblock->s_rd_only) {
|
||||||
|
@ -247,7 +216,4 @@ 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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,51 +6,32 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.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, block_t z0);
|
bits, uid_t uid, gid_t gid, block_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)
|
||||||
{
|
{
|
||||||
phys_bytes len;
|
|
||||||
int r;
|
int r;
|
||||||
struct inode *ldirp;
|
struct inode *ldirp;
|
||||||
struct inode *rip;
|
struct inode *rip;
|
||||||
mode_t omode;
|
|
||||||
char lastc[NAME_MAX + 1];
|
|
||||||
|
|
||||||
/* 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 = fs_m_in.m_vfs_fs_create.path_len; /* including trailing '\0' */
|
|
||||||
if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1)
|
|
||||||
return(ENAMETOOLONG);
|
|
||||||
|
|
||||||
err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_create.grant,
|
|
||||||
(vir_bytes) 0, (vir_bytes) lastc, (size_t) 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(ENOENT);
|
||||||
|
|
||||||
/* Create a new inode by calling new_node(). */
|
/* Create a new inode by calling new_node(). */
|
||||||
rip = new_node(ldirp, lastc, omode, NO_BLOCK);
|
rip = new_node(ldirp, name, mode, uid, gid, NO_BLOCK);
|
||||||
r = err_code;
|
r = err_code;
|
||||||
|
|
||||||
/* If an error occurred, release inode. */
|
/* If an error occurred, release inode. */
|
||||||
|
@ -61,13 +42,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;
|
||||||
/* This 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);
|
||||||
|
@ -79,32 +59,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[NAME_MAX + 1];
|
|
||||||
phys_bytes len;
|
|
||||||
|
|
||||||
/* Copy the last component and set up caller's user and group id */
|
|
||||||
len = fs_m_in.m_vfs_fs_mknod.path_len; /* including trailing '\0' */
|
|
||||||
if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1)
|
|
||||||
return(ENAMETOOLONG);
|
|
||||||
|
|
||||||
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(ENOENT);
|
||||||
|
|
||||||
/* 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, (block_t) dev);
|
||||||
(block_t) fs_m_in.m_vfs_fs_mknod.device);
|
|
||||||
|
|
||||||
put_inode(ip);
|
put_inode(ip);
|
||||||
put_inode(ldirp);
|
put_inode(ldirp);
|
||||||
|
@ -115,33 +80,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[NAME_MAX + 1]; /* last component */
|
|
||||||
phys_bytes len;
|
|
||||||
|
|
||||||
/* Copy the last component and set up caller's user and group id */
|
|
||||||
len = fs_m_in.m_vfs_fs_mkdir.path_len; /* including trailing '\0' */
|
|
||||||
if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1)
|
|
||||||
return(ENAMETOOLONG);
|
|
||||||
|
|
||||||
err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mkdir.grant,
|
|
||||||
(vir_bytes) 0, (vir_bytes) lastc, (phys_bytes) 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(ENOENT);
|
||||||
|
|
||||||
/* 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, (block_t) 0);
|
rip = new_node(ldirp, name, mode, uid, gid, (block_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 */
|
||||||
|
@ -154,12 +104,10 @@ 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. */
|
|
||||||
rip->i_mode = fs_m_in.m_vfs_fs_mkdir.mode; /* set mode */
|
|
||||||
/* enter . in the new dir*/
|
/* enter . in the new dir*/
|
||||||
r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM, I_DIRECTORY);
|
r1 = search_dir(rip, ".", &dot, ENTER, I_DIRECTORY);
|
||||||
/* enter .. in the new dir */
|
/* enter .. in the new dir */
|
||||||
r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM, I_DIRECTORY);
|
r2 = search_dir(rip, "..", &dotdot, ENTER, I_DIRECTORY);
|
||||||
|
|
||||||
/* 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) {
|
||||||
|
@ -170,11 +118,11 @@ 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, 0) != OK)
|
if (search_dir(ldirp, name, NULL, DELETE, 0) != OK)
|
||||||
panic("Dir disappeared: %d ", (int) rip->i_num);
|
panic("Dir disappeared: %d ", (int) rip->i_num);
|
||||||
rip->i_links_count--; /* undo the increment done in new_node() */
|
rip->i_links_count--; /* undo the increment done in new_node() */
|
||||||
}
|
}
|
||||||
rip->i_dirt = IN_DIRTY; /* either way, i_links_count has changed */
|
rip->i_dirt = IN_DIRTY; /* either way, i_links_count has changed */
|
||||||
|
|
||||||
put_inode(ldirp); /* return the inode of the parent dir */
|
put_inode(ldirp); /* return the inode of the parent dir */
|
||||||
put_inode(rip); /* return the inode of the newly made dir */
|
put_inode(rip); /* return the inode of the newly made dir */
|
||||||
|
@ -185,55 +133,35 @@ 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[NAME_MAX]; /* last component of the new dir's path name */
|
|
||||||
char* link_target_buf = NULL; /* either sip->i_block or bp->b_data */
|
char* link_target_buf = NULL; /* either sip->i_block or bp->b_data */
|
||||||
struct buf *bp = NULL; /* disk buffer for link */
|
struct buf *bp = NULL; /* 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 = fs_m_in.m_vfs_fs_slink.path_len;
|
|
||||||
if (len > NAME_MAX || len > EXT2_NAME_MAX)
|
|
||||||
return(ENAMETOOLONG);
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
/* If we can then create fast symlink (store it in inode),
|
/* If we can then create fast symlink (store it in inode),
|
||||||
* Otherwise allocate a disk block for the contents of the symlink and
|
* Otherwise allocate a disk block for the contents of the symlink and
|
||||||
* 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) {
|
||||||
if ( (fs_m_in.m_vfs_fs_slink.mem_size + 1) > sip->i_sp->s_block_size) {
|
if (bytes + 1 > sip->i_sp->s_block_size) {
|
||||||
r = ENAMETOOLONG;
|
r = ENAMETOOLONG;
|
||||||
} else if ((fs_m_in.m_vfs_fs_slink.mem_size + 1) <= MAX_FAST_SYMLINK_LENGTH) {
|
} else if ((bytes + 1) <= MAX_FAST_SYMLINK_LENGTH) {
|
||||||
r = sys_safecopyfrom(VFS_PROC_NR,
|
r = fsdriver_copyin(data, 0, (char *) sip->i_block, bytes);
|
||||||
fs_m_in.m_vfs_fs_slink.grant_target,
|
|
||||||
(vir_bytes) 0, (vir_bytes) sip->i_block,
|
|
||||||
(vir_bytes) fs_m_in.m_vfs_fs_slink.mem_size);
|
|
||||||
sip->i_dirt = IN_DIRTY;
|
sip->i_dirt = IN_DIRTY;
|
||||||
link_target_buf = (char*) sip->i_block;
|
link_target_buf = (char*) sip->i_block;
|
||||||
} else {
|
} else {
|
||||||
if ((bp = new_block(sip, (off_t) 0)) != NULL) {
|
if ((bp = new_block(sip, (off_t) 0)) != NULL) {
|
||||||
sys_safecopyfrom(VFS_PROC_NR,
|
r = fsdriver_copyin(data, 0, b_data(bp), bytes);
|
||||||
fs_m_in.m_vfs_fs_slink.grant_target,
|
|
||||||
(vir_bytes) 0, (vir_bytes) b_data(bp),
|
|
||||||
(vir_bytes) fs_m_in.m_vfs_fs_slink.mem_size);
|
|
||||||
lmfs_markdirty(bp);
|
lmfs_markdirty(bp);
|
||||||
link_target_buf = b_data(bp);
|
link_target_buf = b_data(bp);
|
||||||
} else {
|
} else {
|
||||||
|
@ -242,9 +170,9 @@ int fs_slink()
|
||||||
}
|
}
|
||||||
if (r == OK) {
|
if (r == OK) {
|
||||||
assert(link_target_buf);
|
assert(link_target_buf);
|
||||||
link_target_buf[fs_m_in.m_vfs_fs_slink.mem_size] = '\0';
|
link_target_buf[bytes] = '\0';
|
||||||
sip->i_size = (off_t) strlen(link_target_buf);
|
sip->i_size = (off_t) strlen(link_target_buf);
|
||||||
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
|
||||||
|
@ -261,7 +189,7 @@ int fs_slink()
|
||||||
|
|
||||||
if(r != OK) {
|
if(r != OK) {
|
||||||
sip->i_links_count = NO_LINK;
|
sip->i_links_count = NO_LINK;
|
||||||
if (search_dir(ldirp, string, NULL, DELETE, IGN_PERM, 0) != OK)
|
if (search_dir(ldirp, name, NULL, DELETE, 0) != OK)
|
||||||
panic("Symbolic link vanished");
|
panic("Symbolic link vanished");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +205,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, block_t b0)
|
char *string, mode_t bits, uid_t uid, gid_t gid, block_t b0)
|
||||||
{
|
{
|
||||||
/* 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
|
||||||
|
@ -295,20 +223,19 @@ 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_links_count >= USHRT_MAX ||
|
if (S_ISDIR(bits) && (ldirp->i_links_count >= USHRT_MAX ||
|
||||||
ldirp->i_links_count >= LINK_MAX)) {
|
ldirp->i_links_count >= 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, bits)) == NULL) {
|
if ( (rip = alloc_inode(ldirp, bits, uid, gid)) == NULL) {
|
||||||
/* Can't creat new inode: out of inodes. */
|
/* Can't creat new inode: out of inodes. */
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
@ -322,7 +249,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,
|
if ((r=search_dir(ldirp, string, &rip->i_num, ENTER,
|
||||||
rip->i_mode & I_TYPE)) != OK) {
|
rip->i_mode & I_TYPE)) != OK) {
|
||||||
rip->i_links_count--; /* pity, have to free disk inode */
|
rip->i_links_count--; /* pity, have to free disk inode */
|
||||||
rip->i_dirt = IN_DIRTY; /* dirty inodes are written out */
|
rip->i_dirt = IN_DIRTY; /* dirty inodes are written out */
|
||||||
|
@ -331,8 +258,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)
|
||||||
|
@ -348,17 +273,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 */
|
||||||
rip->i_seek = ISEEK;
|
if ((rip = find_inode(fs_dev, ino_nr)) != NULL)
|
||||||
|
rip->i_seek = ISEEK;
|
||||||
return(OK);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
/* 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
|
|
||||||
*
|
|
||||||
* Created (MFS based):
|
* Created (MFS based):
|
||||||
* February 2010 (Evgeniy Ivanov)
|
* February 2010 (Evgeniy Ivanov)
|
||||||
*/
|
*/
|
||||||
|
@ -14,357 +8,50 @@
|
||||||
#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/param.h>
|
#include <sys/param.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[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*/ 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_block[0];
|
node->fn_dev = (dev_t) rip->i_block[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(dir_ino, root_ino, flags, res_inop, offsetp, symlinkp)
|
|
||||||
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[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_links_count == 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);
|
|
||||||
if (next_cp == NULL) {
|
|
||||||
put_inode(rip);
|
|
||||||
return(err_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
const char *sp; /* start of link text */
|
|
||||||
|
|
||||||
llen = (size_t) rip->i_size;
|
|
||||||
|
|
||||||
if (llen >= MAX_FAST_SYMLINK_LENGTH) {
|
|
||||||
/* normal symlink */
|
|
||||||
if(!(bp = get_block_map(rip, 0)))
|
|
||||||
return(EIO);
|
|
||||||
sp = b_data(bp);
|
|
||||||
} else {
|
|
||||||
/* fast symlink, stored in inode */
|
|
||||||
sp = (const char*) rip->i_block;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 if needed */
|
|
||||||
memmove(&user_path[llen], suffix, slen+1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (llen + 1 > sizeof(user_path))
|
|
||||||
return(ENAMETOOLONG); /* <expandedlink> + \0 does not fit */
|
|
||||||
|
|
||||||
/* Set terminating nul */
|
|
||||||
user_path[llen]= '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Everything is set, now copy the expanded link to user_path */
|
|
||||||
memmove(user_path, sp, llen);
|
|
||||||
|
|
||||||
if (llen >= MAX_FAST_SYMLINK_LENGTH)
|
|
||||||
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[NAME_MAX + 1]; /* 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
|
||||||
|
@ -373,136 +60,55 @@ 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_links_count == 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,
|
if ( (err_code = search_dir(dirp, string, &numb, LOOK_UP, 0)) != OK) {
|
||||||
chk_perm, 0)) != 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
|
|
||||||
* 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[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.
|
|
||||||
*
|
|
||||||
* If len of component is greater, than allowed, then return 0.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (len > NAME_MAX || len > EXT2_NAME_MAX) {
|
|
||||||
err_code = ENAMETOOLONG;
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Special case of the string at cp is empty */
|
|
||||||
if (len == 0)
|
|
||||||
strlcpy(string, ".", 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, ftype)
|
int search_dir(ldir_ptr, string, numb, flag, ftype)
|
||||||
register struct inode *ldir_ptr; /* ptr to inode for dir to search */
|
register struct inode *ldir_ptr; /* ptr to inode for dir to search */
|
||||||
const char string[NAME_MAX + 1]; /* 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 */
|
int ftype; /* used when ENTER and INCOMPAT_FILETYPE */
|
||||||
int ftype; /* used when ENTER and
|
|
||||||
* INCOMPAT_FILETYPE */
|
|
||||||
{
|
{
|
||||||
/* 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';
|
||||||
* if (flag == DELETE) delete 'string' from the directory;
|
* if (flag == DELETE) delete 'string' from the directory;
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
register struct ext2_disk_dir_desc *dp = NULL;
|
register struct ext2_disk_dir_desc *dp = NULL;
|
||||||
register struct ext2_disk_dir_desc *prev_dp = NULL;
|
register struct ext2_disk_dir_desc *prev_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;
|
unsigned new_slots;
|
||||||
int extended = 0;
|
int extended = 0;
|
||||||
|
@ -514,27 +120,15 @@ int ftype; /* used when ENTER and
|
||||||
return(ENOTDIR);
|
return(ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
new_slots = 0;
|
new_slots = 0;
|
||||||
e_hit = FALSE;
|
e_hit = FALSE;
|
||||||
match = 0; /* set when a string match occurs */
|
match = 0; /* set when a string match occurs */
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
|
||||||
|
if ((string_len = strlen(string)) > EXT2_NAME_MAX)
|
||||||
|
return(ENAMETOOLONG);
|
||||||
|
|
||||||
if (flag == ENTER) {
|
if (flag == ENTER) {
|
||||||
string_len = strlen(string);
|
|
||||||
required_space = MIN_DIR_ENTRY_SIZE + string_len;
|
required_space = MIN_DIR_ENTRY_SIZE + string_len;
|
||||||
required_space += (required_space & 0x03) == 0 ? 0 :
|
required_space += (required_space & 0x03) == 0 ? 0 :
|
||||||
(DIR_ENTRY_ALIGN - (required_space & 0x03) );
|
(DIR_ENTRY_ALIGN - (required_space & 0x03) );
|
||||||
|
|
|
@ -5,34 +5,27 @@
|
||||||
#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);
|
||||||
|
|
||||||
/* 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;
|
||||||
rip->i_dirt = IN_DIRTY;
|
rip->i_dirt = IN_DIRTY;
|
||||||
|
|
||||||
/* 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);
|
||||||
|
@ -42,117 +35,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_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
|
||||||
rip->i_uid = fs_m_in.m_vfs_fs_chown.uid;
|
rip->i_update |= CTIME;
|
||||||
rip->i_gid = fs_m_in.m_vfs_fs_chown.gid;
|
rip->i_dirt = IN_DIRTY;
|
||||||
rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
|
|
||||||
rip->i_update |= CTIME;
|
|
||||||
rip->i_dirt = IN_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
return(OK);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* 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(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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,20 +12,20 @@ struct filp;
|
||||||
struct inode;
|
struct inode;
|
||||||
struct super_block;
|
struct super_block;
|
||||||
|
|
||||||
|
|
||||||
/* balloc.c */
|
/* balloc.c */
|
||||||
void discard_preallocated_blocks(struct inode *rip);
|
void discard_preallocated_blocks(struct inode *rip);
|
||||||
block_t alloc_block(struct inode *rip, block_t goal);
|
block_t alloc_block(struct inode *rip, block_t goal);
|
||||||
void free_block(struct super_block *sp, bit_t bit);
|
void free_block(struct super_block *sp, bit_t bit);
|
||||||
|
|
||||||
/* ialloc.c */
|
/* ialloc.c */
|
||||||
struct inode *alloc_inode(struct inode *parent, mode_t bits);
|
struct inode *alloc_inode(struct inode *parent, mode_t bits, uid_t uid,
|
||||||
|
gid_t gid);
|
||||||
void free_inode(struct inode *rip);
|
void free_inode(struct inode *rip);
|
||||||
|
|
||||||
/* inode.c */
|
/* inode.c */
|
||||||
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);
|
||||||
|
@ -33,56 +33,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);
|
int 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[NAME_MAX + 1], int
|
int *is_mountpt);
|
||||||
chk_perm);
|
struct inode *advance(struct inode *dirp, const char *string);
|
||||||
int search_dir(struct inode *ldir_ptr, const char string [NAME_MAX + 1], ino_t
|
int search_dir(struct inode *ldir_ptr, const char *string, ino_t *numb,
|
||||||
*numb, int flag, int check_permissions, int ftype);
|
int flag, int ftype);
|
||||||
|
|
||||||
/* protect.c */
|
/* protect.c */
|
||||||
int fs_chmod(void);
|
int fs_chmod(ino_t ino_nr, mode_t *mode);
|
||||||
int fs_chown(void);
|
int fs_chown(ino_t ino_nr, 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 rd_indir(struct buf *bp, int index);
|
block_t rd_indir(struct buf *bp, int index);
|
||||||
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);
|
||||||
|
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 */
|
||||||
unsigned int get_block_size(dev_t dev);
|
unsigned int get_block_size(dev_t dev);
|
||||||
|
@ -92,17 +92,11 @@ void write_super(struct super_block *sp);
|
||||||
struct group_desc* get_group_desc(unsigned int bnum);
|
struct group_desc* get_group_desc(unsigned int bnum);
|
||||||
|
|
||||||
/* time.c */
|
/* time.c */
|
||||||
int fs_utime(void);
|
int fs_utime(ino_t ino, 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(const char *file, int line, const 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__)
|
|
||||||
int ansi_strcmp(register const char* ansi_s, register const char *s2,
|
int ansi_strcmp(register const char* ansi_s, register const char *s2,
|
||||||
register size_t ansi_s_length);
|
register size_t ansi_s_length);
|
||||||
bit_t setbit(bitchunk_t *bitmap, bit_t max_bits, unsigned int word);
|
bit_t setbit(bitchunk_t *bitmap, bit_t max_bits, unsigned int word);
|
||||||
|
|
|
@ -6,76 +6,50 @@
|
||||||
#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>
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
static off_t rdahedpos; /* position to read ahead */
|
|
||||||
static struct inode *rdahed_inode; /* pointer to inode to read ahead */
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* 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 = rip->i_sp->s_block_size;
|
||||||
block_size = get_block_size( (dev_t) rip->i_block[0]);
|
f_size = rip->i_size;
|
||||||
f_size = MAX_FILE_POS;
|
if (f_size < 0) f_size = MAX_FILE_POS;
|
||||||
} else {
|
|
||||||
block_size = rip->i_sp->s_block_size;
|
|
||||||
f_size = rip->i_size;
|
|
||||||
if (f_size < 0) f_size = MAX_FILE_POS;
|
|
||||||
}
|
|
||||||
|
|
||||||
rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
|
lmfs_reset_rdwt_err();
|
||||||
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;
|
|
||||||
|
|
||||||
rdwt_err = OK; /* set to EIO if disk error occurs */
|
if (call == FSC_WRITE) {
|
||||||
|
|
||||||
if (rw_flag == WRITING && !block_spec) {
|
|
||||||
/* Check in advance to see if file will grow too big. */
|
/* Check in advance to see if file will grow too big. */
|
||||||
if (position > (off_t) (rip->i_sp->s_max_size - nrbytes))
|
if (position > (off_t) (rip->i_sp->s_max_size - nrbytes))
|
||||||
return(EFBIG);
|
return(EFBIG);
|
||||||
|
@ -85,9 +59,11 @@ int fs_readwrite(void)
|
||||||
/* 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 > bytes_left) chunk = (int) bytes_left;
|
if (chunk > bytes_left) chunk = (int) bytes_left;
|
||||||
|
@ -95,10 +71,10 @@ 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 (rdwt_err < 0) break;
|
if (lmfs_rdwt_err() < 0) break;
|
||||||
|
|
||||||
/* Update counters and pointers. */
|
/* Update counters and pointers. */
|
||||||
nrbytes -= chunk; /* bytes yet to be read */
|
nrbytes -= chunk; /* bytes yet to be read */
|
||||||
|
@ -106,115 +82,42 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check to see if read-ahead is called for, and if so, set it up. */
|
|
||||||
if(rw_flag == READING && rip->i_seek == NO_SEEK &&
|
|
||||||
(unsigned int) position % block_size == 0 &&
|
|
||||||
(regular || mode_word == I_DIRECTORY)) {
|
|
||||||
rdahed_inode = rip;
|
|
||||||
rdahedpos = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
rip->i_seek = NO_SEEK;
|
rip->i_seek = NO_SEEK;
|
||||||
|
|
||||||
if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
|
if (lmfs_rdwt_err() != OK) r = lmfs_rdwt_err(); /* check for disk error */
|
||||||
if (rdwt_err == END_OF_FILE) r = OK;
|
if (lmfs_rdwt_err() == END_OF_FILE) r = OK;
|
||||||
|
|
||||||
if (r == OK) {
|
if (r != OK)
|
||||||
if (rw_flag == READING) rip->i_update |= ATIME;
|
return r;
|
||||||
if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
|
|
||||||
rip->i_dirt = IN_DIRTY; /* inode is thus now dirty */
|
|
||||||
}
|
|
||||||
|
|
||||||
fs_m_out.m_fs_vfs_readwrite.nbytes = cum_io;
|
if (call == FSC_READ) rip->i_update |= ATIME;
|
||||||
|
if (call == FSC_WRITE) rip->i_update |= CTIME | MTIME;
|
||||||
|
rip->i_dirt = IN_DIRTY; /* inode is thus now dirty */
|
||||||
|
|
||||||
return(r);
|
return(cum_io);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/* Pseudo inode for rw_chunk */
|
|
||||||
struct inode rip;
|
|
||||||
|
|
||||||
r = OK;
|
|
||||||
|
|
||||||
/* 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(fs_m_in.m_vfs_fs_breadwrite.device);
|
|
||||||
|
|
||||||
rip.i_block[0] = (block_t) fs_m_in.m_vfs_fs_breadwrite.device;
|
|
||||||
rip.i_mode = I_BLOCK_SPECIAL;
|
|
||||||
rip.i_size = 0;
|
|
||||||
|
|
||||||
rdwt_err = OK; /* set to EIO if disk error occurs */
|
|
||||||
|
|
||||||
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 (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 (rdwt_err != OK) r = rdwt_err; /* check for disk error */
|
|
||||||
if (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 */
|
||||||
{
|
{
|
||||||
|
@ -222,43 +125,29 @@ 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 (ex64hi(position) != 0)
|
||||||
|
panic("rw_chunk: position too high");
|
||||||
|
b = read_map(rip, (off_t) ex64lo(position), 0);
|
||||||
|
dev = rip->i_dev;
|
||||||
|
ino = rip->i_num;
|
||||||
|
assert(ino != VMC_NO_INODE);
|
||||||
|
|
||||||
if (block_spec) {
|
if (b == NO_BLOCK) {
|
||||||
b = (unsigned long)(position / block_size);
|
if (call == FSC_READ) {
|
||||||
dev = (dev_t) rip->i_block[0];
|
|
||||||
} else {
|
|
||||||
if (ex64hi(position) != 0)
|
|
||||||
panic("rw_chunk: position too high");
|
|
||||||
b = read_map(rip, (off_t) ex64lo(position), 0);
|
|
||||||
dev = rip->i_dev;
|
|
||||||
ino = rip->i_num;
|
|
||||||
assert(ino != VMC_NO_INODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!block_spec && b == NO_BLOCK) {
|
|
||||||
if (rw_flag == READING) {
|
|
||||||
/* 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("ext2fs: fsdriver_zero failed\n");
|
||||||
printf("ext2fs: sys_safememset failed\n");
|
}
|
||||||
}
|
return r;
|
||||||
return r;
|
|
||||||
} else {
|
} else {
|
||||||
/* Writing to or peeking a nonexistent block.
|
/* Writing to or peeking a nonexistent block.
|
||||||
* Create and enter in inode.
|
* Create and enter in inode.
|
||||||
|
@ -266,7 +155,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 {
|
||||||
|
@ -275,35 +164,28 @@ 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);
|
||||||
assert(ino == VMC_NO_INODE);
|
assert(!(ino_off % block_size));
|
||||||
bp = get_block(dev, b, n);
|
bp = lmfs_get_block_ino(dev, b, n, ino, ino_off);
|
||||||
} else {
|
|
||||||
assert(ino != VMC_NO_INODE);
|
|
||||||
assert(!(ino_off % block_size));
|
|
||||||
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. */
|
||||||
if (bp == NULL)
|
if (bp == NULL)
|
||||||
panic("bp not valid in rw_chunk, this can't happen");
|
panic("bp not valid in rw_chunk, this can't happen");
|
||||||
|
|
||||||
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);
|
|
||||||
lmfs_markdirty(bp);
|
lmfs_markdirty(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,32 +314,6 @@ int mindex; /* index into *bp */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* read_ahead *
|
|
||||||
*===========================================================================*/
|
|
||||||
void read_ahead()
|
|
||||||
{
|
|
||||||
/* Read a block into the cache before it is needed. */
|
|
||||||
unsigned int block_size;
|
|
||||||
register struct inode *rip;
|
|
||||||
struct buf *bp;
|
|
||||||
block_t b;
|
|
||||||
|
|
||||||
if(!rdahed_inode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
rip = rdahed_inode; /* pointer to inode to read ahead from */
|
|
||||||
block_size = get_block_size(rip->i_dev);
|
|
||||||
rdahed_inode = NULL; /* turn off read ahead */
|
|
||||||
if ( (b = read_map(rip, rdahedpos, 1)) == NO_BLOCK) return; /* at EOF */
|
|
||||||
|
|
||||||
assert(rdahedpos >= 0); /* So we can safely cast it to unsigned below */
|
|
||||||
|
|
||||||
bp = rahead(rip, b, ((u64_t)((unsigned long)rdahedpos)), block_size);
|
|
||||||
put_block(bp, PARTIAL_DATA_BLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* rahead *
|
* rahead *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -477,7 +333,7 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
|
||||||
/* Minimum number of blocks to prefetch. */
|
/* Minimum number of blocks to prefetch. */
|
||||||
# define BLOCKS_MINIMUM (nr_bufs < 50 ? 18 : 32)
|
# define BLOCKS_MINIMUM (nr_bufs < 50 ? 18 : 32)
|
||||||
int nr_bufs = lmfs_nr_bufs();
|
int nr_bufs = lmfs_nr_bufs();
|
||||||
int block_spec, read_q_size;
|
int 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;
|
||||||
|
@ -503,12 +359,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;
|
dev = rip->i_dev;
|
||||||
if (block_spec)
|
|
||||||
dev = (dev_t) rip->i_block[0];
|
|
||||||
else
|
|
||||||
dev = rip->i_dev;
|
|
||||||
|
|
||||||
assert(dev != NO_DEV);
|
assert(dev != NO_DEV);
|
||||||
block_size = get_block_size(dev);
|
block_size = get_block_size(dev);
|
||||||
|
|
||||||
|
@ -520,12 +371,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 = lmfs_get_block_ino(dev, block, PREFETCH, rip->i_num, position);
|
||||||
bp = get_block(dev, block, PREFETCH);
|
|
||||||
else
|
|
||||||
bp = lmfs_get_block_ino(dev, block, PREFETCH, rip->i_num, position);
|
|
||||||
|
|
||||||
|
|
||||||
assert(bp != NULL);
|
assert(bp != NULL);
|
||||||
if (lmfs_dev(bp) != NO_DEV) return(bp);
|
if (lmfs_dev(bp) != NO_DEV) return(bp);
|
||||||
|
|
||||||
|
@ -549,20 +395,14 @@ 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) (rip->i_size-ex64lo(position)+(block_size-1)) /
|
||||||
blocks_left = (block_t) NR_IOREQS;
|
|
||||||
} else {
|
|
||||||
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) {
|
ind1_pos = (EXT2_NDIR_BLOCKS) * block_size;
|
||||||
ind1_pos = (EXT2_NDIR_BLOCKS) * block_size;
|
if ((off_t) ex64lo(position) <= ind1_pos && rip->i_size > ind1_pos) {
|
||||||
if ((off_t) ex64lo(position) <= 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. */
|
||||||
|
@ -590,9 +430,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);
|
||||||
}
|
}
|
||||||
|
@ -604,41 +445,55 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */
|
||||||
}
|
}
|
||||||
lmfs_rw_scattered(dev, read_q, read_q_size, READING);
|
lmfs_rw_scattered(dev, read_q, read_q_size, READING);
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* get_dtype *
|
||||||
|
*===========================================================================*/
|
||||||
|
static unsigned int get_dtype(struct ext2_disk_dir_desc *dp)
|
||||||
|
{
|
||||||
|
/* Return the type of the file identified by the given directory entry. */
|
||||||
|
|
||||||
|
if (!HAS_INCOMPAT_FEATURE(superblock, INCOMPAT_FILETYPE))
|
||||||
|
return DT_UNKNOWN;
|
||||||
|
|
||||||
|
switch (dp->d_file_type) {
|
||||||
|
case EXT2_FT_REG_FILE: return DT_REG;
|
||||||
|
case EXT2_FT_DIR: return DT_DIR;
|
||||||
|
case EXT2_FT_SYMLINK: return DT_LNK;
|
||||||
|
case EXT2_FT_BLKDEV: return DT_BLK;
|
||||||
|
case EXT2_FT_CHRDEV: return DT_CHR;
|
||||||
|
case EXT2_FT_FIFO: return DT_FIFO;
|
||||||
|
default: return DT_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* 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) + EXT2_NAME_MAX + 1)
|
#define GETDENTS_BUFSIZE (sizeof(struct dirent) + EXT2_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];
|
||||||
|
struct fsdriver_dentry fsdentry;
|
||||||
struct inode *rip;
|
struct inode *rip;
|
||||||
int r, done;
|
int r, done;
|
||||||
unsigned int block_size, len, reclen;
|
unsigned int block_size, len;
|
||||||
ino_t ino;
|
|
||||||
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 ext2_disk_dir_desc *d_desc;
|
struct ext2_disk_dir_desc *d_desc;
|
||||||
struct dirent *dep;
|
ino_t child_nr;
|
||||||
|
|
||||||
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_ALIGN)
|
if ((unsigned int) pos % DIR_ENTRY_ALIGN)
|
||||||
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;
|
||||||
|
@ -646,14 +501,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 */
|
||||||
|
|
||||||
memset(getdents_buf, '\0', sizeof(getdents_buf)); /* Avoid leaking any data */
|
fsdriver_dentry_init(&fsdentry, data, bytes, getdents_buf,
|
||||||
tmpbuf_off = 0; /* Offset in getdents_buf */
|
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) {
|
||||||
off_t temp_pos = block_pos;
|
off_t temp_pos = block_pos;
|
||||||
/* Since directories don't have holes, 'bp' cannot be NULL. */
|
/* Since directories don't have holes, 'bp' cannot be NULL. */
|
||||||
|
@ -678,30 +534,19 @@ int fs_getdents(void)
|
||||||
if (d_desc->d_ino == 0)
|
if (d_desc->d_ino == 0)
|
||||||
continue; /* Entry is not in use */
|
continue; /* Entry is not in use */
|
||||||
|
|
||||||
#if 0
|
len = d_desc->d_name_len;
|
||||||
/* read.c:682: error: comparison is always false due to
|
|
||||||
* limited range of data type
|
|
||||||
*/
|
|
||||||
if (d_desc->d_name_len > NAME_MAX ||
|
|
||||||
d_desc->d_name_len > EXT2_NAME_MAX) {
|
|
||||||
len = min(NAME_MAX, EXT2_NAME_MAX);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
len = d_desc->d_name_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(len <= NAME_MAX);
|
assert(len <= NAME_MAX);
|
||||||
assert(len <= EXT2_NAME_MAX);
|
assert(len <= EXT2_NAME_MAX);
|
||||||
|
|
||||||
/* Compute record length, incl 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 *)d_desc - b_data(bp));
|
ent_pos = block_pos + ((char *)d_desc - b_data(bp));
|
||||||
|
|
||||||
if (userbuf_off + tmpbuf_off + reclen >= size) {
|
child_nr = (ino_t) conv4(le_CPU, d_desc->d_ino);
|
||||||
/* The user has no space for one more record */
|
r = fsdriver_dentry_add(&fsdentry, child_nr, d_desc->d_name,
|
||||||
|
len, get_dtype(d_desc));
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
@ -711,34 +556,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) conv4(le_CPU, d_desc->d_ino);
|
|
||||||
dep->d_reclen = (unsigned short) reclen;
|
|
||||||
dep->d_namlen = len;
|
|
||||||
memcpy(dep->d_name, d_desc->d_name, len);
|
|
||||||
dep->d_name[len] = '\0';
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
tmpbuf_off += reclen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
put_block(bp, DIRECTORY_BLOCK);
|
put_block(bp, DIRECTORY_BLOCK);
|
||||||
|
@ -746,25 +563,10 @@ 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;
|
|
||||||
rip->i_update |= ATIME;
|
rip->i_update |= ATIME;
|
||||||
rip->i_dirt = IN_DIRTY;
|
rip->i_dirt = IN_DIRTY;
|
||||||
r = OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
put_inode(rip); /* release the inode */
|
put_inode(rip); /* release the inode */
|
||||||
|
|
|
@ -8,23 +8,19 @@
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#include "inode.h"
|
#include "inode.h"
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
#include <minix/vfsif.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* stat_inode *
|
* fs_stat *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int stat_inode(
|
int fs_stat(ino_t ino_nr, struct stat *statbuf)
|
||||||
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 inode *rip;
|
||||||
|
|
||||||
struct stat statbuf;
|
|
||||||
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);
|
||||||
|
@ -35,81 +31,52 @@ 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 = rip->i_num;
|
||||||
|
statbuf->st_mode = rip->i_mode;
|
||||||
|
statbuf->st_nlink = rip->i_links_count;
|
||||||
|
statbuf->st_uid = rip->i_uid;
|
||||||
|
statbuf->st_gid = rip->i_gid;
|
||||||
|
statbuf->st_rdev = (s ? (dev_t)rip->i_block[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 = rip->i_sp->s_block_size;
|
||||||
|
statbuf->st_blocks = rip->i_blocks;
|
||||||
|
|
||||||
statbuf.st_dev = rip->i_dev;
|
|
||||||
statbuf.st_ino = rip->i_num;
|
|
||||||
statbuf.st_mode = rip->i_mode;
|
|
||||||
statbuf.st_nlink = rip->i_links_count;
|
|
||||||
statbuf.st_uid = rip->i_uid;
|
|
||||||
statbuf.st_gid = rip->i_gid;
|
|
||||||
statbuf.st_rdev = (s ? (dev_t)rip->i_block[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 = rip->i_sp->s_block_size;
|
|
||||||
statbuf.st_blocks = rip->i_blocks;
|
|
||||||
|
|
||||||
/* Copy the struct to user space. */
|
|
||||||
r = sys_safecopyto(who_e, gid, (vir_bytes) 0, (vir_bytes) &statbuf,
|
|
||||||
(size_t) sizeof(statbuf));
|
|
||||||
|
|
||||||
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 */
|
put_inode(rip); /* release the inode */
|
||||||
return(r);
|
|
||||||
|
return(OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* 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;
|
|
||||||
|
|
||||||
memset(&st, 0, sizeof(st));
|
|
||||||
|
|
||||||
sp = get_super(fs_dev);
|
sp = get_super(fs_dev);
|
||||||
|
|
||||||
st.f_flag = ST_NOTRUNC;
|
st->f_flag = ST_NOTRUNC;
|
||||||
st.f_bsize = sp->s_block_size;
|
st->f_bsize = sp->s_block_size;
|
||||||
st.f_frsize = sp->s_block_size;
|
st->f_frsize = sp->s_block_size;
|
||||||
st.f_iosize = sp->s_block_size;
|
st->f_iosize = sp->s_block_size;
|
||||||
st.f_blocks = sp->s_blocks_count;
|
st->f_blocks = sp->s_blocks_count;
|
||||||
st.f_bfree = sp->s_free_blocks_count;
|
st->f_bfree = sp->s_free_blocks_count;
|
||||||
st.f_bavail = sp->s_free_blocks_count - sp->s_r_blocks_count;
|
st->f_bavail = sp->s_free_blocks_count - sp->s_r_blocks_count;
|
||||||
st.f_files = sp->s_inodes_count;
|
st->f_files = sp->s_inodes_count;
|
||||||
st.f_ffree = sp->s_free_inodes_count;
|
st->f_ffree = sp->s_free_inodes_count;
|
||||||
st.f_favail = sp->s_free_inodes_count;
|
st->f_favail = sp->s_free_inodes_count;
|
||||||
st.f_namemax = NAME_MAX;
|
st->f_namemax = EXT2_NAME_MAX;
|
||||||
|
|
||||||
/* Copy the struct to user space. */
|
return(OK);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* blockstats *
|
* blockstats *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void fs_blockstats(u64_t *blocks, u64_t *free, u64_t *used)
|
void fs_blockstats(u64_t *blocks, u64_t *free, u64_t *used)
|
||||||
{
|
{
|
||||||
struct super_block *sp = get_super(fs_dev);
|
struct super_block *sp = get_super(fs_dev);
|
||||||
|
|
|
@ -100,7 +100,6 @@ EXTERN struct super_block {
|
||||||
int s_rd_only; /* set to 1 if file sys mounted read only */
|
int s_rd_only; /* set to 1 if file sys mounted read only */
|
||||||
block_t s_bsearch; /* all data blocks below this block are in use*/
|
block_t s_bsearch; /* all data blocks below this block are in use*/
|
||||||
int s_igsearch; /* all groups below this one have no free inodes */
|
int s_igsearch; /* all groups below this one have no free inodes */
|
||||||
char s_is_root;
|
|
||||||
u32_t s_dirs_counter;
|
u32_t s_dirs_counter;
|
||||||
|
|
||||||
} *superblock, *ondisk_superblock;
|
} *superblock, *ondisk_superblock;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* 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.
|
||||||
*
|
*
|
||||||
* Created (MFS based):
|
* Created (MFS based):
|
||||||
|
@ -12,39 +12,36 @@
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
|
|
||||||
int (*fs_call_vec[])(void) = {
|
struct fsdriver ext2_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 */
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,75 +3,50 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include <minix/callnr.h>
|
|
||||||
#include <minix/com.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);
|
||||||
|
|
||||||
/*
|
rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */
|
||||||
* Only the owner of a file or the super_user can change the timestamps.
|
|
||||||
* Here we assume VFS did that check before.
|
|
||||||
*/
|
|
||||||
|
|
||||||
r = OK;
|
switch (atime->tv_nsec) {
|
||||||
if(read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */
|
case UTIME_NOW:
|
||||||
if(r == OK) {
|
rip->i_update |= ATIME;
|
||||||
rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */
|
break;
|
||||||
switch(fs_m_in.m_vfs_fs_utime.acnsec) {
|
case UTIME_OMIT: /* do not touch */
|
||||||
case UTIME_NOW:
|
break;
|
||||||
rip->i_update |= ATIME;
|
default:
|
||||||
break;
|
/* Ext2FS does not support subsecond resolution, so we round down. */
|
||||||
case UTIME_OMIT: /* do not touch */
|
rip->i_atime = atime->tv_sec;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
/*
|
|
||||||
* cases fs_m_in.m_vfs_fs_utime.acnsec < 0 || fs_m_in.m_vfs_fs_utime.acnsec >= 1E9
|
|
||||||
* are caught by VFS to cooperate with old instances of EXT2
|
|
||||||
*/
|
|
||||||
rip->i_atime = fs_m_in.m_vfs_fs_utime.actime;
|
|
||||||
/*
|
|
||||||
* Ext2FS does not support better than second resolution,
|
|
||||||
* so we discard ACNSEC to round down
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(fs_m_in.m_vfs_fs_utime.modnsec) {
|
|
||||||
case UTIME_NOW:
|
|
||||||
rip->i_update |= MTIME;
|
|
||||||
break;
|
|
||||||
case UTIME_OMIT: /* do not touch */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/*
|
|
||||||
* cases fs_m_in.m_vfs_fs_utime.modnsec < 0 || fs_m_in.m_vfs_fs_utime.modnsec >= 1E9
|
|
||||||
* are caught by VFS to cooperate with old instances of EXT2
|
|
||||||
*/
|
|
||||||
rip->i_mtime = fs_m_in.m_vfs_fs_utime.modtime;
|
|
||||||
/*
|
|
||||||
* Ext2FS does not support better than second resolution,
|
|
||||||
* so we discard MODNSEC to round down
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
rip->i_dirt = IN_DIRTY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (mtime->tv_nsec) {
|
||||||
|
case UTIME_NOW:
|
||||||
|
rip->i_update |= MTIME;
|
||||||
|
break;
|
||||||
|
case UTIME_OMIT: /* do not touch */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ext2FS does not support subsecond resolution, so we round down. */
|
||||||
|
rip->i_mtime = mtime->tv_sec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rip->i_dirt = IN_DIRTY;
|
||||||
|
|
||||||
put_inode(rip);
|
put_inode(rip);
|
||||||
return(r);
|
return(OK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,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 *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -51,33 +40,6 @@ long x; /* 32-bit long to be byte swapped */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* mfs_min *
|
|
||||||
*===========================================================================*/
|
|
||||||
int min(unsigned int l, unsigned int r)
|
|
||||||
{
|
|
||||||
if(r >= l) return(l);
|
|
||||||
|
|
||||||
return(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* mfs_nul *
|
|
||||||
*===========================================================================*/
|
|
||||||
void mfs_nul_f(const char *file, int line, const char *str, unsigned int len,
|
|
||||||
unsigned int maxlen)
|
|
||||||
{
|
|
||||||
if(len < maxlen && str[len-1] != '\0') {
|
|
||||||
printf("ext2 %s:%d string (length %d, maxlen %d) not null-terminated\n",
|
|
||||||
file, line, len, maxlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MYASSERT(c) if(!(c)) { printf("ext2:%s:%d: sanity check: %s failed\n", \
|
|
||||||
file, line, #c); panic("sanity check " #c " failed: %d", __LINE__); }
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* ansi_strcmp *
|
* ansi_strcmp *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
Loading…
Reference in a new issue