2002-08-10 00:20:28 +04:00
|
|
|
/* Virtual File System and
|
|
|
|
** File System Interface Layer
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2004-02-23 06:19:02 +03:00
|
|
|
** Copyright 2002-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
2002-08-10 00:20:28 +04:00
|
|
|
** Distributed under the terms of the OpenBeOS License.
|
2004-05-06 05:25:36 +04:00
|
|
|
**
|
2002-07-09 16:24:59 +04:00
|
|
|
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
|
|
|
** Distributed under the terms of the NewOS License.
|
|
|
|
*/
|
|
|
|
|
2004-06-07 21:25:55 +04:00
|
|
|
#include <OS.h>
|
|
|
|
#include <StorageDefs.h>
|
|
|
|
#include <fs_info.h>
|
|
|
|
#include <fs_interface.h>
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
#include <disk_device_manager/KDiskDeviceManager.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
#include <kernel.h>
|
2003-10-08 03:12:37 +04:00
|
|
|
#include <boot/kernel_args.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
#include <vfs.h>
|
|
|
|
#include <vm.h>
|
|
|
|
#include <vm_cache.h>
|
|
|
|
#include <debug.h>
|
|
|
|
#include <khash.h>
|
|
|
|
#include <lock.h>
|
|
|
|
#include <thread.h>
|
2002-10-30 02:07:06 +03:00
|
|
|
#include <malloc.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
#include <arch/cpu.h>
|
|
|
|
#include <elf.h>
|
2002-07-12 02:21:56 +04:00
|
|
|
#include <kerrors.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
#include <fd.h>
|
2003-01-18 17:13:44 +03:00
|
|
|
#include <fs/node_monitor.h>
|
2004-06-15 19:35:10 +04:00
|
|
|
#include <util/kernel_cpp.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <sys/stat.h>
|
2003-09-21 00:47:27 +04:00
|
|
|
#include <sys/resource.h>
|
2002-07-14 09:13:20 +04:00
|
|
|
#include <fcntl.h>
|
2002-08-20 15:00:54 +04:00
|
|
|
#include <limits.h>
|
2003-01-18 17:13:44 +03:00
|
|
|
#include <stddef.h>
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-06-08 10:43:46 +04:00
|
|
|
//#define TRACE_VFS
|
|
|
|
#ifdef TRACE_VFS
|
2002-07-09 16:24:59 +04:00
|
|
|
# define PRINT(x) dprintf x
|
|
|
|
# define FUNCTION(x) dprintf x
|
|
|
|
#else
|
|
|
|
# define PRINT(x) ;
|
|
|
|
# define FUNCTION(x) ;
|
|
|
|
#endif
|
|
|
|
|
2002-08-20 15:00:54 +04:00
|
|
|
#define MAX_SYM_LINKS SYMLINKS_MAX
|
2002-07-28 23:39:49 +04:00
|
|
|
|
2004-04-27 01:46:01 +04:00
|
|
|
static struct {
|
|
|
|
const char *path;
|
|
|
|
const char *target;
|
|
|
|
} sPredefinedLinks[] = {
|
|
|
|
{"/system", "/boot/beos/system"},
|
|
|
|
{"/bin", "/boot/beos/bin"},
|
|
|
|
{"/etc", "/boot/beos/etc"},
|
|
|
|
{"/var", "/boot/var"},
|
|
|
|
{"/tmp", "/boot/tmp"},
|
|
|
|
{NULL}
|
|
|
|
};
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
struct vnode {
|
2002-09-25 18:10:50 +04:00
|
|
|
struct vnode *next;
|
|
|
|
struct vm_cache *cache;
|
2003-10-17 18:47:15 +04:00
|
|
|
mount_id device;
|
2003-01-18 17:13:44 +03:00
|
|
|
list_link mount_link;
|
2002-09-25 18:10:50 +04:00
|
|
|
vnode_id id;
|
|
|
|
fs_vnode private_node;
|
|
|
|
struct fs_mount *mount;
|
|
|
|
struct vnode *covered_by;
|
|
|
|
int32 ref_count;
|
|
|
|
bool delete_me;
|
|
|
|
bool busy;
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct vnode_hash_key {
|
2003-10-17 18:47:15 +04:00
|
|
|
mount_id device;
|
|
|
|
vnode_id vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
2004-06-07 21:25:55 +04:00
|
|
|
#define FS_CALL(vnode, op) (vnode->mount->fs->op)
|
|
|
|
#define FS_MOUNT_CALL(mount, op) (mount->fs->op)
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
struct fs_mount {
|
2002-09-25 18:10:50 +04:00
|
|
|
struct fs_mount *next;
|
2004-06-07 21:25:55 +04:00
|
|
|
file_system_info *fs;
|
2002-09-25 20:34:33 +04:00
|
|
|
mount_id id;
|
2002-09-25 18:10:50 +04:00
|
|
|
void *cookie;
|
|
|
|
char *mount_point;
|
|
|
|
recursive_lock rlock;
|
|
|
|
struct vnode *root_vnode;
|
|
|
|
struct vnode *covers_vnode;
|
2003-01-18 17:13:44 +03:00
|
|
|
struct list vnodes;
|
2002-09-25 18:10:50 +04:00
|
|
|
bool unmounting;
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
static mutex sFileSystemsMutex;
|
2002-09-25 18:10:50 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
static mutex sMountMutex;
|
|
|
|
static mutex sMountOpMutex;
|
|
|
|
static mutex sVnodeMutex;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
#define VNODE_HASH_TABLE_SIZE 1024
|
2003-10-17 18:47:15 +04:00
|
|
|
static hash_table *sVnodeTable;
|
|
|
|
static struct vnode *sRoot;
|
2002-09-25 18:10:50 +04:00
|
|
|
|
|
|
|
#define MOUNTS_HASH_TABLE_SIZE 16
|
2003-10-17 18:47:15 +04:00
|
|
|
static hash_table *sMountsTable;
|
|
|
|
static mount_id sNextMountID = 0;
|
2002-09-25 18:10:50 +04:00
|
|
|
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
/* function declarations */
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
// file descriptor operation prototypes
|
2004-06-16 14:32:26 +04:00
|
|
|
static status_t file_read(struct file_descriptor *, off_t pos, void *buffer, size_t *);
|
|
|
|
static status_t file_write(struct file_descriptor *, off_t pos, const void *buffer, size_t *);
|
2002-07-17 11:55:51 +04:00
|
|
|
static off_t file_seek(struct file_descriptor *, off_t pos, int seek_type);
|
2002-07-14 09:13:20 +04:00
|
|
|
static void file_free_fd(struct file_descriptor *);
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t file_close(struct file_descriptor *);
|
2002-10-17 07:09:25 +04:00
|
|
|
static status_t dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count);
|
2002-09-25 06:18:20 +04:00
|
|
|
static status_t dir_rewind(struct file_descriptor *);
|
2002-07-14 09:13:20 +04:00
|
|
|
static void dir_free_fd(struct file_descriptor *);
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t dir_close(struct file_descriptor *);
|
2002-10-17 07:09:25 +04:00
|
|
|
static status_t attr_dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count);
|
2002-09-26 07:50:14 +04:00
|
|
|
static status_t attr_dir_rewind(struct file_descriptor *);
|
|
|
|
static void attr_dir_free_fd(struct file_descriptor *);
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t attr_dir_close(struct file_descriptor *);
|
2004-06-16 14:32:26 +04:00
|
|
|
static status_t attr_read(struct file_descriptor *, off_t pos, void *buffer, size_t *);
|
|
|
|
static status_t attr_write(struct file_descriptor *, off_t pos, const void *buffer, size_t *);
|
2002-09-25 06:18:20 +04:00
|
|
|
static off_t attr_seek(struct file_descriptor *, off_t pos, int seek_type);
|
|
|
|
static void attr_free_fd(struct file_descriptor *);
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t attr_close(struct file_descriptor *);
|
|
|
|
static status_t attr_read_stat(struct file_descriptor *, struct stat *);
|
2002-10-17 07:09:25 +04:00
|
|
|
static status_t attr_write_stat(struct file_descriptor *, const struct stat *, int statMask);
|
|
|
|
static status_t index_dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count);
|
2002-09-26 07:50:14 +04:00
|
|
|
static status_t index_dir_rewind(struct file_descriptor *);
|
|
|
|
static void index_dir_free_fd(struct file_descriptor *);
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t index_dir_close(struct file_descriptor *);
|
2002-09-25 06:18:20 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t common_ioctl(struct file_descriptor *, ulong, void *buf, size_t len);
|
|
|
|
static status_t common_read_stat(struct file_descriptor *, struct stat *);
|
2002-10-17 07:09:25 +04:00
|
|
|
static status_t common_write_stat(struct file_descriptor *, const struct stat *, int statMask);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
static status_t dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize);
|
2003-09-04 08:01:25 +04:00
|
|
|
static void inc_vnode_ref_count(struct vnode *vnode);
|
|
|
|
static status_t dec_vnode_ref_count(struct vnode *vnode, bool reenter);
|
|
|
|
static inline void put_vnode(struct vnode *vnode);
|
2002-07-19 01:06:02 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
static struct fd_ops sFileOps = {
|
2002-07-14 09:13:20 +04:00
|
|
|
file_read,
|
|
|
|
file_write,
|
|
|
|
file_seek,
|
|
|
|
common_ioctl,
|
2002-10-29 06:54:07 +03:00
|
|
|
NULL, // select()
|
|
|
|
NULL, // deselect()
|
|
|
|
NULL, // read_dir()
|
|
|
|
NULL, // rewind_dir()
|
2002-07-14 09:13:20 +04:00
|
|
|
common_read_stat,
|
2002-10-17 07:09:25 +04:00
|
|
|
common_write_stat,
|
2002-07-17 11:55:51 +04:00
|
|
|
file_close,
|
2002-07-14 09:13:20 +04:00
|
|
|
file_free_fd
|
|
|
|
};
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
static struct fd_ops sDirectoryOps = {
|
2002-10-29 06:54:07 +03:00
|
|
|
NULL, // read()
|
|
|
|
NULL, // write()
|
|
|
|
NULL, // seek()
|
2002-07-14 09:13:20 +04:00
|
|
|
common_ioctl,
|
2002-10-29 06:54:07 +03:00
|
|
|
NULL, // select()
|
|
|
|
NULL, // deselect()
|
2002-07-14 09:13:20 +04:00
|
|
|
dir_read,
|
|
|
|
dir_rewind,
|
|
|
|
common_read_stat,
|
2002-10-17 07:09:25 +04:00
|
|
|
common_write_stat,
|
2002-07-17 11:55:51 +04:00
|
|
|
dir_close,
|
2002-07-14 09:13:20 +04:00
|
|
|
dir_free_fd
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
static struct fd_ops sAttributeDirectoryOps = {
|
2002-10-29 06:54:07 +03:00
|
|
|
NULL, // read()
|
|
|
|
NULL, // write()
|
|
|
|
NULL, // seek()
|
2002-09-26 07:50:14 +04:00
|
|
|
common_ioctl,
|
2002-10-29 06:54:07 +03:00
|
|
|
NULL, // select()
|
|
|
|
NULL, // deselect()
|
2002-09-26 07:50:14 +04:00
|
|
|
attr_dir_read,
|
|
|
|
attr_dir_rewind,
|
|
|
|
common_read_stat,
|
2002-10-17 07:09:25 +04:00
|
|
|
common_write_stat,
|
2002-09-26 07:50:14 +04:00
|
|
|
attr_dir_close,
|
|
|
|
attr_dir_free_fd
|
|
|
|
};
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
static struct fd_ops sAttributeOps = {
|
2002-09-25 06:18:20 +04:00
|
|
|
attr_read,
|
|
|
|
attr_write,
|
|
|
|
attr_seek,
|
|
|
|
common_ioctl,
|
2002-10-29 06:54:07 +03:00
|
|
|
NULL, // select()
|
|
|
|
NULL, // deselect()
|
|
|
|
NULL, // read_dir()
|
|
|
|
NULL, // rewind_dir()
|
2002-09-25 06:18:20 +04:00
|
|
|
attr_read_stat,
|
2002-10-17 07:09:25 +04:00
|
|
|
attr_write_stat,
|
2002-09-25 06:18:20 +04:00
|
|
|
attr_close,
|
|
|
|
attr_free_fd
|
|
|
|
};
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
static struct fd_ops sIndexDirectoryOps = {
|
2002-10-17 07:09:25 +04:00
|
|
|
NULL, // read()
|
|
|
|
NULL, // write()
|
|
|
|
NULL, // seek()
|
|
|
|
NULL, // ioctl()
|
2002-10-29 06:54:07 +03:00
|
|
|
NULL, // select()
|
|
|
|
NULL, // deselect()
|
2002-09-26 07:50:14 +04:00
|
|
|
index_dir_read,
|
|
|
|
index_dir_rewind,
|
2002-10-17 07:09:25 +04:00
|
|
|
NULL, // read_stat()
|
|
|
|
NULL, // write_stat()
|
2002-09-26 07:50:14 +04:00
|
|
|
index_dir_close,
|
|
|
|
index_dir_free_fd
|
|
|
|
};
|
|
|
|
|
2003-09-04 08:07:39 +04:00
|
|
|
#if 0
|
2003-10-17 18:47:15 +04:00
|
|
|
static struct fd_ops sIndexOps = {
|
2003-09-04 08:07:39 +04:00
|
|
|
NULL, // read()
|
|
|
|
NULL, // write()
|
|
|
|
NULL, // seek()
|
|
|
|
NULL, // ioctl()
|
|
|
|
NULL, // select()
|
|
|
|
NULL, // deselect()
|
|
|
|
NULL, // dir_read()
|
|
|
|
NULL, // dir_rewind()
|
|
|
|
index_read_stat, // read_stat()
|
|
|
|
NULL, // write_stat()
|
|
|
|
NULL, // dir_close()
|
|
|
|
NULL // free_fd()
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
static int
|
|
|
|
mount_compare(void *_m, const void *_key)
|
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
struct fs_mount *mount = (fs_mount *)_m;
|
|
|
|
const mount_id *id = (mount_id *)_key;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount->id == *id)
|
2002-07-09 16:24:59 +04:00
|
|
|
return 0;
|
2002-07-17 11:55:51 +04:00
|
|
|
|
|
|
|
return -1;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-29 11:36:05 +03:00
|
|
|
static uint32
|
|
|
|
mount_hash(void *_m, const void *_key, uint32 range)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
struct fs_mount *mount = (fs_mount *)_m;
|
|
|
|
const mount_id *id = (mount_id *)_key;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
if (mount)
|
2002-07-09 16:24:59 +04:00
|
|
|
return mount->id % range;
|
2002-07-17 11:55:51 +04:00
|
|
|
|
|
|
|
return *id % range;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
/** Finds the mounted device (the fs_mount structure) with the given ID.
|
|
|
|
* Note, you must hold the gMountMutex lock when you call this function.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct fs_mount *
|
|
|
|
find_mount(mount_id id)
|
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
ASSERT_LOCKED_MUTEX(&sMountMutex);
|
2002-09-26 07:50:14 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
return (fs_mount *)hash_lookup(sMountsTable, (void *)&id);
|
2002-09-26 07:50:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
static struct fs_mount *
|
|
|
|
get_mount(mount_id id)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sMountMutex);
|
2003-09-04 08:01:25 +04:00
|
|
|
|
|
|
|
mount = find_mount(id);
|
|
|
|
if (mount) {
|
|
|
|
// ToDo: the volume is locked (against removal) by locking
|
|
|
|
// its root node - investigate if that's a good idea
|
|
|
|
if (mount->root_vnode)
|
|
|
|
inc_vnode_ref_count(mount->root_vnode);
|
|
|
|
else
|
|
|
|
mount = NULL;
|
|
|
|
}
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sMountMutex);
|
2003-09-04 08:01:25 +04:00
|
|
|
|
|
|
|
return mount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
put_mount(struct fs_mount *mount)
|
|
|
|
{
|
|
|
|
if (mount)
|
|
|
|
put_vnode(mount->root_vnode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
static status_t
|
2004-06-07 21:25:55 +04:00
|
|
|
put_file_system(file_system_info *fs)
|
2002-09-25 18:10:50 +04:00
|
|
|
{
|
2004-06-07 21:25:55 +04:00
|
|
|
return put_module(fs->module_info.name);
|
2002-09-25 18:10:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-07 21:25:55 +04:00
|
|
|
static file_system_info *
|
|
|
|
get_file_system(const char *fsName)
|
2002-09-25 18:10:50 +04:00
|
|
|
{
|
2004-06-07 21:25:55 +04:00
|
|
|
// construct module name (we currently support only one API)
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
snprintf(name, sizeof(name), "file_systems/%s/v1", fsName);
|
2002-09-25 18:10:50 +04:00
|
|
|
|
2004-06-07 21:25:55 +04:00
|
|
|
file_system_info *info;
|
|
|
|
if (get_module(name, (module_info **)&info) != B_OK)
|
|
|
|
return NULL;
|
2002-09-25 18:10:50 +04:00
|
|
|
|
2004-06-07 21:25:55 +04:00
|
|
|
return info;
|
2002-09-25 18:10:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
static int
|
2002-11-29 11:36:05 +03:00
|
|
|
vnode_compare(void *_vnode, const void *_key)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
struct vnode *vnode = (struct vnode *)_vnode;
|
|
|
|
const struct vnode_hash_key *key = (vnode_hash_key *)_key;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (vnode->device == key->device && vnode->id == key->vnode)
|
2002-07-09 16:24:59 +04:00
|
|
|
return 0;
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
return -1;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-29 11:36:05 +03:00
|
|
|
static uint32
|
|
|
|
vnode_hash(void *_vnode, const void *_key, uint32 range)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
struct vnode *vnode = (struct vnode *)_vnode;
|
|
|
|
const struct vnode_hash_key *key = (vnode_hash_key *)_key;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
#define VHASH(mountid, vnodeid) (((uint32)((vnodeid) >> 32) + (uint32)(vnodeid)) ^ (uint32)(mountid))
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (vnode != NULL)
|
2003-10-17 18:47:15 +04:00
|
|
|
return (VHASH(vnode->device, vnode->id) % range);
|
|
|
|
|
|
|
|
return (VHASH(key->device, key->vnode) % range);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
#undef VHASH
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2002-09-26 07:50:14 +04:00
|
|
|
add_vnode_to_mount_list(struct vnode *vnode, struct fs_mount *mount)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
recursive_lock_lock(&mount->rlock);
|
|
|
|
|
2003-01-18 17:13:44 +03:00
|
|
|
list_add_link_to_head(&mount->vnodes, &vnode->mount_link);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
recursive_lock_unlock(&mount->rlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2002-09-26 07:50:14 +04:00
|
|
|
remove_vnode_from_mount_list(struct vnode *vnode, struct fs_mount *mount)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
recursive_lock_lock(&mount->rlock);
|
|
|
|
|
2003-01-18 17:13:44 +03:00
|
|
|
list_remove_link(&vnode->mount_link);
|
|
|
|
vnode->mount_link.next = vnode->mount_link.prev = NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
recursive_lock_unlock(&mount->rlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
static status_t
|
|
|
|
create_new_vnode(struct vnode **_vnode, mount_id mountID, vnode_id vnodeID)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2004-06-08 10:43:46 +04:00
|
|
|
FUNCTION(("create_new_vnode()\n"));
|
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
struct vnode *vnode = (struct vnode *)malloc(sizeof(struct vnode));
|
2002-09-26 07:50:14 +04:00
|
|
|
if (vnode == NULL)
|
2004-02-02 18:09:21 +03:00
|
|
|
return B_NO_MEMORY;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
// initialize basic values
|
2002-09-26 07:50:14 +04:00
|
|
|
memset(vnode, 0, sizeof(struct vnode));
|
2004-02-02 18:09:21 +03:00
|
|
|
vnode->device = mountID;
|
|
|
|
vnode->id = vnodeID;
|
|
|
|
|
|
|
|
// add the vnode to the mount structure
|
|
|
|
mutex_lock(&sMountMutex);
|
|
|
|
vnode->mount = find_mount(mountID);
|
|
|
|
if (!vnode->mount) {
|
|
|
|
mutex_unlock(&sMountMutex);
|
|
|
|
free(vnode);
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
hash_insert(sVnodeTable, vnode);
|
|
|
|
add_vnode_to_mount_list(vnode, vnode->mount);
|
|
|
|
|
|
|
|
mutex_unlock(&sMountMutex);
|
|
|
|
|
|
|
|
vnode->ref_count = 1;
|
|
|
|
*_vnode = vnode;
|
|
|
|
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-21 16:49:26 +03:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
dec_vnode_ref_count(struct vnode *vnode, bool reenter)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
int old_ref;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (vnode->busy == true)
|
|
|
|
panic("dec_vnode_ref_count called on vnode that was busy! vnode %p\n", vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
old_ref = atomic_add(&vnode->ref_count, -1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 03:24:12 +04:00
|
|
|
PRINT(("dec_vnode_ref_count: vnode %p, ref now %ld\n", vnode, vnode->ref_count));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
if (old_ref == 1) {
|
2002-07-20 04:16:12 +04:00
|
|
|
vnode->busy = true;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
/* if we have a vm_cache attached, remove it */
|
2002-07-20 04:16:12 +04:00
|
|
|
if (vnode->cache)
|
|
|
|
vm_cache_release_ref((vm_cache_ref *)vnode->cache);
|
|
|
|
vnode->cache = NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (vnode->delete_me)
|
2002-09-24 20:17:22 +04:00
|
|
|
FS_CALL(vnode, remove_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
|
2002-07-09 16:24:59 +04:00
|
|
|
else
|
2002-09-24 20:17:22 +04:00
|
|
|
FS_CALL(vnode, put_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
remove_vnode_from_mount_list(vnode, vnode->mount);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
|
|
|
hash_remove(sVnodeTable, vnode);
|
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-30 02:07:06 +03:00
|
|
|
free(vnode);
|
2002-10-05 23:45:31 +04:00
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
err = 1;
|
|
|
|
} else {
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
err = 0;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-21 16:49:26 +03:00
|
|
|
static void
|
2002-07-20 04:16:12 +04:00
|
|
|
inc_vnode_ref_count(struct vnode *vnode)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
atomic_add(&vnode->ref_count, 1);
|
2002-09-24 03:24:12 +04:00
|
|
|
PRINT(("inc_vnode_ref_count: vnode %p, ref now %ld\n", vnode, vnode->ref_count));
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct vnode *
|
2002-09-25 18:10:50 +04:00
|
|
|
lookup_vnode(mount_id mountID, vnode_id vnodeID)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
|
|
|
struct vnode_hash_key key;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
key.device = mountID;
|
|
|
|
key.vnode = vnodeID;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
return (vnode *)hash_lookup(sVnodeTable, &key);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-21 16:49:26 +03:00
|
|
|
static status_t
|
2002-09-25 18:10:50 +04:00
|
|
|
get_vnode(mount_id mountID, vnode_id vnodeID, struct vnode **_vnode, int reenter)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-09-25 18:10:50 +04:00
|
|
|
FUNCTION(("get_vnode: mountid %ld vnid 0x%Lx %p\n", mountID, vnodeID, _vnode));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
restart:
|
|
|
|
struct vnode *vnode = lookup_vnode(mountID, vnodeID);
|
|
|
|
if (vnode && vnode->busy) {
|
|
|
|
// ToDo: this is an endless loop if the vnode is not
|
|
|
|
// becoming unbusy anymore (for whatever reason)
|
|
|
|
mutex_unlock(&sVnodeMutex);
|
|
|
|
snooze(10000); // 10 ms
|
|
|
|
mutex_lock(&sVnodeMutex);
|
|
|
|
goto restart;
|
2002-10-07 19:31:40 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-08-18 07:21:26 +04:00
|
|
|
PRINT(("get_vnode: tried to lookup vnode, got %p\n", vnode));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
status_t status;
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (vnode) {
|
|
|
|
inc_vnode_ref_count(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
} else {
|
|
|
|
// we need to create a new vnode and read it in
|
2004-02-02 18:09:21 +03:00
|
|
|
status = create_new_vnode(&vnode, mountID, vnodeID);
|
|
|
|
if (status < B_OK)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err;
|
2002-09-26 07:50:14 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
vnode->busy = true;
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
status = FS_CALL(vnode, get_vnode)(vnode->mount->cookie, vnodeID, &vnode->private_node, reenter);
|
|
|
|
if (status < B_OK || vnode->private_node == NULL) {
|
2002-07-20 04:16:12 +04:00
|
|
|
remove_vnode_from_mount_list(vnode, vnode->mount);
|
2004-02-02 18:09:21 +03:00
|
|
|
if (status == B_NO_ERROR)
|
|
|
|
status = B_BAD_VALUE;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
2004-02-02 18:09:21 +03:00
|
|
|
|
|
|
|
if (status < B_OK)
|
2002-07-09 16:24:59 +04:00
|
|
|
goto err1;
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
vnode->busy = false;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-08-18 07:21:26 +04:00
|
|
|
PRINT(("get_vnode: returning %p\n", vnode));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
*_vnode = vnode;
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
err1:
|
2003-10-17 18:47:15 +04:00
|
|
|
hash_remove(sVnodeTable, vnode);
|
2004-02-02 18:09:21 +03:00
|
|
|
remove_vnode_from_mount_list(vnode, vnode->mount);
|
2002-07-09 16:24:59 +04:00
|
|
|
err:
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (vnode)
|
2002-10-30 02:07:06 +03:00
|
|
|
free(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-10 00:20:28 +04:00
|
|
|
static inline void
|
2002-07-20 04:16:12 +04:00
|
|
|
put_vnode(struct vnode *vnode)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
dec_vnode_ref_count(vnode, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static status_t
|
2002-09-25 18:10:50 +04:00
|
|
|
entry_ref_to_vnode(mount_id mountID, vnode_id directoryID, const char *name, struct vnode **_vnode)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
struct vnode *directory, *vnode;
|
2002-07-20 04:16:12 +04:00
|
|
|
vnode_id id;
|
|
|
|
int status;
|
2002-07-28 22:41:07 +04:00
|
|
|
int type;
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
status = get_vnode(mountID, directoryID, &directory, false);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
status = FS_CALL(directory, lookup)(directory->mount->cookie,
|
2002-07-28 22:41:07 +04:00
|
|
|
directory->private_node, name, &id, &type);
|
|
|
|
put_vnode(directory);
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
2002-09-25 18:10:50 +04:00
|
|
|
vnode = lookup_vnode(mountID, id);
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-28 22:41:07 +04:00
|
|
|
|
|
|
|
if (vnode == NULL) {
|
|
|
|
// fs_lookup() should have left the vnode referenced, so chances
|
|
|
|
// are good that this will never happen
|
2002-09-25 18:10:50 +04:00
|
|
|
panic("entry_ref_to_vnode: could not lookup vnode (mountid 0x%lx vnid 0x%Lx)\n", mountID, id);
|
2002-07-28 22:41:07 +04:00
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
*_vnode = vnode;
|
|
|
|
return B_OK;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-05 23:45:31 +04:00
|
|
|
static status_t
|
2003-09-08 08:02:34 +04:00
|
|
|
vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
|
|
|
|
int count, struct vnode **_vnode, int *_type)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-10-05 23:45:31 +04:00
|
|
|
status_t status = 0;
|
2003-09-08 08:02:34 +04:00
|
|
|
int type = 0;
|
2002-10-05 23:45:31 +04:00
|
|
|
|
2004-06-08 15:34:49 +04:00
|
|
|
FUNCTION(("vnode_path_to_vnode(vnode = %p, path = %s)\n", vnode, path));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (!path)
|
2004-06-08 15:34:49 +04:00
|
|
|
return B_BAD_VALUE;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-28 23:39:49 +04:00
|
|
|
while (true) {
|
2002-07-28 22:41:07 +04:00
|
|
|
struct vnode *nextVnode;
|
|
|
|
vnode_id vnodeID;
|
|
|
|
char *nextPath;
|
|
|
|
|
2003-08-18 07:21:26 +04:00
|
|
|
PRINT(("vnode_path_to_vnode: top of loop. p = %p, p = '%s'\n", path, path));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
// done?
|
2003-08-18 07:21:26 +04:00
|
|
|
if (path[0] == '\0')
|
2002-07-09 16:24:59 +04:00
|
|
|
break;
|
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
// walk to find the next path component ("path" will point to a single
|
|
|
|
// path component), and filter out multiple slashes
|
2003-08-18 07:21:26 +04:00
|
|
|
for (nextPath = path + 1; *nextPath != '\0' && *nextPath != '/'; nextPath++);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (*nextPath == '/') {
|
|
|
|
*nextPath = '\0';
|
2002-07-09 16:24:59 +04:00
|
|
|
do
|
2002-07-20 04:16:12 +04:00
|
|
|
nextPath++;
|
|
|
|
while (*nextPath == '/');
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-08 15:34:49 +04:00
|
|
|
// See if the '..' is at the root of a mount and move to the covered
|
|
|
|
// vnode so we pass the '..' path to the underlying filesystem
|
2002-11-11 15:14:19 +03:00
|
|
|
if (!strcmp("..", path)
|
|
|
|
&& vnode->mount->root_vnode == vnode
|
|
|
|
&& vnode->mount->covers_vnode) {
|
|
|
|
nextVnode = vnode->mount->covers_vnode;
|
|
|
|
inc_vnode_ref_count(nextVnode);
|
|
|
|
put_vnode(vnode);
|
|
|
|
vnode = nextVnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-11-11 15:14:19 +03:00
|
|
|
// Check if we have the right to search the current directory vnode.
|
|
|
|
// If a file system doesn't have the access() function, we assume that
|
|
|
|
// searching a directory is always allowed
|
|
|
|
if (FS_CALL(vnode, access))
|
|
|
|
status = FS_CALL(vnode, access)(vnode->mount->cookie, vnode->private_node, X_OK);
|
|
|
|
|
|
|
|
// Tell the filesystem to get the vnode of this path component (if we got the
|
|
|
|
// permission from the call above)
|
|
|
|
if (status >= B_OK)
|
|
|
|
status = FS_CALL(vnode, lookup)(vnode->mount->cookie, vnode->private_node, path, &vnodeID, &type);
|
|
|
|
|
|
|
|
if (status < B_OK) {
|
2002-07-28 22:41:07 +04:00
|
|
|
put_vnode(vnode);
|
2002-07-28 23:39:49 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-11-11 15:14:19 +03:00
|
|
|
// Lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called
|
2002-07-28 23:39:49 +04:00
|
|
|
// from inside the filesystem, thus the vnode would have to be in the list and it's
|
|
|
|
// ref count incremented at this point
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
|
|
|
nextVnode = lookup_vnode(vnode->device, vnodeID);
|
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (!nextVnode) {
|
2003-02-21 16:49:26 +03:00
|
|
|
// pretty screwed up here - the file system found the vnode, but the hash
|
|
|
|
// lookup failed, so our internal structures are messed up
|
2003-10-17 18:47:15 +04:00
|
|
|
panic("path_to_vnode: could not lookup vnode (mountid 0x%lx vnid 0x%Lx)\n", vnode->device, vnodeID);
|
2002-07-28 22:41:07 +04:00
|
|
|
put_vnode(vnode);
|
2003-02-21 16:49:26 +03:00
|
|
|
return B_ENTRY_NOT_FOUND;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
// 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')) {
|
2002-07-28 23:39:49 +04:00
|
|
|
char *buffer;
|
|
|
|
|
2004-06-08 10:43:46 +04:00
|
|
|
PRINT(("traverse link\n"));
|
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
// it's not exactly nice style using goto in this way, but hey, it works :-/
|
2002-07-28 23:39:49 +04:00
|
|
|
if (count + 1 > MAX_SYM_LINKS) {
|
2002-08-03 06:03:27 +04:00
|
|
|
status = B_LINK_LIMIT;
|
|
|
|
goto resolve_link_error;
|
2002-07-28 23:39:49 +04:00
|
|
|
}
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
buffer = (char *)malloc(SYS_MAX_PATH_LEN);
|
2002-07-28 23:39:49 +04:00
|
|
|
if (buffer == NULL) {
|
2002-08-03 06:03:27 +04:00
|
|
|
status = B_NO_MEMORY;
|
|
|
|
goto resolve_link_error;
|
2002-07-28 23:39:49 +04:00
|
|
|
}
|
2002-08-03 06:03:27 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
status = FS_CALL(nextVnode, read_link)(nextVnode->mount->cookie, nextVnode->private_node, buffer, SYS_MAX_PATH_LEN);
|
2002-07-28 23:39:49 +04:00
|
|
|
if (status < B_OK) {
|
2002-10-30 02:07:06 +03:00
|
|
|
free(buffer);
|
2002-08-03 06:03:27 +04:00
|
|
|
|
2002-11-11 15:14:19 +03:00
|
|
|
resolve_link_error:
|
2002-08-03 06:03:27 +04:00
|
|
|
put_vnode(vnode);
|
|
|
|
put_vnode(nextVnode);
|
|
|
|
|
2002-07-28 23:39:49 +04:00
|
|
|
return status;
|
|
|
|
}
|
2002-08-03 06:03:27 +04:00
|
|
|
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 == '/')
|
|
|
|
;
|
2003-10-17 18:47:15 +04:00
|
|
|
vnode = sRoot;
|
2002-08-03 06:03:27 +04:00
|
|
|
inc_vnode_ref_count(vnode);
|
|
|
|
}
|
2004-06-08 15:34:49 +04:00
|
|
|
inc_vnode_ref_count(vnode);
|
|
|
|
// balance the next recursion - we will decrement the ref_count
|
|
|
|
// of the vnode, no matter if we succeeded or not
|
2002-08-03 06:03:27 +04:00
|
|
|
|
2003-09-08 08:02:34 +04:00
|
|
|
status = vnode_path_to_vnode(vnode, path, traverseLeafLink, count + 1, &nextVnode, _type);
|
2002-07-28 23:39:49 +04:00
|
|
|
|
2002-10-30 02:07:06 +03:00
|
|
|
free(buffer);
|
2002-07-28 23:39:49 +04:00
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
if (status < B_OK) {
|
|
|
|
put_vnode(vnode);
|
|
|
|
return status;
|
|
|
|
}
|
2002-07-28 23:39:49 +04:00
|
|
|
}
|
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
// decrease the ref count on the old dir we just looked up into
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
path = nextPath;
|
|
|
|
vnode = nextVnode;
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
// see if we hit a mount point
|
2002-07-20 04:16:12 +04:00
|
|
|
if (vnode->covered_by) {
|
|
|
|
nextVnode = vnode->covered_by;
|
|
|
|
inc_vnode_ref_count(nextVnode);
|
2002-07-28 22:41:07 +04:00
|
|
|
put_vnode(vnode);
|
2002-07-20 04:16:12 +04:00
|
|
|
vnode = nextVnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
*_vnode = vnode;
|
2003-09-08 08:02:34 +04:00
|
|
|
if (_type)
|
|
|
|
*_type = type;
|
|
|
|
|
2002-07-28 23:39:49 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-28 23:39:49 +04:00
|
|
|
|
2003-09-08 08:02:34 +04:00
|
|
|
static status_t
|
2002-08-03 06:03:27 +04:00
|
|
|
path_to_vnode(char *path, bool traverseLink, struct vnode **_vnode, bool kernel)
|
2002-07-28 23:39:49 +04:00
|
|
|
{
|
|
|
|
struct vnode *start;
|
2002-10-05 23:45:31 +04:00
|
|
|
|
2003-08-18 07:21:26 +04:00
|
|
|
FUNCTION(("path_to_vnode(path = \"%s\")\n", path));
|
2002-07-28 23:39:49 +04:00
|
|
|
|
|
|
|
if (!path)
|
2004-06-08 15:34:49 +04:00
|
|
|
return B_BAD_VALUE;
|
2002-07-28 23:39:49 +04:00
|
|
|
|
|
|
|
// figure out if we need to start at root or at cwd
|
|
|
|
if (*path == '/') {
|
|
|
|
while (*++path == '/')
|
|
|
|
;
|
2003-10-17 18:47:15 +04:00
|
|
|
start = sRoot;
|
2002-07-28 23:39:49 +04:00
|
|
|
inc_vnode_ref_count(start);
|
|
|
|
} else {
|
|
|
|
struct io_context *context = get_current_io_context(kernel);
|
|
|
|
|
|
|
|
mutex_lock(&context->io_mutex);
|
|
|
|
start = context->cwd;
|
|
|
|
inc_vnode_ref_count(start);
|
|
|
|
mutex_unlock(&context->io_mutex);
|
|
|
|
}
|
|
|
|
|
2003-09-08 08:02:34 +04:00
|
|
|
return vnode_path_to_vnode(start, path, traverseLink, 0, _vnode, NULL);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Returns the vnode in the next to last segment of the path, and returns
|
|
|
|
* the last portion in filename.
|
2002-08-14 00:39:25 +04:00
|
|
|
* The path buffer must be able to store at least one additional character.
|
2002-07-09 16:24:59 +04:00
|
|
|
*/
|
|
|
|
|
2003-09-08 08:02:34 +04:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
char *p = strrchr(path, '/');
|
2003-09-08 08:02:34 +04:00
|
|
|
// '/' are not allowed in file names!
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-05 23:45:31 +04:00
|
|
|
FUNCTION(("path_to_dir_vnode(path = %s)\n", path));
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
if (!p) {
|
|
|
|
// this path is single segment with no '/' in it
|
|
|
|
// ex. "foo"
|
|
|
|
strcpy(filename, path);
|
|
|
|
strcpy(path, ".");
|
|
|
|
} else {
|
|
|
|
// replace the filename portion of the path with a '.'
|
2002-07-28 22:41:07 +04:00
|
|
|
strcpy(filename, ++p);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
if (p[0] != '\0'){
|
|
|
|
p[0] = '.';
|
|
|
|
p[1] = '\0';
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
}
|
2002-08-03 06:03:27 +04:00
|
|
|
return path_to_vnode(path, true, _vnode, kernel);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
/** Gets the full path to a given directory vnode.
|
|
|
|
* It uses the fs_get_vnode_name() call to get the name of a vnode; if a
|
|
|
|
* file system doesn't support this call, it will fall back to iterating
|
|
|
|
* through the parent directory to get the name of the child.
|
|
|
|
*
|
2002-07-23 18:10:12 +04:00
|
|
|
* To protect against circular loops, it supports a maximum tree depth
|
2002-07-19 01:06:02 +04:00
|
|
|
* of 256 levels.
|
|
|
|
*
|
|
|
|
* Note that the path may not be correct the time this function returns!
|
|
|
|
* It doesn't use any locking to prevent returning the correct path, as
|
|
|
|
* paths aren't safe anyway: the path to a file can change at any time.
|
2002-07-23 18:10:12 +04:00
|
|
|
*
|
|
|
|
* It might be a good idea, though, to check if the returned path exists
|
|
|
|
* in the calling function (it's not done here because of efficiency)
|
2002-07-19 01:06:02 +04:00
|
|
|
*/
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static status_t
|
2002-07-19 01:06:02 +04:00
|
|
|
dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
|
|
|
|
{
|
|
|
|
/* this implementation is currently bound to SYS_MAX_PATH_LEN */
|
|
|
|
char path[SYS_MAX_PATH_LEN];
|
|
|
|
int32 insert = sizeof(path);
|
|
|
|
int32 maxLevel = 256;
|
|
|
|
int32 length;
|
|
|
|
status_t status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
if (vnode == NULL || buffer == NULL)
|
|
|
|
return EINVAL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 08:20:07 +04:00
|
|
|
// we don't use get_vnode() here because this call is more
|
|
|
|
// efficient and does all we need from get_vnode()
|
2002-07-19 01:06:02 +04:00
|
|
|
inc_vnode_ref_count(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
path[--insert] = '\0';
|
|
|
|
|
|
|
|
while (true) {
|
2002-07-19 08:20:07 +04:00
|
|
|
// the name buffer is also used for fs_read_dir()
|
|
|
|
char nameBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
|
|
|
char *name = &((struct dirent *)nameBuffer)->d_name[0];
|
2002-07-28 22:41:07 +04:00
|
|
|
struct vnode *parentVnode;
|
|
|
|
vnode_id parentID, id;
|
|
|
|
int type;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
// lookup the parent vnode
|
2003-10-17 18:47:15 +04:00
|
|
|
status = FS_CALL(vnode, lookup)(vnode->mount->cookie, vnode->private_node, "..", &parentID, &type);
|
2002-07-28 22:41:07 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
goto out;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
|
|
|
parentVnode = lookup_vnode(vnode->device, parentID);
|
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-28 22:41:07 +04:00
|
|
|
|
|
|
|
if (parentVnode == NULL) {
|
2003-10-17 18:47:15 +04:00
|
|
|
panic("dir_vnode_to_path: could not lookup vnode (mountid 0x%lx vnid 0x%Lx)\n", vnode->device, parentID);
|
2002-07-28 22:41:07 +04:00
|
|
|
status = B_ENTRY_NOT_FOUND;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-19 08:20:07 +04:00
|
|
|
// Does the file system support getting the name of a vnode?
|
|
|
|
// If so, get it here...
|
2002-09-24 20:17:22 +04:00
|
|
|
if (status == B_OK && FS_CALL(vnode, get_vnode_name))
|
2003-10-17 18:47:15 +04:00
|
|
|
status = FS_CALL(vnode, get_vnode_name)(vnode->mount->cookie, vnode->private_node, name, B_FILE_NAME_LENGTH);
|
2002-07-19 08:20:07 +04:00
|
|
|
|
|
|
|
// ... if not, find it out later (by iterating through
|
|
|
|
// the parent directory, searching for the id)
|
2002-07-20 04:16:12 +04:00
|
|
|
id = vnode->id;
|
2002-07-19 08:20:07 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
// release the current vnode, we only need its parent from now on
|
|
|
|
put_vnode(vnode);
|
2002-07-28 22:41:07 +04:00
|
|
|
vnode = parentVnode;
|
2002-07-19 01:06:02 +04:00
|
|
|
|
|
|
|
if (status < B_OK)
|
2002-07-28 22:41:07 +04:00
|
|
|
goto out;
|
2002-07-19 01:06:02 +04:00
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
// ToDo: add an explicit check for loops in about 10 levels to do
|
|
|
|
// real loop detection
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
// don't go deeper as 'maxLevel' to prevent circular loops
|
2002-07-28 22:41:07 +04:00
|
|
|
if (maxLevel-- < 0) {
|
|
|
|
status = ELOOP;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-07-19 01:06:02 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
if (parentID == id) {
|
2002-07-19 01:06:02 +04:00
|
|
|
// we have reached the root level directory of this file system
|
2002-07-28 22:41:07 +04:00
|
|
|
// which means we have constructed the full path
|
2002-07-19 01:06:02 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (!FS_CALL(vnode, get_vnode_name)) {
|
2002-07-19 08:20:07 +04:00
|
|
|
// If we don't got the vnode's name yet, we have to search for it
|
|
|
|
// in the parent directory now
|
2002-09-24 03:24:12 +04:00
|
|
|
fs_cookie cookie;
|
2002-07-19 01:06:02 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
status = FS_CALL(vnode, open_dir)(vnode->mount->cookie, vnode->private_node, &cookie);
|
2002-07-19 01:06:02 +04:00
|
|
|
if (status >= B_OK) {
|
2002-07-19 08:20:07 +04:00
|
|
|
struct dirent *dirent = (struct dirent *)nameBuffer;
|
|
|
|
while (true) {
|
|
|
|
uint32 num = 1;
|
2002-09-24 20:17:22 +04:00
|
|
|
status = FS_CALL(vnode, read_dir)(vnode->mount->cookie, vnode->private_node,
|
|
|
|
cookie, dirent, sizeof(nameBuffer), &num);
|
2002-07-19 08:20:07 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (id == dirent->d_ino)
|
|
|
|
// found correct entry!
|
|
|
|
break;
|
|
|
|
}
|
2002-09-24 20:17:22 +04:00
|
|
|
FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-19 01:06:02 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
goto out;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-19 01:06:02 +04:00
|
|
|
|
|
|
|
// add the name infront of the current path
|
|
|
|
name[B_FILE_NAME_LENGTH - 1] = '\0';
|
|
|
|
length = strlen(name);
|
|
|
|
insert -= length;
|
|
|
|
if (insert <= 0) {
|
2002-07-28 22:41:07 +04:00
|
|
|
status = ENOBUFS;
|
|
|
|
goto out;
|
2002-07-19 01:06:02 +04:00
|
|
|
}
|
|
|
|
memcpy(path + insert, name, length);
|
2002-07-19 08:20:07 +04:00
|
|
|
path[--insert] = '/';
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
// add the mountpoint
|
|
|
|
length = strlen(vnode->mount->mount_point);
|
2003-09-04 08:01:25 +04:00
|
|
|
if (bufferSize - (sizeof(path) - insert) < (uint32)length + 1) {
|
2002-07-28 22:41:07 +04:00
|
|
|
status = ENOBUFS;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-07-19 01:06:02 +04:00
|
|
|
|
|
|
|
memcpy(buffer, vnode->mount->mount_point, length);
|
2002-07-19 08:20:07 +04:00
|
|
|
if (insert != sizeof(path))
|
|
|
|
memcpy(buffer + length, path + insert, sizeof(path) - insert);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
out:
|
|
|
|
put_vnode(vnode);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
/** Checks the length of every path component, and adds a '.'
|
|
|
|
* if the path ends in a slash.
|
|
|
|
* The given path buffer must be able to store at least one
|
|
|
|
* additional character.
|
|
|
|
*/
|
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
static status_t
|
|
|
|
check_path(char *to)
|
|
|
|
{
|
|
|
|
int32 length = 0;
|
|
|
|
|
|
|
|
// check length of every path component
|
|
|
|
|
|
|
|
while (*to) {
|
|
|
|
char *begin;
|
|
|
|
if (*to == '/')
|
|
|
|
to++, length++;
|
2002-08-05 09:37:17 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
begin = to;
|
|
|
|
while (*to != '/' && *to)
|
|
|
|
to++, length++;
|
|
|
|
|
|
|
|
if (to - begin > B_FILE_NAME_LENGTH)
|
|
|
|
return B_NAME_TOO_LONG;
|
|
|
|
}
|
2002-08-05 09:37:17 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
if (length == 0)
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
|
|
|
|
// complete path if there is a slash at the end
|
|
|
|
|
|
|
|
if (*(to - 1) == '/') {
|
|
|
|
if (length > SYS_MAX_PATH_LEN - 2)
|
|
|
|
return B_NAME_TOO_LONG;
|
|
|
|
|
|
|
|
to[0] = '.';
|
|
|
|
to[1] = '\0';
|
|
|
|
}
|
2002-08-05 09:37:17 +04:00
|
|
|
|
2002-07-19 01:06:02 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
static struct file_descriptor *
|
|
|
|
get_fd_and_vnode(int fd, struct vnode **_vnode, bool kernel)
|
|
|
|
{
|
|
|
|
struct file_descriptor *descriptor = get_fd(get_current_io_context(kernel), fd);
|
|
|
|
if (descriptor == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
if (descriptor->u.vnode == NULL) {
|
2002-09-25 06:18:20 +04:00
|
|
|
put_fd(descriptor);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-05-16 15:55:42 +04:00
|
|
|
// ToDo: when we can close a file descriptor at any point, investigate
|
|
|
|
// if this is still valid to do (accessing the vnode without ref_count
|
|
|
|
// or locking)
|
2002-09-26 07:50:14 +04:00
|
|
|
*_vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
return descriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct vnode *
|
|
|
|
get_vnode_from_fd(struct io_context *ioContext, int fd)
|
|
|
|
{
|
|
|
|
struct file_descriptor *descriptor;
|
|
|
|
struct vnode *vnode;
|
|
|
|
|
|
|
|
descriptor = get_fd(ioContext, fd);
|
|
|
|
if (descriptor == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
if (vnode != NULL)
|
|
|
|
inc_vnode_ref_count(vnode);
|
|
|
|
|
|
|
|
put_fd(descriptor);
|
|
|
|
return vnode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-10 00:20:28 +04:00
|
|
|
static status_t
|
|
|
|
fd_and_path_to_vnode(int fd, char *path, bool traverseLeafLink, struct vnode **_vnode, bool kernel)
|
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
|
|
|
|
if (fd != -1) {
|
|
|
|
struct file_descriptor *descriptor = get_fd_and_vnode(fd, &vnode, kernel);
|
|
|
|
if (descriptor == NULL)
|
2002-09-25 06:18:20 +04:00
|
|
|
return B_FILE_ERROR;
|
2002-08-10 00:20:28 +04:00
|
|
|
|
|
|
|
inc_vnode_ref_count(vnode);
|
|
|
|
put_fd(descriptor);
|
|
|
|
|
|
|
|
*_vnode = vnode;
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return path_to_vnode(path, traverseLeafLink, _vnode, kernel);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
static int
|
|
|
|
get_new_fd(int type, struct vnode *vnode, fs_cookie cookie, int openMode, bool kernel)
|
|
|
|
{
|
|
|
|
struct file_descriptor *descriptor;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
descriptor = alloc_fd();
|
|
|
|
if (!descriptor)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
descriptor->u.vnode = vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
descriptor->cookie = cookie;
|
|
|
|
switch (type) {
|
|
|
|
case FDTYPE_FILE:
|
2003-10-17 18:47:15 +04:00
|
|
|
descriptor->ops = &sFileOps;
|
2002-09-25 06:18:20 +04:00
|
|
|
break;
|
|
|
|
case FDTYPE_DIR:
|
2003-10-17 18:47:15 +04:00
|
|
|
descriptor->ops = &sDirectoryOps;
|
2002-09-25 06:18:20 +04:00
|
|
|
break;
|
|
|
|
case FDTYPE_ATTR:
|
2003-10-17 18:47:15 +04:00
|
|
|
descriptor->ops = &sAttributeOps;
|
2002-09-26 07:50:14 +04:00
|
|
|
break;
|
|
|
|
case FDTYPE_ATTR_DIR:
|
2003-10-17 18:47:15 +04:00
|
|
|
descriptor->ops = &sAttributeDirectoryOps;
|
2002-09-26 07:50:14 +04:00
|
|
|
break;
|
|
|
|
case FDTYPE_INDEX_DIR:
|
2003-10-17 18:47:15 +04:00
|
|
|
descriptor->ops = &sIndexDirectoryOps;
|
2002-09-25 06:18:20 +04:00
|
|
|
break;
|
|
|
|
default:
|
2002-09-26 07:50:14 +04:00
|
|
|
panic("get_new_fd() called with unknown type %d\n", type);
|
2002-09-25 06:18:20 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
descriptor->type = type;
|
|
|
|
descriptor->open_mode = openMode;
|
|
|
|
|
|
|
|
fd = new_fd(get_current_io_context(kernel), descriptor);
|
|
|
|
if (fd < 0) {
|
2002-10-30 02:07:06 +03:00
|
|
|
free(descriptor);
|
2002-09-25 06:18:20 +04:00
|
|
|
return B_NO_MORE_FDS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// #pragma mark -
|
2004-06-07 18:25:22 +04:00
|
|
|
// Public VFS API
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2004-06-07 18:25:22 +04:00
|
|
|
extern "C" status_t
|
|
|
|
new_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode)
|
2003-02-21 16:49:26 +03:00
|
|
|
{
|
2004-06-08 10:43:46 +04:00
|
|
|
FUNCTION(("new_vnode()\n"));
|
|
|
|
|
2003-02-21 16:49:26 +03:00
|
|
|
if (privateNode == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
2003-02-21 16:49:26 +03:00
|
|
|
|
|
|
|
// file system integrity check:
|
|
|
|
// test if the vnode already exists and bail out if this is the case!
|
|
|
|
|
|
|
|
// ToDo: the R5 implementation obviously checks for a different cookie
|
|
|
|
// and doesn't panic if they are equal
|
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
struct vnode *vnode = lookup_vnode(mountID, vnodeID);
|
2003-02-21 16:49:26 +03:00
|
|
|
if (vnode != NULL)
|
|
|
|
panic("vnode %ld:%Ld already exists (node = %p, vnode->node = %p)!", mountID, vnodeID, privateNode, vnode->private_node);
|
|
|
|
|
2004-02-02 18:09:21 +03:00
|
|
|
status_t status = create_new_vnode(&vnode, mountID, vnodeID);
|
|
|
|
if (status == B_OK)
|
|
|
|
vnode->private_node = privateNode;
|
2003-02-21 16:49:26 +03:00
|
|
|
|
2004-06-08 10:43:46 +04:00
|
|
|
PRINT(("returns: %s\n", strerror(status)));
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2003-02-21 16:49:26 +03:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-07 18:25:22 +04:00
|
|
|
extern "C" status_t
|
|
|
|
get_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode *_fsNode)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct vnode *vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
int status = get_vnode(mountID, vnodeID, &vnode, true);
|
2002-07-28 22:41:07 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
*_fsNode = vnode->private_node;
|
2002-07-28 22:41:07 +04:00
|
|
|
return B_OK;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2004-06-07 18:25:22 +04:00
|
|
|
extern "C" status_t
|
|
|
|
put_vnode(mount_id mountID, vnode_id vnodeID)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
2002-09-25 18:10:50 +04:00
|
|
|
vnode = lookup_vnode(mountID, vnodeID);
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (vnode)
|
|
|
|
dec_vnode_ref_count(vnode, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
return B_OK;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-07 18:25:22 +04:00
|
|
|
extern "C" status_t
|
|
|
|
remove_vnode(mount_id mountID, vnode_id vnodeID)
|
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
|
|
|
|
mutex_lock(&sVnodeMutex);
|
|
|
|
|
|
|
|
vnode = lookup_vnode(mountID, vnodeID);
|
|
|
|
if (vnode)
|
|
|
|
vnode->delete_me = true;
|
|
|
|
|
|
|
|
mutex_unlock(&sVnodeMutex);
|
2004-06-07 21:25:55 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" status_t
|
|
|
|
unremove_vnode(mount_id mountID, vnode_id vnodeID)
|
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
|
|
|
|
mutex_lock(&sVnodeMutex);
|
|
|
|
|
|
|
|
vnode = lookup_vnode(mountID, vnodeID);
|
|
|
|
if (vnode)
|
|
|
|
vnode->delete_me = false;
|
|
|
|
|
|
|
|
mutex_unlock(&sVnodeMutex);
|
|
|
|
return B_OK;
|
2004-06-07 18:25:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
// Functions the VFS exports for other parts of the kernel
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
void
|
|
|
|
vfs_vnode_acquire_ref(void *vnode)
|
|
|
|
{
|
|
|
|
FUNCTION(("vfs_vnode_acquire_ref: vnode 0x%p\n", vnode));
|
|
|
|
inc_vnode_ref_count((struct vnode *)vnode);
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
void
|
|
|
|
vfs_vnode_release_ref(void *vnode)
|
|
|
|
{
|
|
|
|
FUNCTION(("vfs_vnode_release_ref: vnode 0x%p\n", vnode));
|
|
|
|
dec_vnode_ref_count((struct vnode *)vnode, false);
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
void *
|
|
|
|
vfs_get_cache_ptr(void *vnode)
|
|
|
|
{
|
|
|
|
return ((struct vnode *)vnode)->cache;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-07-20 04:16:12 +04:00
|
|
|
vfs_set_cache_ptr(void *vnode, void *cache)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2003-08-20 06:35:24 +04:00
|
|
|
if (atomic_test_and_set((int32 *)&(((struct vnode *)vnode)->cache), (int32)cache, 0) == 0)
|
2002-07-20 04:16:12 +04:00
|
|
|
return 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
int
|
|
|
|
vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode)
|
|
|
|
{
|
|
|
|
struct io_context *ioctx;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
ioctx = get_current_io_context(kernel);
|
|
|
|
*vnode = get_vnode_from_fd(ioctx, fd);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (*vnode == NULL)
|
2003-02-21 16:49:26 +03:00
|
|
|
return B_FILE_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return B_NO_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-23 07:31:51 +03:00
|
|
|
status_t
|
2002-08-03 06:03:27 +04:00
|
|
|
vfs_get_vnode_from_path(const char *path, bool kernel, void **_vnode)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-03 06:03:27 +04:00
|
|
|
struct vnode *vnode;
|
2004-02-23 07:31:51 +03:00
|
|
|
status_t status;
|
|
|
|
char buffer[SYS_MAX_PATH_LEN + 1];
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
PRINT(("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", path, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-23 07:31:51 +03:00
|
|
|
strlcpy(buffer, path, sizeof(buffer));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-23 07:31:51 +03:00
|
|
|
status = path_to_vnode(buffer, true, &vnode, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-23 07:31:51 +03:00
|
|
|
*_vnode = vnode;
|
|
|
|
return B_OK;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2003-09-08 08:02:34 +04:00
|
|
|
status_t
|
|
|
|
vfs_get_module_path(const char *basePath, const char *moduleName, char *pathBuffer,
|
|
|
|
size_t bufferSize)
|
|
|
|
{
|
|
|
|
struct vnode *dir, *file;
|
|
|
|
status_t status;
|
|
|
|
size_t length;
|
|
|
|
char *path;
|
|
|
|
|
2004-04-28 15:20:19 +04:00
|
|
|
if (bufferSize == 0 || strlcpy(pathBuffer, basePath, bufferSize - 1) > bufferSize - 1)
|
2003-09-08 08:02:34 +04:00
|
|
|
return B_BUFFER_OVERFLOW;
|
|
|
|
|
|
|
|
status = path_to_vnode(pathBuffer, true, &dir, true);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
length = strlen(pathBuffer);
|
|
|
|
if (pathBuffer[length - 1] != '/') {
|
|
|
|
pathBuffer[length] = '/';
|
|
|
|
length++;
|
|
|
|
}
|
|
|
|
|
|
|
|
path = pathBuffer + length;
|
|
|
|
bufferSize -= length;
|
|
|
|
|
|
|
|
while (moduleName) {
|
|
|
|
int type;
|
|
|
|
|
|
|
|
char *nextPath = strchr(moduleName, '/');
|
|
|
|
if (nextPath == NULL)
|
|
|
|
length = strlen(moduleName);
|
|
|
|
else
|
|
|
|
length = nextPath - moduleName;
|
|
|
|
|
2004-04-28 15:20:19 +04:00
|
|
|
if (length + 1 >= bufferSize) {
|
2003-09-08 08:02:34 +04:00
|
|
|
status = B_BUFFER_OVERFLOW;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(path, moduleName, length);
|
|
|
|
path[length] = '\0';
|
|
|
|
moduleName = nextPath;
|
|
|
|
|
|
|
|
status = vnode_path_to_vnode(dir, path, true, 0, &file, &type);
|
|
|
|
if (status < B_OK)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
put_vnode(dir);
|
|
|
|
|
|
|
|
if (S_ISDIR(type)) {
|
|
|
|
// goto the next directory
|
|
|
|
path[length] = '/';
|
|
|
|
path[length + 1] = '\0';
|
|
|
|
path += length + 1;
|
|
|
|
|
|
|
|
dir = file;
|
|
|
|
} else if (S_ISREG(type)) {
|
|
|
|
// it's a file so it should be what we've searched for
|
|
|
|
put_vnode(file);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
} else {
|
2004-06-08 10:43:46 +04:00
|
|
|
PRINT(("vfs_get_module_path(): something is strange here: %d...\n", type));
|
2003-09-08 08:02:34 +04:00
|
|
|
status = B_ERROR;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we got here, the moduleName just pointed to a directory, not to
|
|
|
|
// a real module - what should we do in this case?
|
|
|
|
status = B_ENTRY_NOT_FOUND;
|
|
|
|
|
|
|
|
err:
|
|
|
|
put_vnode(dir);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
int
|
2003-10-17 18:47:15 +04:00
|
|
|
vfs_put_vnode_ptr(void *_vnode)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
struct vnode *vnode = (struct vnode *)_vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
put_vnode(vnode);
|
2002-07-20 04:16:12 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
ssize_t
|
2003-10-17 18:47:15 +04:00
|
|
|
vfs_can_page(void *_vnode)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
struct vnode *vnode = (struct vnode *)_vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("vfs_canpage: vnode 0x%p\n", vnode));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, can_page))
|
|
|
|
return FS_CALL(vnode, can_page)(vnode->mount->cookie, vnode->private_node);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
ssize_t
|
2003-10-17 18:47:15 +04:00
|
|
|
vfs_read_page(void *_vnode, iovecs *vecs, off_t pos)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
struct vnode *vnode = (struct vnode *)_vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("vfs_readpage: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 04:42:17 +04:00
|
|
|
return FS_CALL(vnode, read_pages)(vnode->mount->cookie, vnode->private_node, vecs, pos);
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
ssize_t
|
2003-10-17 18:47:15 +04:00
|
|
|
vfs_write_page(void *_vnode, iovecs *vecs, off_t pos)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2003-10-17 18:47:15 +04:00
|
|
|
struct vnode *vnode = (struct vnode *)_vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("vfs_writepage: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 04:42:17 +04:00
|
|
|
return FS_CALL(vnode, write_pages)(vnode->mount->cookie, vnode->private_node, vecs, pos);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
/** Sets up a new io_control structure, and inherits the properties
|
|
|
|
* of the parent io_control if it is given.
|
|
|
|
*/
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
void *
|
|
|
|
vfs_new_io_context(void *_parentContext)
|
|
|
|
{
|
|
|
|
size_t table_size;
|
|
|
|
struct io_context *context;
|
|
|
|
struct io_context *parentContext;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
context = (io_context *)malloc(sizeof(struct io_context));
|
2002-07-20 04:16:12 +04:00
|
|
|
if (context == NULL)
|
|
|
|
return NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
memset(context, 0, sizeof(struct io_context));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
parentContext = (struct io_context *)_parentContext;
|
|
|
|
if (parentContext)
|
|
|
|
table_size = parentContext->table_size;
|
|
|
|
else
|
|
|
|
table_size = DEFAULT_FD_TABLE_SIZE;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
context->fds = (file_descriptor **)malloc(sizeof(struct file_descriptor *) * table_size);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (context->fds == NULL) {
|
2002-10-30 02:07:06 +03:00
|
|
|
free(context);
|
2002-07-20 04:16:12 +04:00
|
|
|
return NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
memset(context->fds, 0, sizeof(struct file_descriptor *) * table_size);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (mutex_init(&context->io_mutex, "I/O context") < 0) {
|
2002-10-30 02:07:06 +03:00
|
|
|
free(context->fds);
|
|
|
|
free(context);
|
2002-07-20 04:16:12 +04:00
|
|
|
return NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-10-07 19:31:40 +04:00
|
|
|
// Copy all parent files which don't have the O_CLOEXEC flag set
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (parentContext) {
|
|
|
|
size_t i;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_lock(&parentContext->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
context->cwd = parentContext->cwd;
|
|
|
|
if (context->cwd)
|
|
|
|
inc_vnode_ref_count(context->cwd);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
for (i = 0; i < table_size; i++) {
|
2002-10-07 19:31:40 +04:00
|
|
|
if (parentContext->fds[i] && (parentContext->fds[i]->open_mode & O_CLOEXEC) == 0) {
|
2002-07-20 04:16:12 +04:00
|
|
|
context->fds[i] = parentContext->fds[i];
|
|
|
|
atomic_add(&context->fds[i]->ref_count, 1);
|
|
|
|
}
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_unlock(&parentContext->io_mutex);
|
|
|
|
} else {
|
2003-10-17 18:47:15 +04:00
|
|
|
context->cwd = sRoot;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (context->cwd)
|
|
|
|
inc_vnode_ref_count(context->cwd);
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
context->table_size = table_size;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-01-18 17:13:44 +03:00
|
|
|
list_init(&context->node_monitors);
|
|
|
|
context->max_monitors = MAX_NODE_MONITORS;
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return context;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
int
|
|
|
|
vfs_free_io_context(void *_ioContext)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct io_context *context = (struct io_context *)_ioContext;
|
2003-09-04 08:01:25 +04:00
|
|
|
uint32 i;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (context->cwd)
|
|
|
|
dec_vnode_ref_count(context->cwd, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_lock(&context->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
for (i = 0; i < context->table_size; i++) {
|
|
|
|
if (context->fds[i])
|
|
|
|
put_fd(context->fds[i]);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_unlock(&context->io_mutex);
|
|
|
|
|
|
|
|
mutex_destroy(&context->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-01-18 17:13:44 +03:00
|
|
|
remove_node_monitors(context);
|
2002-10-30 02:07:06 +03:00
|
|
|
free(context->fds);
|
|
|
|
free(context);
|
2003-01-18 17:13:44 +03:00
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-20 04:16:12 +04:00
|
|
|
vfs_resize_fd_table(struct io_context *context, const int newSize)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
void *fds;
|
|
|
|
int status = B_OK;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (newSize <= 0 || newSize > MAX_FD_TABLE_SIZE)
|
|
|
|
return EINVAL;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_lock(&context->io_mutex);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
if ((size_t)newSize < context->table_size) {
|
2002-07-20 04:16:12 +04:00
|
|
|
// shrink the fd table
|
|
|
|
int i;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// Make sure none of the fds being dropped are in use
|
|
|
|
for(i = context->table_size; i-- > newSize;) {
|
|
|
|
if (context->fds[i]) {
|
|
|
|
status = EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-10-30 02:07:06 +03:00
|
|
|
fds = malloc(sizeof(struct file_descriptor *) * newSize);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (fds == NULL) {
|
|
|
|
status = ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
memcpy(fds, context->fds, sizeof(struct file_descriptor *) * newSize);
|
|
|
|
} else {
|
|
|
|
// enlarge the fd table
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-30 02:07:06 +03:00
|
|
|
fds = malloc(sizeof(struct file_descriptor *) * newSize);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (fds == NULL) {
|
|
|
|
status = ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// copy the fd array, and zero the additional slots
|
|
|
|
memcpy(fds, context->fds, sizeof(void *) * context->table_size);
|
|
|
|
memset((char *)fds + (sizeof(void *) * context->table_size), 0,
|
|
|
|
sizeof(void *) * (newSize - context->table_size));
|
2002-07-14 09:13:20 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-30 02:07:06 +03:00
|
|
|
free(context->fds);
|
2003-10-17 18:47:15 +04:00
|
|
|
context->fds = (file_descriptor **)fds;
|
2002-07-20 04:16:12 +04:00
|
|
|
context->table_size = newSize;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
out:
|
|
|
|
mutex_unlock(&context->io_mutex);
|
2002-07-14 09:13:20 +04:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
int
|
|
|
|
vfs_getrlimit(int resource, struct rlimit * rlp)
|
2002-07-14 09:13:20 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
if (!rlp)
|
|
|
|
return -1;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
switch (resource) {
|
|
|
|
case RLIMIT_NOFILE:
|
|
|
|
{
|
|
|
|
struct io_context *ioctx = get_current_io_context(false);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_lock(&ioctx->io_mutex);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
rlp->rlim_cur = ioctx->table_size;
|
|
|
|
rlp->rlim_max = MAX_FD_TABLE_SIZE;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_unlock(&ioctx->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
int
|
|
|
|
vfs_setrlimit(int resource, const struct rlimit * rlp)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
if (!rlp)
|
|
|
|
return -1;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
switch (resource) {
|
|
|
|
case RLIMIT_NOFILE:
|
|
|
|
return vfs_resize_fd_table(get_current_io_context(false), rlp->rlim_cur);
|
2002-07-17 11:55:51 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
2002-07-17 11:55:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-06 05:25:36 +04:00
|
|
|
status_t
|
|
|
|
vfs_bootstrap_file_systems(void)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2004-04-27 01:46:01 +04:00
|
|
|
status_t status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// bootstrap the root filesystem
|
2004-06-15 19:35:10 +04:00
|
|
|
status = _kern_mount("/", NULL, "rootfs", NULL);
|
2004-04-27 01:46:01 +04:00
|
|
|
if (status < B_OK)
|
2002-07-20 04:16:12 +04:00
|
|
|
panic("error mounting rootfs!\n");
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_setcwd(-1, "/");
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// bootstrap the devfs
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_create_dir("/dev", 0755);
|
|
|
|
status = _kern_mount("/dev", NULL, "devfs", NULL);
|
2004-04-27 01:46:01 +04:00
|
|
|
if (status < B_OK)
|
2002-07-20 04:16:12 +04:00
|
|
|
panic("error mounting devfs\n");
|
|
|
|
|
2003-06-27 07:46:27 +04:00
|
|
|
// bootstrap the pipefs
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_create_dir("/pipe", 0755);
|
|
|
|
status = _kern_mount("/pipe", NULL, "pipefs", NULL);
|
2004-04-27 01:46:01 +04:00
|
|
|
if (status < B_OK)
|
2003-06-27 07:46:27 +04:00
|
|
|
panic("error mounting pipefs\n");
|
|
|
|
|
2004-06-07 21:25:55 +04:00
|
|
|
// bootstrap the bootfs (if possible)
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_create_dir("/boot", 0755);
|
|
|
|
status = _kern_mount("/boot", NULL, "bootfs", NULL);
|
2004-06-07 21:25:55 +04:00
|
|
|
if (status < B_OK) {
|
|
|
|
// this is no fatal exception at this point, as we may mount
|
|
|
|
// a real on disk file system later
|
|
|
|
dprintf("error mounting bootfs\n");
|
|
|
|
}
|
|
|
|
|
2004-04-27 01:46:01 +04:00
|
|
|
// create some standard links on the rootfs
|
|
|
|
|
|
|
|
for (int32 i = 0; sPredefinedLinks[i].path != NULL; i++) {
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_create_symlink(sPredefinedLinks[i].path, sPredefinedLinks[i].target, 0);
|
2004-04-27 01:46:01 +04:00
|
|
|
// we don't care if it will succeed or not
|
|
|
|
}
|
|
|
|
|
2004-05-06 05:25:36 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
vfs_mount_boot_file_system()
|
|
|
|
{
|
2004-06-15 19:35:10 +04:00
|
|
|
// make the boot partition (and probably others) available
|
|
|
|
KDiskDeviceManager::CreateDefault();
|
|
|
|
|
2004-06-08 10:43:46 +04:00
|
|
|
file_system_info *bootfs;
|
|
|
|
if ((bootfs = get_file_system("bootfs")) == NULL) {
|
|
|
|
// no bootfs there, yet
|
|
|
|
|
|
|
|
// ToDo: do this for real!
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t status = _kern_mount("/boot", "/dev/disk/scsi/0/0/0/raw", "bfs", NULL);
|
2004-06-08 10:43:46 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
panic("could not get boot device: %s!\n", strerror(status));
|
|
|
|
} else
|
|
|
|
put_file_system(bootfs);
|
2004-05-06 05:25:36 +04:00
|
|
|
|
2004-06-07 21:25:55 +04:00
|
|
|
dev_t bootDevice = sNextMountID - 1;
|
2004-05-06 05:25:36 +04:00
|
|
|
|
2004-04-27 01:46:01 +04:00
|
|
|
// create link for the name of the boot device
|
|
|
|
|
|
|
|
fs_info info;
|
|
|
|
if (_kern_read_fs_info(bootDevice, &info) == B_OK) {
|
|
|
|
char path[B_FILE_NAME_LENGTH + 1];
|
|
|
|
snprintf(path, sizeof(path), "/%s", info.volume_name);
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_create_symlink(path, "/boot", 0);
|
2004-04-27 01:46:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-06 05:25:36 +04:00
|
|
|
status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
vfs_init(kernel_args *ka)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
|
|
|
struct vnode *v;
|
2003-10-17 18:47:15 +04:00
|
|
|
sVnodeTable = hash_init(VNODE_HASH_TABLE_SIZE, (addr)&v->next - (addr)v,
|
2002-07-20 04:16:12 +04:00
|
|
|
&vnode_compare, &vnode_hash);
|
2003-10-17 18:47:15 +04:00
|
|
|
if (sVnodeTable == NULL)
|
2002-07-20 04:16:12 +04:00
|
|
|
panic("vfs_init: error creating vnode hash table\n");
|
|
|
|
}
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
2003-10-17 18:47:15 +04:00
|
|
|
sMountsTable = hash_init(MOUNTS_HASH_TABLE_SIZE, (addr)&mount->next - (addr)mount,
|
2002-07-20 04:16:12 +04:00
|
|
|
&mount_compare, &mount_hash);
|
2003-10-17 18:47:15 +04:00
|
|
|
if (sMountsTable == NULL)
|
2002-07-20 04:16:12 +04:00
|
|
|
panic("vfs_init: error creating mounts hash table\n");
|
|
|
|
}
|
2003-01-18 17:13:44 +03:00
|
|
|
|
|
|
|
node_monitor_init();
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
sRoot = NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (mutex_init(&sFileSystemsMutex, "vfs_lock") < 0)
|
2002-09-25 18:10:50 +04:00
|
|
|
panic("vfs_init: error allocating file systems lock\n");
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (mutex_init(&sMountOpMutex, "vfs_mount_op_lock") < 0)
|
2002-09-25 18:10:50 +04:00
|
|
|
panic("vfs_init: error allocating mount op lock\n");
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (mutex_init(&sMountMutex, "vfs_mount_lock") < 0)
|
2002-09-25 18:10:50 +04:00
|
|
|
panic("vfs_init: error allocating mount lock\n");
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (mutex_init(&sVnodeMutex, "vfs_vnode_lock") < 0)
|
2002-09-25 18:10:50 +04:00
|
|
|
panic("vfs_init: error allocating vnode lock\n");
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
return 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// #pragma mark -
|
|
|
|
// The filetype-dependent implementations (fd_ops + open/create/rename/remove, ...)
|
|
|
|
|
|
|
|
|
|
|
|
/** Calls fs_open() on the given vnode and returns a new
|
|
|
|
* file descriptor for it
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
2002-09-25 06:18:20 +04:00
|
|
|
create_vnode(struct vnode *directory, const char *name, int openMode, int perms, bool kernel)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
2002-09-24 03:24:12 +04:00
|
|
|
fs_cookie cookie;
|
2002-07-20 04:16:12 +04:00
|
|
|
vnode_id newID;
|
|
|
|
int status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(directory, create) == NULL)
|
2002-07-20 04:16:12 +04:00
|
|
|
return EROFS;
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
status = FS_CALL(directory, create)(directory->mount->cookie, directory->private_node, name, openMode, perms, &cookie, &newID);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
|
|
|
vnode = lookup_vnode(directory->device, newID);
|
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
if (vnode == NULL) {
|
|
|
|
dprintf("vfs: fs_create() returned success but there is no vnode!");
|
|
|
|
return EINVAL;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
if ((status = get_new_fd(FDTYPE_FILE, vnode, cookie, openMode, kernel)) >= 0)
|
2002-07-20 04:16:12 +04:00
|
|
|
return status;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
// something went wrong, clean up
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
|
2002-07-20 04:16:12 +04:00
|
|
|
put_vnode(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
FS_CALL(directory, unlink)(directory->mount->cookie, directory->private_node, name);
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
return status;
|
2002-07-14 09:13:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
/** Calls fs_open() on the given vnode and returns a new
|
|
|
|
* file descriptor for it
|
|
|
|
*/
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
static int
|
2002-07-20 04:16:12 +04:00
|
|
|
open_vnode(struct vnode *vnode, int omode, bool kernel)
|
2002-07-14 09:13:20 +04:00
|
|
|
{
|
2002-09-24 03:24:12 +04:00
|
|
|
fs_cookie cookie;
|
2002-07-14 09:13:20 +04:00
|
|
|
int status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
status = FS_CALL(vnode, open)(vnode->mount->cookie, vnode->private_node, omode, &cookie);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
status = get_new_fd(FDTYPE_FILE, vnode, cookie, omode, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < 0) {
|
2002-09-24 20:17:22 +04:00
|
|
|
FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
/** Calls fs open_dir() on the given vnode and returns a new
|
2002-07-20 04:16:12 +04:00
|
|
|
* file descriptor for it
|
|
|
|
*/
|
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
static int
|
2002-07-20 04:16:12 +04:00
|
|
|
open_dir_vnode(struct vnode *vnode, bool kernel)
|
2002-07-14 09:13:20 +04:00
|
|
|
{
|
2002-09-24 03:24:12 +04:00
|
|
|
fs_cookie cookie;
|
2002-09-26 07:50:14 +04:00
|
|
|
int status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
status = FS_CALL(vnode, open_dir)(vnode->mount->cookie, vnode->private_node, &cookie);
|
2003-08-18 07:21:26 +04:00
|
|
|
if (status < B_OK)
|
2002-07-14 09:13:20 +04:00
|
|
|
return status;
|
|
|
|
|
|
|
|
// file is opened, create a fd
|
2002-09-26 07:50:14 +04:00
|
|
|
status = get_new_fd(FDTYPE_DIR, vnode, cookie, 0, kernel);
|
|
|
|
if (status >= 0)
|
|
|
|
return status;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
FS_CALL(vnode, free_dir_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2002-07-14 09:13:20 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
/** Calls fs open_attr_dir() on the given vnode and returns a new
|
|
|
|
* file descriptor for it.
|
|
|
|
* Used by attr_dir_open(), and attr_dir_open_fd().
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
open_attr_dir_vnode(struct vnode *vnode, bool kernel)
|
|
|
|
{
|
|
|
|
fs_cookie cookie;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
status = FS_CALL(vnode, open_attr_dir)(vnode->mount->cookie, vnode->private_node, &cookie);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
// file is opened, create a fd
|
|
|
|
status = get_new_fd(FDTYPE_ATTR_DIR, vnode, cookie, 0, kernel);
|
|
|
|
if (status >= 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
FS_CALL(vnode, close_attr_dir)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
FS_CALL(vnode, free_attr_dir_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static int
|
2002-09-25 18:10:50 +04:00
|
|
|
file_create_entry_ref(mount_id mountID, vnode_id directoryID, const char *name, int openMode, int perms, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2003-09-04 08:01:25 +04:00
|
|
|
struct vnode *directory;
|
2002-07-20 04:16:12 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
FUNCTION(("file_create_entry_ref: name = '%s', omode %x, perms %d, kernel %d\n", name, openMode, perms, kernel));
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
// get directory to put the new file in
|
2002-09-25 18:10:50 +04:00
|
|
|
status = get_vnode(mountID, directoryID, &directory, false);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
status = create_vnode(directory, name, openMode, perms, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
put_vnode(directory);
|
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static int
|
2002-09-25 06:18:20 +04:00
|
|
|
file_create(char *path, int openMode, int perms, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-09-25 16:13:09 +04:00
|
|
|
char name[B_FILE_NAME_LENGTH];
|
2003-09-04 08:01:25 +04:00
|
|
|
struct vnode *directory;
|
2002-07-20 04:16:12 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
FUNCTION(("file_create: path '%s', omode %x, perms %d, kernel %d\n", path, openMode, perms, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// get directory to put the new file in
|
2002-09-25 16:13:09 +04:00
|
|
|
status = path_to_dir_vnode(path, &directory, name, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
status = create_vnode(directory, name, openMode, perms, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
put_vnode(directory);
|
2002-07-20 04:16:12 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-09-25 18:10:50 +04:00
|
|
|
file_open_entry_ref(mount_id mountID, vnode_id directoryID, const char *name, int openMode, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
if (name == NULL || *name == '\0')
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("file_open_entry_ref()\n"));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// get the vnode matching the entry_ref
|
2002-09-25 18:10:50 +04:00
|
|
|
status = entry_ref_to_vnode(mountID, directoryID, name, &vnode);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
status = open_vnode(vnode, openMode, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2002-07-20 04:16:12 +04:00
|
|
|
file_open(char *path, int omode, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct vnode *vnode = NULL;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("file_open: entry. path = '%s', omode %d, kernel %d\n", path, omode, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// get the vnode matching the path
|
2002-08-05 09:37:17 +04:00
|
|
|
status = path_to_vnode(path, (omode & O_NOTRAVERSE) == 0, &vnode, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
2002-07-19 08:20:07 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
status = open_vnode(vnode, omode, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
file_close(struct file_descriptor *descriptor)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
FUNCTION(("file_close(descriptor = %p)\n", descriptor));
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, close))
|
2002-09-25 06:18:20 +04:00
|
|
|
return FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
static void
|
|
|
|
file_free_fd(struct file_descriptor *descriptor)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
|
|
|
if (vnode != NULL) {
|
|
|
|
FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
put_vnode(vnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-16 14:32:26 +04:00
|
|
|
static status_t
|
2002-08-09 21:03:03 +04:00
|
|
|
file_read(struct file_descriptor *descriptor, off_t pos, void *buffer, size_t *length)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-05 09:37:17 +04:00
|
|
|
FUNCTION(("file_read: buf %p, pos %Ld, len %p = %ld\n", buffer, pos, length, *length));
|
2002-09-24 20:17:22 +04:00
|
|
|
return FS_CALL(vnode, read)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-16 14:32:26 +04:00
|
|
|
static status_t
|
2002-08-09 21:03:03 +04:00
|
|
|
file_write(struct file_descriptor *descriptor, off_t pos, const void *buffer, size_t *length)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-05 09:37:17 +04:00
|
|
|
FUNCTION(("file_write: buf %p, pos %Ld, len %p\n", buffer, pos, length));
|
2002-09-24 20:17:22 +04:00
|
|
|
return FS_CALL(vnode, write)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length);
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static off_t
|
|
|
|
file_seek(struct file_descriptor *descriptor, off_t pos, int seekType)
|
|
|
|
{
|
2002-10-08 04:42:17 +04:00
|
|
|
off_t offset;
|
|
|
|
|
|
|
|
switch (seekType) {
|
|
|
|
case SEEK_SET:
|
|
|
|
offset = 0;
|
|
|
|
break;
|
|
|
|
case SEEK_CUR:
|
|
|
|
offset = descriptor->pos;
|
|
|
|
break;
|
|
|
|
case SEEK_END:
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
struct stat stat;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, read_stat) == NULL)
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
|
|
|
|
status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
offset = stat.st_size;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// assumes off_t is 64 bits wide
|
|
|
|
if (offset > 0 && LONGLONG_MAX - offset < pos)
|
|
|
|
return EOVERFLOW;
|
|
|
|
|
|
|
|
pos += offset;
|
|
|
|
if (pos < 0)
|
|
|
|
return B_BAD_VALUE;
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2002-10-08 04:42:17 +04:00
|
|
|
return descriptor->pos = pos;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
static status_t
|
2002-09-25 18:10:50 +04:00
|
|
|
dir_create_entry_ref(mount_id mountID, vnode_id parentID, const char *name, int perms, bool kernel)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
vnode_id newID;
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t status;
|
2002-07-23 18:10:12 +04:00
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
if (name == NULL || *name == '\0')
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
FUNCTION(("dir_create_entry_ref(dev = %ld, ino = %Ld, name = '%s', perms = %d)\n", mountID, parentID, name, perms));
|
2002-07-23 18:10:12 +04:00
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
status = get_vnode(mountID, parentID, &vnode, kernel);
|
2002-07-23 18:10:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, create_dir))
|
|
|
|
status = FS_CALL(vnode, create_dir)(vnode->mount->cookie, vnode->private_node, name, perms, &newID);
|
2002-07-23 18:10:12 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
|
|
|
put_vnode(vnode);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
dir_create(char *path, int perms, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
char filename[SYS_MAX_NAME_LEN];
|
2002-07-14 09:13:20 +04:00
|
|
|
struct vnode *vnode;
|
2002-07-23 18:10:12 +04:00
|
|
|
vnode_id newID;
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("dir_create: path '%s', perms %d, kernel %d\n", path, perms, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
status = path_to_dir_vnode(path, &vnode, filename, kernel);
|
2002-07-14 09:13:20 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, create_dir))
|
|
|
|
status = FS_CALL(vnode, create_dir)(vnode->mount->cookie, vnode->private_node, filename, perms, &newID);
|
2002-07-14 09:13:20 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
put_vnode(vnode);
|
2002-07-14 09:13:20 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static int
|
2002-09-25 18:10:50 +04:00
|
|
|
dir_open_node_ref(mount_id mountID, vnode_id directoryID, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("dir_open_entry_ref()\n"));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// get the vnode matching the node_ref
|
2002-09-25 18:10:50 +04:00
|
|
|
status = get_vnode(mountID, directoryID, &vnode, false);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
status = open_dir_vnode(vnode, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static int
|
2002-09-25 18:10:50 +04:00
|
|
|
dir_open_entry_ref(mount_id mountID, vnode_id parentID, const char *name, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("dir_open_entry_ref()\n"));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
if (name == NULL || *name == '\0')
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// get the vnode matching the entry_ref
|
2002-09-25 18:10:50 +04:00
|
|
|
status = entry_ref_to_vnode(mountID, parentID, name, &vnode);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
status = open_dir_vnode(vnode, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
put_vnode(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static int
|
|
|
|
dir_open(char *path, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("dir_open: path = '%s', kernel %d\n", path, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
status = path_to_vnode(path, true, &vnode, kernel);
|
2003-08-18 07:21:26 +04:00
|
|
|
if (status < B_OK)
|
2002-07-20 04:16:12 +04:00
|
|
|
return status;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2003-08-18 07:21:26 +04:00
|
|
|
status = open_dir_vnode(vnode, kernel);
|
|
|
|
if (status < B_OK)
|
2002-07-20 04:16:12 +04:00
|
|
|
put_vnode(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-25 06:18:20 +04:00
|
|
|
dir_close(struct file_descriptor *descriptor)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
|
|
|
FUNCTION(("dir_close(descriptor = %p)\n", descriptor));
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, close_dir))
|
|
|
|
return FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
dir_free_fd(struct file_descriptor *descriptor)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
|
|
|
if (vnode != NULL) {
|
|
|
|
FS_CALL(vnode, free_dir_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
put_vnode(vnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static status_t
|
|
|
|
dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, read_dir))
|
|
|
|
return FS_CALL(vnode, read_dir)(vnode->mount->cookie,vnode->private_node,descriptor->cookie,buffer,bufferSize,_count);
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
static status_t
|
|
|
|
dir_rewind(struct file_descriptor *descriptor)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, rewind_dir))
|
|
|
|
return FS_CALL(vnode, rewind_dir)(vnode->mount->cookie,vnode->private_node,descriptor->cookie);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return EOPNOTSUPP;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
static status_t
|
|
|
|
dir_remove(char *path, bool kernel)
|
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
struct vnode *directory;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
status = path_to_dir_vnode(path, &directory, name, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(directory, remove_dir))
|
|
|
|
status = FS_CALL(directory, remove_dir)(directory->mount->cookie, directory->private_node, name);
|
2002-08-14 00:39:25 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
|
|
|
put_vnode(directory);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
common_ioctl(struct file_descriptor *descriptor, ulong op, void *buffer, size_t length)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, ioctl))
|
|
|
|
return FS_CALL(vnode, ioctl)(vnode->mount->cookie,vnode->private_node,descriptor->cookie,op,buffer,length);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
common_sync(int fd, bool kernel)
|
|
|
|
{
|
|
|
|
struct file_descriptor *descriptor;
|
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("vfs_fsync: entry. fd %d kernel %d\n", fd, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-10 00:20:28 +04:00
|
|
|
descriptor = get_fd_and_vnode(fd, &vnode, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (descriptor == NULL)
|
2003-02-21 16:49:26 +03:00
|
|
|
return B_FILE_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, fsync) != NULL)
|
|
|
|
status = FS_CALL(vnode, fsync)(vnode->mount->cookie, vnode->private_node);
|
2002-07-20 04:16:12 +04:00
|
|
|
else
|
|
|
|
status = EOPNOTSUPP;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
put_fd(descriptor);
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
static ssize_t
|
2002-08-03 06:03:27 +04:00
|
|
|
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;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, read_link) != NULL)
|
|
|
|
status = FS_CALL(vnode, read_link)(vnode->mount->cookie, vnode->private_node, buffer, bufferSize);
|
2002-08-03 06:03:27 +04:00
|
|
|
else
|
|
|
|
status = B_BAD_VALUE;
|
|
|
|
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-08-05 09:37:17 +04:00
|
|
|
common_write_link(char *path, char *toPath, bool kernel)
|
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
status = path_to_vnode(path, false, &vnode, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, write_link) != NULL)
|
|
|
|
status = FS_CALL(vnode, write_link)(vnode->mount->cookie, vnode->private_node, toPath);
|
2002-08-05 09:37:17 +04:00
|
|
|
else
|
|
|
|
status = EOPNOTSUPP;
|
|
|
|
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
static status_t
|
2002-08-05 09:37:17 +04:00
|
|
|
common_create_symlink(char *path, const char *toPath, int mode, bool kernel)
|
2002-07-28 22:41:07 +04:00
|
|
|
{
|
|
|
|
// path validity checks have to be in the calling function!
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
FUNCTION(("common_create_symlink(path = %s, toPath = %s, mode = %d, kernel = %d)\n", path, toPath, mode, kernel));
|
2002-08-03 06:03:27 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
status = path_to_dir_vnode(path, &vnode, name, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, create_symlink) != NULL)
|
|
|
|
status = FS_CALL(vnode, create_symlink)(vnode->mount->cookie, vnode->private_node, name, toPath, mode);
|
2002-07-28 22:41:07 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
static status_t
|
|
|
|
common_create_link(char *path, char *toPath, bool kernel)
|
|
|
|
{
|
|
|
|
// path validity checks have to be in the calling function!
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
struct vnode *directory, *vnode;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
FUNCTION(("common_create_link(path = %s, toPath = %s, kernel = %d)\n", path, toPath, kernel));
|
|
|
|
|
|
|
|
status = path_to_dir_vnode(path, &directory, name, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = path_to_vnode(toPath, true, &vnode, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (directory->mount != vnode->mount) {
|
|
|
|
status = B_CROSS_DEVICE_LINK;
|
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, link) != NULL)
|
|
|
|
status = FS_CALL(vnode, link)(directory->mount->cookie, directory->private_node, name, vnode->private_node);
|
2002-08-14 00:39:25 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
|
|
|
err1:
|
|
|
|
put_vnode(vnode);
|
|
|
|
err:
|
|
|
|
put_vnode(directory);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
common_unlink(char *path, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
char filename[SYS_MAX_NAME_LEN];
|
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
FUNCTION(("common_unlink: path '%s', kernel %d\n", path, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
status = path_to_dir_vnode(path, &vnode, filename, kernel);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, unlink) != NULL)
|
|
|
|
status = FS_CALL(vnode, unlink)(vnode->mount->cookie, vnode->private_node, filename);
|
2002-07-20 04:16:12 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
put_vnode(vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-08-13 17:51:36 +04:00
|
|
|
common_access(char *path, int mode, bool kernel)
|
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
status = path_to_vnode(path, true, &vnode, kernel);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, access) != NULL)
|
|
|
|
status = FS_CALL(vnode, access)(vnode->mount->cookie, vnode->private_node, mode);
|
2002-08-13 17:51:36 +04:00
|
|
|
else
|
|
|
|
status = EOPNOTSUPP;
|
|
|
|
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-08-03 06:03:27 +04:00
|
|
|
common_rename(char *path, char *newPath, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-09-25 16:13:09 +04:00
|
|
|
struct vnode *fromVnode, *toVnode;
|
|
|
|
char fromName[SYS_MAX_NAME_LEN];
|
|
|
|
char toName[SYS_MAX_NAME_LEN];
|
2002-07-20 04:16:12 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
FUNCTION(("common_rename(path = %s, newPath = %s, kernel = %d)\n", path, newPath, kernel));
|
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
status = path_to_dir_vnode(path, &fromVnode, fromName, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < 0)
|
2002-09-25 16:13:09 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
status = path_to_dir_vnode(newPath, &toVnode, toName, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < 0)
|
2002-09-25 16:13:09 +04:00
|
|
|
goto err;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (fromVnode->device != toVnode->device) {
|
2002-09-25 16:13:09 +04:00
|
|
|
status = B_CROSS_DEVICE_LINK;
|
|
|
|
goto err1;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
if (FS_CALL(fromVnode, rename) != NULL)
|
|
|
|
status = FS_CALL(fromVnode, rename)(fromVnode->mount->cookie, fromVnode->private_node, fromName, toVnode->private_node, toName);
|
2002-07-20 04:16:12 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
err1:
|
2002-09-25 16:13:09 +04:00
|
|
|
put_vnode(toVnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
err:
|
2002-09-25 16:13:09 +04:00
|
|
|
put_vnode(fromVnode);
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-25 06:18:20 +04:00
|
|
|
common_read_stat(struct file_descriptor *descriptor, struct stat *stat)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
FUNCTION(("common_read_stat: stat %p\n", stat));
|
2002-09-25 06:18:20 +04:00
|
|
|
return FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, stat);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-10-17 07:09:25 +04:00
|
|
|
common_write_stat(struct file_descriptor *descriptor, const struct stat *stat, int statMask)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
|
|
|
|
FUNCTION(("common_write_stat(vnode = %p, stat = %p, statMask = %d)\n", vnode, stat, statMask));
|
|
|
|
if (!FS_CALL(vnode, write_stat))
|
|
|
|
return EROFS;
|
|
|
|
|
|
|
|
return FS_CALL(vnode, write_stat)(vnode->mount->cookie, vnode->private_node, stat, statMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
common_path_read_stat(char *path, bool traverseLeafLink, struct stat *stat, bool kernel)
|
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
FUNCTION(("common_path_read_stat: path '%s', stat %p,\n", path, stat));
|
|
|
|
|
|
|
|
status = path_to_vnode(path, traverseLeafLink, &vnode, kernel);
|
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, stat);
|
|
|
|
|
|
|
|
put_vnode(vnode);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
common_path_write_stat(char *path, bool traverseLeafLink, const struct stat *stat, int statMask, bool kernel)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
FUNCTION(("common_write_stat: path '%s', stat %p, stat_mask %d, kernel %d\n", path, stat, statMask, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
status = path_to_vnode(path, traverseLeafLink, &vnode, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
if (FS_CALL(vnode, write_stat))
|
|
|
|
status = FS_CALL(vnode, write_stat)(vnode->mount->cookie, vnode->private_node, stat, statMask);
|
2002-07-20 04:16:12 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
|
|
|
attr_dir_open(int fd, char *path, bool kernel)
|
2002-09-26 07:50:14 +04:00
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
FUNCTION(("attr_dir_open(fd = %d, path = '%s', kernel = %d)\n", fd, path, kernel));
|
2002-09-26 07:50:14 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = fd_and_path_to_vnode(fd, path, true, &vnode, kernel);
|
2002-09-26 07:50:14 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = open_attr_dir_vnode(vnode, kernel);
|
|
|
|
if (status < 0)
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-26 07:50:14 +04:00
|
|
|
attr_dir_close(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
|
|
|
|
FUNCTION(("dir_close(descriptor = %p)\n", descriptor));
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, close_attr_dir))
|
|
|
|
return FS_CALL(vnode, close_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
attr_dir_free_fd(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
|
|
|
|
if (vnode != NULL) {
|
|
|
|
FS_CALL(vnode, free_attr_dir_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
put_vnode(vnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
attr_dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, read_attr_dir))
|
|
|
|
return FS_CALL(vnode, read_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, buffer, bufferSize, _count);
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
attr_dir_rewind(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, rewind_attr_dir))
|
|
|
|
return FS_CALL(vnode, rewind_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
static int
|
|
|
|
attr_create(int fd, const char *name, uint32 type, int openMode, bool kernel)
|
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
fs_cookie cookie;
|
|
|
|
int status;
|
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
if (name == NULL || *name == '\0')
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
vnode = get_vnode_from_fd(get_current_io_context(kernel), fd);
|
|
|
|
if (vnode == NULL)
|
|
|
|
return B_FILE_ERROR;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, create_attr) == NULL) {
|
|
|
|
status = EROFS;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = FS_CALL(vnode, create_attr)(vnode->mount->cookie, vnode->private_node, name, type, openMode, &cookie);
|
|
|
|
if (status < B_OK)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if ((status = get_new_fd(FDTYPE_ATTR, vnode, cookie, openMode, kernel)) >= 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
|
|
|
|
FS_CALL(vnode, remove_attr)(vnode->mount->cookie, vnode->private_node, name);
|
|
|
|
|
|
|
|
err:
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
attr_open(int fd, const char *name, int openMode, bool kernel)
|
|
|
|
{
|
|
|
|
struct vnode *vnode;
|
|
|
|
fs_cookie cookie;
|
|
|
|
int status;
|
|
|
|
|
2002-09-25 16:13:09 +04:00
|
|
|
if (name == NULL || *name == '\0')
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2002-09-25 06:18:20 +04:00
|
|
|
vnode = get_vnode_from_fd(get_current_io_context(kernel), fd);
|
|
|
|
if (vnode == NULL)
|
|
|
|
return B_FILE_ERROR;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, open_attr) == NULL) {
|
|
|
|
status = EOPNOTSUPP;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = FS_CALL(vnode, open_attr)(vnode->mount->cookie, vnode->private_node, name, openMode, &cookie);
|
|
|
|
if (status < B_OK)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if ((status = get_new_fd(FDTYPE_ATTR, vnode, cookie, openMode, kernel)) >= 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
|
|
|
|
|
|
|
|
err:
|
|
|
|
put_vnode(vnode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-25 06:18:20 +04:00
|
|
|
attr_close(struct file_descriptor *descriptor)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
|
|
|
FUNCTION(("attr_close(descriptor = %p)\n", descriptor));
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, close_attr))
|
|
|
|
return FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
attr_free_fd(struct file_descriptor *descriptor)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
|
|
|
if (vnode != NULL) {
|
|
|
|
FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
put_vnode(vnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-16 14:32:26 +04:00
|
|
|
static status_t
|
2002-09-25 06:18:20 +04:00
|
|
|
attr_read(struct file_descriptor *descriptor, off_t pos, void *buffer, size_t *length)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
|
|
|
FUNCTION(("attr_read: buf %p, pos %Ld, len %p = %ld\n", buffer, pos, length, *length));
|
|
|
|
if (!FS_CALL(vnode, read_attr))
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
|
|
|
|
return FS_CALL(vnode, read_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-16 14:32:26 +04:00
|
|
|
static status_t
|
2002-09-25 06:18:20 +04:00
|
|
|
attr_write(struct file_descriptor *descriptor, off_t pos, const void *buffer, size_t *length)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
|
|
|
FUNCTION(("attr_write: buf %p, pos %Ld, len %p\n", buffer, pos, length));
|
|
|
|
if (!FS_CALL(vnode, write_attr))
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
|
|
|
|
return FS_CALL(vnode, write_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static off_t
|
|
|
|
attr_seek(struct file_descriptor *descriptor, off_t pos, int seekType)
|
|
|
|
{
|
2002-10-08 04:42:17 +04:00
|
|
|
off_t offset;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
2002-10-08 04:42:17 +04:00
|
|
|
switch (seekType) {
|
|
|
|
case SEEK_SET:
|
|
|
|
offset = 0;
|
|
|
|
break;
|
|
|
|
case SEEK_CUR:
|
|
|
|
offset = descriptor->pos;
|
|
|
|
break;
|
|
|
|
case SEEK_END:
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
struct stat stat;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, read_stat) == NULL)
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
|
|
|
|
status = FS_CALL(vnode, read_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, &stat);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
offset = stat.st_size;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// assumes off_t is 64 bits wide
|
|
|
|
if (offset > 0 && LONGLONG_MAX - offset < pos)
|
|
|
|
return EOVERFLOW;
|
|
|
|
|
|
|
|
pos += offset;
|
|
|
|
if (pos < 0)
|
|
|
|
return B_BAD_VALUE;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
2002-10-08 04:42:17 +04:00
|
|
|
return descriptor->pos = pos;
|
2002-09-25 06:18:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-25 06:18:20 +04:00
|
|
|
attr_read_stat(struct file_descriptor *descriptor, struct stat *stat)
|
|
|
|
{
|
2002-09-26 07:50:14 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
|
|
|
FUNCTION(("attr_read_stat: stat 0x%p\n", stat));
|
|
|
|
if (!FS_CALL(vnode, read_attr_stat))
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
|
|
|
|
return FS_CALL(vnode, read_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-10-17 07:09:25 +04:00
|
|
|
attr_write_stat(struct file_descriptor *descriptor, const struct stat *stat, int statMask)
|
2002-09-25 06:18:20 +04:00
|
|
|
{
|
2002-10-17 07:09:25 +04:00
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
2002-09-25 06:18:20 +04:00
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
FUNCTION(("attr_write_stat: stat = %p, statMask %d\n", stat, statMask));
|
2002-09-25 06:18:20 +04:00
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
if (!FS_CALL(vnode, write_attr_stat))
|
|
|
|
return EROFS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
return FS_CALL(vnode, write_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat, statMask);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-25 16:13:09 +04:00
|
|
|
attr_remove(int fd, const char *name, bool kernel)
|
|
|
|
{
|
|
|
|
struct file_descriptor *descriptor;
|
|
|
|
struct vnode *vnode;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
if (name == NULL || *name == '\0')
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
FUNCTION(("attr_remove: fd = %d, name = \"%s\", kernel %d\n", fd, name, kernel));
|
|
|
|
|
|
|
|
descriptor = get_fd_and_vnode(fd, &vnode, kernel);
|
|
|
|
if (descriptor == NULL)
|
|
|
|
return B_FILE_ERROR;
|
|
|
|
|
|
|
|
if (FS_CALL(vnode, remove_attr))
|
|
|
|
status = FS_CALL(vnode, remove_attr)(vnode->mount->cookie, vnode->private_node, name);
|
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
2004-05-17 14:01:17 +04:00
|
|
|
put_fd(descriptor);
|
2002-09-25 16:13:09 +04:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-25 16:13:09 +04:00
|
|
|
attr_rename(int fromfd, const char *fromName, int tofd, const char *toName, bool kernel)
|
|
|
|
{
|
|
|
|
struct file_descriptor *fromDescriptor, *toDescriptor;
|
|
|
|
struct vnode *fromVnode, *toVnode;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
if (fromName == NULL || *fromName == '\0' || toName == NULL || *toName == '\0')
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
FUNCTION(("attr_rename: from fd = %d, from name = \"%s\", to fd = %d, to name = \"%s\", kernel %d\n", fromfd, fromName, tofd, toName, kernel));
|
|
|
|
|
|
|
|
fromDescriptor = get_fd_and_vnode(fromfd, &fromVnode, kernel);
|
|
|
|
if (fromDescriptor == NULL)
|
|
|
|
return B_FILE_ERROR;
|
|
|
|
|
|
|
|
toDescriptor = get_fd_and_vnode(tofd, &toVnode, kernel);
|
|
|
|
if (toDescriptor == NULL) {
|
|
|
|
status = B_FILE_ERROR;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// are the files on the same volume?
|
2003-10-17 18:47:15 +04:00
|
|
|
if (fromVnode->device != toVnode->device) {
|
2002-09-25 16:13:09 +04:00
|
|
|
status = B_CROSS_DEVICE_LINK;
|
|
|
|
goto err1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FS_CALL(fromVnode, rename_attr))
|
|
|
|
status = FS_CALL(fromVnode, rename_attr)(fromVnode->mount->cookie, fromVnode->private_node, fromName, toVnode->private_node, toName);
|
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
|
|
|
err1:
|
2004-05-17 14:01:17 +04:00
|
|
|
put_fd(toDescriptor);
|
2002-09-25 16:13:09 +04:00
|
|
|
err:
|
2004-05-17 14:01:17 +04:00
|
|
|
put_fd(fromDescriptor);
|
2002-09-25 16:13:09 +04:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-26 07:50:14 +04:00
|
|
|
index_dir_open(mount_id mountID, bool kernel)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
|
|
|
fs_cookie cookie;
|
2003-09-04 08:01:25 +04:00
|
|
|
status_t status;
|
2002-09-26 07:50:14 +04:00
|
|
|
|
|
|
|
FUNCTION(("index_dir_open(mountID = %ld, kernel = %d)\n", mountID, kernel));
|
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
mount = get_mount(mountID);
|
2002-09-26 07:50:14 +04:00
|
|
|
if (mount == NULL)
|
2003-09-04 08:01:25 +04:00
|
|
|
return B_BAD_VALUE;
|
2002-09-26 07:50:14 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
if (FS_MOUNT_CALL(mount, open_index_dir) == NULL) {
|
|
|
|
status = EOPNOTSUPP;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-09-26 07:50:14 +04:00
|
|
|
|
|
|
|
status = FS_MOUNT_CALL(mount, open_index_dir)(mount->cookie, &cookie);
|
|
|
|
if (status < B_OK)
|
2003-09-04 08:01:25 +04:00
|
|
|
goto out;
|
2002-09-26 07:50:14 +04:00
|
|
|
|
|
|
|
// get fd for the index directory
|
2003-10-17 18:47:15 +04:00
|
|
|
status = get_new_fd(FDTYPE_INDEX_DIR, (struct vnode *)mount, cookie, 0, kernel);
|
2002-09-26 07:50:14 +04:00
|
|
|
if (status >= 0)
|
2003-09-04 08:01:25 +04:00
|
|
|
goto out;
|
2002-09-26 07:50:14 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
// something went wrong
|
2002-09-26 07:50:14 +04:00
|
|
|
FS_MOUNT_CALL(mount, close_index_dir)(mount->cookie, cookie);
|
|
|
|
FS_MOUNT_CALL(mount, free_index_dir_cookie)(mount->cookie, cookie);
|
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
out:
|
|
|
|
put_mount(mount);
|
2002-09-26 07:50:14 +04:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-26 07:50:14 +04:00
|
|
|
index_dir_close(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount = descriptor->u.mount;
|
|
|
|
|
|
|
|
FUNCTION(("dir_close(descriptor = %p)\n", descriptor));
|
|
|
|
|
|
|
|
if (FS_MOUNT_CALL(mount, close_index_dir))
|
|
|
|
return FS_MOUNT_CALL(mount, close_index_dir)(mount->cookie, descriptor->cookie);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
index_dir_free_fd(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount = descriptor->u.mount;
|
|
|
|
|
|
|
|
if (mount != NULL) {
|
|
|
|
FS_MOUNT_CALL(mount, free_index_dir_cookie)(mount->cookie, descriptor->cookie);
|
|
|
|
// ToDo: find a replacement ref_count object - perhaps the root dir?
|
|
|
|
//put_vnode(vnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
index_dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount = descriptor->u.mount;
|
|
|
|
|
|
|
|
if (FS_MOUNT_CALL(mount, read_index_dir))
|
|
|
|
return FS_MOUNT_CALL(mount, read_index_dir)(mount->cookie, descriptor->cookie, buffer, bufferSize, _count);
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
index_dir_rewind(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount = descriptor->u.mount;
|
|
|
|
|
|
|
|
if (FS_MOUNT_CALL(mount, rewind_index_dir))
|
|
|
|
return FS_MOUNT_CALL(mount, rewind_index_dir)(mount->cookie, descriptor->cookie);
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-17 23:34:09 +04:00
|
|
|
static status_t
|
|
|
|
index_create(mount_id mountID, const char *name, uint32 type, uint32 flags, bool kernel)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
2003-09-04 08:01:25 +04:00
|
|
|
status_t status;
|
2002-10-17 23:34:09 +04:00
|
|
|
|
|
|
|
FUNCTION(("index_create(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel));
|
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
mount = get_mount(mountID);
|
2002-10-17 23:34:09 +04:00
|
|
|
if (mount == NULL)
|
2003-09-04 08:01:25 +04:00
|
|
|
return B_BAD_VALUE;
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
if (FS_MOUNT_CALL(mount, create_index) == NULL) {
|
|
|
|
status = EROFS;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
status = FS_MOUNT_CALL(mount, create_index)(mount->cookie, name, type, flags);
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
out:
|
|
|
|
put_mount(mount);
|
|
|
|
return status;
|
2002-10-17 23:34:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-04 08:07:39 +04:00
|
|
|
#if 0
|
2002-10-17 23:34:09 +04:00
|
|
|
static status_t
|
|
|
|
index_read_stat(struct file_descriptor *descriptor, struct stat *stat)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
|
|
|
|
// ToDo: currently unused!
|
|
|
|
FUNCTION(("index_read_stat: stat 0x%p\n", stat));
|
|
|
|
if (!FS_CALL(vnode, read_index_stat))
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
//return FS_CALL(vnode, read_index_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-04 08:07:39 +04:00
|
|
|
static void
|
|
|
|
index_free_fd(struct file_descriptor *descriptor)
|
|
|
|
{
|
|
|
|
struct vnode *vnode = descriptor->u.vnode;
|
|
|
|
|
|
|
|
if (vnode != NULL) {
|
|
|
|
FS_CALL(vnode, free_index_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
|
|
|
|
put_vnode(vnode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2002-10-17 23:34:09 +04:00
|
|
|
static status_t
|
|
|
|
index_name_read_stat(mount_id mountID, const char *name, struct stat *stat, bool kernel)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
2003-09-04 08:01:25 +04:00
|
|
|
status_t status;
|
2002-10-17 23:34:09 +04:00
|
|
|
|
|
|
|
FUNCTION(("index_remove(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel));
|
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
mount = get_mount(mountID);
|
2002-10-17 23:34:09 +04:00
|
|
|
if (mount == NULL)
|
2003-09-04 08:01:25 +04:00
|
|
|
return B_BAD_VALUE;
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
if (FS_MOUNT_CALL(mount, read_index_stat) == NULL) {
|
|
|
|
status = EOPNOTSUPP;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
status = FS_MOUNT_CALL(mount, read_index_stat)(mount->cookie, name, stat);
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
out:
|
|
|
|
put_mount(mount);
|
|
|
|
return status;
|
2002-10-17 23:34:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
index_remove(mount_id mountID, const char *name, bool kernel)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
2003-09-04 08:01:25 +04:00
|
|
|
status_t status;
|
2002-10-17 23:34:09 +04:00
|
|
|
|
|
|
|
FUNCTION(("index_remove(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel));
|
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
mount = get_mount(mountID);
|
2002-10-17 23:34:09 +04:00
|
|
|
if (mount == NULL)
|
2003-09-04 08:01:25 +04:00
|
|
|
return B_BAD_VALUE;
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
if (FS_MOUNT_CALL(mount, remove_index) == NULL) {
|
|
|
|
status = EROFS;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
status = FS_MOUNT_CALL(mount, remove_index)(mount->cookie, name);
|
2002-10-17 23:34:09 +04:00
|
|
|
|
2003-09-04 08:01:25 +04:00
|
|
|
out:
|
|
|
|
put_mount(mount);
|
|
|
|
return status;
|
2002-10-17 23:34:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// #pragma mark -
|
|
|
|
// General File System functions
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-09-25 18:10:50 +04:00
|
|
|
fs_mount(char *path, const char *device, const char *fsName, void *args, bool kernel)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
|
|
|
struct vnode *covered_vnode = NULL;
|
|
|
|
vnode_id root_id;
|
2002-09-25 18:10:50 +04:00
|
|
|
int err = 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-28 06:19:26 +04:00
|
|
|
FUNCTION(("fs_mount: entry. path = '%s', fs_name = '%s'\n", path, fsName));
|
2002-09-25 18:10:50 +04:00
|
|
|
|
2002-09-28 06:19:26 +04:00
|
|
|
// The path is always safe, we just have to make sure that fsName is
|
|
|
|
// almost valid - we can't make any assumptions about device and args,
|
|
|
|
// though.
|
|
|
|
if (fsName == NULL || fsName[0] == '\0')
|
2002-09-25 18:10:50 +04:00
|
|
|
return B_BAD_VALUE;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sMountOpMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-30 02:07:06 +03:00
|
|
|
mount = (struct fs_mount *)malloc(sizeof(struct fs_mount));
|
2002-09-25 18:10:50 +04:00
|
|
|
if (mount == NULL) {
|
|
|
|
err = B_NO_MEMORY;
|
2002-07-20 04:16:12 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-01-18 17:13:44 +03:00
|
|
|
list_init_etc(&mount->vnodes, offsetof(struct vnode, mount_link));
|
2002-09-05 15:18:38 +04:00
|
|
|
|
2002-10-30 02:07:06 +03:00
|
|
|
mount->mount_point = strdup(path);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (mount->mount_point == NULL) {
|
2002-09-25 16:13:09 +04:00
|
|
|
err = B_NO_MEMORY;
|
2002-07-20 04:16:12 +04:00
|
|
|
goto err1;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
mount->fs = get_file_system(fsName);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (mount->fs == NULL) {
|
2003-02-21 16:49:26 +03:00
|
|
|
err = ENODEV;
|
2002-07-20 04:16:12 +04:00
|
|
|
goto err2;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-06-08 10:43:46 +04:00
|
|
|
err = recursive_lock_init(&mount->rlock, "mount rlock");
|
|
|
|
if (err < B_OK)
|
|
|
|
goto err3;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mount->id = sNextMountID++;
|
2002-07-20 04:16:12 +04:00
|
|
|
mount->unmounting = false;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2004-06-08 10:43:46 +04:00
|
|
|
mutex_lock(&sMountMutex);
|
|
|
|
|
|
|
|
// insert mount struct into list before we call fs mount()
|
|
|
|
hash_insert(sMountsTable, mount);
|
|
|
|
|
|
|
|
mutex_unlock(&sMountMutex);
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (!sRoot) {
|
2002-07-20 04:16:12 +04:00
|
|
|
// we haven't mounted anything yet
|
|
|
|
if (strcmp(path, "/") != 0) {
|
2003-02-21 16:49:26 +03:00
|
|
|
err = B_ERROR;
|
2004-06-08 10:43:46 +04:00
|
|
|
goto err4;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
err = FS_MOUNT_CALL(mount, mount)(mount->id, device, NULL, &mount->cookie, &root_id);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (err < 0) {
|
2003-02-21 16:49:26 +03:00
|
|
|
// ToDo: why should we hide the error code from the file system here?
|
|
|
|
//err = ERR_VFS_GENERAL;
|
2004-06-08 10:43:46 +04:00
|
|
|
goto err4;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mount->covers_vnode = NULL; // this is the root mount
|
|
|
|
} else {
|
2002-08-03 06:03:27 +04:00
|
|
|
err = path_to_vnode(path, true, &covered_vnode, kernel);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (err < 0)
|
2004-06-08 10:43:46 +04:00
|
|
|
goto err4;
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (!covered_vnode) {
|
2003-02-21 16:49:26 +03:00
|
|
|
err = B_ERROR;
|
2004-06-08 10:43:46 +04:00
|
|
|
goto err4;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// XXX insert check to make sure covered_vnode is a DIR, or maybe it's okay for it not to be
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (covered_vnode != sRoot
|
2002-09-24 20:17:22 +04:00
|
|
|
&& covered_vnode->mount->root_vnode == covered_vnode) {
|
2002-07-20 04:16:12 +04:00
|
|
|
err = ERR_VFS_ALREADY_MOUNTPOINT;
|
2004-06-08 10:43:46 +04:00
|
|
|
goto err4;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mount->covers_vnode = covered_vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// mount it
|
2002-09-26 07:50:14 +04:00
|
|
|
err = FS_MOUNT_CALL(mount, mount)(mount->id, device, NULL, &mount->cookie, &root_id);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (err < 0)
|
2004-06-08 10:43:46 +04:00
|
|
|
goto err5;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
err = get_vnode(mount->id, root_id, &mount->root_vnode, 0);
|
|
|
|
if (err < 0)
|
2004-06-08 10:43:46 +04:00
|
|
|
goto err6;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// XXX may be a race here
|
|
|
|
if (mount->covers_vnode)
|
|
|
|
mount->covers_vnode->covered_by = mount->root_vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
if (!sRoot)
|
|
|
|
sRoot = mount->root_vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sMountOpMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-06-08 10:43:46 +04:00
|
|
|
err6:
|
2002-09-26 07:50:14 +04:00
|
|
|
FS_MOUNT_CALL(mount, unmount)(mount->cookie);
|
2004-06-08 10:43:46 +04:00
|
|
|
err5:
|
2002-07-20 04:16:12 +04:00
|
|
|
if (mount->covers_vnode)
|
2002-09-25 18:10:50 +04:00
|
|
|
put_vnode(mount->covers_vnode);
|
2004-06-08 10:43:46 +04:00
|
|
|
err4:
|
|
|
|
mutex_lock(&sMountMutex);
|
|
|
|
hash_remove(sMountsTable, mount);
|
|
|
|
mutex_unlock(&sMountMutex);
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
recursive_lock_destroy(&mount->rlock);
|
2004-06-08 10:43:46 +04:00
|
|
|
err3:
|
2002-09-25 18:10:50 +04:00
|
|
|
put_file_system(mount->fs);
|
2002-07-20 04:16:12 +04:00
|
|
|
err2:
|
2002-10-30 02:07:06 +03:00
|
|
|
free(mount->mount_point);
|
2002-07-20 04:16:12 +04:00
|
|
|
err1:
|
2002-10-30 02:07:06 +03:00
|
|
|
free(mount);
|
2002-07-20 04:16:12 +04:00
|
|
|
err:
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sMountOpMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return err;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
fs_unmount(char *path, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct fs_mount *mount;
|
2002-07-28 22:41:07 +04:00
|
|
|
struct vnode *vnode;
|
2002-07-20 04:16:12 +04:00
|
|
|
int err;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
err = path_to_vnode(path, true, &vnode, kernel);
|
2002-07-28 22:41:07 +04:00
|
|
|
if (err < 0)
|
|
|
|
return ERR_VFS_PATH_NOT_FOUND;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sMountOpMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mount = find_mount(vnode->device);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (!mount)
|
2002-09-25 18:10:50 +04:00
|
|
|
panic("vfs_unmount: find_mount() failed on root vnode @%p of mount\n", vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
if (mount->root_vnode != vnode) {
|
2002-07-20 04:16:12 +04:00
|
|
|
// not mountpoint
|
2002-09-25 18:10:50 +04:00
|
|
|
put_vnode(vnode);
|
2002-07-20 04:16:12 +04:00
|
|
|
err = ERR_VFS_NOT_MOUNTPOINT;
|
2002-07-28 22:41:07 +04:00
|
|
|
goto err;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-01-05 04:03:14 +03:00
|
|
|
/* grab the vnode master mutex to keep someone from creating
|
|
|
|
* a vnode while we're figuring out if we can continue
|
|
|
|
*/
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
/* simulate the root vnode having it's refcount decremented */
|
|
|
|
mount->root_vnode->ref_count -= 2;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-28 22:41:07 +04:00
|
|
|
// cycle through the list of vnodes associated with this mount and
|
|
|
|
// make sure all of them are not busy or have refs on them
|
2003-01-18 17:13:44 +03:00
|
|
|
vnode = NULL;
|
2003-10-17 18:47:15 +04:00
|
|
|
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
|
2002-07-28 22:41:07 +04:00
|
|
|
if (vnode->busy || vnode->ref_count != 0) {
|
2002-07-20 04:16:12 +04:00
|
|
|
mount->root_vnode->ref_count += 2;
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-09-25 18:10:50 +04:00
|
|
|
put_vnode(mount->root_vnode);
|
2002-07-28 22:41:07 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
err = EBUSY;
|
2002-07-28 22:41:07 +04:00
|
|
|
goto err;
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
/* we can safely continue, mark all of the vnodes busy and this mount
|
|
|
|
structure in unmounting state */
|
2003-10-17 18:47:15 +04:00
|
|
|
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
|
2002-07-28 22:41:07 +04:00
|
|
|
if (vnode != mount->root_vnode)
|
|
|
|
vnode->busy = true;
|
2002-09-25 18:10:50 +04:00
|
|
|
}
|
2002-07-20 04:16:12 +04:00
|
|
|
mount->unmounting = true;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-01-05 04:03:14 +03:00
|
|
|
/* add 2 back to the root vnode's ref */
|
|
|
|
mount->root_vnode->ref_count += 2;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sVnodeMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mount->covers_vnode->covered_by = NULL;
|
2002-09-25 18:10:50 +04:00
|
|
|
put_vnode(mount->covers_vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
/* release the ref on the root vnode twice */
|
2002-09-25 18:10:50 +04:00
|
|
|
put_vnode(mount->root_vnode);
|
|
|
|
put_vnode(mount->root_vnode);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
// ToDo: when full vnode cache in place, will need to force
|
2002-07-20 04:16:12 +04:00
|
|
|
// a putvnode/removevnode here
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
/* remove the mount structure from the hash table */
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sMountMutex);
|
|
|
|
hash_remove(sMountsTable, mount);
|
|
|
|
mutex_unlock(&sMountMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sMountOpMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
FS_MOUNT_CALL(mount, unmount)(mount->cookie);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-09-25 18:10:50 +04:00
|
|
|
// release the file system
|
|
|
|
put_file_system(mount->fs);
|
|
|
|
|
2002-10-30 02:07:06 +03:00
|
|
|
free(mount->mount_point);
|
|
|
|
free(mount);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
err:
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sMountOpMutex);
|
2002-07-20 04:16:12 +04:00
|
|
|
return err;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
fs_sync(void)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
struct hash_iterator iter;
|
|
|
|
struct fs_mount *mount;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("vfs_sync: entry.\n"));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
/* cycle through and call sync on each mounted fs */
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sMountOpMutex);
|
|
|
|
mutex_lock(&sMountMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
hash_open(sMountsTable, &iter);
|
|
|
|
while ((mount = (struct fs_mount *)hash_next(sMountsTable, &iter))) {
|
2002-09-26 07:50:14 +04:00
|
|
|
if (FS_MOUNT_CALL(mount, sync))
|
|
|
|
FS_MOUNT_CALL(mount, sync)(mount->cookie);
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2003-10-17 18:47:15 +04:00
|
|
|
hash_close(sMountsTable, &iter, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sMountMutex);
|
|
|
|
mutex_unlock(&sMountOpMutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-07-23 18:10:12 +04:00
|
|
|
fs_read_info(dev_t device, struct fs_info *info)
|
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
|
|
|
int status;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sMountMutex);
|
2002-07-23 18:10:12 +04:00
|
|
|
|
|
|
|
mount = find_mount(device);
|
|
|
|
if (mount == NULL) {
|
|
|
|
status = EINVAL;
|
2003-09-04 08:19:24 +04:00
|
|
|
goto out;
|
2002-07-23 18:10:12 +04:00
|
|
|
}
|
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
if (FS_MOUNT_CALL(mount, read_fs_info))
|
|
|
|
status = FS_MOUNT_CALL(mount, read_fs_info)(mount->cookie, info);
|
2002-07-23 18:10:12 +04:00
|
|
|
else
|
|
|
|
status = EOPNOTSUPP;
|
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
// fill in other info the file system doesn't (have to) know about
|
2002-07-23 18:10:12 +04:00
|
|
|
info->dev = mount->id;
|
|
|
|
info->root = mount->root_vnode->id;
|
|
|
|
|
2003-09-04 08:19:24 +04:00
|
|
|
out:
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sMountMutex);
|
2002-07-23 18:10:12 +04:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-07-28 22:41:07 +04:00
|
|
|
fs_write_info(dev_t device, const struct fs_info *info, int mask)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
struct fs_mount *mount;
|
|
|
|
int status;
|
|
|
|
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_lock(&sMountMutex);
|
2002-07-23 18:10:12 +04:00
|
|
|
|
|
|
|
mount = find_mount(device);
|
|
|
|
if (mount == NULL) {
|
|
|
|
status = EINVAL;
|
2003-09-04 08:19:24 +04:00
|
|
|
goto out;
|
2002-07-23 18:10:12 +04:00
|
|
|
}
|
|
|
|
|
2002-09-26 07:50:14 +04:00
|
|
|
if (FS_MOUNT_CALL(mount, write_fs_info))
|
|
|
|
status = FS_MOUNT_CALL(mount, write_fs_info)(mount->cookie, info, mask);
|
2002-07-23 18:10:12 +04:00
|
|
|
else
|
|
|
|
status = EROFS;
|
|
|
|
|
2003-09-04 08:19:24 +04:00
|
|
|
out:
|
2003-10-17 18:47:15 +04:00
|
|
|
mutex_unlock(&sMountMutex);
|
2002-07-23 18:10:12 +04:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-07-20 04:16:12 +04:00
|
|
|
get_cwd(char *buffer, size_t size, bool kernel)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
// Get current working directory from io context
|
|
|
|
struct io_context *context = get_current_io_context(kernel);
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
FUNCTION(("vfs_get_cwd: buf %p, size %ld\n", buffer, size));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_lock(&context->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (context->cwd)
|
|
|
|
status = dir_vnode_to_path(context->cwd, buffer, size);
|
|
|
|
else
|
|
|
|
status = B_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_unlock(&context->io_mutex);
|
|
|
|
return status;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
static status_t
|
2002-08-10 00:20:28 +04:00
|
|
|
set_cwd(int fd, char *path, bool kernel)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
|
|
|
struct io_context *context;
|
|
|
|
struct vnode *vnode = NULL;
|
|
|
|
struct vnode *oldDirectory;
|
|
|
|
struct stat stat;
|
|
|
|
int rc;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-03 06:03:27 +04:00
|
|
|
FUNCTION(("set_cwd: path = \'%s\'\n", path));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// Get vnode for passed path, and bail if it failed
|
2002-08-10 00:20:28 +04:00
|
|
|
rc = fd_and_path_to_vnode(fd, path, true, &vnode, kernel);
|
2002-07-09 16:24:59 +04:00
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
2002-09-24 20:17:22 +04:00
|
|
|
rc = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat);
|
2002-07-09 16:24:59 +04:00
|
|
|
if (rc < 0)
|
2002-07-20 04:16:12 +04:00
|
|
|
goto err;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (!S_ISDIR(stat.st_mode)) {
|
|
|
|
// nope, can't cwd to here
|
2003-02-21 16:49:26 +03:00
|
|
|
rc = B_NOT_A_DIRECTORY;
|
2002-07-20 04:16:12 +04:00
|
|
|
goto err;
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// Get current io context and lock
|
|
|
|
context = get_current_io_context(kernel);
|
|
|
|
mutex_lock(&context->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// save the old current working directory first
|
|
|
|
oldDirectory = context->cwd;
|
|
|
|
context->cwd = vnode;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
mutex_unlock(&context->io_mutex);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (oldDirectory)
|
|
|
|
put_vnode(oldDirectory);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return B_NO_ERROR;
|
|
|
|
|
|
|
|
err:
|
|
|
|
put_vnode(vnode);
|
|
|
|
return rc;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// #pragma mark -
|
|
|
|
// Calls from within the kernel
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_mount(const char *path, const char *device, const char *fs_name, void *args)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return fs_mount(pathBuffer, device, fs_name, args, true);
|
2002-07-14 09:13:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_unmount(const char *path)
|
2002-07-14 09:13:20 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return fs_unmount(pathBuffer, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-04 08:19:24 +04:00
|
|
|
status_t
|
|
|
|
_kern_read_fs_info(dev_t device, struct fs_info *info)
|
|
|
|
{
|
|
|
|
if (info == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
return fs_read_info(device, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
_kern_write_fs_info(dev_t device, const struct fs_info *info, int mask)
|
|
|
|
{
|
|
|
|
if (info == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
return fs_write_info(device, info, mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_sync(void)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
return fs_sync();
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_open_entry_ref(dev_t device, ino_t inode, const char *name, int omode)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
char nameCopy[B_FILE_NAME_LENGTH];
|
2002-08-14 00:39:25 +04:00
|
|
|
strlcpy(nameCopy, name, sizeof(nameCopy) - 1);
|
2002-07-23 18:10:12 +04:00
|
|
|
|
|
|
|
return file_open_entry_ref(device, inode, nameCopy, omode, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_open(const char *path, int omode)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return file_open(pathBuffer, omode, true);
|
2002-07-23 18:10:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_open_dir_node_ref(dev_t device, ino_t inode)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
return dir_open_node_ref(device, inode, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_open_dir_entry_ref(dev_t device, ino_t inode, const char *name)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
return dir_open_entry_ref(device, inode, name, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_open_dir(const char *path)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return dir_open(pathBuffer, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_fsync(int fd)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
return common_sync(fd, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_create_entry_ref(dev_t device, ino_t inode, const char *name, int omode, int perms)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
return file_create_entry_ref(device, inode, name, omode, perms, true);
|
2002-07-23 18:10:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_create(const char *path, int omode, int perms)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
char buffer[SYS_MAX_PATH_LEN + 1];
|
2002-08-14 00:39:25 +04:00
|
|
|
strlcpy(buffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return file_create(buffer, omode, perms, true);
|
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
return dir_create_entry_ref(device, inode, name, perms, true);
|
2002-07-23 18:10:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_create_dir(const char *path, int perms)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
|
|
|
|
|
|
|
return dir_create(pathBuffer, perms, true);
|
|
|
|
}
|
2002-07-14 09:13:20 +04:00
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_remove_dir(const char *path)
|
2002-08-14 00:39:25 +04:00
|
|
|
{
|
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
|
|
|
|
|
|
|
return dir_remove(pathBuffer, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
ssize_t
|
|
|
|
_kern_read_link(const char *path, char *buffer, size_t bufferSize)
|
2002-08-03 06:03:27 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-08-03 06:03:27 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return common_read_link(pathBuffer, buffer, bufferSize, true);
|
2002-08-03 06:03:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_write_link(const char *path, const char *toPath)
|
2002-08-09 21:03:03 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char toPathBuffer[SYS_MAX_PATH_LEN + 1];
|
2002-08-09 21:03:03 +04:00
|
|
|
int status;
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
|
|
|
strlcpy(toPathBuffer, toPath, SYS_MAX_PATH_LEN - 1);
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
status = check_path(toPathBuffer);
|
2002-08-09 21:03:03 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return common_write_link(pathBuffer, toPathBuffer, true);
|
2002-08-09 21:03:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_create_symlink(const char *path, const char *toPath, int mode)
|
2002-07-28 22:41:07 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char toPathBuffer[SYS_MAX_PATH_LEN + 1];
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t status;
|
2002-07-28 22:41:07 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
|
|
|
strlcpy(toPathBuffer, toPath, SYS_MAX_PATH_LEN - 1);
|
2002-07-28 22:41:07 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
status = check_path(toPathBuffer);
|
2002-07-28 22:41:07 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return common_create_symlink(pathBuffer, toPathBuffer, mode, true);
|
2002-07-28 22:41:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_create_link(const char *path, const char *toPath)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char toPathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
|
|
|
strlcpy(toPathBuffer, toPath, SYS_MAX_PATH_LEN - 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return common_create_link(pathBuffer, toPathBuffer, true);
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_unlink(const char *path)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
|
|
|
|
|
|
|
return common_unlink(pathBuffer, true);
|
|
|
|
}
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_rename(const char *oldPath, const char *newPath)
|
2002-08-14 00:39:25 +04:00
|
|
|
{
|
|
|
|
char oldPathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char newPathBuffer[SYS_MAX_PATH_LEN + 1];
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
strlcpy(oldPathBuffer, oldPath, SYS_MAX_PATH_LEN - 1);
|
|
|
|
strlcpy(newPathBuffer, newPath, SYS_MAX_PATH_LEN - 1);
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return common_rename(oldPathBuffer, newPathBuffer, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_access(const char *path, int mode)
|
2002-08-13 17:51:36 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-08-13 17:51:36 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return common_access(pathBuffer, mode, true);
|
2002-08-13 17:51:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
status_t
|
|
|
|
_kern_read_path_stat(const char *path, bool traverseLeafLink, struct stat *stat, size_t statSize)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2004-05-10 18:33:17 +04:00
|
|
|
struct stat completeStat;
|
|
|
|
struct stat *originalStat = NULL;
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
2004-05-10 18:33:17 +04:00
|
|
|
status_t status;
|
|
|
|
|
|
|
|
if (statSize > sizeof(struct stat))
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
// this supports different stat extensions
|
|
|
|
if (statSize < sizeof(struct stat)) {
|
|
|
|
originalStat = stat;
|
|
|
|
stat = &completeStat;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = common_path_read_stat(pathBuffer, traverseLeafLink, stat, true);
|
|
|
|
if (status == B_OK && originalStat != NULL)
|
|
|
|
memcpy(originalStat, stat, statSize);
|
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
status_t
|
|
|
|
_kern_write_path_stat(const char *path, bool traverseLeafLink, const struct stat *stat, size_t statSize, int statMask)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2004-05-10 18:33:17 +04:00
|
|
|
struct stat completeStat;
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
2004-05-10 18:33:17 +04:00
|
|
|
|
|
|
|
if (statSize > sizeof(struct stat))
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
// this supports different stat extensions
|
|
|
|
|
|
|
|
if (statSize < sizeof(struct stat)) {
|
|
|
|
memset((uint8 *)&completeStat + statSize, 0, sizeof(struct stat) - statSize);
|
|
|
|
memcpy(&completeStat, stat, statSize);
|
|
|
|
stat = &completeStat;
|
|
|
|
}
|
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
return common_path_write_stat(pathBuffer, traverseLeafLink, stat, statMask, true);
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-17 11:55:51 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_open_attr_dir(int fd, const char *path)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
|
|
|
|
|
|
|
return attr_dir_open(fd, pathBuffer, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_create_attr(int fd, const char *name, uint32 type, int openMode)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
return attr_create(fd, name, type, openMode, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_open_attr(int fd, const char *name, int openMode)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
return attr_open(fd, name, openMode, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_remove_attr(int fd, const char *name)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
return attr_remove(fd, name, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_rename_attr(int fromFile, const char *fromName, int toFile, const char *toName)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
return attr_rename(fromFile, fromName, toFile, toName, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-17 23:34:09 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_kern_open_index_dir(dev_t device)
|
2002-10-17 23:34:09 +04:00
|
|
|
{
|
|
|
|
return index_dir_open(device, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_create_index(dev_t device, const char *name, uint32 type, uint32 flags)
|
2002-10-17 23:34:09 +04:00
|
|
|
{
|
|
|
|
return index_create(device, name, type, flags, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_read_index_stat(dev_t device, const char *name, struct stat *stat)
|
2002-10-17 23:34:09 +04:00
|
|
|
{
|
|
|
|
return index_name_read_stat(device, name, stat, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_remove_index(dev_t device, const char *name)
|
2002-10-17 23:34:09 +04:00
|
|
|
{
|
|
|
|
return index_remove(device, name, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_getcwd(char *buffer, size_t size)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN];
|
2002-08-10 00:20:28 +04:00
|
|
|
int status;
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2002-08-10 00:20:28 +04:00
|
|
|
PRINT(("sys_getcwd: buf %p, %ld\n", buffer, size));
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
// Call vfs to get current working directory
|
2002-08-14 00:39:25 +04:00
|
|
|
status = get_cwd(path, SYS_MAX_PATH_LEN - 1, true);
|
2002-08-10 00:20:28 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-10 00:20:28 +04:00
|
|
|
path[SYS_MAX_PATH_LEN - 1] = '\0';
|
|
|
|
strlcpy(buffer, path, size);
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2002-08-10 00:20:28 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_kern_setcwd(int fd, const char *path)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
2002-10-08 07:24:51 +04:00
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return set_cwd(fd, pathBuffer, true);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
2002-07-20 04:16:12 +04:00
|
|
|
// Calls from userland (with extra address checks)
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_mount(const char *upath, const char *udevice, const char *ufs_name, void *args)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
2004-02-23 06:19:02 +03:00
|
|
|
char fs_name[B_OS_NAME_LENGTH + 1];
|
2002-07-28 22:41:07 +04:00
|
|
|
char device[SYS_MAX_PATH_LEN + 1];
|
2002-07-20 04:16:12 +04:00
|
|
|
int rc;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(upath)
|
|
|
|
|| !IS_USER_ADDRESS(ufs_name)
|
|
|
|
|| !IS_USER_ADDRESS(udevice))
|
2002-07-23 18:10:12 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
rc = user_strlcpy(path, upath, SYS_MAX_PATH_LEN);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-23 06:19:02 +03:00
|
|
|
rc = user_strlcpy(fs_name, ufs_name, B_OS_NAME_LENGTH);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
if (udevice) {
|
2002-10-08 07:24:51 +04:00
|
|
|
rc = user_strlcpy(device, udevice, SYS_MAX_PATH_LEN);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
} else
|
2002-08-14 00:39:25 +04:00
|
|
|
device[0] = '\0';
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return fs_mount(path, device, fs_name, args, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_unmount(const char *userPath)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
2002-08-14 00:39:25 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-08-14 00:39:25 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return fs_unmount(path, false);
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2003-09-04 08:19:24 +04:00
|
|
|
status_t
|
|
|
|
_user_read_fs_info(dev_t device, struct fs_info *userInfo)
|
|
|
|
{
|
|
|
|
struct fs_info info;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
if (userInfo == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userInfo))
|
2003-09-04 08:19:24 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
status = fs_read_info(device, &info);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (user_memcpy(userInfo, &info, sizeof(struct fs_info)) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
_user_write_fs_info(dev_t device, const struct fs_info *userInfo, int mask)
|
|
|
|
{
|
|
|
|
struct fs_info info;
|
|
|
|
|
|
|
|
if (userInfo == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userInfo)
|
2003-09-04 08:19:24 +04:00
|
|
|
|| user_memcpy(&info, userInfo, sizeof(struct fs_info)) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return fs_write_info(device, &info, mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_sync(void)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
|
|
|
return fs_sync();
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_open_entry_ref(dev_t device, ino_t inode, const char *userName, int omode)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
int status;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName))
|
2003-02-21 16:49:26 +03:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-23 18:10:12 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(name, userName, sizeof(name) - 1);
|
2002-07-23 18:10:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return file_open_entry_ref(device, inode, name, omode, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_open(const char *userPath, int omode)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
2002-08-14 00:39:25 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath))
|
2003-02-21 16:49:26 +03:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-08-14 00:39:25 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return file_open(path, omode, false);
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_open_dir_node_ref(dev_t device, ino_t inode)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
return dir_open_node_ref(device, inode, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_open_dir_entry_ref(dev_t device, ino_t inode, const char *uname)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
int status;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(uname))
|
2002-10-08 07:24:51 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-23 18:10:12 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(name, uname, sizeof(name));
|
2002-07-23 18:10:12 +04:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return dir_open_entry_ref(device, inode, name, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_open_dir(const char *userPath)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
2002-07-23 18:10:12 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath))
|
2002-10-08 07:24:51 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-07-23 18:10:12 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return dir_open(path, false);
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_fsync(int fd)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
|
|
|
return common_sync(fd, false);
|
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2002-07-23 18:10:12 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_create_entry_ref(dev_t device, ino_t inode, const char *userName, int openMode, int perms)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
int status;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName))
|
2002-10-08 07:24:51 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-23 18:10:12 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(name, userName, sizeof(name));
|
2002-07-23 18:10:12 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
return file_create_entry_ref(device, inode, name, openMode, perms, false);
|
2002-07-23 18:10:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_create(const char *userPath, int openMode, int perms)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath))
|
2002-08-14 00:39:25 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-07-28 22:41:07 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
return file_create(path, openMode, perms, false);
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_create_dir_entry_ref(dev_t device, ino_t inode, const char *userName, int perms)
|
2002-07-23 18:10:12 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t status;
|
2002-07-23 18:10:12 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName))
|
2002-08-14 00:39:25 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-23 18:10:12 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(name, userName, sizeof(name));
|
2002-07-23 18:10:12 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return dir_create_entry_ref(device, inode, name, perms, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_create_dir(const char *userPath, int perms)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath))
|
2002-08-14 00:39:25 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-07-28 22:41:07 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return dir_create(path, perms, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_remove_dir(const char *userPath)
|
2002-08-14 00:39:25 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
|
|
|
int status;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath))
|
2002-08-14 00:39:25 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-08-14 00:39:25 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return dir_remove(path, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
ssize_t
|
|
|
|
_user_read_link(const char *userPath, char *userBuffer, size_t bufferSize)
|
2002-08-03 06:03:27 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char buffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
int status;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath)
|
|
|
|
|| !IS_USER_ADDRESS(userBuffer))
|
2002-08-03 06:03:27 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-08-03 06:03:27 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-08-14 00:39:25 +04:00
|
|
|
|
|
|
|
if (bufferSize > SYS_MAX_PATH_LEN)
|
|
|
|
bufferSize = SYS_MAX_PATH_LEN;
|
2002-08-03 06:03:27 +04:00
|
|
|
|
|
|
|
status = common_read_link(path, buffer, bufferSize, false);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
// ToDo: think about buffer length and the return value at read_link()
|
2003-09-27 09:29:04 +04:00
|
|
|
status = user_strlcpy(userBuffer, buffer, bufferSize);
|
|
|
|
if (status >= 0)
|
|
|
|
status = B_OK;
|
|
|
|
return status;
|
2002-08-03 06:03:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_write_link(const char *userPath, const char *userToPath)
|
2002-08-09 21:03:03 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char toPath[SYS_MAX_PATH_LEN + 1];
|
|
|
|
int status;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath)
|
|
|
|
|| !IS_USER_ADDRESS(userToPath))
|
2002-08-09 21:03:03 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-08-09 21:03:03 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(toPath, userToPath, SYS_MAX_PATH_LEN);
|
2002-08-09 21:03:03 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = check_path(toPath);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return common_write_link(path, toPath, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_create_symlink(const char *userPath, const char *userToPath, int mode)
|
2002-07-28 22:41:07 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char toPath[SYS_MAX_PATH_LEN + 1];
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t status;
|
2002-07-28 22:41:07 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath)
|
|
|
|
|| !IS_USER_ADDRESS(userToPath))
|
2002-07-28 22:41:07 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-07-28 22:41:07 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(toPath, userToPath, SYS_MAX_PATH_LEN);
|
2002-07-28 22:41:07 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = check_path(toPath);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
2002-08-05 09:37:17 +04:00
|
|
|
return common_create_symlink(path, toPath, mode, false);
|
2002-07-28 22:41:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_create_link(const char *userPath, const char *userToPath)
|
2002-08-14 00:39:25 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char toPath[SYS_MAX_PATH_LEN + 1];
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t status;
|
2002-08-14 00:39:25 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath)
|
|
|
|
|| !IS_USER_ADDRESS(userToPath))
|
2002-08-14 00:39:25 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-08-14 00:39:25 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(toPath, userToPath, SYS_MAX_PATH_LEN);
|
2002-08-14 00:39:25 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = check_path(toPath);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return common_create_link(path, toPath, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_unlink(const char *userPath)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-07-28 22:41:07 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
2002-08-13 17:51:36 +04:00
|
|
|
int status;
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath))
|
2002-08-13 17:51:36 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-08-13 17:51:36 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-20 04:16:12 +04:00
|
|
|
|
|
|
|
return common_unlink(path, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_rename(const char *userOldPath, const char *userNewPath)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char oldPath[SYS_MAX_PATH_LEN + 1];
|
|
|
|
char newPath[SYS_MAX_PATH_LEN + 1];
|
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userOldPath) || !IS_USER_ADDRESS(userNewPath))
|
2002-08-14 00:39:25 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(oldPath, userOldPath, SYS_MAX_PATH_LEN);
|
2002-08-14 00:39:25 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(newPath, userNewPath, SYS_MAX_PATH_LEN);
|
2002-08-14 00:39:25 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
return common_rename(oldPath, newPath, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_access(const char *userPath, int mode)
|
2002-08-13 17:51:36 +04:00
|
|
|
{
|
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
|
|
|
int status;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath))
|
2002-08-13 17:51:36 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
status = user_strlcpy(path, userPath, SYS_MAX_PATH_LEN);
|
2002-08-13 17:51:36 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return common_access(path, mode, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
status_t
|
|
|
|
_user_read_path_stat(const char *userPath, bool traverseLink, struct stat *userStat,
|
|
|
|
size_t statSize)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-03 06:03:27 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
2002-07-20 04:16:12 +04:00
|
|
|
struct stat stat;
|
2002-10-17 07:09:25 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
if (statSize > sizeof(struct stat))
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath)
|
|
|
|
|| !IS_USER_ADDRESS(userStat)
|
2002-10-17 07:09:25 +04:00
|
|
|
|| user_strlcpy(path, userPath, SYS_MAX_PATH_LEN) < B_OK)
|
2002-08-03 06:03:27 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
status = common_path_read_stat(path, traverseLink, &stat, false);
|
2004-05-10 18:33:17 +04:00
|
|
|
if (status < B_OK)
|
2002-10-17 07:09:25 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
return user_memcpy(userStat, &stat, statSize);
|
2002-07-20 04:16:12 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
status_t
|
|
|
|
_user_write_path_stat(const char *userPath, bool traverseLeafLink, const struct stat *userStat,
|
|
|
|
size_t statSize, int statMask)
|
2002-07-20 04:16:12 +04:00
|
|
|
{
|
2002-08-10 00:20:28 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN + 1];
|
2002-07-20 04:16:12 +04:00
|
|
|
struct stat stat;
|
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
if (statSize > sizeof(struct stat))
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userStat)
|
|
|
|
|| !IS_USER_ADDRESS(userPath)
|
2002-10-17 07:09:25 +04:00
|
|
|
|| user_strlcpy(path, userPath, SYS_MAX_PATH_LEN) < B_OK
|
2004-05-10 18:33:17 +04:00
|
|
|
|| user_memcpy(&stat, userStat, statSize) < B_OK)
|
2002-10-08 07:24:51 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-07-20 04:16:12 +04:00
|
|
|
|
2004-05-10 18:33:17 +04:00
|
|
|
// clear additional stat fields
|
|
|
|
if (statSize < sizeof(struct stat))
|
|
|
|
memset((uint8 *)&stat + statSize, 0, sizeof(struct stat) - statSize);
|
|
|
|
|
2002-10-17 07:09:25 +04:00
|
|
|
return common_path_write_stat(path, traverseLeafLink, &stat, statMask, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-08 07:24:51 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_open_attr_dir(int fd, const char *userPath)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
char pathBuffer[SYS_MAX_PATH_LEN + 1];
|
|
|
|
|
|
|
|
if (fd == -1) {
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath)
|
2002-10-08 07:24:51 +04:00
|
|
|
|| user_strlcpy(pathBuffer, userPath, SYS_MAX_PATH_LEN) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return attr_dir_open(fd, pathBuffer, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_create_attr(int fd, const char *userName, uint32 type, int openMode)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName)
|
2002-10-08 07:24:51 +04:00
|
|
|
|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return attr_create(fd, name, type, openMode, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_open_attr(int fd, const char *userName, int openMode)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName)
|
2002-10-08 07:24:51 +04:00
|
|
|
|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return attr_open(fd, name, openMode, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_remove_attr(int fd, const char *userName)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName)
|
2002-10-08 07:24:51 +04:00
|
|
|
|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return attr_remove(fd, name, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_rename_attr(int fromFile, const char *userFromName, int toFile, const char *userToName)
|
2002-10-08 07:24:51 +04:00
|
|
|
{
|
|
|
|
char fromName[B_FILE_NAME_LENGTH];
|
|
|
|
char toName[B_FILE_NAME_LENGTH];
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userFromName)
|
|
|
|
|| !IS_USER_ADDRESS(userToName))
|
2002-10-08 07:24:51 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
if (user_strlcpy(fromName, userFromName, B_FILE_NAME_LENGTH) < B_OK
|
|
|
|
|| user_strlcpy(toName, userToName, B_FILE_NAME_LENGTH) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return attr_rename(fromFile, fromName, toFile, toName, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-17 23:34:09 +04:00
|
|
|
int
|
2004-06-15 19:35:10 +04:00
|
|
|
_user_open_index_dir(dev_t device)
|
2002-10-17 23:34:09 +04:00
|
|
|
{
|
|
|
|
return index_dir_open(device, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_create_index(dev_t device, const char *userName, uint32 type, uint32 flags)
|
2002-10-17 23:34:09 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName)
|
2002-10-17 23:34:09 +04:00
|
|
|
|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return index_create(device, name, type, flags, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_read_index_stat(dev_t device, const char *userName, struct stat *userStat)
|
2002-10-17 23:34:09 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
struct stat stat;
|
|
|
|
status_t status;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName)
|
|
|
|
|| !IS_USER_ADDRESS(userStat)
|
2002-10-17 23:34:09 +04:00
|
|
|
|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
status = index_name_read_stat(device, name, &stat, false);
|
|
|
|
if (status == B_OK) {
|
|
|
|
if (user_memcpy(userStat, &stat, sizeof(stat)) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_remove_index(dev_t device, const char *userName)
|
2002-10-17 23:34:09 +04:00
|
|
|
{
|
|
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userName)
|
2002-10-17 23:34:09 +04:00
|
|
|
|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return index_remove(device, name, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_getcwd(char *userBuffer, size_t size)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-08-14 00:39:25 +04:00
|
|
|
char buffer[SYS_MAX_PATH_LEN];
|
2002-07-20 04:16:12 +04:00
|
|
|
int status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
PRINT(("user_getcwd: buf %p, %ld\n", userBuffer, size));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userBuffer))
|
2002-08-14 00:39:25 +04:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
if (size > SYS_MAX_PATH_LEN)
|
|
|
|
size = SYS_MAX_PATH_LEN;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
status = get_cwd(buffer, size, false);
|
2002-07-20 04:16:12 +04:00
|
|
|
if (status < 0)
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
// Copy back the result
|
2002-10-08 07:24:51 +04:00
|
|
|
if (user_strlcpy(userBuffer, buffer, size) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-07-20 04:16:12 +04:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:35:10 +04:00
|
|
|
status_t
|
|
|
|
_user_setcwd(int fd, const char *userPath)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-07-20 04:16:12 +04:00
|
|
|
char path[SYS_MAX_PATH_LEN];
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-10 00:20:28 +04:00
|
|
|
PRINT(("user_setcwd: path = %p\n", userPath));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-14 00:39:25 +04:00
|
|
|
if (fd == -1) {
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userPath)
|
2002-10-08 07:24:51 +04:00
|
|
|
|| user_strlcpy(path, userPath, SYS_MAX_PATH_LEN) < B_OK)
|
2002-08-10 00:20:28 +04:00
|
|
|
return B_BAD_ADDRESS;
|
2002-10-08 07:24:51 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-10 00:20:28 +04:00
|
|
|
return set_cwd(fd, path, false);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-20 04:16:12 +04:00
|
|
|
|