diff --git a/bin/pax/ar_io.c b/bin/pax/ar_io.c index d3d69a45f..164740a26 100644 --- a/bin/pax/ar_io.c +++ b/bin/pax/ar_io.c @@ -456,13 +456,8 @@ ar_close(void) /* mimic cpio's block count first */ if (frmt && strcmp(NM_CPIO, argv0) == 0) { -#ifdef __minix - (void)fprintf(listf, "%d blocks\n", - (rdcnt ? rdcnt : wrcnt) / 5120); -#else (void)fprintf(listf, OFFT_F " blocks\n", (rdcnt ? rdcnt : wrcnt) / 5120); -#endif } ar_summary(0); diff --git a/include/minix/callnr.h b/include/minix/callnr.h index 629f04ec2..bcb574ccd 100644 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -17,7 +17,7 @@ #define CHMOD 15 #define CHOWN 16 #define BRK 17 -#define LSEEK 19 +#define LSEEK_321 19 #define MINIX_GETPID 20 #define MOUNT 21 #define UMOUNT 22 @@ -48,7 +48,7 @@ #define FSTAT 52 #define LSTAT 53 #define IOCTL 54 -#define FCNTL 55 +#define FCNTL_321 55 #define FS_READY 57 #define PIPE2 58 #define EXEC 59 @@ -59,6 +59,8 @@ #define ITIMER 64 #define GETMCONTEXT 67 #define SETMCONTEXT 68 +#define GETDENTS 69 +#define FTRUNCATE 70 /* Posix signal handling. */ #define SIGACTION 71 @@ -70,7 +72,7 @@ #define REBOOT 76 #define SVRCTL 77 #define SYSUNAME 78 -#define GETDENTS 80 /* to VFS */ +#define GETDENTS_321 80 /* to VFS */ #define LLSEEK 81 /* to VFS */ #define FSTATFS 82 /* to VFS */ #define STATVFS 83 /* to VFS */ @@ -83,14 +85,14 @@ #define GETTIMEOFDAY 90 /* to PM */ #define SETEUID 91 /* to PM */ #define SETEGID 92 /* to PM */ -#define TRUNCATE 93 /* to VFS */ -#define FTRUNCATE 94 /* to VFS */ +#define TRUNCATE_321 93 /* to VFS */ +#define FTRUNCATE_321 94 /* to VFS */ #define FCHMOD 95 /* to VFS */ #define FCHOWN 96 /* to VFS */ +#define LSEEK 97 #define SPROF 98 /* to PM */ #define CPROF 99 /* to PM */ -/* Calls provided by PM and FS that are not part of the API */ #define PM_NEWEXEC 100 /* from VFS or RS to PM: new exec */ #define SRV_FORK 101 /* to PM: special fork call for RS */ #define EXEC_RESTART 102 /* to PM: final part of exec for RS */ @@ -98,6 +100,8 @@ #define ISSETUGID 106 /* to PM: ask if process is tainted */ #define GETEPINFO_O 107 /* to PM: get pid/uid/gid of an endpoint */ #define UTIMENS 108 /* to FS: [f]utimens(); also [fl]utimes */ +#define FCNTL 109 /* to VFS */ +#define TRUNCATE 110 /* to VFS */ #define SRV_KILL 111 /* to PM: special kill call for RS */ #define GCOV_FLUSH 112 /* flush gcov data from server to gcov files */ diff --git a/include/minix/config.h b/include/minix/config.h index 0ae3767a7..216c3fc9f 100644 --- a/include/minix/config.h +++ b/include/minix/config.h @@ -5,6 +5,9 @@ #define OS_RELEASE "3" #define OS_VERSION "2.1" +/* Keep these in sync with os_version above for temp version check in VFS */ +#define OS_VMAJOR 2 +#define OS_VMINOR 1 /* This file sets configuration parameters for the MINIX kernel, FS, and PM. * It is divided up into two main sections. The first section contains * user-settable parameters. In the second section, various internal system diff --git a/include/minix/vfsif.h b/include/minix/vfsif.h index a9a9a722c..e34f5c8de 100644 --- a/include/minix/vfsif.h +++ b/include/minix/vfsif.h @@ -75,7 +75,7 @@ #define VFS_FS_PROTO_VERSION(b) (((b) & RES_PROTO_V_MASK) >> RES_PROTO_V_SHIFT) #define VFS_FS_PROTO_PUT_VERSION(b,v) \ ((b) |= (((v) << RES_PROTO_V_SHIFT) & RES_PROTO_V_MASK)) -#define VFS_FS_CURRENT_VERSION 0 /* Current version */ +#define VFS_FS_CURRENT_VERSION 1 /* Current version */ /* VFS/FS flags */ #define REQ_RDONLY 001 diff --git a/include/sys/statfs.h b/include/sys/statfs.h index 064f0eb56..a80eef121 100644 --- a/include/sys/statfs.h +++ b/include/sys/statfs.h @@ -7,7 +7,7 @@ #include struct statfs { - off_t f_bsize; /* file system block size */ + int f_bsize; /* file system block size */ }; int fstatfs(int fd, struct statfs *st); diff --git a/include/sys/vm.h b/include/sys/vm.h index e60ce198f..c211a2f2e 100644 --- a/include/sys/vm.h +++ b/include/sys/vm.h @@ -18,7 +18,7 @@ struct mapreq struct mapreqvm { int flags; /* reserved, must be 0 */ - off_t phys_offset; + phys_bytes phys_offset; size_t size; int readonly; char reserved[36]; /* reserved, must be 0 */ diff --git a/kernel/arch/earm/protect.c b/kernel/arch/earm/protect.c index 285d9dd2c..73e37a339 100644 --- a/kernel/arch/earm/protect.c +++ b/kernel/arch/earm/protect.c @@ -102,7 +102,7 @@ void arch_post_init(void) pg_info(&vm->p_seg.p_ttbr, &vm->p_seg.p_ttbr_v); } -int libexec_pg_alloc(struct exec_info *execi, off_t vaddr, size_t len) +static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len) { pg_map(PG_ALLOCATEME, vaddr, vaddr+len, &kinfo); pg_load(); diff --git a/kernel/arch/i386/protect.c b/kernel/arch/i386/protect.c index 5a98a41ad..0a9d2d25d 100644 --- a/kernel/arch/i386/protect.c +++ b/kernel/arch/i386/protect.c @@ -376,7 +376,7 @@ void arch_post_init(void) pg_info(&vm->p_seg.p_cr3, &vm->p_seg.p_cr3_v); } -int libexec_pg_alloc(struct exec_info *execi, off_t vaddr, size_t len) +static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len) { pg_map(PG_ALLOCATEME, vaddr, vaddr+len, &kinfo); pg_load(); diff --git a/lib/libc/sys-minix/fcntl.c b/lib/libc/sys-minix/fcntl.c index 59c37a652..1c6a29f45 100644 --- a/lib/libc/sys-minix/fcntl.c +++ b/lib/libc/sys-minix/fcntl.c @@ -2,6 +2,7 @@ #include "namespace.h" #include +#include #include #include @@ -9,12 +10,78 @@ __weak_alias(fcntl, _fcntl) #endif +static int __fcntl_321(int fd, int cmd, va_list argp); + +int __fcntl_321(int fd, int cmd, va_list argp) +{ + message m; + struct flock_321 f_321; + struct flock *flock; + int r; + + /* Set up for the sensible case where there is no variable parameter. This + * covers F_GETFD, F_GETFL and invalid commands. + */ + m.m1_i3 = 0; + m.m1_p1 = NULL; + + /* Adjust for the stupid cases. */ + switch(cmd) { + case F_DUPFD: + case F_SETFD: + case F_SETFL: + m.m1_i3 = va_arg(argp, int); + break; + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_FREESP: + /* VFS expects old format, so translate */ + flock = (struct flock *) va_arg(argp, struct flock *); + f_321.l_type = flock->l_type; + f_321.l_whence = flock->l_whence; + f_321.l_start = flock->l_start; + f_321.l_len = flock->l_len; + f_321.l_pid = flock->l_pid; + m.m1_p1 = (char *) &f_321; + break; + } + + /* Clean up and make the system call. */ + m.m1_i1 = fd; + m.m1_i2 = cmd; + + r = _syscall(VFS_PROC_NR, FCNTL_321, &m); + + if (r == 0) { + /* Maybe we need to convert back */ + + switch(cmd) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_FREESP: + /* VFS expected old format but libc new format, so translate */ + flock->l_type = f_321.l_type; + flock->l_whence = f_321.l_whence; + flock->l_start = f_321.l_start; + flock->l_len = f_321.l_len; + flock->l_pid = f_321.l_pid; + break; + } + } + + return r; +} + int fcntl(int fd, int cmd, ...) { - va_list argp; + va_list argp, argp_321; message m; + int r, org_errno; va_start(argp, cmd); + va_start(argp_321, cmd); /* Set up for the sensible case where there is no variable parameter. This * covers F_GETFD, F_GETFL and invalid commands. @@ -41,5 +108,15 @@ int fcntl(int fd, int cmd, ...) va_end(argp); m.m1_i1 = fd; m.m1_i2 = cmd; - return(_syscall(VFS_PROC_NR, FCNTL, &m)); + org_errno = errno; + r = _syscall(VFS_PROC_NR, FCNTL, &m); + + if (r == -1 && errno == ENOSYS) { + errno = org_errno; + r = __fcntl_321(fd, cmd, argp_321); + } + + va_end(argp_321); + + return r; } diff --git a/lib/libc/sys-minix/ftruncate.c b/lib/libc/sys-minix/ftruncate.c index e95e258e4..4437dfea8 100644 --- a/lib/libc/sys-minix/ftruncate.c +++ b/lib/libc/sys-minix/ftruncate.c @@ -2,6 +2,8 @@ #include "namespace.h" #include +#include +#include #include #include @@ -9,11 +11,38 @@ __weak_alias(ftruncate, _ftruncate) #endif -int ftruncate(int _fd, off_t _length) +static int __ftruncate_321(int _fd, int _length); + +static int __ftruncate_321(int _fd, int _length) { message m; m.m2_l1 = _length; m.m2_i1 = _fd; - return(_syscall(VFS_PROC_NR, FTRUNCATE, &m)); + return(_syscall(VFS_PROC_NR, FTRUNCATE_321, &m)); +} + +int ftruncate(int _fd, off_t _length) +{ + message m; + int orig_errno, r; + + m.m2_l1 = ex64lo(_length); + m.m2_l2 = ex64hi(_length); + m.m2_i1 = _fd; + + orig_errno = errno; + r = _syscall(VFS_PROC_NR, FTRUNCATE, &m); + if (r == -1 && errno == ENOSYS) { + /* Old VFS, no support for new ftruncate */ + if (_length >= INT_MIN && _length <= INT_MAX) { + errno = orig_errno; + return __ftruncate_321(_fd, (int) _length); + } + + /* Not going to fit */ + errno = EOVERFLOW; + } + + return r; } diff --git a/lib/libc/sys-minix/getdents.c b/lib/libc/sys-minix/getdents.c index ef17e5440..1cb2d715f 100644 --- a/lib/libc/sys-minix/getdents.c +++ b/lib/libc/sys-minix/getdents.c @@ -3,15 +3,83 @@ #include #include +#include +#include +#include +#include + +static ssize_t __getdents321(int fd, char *buffer, size_t nbytes); ssize_t getdents(int fd, char *buffer, size_t nbytes) { message m; + int r, orig_errno; + orig_errno = errno; m.m1_i1 = fd; m.m1_i2 = nbytes; m.m1_p1 = (char *) buffer; - return _syscall(VFS_PROC_NR, GETDENTS, &m); + r = _syscall(VFS_PROC_NR, GETDENTS, &m); + if (r == -1 && errno == ENOSYS) { + errno = orig_errno;/* Restore old value so world is still as expected*/ + r = __getdents321(fd, buffer, nbytes); + } + + return r; +} + +ssize_t __getdents321(int fd, char *buffer, size_t nbytes) +{ + message m; + int r, consumed = 0, newconsumed = 0; + char *intermediate = NULL; + struct dirent *dent; + struct dirent_321 *dent_321; +#define DWORD_ALIGN(d) if((d) % sizeof(long)) (d)+=sizeof(long)-(d)%sizeof(long) + + intermediate = malloc(nbytes); + if (intermediate == NULL) return EINVAL; + + m.m1_i1 = fd; + /* Pretend the buffer is smaller so we know the converted/expanded version + * will fit. + */ + nbytes = nbytes / 2; + if (nbytes < (sizeof(struct dirent) + NAME_MAX + 1)) { + free(intermediate); + return EINVAL; /* This might not fit. Sorry */ + } + + m.m1_i2 = nbytes; + m.m1_p1 = (char *) intermediate; + r = _syscall(VFS_PROC_NR, GETDENTS_321, &m); + + if (r <= 0) { + free(intermediate); + return r; + } + + /* Provided format is struct dirent_321 and has to be translated to + * struct dirent */ + dent_321 = (struct dirent_321 *) intermediate; + dent = (struct dirent *) buffer; + + while (consumed < r && dent_321->d_reclen > 0) { + dent->d_ino = (ino_t) dent_321->d_ino; + dent->d_off = (off_t) dent_321->d_off; + dent->d_reclen = offsetof(struct dirent, d_name) + + strlen(dent_321->d_name) + 1; + DWORD_ALIGN(dent->d_reclen); + strcpy(dent->d_name, dent_321->d_name); + consumed += dent_321->d_reclen; + newconsumed += dent->d_reclen; + dent_321 = (struct dirent_321 *) &intermediate[consumed]; + dent = (struct dirent *) &buffer[newconsumed]; + } + + free(intermediate); + + return newconsumed; } #if defined(__minix) && defined(__weak_alias) diff --git a/lib/libc/sys-minix/lseek.c b/lib/libc/sys-minix/lseek.c index fbcfb09aa..73d8414f0 100644 --- a/lib/libc/sys-minix/lseek.c +++ b/lib/libc/sys-minix/lseek.c @@ -2,22 +2,53 @@ #include "namespace.h" #include +#include +#include #include #ifdef __weak_alias __weak_alias(lseek, _lseek) #endif -off_t lseek(fd, offset, whence) -int fd; -off_t offset; -int whence; +i32_t __lseek_321(int fd, i32_t offset, int whence); + +i32_t __lseek_321(int fd, i32_t offset, int whence) { message m; m.m2_i1 = fd; m.m2_l1 = offset; m.m2_i2 = whence; - if (_syscall(VFS_PROC_NR, LSEEK, &m) < 0) return( (off_t) -1); - return( (off_t) m.m2_l1); + if (_syscall(VFS_PROC_NR, LSEEK_321, &m) < 0) return(-1); + return( (i32_t) m.m2_l1); +} + +off_t +lseek(int fd, off_t offset, int whence) +{ + message m; + int orig_errno; + + m.m2_i1 = fd; + m.m2_l1 = ex64lo(offset); + m.m2_l2 = ex64hi(offset); + m.m2_i2 = whence; + + orig_errno = errno; + if (_syscall(VFS_PROC_NR, LSEEK, &m) < 0) { + if (errno == ENOSYS) { + /* Old VFS, no support for new lseek */ + if (offset >= INT_MIN && offset <= INT_MAX) { + /* offset fits in old range, retry */ + errno = orig_errno; + return (off_t) __lseek_321(fd, (i32_t) offset, whence); + } + + /* Not going to fit */ + errno = EOVERFLOW; + } + + return( (off_t) -1); + } + return( (off_t) make64(m.m2_l1, m.m2_l2)); } diff --git a/lib/libc/sys-minix/truncate.c b/lib/libc/sys-minix/truncate.c index e72ca9da4..1d20db861 100644 --- a/lib/libc/sys-minix/truncate.c +++ b/lib/libc/sys-minix/truncate.c @@ -6,16 +6,46 @@ __weak_alias(truncate, _truncate) #endif +#include +#include #include #include +static int __truncate_321(const char *_path, int _length); -int truncate(const char *_path, off_t _length) +static int __truncate_321(const char *_path, int _length) { message m; m.m2_p1 = (char *) __UNCONST(_path); m.m2_i1 = strlen(_path)+1; m.m2_l1 = _length; - return(_syscall(VFS_PROC_NR, TRUNCATE, &m)); + return(_syscall(VFS_PROC_NR, TRUNCATE_321, &m)); +} + +int truncate(const char *_path, off_t _length) +{ + message m; + int orig_errno, r; + + m.m2_p1 = (char *) __UNCONST(_path); + m.m2_i1 = strlen(_path)+1; + m.m2_l1 = ex64lo(_length); + m.m2_l2 = ex64hi(_length); + + orig_errno = errno; + r = _syscall(VFS_PROC_NR, TRUNCATE, &m); + + if (r == -1 && errno == ENOSYS) { + /* Old VFS, no support for new truncate */ + if (_length >= INT_MIN && _length <= INT_MAX) { + errno = orig_errno; + return __truncate_321(_path, (int) _length); + } + + /* Not going to fit */ + errno = EOVERFLOW; + } + + return r; } diff --git a/lib/libexec/exec_general.c b/lib/libexec/exec_general.c index a1afecfa7..e9145c611 100644 --- a/lib/libexec/exec_general.c +++ b/lib/libexec/exec_general.c @@ -18,7 +18,7 @@ #include #include -int libexec_alloc_mmap_prealloc_junk(struct exec_info *execi, off_t vaddr, size_t len) +int libexec_alloc_mmap_prealloc_junk(struct exec_info *execi, vir_bytes vaddr, size_t len) { if(minix_mmap_for(execi->proc_e, (void *) vaddr, len, PROT_READ|PROT_WRITE|PROT_EXEC, @@ -29,7 +29,7 @@ int libexec_alloc_mmap_prealloc_junk(struct exec_info *execi, off_t vaddr, size_ return OK; } -int libexec_alloc_mmap_prealloc_cleared(struct exec_info *execi, off_t vaddr, size_t len) +int libexec_alloc_mmap_prealloc_cleared(struct exec_info *execi, vir_bytes vaddr, size_t len) { if(minix_mmap_for(execi->proc_e, (void *) vaddr, len, PROT_READ|PROT_WRITE|PROT_EXEC, @@ -40,7 +40,7 @@ int libexec_alloc_mmap_prealloc_cleared(struct exec_info *execi, off_t vaddr, si return OK; } -int libexec_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len) +int libexec_alloc_mmap_ondemand(struct exec_info *execi, vir_bytes vaddr, size_t len) { if(minix_mmap_for(execi->proc_e, (void *) vaddr, len, PROT_READ|PROT_WRITE|PROT_EXEC, @@ -56,20 +56,20 @@ int libexec_clearproc_vm_procctl(struct exec_info *execi) return vm_procctl(execi->proc_e, VMPPARAM_CLEAR); } -int libexec_clear_sys_memset(struct exec_info *execi, off_t vaddr, size_t len) +int libexec_clear_sys_memset(struct exec_info *execi, vir_bytes vaddr, size_t len) { return sys_memset(execi->proc_e, 0, vaddr, len); } int libexec_copy_memcpy(struct exec_info *execi, - off_t off, off_t vaddr, size_t len) + off_t off, vir_bytes vaddr, size_t len) { assert(off + len <= execi->hdr_len); memcpy((char *) vaddr, (char *) execi->hdr + off, len); return OK; } -int libexec_clear_memset(struct exec_info *execi, off_t vaddr, size_t len) +int libexec_clear_memset(struct exec_info *execi, vir_bytes vaddr, size_t len) { memset((char *) vaddr, 0, len); return OK; diff --git a/lib/libexec/libexec.h b/lib/libexec/libexec.h index b9a8fe15f..b9ba03ee5 100644 --- a/lib/libexec/libexec.h +++ b/lib/libexec/libexec.h @@ -6,13 +6,13 @@ struct exec_info; typedef int (*libexec_loadfunc_t)(struct exec_info *execi, - off_t offset, off_t vaddr, size_t len); + off_t offset, vir_bytes vaddr, size_t len); typedef int (*libexec_clearfunc_t)(struct exec_info *execi, - off_t vaddr, size_t len); + vir_bytes vaddr, size_t len); typedef int (*libexec_allocfunc_t)(struct exec_info *execi, - off_t vaddr, size_t len); + vir_bytes vaddr, size_t len); typedef int (*libexec_procclearfunc_t)(struct exec_info *execi); @@ -61,12 +61,15 @@ int libexec_pm_newexec(endpoint_t proc_e, struct exec_info *execi); typedef int (*libexec_exec_loadfunc_t)(struct exec_info *execi); int libexec_load_elf(struct exec_info *execi); -int libexec_copy_memcpy(struct exec_info *execi, off_t offset, off_t vaddr, size_t len); -int libexec_clear_memset(struct exec_info *execi, off_t vaddr, size_t len); -int libexec_alloc_mmap_prealloc_cleared(struct exec_info *execi, off_t vaddr, size_t len); -int libexec_alloc_mmap_prealloc_junk(struct exec_info *execi, off_t vaddr, size_t len); -int libexec_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len); +/* Default callbacks for kernel. */ +int libexec_copy_memcpy(struct exec_info *execi, off_t offset, vir_bytes vaddr, size_t len); +int libexec_clear_memset(struct exec_info *execi, vir_bytes vaddr, size_t len); + +/* Default callbacks. */ +int libexec_alloc_mmap_prealloc_cleared(struct exec_info *execi, vir_bytes vaddr, size_t len); +int libexec_alloc_mmap_prealloc_junk(struct exec_info *execi, vir_bytes vaddr, size_t len); +int libexec_alloc_mmap_ondemand(struct exec_info *execi, vir_bytes vaddr, size_t len); int libexec_clearproc_vm_procctl(struct exec_info *execi); -int libexec_clear_sys_memset(struct exec_info *execi, off_t vaddr, size_t len); +int libexec_clear_sys_memset(struct exec_info *execi, vir_bytes vaddr, size_t len); #endif /* !_LIBEXEC_H_ */ diff --git a/lib/libvtreefs/glo.h b/lib/libvtreefs/glo.h index c770ae5d0..f57983c37 100644 --- a/lib/libvtreefs/glo.h +++ b/lib/libvtreefs/glo.h @@ -8,6 +8,7 @@ EXTERN struct fs_hooks *vtreefs_hooks; +EXTERN int proto_version; EXTERN message fs_m_in; EXTERN message fs_m_out; diff --git a/lib/libvtreefs/mount.c b/lib/libvtreefs/mount.c index 06c7a05f6..6006c6034 100644 --- a/lib/libvtreefs/mount.c +++ b/lib/libvtreefs/mount.c @@ -18,6 +18,13 @@ int fs_readsuper(void) if (fs_m_in.REQ_FLAGS & REQ_ISROOT) return EINVAL; + /* Get VFS-FS protocol version */ + if (!(fs_m_in.REQ_FLAGS & REQ_HASPROTO)) { + proto_version = 0; + } else { + proto_version = VFS_FS_PROTO_VERSION(fs_m_in.REQ_PROTO); + } + /* Get the root inode and increase its reference count. */ root = get_root_inode(); ref_inode(root); diff --git a/lib/libvtreefs/read.c b/lib/libvtreefs/read.c index d5357622e..9947536f3 100644 --- a/lib/libvtreefs/read.c +++ b/lib/libvtreefs/read.c @@ -67,6 +67,153 @@ int fs_read(void) return r; } +/*===========================================================================* + * fs_getdents_321 * + *===========================================================================*/ +int fs_getdents_321(void) +{ + /* Retrieve directory entries. + */ + struct inode *node, *child = NULL; + struct dirent_321 *dent; + char *name; + size_t len, off, user_off, user_left; + off_t pos; + int r, skip, get_next, indexed; + static char buf[GETDENTS_BUFSIZ]; + + if (fs_m_in.REQ_SEEK_POS_HI != 0) + return EIO; + + if ((node = find_inode(fs_m_in.REQ_INODE_NR)) == NULL) + return EINVAL; + + off = 0; + user_off = 0; + user_left = fs_m_in.REQ_MEM_SIZE; + indexed = node->i_indexed; + get_next = FALSE; + child = NULL; + + /* Call the getdents hook, if any, to "refresh" the directory. */ + if (!is_inode_deleted(node) && vtreefs_hooks->getdents_hook != NULL) { + r = vtreefs_hooks->getdents_hook(node, get_inode_cbdata(node)); + if (r != OK) return r; + } + + for (pos = fs_m_in.REQ_SEEK_POS_LO; ; pos++) { + /* Determine which inode and name to use for this entry. */ + if (pos == 0) { + /* The "." entry. */ + child = node; + name = "."; + } + else if (pos == 1) { + /* The ".." entry. */ + child = get_parent_inode(node); + if (child == NULL) + child = node; + name = ".."; + } + else if (pos - 2 < indexed) { + /* All indexed entries. */ + child = get_inode_by_index(node, pos - 2); + + /* If there is no inode with this particular index, + * continue with the next index number. + */ + if (child == NULL) continue; + + name = child->i_name; + } + else { + /* All non-indexed entries. */ + + /* If this is the first loop iteration, first get to + * the non-indexed child identified by the current + * position. + */ + if (get_next == FALSE) { + skip = pos - indexed - 2; + child = get_first_inode(node); + + /* Skip indexed children. */ + while (child != NULL && + child->i_index != NO_INDEX) + child = get_next_inode(child); + + /* Skip to the right position. */ + while (child != NULL && skip-- > 0) + child = get_next_inode(child); + + get_next = TRUE; + } + else { + child = get_next_inode(child); + } + + /* No more children? Then stop. */ + if (child == NULL) + break; + + assert(!is_inode_deleted(child)); + + name = child->i_name; + } + + len = DWORD_ALIGN(sizeof(struct dirent_321) + strlen(name)); + + /* Is the user buffer too small to store another record? */ + if (user_off + off + len > user_left) { + /* Is the user buffer too small for even a single + * record? + */ + if (user_off == 0 && off == 0) + return EINVAL; + + break; + } + + /* If our own buffer cannot contain the new record, copy out + * first. + */ + if (off + len > sizeof(buf)) { + r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, + user_off, (vir_bytes) buf, off); + if (r != OK) return r; + + user_off += off; + user_left -= off; + off = 0; + } + + /* Fill in the actual directory entry. */ + dent = (struct dirent_321 *) &buf[off]; + dent->d_ino = (u32_t) get_inode_number(child); + dent->d_off = (i32_t) pos; + dent->d_reclen = len; + strcpy(dent->d_name, name); + + off += len; + } + + /* If there is anything left in our own buffer, copy that out now. */ + if (off > 0) { + r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, + user_off, (vir_bytes) buf, off); + if (r != OK) + return r; + + user_off += off; + } + + fs_m_out.RES_SEEK_POS_HI = 0; + fs_m_out.RES_SEEK_POS_LO = pos; + fs_m_out.RES_NBYTES = user_off; + + return OK; +} + /*===========================================================================* * fs_getdents * *===========================================================================*/ @@ -82,6 +229,9 @@ int fs_getdents(void) int r, skip, get_next, indexed; static char buf[GETDENTS_BUFSIZ]; + if (proto_version == 0) + return fs_getdents_321(); + if (fs_m_in.REQ_SEEK_POS_HI != 0) return EIO; @@ -189,8 +339,8 @@ int fs_getdents(void) /* Fill in the actual directory entry. */ dent = (struct dirent *) &buf[off]; - dent->d_ino = get_inode_number(child); - dent->d_off = pos; + dent->d_ino = (ino_t) get_inode_number(child); + dent->d_off = (off_t) pos; dent->d_reclen = len; strcpy(dent->d_name, name); diff --git a/servers/ext2/glo.h b/servers/ext2/glo.h index 2f20f8c8d..f79e03be5 100644 --- a/servers/ext2/glo.h +++ b/servers/ext2/glo.h @@ -21,6 +21,8 @@ extern char dot2[3]; /* meaning to search_dir: no access permission check. */ extern int(*fs_call_vec[]) (void); +EXTERN int proto_version; + EXTERN message fs_m_in; EXTERN message fs_m_out; EXTERN vfs_ucred_t credentials; diff --git a/servers/ext2/link.c b/servers/ext2/link.c index 3304834dd..514714132 100644 --- a/servers/ext2/link.c +++ b/servers/ext2/link.c @@ -719,7 +719,7 @@ off_t len; panic("zeroblock_range: no block"); offset = pos % rip->i_sp->s_block_size; if (offset + len > rip->i_sp->s_block_size) - panic("zeroblock_range: len too long: %d", len); + panic("zeroblock_range: len too long: %lld", len); memset(b_data(bp) + offset, 0, len); lmfs_markdirty(bp); put_block(bp, FULL_DATA_BLOCK); diff --git a/servers/ext2/mount.c b/servers/ext2/mount.c index fbd4f754a..07186dc84 100644 --- a/servers/ext2/mount.c +++ b/servers/ext2/mount.c @@ -39,6 +39,12 @@ int fs_readsuper() readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0; isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0; + if (!(fs_m_in.REQ_FLAGS & REQ_HASPROTO)) { + proto_version = 0; + } else { + proto_version = VFS_FS_PROTO_VERSION(fs_m_in.REQ_PROTO); + } + if (label_len > sizeof(fs_dev_label)) return(EINVAL); diff --git a/servers/ext2/read.c b/servers/ext2/read.c index f9af4c720..6f4d8b90f 100644 --- a/servers/ext2/read.c +++ b/servers/ext2/read.c @@ -610,6 +610,159 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ } +/*===========================================================================* + * fs_getdents_321 * + *===========================================================================*/ +static int fs_getdents_321(void) +{ +#define GETDENTS_321_BUFSIZE (sizeof(struct dirent_321) + EXT2_NAME_MAX + 1) +#define GETDENTS_321_ENTRIES 8 + static char getdents_buf[GETDENTS_321_BUFSIZE * GETDENTS_321_ENTRIES]; + struct inode *rip; + int o, r, done; + unsigned int block_size, len, reclen; + pino_t ino; + block_t b; + cp_grant_id_t gid; + size_t size, tmpbuf_off, userbuf_off; + off_t pos, off, block_pos, new_pos, ent_pos; + struct buf *bp; + struct ext2_disk_dir_desc *d_desc; + struct dirent *dep; + + ino = (pino_t) fs_m_in.REQ_INODE_NR; + gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; + size = (size_t) fs_m_in.REQ_MEM_SIZE; + pos = (off_t) fs_m_in.REQ_SEEK_POS_LO; + + /* Check whether the position is properly aligned */ + if ((unsigned int) pos % DIR_ENTRY_ALIGN) + return(ENOENT); + + if ((rip = get_inode(fs_dev, ino)) == NULL) + return(EINVAL); + + block_size = rip->i_sp->s_block_size; + off = (pos % block_size); /* Offset in block */ + block_pos = pos - off; + done = FALSE; /* Stop processing directory blocks when done is set */ + + memset(getdents_buf, '\0', sizeof(getdents_buf)); /* Avoid leaking any data */ + tmpbuf_off = 0; /* Offset in 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 + * fills up before EOF, new_pos will be modified. */ + new_pos = rip->i_size; + + for (; block_pos < rip->i_size; block_pos += block_size) { + off_t temp_pos = block_pos; + b = read_map(rip, block_pos, 0); /* get block number */ + /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */ + bp = get_block(rip->i_dev, b, NORMAL); /* get a dir block */ + assert(bp != NULL); + + /* Search a directory block. */ + d_desc = (struct ext2_disk_dir_desc*) &b_data(bp); + + /* we need to seek to entry at off bytes. + * when NEXT_DISC_DIR_POS == block_size it's last dentry. + */ + for (; temp_pos + conv2(le_CPU, d_desc->d_rec_len) <= pos + && NEXT_DISC_DIR_POS(d_desc, &b_data(bp)) < block_size; + d_desc = NEXT_DISC_DIR_DESC(d_desc)) { + temp_pos += conv2(le_CPU, d_desc->d_rec_len); + } + + for (; CUR_DISC_DIR_POS(d_desc, &b_data(bp)) < block_size; + d_desc = NEXT_DISC_DIR_DESC(d_desc)) { + if (d_desc->d_ino == 0) + continue; /* Entry is not in use */ + +#if 0 /* d_nam_len is a uint8_t, so the test is always false. */ + if (d_desc->d_name_len > NAME_MAX || + d_desc->d_name_len > EXT2_NAME_MAX) { + len = min(NAME_MAX, EXT2_NAME_MAX); + } else { + len = d_desc->d_name_len; + } +#endif + len = d_desc->d_name_len; + + /* Compute record length */ + reclen = offsetof(struct dirent_321, d_name) + len + 1; + o = (reclen % sizeof(long)); + if (o != 0) + reclen += sizeof(long) - o; + + /* Need the position of this entry in the directory */ + ent_pos = block_pos + ((char *)d_desc - b_data(bp)); + + if (userbuf_off + tmpbuf_off + reclen >= size) { + /* The user has no space for one more record */ + done = TRUE; + + /* Record the position of this entry, it is the + * starting point of the next request (unless the + * position is modified with lseek). + */ + new_pos = ent_pos; + break; + } + + if (tmpbuf_off + reclen >= + GETDENTS_321_BUFSIZE * GETDENTS_321_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_ino = (u32_t) conv4(le_CPU, d_desc->d_ino); + dep->d_off = (i32_t) ent_pos; + dep->d_reclen = (unsigned short) reclen; + memcpy(dep->d_name, d_desc->d_name, len); + dep->d_name[len] = '\0'; + tmpbuf_off += reclen; + } + + put_block(bp, DIRECTORY_BLOCK); + if (done) + break; + } + + if (tmpbuf_off != 0) { + 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; + } + + if (done && userbuf_off == 0) + r = EINVAL; /* The user's buffer is too small */ + else { + fs_m_out.RES_NBYTES = userbuf_off; + fs_m_out.RES_SEEK_POS_LO = new_pos; + rip->i_update |= ATIME; + rip->i_dirt = IN_DIRTY; + r = OK; + } + + put_inode(rip); /* release the inode */ + return(r); +} + /*===========================================================================* * fs_getdents * *===========================================================================*/ @@ -629,6 +782,10 @@ int fs_getdents(void) struct ext2_disk_dir_desc *d_desc; struct dirent *dep; + if (proto_version == 0) { + return fs_getdents_321(); + } + ino = (pino_t) fs_m_in.REQ_INODE_NR; gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; size = (size_t) fs_m_in.REQ_MEM_SIZE; @@ -729,8 +886,8 @@ int fs_getdents(void) } dep = (struct dirent *) &getdents_buf[tmpbuf_off]; - dep->d_ino = conv4(le_CPU, d_desc->d_ino); - dep->d_off = ent_pos; + dep->d_ino = (ino_t) conv4(le_CPU, d_desc->d_ino); + dep->d_off = (off_t) ent_pos; dep->d_reclen = (unsigned short) reclen; memcpy(dep->d_name, d_desc->d_name, len); dep->d_name[len] = '\0'; diff --git a/servers/iso9660fs/const.h b/servers/iso9660fs/const.h index 3dfd35317..3174947f1 100644 --- a/servers/iso9660fs/const.h +++ b/servers/iso9660fs/const.h @@ -1,5 +1,5 @@ -#define GETDENTS_BUFSIZ 257 +#define GETDENTS_BUFSIZ 261 #define ISO9660_STANDARD_ID "CD001" /* Standard code for ISO9660 filesystems */ diff --git a/servers/iso9660fs/glo.h b/servers/iso9660fs/glo.h index 9ddf8b2df..0e5bc5050 100644 --- a/servers/iso9660fs/glo.h +++ b/servers/iso9660fs/glo.h @@ -19,6 +19,7 @@ EXTERN int FS_STATE; EXTERN uid_t caller_uid; EXTERN gid_t caller_gid; +EXTERN int proto_version; EXTERN int req_nr; /* request number to the server */ EXTERN int SELF_E; /* process number */ diff --git a/servers/iso9660fs/mount.c b/servers/iso9660fs/mount.c index 62e2fa952..021c7ab6e 100644 --- a/servers/iso9660fs/mount.c +++ b/servers/iso9660fs/mount.c @@ -18,6 +18,12 @@ int fs_readsuper() { label_gid = fs_m_in.REQ_GRANT; label_len = fs_m_in.REQ_PATH_LEN; + if (!(fs_m_in.REQ_FLAGS & REQ_HASPROTO)) { + proto_version = 0; + } else { + proto_version = VFS_FS_PROTO_VERSION(fs_m_in.REQ_PROTO); + } + if (label_len > sizeof(fs_dev_label)) return(EINVAL); diff --git a/servers/iso9660fs/read.c b/servers/iso9660fs/read.c index 917dea79c..a55d5933c 100644 --- a/servers/iso9660fs/read.c +++ b/servers/iso9660fs/read.c @@ -137,9 +137,9 @@ int fs_bread(void) /*===========================================================================* - * fs_getdents * + * fs_getdents_321 * *===========================================================================*/ -int fs_getdents(void) { +int fs_getdents_321(void) { struct dir_record *dir; pino_t ino; cp_grant_id_t gid; @@ -246,7 +246,158 @@ int fs_getdents(void) { /* The standard data structure is created using the * data in the buffer. */ dirp = (struct dirent *) &getdents_buf[tmpbuf_offset]; - dirp->d_ino = (pino_t)(b_data(bp) + block_pos); + dirp->d_ino = (u32_t) (b_data(bp) + block_pos); + dirp->d_off= (i32_t) cur_pos; + dirp->d_reclen= reclen; + memcpy(dirp->d_name, name, len); + dirp->d_name[len]= '\0'; + tmpbuf_offset += reclen; + + cur_pos += dir_tmp->length; + release_dir_record(dir_tmp); + } + + block_pos += dir_tmp->length; + } + + put_block(bp); /* release the block */ + if (done == TRUE) break; + + cur_pos += block_size - cur_pos; + block++; /* read the next one */ + } + + if (tmpbuf_offset != 0) { + r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off, + (vir_bytes) getdents_buf, tmpbuf_offset); + if (r != OK) + panic("fs_getdents: sys_safecopyto failed: %d", r); + + userbuf_off += tmpbuf_offset; + } + + fs_m_out.RES_NBYTES = userbuf_off; + fs_m_out.RES_SEEK_POS_LO = cur_pos; + + release_dir_record(dir); /* release the inode */ + return(OK); +} + +/*===========================================================================* + * fs_getdents * + *===========================================================================*/ +int fs_getdents(void) { + struct dir_record *dir; + pino_t ino; + cp_grant_id_t gid; + size_t block_size; + off_t pos, block_pos, block, cur_pos, tmpbuf_offset, userbuf_off; + struct buf *bp; + struct dir_record *dir_tmp; + struct dirent *dirp; + int r,done,o,len,reclen; + char *cp; + char name[NAME_MAX + 1]; + char name_old[NAME_MAX + 1]; + + if (proto_version == 0) { + return fs_getdents_321(); + } + + /* Initialize the tmp arrays */ + memset(name,'\0',NAME_MAX); + memset(name_old,'\0',NAME_MAX); + + /* Get input parameters */ + ino = fs_m_in.REQ_INODE_NR; + gid = fs_m_in.REQ_GRANT; + pos = fs_m_in.REQ_SEEK_POS_LO; + + block_size = v_pri.logical_block_size_l; + cur_pos = pos; /* The current position */ + tmpbuf_offset = 0; + userbuf_off = 0; + memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */ + + if ((dir = get_dir_record(ino)) == NULL) return(EINVAL); + + block = dir->loc_extent_l; /* First block of the directory */ + block += pos / block_size; /* Shift to the block where start to read */ + done = FALSE; + + while (cur_posd_file_size) { + bp = get_block(block); /* Get physical block */ + + if (bp == NULL) { + release_dir_record(dir); + return(EINVAL); + } + + block_pos = cur_pos % block_size; /* Position where to start read */ + + while (block_pos < block_size) { + dir_tmp = get_free_dir_record(); + create_dir_record(dir_tmp,b_data(bp) + block_pos, + block*block_size + block_pos); + if (dir_tmp->length == 0) { /* EOF. I exit and return 0s */ + block_pos = block_size; + done = TRUE; + release_dir_record(dir_tmp); + } else { /* The dir record is valid. Copy data... */ + if (dir_tmp->file_id[0] == 0) + strlcpy(name, ".", NAME_MAX + 1); + else if (dir_tmp->file_id[0] == 1) + strlcpy(name, "..", NAME_MAX + 1); + else { + /* Extract the name from the field file_id */ + strncpy(name, dir_tmp->file_id, + dir_tmp->length_file_id); + name[dir_tmp->length_file_id] = 0; + + /* Tidy up file name */ + cp = memchr(name, ';', NAME_MAX); + if (cp != NULL) name[cp - name] = 0; + + /*If no file extension, then remove final '.'*/ + if (name[strlen(name) - 1] == '.') + name[strlen(name) - 1] = '\0'; + } + + if (strcmp(name_old, name) == 0) { + cur_pos += dir_tmp->length; + release_dir_record(dir_tmp); + continue; + } + + strlcpy(name_old, name, NAME_MAX + 1); + + /* Compute the length of the name */ + cp = memchr(name, '\0', NAME_MAX); + if (cp == NULL) len = NAME_MAX; + else len= cp - name; + + /* Compute record length */ + reclen = offsetof(struct dirent, d_name) + len + 1; + o = (reclen % sizeof(long)); + if (o != 0) + reclen += sizeof(long) - o; + + /* If the new record does not fit, then copy the buffer + * and start from the beginning. */ + if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) { + r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off, + (vir_bytes)getdents_buf, tmpbuf_offset); + + if (r != OK) + panic("fs_getdents: sys_safecopyto failed: %d", r); + userbuf_off += tmpbuf_offset; + tmpbuf_offset= 0; + } + + /* The standard data structure is created using the + * data in the buffer. */ + dirp = (struct dirent *) &getdents_buf[tmpbuf_offset]; + dirp->d_ino = (u32_t)(b_data(bp) + (size_t)block_pos); dirp->d_off= cur_pos; dirp->d_reclen= reclen; memcpy(dirp->d_name, name, len); diff --git a/servers/mfs/glo.h b/servers/mfs/glo.h index 09d30d986..15792f571 100644 --- a/servers/mfs/glo.h +++ b/servers/mfs/glo.h @@ -27,6 +27,7 @@ EXTERN uid_t caller_uid; EXTERN gid_t caller_gid; EXTERN int req_nr; +EXTERN int proto_version; EXTERN endpoint_t SELF_E; diff --git a/servers/mfs/inode.h b/servers/mfs/inode.h index dfacdf303..3035595e0 100644 --- a/servers/mfs/inode.h +++ b/servers/mfs/inode.h @@ -32,7 +32,7 @@ EXTERN struct inode { /* The following items are not present on the disk. */ dev_t i_dev; /* which device is the inode on */ - ino_t i_num; /* inode number on its (minor) device */ + pino_t i_num; /* inode number on its (minor) device */ int i_count; /* # times inode used; 0 means slot is free */ unsigned int i_ndzones; /* # direct zones (Vx_NR_DZONES) */ unsigned int i_nindirs; /* # indirect zones per indirect block */ diff --git a/servers/mfs/mount.c b/servers/mfs/mount.c index 7b32de5da..b4042ceb2 100644 --- a/servers/mfs/mount.c +++ b/servers/mfs/mount.c @@ -30,6 +30,12 @@ int fs_readsuper() readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0; isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0; + if (!(fs_m_in.REQ_FLAGS & REQ_HASPROTO)) { + proto_version = 0; + } else { + proto_version = VFS_FS_PROTO_VERSION(fs_m_in.REQ_PROTO); + } + if (label_len > sizeof(fs_dev_label)) return(EINVAL); diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index 1c60ae704..8c4712487 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -67,6 +67,7 @@ int search_dir(struct inode *ldir_ptr, char string [MFS_NAME_MAX], pino_t int fs_chmod(void); int fs_chown(void); int fs_getdents(void); +int fs_getdents_321(void); int forbidden(struct inode *rip, pmode_t access_desired); int read_only(struct inode *ip); diff --git a/servers/mfs/read.c b/servers/mfs/read.c index cb41e25c1..a0a9f6e66 100644 --- a/servers/mfs/read.c +++ b/servers/mfs/read.c @@ -604,6 +604,153 @@ unsigned bytes_ahead; /* bytes beyond position for immediate use */ } +/*===========================================================================* + * fs_getdents_321 * + *===========================================================================*/ +int fs_getdents_321(void) +{ +#define GETDENTS_321_BUFSIZE (sizeof(struct dirent_321) + MFS_NAME_MAX + 1) +#define GETDENTS_321_ENTRIES 8 + static char getdents_buf[GETDENTS_321_BUFSIZE * GETDENTS_321_ENTRIES]; + register struct inode *rip; + int o, r, done; + unsigned int block_size, len, reclen; + pino_t ino; + block_t b; + cp_grant_id_t gid; + size_t size, tmpbuf_off, userbuf_off; + off_t pos, off, block_pos, new_pos, ent_pos; + struct buf *bp; + struct direct *dp; + struct dirent_321 *dep; + char *cp; + + ino = (pino_t) fs_m_in.REQ_INODE_NR; + gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; + size = (size_t) fs_m_in.REQ_MEM_SIZE; + pos = (off_t) fs_m_in.REQ_SEEK_POS_LO; + + /* Check whether the position is properly aligned */ + if ((unsigned int) pos % DIR_ENTRY_SIZE) + return(ENOENT); + + if ((rip = get_inode(fs_dev, ino)) == NULL) + return(EINVAL); + + block_size = rip->i_sp->s_block_size; + off = (pos % block_size); /* Offset in block */ + block_pos = pos - off; + done = FALSE; /* Stop processing directory blocks when done is set */ + + tmpbuf_off = 0; /* Offset in getdents_buf */ + memset(getdents_buf, '\0', sizeof(getdents_buf)); /* Avoid leaking any data */ + userbuf_off = 0; /* Offset in 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. */ + new_pos = rip->i_size; + + for(; block_pos < rip->i_size; block_pos += block_size) { + b = read_map(rip, block_pos, 0); /* get block number */ + + /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */ + bp = get_block(rip->i_dev, b, NORMAL); /* get a dir block */ + + assert(bp != NULL); + + /* Search a directory block. */ + if (block_pos < pos) + dp = &b_dir(bp)[off / DIR_ENTRY_SIZE]; + else + dp = &b_dir(bp)[0]; + for (; dp < &b_dir(bp)[NR_DIR_ENTRIES(block_size)]; dp++) { + if (dp->mfs_d_ino == 0) + continue; /* Entry is not in use */ + + /* Compute the length of the name */ + cp = memchr(dp->mfs_d_name, '\0', sizeof(dp->mfs_d_name)); + if (cp == NULL) + len = sizeof(dp->mfs_d_name); + else + len = cp - (dp->mfs_d_name); + + /* Compute record length */ + reclen = offsetof(struct dirent_321, d_name) + len + 1; + o = (reclen % sizeof(long)); + if (o != 0) + reclen += sizeof(long) - o; + + /* Need the position of this entry in the directory */ + ent_pos = block_pos + ((char *) dp - (char *) bp->data); + + if (userbuf_off + tmpbuf_off + reclen >= size) { + /* The user has no space for one more record */ + done = TRUE; + + /* Record the position of this entry, it is the + * starting point of the next request (unless the + * postion is modified with lseek). + */ + new_pos = ent_pos; + break; + } + + if (tmpbuf_off + reclen >= + GETDENTS_321_BUFSIZE * GETDENTS_321_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_321 *) &getdents_buf[tmpbuf_off]; + dep->d_ino = (u32_t) dp->mfs_d_ino; + dep->d_off = (i32_t) ent_pos; + dep->d_reclen = (unsigned short) reclen; + memcpy(dep->d_name, dp->mfs_d_name, len); + dep->d_name[len] = '\0'; + tmpbuf_off += reclen; + } + + put_block(bp, DIRECTORY_BLOCK); + if (done) + break; + } + + if (tmpbuf_off != 0) { + 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; + } + + if (done && userbuf_off == 0) + r = EINVAL; /* The user's buffer is too small */ + else { + fs_m_out.RES_NBYTES = userbuf_off; + fs_m_out.RES_SEEK_POS_LO = new_pos; + if(!rip->i_sp->s_rd_only) { + rip->i_update |= ATIME; + IN_MARKDIRTY(rip); + } + r = OK; + } + + put_inode(rip); /* release the inode */ + return(r); +} + /*===========================================================================* * fs_getdents * *===========================================================================*/ @@ -624,6 +771,12 @@ int fs_getdents(void) struct dirent *dep; char *cp; + if (proto_version == 0) { + /* VFS-FS protocol version 0 uses 32-bits ino_t and off_t. We need to + * use the binary compatible version of this routine */ + return fs_getdents_321(); + } + ino = (pino_t) fs_m_in.REQ_INODE_NR; gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; size = (size_t) fs_m_in.REQ_MEM_SIZE; @@ -706,8 +859,8 @@ int fs_getdents(void) } dep = (struct dirent *) &getdents_buf[tmpbuf_off]; - dep->d_ino = dp->mfs_d_ino; - dep->d_off = ent_pos; + dep->d_ino = (ino_t) dp->mfs_d_ino; + dep->d_off = (off_t) ent_pos; dep->d_reclen = (unsigned short) reclen; memcpy(dep->d_name, dp->mfs_d_name, len); dep->d_name[len] = '\0'; diff --git a/servers/mfs/stadir.c b/servers/mfs/stadir.c index 362306298..e721a73ae 100644 --- a/servers/mfs/stadir.c +++ b/servers/mfs/stadir.c @@ -66,9 +66,9 @@ static int stat_inode( 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_nlinks; + statbuf.st_ino = (ino_t) rip->i_num; + statbuf.st_mode = (mode_t) rip->i_mode; + statbuf.st_nlink = (nlink_t) rip->i_nlinks; statbuf.st_uid = rip->i_uid; statbuf.st_gid = rip->i_gid; statbuf.st_rdev = (s ? (dev_t) rip->i_zone[0] : NO_DEV); diff --git a/servers/mfs/super.h b/servers/mfs/super.h index d932fa3d5..c8e2e887c 100644 --- a/servers/mfs/super.h +++ b/servers/mfs/super.h @@ -22,14 +22,14 @@ */ EXTERN struct super_block { - pino_t s_ninodes; /* # usable inodes on the minor device */ + u32_t s_ninodes; /* # usable inodes on the minor device */ zone1_t s_nzones; /* total device size, including bit maps etc */ short s_imap_blocks; /* # of blocks used by inode bit map */ short s_zmap_blocks; /* # of blocks used by zone bit map */ zone1_t s_firstdatazone_old; /* number of first data zone (small) */ short s_log_zone_size; /* log2 of blocks/zone */ unsigned short s_flags; /* FS state flags */ - off_t s_max_size; /* maximum file size on this device */ + i32_t s_max_size; /* maximum file size on this device */ zone_t s_zones; /* number of zones (replaces s_nzones in V2) */ short s_magic; /* magic number to recognize super-blocks */ diff --git a/servers/rs/exec.c b/servers/rs/exec.c index 0701439c2..865b3142c 100644 --- a/servers/rs/exec.c +++ b/servers/rs/exec.c @@ -7,7 +7,7 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname, char *frame, int frame_len); static int exec_restart(int proc_e, int result, vir_bytes pc); static int read_seg(struct exec_info *execi, off_t off, - off_t seg_addr, size_t seg_bytes); + vir_bytes seg_addr, size_t seg_bytes); static int exec_restart(int proc_e, int result, vir_bytes pc); /* Array of loaders for different object formats */ @@ -191,7 +191,7 @@ static int exec_restart(int proc_e, int result, vir_bytes pc) static int read_seg( struct exec_info *execi, /* various data needed for exec */ off_t off, /* offset in file */ -off_t seg_addr, /* address to load segment */ +vir_bytes seg_addr, /* address to load segment */ size_t seg_bytes /* how much is to be transferred? */ ) { diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index 638d1d404..c936c6bf2 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -64,7 +64,7 @@ static void clo_exec(struct fproc *rfp); static int stack_prepare_elf(struct vfs_exec_info *execi, char *curstack, size_t *frame_len, vir_bytes *vsp, int *extrabase); static int map_header(struct vfs_exec_info *execi); -static int read_seg(struct exec_info *execi, off_t off, off_t seg_addr, size_t seg_bytes); +static int read_seg(struct exec_info *execi, off_t off, vir_bytes seg_addr, size_t seg_bytes); #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */ @@ -571,7 +571,7 @@ char path[PATH_MAX]; /* path to script file */ /* Issue request */ r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, ((u64_t)(pos)), READING, - VFS_PROC_NR, buf, _MAX_BLOCK_SIZE, &new_pos, &cum_io); + VFS_PROC_NR, (vir_bytes) buf, _MAX_BLOCK_SIZE, &new_pos, &cum_io); if (r != OK) return(r); n = vp->v_size; @@ -679,7 +679,7 @@ int replace /*===========================================================================* * read_seg * *===========================================================================*/ -static int read_seg(struct exec_info *execi, off_t off, off_t seg_addr, size_t seg_bytes) +static int read_seg(struct exec_info *execi, off_t off, vir_bytes seg_addr, size_t seg_bytes) { /* * The byte count on read is usually smaller than the segment count, because @@ -696,7 +696,7 @@ static int read_seg(struct exec_info *execi, off_t off, off_t seg_addr, size_t s if ((unsigned long) vp->v_size < off+seg_bytes) return(EIO); if ((r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, ((u64_t)(off)), READING, - execi->proc_e, (char*)seg_addr, seg_bytes, + execi->proc_e, (vir_bytes) seg_addr, seg_bytes, &new_pos, &cum_io)) != OK) { printf("VFS: read_seg: req_readwrite failed (data)\n"); return(r); @@ -742,7 +742,7 @@ static int map_header(struct vfs_exec_info *execi) execi->args.hdr = hdr; r = req_readwrite(execi->vp->v_fs_e, execi->vp->v_inode_nr, - ((u64_t)(pos)), READING, VFS_PROC_NR, hdr, + ((u64_t)(pos)), READING, VFS_PROC_NR, (vir_bytes) hdr, execi->args.hdr_len, &new_pos, &cum_io); if (r != OK) { printf("VFS: exec: map_header: req_readwrite failed\n"); diff --git a/servers/vfs/link.c b/servers/vfs/link.c index 8ffc03ee0..dafeb3424 100644 --- a/servers/vfs/link.c +++ b/servers/vfs/link.c @@ -16,6 +16,7 @@ #include #include #include +#include /* Remove with version check in do_truncate */ #include #include #include @@ -306,8 +307,18 @@ int do_truncate(message *UNUSED(m_out)) resolve.l_vmnt_lock = VMNT_READ; resolve.l_vnode_lock = VNODE_WRITE; - length = (off_t) job_m_in.flength; - if (length < 0) return(EINVAL); + if (job_call_nr == TRUNCATE_321) { + length = (off_t) job_m_in.m2_l1; + if ((int) job_m_in.flength < 0) return(EINVAL); + } else { +#if OS_VMAJOR == 2 && OS_VMINOR == 1 + length = (off_t) make64(job_m_in.m2_l1, 0); /* Ignore higher bits */ +#else +#error "Please remove this version check. Recompile dynamic packages first." + length = (off_t) make64(job_m_in.m2_l1, job_m_in.m2_l2); +#endif + if (length < 0) return(EINVAL); + } /* Temporarily open file */ if (fetch_name(vname, vname_length, fullpath) != OK) return(err_code); @@ -343,9 +354,20 @@ int do_ftruncate(message *UNUSED(m_out)) off_t length; scratch(fp).file.fd_nr = job_m_in.fd; - length = (off_t) job_m_in.flength; - if (length < 0) return(EINVAL); + if (job_call_nr == FTRUNCATE_321) { + length = (off_t) job_m_in.m2_l1; + if ((int) job_m_in.flength < 0) return(EINVAL); + } else { +#if OS_VMAJOR == 2 && OS_VMINOR == 1 + length = (off_t) make64(job_m_in.m2_l1, 0); /* Ignore higher bits */ +#else +#error "Please remove this version check. Recompile dynamic packages first." + length = (off_t) make64(job_m_in.m2_l1, job_m_in.m2_l2); +#endif + if (length < 0) return(EINVAL); + } + /* File is already opened; get a vnode pointer from filp */ if ((rfilp = get_filp(scratch(fp).file.fd_nr, VNODE_WRITE)) == NULL) diff --git a/servers/vfs/lock.c b/servers/vfs/lock.c index 0551a8401..d113faa93 100644 --- a/servers/vfs/lock.c +++ b/servers/vfs/lock.c @@ -6,6 +6,7 @@ */ #include "fs.h" +#include #include #include #include @@ -30,11 +31,26 @@ int req; /* either F_SETLK or F_SETLKW */ mode_t mo; off_t first, last; struct flock flock; + struct flock_321 fa_321; struct file_lock *flp, *flp2, *empty; /* Fetch the flock structure from user space. */ - r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer, VFS_PROC_NR, - (vir_bytes) &flock, sizeof(flock)); + if (job_call_nr == FCNTL_321) { + r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer, + VFS_PROC_NR, (vir_bytes) &fa_321, sizeof(fa_321)); + + /* Convert old values to new structure */ + if (r == OK) { + flock.l_type = fa_321.l_type; + flock.l_whence = fa_321.l_whence; + flock.l_start = (off_t) fa_321.l_start; + flock.l_len = (off_t) fa_321.l_len; + flock.l_pid = fa_321.l_pid; + } + } else { + r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer, + VFS_PROC_NR, (vir_bytes) &flock, sizeof(flock)); + } if (r != OK) return(EINVAL); /* Make some error checks. */ @@ -147,8 +163,23 @@ int req; /* either F_SETLK or F_SETLKW */ } /* Copy the flock structure back to the caller. */ - r = sys_datacopy(VFS_PROC_NR, (vir_bytes) &flock, - who_e, (vir_bytes) scratch(fp).io.io_buffer, sizeof(flock)); + if (job_call_nr == FCNTL_321) { + /* Convert new values to old structure */ + if (r == OK) { + fa_321.l_type = flock.l_type; + fa_321.l_whence = flock.l_whence; + fa_321.l_start = (i32_t) flock.l_start; + fa_321.l_len = (i32_t) flock.l_len; + fa_321.l_pid = flock.l_pid; + } + r = sys_datacopy(VFS_PROC_NR, (vir_bytes) &fa_321, + who_e, (vir_bytes) scratch(fp).io.io_buffer, + sizeof(fa_321)); + } else { + r = sys_datacopy(VFS_PROC_NR, (vir_bytes) &flock, + who_e, (vir_bytes) scratch(fp).io.io_buffer, + sizeof(flock)); + } return(r); } diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index f3f040d3a..aab889d68 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -177,23 +177,38 @@ int do_fcntl(message *UNUSED(m_out)) case F_FREESP: { /* Free a section of a file */ - off_t start, end; + off_t start, end, offset; struct flock flock_arg; - signed long offset; /* Check if it's a regular file. */ if (!S_ISREG(f->filp_vno->v_mode)) r = EINVAL; else if (!(f->filp_mode & W_BIT)) r = EBADF; - else + else { /* Copy flock data from userspace. */ - r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer, - SELF, (vir_bytes) &flock_arg, - sizeof(flock_arg)); + if (job_call_nr == FCNTL_321) { + struct flock_321 fa_321; + r = sys_datacopy(who_e, + (vir_bytes) scratch(fp).io.io_buffer, SELF, + (vir_bytes) &fa_321, sizeof(fa_321)); + /* Let's convert the values to the new structure */ + if (r == OK) { + flock_arg.l_type = fa_321.l_type; + flock_arg.l_whence = fa_321.l_whence; + flock_arg.l_start = (off_t) fa_321.l_start; + flock_arg.l_len = (off_t) fa_321.l_len; + flock_arg.l_pid = fa_321.l_pid; + } + } else { + r = sys_datacopy(who_e, + (vir_bytes) scratch(fp).io.io_buffer, SELF, + (vir_bytes) &flock_arg, sizeof(flock_arg)); + } + } if (r != OK) break; /* Convert starting offset to signed. */ - offset = (signed long) flock_arg.l_start; + offset = (off_t) flock_arg.l_start; /* Figure out starting position base. */ switch(flock_arg.l_whence) { diff --git a/servers/vfs/open.c b/servers/vfs/open.c index 3b1b5b9b0..e4c5a1a99 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -590,6 +590,9 @@ int do_mkdir(message *UNUSED(m_out)) return(r); } +/*===========================================================================* + * actual_lseek * + *===========================================================================*/ int actual_lseek(message *m_out, int seekfd, int seekwhence, off_t offset) { /* Perform the lseek(ls_fd, offset, whence) system call. */ @@ -614,19 +617,14 @@ int actual_lseek(message *m_out, int seekfd, int seekwhence, off_t offset) default: unlock_filp(rfilp); return(EINVAL); } - if (offset >= 0) - newpos = pos + offset; - else - newpos = sub64ul(pos, -offset); - - /* Check for overflow. */ - if (ex64hi(newpos) != 0) { - r = EOVERFLOW; - } else if ((off_t) ex64lo(newpos) < 0) { /* no negative file size */ + if (offset < 0 && -offset > pos) { /* no negative file size */ r = EOVERFLOW; } else { + newpos = pos + offset; + /* insert the new position into the output message */ m_out->reply_l1 = ex64lo(newpos); + m_out->reply_l2 = ex64hi(newpos); if (cmp64(newpos, rfilp->filp_pos) != 0) { rfilp->filp_pos = newpos; diff --git a/servers/vfs/path.c b/servers/vfs/path.c index 3d94215db..cf187199e 100644 --- a/servers/vfs/path.c +++ b/servers/vfs/path.c @@ -626,7 +626,7 @@ char ename[NAME_MAX + 1]; do { r = req_getdents(dirp->v_fs_e, dirp->v_inode_nr, pos, buf, sizeof(buf), - &new_pos, 1); + &new_pos, 1, 0 /* Not MINIX 3.2.1 format */); if (r == 0) { return(ENOENT); /* end of entries -- matching inode !found */ diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 12b2c49da..b94b2d9ec 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -167,6 +167,7 @@ void close_reply(void); int common_open(char path[PATH_MAX], int oflags, mode_t omode); int do_creat(void); int do_lseek(message *m_out); +int do_lseek321(message *m_out); int do_llseek(message *m_out); int do_mknod(message *m_out); int do_mkdir(message *m_out); @@ -228,7 +229,7 @@ int rw_pipe(int rw_flag, endpoint_t usr, struct filp *f, char *buf, /* request.c */ int req_breadwrite(endpoint_t fs_e, endpoint_t user_e, dev_t dev, u64_t pos, - unsigned int num_of_bytes, char *user_addr, int rw_flag, + unsigned int num_of_bytes, vir_bytes user_addr, int rw_flag, u64_t *new_posp, unsigned int *cum_iop); int req_chmod(endpoint_t fs_e, ino_t inode_nr, mode_t rmode, mode_t *new_modep); @@ -241,7 +242,7 @@ int req_fstatfs(endpoint_t fs_e, endpoint_t proc_e, vir_bytes buf); int req_statvfs(endpoint_t fs_e, endpoint_t proc_e, vir_bytes buf); int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end); int req_getdents(endpoint_t fs_e, ino_t inode_nr, u64_t pos, char *buf, - size_t size, u64_t *new_pos, int direct); + size_t size, u64_t *new_pos, int direct, int getdents_321); int req_inhibread(endpoint_t fs_e, ino_t inode_nr); int req_link(endpoint_t fs_e, ino_t link_parent, char *lastc, ino_t linked_file); @@ -261,7 +262,7 @@ int req_rdlink(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e, int req_readsuper(struct vmnt *vmp, char *driver_name, dev_t dev, int readonly, int isroot, struct node_details *res_nodep); int req_readwrite(endpoint_t fs_e, ino_t inode_nr, u64_t pos, int rw_flag, - endpoint_t user_e, char *user_addr, unsigned int num_of_bytes, + endpoint_t user_e, vir_bytes user_addr, unsigned int num_of_bytes, u64_t *new_posp, unsigned int *cum_iop); int req_bpeek(endpoint_t fs_e, dev_t dev, u64_t pos, unsigned int num_of_bytes); int req_peek(endpoint_t fs_e, ino_t inode_nr, u64_t pos, unsigned int bytes); diff --git a/servers/vfs/read.c b/servers/vfs/read.c index 7460d18c9..09adbcae9 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -194,8 +194,8 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, if(rw_flag == PEEKING) { r = req_bpeek(vp->v_bfs_e, vp->v_sdev, position, size); } else { - r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, - position, size, buf, rw_flag, &res_pos, &res_cum_io); + r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position, + size, (vir_bytes) buf, rw_flag, &res_pos, &res_cum_io); if (r == OK) { position = res_pos; cum_io += res_cum_io; @@ -215,7 +215,8 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, } else { u64_t new_pos; r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position, - rw_flag, for_e, buf, size, &new_pos, &cum_io_incr); + rw_flag, for_e, (vir_bytes) buf, size, &new_pos, + &cum_io_incr); if (r >= 0) { if (ex64hi(new_pos)) @@ -262,10 +263,11 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, int do_getdents(message *UNUSED(m_out)) { /* Perform the getdents(fd, buf, size) system call. */ - int r = OK; + int r = OK, getdents_321 = 0; u64_t new_pos; register struct filp *rfilp; + if (job_call_nr == GETDENTS_321) getdents_321 = 1; scratch(fp).file.fd_nr = job_m_in.fd; scratch(fp).io.io_buffer = job_m_in.buffer; scratch(fp).io.io_nbytes = (size_t) job_m_in.nbytes; @@ -285,7 +287,7 @@ int do_getdents(message *UNUSED(m_out)) r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, rfilp->filp_pos, scratch(fp).io.io_buffer, - scratch(fp).io.io_nbytes, &new_pos,0); + scratch(fp).io.io_nbytes, &new_pos, 0, getdents_321); if (r > 0) rfilp->filp_pos = new_pos; } @@ -341,7 +343,7 @@ size_t req_size; panic("unmapped pipe"); r = req_readwrite(vp->v_mapfs_e, vp->v_mapinode_nr, position, rw_flag, usr_e, - buf, size, &new_pos, &cum_io_incr); + (vir_bytes) buf, size, &new_pos, &cum_io_incr); if (r != OK) { return(r); diff --git a/servers/vfs/request.c b/servers/vfs/request.c index 0f4b016e3..1713f8772 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -6,25 +6,29 @@ */ #include "fs.h" -#include -#include -#include -#include -#include -#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include "fproc.h" +#include "param.h" +#include "path.h" #include "vmnt.h" #include "vnode.h" -#include "path.h" -#include "param.h" +static size_t translate_dents(char *src, size_t size, char *dst, int direction); + /*===========================================================================* * req_breadwrite * *===========================================================================*/ @@ -34,7 +38,7 @@ int req_breadwrite( dev_t dev, u64_t pos, unsigned int num_of_bytes, - char *user_addr, + vir_bytes user_addr, int rw_flag, u64_t *new_posp, unsigned int *cum_iop @@ -44,7 +48,7 @@ int req_breadwrite( cp_grant_id_t grant_id; message m; - grant_id = cpf_grant_magic(fs_e, user_e, (vir_bytes) user_addr, num_of_bytes, + grant_id = cpf_grant_magic(fs_e, user_e, user_addr, num_of_bytes, (rw_flag == READING ? CPF_WRITE : CPF_READ)); if(grant_id == -1) panic("req_breadwrite: cpf_grant_magic failed"); @@ -300,19 +304,65 @@ int req_getdents( char *buf, size_t size, u64_t *new_pos, - int direct + int direct, + int getdents_321 /* Set to 1 if user land expects old format */ ) { int r; + int fs_getdents_321 = 0, do_translation = 0; message m; cp_grant_id_t grant_id; + struct vmnt *vmp; + char *indir_buf_src = NULL; + char *indir_buf_dst = NULL; - if (direct) { - grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, size, - CPF_WRITE); + vmp = find_vmnt(fs_e); + assert(vmp != NULL); + + if (VFS_FS_PROTO_VERSION(vmp->m_proto) == 0) { + fs_getdents_321 = 1; + } + + /* When we have to translate new struct dirent to the old format or vice + * versa, we're going to have to ignore the user provided buffer and do only + * one entry at a time. We have to do the translation here and allocate + * space on the stack. This is a limited resource. Besides, we don't want to + * be dependent on crazy buffer sizes provided by user space (i.e., we'd have + * to allocate a similarly sized buffer here). + * + * We need to translate iff: + * 1. userland expects old format and FS provides new format + * 2. userland expects new format and FS provides old format + * We don't need to translate iff + * 3. userland expects old format and FS provides old format + * 4. userland expects new format and FS provides new format + * + * Note: VFS expects new format (when doing 'direct'), covered by case 2. + */ + if (getdents_321 && !fs_getdents_321) { /* case 1 */ + do_translation = 1; + } else if (fs_getdents_321 && !getdents_321) {/* case 2 */ + do_translation = 1; + } + + if (do_translation) { + /* We're cutting down the buffer size in two so it's guaranteed we + * have enough space for the translation (data structure has become + * larger). + */ + size = size / 2; + indir_buf_src = malloc(size); + indir_buf_dst = malloc(size * 2); /* dst buffer keeps original size */ + if (indir_buf_src == NULL || indir_buf_dst == NULL) + panic("Couldn't allocate temp buf space\n"); + + grant_id = cpf_grant_direct(fs_e, (vir_bytes) indir_buf_src, size, + CPF_WRITE); + } else if (direct) { + grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, size, CPF_WRITE); } else { grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, size, - CPF_WRITE); + CPF_WRITE); } if (grant_id < 0) @@ -329,14 +379,84 @@ int req_getdents( r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); + if (do_translation) { + if (r == OK) { + m.RES_NBYTES = translate_dents(indir_buf_src, m.RES_NBYTES, + indir_buf_dst, getdents_321); + if (direct) { + memcpy(buf, indir_buf_dst, m.RES_NBYTES); + } else { + r = sys_vircopy(SELF, (vir_bytes) indir_buf_dst, who_e, + (vir_bytes) buf, m.RES_NBYTES); + } + } + free(indir_buf_src); + free(indir_buf_dst); + } + if (r == OK) { - *new_pos = ((u64_t)(m.RES_SEEK_POS_LO)); - r = m.RES_NBYTES; + *new_pos = ((u64_t)(m.RES_SEEK_POS_LO)); + r = m.RES_NBYTES; } return(r); } +/*===========================================================================* + * translate_dents * + *===========================================================================*/ +static size_t +translate_dents(char *src, size_t size, char *dst, int to_getdents_321) +{ +/* Convert between 'struct dirent' and 'struct dirent_321' both ways and + * return the size of the new buffer. + */ + int consumed = 0, newconsumed = 0; + struct dirent *dent; + struct dirent_321 *dent_321; +#define DWORD_ALIGN(d) if((d) % sizeof(long)) (d)+=sizeof(long)-(d)%sizeof(long) + + if (to_getdents_321) { + /* Provided format is struct dirent and has to be translated + * to struct dirent_321 */ + dent_321 = (struct dirent_321 *) dst; + dent = (struct dirent *) src; + + while (consumed < size && dent->d_reclen > 0) { + dent_321->d_ino = (u32_t) dent->d_ino; + dent_321->d_off = (i32_t) dent->d_off; + dent_321->d_reclen = offsetof(struct dirent_321,d_name)+ + strlen(dent->d_name) + 1; + DWORD_ALIGN(dent_321->d_reclen); + strcpy(dent_321->d_name, dent->d_name); + consumed += dent->d_reclen; + newconsumed += dent_321->d_reclen; + dent = (struct dirent *) &src[consumed]; + dent_321 = (struct dirent_321 *) &dst[newconsumed]; + } + } else { + /* Provided format is struct dirent_321 and has to be + * translated to struct dirent */ + dent_321 = (struct dirent_321 *) src; + dent = (struct dirent *) dst; + + while (consumed < size && dent_321->d_reclen > 0) { + dent->d_ino = (ino_t) dent_321->d_ino; + dent->d_off = (off_t) dent_321->d_off; + dent->d_reclen = offsetof(struct dirent, d_name) + + strlen(dent_321->d_name) + 1; + DWORD_ALIGN(dent->d_reclen); + strcpy(dent->d_name, dent_321->d_name); + consumed += dent_321->d_reclen; + newconsumed += dent->d_reclen; + dent_321 = (struct dirent_321 *) &src[consumed]; + dent = (struct dirent *) &dst[newconsumed]; + } + } + + return newconsumed; +} + /*===========================================================================* * req_inhibread * *===========================================================================*/ @@ -762,8 +882,6 @@ int req_readsuper( res_nodep->fs_e = m.m_source; res_nodep->inode_nr = (ino_t) m.RES_INODE_NR; vmp->m_proto = m.RES_PROTO; - printf("%d: proto = 0x%x, version=%d conreqs=%d\n", fs_e, vmp->m_proto, - VFS_FS_PROTO_VERSION(vmp->m_proto), VFS_FS_PROTO_CONREQS(vmp->m_proto)); res_nodep->fmode = (mode_t) m.RES_MODE; res_nodep->fsize = m.RES_FILE_SIZE_LO; res_nodep->uid = (uid_t) m.RES_UID; @@ -784,7 +902,7 @@ ino_t inode_nr; u64_t pos; int rw_flag; endpoint_t user_e; -char *user_addr; +vir_bytes user_addr; unsigned int num_of_bytes; u64_t *new_posp; unsigned int *cum_iop; @@ -796,7 +914,7 @@ unsigned int *cum_iop; if (ex64hi(pos) != 0) panic("req_readwrite: pos too large"); - grant_id = cpf_grant_magic(fs_e, user_e, (vir_bytes) user_addr, num_of_bytes, + grant_id = cpf_grant_magic(fs_e, user_e, user_addr, num_of_bytes, (rw_flag==READING ? CPF_WRITE:CPF_READ)); if (grant_id == -1) panic("req_readwrite: cpf_grant_magic failed"); diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 586c055d5..c3cb3f54d 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -23,7 +23,7 @@ int (*call_vec[])(message *m_out) = { do_open, /* 5 = open */ do_close, /* 6 = close */ no_sys, /* 7 = wait */ - no_sys, /* 8 = unused (was creat) */ + no_sys, /* 8 = unused */ do_link, /* 9 = link */ do_unlink, /* 10 = unlink */ no_sys, /* 11 = waitpid */ @@ -34,7 +34,7 @@ int (*call_vec[])(message *m_out) = { do_chown, /* 16 = chown */ no_sys, /* 17 = break */ no_sys, /* 18 = unused (was old stat)*/ - do_lseek, /* 19 = lseek */ + no_sys, /* 19 = unused (was lseek_321)*/ no_sys, /* 20 = getpid */ do_mount, /* 21 = mount */ do_umount, /* 22 = umount */ @@ -56,7 +56,7 @@ int (*call_vec[])(message *m_out) = { do_rename, /* 38 = rename */ do_mkdir, /* 39 = mkdir */ do_unlink, /* 40 = rmdir */ - no_sys, /* 41 = unused (was dup) */ + no_sys, /* 41 = unused */ do_pipe, /* 42 = pipe */ no_sys, /* 43 = times */ no_sys, /* 44 = (prof) */ @@ -84,8 +84,8 @@ int (*call_vec[])(message *m_out) = { do_fstat, /* 66 = fstat - badly numbered, being phased out */ do_lstat, /* 67 = lstat - badly numbered, being phased out */ no_sys, /* 68 = (setmcontext) */ - no_sys, /* 69 = unused */ - no_sys, /* 70 = unused */ + do_getdents, /* 69 = getdents */ + do_ftruncate, /* 70 = ftruncate */ no_sys, /* 71 = (sigaction) */ no_sys, /* 72 = (sigsuspend) */ no_sys, /* 73 = (sigpending) */ @@ -95,11 +95,11 @@ int (*call_vec[])(message *m_out) = { do_svrctl, /* 77 = svrctl */ no_sys, /* 78 = (sysuname) */ no_sys, /* 79 = unused */ - do_getdents, /* 80 = getdents */ + do_getdents, /* 80 = getdents_321 (to be phased out) */ do_llseek, /* 81 = llseek */ do_fstatfs, /* 82 = fstatfs */ - do_statvfs, /* 83 = fstatvfs */ - do_fstatvfs, /* 84 = statvfs */ + do_statvfs, /* 83 = fstatvfs */ + do_fstatvfs, /* 84 = statvfs */ do_select, /* 85 = select */ do_fchdir, /* 86 = fchdir */ do_fsync, /* 87 = fsync */ @@ -108,11 +108,11 @@ int (*call_vec[])(message *m_out) = { no_sys, /* 90 = (gettimeofday) */ no_sys, /* 91 = (seteuid) */ no_sys, /* 92 = (setegid) */ - do_truncate, /* 93 = truncate */ - do_ftruncate, /* 94 = truncate */ + do_truncate, /* 93 = truncate_321 (to be phased out) */ + do_ftruncate, /* 94 = ftruncate_321 (to be phased out) */ do_chmod, /* 95 = fchmod */ do_chown, /* 96 = fchown */ - no_sys, /* 97 = unused */ + do_lseek, /* 97 = lseek */ no_sys, /* 98 = (sprofile) */ no_sys, /* 99 = (cprofile) */ no_sys, /* 100 = (newexec) */ @@ -124,8 +124,8 @@ int (*call_vec[])(message *m_out) = { no_sys, /* 106 = unused */ no_sys, /* 107 = (getepinfo) */ do_utimens, /* 108 = utimens */ - no_sys, /* 109 = unused */ - no_sys, /* 110 = unused */ + do_fcntl, /* 109 = fcntl */ + do_truncate, /* 110 = unused */ no_sys, /* 111 = (srv_kill) */ do_gcov_flush, /* 112 = gcov_flush */ no_sys, /* 113 = (getsid) */ diff --git a/servers/vm/main.c b/servers/vm/main.c index 8b63b6fbb..1cef6c7ad 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -214,7 +214,7 @@ struct vm_exec_info { }; static int libexec_copy_physcopy(struct exec_info *execi, - off_t off, off_t vaddr, size_t len) + off_t off, vir_bytes vaddr, size_t len) { vir_bytes end; struct vm_exec_info *ei = execi->opaque; @@ -237,14 +237,14 @@ static void boot_alloc(struct exec_info *execi, off_t vaddr, } static int libexec_alloc_vm_prealloc(struct exec_info *execi, - off_t vaddr, size_t len) + vir_bytes vaddr, size_t len) { boot_alloc(execi, vaddr, len, MF_PREALLOC); return OK; } static int libexec_alloc_vm_ondemand(struct exec_info *execi, - off_t vaddr, size_t len) + vir_bytes vaddr, size_t len) { boot_alloc(execi, vaddr, len, 0); return OK; diff --git a/sys/sys/ansi.h b/sys/sys/ansi.h index d96dcf123..50909a83c 100644 --- a/sys/sys/ansi.h +++ b/sys/sys/ansi.h @@ -38,8 +38,8 @@ typedef char * __caddr_t; /* core address */ typedef __uint32_t __gid_t; /* group id */ typedef __uint32_t __in_addr_t; /* IP(v4) address */ typedef __uint16_t __in_port_t; /* "Internet" port number */ -typedef __uint16_t __mode_t; /* file permissions */ -typedef __int32_t __off_t; /* file offset */ +typedef __uint32_t __mode_t; /* file permissions */ +typedef __int64_t __off_t; /* file offset */ typedef __int32_t __pid_t; /* process id */ typedef __uint8_t __sa_family_t; /* socket address family */ typedef __int32_t __socklen_t; /* socket-related datum length */ diff --git a/sys/sys/dirent.h b/sys/sys/dirent.h index 3bdc05006..d09ce8b29 100644 --- a/sys/sys/dirent.h +++ b/sys/sys/dirent.h @@ -17,6 +17,13 @@ struct dirent { /* Largest entry (8 slots) */ char d_name[1]; /* Null terminated name */ }; +struct dirent_321 { /* Largest entry (8 slots) */ + u32_t d_ino; /* I-node number */ + i32_t d_off; /* Offset in directory */ + unsigned short d_reclen; /* Length of this record */ + char d_name[1]; /* Null terminated name */ +}; + #if defined(_NETBSD_SOURCE) #define MAXNAMLEN 511 #define d_fileno d_ino diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h index 0fab6a5bc..c556b4107 100644 --- a/sys/sys/fcntl.h +++ b/sys/sys/fcntl.h @@ -153,6 +153,14 @@ struct flock { pid_t l_pid; /* process id of the locks' owner */ }; +struct flock_321 { + short l_type; /* type: F_RDLCK, F_WRLCK, or F_UNLCK */ + short l_whence; /* flag for starting offset */ + i32_t l_start; /* relative offset in bytes */ + i32_t l_len; /* size; if 0, then until EOF */ + pid_t l_pid; /* process id of the locks' owner */ +}; + #if defined(_NETBSD_SOURCE) /* lock operations for flock(2) */ #define LOCK_SH F_RDLCK /* Shared lock */ diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 8ca19b735..b3b536e80 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -58,7 +58,6 @@ #endif struct stat { -# ifdef AVOID_USING_BIG_TYPES dev_t st_dev; /* inode's device */ mode_t st_mode; /* inode protection mode */ ino_t st_ino; /* inode's number */ @@ -66,16 +65,6 @@ struct stat { uid_t st_uid; /* user ID of the file's owner */ gid_t st_gid; /* group ID of the file's group */ dev_t st_rdev; /* device type */ -# else /* !AVOID_USING_BIG_TYPES */ -/* XXX For now MINIX is still using big_xxx_t types; just cut this when the day finally comes! */ - big_dev_t st_dev; /* inode's device */ - big_mode_t st_mode; /* inode protection mode */ - big_ino_t st_ino; /* inode's number */ - big_nlink_t st_nlink; /* number of hard links */ - big_uid_t st_uid; /* user ID of the file's owner */ - big_gid_t st_gid; /* group ID of the file's group */ - big_dev_t st_rdev; /* device type */ -# endif /* AVOID_USING_BIG_TYPES */ #if (_POSIX_C_SOURCE - 0) >= 200809L || (_XOPEN_SOURCE - 0) >= 700 || \ defined(_NETBSD_SOURCE) struct timespec st_atim; /* time of last access */ @@ -96,11 +85,7 @@ struct stat { off_t st_size; /* file size, in off_t bytes */ off_t st_size_rest; #else -# ifdef AVOID_USING_BIG_TYPES off_t st_size; /* file size, in bytes */ -# else /* !AVOID_USING_BIG_TYPES */ /* XXX also cut here */ - big_off_t st_size; /* file size, in bytes */ -# endif /* AVOID_USING_BIG_TYPES */ #endif blkcnt_t st_blocks; /* blocks allocated for file */ blksize_t st_blksize; /* optimal blocksize for I/O */ diff --git a/sys/sys/types.h b/sys/sys/types.h index acc33f114..00cabd7d9 100644 --- a/sys/sys/types.h +++ b/sys/sys/types.h @@ -106,15 +106,6 @@ typedef int16_t i16_t; typedef int32_t i32_t; typedef int64_t i64_t; -typedef uint64_t big_ino_t; -typedef int64_t big_off_t; -typedef u32_t big_dev_t; -typedef u32_t big_gid_t; -typedef u32_t big_mode_t; -typedef u32_t big_nlink_t; -typedef u32_t big_uid_t; - - #ifdef _NETBSD_SOURCE /* some Minix specific types that do not conflict with posix */ typedef uint32_t zone_t; /* zone number */ @@ -204,7 +195,7 @@ typedef __gid_t gid_t; /* group id */ typedef int idtype_t; /* type of the id */ typedef uint32_t id_t; /* group id, process id or user id */ -typedef uint32_t ino_t; /* inode number */ +typedef uint64_t ino_t; /* inode number */ typedef long key_t; /* IPC key (for Sys V IPC) */ #ifndef mode_t @@ -212,7 +203,7 @@ typedef __mode_t mode_t; /* permissions */ #define mode_t __mode_t #endif -typedef int16_t nlink_t; /* link count */ +typedef uint32_t nlink_t; /* link count */ #ifndef off_t typedef __off_t off_t; /* file offset */ diff --git a/usr.bin/gzip/gzip.c b/usr.bin/gzip/gzip.c index cd4837807..dd763682d 100644 --- a/usr.bin/gzip/gzip.c +++ b/usr.bin/gzip/gzip.c @@ -66,7 +66,7 @@ __RCSID("$NetBSD: gzip.c,v 1.105 2011/08/30 23:06:00 joerg Exp $"); #include #ifndef PRIdOFF -#define PRIdOFF PRId32 +#define PRIdOFF PRId64 #endif /* what type of file are we dealing with */ @@ -1276,11 +1276,7 @@ file_compress(char *file, char *outfile, size_t outsize) if (osb.st_size != size) { maybe_warnx("output file: %s wrong size (%" PRIdOFF " != %" PRIdOFF "), deleting", -#ifndef __minix outfile, osb.st_size, size); -#else - outfile, osb.st_size, (big_off_t)size); -#endif goto bad_outfile; } @@ -1559,11 +1555,7 @@ file_uncompress(char *file, char *outfile, size_t outsize) if (osb.st_size != size) { maybe_warnx("stat gave different size: %" PRIdOFF " != %" PRIdOFF " (leaving original)", -#ifndef __minix size, osb.st_size); -#else - (big_off_t)size, osb.st_size); -#endif close(ofd); unlink(outfile); return -1;