Big commit: Added symlink support to the kernel.

- added needed syscalls to access symlink support from userland
- implemented lstat(), symlink(), and readlink()
- added dev_t to ktypes.h (for now - should be in a public header anyway)
- added symlink support to the "ls" command (now calls lstat() and shows the
  link target with the -l option)
- changed the sys_read_stat() call to support symlinks, and updated files
  using that function (it gets an extra argument: bool traverseLink)


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@560 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2002-08-03 02:03:27 +00:00
parent 409a1aeacd
commit ae372703ce
15 changed files with 336 additions and 366 deletions

View File

@ -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);

View File

@ -10,7 +10,7 @@
// This file should reside in headers/posix, not here...
// needs ino_t (int64), and dev_t (long)
#include <ktypes.h>
typedef long dev_t;
typedef struct dirent {
dev_t d_dev;

View File

@ -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 <sys/time.h>
#include <OS.h>
//#include <sys/types.h>
#include <ktypes.h>
/**
* @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 <sys/cdefs.h>
/** @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_ */

View File

@ -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);

View File

@ -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_

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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 ;

View File

@ -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:

View File

@ -2,6 +2,7 @@
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
#include <syscalls.h>
#include <stdio.h>
#include <string.h>
@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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)) {

View File

@ -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();