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
This commit is contained in:
Axel Dörfler 2004-05-03 00:00:57 +00:00
parent b166160684
commit b9523fa3ef
3 changed files with 385 additions and 0 deletions

View File

@ -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 <string.h>
#endif
#ifdef USER
# include <stdio.h>
# 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 <KernelExport.h>
#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 */

View File

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

View File

@ -0,0 +1,231 @@
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kprotos.h"
#include "argv.h"
#include <fs_attr.h>
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 <bfs-image> <source-files ...> <target>\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;
}