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