Patch by Raghuram Nagireddy:
Re-use the kernel emulation of the FS shell to implement a FUSE module for BFS. In theory, it could use any Haiku file system implementation just like the FS shell itself, but currently only the BFS code supports being compiled as an FS shell module. The build target is <build>bfs_fuse On Ubuntu, you would do this: sudo apt-get install libfuse-dev jam \<build\>bfs_fuse mkdir path/to/moundPoint path/to/bfs_fuse /dev/sdaX path/to/mountPoint And that will mount your BFS volume at /dev/sdaX read/write. As this is new code, you should be careful with your data and expect potential data loss. Not that I don't trust Raghu's code, but a warning is always better with such things. So far, my tests have been successful and it is great to finally have write support for BFS in Linux! Thanks a lot, Raghu, for your great work! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31409 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -32,8 +32,7 @@ if ! $(HOST_PLATFORM_BEOS_COMPATIBLE) {
|
||||
|
||||
UsePrivateHeaders fs_shell ;
|
||||
|
||||
BuildPlatformMain <build>bfs_shell
|
||||
:
|
||||
local bfsSource =
|
||||
bfs_disk_system.cpp
|
||||
BlockAllocator.cpp
|
||||
BPlusTree.cpp
|
||||
@@ -47,7 +46,20 @@ BuildPlatformMain <build>bfs_shell
|
||||
Volume.cpp
|
||||
|
||||
kernel_interface.cpp
|
||||
;
|
||||
|
||||
BuildPlatformMain <build>bfs_shell
|
||||
:
|
||||
$(bfsSource)
|
||||
|
||||
: <build>fs_shell.a $(libHaikuCompat) $(HOST_LIBSUPC++) $(HOST_LIBSTDC++)
|
||||
$(HOST_LIBROOT) $(fsShellCommandLibs)
|
||||
;
|
||||
|
||||
BuildPlatformMain <build>bfs_fuse
|
||||
:
|
||||
$(bfsSource)
|
||||
|
||||
: <build>fuse_module.a $(libHaikuCompat) $(HOST_LIBSUPC++) $(HOST_LIBSTDC++)
|
||||
$(HOST_LIBROOT) $(fsShellCommandLibs) fuse
|
||||
;
|
||||
|
||||
@@ -31,7 +31,7 @@ if $(HOST_PLATFORM_BEOS_COMPATIBLE) {
|
||||
fsShellCommandLibs = $(HOST_NETWORK_LIBS) ;
|
||||
}
|
||||
|
||||
BuildPlatformStaticLibrary <build>fs_shell.a :
|
||||
local kernelEmulationSources =
|
||||
atomic.cpp
|
||||
block_cache.cpp
|
||||
byte_order.cpp
|
||||
@@ -63,7 +63,17 @@ BuildPlatformStaticLibrary <build>fs_shell.a :
|
||||
uio.cpp
|
||||
unistd.cpp
|
||||
vfs.cpp
|
||||
;
|
||||
|
||||
BuildPlatformStaticLibrary <build>fuse_module.a :
|
||||
$(kernelEmulationSources)
|
||||
$(externalCommandsSources)
|
||||
|
||||
fuse.cpp
|
||||
;
|
||||
|
||||
BuildPlatformStaticLibrary <build>fs_shell.a :
|
||||
$(kernelEmulationSources)
|
||||
$(externalCommandsSources)
|
||||
|
||||
fssh.cpp
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* Copyright 2009, Raghuram Nagireddy <[email protected]>.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#define FUSE_USE_VERSION 27
|
||||
|
||||
#include <fuse/fuse.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fssh.h"
|
||||
|
||||
#include "driver_settings.h"
|
||||
#include "external_commands.h"
|
||||
#include "fd.h"
|
||||
#include "fssh_dirent.h"
|
||||
#include "fssh_errno.h"
|
||||
#include "fssh_errors.h"
|
||||
#include "fssh_fcntl.h"
|
||||
#include "fssh_fs_info.h"
|
||||
#include "fssh_module.h"
|
||||
#include "fssh_node_monitor.h"
|
||||
#include "fssh_stat.h"
|
||||
#include "fssh_string.h"
|
||||
#include "fssh_type_constants.h"
|
||||
#include "module.h"
|
||||
#include "syscalls.h"
|
||||
#include "vfs.h"
|
||||
|
||||
|
||||
extern fssh_module_info *modules[];
|
||||
|
||||
extern fssh_file_system_module_info gRootFileSystem;
|
||||
|
||||
namespace FSShell {
|
||||
|
||||
const char* kMountPoint = "/myfs";
|
||||
|
||||
static mode_t sUmask = 0022;
|
||||
|
||||
#define PRINTD(x) fprintf(stderr, x)
|
||||
|
||||
|
||||
static fssh_status_t
|
||||
init_kernel()
|
||||
{
|
||||
fssh_status_t error;
|
||||
|
||||
// init module subsystem
|
||||
error = module_init(NULL);
|
||||
if (error != FSSH_B_OK) {
|
||||
fprintf(stderr, "module_init() failed: %s\n", fssh_strerror(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// init driver settings
|
||||
error = driver_settings_init();
|
||||
if (error != FSSH_B_OK) {
|
||||
fprintf(stderr, "initializing driver settings failed: %s\n",
|
||||
fssh_strerror(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// register built-in modules, i.e. the rootfs and the client FS
|
||||
register_builtin_module(&gRootFileSystem.info);
|
||||
for (int i = 0; modules[i]; i++)
|
||||
register_builtin_module(modules[i]);
|
||||
|
||||
// init VFS
|
||||
error = vfs_init(NULL);
|
||||
if (error != FSSH_B_OK) {
|
||||
fprintf(stderr, "initializing VFS failed: %s\n", fssh_strerror(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// init kernel IO context
|
||||
gKernelIOContext = (io_context*)vfs_new_io_context(NULL);
|
||||
if (!gKernelIOContext) {
|
||||
fprintf(stderr, "creating IO context failed!\n");
|
||||
return FSSH_B_NO_MEMORY;
|
||||
}
|
||||
|
||||
// mount root FS
|
||||
fssh_dev_t rootDev = _kern_mount("/", NULL, "rootfs", 0, NULL, 0);
|
||||
if (rootDev < 0) {
|
||||
fprintf(stderr, "mounting rootfs failed: %s\n", fssh_strerror(rootDev));
|
||||
return rootDev;
|
||||
}
|
||||
|
||||
// set cwd to "/"
|
||||
error = _kern_setcwd(-1, "/");
|
||||
if (error != FSSH_B_OK) {
|
||||
fprintf(stderr, "setting cwd failed: %s\n", fssh_strerror(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// create mount point for the client FS
|
||||
error = _kern_create_dir(-1, kMountPoint, 0775);
|
||||
if (error != FSSH_B_OK) {
|
||||
fprintf(stderr, "creating mount point failed: %s\n",
|
||||
fssh_strerror(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
return FSSH_B_OK;
|
||||
}
|
||||
|
||||
static void fromFsshStatToStat (struct fssh_stat *f_stbuf, struct stat *stbuf)
|
||||
{
|
||||
stbuf->st_dev = f_stbuf->fssh_st_dev;
|
||||
stbuf->st_ino = f_stbuf->fssh_st_ino;
|
||||
stbuf->st_mode = f_stbuf->fssh_st_mode;
|
||||
stbuf->st_nlink = f_stbuf->fssh_st_nlink;
|
||||
stbuf->st_uid = f_stbuf->fssh_st_uid;
|
||||
stbuf->st_gid = f_stbuf->fssh_st_gid;
|
||||
stbuf->st_rdev = f_stbuf->fssh_st_rdev;
|
||||
stbuf->st_size = f_stbuf->fssh_st_size;
|
||||
stbuf->st_blksize = f_stbuf->fssh_st_blksize;
|
||||
stbuf->st_blocks = f_stbuf->fssh_st_blocks;
|
||||
stbuf->st_atime = f_stbuf->fssh_st_atime;
|
||||
stbuf->st_mtime = f_stbuf->fssh_st_mtime;
|
||||
stbuf->st_ctime = f_stbuf->fssh_st_ctime;
|
||||
}
|
||||
|
||||
#define _ERR(x) (-1*fssh_to_host_error(x))
|
||||
|
||||
|
||||
// pragma mark - FUSE functions
|
||||
|
||||
|
||||
//extern "C" {
|
||||
|
||||
|
||||
int
|
||||
fuse_getattr(const char* path, struct stat* stbuf)
|
||||
{
|
||||
PRINTD("##getattr\n");
|
||||
struct fssh_stat f_stbuf;
|
||||
fssh_status_t status = _kern_read_stat(-1, path, false, &f_stbuf,
|
||||
sizeof(f_stbuf));
|
||||
fromFsshStatToStat(&f_stbuf, stbuf);
|
||||
printf("GETATTR returned: %d\n", status);
|
||||
return _ERR(status);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_access(const char* path, int mask)
|
||||
{
|
||||
PRINTD("##access\n");
|
||||
return _ERR(_kern_access(path, mask));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_readlink(const char* path, char* buffer, size_t size)
|
||||
{
|
||||
PRINTD("##readlink\n");
|
||||
size_t n_size = size - 1;
|
||||
fssh_status_t st = _kern_read_link(-1, path, buffer, &n_size);
|
||||
if (st >= FSSH_B_OK)
|
||||
buffer[n_size] = '\0';
|
||||
return _ERR(st);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_readdir(const char* path, void* buf, fuse_fill_dir_t filler,
|
||||
off_t offset, struct fuse_file_info* fi)
|
||||
{
|
||||
PRINTD("##readdir\n");
|
||||
int dfp = _kern_open_dir(-1, path);
|
||||
if (dfp < FSSH_B_OK)
|
||||
return _ERR(dfp);
|
||||
|
||||
fssh_ssize_t entriesRead = 0;
|
||||
struct fssh_stat f_st;
|
||||
struct stat st;
|
||||
char buffer[sizeof(fssh_dirent) + FSSH_B_FILE_NAME_LENGTH];
|
||||
fssh_dirent* dirEntry = (fssh_dirent*)buffer;
|
||||
while ((entriesRead = _kern_read_dir(dfp, dirEntry,
|
||||
sizeof(buffer), 1)) == 1) {
|
||||
fssh_memset(&st, 0, sizeof(st));
|
||||
fssh_memset(&f_st, 0, sizeof(f_st));
|
||||
fssh_status_t status = _kern_read_stat(dfp, dirEntry->d_name,
|
||||
false, &f_st, sizeof(f_st));
|
||||
if (status >= FSSH_B_OK) {
|
||||
fromFsshStatToStat(&f_st, &st);
|
||||
if (filler(buf, dirEntry->d_name, &st, 0))
|
||||
break;
|
||||
}
|
||||
}
|
||||
_kern_close(dfp);
|
||||
//TODO: check _kern_close
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_mknod(const char* path, mode_t mode, dev_t rdev)
|
||||
{
|
||||
PRINTD("##mknod\n");
|
||||
if (S_ISREG(mode)) {
|
||||
int fd = _kern_open(-1, path,
|
||||
FSSH_O_CREAT | FSSH_O_EXCL | FSSH_O_WRONLY, mode);
|
||||
if (fd >= FSSH_B_OK)
|
||||
return _ERR(_kern_close(fd));
|
||||
return _ERR(fd);
|
||||
} else if (S_ISFIFO(mode))
|
||||
return _ERR(FSSH_EINVAL);
|
||||
else
|
||||
return _ERR(FSSH_EINVAL);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_mkdir(const char* path, mode_t mode)
|
||||
{
|
||||
PRINTD("##mkdir\n");
|
||||
return _ERR(_kern_create_dir(-1, path, mode));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_symlink(const char* from, const char* to)
|
||||
{
|
||||
PRINTD("##symlink\n");
|
||||
return _ERR(_kern_create_symlink(-1, from, to,
|
||||
FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_unlink(const char* path)
|
||||
{
|
||||
PRINTD("##unlink\n");
|
||||
return _ERR(_kern_unlink(-1, path));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_rmdir(const char* path)
|
||||
{
|
||||
PRINTD("##rmdir\n");
|
||||
return _ERR(_kern_remove_dir(-1, path));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_rename(const char* from, const char* to)
|
||||
{
|
||||
PRINTD("##rename\n");
|
||||
return _ERR(_kern_rename(-1, from, -1, to));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_link(const char* from, const char* to)
|
||||
{
|
||||
PRINTD("##link\n");
|
||||
return _ERR(_kern_create_link(from, to));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_chmod(const char* path, mode_t mode)
|
||||
{
|
||||
PRINTD("##chmod\n");
|
||||
fssh_struct_stat st;
|
||||
st.fssh_st_mode = mode;
|
||||
return _ERR(_kern_write_stat(-1, path, false, &st, sizeof(st),
|
||||
FSSH_B_STAT_MODE));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_chown(const char* path, uid_t uid, gid_t gid)
|
||||
{
|
||||
PRINTD("##chown\n");
|
||||
fssh_struct_stat st;
|
||||
st.fssh_st_uid = uid;
|
||||
st.fssh_st_gid = gid;
|
||||
return _ERR(_kern_write_stat(-1, path, false, &st, sizeof(st),
|
||||
FSSH_B_STAT_UID|FSSH_B_STAT_GID));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_open(const char* path, struct fuse_file_info* fi)
|
||||
{
|
||||
PRINTD("##open\n");
|
||||
// TODO: Do we have a syscall similar to the open syscall in linux which
|
||||
// takes only two args: path and flags with no mask/perms?
|
||||
int fd = _kern_open(-1, path, fi->flags,
|
||||
(FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask);
|
||||
_kern_close(fd);
|
||||
if (fd < FSSH_B_OK)
|
||||
return _ERR(fd);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_read(const char* path, char* buf, size_t size, off_t offset,
|
||||
struct fuse_file_info* fi)
|
||||
{
|
||||
PRINTD("##read\n");
|
||||
int fd = _kern_open(-1, path, FSSH_O_RDONLY,
|
||||
(FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask);
|
||||
if (fd < FSSH_B_OK)
|
||||
return _ERR(fd);
|
||||
|
||||
int res = _kern_read(fd, offset, buf, size);
|
||||
_kern_close(fd);
|
||||
if (res < FSSH_B_OK)
|
||||
res = _ERR(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fuse_write(const char* path, const char* buf, size_t size, off_t offset,
|
||||
struct fuse_file_info* fi)
|
||||
{
|
||||
PRINTD("##write\n");
|
||||
int fd = _kern_open(-1, path, FSSH_O_WRONLY,
|
||||
(FSSH_S_IRWXU | FSSH_S_IRWXG | FSSH_S_IRWXO) & ~sUmask);
|
||||
if (fd < FSSH_B_OK)
|
||||
return _ERR(fd);
|
||||
|
||||
int res = _kern_write(fd, offset, buf, size);
|
||||
_kern_close(fd);
|
||||
if (res < FSSH_B_OK)
|
||||
res = _ERR(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fuse_destroy(void* priv_data)
|
||||
{
|
||||
_kern_sync();
|
||||
}
|
||||
|
||||
|
||||
//} // extern "C" {
|
||||
|
||||
|
||||
struct fuse_operations fuse_cmds;
|
||||
|
||||
|
||||
static void
|
||||
initialiseFuseOps(struct fuse_operations* fuse_cmds)
|
||||
{
|
||||
fuse_cmds->getattr = fuse_getattr;
|
||||
fuse_cmds->access = fuse_access;
|
||||
fuse_cmds->readlink = fuse_readlink;
|
||||
fuse_cmds->readdir = fuse_readdir;
|
||||
fuse_cmds->mknod = fuse_mknod;
|
||||
fuse_cmds->mkdir = fuse_mkdir;
|
||||
fuse_cmds->symlink = fuse_symlink;
|
||||
fuse_cmds->unlink = fuse_unlink;
|
||||
fuse_cmds->rmdir = fuse_rmdir;
|
||||
fuse_cmds->rename = fuse_rename;
|
||||
fuse_cmds->link = fuse_link;
|
||||
fuse_cmds->chmod = fuse_chmod;
|
||||
fuse_cmds->chown = fuse_chown;
|
||||
fuse_cmds->truncate = NULL;
|
||||
fuse_cmds->utimens = NULL;
|
||||
fuse_cmds->open = fuse_open;
|
||||
fuse_cmds->read = fuse_read;
|
||||
fuse_cmds->write = fuse_write;
|
||||
fuse_cmds->statfs = NULL;
|
||||
fuse_cmds->release = NULL;
|
||||
fuse_cmds->fsync = NULL;
|
||||
fuse_cmds->destroy = fuse_destroy;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fssh_fuse_session(const char* device, const char* mntPoint, const char* fsName)
|
||||
{
|
||||
fssh_dev_t fsDev = _kern_mount(kMountPoint, device, fsName, 0, NULL, 0);
|
||||
if (fsDev < 0) {
|
||||
fprintf(stderr, "Error: Mounting FS failed: %s\n",
|
||||
fssh_strerror(fsDev));
|
||||
return 1;
|
||||
}
|
||||
const char* argv[5];
|
||||
argv[0] = (const char*)"bfs_shell";
|
||||
argv[1] = mntPoint;
|
||||
argv[2] = (const char*)"-d";
|
||||
argv[3] = (const char*)"-s";
|
||||
initialiseFuseOps(&fuse_cmds);
|
||||
return fuse_main(4, (char**)argv, &fuse_cmds, NULL);
|
||||
}
|
||||
|
||||
|
||||
} // namespace FSShell
|
||||
|
||||
|
||||
using namespace FSShell;
|
||||
|
||||
|
||||
static void
|
||||
print_usage_and_exit(const char* binName)
|
||||
{
|
||||
fprintf(stderr,"Usage: %s <device> <mount point>\n", binName);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, const char* const* argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
print_usage_and_exit(argv[0]);
|
||||
|
||||
const char* device = argv[1];
|
||||
const char* mntPoint = argv[2];
|
||||
|
||||
if (!modules[0]) {
|
||||
fprintf(stderr, "Error: Couldn't find FS module!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fssh_status_t error = init_kernel();
|
||||
if (error != FSSH_B_OK) {
|
||||
fprintf(stderr, "Error: Initializing kernel failed: %s\n",
|
||||
fssh_strerror(error));
|
||||
return error;
|
||||
}
|
||||
const char* fsName = modules[0]->name;
|
||||
return fssh_fuse_session(device, mntPoint, fsName);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
void*
|
||||
fssh_memchr(const void *source, int value, fssh_size_t length)
|
||||
{
|
||||
return memchr(source, value, length);
|
||||
return memchr((void*)source, value, length);
|
||||
}
|
||||
|
||||
|
||||
@@ -106,21 +106,21 @@ fssh_strncmp(const char *string1, const char *string2, fssh_size_t length)
|
||||
char*
|
||||
fssh_strchr(const char *string, int character)
|
||||
{
|
||||
return strchr(string, character);
|
||||
return strchr((char*)string, character);
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
fssh_strrchr(const char *string, int character)
|
||||
{
|
||||
return strrchr(string, character);
|
||||
return strrchr((char*)string, character);
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
fssh_strstr(const char *string, const char *searchString)
|
||||
{
|
||||
return strstr(string, searchString);
|
||||
return strstr((char*)string, searchString);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ fssh_strchrnul(const char *string, int character)
|
||||
char*
|
||||
fssh_strpbrk(const char *string, const char *set)
|
||||
{
|
||||
return strpbrk(string, set);
|
||||
return strpbrk((char*)string, set);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user