diff --git a/headers/os/kernel/syscalls.h b/headers/os/kernel/syscalls.h index 0e117dc737..d5d92aac7a 100755 --- a/headers/os/kernel/syscalls.h +++ b/headers/os/kernel/syscalls.h @@ -37,8 +37,6 @@ off_t sys_seek(int fd, off_t pos, int seek_type); int sys_ioctl(int fd, ulong op, void *buf, size_t length); int sys_unlink(const char *path); int sys_rename(const char *oldpath, const char *newpath); -int sys_rstat(const char *path, struct stat *stat); -int sys_wstat(const char *path, struct stat *stat, int stat_mask); int sys_fstat(int, struct stat *); char *sys_getcwd(char* buf, size_t size); int sys_setcwd(const char* path); diff --git a/headers/posix/dirent.h b/headers/posix/dirent.h index 80d60a1049..72c890f01a 100644 --- a/headers/posix/dirent.h +++ b/headers/posix/dirent.h @@ -10,7 +10,7 @@ // This file should reside in headers/posix, not here... // needs ino_t (int64), and dev_t (long) #include -typedef long dev_t; + typedef struct dirent { dev_t d_dev; diff --git a/headers/posix/sys/stat.h b/headers/posix/sys/stat.h index c56e3d2f5d..996118dcd9 100644 --- a/headers/posix/sys/stat.h +++ b/headers/posix/sys/stat.h @@ -1,246 +1,102 @@ -/*- - * Copyright (c) 1982, 1986, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)stat.h 8.9 (Berkeley) 8/17/94 - */ - #ifndef _SYS_STAT_H_ -#define _SYS_STAT_H_ +#define _SYS_STAT_H_ -//#include +#include +//#include +#include -/** - * @file stat.h - * @brief Stat structures and defines - */ - -/** - * @defgroup OpenBeOS_POSIX POSIX Headers - * @brief Headers to provide the POSIX layer - */ - -/** - * @defgroup Stat sys/stat.h - * @brief Structures and prototypes for stat operations - * @ingroup OpenBeOS_POSIX - * @{ - */ - -/* XXX - some types we don't yet have in sys/types.h (because we don't yet - * have a sys/types.h and these aren't in ktypes.h!) +/* + * stat structure */ -#ifdef _KERNEL_MODE -struct ostat { - mode_t st_mode; /* inode protection mode */ - ino_t st_ino; /* inode's number */ - uint16 st_dev; /* inode's device */ - nlink_t st_nlink; /* number of hard links */ - uid_t st_uid; /* user ID of the file's owner */ - gid_t st_gid; /* group ID of the file's group */ - off_t st_size; /* file size, in bytes */ - time_t st_atime; /* time of last access */ - time_t st_mtime; /* time of last data modification */ - time_t st_ctime; /* time of last file status change */ - int64 st_blocks; /* blocks allocated for file */ - int32 st_blksize; /* optimal blocksize for I/O */ -}; -#endif /* _KERNEL_MODE */ - -/* XXX - The stat structure, as defined by POSIX. - * Just implement what we can for the time being. - */ struct stat { - mode_t st_mode; /* File mode */ - ino_t st_ino; /* vnode_id */ -// dev_t st_dev; /* inode's device */ - nlink_t st_nlink; /* number of hard links */ - uid_t st_uid; /* user ID of the file's owner */ - gid_t st_gid; /* group ID of the file's group */ - off_t st_size; /* file size, in bytes */ - time_t st_atime; /* time of last access */ - time_t st_mtime; /* time of last data modification */ - time_t st_ctime; /* time of last file status change */ - int64 st_blocks; /* blocks allocated for file */ - uint32 st_blksize; /* optimal blocksize for I/O */ + dev_t st_dev; /* "device" that this file resides on */ + ino_t st_ino; /* this file's inode #, unique per device */ + mode_t st_mode; /* mode bits (rwx for user, group, etc) */ + nlink_t st_nlink; /* number of hard links to this file */ + uid_t st_uid; /* user id of the owner of this file */ + gid_t st_gid; /* group id of the owner of this file */ + off_t st_size; /* size in bytes of this file */ + dev_t st_rdev; /* device type (not used) */ + size_t st_blksize; /* preferred block size for i/o */ + time_t st_atime; /* last access time */ + time_t st_mtime; /* last modification time */ + time_t st_ctime; /* last change time, not creation time */ + time_t st_crtime; /* creation time */ }; -/** - * @defgroup POSIX_filemodes File mode defines - * @brief Defines of the file modes we allow - * @ingroup Stat - *@{ - */ -/** @def S_ISUID set user id on execution */ -/** @def S_ISGID set group id on execution */ -/** @def S_ISTXT sticky bit */ -#define S_ISUID 0004000 -#define S_ISGID 0002000 -#define S_ISTXT 0001000 +/* extended file types */ +#define S_ATTR_DIR 01000000000 /* attribute directory */ +#define S_ATTR 02000000000 /* attribute */ +#define S_INDEX_DIR 04000000000 /* index (or index directory) */ +#define S_STR_INDEX 00100000000 /* string index */ +#define S_INT_INDEX 00200000000 /* int32 index */ +#define S_UINT_INDEX 00400000000 /* uint32 index */ +#define S_LONG_LONG_INDEX 00010000000 /* int64 index */ +#define S_ULONG_LONG_INDEX 00020000000 /* uint64 index */ +#define S_FLOAT_INDEX 00040000000 /* float index */ +#define S_DOUBLE_INDEX 00001000000 /* double index */ +#define S_ALLOW_DUPS 00002000000 /* allow duplicate entries (currently unused) */ -/** @def S_IRWXU RWX mask for owner */ -/** @def S_IRUSR R for owner */ -/** @def S_IWUSR W for owner */ -/** @def S_IXUSR X for owner */ -#define S_IRWXU 0000700 -#define S_IRUSR 0000400 -#define S_IWUSR 0000200 -#define S_IXUSR 0000100 +/* standard file types */ +#define S_IFMT 00000170000 /* type of file */ +#define S_IFLNK 00000120000 /* symbolic link */ +#define S_IFREG 00000100000 /* regular */ +#define S_IFBLK 00000060000 /* block special */ +#define S_IFDIR 00000040000 /* directory */ +#define S_IFCHR 00000020000 /* character special */ +#define S_IFIFO 00000010000 /* fifo */ -/** @def S_IRWXG RWX mask for group */ -/** @def S_IWGRP W for group */ -/** @def S_IRGRP R for group */ -/** @def S_IXGRP X for group */ -#define S_IRWXG 0000070 -#define S_IRGRP 0000040 -#define S_IWGRP 0000020 -#define S_IXGRP 0000010 +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISINDEX(m) (((m) & S_INDEX_DIR) == S_INDEX_DIR) -/** @def S_IXOTH RWX mask for other */ -/** @def S_IROTH R for other */ -/** @def S_IWOTH W for other */ -/** @def S_IXOTH X for other */ -#define S_IRWXO 0000007 -#define S_IROTH 0000004 -#define S_IWOTH 0000002 -#define S_IXOTH 0000001 +#define S_IUMSK 07777 /* user settable bits */ -#define S_IFMT 0170000 -#define S_IFSOCK 0140000 -#define S_IFIFO 0010000 -#define S_IFCHR 0020000 -#define S_IFDIR 0040000 -#define S_IFBLK 0060000 -#define S_IFREG 0100000 -#define S_IFLNK 0120000 -#define S_IFWHT 0160000 -#define S_ISVTX 0001000 +#define S_ISUID 04000 /* set user id on execution */ +#define S_ISGID 02000 /* set group id on execution */ -/** - * @defgroup stat_tests Stat Macro's - * @ingroup POSIX_filemodes - * @brief macro's that should be used to test for the type of device - * @{ - */ -/** @def S_ISDIR(m) it's a directory */ -/** @def S_ISREG(m) it's a regular file */ -/** @def S_ISCHR(m) it's a character device */ -/** @def S_ISBLK(m) it's a block device */ -/** @def S_ISFIFO(m) it's a fifo device */ -/** @def S_ISLNK(m) it's a symbolic link */ -/** @def S_ISSOCK(m) it's a socket */ -/** @def S_ISWHT(m) whiteout? */ -#define S_ISDIR(m) ((m & 0170000) == 0040000) -#define S_ISREG(m) ((m & 0170000) == 0100000) -#define S_ISCHR(m) ((m & 0170000) == 0020000) -#define S_ISBLK(m) ((m & 0170000) == 0060000) -#define S_ISFIFO(m) ((m & 0170000) == 0010000) -#define S_ISLNK(m) ((m & 0170000) == 0120000) -#define S_ISSOCK(m) ((m & 0170000) == 0140000) -#define S_ISWHT(m) ((m & 0170000) == 0160000) -/** @} */ +#define S_ISVTX 01000 /* save swapped text even after use */ + +#define S_IRWXU 00700 /* read, write, execute: owner */ +#define S_IRUSR 00400 /* read permission: owner */ +#define S_IWUSR 00200 /* write permission: owner */ +#define S_IXUSR 00100 /* execute permission: owner */ +#define S_IRWXG 00070 /* read, write, execute: group */ +#define S_IRGRP 00040 /* read permission: group */ +#define S_IWGRP 00020 /* write permission: group */ +#define S_IXGRP 00010 /* execute permission: group */ +#define S_IRWXO 00007 /* read, write, execute: other */ +#define S_IROTH 00004 /* read permission: other */ +#define S_IWOTH 00002 /* write permission: other */ +#define S_IXOTH 00001 /* execute permission: other */ /** @def ACCESSPERMS 00777 */ -/** @def ALLPERMS 07777 */ -/** @def DEFFILEMODE 00666 default file mode, everyone can read/write*/ #define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) +/** @def ALLPERMS 07777 */ #define ALLPERMS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) +/** @def DEFFILEMODE 00666 default file mode, everyone can read/write*/ #define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) -/** @} */ - -/* - * Definitions of flags stored in file flags word. - * - * Super-user and owner changeable flags. - */ -#define UF_SETTABLE 0x0000ffff /* mask of owner changeable flags */ -#define UF_NODUMP 0x00000001 /* do not dump file */ -#define UF_IMMUTABLE 0x00000002 /* file may not be changed */ -#define UF_APPEND 0x00000004 /* writes to file may only append */ -#define UF_OPAQUE 0x00000008 /* directory is opaque wrt. union */ -/* - * Super-user changeable flags. - */ -#define SF_SETTABLE 0xffff0000 /* mask of superuser changeable flags */ -#define SF_ARCHIVED 0x00010000 /* file is archived */ -#define SF_IMMUTABLE 0x00020000 /* file may not be changed */ -#define SF_APPEND 0x00040000 /* writes to file may only append */ - -#ifdef _KERNEL_MODE -/* - * Shorthand abbreviations of above. - */ -#define OPAQUE (UF_OPAQUE) -#define APPEND (UF_APPEND | SF_APPEND) -#define IMMUTABLE (UF_IMMUTABLE | SF_IMMUTABLE) -#endif /* _KERNEL_MODE */ - -#ifndef _KERNEL_MODE_ - //#include - - /** @fn int chmod(const char *path, mode_t mode) - * Changes the file protection modes to those given by mode - * - * @ref POISX_filemodes - */ - int chmod (const char *, mode_t); - /** @fn int fstat(int fd, struct stat *stat) - * get file information on a file identified by descriptor fd - * - * @ref stat - */ - int fstat (int, struct stat *); - //int mknod (const char *, mode_t, dev_t); - int mkdir (const char *, mode_t); - int mkfifo (const char *, mode_t); - /** @fn int stat(const char *path, struct stat *stat) - * Get file information for file path and store it in the structure - * stat - * - * @ref stat - */ - int stat (const char *, struct stat *); - mode_t umask (mode_t); - int fchmod (int, mode_t); - int lstat (const char *, struct stat *); - +#ifdef __cplusplus +extern "C" { #endif -/** @} */ +extern int chmod(const char *path, mode_t mode); +extern int fchmod(int fd, mode_t mode); +extern int stat(const char *path, struct stat *buf); +extern int fstat(int fd, struct stat *buf); +extern int lstat(const char *path, struct stat *st); +extern int mkdir(const char *path, mode_t mode); +extern int mkfifo(const char *path, mode_t mode); +extern mode_t umask(mode_t cmask); -#endif /* !_SYS_STAT_H_ */ +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_STAT_H_ */ diff --git a/headers/private/kernel/ksyscalls.h b/headers/private/kernel/ksyscalls.h index 17684ebe8d..f67a9d96a3 100755 --- a/headers/private/kernel/ksyscalls.h +++ b/headers/private/kernel/ksyscalls.h @@ -22,8 +22,8 @@ enum { SYSCALL_CREATE, SYSCALL_UNLINK, SYSCALL_RENAME, - SYSCALL_RSTAT, - SYSCALL_WSTAT, + SYSCALL_READ_STAT, + SYSCALL_WRITE_STAT, SYSCALL_SYSTEM_TIME, SYSCALL_SNOOZE, SYSCALL_SEM_CREATE, @@ -82,7 +82,7 @@ enum { SYSCALL_SYSCTL, SYSCALL_SOCKET, SYSCALL_GETDTABLESIZE, - SYSCALL_FSTAT, + SYSCALL_FD_STAT, SYSCALL_READ_DIR, SYSCALL_REWIND_DIR, SYSCALL_OPEN_DIR, @@ -93,7 +93,9 @@ enum { SYSCALL_OPEN_DIR_ENTRY_REF, SYSCALL_OPEN_DIR_NODE_REF, SYSCALL_CREATE_ENTRY_REF, - SYSCALL_CREATE_DIR_ENTRY_REF + SYSCALL_CREATE_DIR_ENTRY_REF, + SYSCALL_CREATE_SYMLINK, + SYSCALL_READ_LINK, }; int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_ret); diff --git a/headers/private/kernel/ktypes.h b/headers/private/kernel/ktypes.h index 86df12b789..2a527941d6 100755 --- a/headers/private/kernel/ktypes.h +++ b/headers/private/kernel/ktypes.h @@ -20,15 +20,14 @@ typedef int team_id; typedef int sem_id; typedef int port_id; typedef int image_id; +typedef uint32 dev_t; typedef uint64 ino_t; typedef uint64 vnode_id; typedef uint32 fs_id; typedef uint16 nlink_t; typedef uint32 uid_t; typedef uint32 gid_t; - -/* compat with beos (was int32 on beos) */ -typedef int status_t; +typedef int32 status_t; #ifdef _OBOS_TIME_T_ diff --git a/headers/private/kernel/unistd.h b/headers/private/kernel/unistd.h index 53ec765271..62424682b8 100755 --- a/headers/private/kernel/unistd.h +++ b/headers/private/kernel/unistd.h @@ -41,6 +41,9 @@ extern int optreset; extern char **environ; +int readlink(const char *path, char *buffer, size_t bufferSize); +int symlink(const char *path, const char *toPath); + off_t lseek(int, off_t, int); ssize_t read(int, void *, size_t); ssize_t pread(int, void *, size_t, off_t); diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index f4f20465d8..ae9be1124f 100755 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -158,10 +158,12 @@ int sys_create_entry_ref(dev_t device, ino_t inode, const char *uname, int omode int sys_create(const char *path, int omode, int perms); int sys_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms); int sys_create_dir(const char *path, int perms); -int sys_symlink(const char *path, const char *toPath); +int sys_read_link(const char *path, char *buffer, size_t bufferSize); +int sys_create_symlink(const char *path, const char *toPath); int sys_unlink(const char *path); int sys_rename(const char *oldpath, const char *newpath); -int sys_write_stat(const char *path, struct stat *stat, int stat_mask); +int sys_read_stat(const char *path, bool traverseLink, struct stat *stat); +int sys_write_stat(const char *path, bool traverseLink, struct stat *stat, int statMask); char *sys_getcwd(char *buf, size_t size); int sys_setcwd(const char* path); @@ -180,11 +182,12 @@ int user_create_entry_ref(dev_t device, ino_t inode, const char *uname, int omod int user_create(const char *path, int omode, int perms); int user_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms); int user_create_dir(const char *path, int perms); -int user_symlink(const char *path, const char *toPath); +int user_read_link(const char *path, char *buffer, size_t bufferSize); +int user_create_symlink(const char *path, const char *toPath); int user_unlink(const char *path); int user_rename(const char *oldpath, const char *newpath); -int user_read_stat(const char *path, struct stat *stat); -int user_write_stat(const char *path, struct stat *stat, int stat_mask); +int user_read_stat(const char *path, bool traverseLink, struct stat *stat); +int user_write_stat(const char *path, bool traverseLink, struct stat *stat, int statMask); int user_getcwd(char *buf, size_t size); int user_setcwd(const char* path); @@ -194,7 +197,6 @@ extern ssize_t sys_write(int fd, const void *buf, off_t pos, size_t len); extern int sys_ioctl(int fd, ulong cmd, void *data, size_t length); extern ssize_t sys_read_dir(int fd, struct dirent *buffer, size_t bufferSize, uint32 maxCount); extern status_t sys_rewind_dir(int fd); -extern int sys_read_stat(const char *path, struct stat *stat); extern int sys_close(int fd); extern int sys_dup(int fd); extern int sys_dup2(int ofd, int nfd); diff --git a/src/kernel/Jamfile b/src/kernel/Jamfile index 3e86f891e2..0f38984e53 100644 --- a/src/kernel/Jamfile +++ b/src/kernel/Jamfile @@ -351,6 +351,7 @@ KernelStaticLibraryObjects libc.a : <$(SOURCE_GRIST)!libc!unistd>lseek.o <$(SOURCE_GRIST)!libc!unistd>open.o <$(SOURCE_GRIST)!libc!unistd>opendir.o + <$(SOURCE_GRIST)!libc!unistd>link.o <$(SOURCE_GRIST)!libc!unistd>pread.o <$(SOURCE_GRIST)!libc!unistd>pwrite.o <$(SOURCE_GRIST)!libc!unistd>read.o @@ -467,6 +468,7 @@ KernelLd libc.so : <$(SOURCE_GRIST)!libc!unistd>lseek.o <$(SOURCE_GRIST)!libc!unistd>open.o <$(SOURCE_GRIST)!libc!unistd>opendir.o + <$(SOURCE_GRIST)!libc!unistd>link.o <$(SOURCE_GRIST)!libc!unistd>pread.o <$(SOURCE_GRIST)!libc!unistd>pwrite.o <$(SOURCE_GRIST)!libc!unistd>read.o @@ -585,6 +587,19 @@ KernelLd ls : bin/ls ; +KernelLd symlink : + libglue2.o + <$(SOURCE_GRIST)!apps!symlink>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/symlink + ; + # Note: shell is a built in target, thus we need the grist. KernelLd obos_shell : libglue2.o diff --git a/src/kernel/apps/Jamfile b/src/kernel/apps/Jamfile index 6c2b09659c..8d14ae3981 100644 --- a/src/kernel/apps/Jamfile +++ b/src/kernel/apps/Jamfile @@ -7,6 +7,7 @@ SubInclude OBOS_TOP src kernel apps filetest ; SubInclude OBOS_TOP src kernel apps fortune ; SubInclude OBOS_TOP src kernel apps hostname ; SubInclude OBOS_TOP src kernel apps ls ; +SubInclude OBOS_TOP src kernel apps symlink ; SubInclude OBOS_TOP src kernel apps ps ; SubInclude OBOS_TOP src kernel apps rld ; SubInclude OBOS_TOP src kernel apps shell ; diff --git a/src/kernel/apps/ls/main.c b/src/kernel/apps/ls/main.c index 034f922ae0..0c650dfb1d 100644 --- a/src/kernel/apps/ls/main.c +++ b/src/kernel/apps/ls/main.c @@ -12,7 +12,7 @@ extern char *__progname; -void (*disp_func)(const char *, struct stat *) = NULL; +void (*disp_func)(const char *, const char *, struct stat *) = NULL; static int show_all = 0; mode_t perms [9] = { @@ -27,7 +27,9 @@ mode_t perms [9] = { S_IXOTH }; -static void display_l(const char *filename, struct stat *stat) + +static void +display_l(const char *path, const char *filename, struct stat *stat) { const char *type; char perm[11]; @@ -51,16 +53,32 @@ static void display_l(const char *filename, struct stat *stat) } if (S_ISDIR(stat->st_mode)) perm[0] = 'd'; - - printf("%10s %12lld %s\n" ,perm ,stat->st_size ,filename); + else if (S_ISLNK(stat->st_mode)) + perm[0] = 'l'; + else if (S_ISCHR(stat->st_mode)) + perm[0] = 'c'; + + printf("%10s %12lld %s" ,perm ,stat->st_size ,filename); + + if (S_ISLNK(stat->st_mode)) { + char buffer[1024]; + if (readlink(path, buffer, sizeof(buffer)) != 0) + strcpy(buffer, "???"); + printf(" (-> %s)\n", buffer); + } else + putchar('\n'); } -static void display(const char *filename, struct stat *stat) + +static void +display(const char *path, const char *filename, struct stat *stat) { printf("%s\n", filename); } -int main(int argc, char *argv[]) + +int +main(int argc, char *argv[]) { int rc; int rc2; @@ -85,14 +103,13 @@ int main(int argc, char *argv[]) argc -= optind; argv += optind; - if(*argv == NULL) { + if (*argv == NULL) arg = "."; - } else { + else arg = *argv; - } rc = stat(arg, &st); - if(rc < 0) { + if (rc < 0) { printf("%s: %s: %s\n", __progname, arg, strerror(rc)); goto err_ls; @@ -109,7 +126,7 @@ int main(int argc, char *argv[]) /* process the '.' entry */ rc = stat(arg, &st); if (rc == 0) { - (*disp_func)(".", &st); + (*disp_func)(arg, ".", &st); totbytes += st.st_size; } } @@ -128,9 +145,9 @@ int main(int argc, char *argv[]) } strlcat(buf2, de->d_name, sizeof(buf2)); - rc2 = stat(buf2, &st); + rc2 = lstat(buf2, &st); if (rc2 == 0) { - (*disp_func)(de->d_name, &st); + (*disp_func)(buf2, de->d_name, &st); totbytes += st.st_size; } count++; @@ -140,7 +157,7 @@ int main(int argc, char *argv[]) printf("%lld bytes in %d files\n", totbytes, count); } else { - (*disp_func)(arg, &st); + (*disp_func)(arg, arg, &st); } err_ls: diff --git a/src/kernel/apps/shell/commands.c b/src/kernel/apps/shell/commands.c index 6e04c94e97..e77d85cc80 100644 --- a/src/kernel/apps/shell/commands.c +++ b/src/kernel/apps/shell/commands.c @@ -2,6 +2,7 @@ ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ + #include #include #include @@ -168,13 +169,13 @@ int cmd_stat(int argc, char *argv[]) int rc; struct stat stat; - if(argc < 2) { + if (argc < 2) { printf("not enough arguments to stat\n"); return 0; } - rc = sys_read_stat(argv[1], &stat); - if(rc >= 0) { + rc = sys_read_stat(argv[1], true, &stat); + if (rc >= 0) { printf("stat of file '%s': \n", argv[1]); printf("vnid 0x%x\n", (unsigned int)stat.st_ino); // printf("type %d\n", stat.type); diff --git a/src/kernel/core/addons/bus_managers/bus_man.c b/src/kernel/core/addons/bus_managers/bus_man.c index b9c111b58b..3d708ee04b 100755 --- a/src/kernel/core/addons/bus_managers/bus_man.c +++ b/src/kernel/core/addons/bus_managers/bus_man.c @@ -99,7 +99,7 @@ static int bus_find_device_recurse(int *n, char *base_path, int max_path_len, in dirent->d_name[dirent->d_reclen] = '\0'; strlcat(base_path, dirent->d_name, max_path_len); - err = sys_read_stat(base_path, &stat); + err = sys_read_stat(base_path, true, &stat); if (err < 0) continue; diff --git a/src/kernel/core/fs/vfs.c b/src/kernel/core/fs/vfs.c index 516ca26f47..ddac3ef328 100755 --- a/src/kernel/core/fs/vfs.c +++ b/src/kernel/core/fs/vfs.c @@ -499,14 +499,10 @@ get_vnode_from_fd(struct io_context *ioContext, int fd) return NULL; vnode = descriptor->vnode; - if (vnode == NULL) - goto out; + if (vnode != NULL) + inc_vnode_ref_count(vnode); - inc_vnode_ref_count(vnode); - -out: put_fd(descriptor); - return vnode; } @@ -562,7 +558,7 @@ entry_ref_to_vnode(fs_id fsID,vnode_id directoryID,const char *name,struct vnode static int -vnode_path_to_vnode(struct vnode *vnode, char *path, struct vnode **_vnode, int count) +vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink, struct vnode **_vnode, int count) { int status = 0; @@ -624,45 +620,64 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, struct vnode **_vnode, int return ERR_VFS_PATH_NOT_FOUND; } + // If the new node is a symbolic link, resolve it (if we've been told to do it) + if (S_ISLNK(type) && !(!traverseLeafLink && nextPath[0] == '\0')) { + char *buffer; + + // it's not exactly nice style using goto in this way, but hey, it works :-/ + if (count + 1 > MAX_SYM_LINKS) { + status = B_LINK_LIMIT; + goto resolve_link_error; + } + + buffer = kmalloc(SYS_MAX_PATH_LEN); + if (buffer == NULL) { + status = B_NO_MEMORY; + goto resolve_link_error; + } + + status = FS_CALL(nextVnode,fs_read_link)(nextVnode->mount->cookie, nextVnode->private_node, buffer, SYS_MAX_PATH_LEN); + if (status < B_OK) { + kfree(buffer); + +resolve_link_error: + put_vnode(vnode); + put_vnode(nextVnode); + + return status; + } + put_vnode(nextVnode); + + // Check if we start from the root directory or the current + // directory ("vnode" still points to that one). + // Cut off all leading slashes if it's the root directory + path = buffer; + if (path[0] == '/') { + // we don't need the old directory anymore + put_vnode(vnode); + + while (*++path == '/') + ; + vnode = root_vnode; + inc_vnode_ref_count(vnode); + } + + status = vnode_path_to_vnode(vnode, path, traverseLeafLink, &nextVnode, count + 1); + + kfree(buffer); + + if (status < B_OK) { + put_vnode(vnode); + return status; + } + } + // decrease the ref count on the old dir we just looked up into put_vnode(vnode); path = nextPath; vnode = nextVnode; - // If the new node is a symbolic link, resolve it - if (S_ISLNK(type)) { - char *buffer; - - if (count + 1 > MAX_SYM_LINKS) { - put_vnode(vnode); - return B_LINK_LIMIT; - } - - buffer = kmalloc(SYS_MAX_PATH_LEN); - if (buffer == NULL) { - put_vnode(vnode); - return B_NO_MEMORY; - } - - status = FS_CALL(vnode,fs_read_link)(vnode->mount->cookie, vnode->private_node, buffer, SYS_MAX_PATH_LEN); - if (status < B_OK) { - put_vnode(vnode); - kfree(buffer); - return status; - } - - status = vnode_path_to_vnode(vnode, buffer, &nextVnode, count + 1); - - put_vnode(vnode); - kfree(buffer); - - if (status < B_OK) - return status; - - vnode = nextVnode; - } - // see if we hit a mount point if (vnode->covered_by) { nextVnode = vnode->covered_by; @@ -678,7 +693,7 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, struct vnode **_vnode, int static int -path_to_vnode(char *path, struct vnode **_vnode, bool kernel) +path_to_vnode(char *path, bool traverseLink, struct vnode **_vnode, bool kernel) { struct vnode *start; int linkCount = 0; @@ -702,7 +717,7 @@ path_to_vnode(char *path, struct vnode **_vnode, bool kernel) mutex_unlock(&context->io_mutex); } - return vnode_path_to_vnode(start, path, _vnode, 0); + return vnode_path_to_vnode(start, path, traverseLink, _vnode, 0); } @@ -730,7 +745,7 @@ path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel p[1] = '\0'; } } - return path_to_vnode(path, _vnode, kernel); + return path_to_vnode(path, true, _vnode, kernel); } @@ -1013,9 +1028,9 @@ vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode) int -vfs_get_vnode_from_path(const char *path, bool kernel, void **vnode) +vfs_get_vnode_from_path(const char *path, bool kernel, void **_vnode) { - struct vnode *v; + struct vnode *vnode; int err; char buf[SYS_MAX_PATH_LEN+1]; @@ -1024,13 +1039,10 @@ vfs_get_vnode_from_path(const char *path, bool kernel, void **vnode) strncpy(buf, path, SYS_MAX_PATH_LEN); buf[SYS_MAX_PATH_LEN] = 0; - err = path_to_vnode(buf, &v, kernel); - if (err < 0) - goto err; + err = path_to_vnode(buf, true, &vnode, kernel); + if (err >= 0) + *_vnode = vnode; - *vnode = v; - -err: return err; } @@ -1731,7 +1743,7 @@ file_open(char *path, int omode, bool kernel) FUNCTION(("file_open: entry. path = '%s', omode %d, kernel %d\n", path, omode, kernel)); // get the vnode matching the path - status = path_to_vnode(path, &vnode, kernel); + status = path_to_vnode(path, true, &vnode, kernel); if (status < B_OK) return status; @@ -1884,7 +1896,7 @@ dir_open(char *path, bool kernel) FUNCTION(("dir_open: path = '%s', kernel %d\n", path, kernel)); - status = path_to_vnode(path, &vnode, kernel); + status = path_to_vnode(path, true, &vnode, kernel); if (status < 0) return status; @@ -1979,6 +1991,27 @@ common_sync(int fd, bool kernel) } +static int +common_read_link(char *path, char *buffer, size_t bufferSize, bool kernel) +{ + struct vnode *vnode; + int status; + + status = path_to_vnode(path, false, &vnode, kernel); + if (status < B_OK) + return status; + + if (FS_CALL(vnode,fs_read_link) != NULL) + status = FS_CALL(vnode,fs_read_link)(vnode->mount->cookie, vnode->private_node, buffer, bufferSize); + else + status = B_BAD_VALUE; + + put_vnode(vnode); + + return status; +} + + static int common_symlink(char *path, const char *toPath, bool kernel) { @@ -1987,6 +2020,8 @@ common_symlink(char *path, const char *toPath, bool kernel) struct vnode *vnode; int status; + FUNCTION(("common_symlink(path = %s, toPath = %s, kernel = %d)\n", path, toPath, kernel)); + status = path_to_dir_vnode(path, &vnode, name, kernel); if (status < B_OK) return status; @@ -2009,7 +2044,7 @@ common_unlink(char *path, bool kernel) struct vnode *vnode; int status; - FUNCTION(("vfs_unlink: path '%s', kernel %d\n", path, kernel)); + FUNCTION(("common_unlink: path '%s', kernel %d\n", path, kernel)); status = path_to_dir_vnode(path, &vnode, filename, kernel); if (status < 0) @@ -2027,18 +2062,20 @@ common_unlink(char *path, bool kernel) static int -common_rename(char *path, char *newpath, bool kernel) +common_rename(char *path, char *newPath, bool kernel) { struct vnode *vnode1, *vnode2; char filename1[SYS_MAX_NAME_LEN]; char filename2[SYS_MAX_NAME_LEN]; int status; + FUNCTION(("common_rename(path = %s, newPath = %s, kernel = %d)\n", path, newPath, kernel)); + status = path_to_dir_vnode(path, &vnode1, filename1, kernel); if (status < 0) goto err; - status = path_to_dir_vnode(newpath, &vnode2, filename2, kernel); + status = path_to_dir_vnode(newPath, &vnode2, filename2, kernel); if (status < 0) goto err1; @@ -2062,14 +2099,14 @@ err: static int -common_write_stat(char *path, const struct stat *stat, int statMask, bool kernel) +common_write_stat(char *path, bool traverseLeafLink, const struct stat *stat, int statMask, bool kernel) { struct vnode *vnode; int status; - FUNCTION(("vfs_write_stat: path '%s', stat 0x%p, stat_mask %d, kernel %d\n", path, stat, statMask, kernel)); + FUNCTION(("common_write_stat: path '%s', stat 0x%p, stat_mask %d, kernel %d\n", path, stat, statMask, kernel)); - status = path_to_vnode(path, &vnode, kernel); + status = path_to_vnode(path, traverseLeafLink, &vnode, kernel); if (status < 0) return status; @@ -2137,7 +2174,7 @@ fs_mount(char *path, const char *device, const char *fs_name, void *args, bool k mount->covers_vnode = NULL; // this is the root mount } else { - err = path_to_vnode(path,&covered_vnode,kernel); + err = path_to_vnode(path, true, &covered_vnode, kernel); if (err < 0) goto err2; @@ -2210,7 +2247,7 @@ fs_unmount(char *path, bool kernel) FUNCTION(("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel)); - err = path_to_vnode(path, &vnode, kernel); + err = path_to_vnode(path, true, &vnode, kernel); if (err < 0) return ERR_VFS_PATH_NOT_FOUND; @@ -2395,10 +2432,10 @@ set_cwd(char *path, bool kernel) struct stat stat; int rc; - FUNCTION(("vfs_set_cwd: path = \'%s\'\n", path)); + FUNCTION(("set_cwd: path = \'%s\'\n", path)); // Get vnode for passed path, and bail if it failed - rc = path_to_vnode(path, &vnode, kernel); + rc = path_to_vnode(path, true, &vnode, kernel); if (rc < 0) return rc; @@ -2580,7 +2617,20 @@ sys_create_dir(const char *path, int perms) int -sys_symlink(const char *userPath, const char *userToPath) +sys_read_link(const char *path, char *buffer, size_t bufferSize) +{ + char pathCopy[SYS_MAX_PATH_LEN + 1]; + int status; + + strncpy(pathCopy, path, SYS_MAX_PATH_LEN); + pathCopy[SYS_MAX_PATH_LEN] = '\0'; + + return common_read_link(pathCopy, buffer, bufferSize, true); +} + + +int +sys_create_symlink(const char *userPath, const char *userToPath) { char path[SYS_MAX_PATH_LEN + 1]; char toPath[SYS_MAX_PATH_LEN + 1]; @@ -2629,37 +2679,37 @@ sys_rename(const char *oldpath, const char *newpath) int -sys_read_stat(const char *path, struct stat *stat) +sys_read_stat(const char *path, bool traverseLeafLink, struct stat *stat) { - char buf[SYS_MAX_PATH_LEN+1]; + char buffer[SYS_MAX_PATH_LEN + 1]; struct vnode *vnode; int status; - strncpy(buf, path, SYS_MAX_PATH_LEN); - buf[SYS_MAX_PATH_LEN] = 0; + strncpy(buffer, path, SYS_MAX_PATH_LEN); + buffer[SYS_MAX_PATH_LEN] = 0; FUNCTION(("sys_read_stat: path '%s', stat %p,\n", path, stat)); - status = path_to_vnode(buf, &vnode, true); + status = path_to_vnode(buffer, traverseLeafLink, &vnode, true); if (status < 0) return status; status = FS_CALL(vnode,fs_read_stat)(vnode->mount->cookie, vnode->private_node, stat); - dec_vnode_ref_count(vnode, false); + put_vnode(vnode); return status; } int -sys_write_stat(const char *path, struct stat *stat, int stat_mask) +sys_write_stat(const char *path, bool traverseLeafLink, struct stat *stat, int statMask) { - char buf[SYS_MAX_PATH_LEN+1]; + char buffer[SYS_MAX_PATH_LEN + 1]; - strncpy(buf, path, SYS_MAX_PATH_LEN); - buf[SYS_MAX_PATH_LEN] = 0; + strncpy(buffer, path, SYS_MAX_PATH_LEN); + buffer[SYS_MAX_PATH_LEN] = 0; - return common_write_stat(buf, stat, stat_mask, true); + return common_write_stat(buffer, traverseLeafLink, stat, statMask, true); } @@ -2901,15 +2951,15 @@ user_create_dir_entry_ref(dev_t device, ino_t inode, const char *uname, int perm int -user_create_dir(const char *upath, int perms) +user_create_dir(const char *userPath, int perms) { char path[SYS_MAX_PATH_LEN + 1]; int status; - if (!CHECK_USER_ADDRESS(upath)) + if (!CHECK_USER_ADDRESS(userPath)) return ERR_VM_BAD_USER_MEMORY; - status = user_strncpy(path, upath, SYS_MAX_PATH_LEN); + status = user_strncpy(path, userPath, SYS_MAX_PATH_LEN); if (status < 0) return status; path[SYS_MAX_PATH_LEN] = '\0'; @@ -2919,7 +2969,31 @@ user_create_dir(const char *upath, int perms) int -user_symlink(const char *userPath, const char *userToPath) +user_read_link(const char *userPath, char *userBuffer, size_t bufferSize) +{ + char path[SYS_MAX_PATH_LEN + 1]; + char buffer[SYS_MAX_PATH_LEN + 1]; + int status; + + if (!CHECK_USER_ADDRESS(userPath) + || !CHECK_USER_ADDRESS(userBuffer)) + return B_BAD_ADDRESS; + + status = user_strncpy(path, userPath, SYS_MAX_PATH_LEN); + if (status < 0) + return status; + path[SYS_MAX_PATH_LEN] = '\0'; + + status = common_read_link(path, buffer, bufferSize, false); + if (status < B_OK) + return status; + + return user_strncpy(userBuffer, buffer, SYS_MAX_PATH_LEN); +} + + +int +user_create_symlink(const char *userPath, const char *userToPath) { char path[SYS_MAX_PATH_LEN + 1]; char toPath[SYS_MAX_PATH_LEN + 1]; @@ -2993,25 +3067,25 @@ user_rename(const char *uoldpath, const char *unewpath) int -user_read_stat(const char *upath, struct stat *ustat) +user_read_stat(const char *userPath, bool traverseLink, struct stat *userStat) { - char path[SYS_MAX_PATH_LEN]; + char path[SYS_MAX_PATH_LEN + 1]; struct vnode *vnode = NULL; struct stat stat; int rc; - if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) - return ERR_VM_BAD_USER_MEMORY; + if (!CHECK_USER_ADDRESS(userPath) + || !CHECK_USER_ADDRESS(userStat)) + return B_BAD_ADDRESS; - if ((addr)ustat >= KERNEL_BASE && (addr)ustat <= KERNEL_TOP) - return ERR_VM_BAD_USER_MEMORY; - - rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); + rc = user_strncpy(path, userPath, SYS_MAX_PATH_LEN); if (rc < 0) return rc; - path[SYS_MAX_PATH_LEN-1] = 0; + path[SYS_MAX_PATH_LEN] = 0; - rc = path_to_vnode(path, &vnode, false); + FUNCTION(("user_read_stat(path = %s, traverseLeafLink = %d)\n", path, traverseLink)); + + rc = path_to_vnode(path, traverseLink, &vnode, false); if (rc < 0) return rc; @@ -3023,35 +3097,31 @@ user_read_stat(const char *upath, struct stat *ustat) if (rc < 0) return rc; - rc = user_memcpy(ustat, &stat, sizeof(struct stat)); - - return rc; + return user_memcpy(userStat, &stat, sizeof(struct stat)); } int -user_write_stat(const char *upath, struct stat *ustat, int stat_mask) +user_write_stat(const char *userPath, bool traverseLeafLink, struct stat *userStat, int statMask) { char path[SYS_MAX_PATH_LEN+1]; struct stat stat; int rc; - if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) - return ERR_VM_BAD_USER_MEMORY; + if (!CHECK_USER_ADDRESS(userPath) + || !CHECK_USER_ADDRESS(userStat)) + return B_BAD_ADDRESS; - if ((addr)ustat >= KERNEL_BASE && (addr)ustat <= KERNEL_TOP) - return ERR_VM_BAD_USER_MEMORY; - - rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN); + rc = user_strncpy(path, userPath, SYS_MAX_PATH_LEN); if (rc < 0) return rc; path[SYS_MAX_PATH_LEN] = 0; - rc = user_memcpy(&stat, ustat, sizeof(struct stat)); + rc = user_memcpy(&stat, userStat, sizeof(struct stat)); if (rc < 0) return rc; - return common_write_stat(path, &stat, stat_mask, false); + return common_write_stat(path, traverseLeafLink, &stat, statMask, false); } diff --git a/src/kernel/core/module.c b/src/kernel/core/module.c index ec2950f664..6ac2b66f86 100644 --- a/src/kernel/core/module.c +++ b/src/kernel/core/module.c @@ -415,7 +415,7 @@ static int recurse_directory(const char *path, const char *match) strlcat(newpath, "/", slen); strlcat(newpath, dirent->d_name, slen); - if ((res = sys_read_stat(newpath, &stat)) != B_NO_ERROR) { + if ((res = sys_read_stat(newpath, true, &stat)) != B_NO_ERROR) { kfree(newpath); break; } @@ -758,7 +758,7 @@ static inline int module_traverse_dir(module_iterator *iter) iter->cur_header = NULL; iter->module_pos = 0; - if ((res = sys_read_stat(path, &stat)) != B_NO_ERROR) + if ((res = sys_read_stat(path, true, &stat)) != B_NO_ERROR) return res; if (S_ISREG(stat.st_mode)) { diff --git a/src/kernel/core/syscalls.c b/src/kernel/core/syscalls.c index 1abb0ae2db..3b9012e673 100644 --- a/src/kernel/core/syscalls.c +++ b/src/kernel/core/syscalls.c @@ -111,20 +111,26 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re case SYSCALL_CREATE_DIR: *call_ret = user_create_dir((const char *)arg0, (int)arg1); break; + case SYSCALL_CREATE_SYMLINK: + *call_ret = user_create_symlink((const char *)arg0, (const char *)arg1); + break; + case SYSCALL_READ_LINK: + *call_ret = user_read_link((const char *)arg0, (char *)arg1, (size_t)arg2); + break; case SYSCALL_UNLINK: *call_ret = user_unlink((const char *)arg0); break; case SYSCALL_RENAME: *call_ret = user_rename((const char *)arg0, (const char *)arg1); break; - case SYSCALL_RSTAT: - *call_ret = user_read_stat((const char *)arg0, (struct stat *)arg1); + case SYSCALL_READ_STAT: + *call_ret = user_read_stat((const char *)arg0, (bool)arg1, (struct stat *)arg2); break; - case SYSCALL_FSTAT: + case SYSCALL_FD_STAT: *call_ret = user_fstat((int)arg0, (struct stat*)arg1); break; - case SYSCALL_WSTAT: - *call_ret = user_write_stat((const char *)arg0, (struct stat *)arg1, (int)arg2); + case SYSCALL_WRITE_STAT: + *call_ret = user_write_stat((const char *)arg0, (bool)arg1, (struct stat *)arg2, (int)arg3); break; case SYSCALL_SYSTEM_TIME: *call_ret = system_time();