From b9523fa3efed4488389d5b13bf6e842dbc61140a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 3 May 2004 00:00:57 +0000 Subject: [PATCH] Wrote a simple tool to copy files to a BFS image from a shell. Internally, it uses the fs_shell offerings to provide that functionality. This tool allows to overcome the BeOS cache bug that happens as soon as you mount a file system image; when you write the files onto an image using this tool, you will be able to use it in Bochs (or other such uses) directly without a reboot. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7357 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/tools/copy_to_bfs_image/Debug.h | 103 ++++++++ src/tools/copy_to_bfs_image/Jamfile | 51 ++++ .../copy_to_bfs_image/copy_to_bfs_image.cpp | 231 ++++++++++++++++++ 3 files changed, 385 insertions(+) create mode 100644 src/tools/copy_to_bfs_image/Debug.h create mode 100644 src/tools/copy_to_bfs_image/Jamfile create mode 100644 src/tools/copy_to_bfs_image/copy_to_bfs_image.cpp diff --git a/src/tools/copy_to_bfs_image/Debug.h b/src/tools/copy_to_bfs_image/Debug.h new file mode 100644 index 0000000000..f518582f23 --- /dev/null +++ b/src/tools/copy_to_bfs_image/Debug.h @@ -0,0 +1,103 @@ +#ifndef DEBUG_H +#define DEBUG_H +/* Debug - debug stuff +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + +#ifdef DEBUG +# include +#endif + +#ifdef USER +# include +# define __out printf +#else +# define __out dprintf +#endif + +// Which debugger should be used when? +// The DEBUGGER() macro actually has no effect if DEBUG is not defined, +// use the DIE() macro if you really want to die. +#ifdef DEBUG +# ifdef USER +# define DEBUGGER(x) debugger x +# else +# define DEBUGGER(x) kernel_debugger x +# endif +#else +# define DEBUGGER(x) ; +#endif + +#ifdef USER +# define DIE(x) debugger x +#else +# define DIE(x) kernel_debugger x +#endif + +// Short overview over the debug output macros: +// PRINT() +// is for general messages that very unlikely should appear in a release build +// FATAL() +// this is for fatal messages, when something has really gone wrong +// INFORM() +// general information, as disk size, etc. +// REPORT_ERROR(status_t) +// prints out error information +// RETURN_ERROR(status_t) +// calls REPORT_ERROR() and return the value +// D() +// the statements in D() are only included if DEBUG is defined + +#include +#define kprintf printf +#define dprintf printf + +#ifdef DEBUG + #define PRINT(x) { __out("bfs@%ld: ", find_thread(NULL)); __out x; } + #define REPORT_ERROR(status) __out("bfs@%ld: %s:%s:%d: %s\n", find_thread(NULL), __FILE__, __FUNCTION__, __LINE__, strerror(status)); + #define RETURN_ERROR(err) { status_t _status = err; if (_status < B_OK) REPORT_ERROR(_status); return _status;} + #define FATAL(x) { __out("bfs@%ld: ", find_thread(NULL)); __out x; } + #define INFORM(x) { __out("bfs@%ld: ", find_thread(NULL)); __out x; } + #define FUNCTION() __out("bfs@%ld: %s:%s()\n", find_thread(NULL), __FILE__, __FUNCTION__); + #define FUNCTION_START(x) { __out("bfs@%ld: %s:%s() ", find_thread(NULL), __FILE__, __FUNCTION__); __out x; } +// #define FUNCTION() ; +// #define FUNCTION_START(x) ; + #define D(x) {x;}; + #define ASSERT(x) { if (!(x)) DEBUGGER(("bfs: assert failed: " #x "\n")); } +#else + #define PRINT(x) ; + #define REPORT_ERROR(status) ; + #define RETURN_ERROR(status) return status; + #define FATAL(x) { __out("bfs: "); __out x; } + #define INFORM(x) ; + #define FUNCTION() ; + #define FUNCTION_START(x) ; + #define D(x) ; + #define ASSERT(x) ; +#endif + +#ifdef DEBUG + struct block_run; + struct bplustree_header; + struct bplustree_node; + struct data_stream; + struct bfs_inode; + struct disk_super_block; + class Volume; + + // some structure dump functions + extern void dump_block_run(const char *prefix, block_run &run); + extern void dump_super_block(disk_super_block *superBlock); + extern void dump_data_stream(data_stream *stream); + extern void dump_inode(bfs_inode *inode); + extern void dump_bplustree_header(bplustree_header *header); + extern void dump_bplustree_node(bplustree_node *node,bplustree_header *header = NULL,Volume *volume = NULL); + extern void dump_block(const char *buffer, int size); + + extern void add_debugger_commands(); + extern void remove_debugger_commands(); +#endif + +#endif /* DEBUG_H */ diff --git a/src/tools/copy_to_bfs_image/Jamfile b/src/tools/copy_to_bfs_image/Jamfile new file mode 100644 index 0000000000..fcd9bf1cc2 --- /dev/null +++ b/src/tools/copy_to_bfs_image/Jamfile @@ -0,0 +1,51 @@ +SubDir OBOS_TOP src tools copy_to_bfs_image ; + +SubDirHdrs $(OBOS_TOP) src tests add-ons kernel file_systems fs_shell ; +SubDirHdrs $(OBOS_TOP) src add-ons kernel file_systems bfs ; + +UsePrivateHeaders [ FDirName kernel util ] ; # For kernel_cpp.cpp + +{ + # set CHECK_MALLOC to something when doing tests against memory corruption + local malloc_debug_defines ; + local malloc_debug_flags ; + if $(CHECK_MALLOC) { + malloc_debug_defines = _NO_INLINE_ASM ; + malloc_debug_flags = -fcheck-memory-usage ; + } + + local defines = [ FDefines USER + NO_FILE_UNCACHED_IO + UNSAFE_GET_VNODE + #BFS_BIG_ENDIAN_ONLY + $(malloc_debug_defines) ] ; + SubDirCcFlags $(defines) -fno-exceptions -fno-rtti $(malloc_debug_flags) ; + SubDirC++Flags $(defines) -fno-exceptions -fno-rtti $(malloc_debug_flags) -include [ FDirName $(SUBDIR) Debug.h ] ; + # we include our own Debug.h here to make BFS completely silent + # for non-fatal errors/messages +} + +BinCommand copy_to_bfs_image : + copy_to_bfs_image.cpp rootfs.c initfs.c kernel.c cache.c sl.c stub.c + sysdep.c hexdump.c argv.c + + Volume.cpp BPlusTree.cpp Inode.cpp Index.cpp Query.cpp Journal.cpp + BlockAllocator.cpp kernel_interface.cpp Utility.cpp BufferPool.cpp + Debug.cpp kernel_cpp.cpp + : + ; + +# Tell Jam where to find these sources +SEARCH on [ FGristFiles + Volume.cpp BPlusTree.cpp Inode.cpp Index.cpp Query.cpp Journal.cpp + BlockAllocator.cpp kernel_interface.cpp Utility.cpp BufferPool.cpp + Debug.cpp + ] = [ FDirName $(OBOS_TOP) src add-ons kernel file_systems bfs ] ; + +SEARCH on [ FGristFiles + kernel_cpp.cpp + ] = [ FDirName $(OBOS_TOP) src kernel core util ] ; + +SEARCH on [ FGristFiles + rootfs.c initfs.c kernel.c cache.c sl.c stub.c sysdep.c hexdump.c argv.c + ] = [ FDirName $(OBOS_TOP) src tests add-ons kernel file_systems fs_shell ] ; diff --git a/src/tools/copy_to_bfs_image/copy_to_bfs_image.cpp b/src/tools/copy_to_bfs_image/copy_to_bfs_image.cpp new file mode 100644 index 0000000000..38623e5f35 --- /dev/null +++ b/src/tools/copy_to_bfs_image/copy_to_bfs_image.cpp @@ -0,0 +1,231 @@ +/* +*/ + +#include +#include +#include + +#include "kprotos.h" +#include "argv.h" + +#include + + +static status_t +copy_file(const char *from, const char *to) +{ + size_t bufferSize = 4 * 1024; + char buffer[bufferSize]; + + int fd = open(from, O_RDONLY); + if (fd < 0) { + printf("can't open host file: %s\n", from); + return fd; + } + + int bfd = sys_open(1, -1, to, O_RDWR | O_CREAT, S_IFREG | S_IRWXU, 0); + if (bfd < 0) { + close(fd); + printf("error opening: %s\n", to); + return bfd; + } + + status_t err = B_OK; + DIR *attrDirectory; + dirent_t *attr; + + // copy attributes first! + if ((attrDirectory = fs_fopen_attr_dir(fd)) != NULL) { + while ((attr = fs_read_attr_dir(attrDirectory)) != NULL) { + struct attr_info attrInfo; + int32 size = bufferSize, bytesRead; + + if (fs_stat_attr(fd, attr->d_name, &attrInfo) != 0) + continue; + + if (attrInfo.size <= size) + size = attrInfo.size - 1; + else + printf("truncating attribute: %s\n", attr->d_name); + + bytesRead = fs_read_attr(fd, attr->d_name, attrInfo.type, 0, buffer, size); + if (bytesRead < size) { + printf("could not read attribute %s: %s\n", attr->d_name, strerror(bytesRead)); + continue; + } + buffer[size] = '\0'; + + err = sys_write_attr(1, bfd, attr->d_name, attrInfo.type, buffer, size, 0); + if (err < B_OK) { + printf("write attr (\"%s\", type = %p, %p, %ld bytes) failed: %s\n", + attr->d_name, (void *)attrInfo.type, buffer, size, strerror(err)); + continue; + } + } + fs_close_attr_dir(attrDirectory); + } else + puts("could not open attr-dir"); + + ssize_t amount; + while ((amount = read(fd, buffer, bufferSize)) == (ssize_t)bufferSize) { + err = sys_write(1, bfd, buffer, amount); + if (err < 0) + break; + } + + if (amount && err >= 0) + err = sys_write(1, bfd, buffer, amount); + + if (err < 0) + printf("write error: err == %ld, amount == %ld\n", err, amount); + + sys_close(1, bfd); + close(fd); + + return err; +} + + +static status_t +copy_dir(const char *fromPath, const char *toPath) +{ + int err = 0; + char fromName[B_PATH_NAME_LENGTH]; + DIR *from; + dirent_t *dirent; + + from = opendir(fromPath); + if (from == NULL) { + printf("could not open %s\n", fromPath); + return B_ENTRY_NOT_FOUND; + } + + while ((dirent = readdir(from)) != NULL) { + struct stat st; + + if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) + continue; + + strlcpy(fromName, fromPath, B_PATH_NAME_LENGTH); + if (fromName[strlen(fromName) - 1] != '/') + strlcat(fromName, "/", B_PATH_NAME_LENGTH); + strlcat(fromName, dirent->d_name, B_PATH_NAME_LENGTH); + + if (stat(fromName, &st) != 0) + continue; + + char path[B_PATH_NAME_LENGTH]; + strcpy(path, toPath); + strcat(path, "/"); + strcat(path, dirent->d_name); + + if (st.st_mode & S_IFDIR) { + char path[1024]; + + if ((err = sys_mkdir(1, -1, path, MY_S_IRWXU)) == B_OK) + copy_dir(fromName, path); + else + printf("Could not create directory %s: (%s)\n", path, strerror(err)); + } else { + copy_file(fromName, path); + } + } + closedir(from); + + return B_OK; +} + + +status_t +copy(const char *from, const char *to) +{ + // normalize target path + + char toPath[B_PATH_NAME_LENGTH]; + snprintf(toPath, sizeof(toPath), "/myfs/%s", to); + + // choose the correct copy mechanism + + struct stat fromStat; + if (stat(from, &fromStat) != 0) { + fprintf(stderr, "Could not stat \"%s\": %s\n", from, strerror(errno)); + return errno; + } + + struct stat toStat; + status_t status = sys_rstat(1, -1, toPath, &toStat, 1); + if (status != B_OK) { + fprintf(stderr, "Could not stat \"%s\": %s\n", to, strerror(status)); + return status; + } + + if (S_ISDIR(fromStat.st_mode)) { + if (S_ISREG(toStat.st_mode)) { + fprintf(stderr, "Target \"%s\" is not a directory\n.", to); + return B_NOT_A_DIRECTORY; + } + + return copy_dir(from, toPath); + } else { + if (S_ISREG(toStat.st_mode)) { + // overwrite target file + return copy_file(from, toPath); + } else { + // copy into target directory + strlcat(toPath, "/", B_PATH_NAME_LENGTH); + + const char *fileName = strrchr(from, '/'); + if (fileName == NULL) + fileName = from; + else + fileName++; + + strlcat(toPath, fileName, B_PATH_NAME_LENGTH); + + return copy_file(from, toPath); + } + } +} + + +void +usage(const char *programName) +{ + printf("usage: %s \n", programName); + exit(-1); +} + + +int +main(int argc, char **argv) +{ + const char *programName = strrchr(argv[0], '/'); + if (programName == NULL) + programName = argv[0]; + else + programName++; + + if (argc < 4) + usage(programName); + + char *image = argv[1]; + const char *target = argv[argc - 1]; + + init_fs(image); + + for (int32 i = 2; i < argc - 1; i++) { + printf("copy \"%s\" to \"%s\"\n", argv[i], target); + if (copy(argv[i], target) < B_OK) + break; + } + + if (sys_unmount(1, -1, "/myfs") != 0) { + printf("could not un-mount /myfs\n"); + return 5; + } + + shutdown_block_cache(); + + return 0; +} +