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:
parent
b166160684
commit
b9523fa3ef
103
src/tools/copy_to_bfs_image/Debug.h
Normal file
103
src/tools/copy_to_bfs_image/Debug.h
Normal 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 */
|
51
src/tools/copy_to_bfs_image/Jamfile
Normal file
51
src/tools/copy_to_bfs_image/Jamfile
Normal 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 ] ;
|
231
src/tools/copy_to_bfs_image/copy_to_bfs_image.cpp
Normal file
231
src/tools/copy_to_bfs_image/copy_to_bfs_image.cpp
Normal 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user