Added my updated version of Dominic's fsh.

Doesn't build as-is - the makefile is only provided as an example, if it
is used by file systems in the repository, they should build it in their
own test directories.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2961 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2003-03-19 17:50:50 +00:00
parent faa9239d5b
commit 9767c7befd
25 changed files with 10990 additions and 0 deletions
@@ -0,0 +1,100 @@
#ifndef DEBUG_H
#define DEBUG_H
/* Debug - debug stuff
**
** Initial version by Axel Dörfler, [email protected]
** 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: "); __out x; }
#define REPORT_ERROR(status) __out("bfs: %s:%s:%ld: %s\n", __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: "); __out x; }
#define INFORM(x) { __out("bfs: "); __out x; }
#define FUNCTION() __out("bfs: %s()\n",__FUNCTION__);
#define FUNCTION_START(x) { __out("bfs: %s() ",__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) { __out("bfs: "); __out 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);
#endif
#endif /* DEBUG_H */
@@ -0,0 +1,96 @@
/*
This file contains a function, build_argv(), which will take an input
string and chop it into individual words. The return value is an
argv style array (i.e. like what main() receives).
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "argv.h"
#define DOUBLE_QUOTE '"'
#define SINGLE_QUOTE '\''
#define BACK_SLASH '\\'
char **
build_argv(char *str, int *argc)
{
int table_size = 16, _argc;
char *ptr=str;
char **argv;
if (argc == NULL)
argc = &_argc;
*argc = 0;
argv = (char **)calloc(table_size, sizeof(char *));
if (argv == NULL)
return NULL;
while(*str) {
/* skip intervening white space */
while(*str != '\0' && (*str == ' ' || *str == '\t' || *str == '\n'))
str++;
if (*str == '\0')
break;
if (*str == DOUBLE_QUOTE) {
argv[*argc] = ++str;
while(*str && *str != DOUBLE_QUOTE) {
if (*str == BACK_SLASH)
strcpy(str, str+1); /* copy everything down */
str++;
}
} else if (*str == SINGLE_QUOTE) {
argv[*argc] = ++str;
while(*str && *str != SINGLE_QUOTE) {
if (*str == BACK_SLASH)
strcpy(str, str+1); /* copy everything down */
str++;
}
} else {
argv[*argc] = str;
while(*str && *str != ' ' && *str != '\t' && *str != '\n') {
if (*str == BACK_SLASH)
strcpy(str, str+1); /* copy everything down */
str++;
}
}
if (*str != '\0')
*str++ = '\0'; /* chop the string */
*argc = *argc + 1;
if (*argc >= table_size-1) {
char **nargv;
table_size = table_size * 2;
nargv = (char **)calloc(table_size, sizeof(char *));
if (nargv == NULL) { /* drats! failure. */
free(argv);
return NULL;
}
memcpy(nargv, argv, (*argc) * sizeof(char *));
free(argv);
argv = nargv;
}
}
return argv;
}
@@ -0,0 +1,2 @@
/* this function takes a string and chops it into individual "words" */
char **build_argv(char *str, int *argc);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,99 @@
#ifndef _CACHE_H_
#define _CACHE_H_
typedef struct hash_ent {
int dev;
fs_off_t bnum;
fs_off_t hash_val;
void *data;
struct hash_ent *next;
} hash_ent;
typedef struct hash_table {
hash_ent **table;
int max;
int mask; /* == max - 1 */
int num_elements;
} hash_table;
#define HT_DEFAULT_MAX 128
typedef struct cache_ent {
int dev;
fs_off_t block_num;
int bsize;
volatile int flags;
void *data;
void *clone; /* copy of data by set_block_info() */
int lock;
void (*func)(fs_off_t bnum, size_t num_blocks, void *arg);
fs_off_t logged_bnum;
void *arg;
struct cache_ent *next, /* points toward mru end of list */
*prev; /* points toward lru end of list */
} cache_ent;
#define CE_NORMAL 0x0000 /* a nice clean pristine page */
#define CE_DIRTY 0x0002 /* needs to be written to disk */
#define CE_BUSY 0x0004 /* this block has i/o happening, don't touch it */
typedef struct cache_ent_list {
cache_ent *lru; /* tail of the list */
cache_ent *mru; /* head of the list */
} cache_ent_list;
typedef struct block_cache {
struct lock lock;
int flags;
int cur_blocks;
int max_blocks;
hash_table ht;
cache_ent_list normal, /* list of "normal" blocks (clean & dirty) */
locked; /* list of clean and locked blocks */
} block_cache;
#define ALLOW_WRITES 1
#define NO_WRITES 0
extern int init_block_cache(int max_blocks, int flags);
extern void shutdown_block_cache(void);
extern void force_cache_flush(int dev, int prefer_log_blocks);
extern int flush_blocks(int dev, fs_off_t bnum, int nblocks);
extern int flush_device(int dev, int warn_locked);
extern int init_cache_for_device(int fd, fs_off_t max_blocks);
extern int remove_cached_device_blocks(int dev, int allow_write);
extern void *get_block(int dev, fs_off_t bnum, int bsize);
extern void *get_empty_block(int dev, fs_off_t bnum, int bsize);
extern int release_block(int dev, fs_off_t bnum);
extern int mark_blocks_dirty(int dev, fs_off_t bnum, int nblocks);
extern int cached_read(int dev, fs_off_t bnum, void *data,
fs_off_t num_blocks, int bsize);
extern int cached_write(int dev, fs_off_t bnum, const void *data,
fs_off_t num_blocks, int bsize);
extern int cached_write_locked(int dev, fs_off_t bnum, const void *data,
fs_off_t num_blocks, int bsize);
extern int set_blocks_info(int dev, fs_off_t *blocks, int nblocks,
void (*func)(fs_off_t bnum, size_t nblocks, void *arg),
void *arg);
extern size_t read_phys_blocks (int fd, fs_off_t bnum, void *data,
uint num_blocks, int bsize);
extern size_t write_phys_blocks(int fd, fs_off_t bnum, void *data,
uint num_blocks, int bsize);
#endif /* _CACHE_H_ */
@@ -0,0 +1,204 @@
/*
This file contains some kit-wide typedefs and structs that basically
emulate most of a normal posix-y type system. The purpose of hiding
everything behind these typedefs is to avoid inconsistencies between
various systems (such as the difference in size between off_t on BeOS
and some versions of Unix). To further avoid complications I've also
hidden the stat and dirent structs since those vary even more widely.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#ifndef _COMPAT_H
#define _COMPAT_H
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <memory.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#ifdef __BEOS__
#include <OS.h> /* for typedefs and prototypes */
#include <image.h> /* for a few typedefs */
#include <Drivers.h> /* for various ioctl structs, etc */
#include <iovec.h> /* because we're boneheads sometimes */
#else
#include <sys/uio.h>
#endif
/*
By default (for portability reasons) the size of off_t's and ino_t's
is 32-bit. You can change the file system to be 64-bit if you want
by defining OFF_T_SIZE to be 8.
NOTE: if you change the size of OFF_T_SIZE to be 8 you will have to
go through the code and change any calls to printf() to use the
appropriate format for 64-bit integers on your OS. I have seen
4 different formats now: %Ld (BeOS and Linux), %qd (FreeBSD),
%lld (Irix) and %I64d (NT).
*/
#define OFF_T_SIZE 8
#if OFF_T_SIZE == 4
typedef long fs_off_t;
typedef long my_ino_t;
#elif OFF_T_SIZE == 8
typedef long long fs_off_t;
typedef long long my_ino_t;
#else
#error OFF_T_SIZE must be either 4 or 8.
#endif
typedef int my_dev_t;
typedef int my_mode_t;
typedef int my_uid_t;
typedef int my_gid_t;
/* This is the maximum length of a file name. Adjust it as you see fit */
#define FILE_NAME_LENGTH 256
/* This is maximum name size for naming a volume or semaphore/lock */
#define IDENT_NAME_LENGTH 32
typedef struct my_dirent {
my_dev_t d_dev;
my_ino_t d_ino;
unsigned short d_reclen;
char d_name[1];
} my_dirent_t;
typedef struct {
int fd;
struct my_dirent ent;
} MY_DIR;
/*
This is a pretty regular stat structure but it's our "internal"
version since if we depended on the host version we'd be exposed
to all sorts of nasty things (different sized ino_t's, etc).
We also can't use the normal naming style of "st_" for each field
name because on some systems fields like st_atime are really just
define's that expand to all sorts of weird stuff.
*/
struct my_stat {
my_dev_t dev; /* "device" that this file resides on */
my_ino_t ino; /* this file's inode #, unique per device */
my_mode_t mode; /* mode bits (rwx for user, group, etc) */
int nlink; /* number of hard links to this file */
my_uid_t uid; /* user id of the owner of this file */
my_gid_t gid; /* group id of the owner of this file */
fs_off_t size; /* size in bytes of this file */
size_t blksize; /* preferred block size for i/o */
time_t atime; /* last access time */
time_t mtime; /* last modification time */
time_t ctime; /* last change time, not creation time */
time_t crtime; /* creation time; not posix but useful */
};
#define MY_S_IFMT 00000170000 /* type of file */
#define MY_S_IFLNK 00000120000 /* symbolic link */
#define MY_S_IFREG 00000100000 /* regular */
#define MY_S_IFBLK 00000060000 /* block special */
#define MY_S_IFDIR 00000040000 /* directory */
#define MY_S_IFCHR 00000020000 /* character special */
#define MY_S_IFIFO 00000010000 /* fifo */
#define MY_S_ISREG(m) (((m) & MY_S_IFMT) == MY_S_IFREG)
#define MY_S_ISLNK(m) (((m) & MY_S_IFMT) == MY_S_IFLNK)
#define MY_S_ISBLK(m) (((m) & MY_S_IFMT) == MY_S_IFBLK)
#define MY_S_ISDIR(m) (((m) & MY_S_IFMT) == MY_S_IFDIR)
#define MY_S_ISCHR(m) (((m) & MY_S_IFMT) == MY_S_IFCHR)
#define MY_S_ISFIFO(m) (((m) & MY_S_IFMT) == MY_S_IFIFO)
#define MY_S_IUMSK 07777 /* user settable bits */
#define MY_S_ISUID 04000 /* set user id on execution */
#define MY_S_ISGID 02000 /* set group id on execution */
#define MY_S_ISVTX 01000 /* save swapped text even after use */
#define MY_S_IRWXU 00700 /* read, write, execute: owner */
#define MY_S_IRUSR 00400 /* read permission: owner */
#define MY_S_IWUSR 00200 /* write permission: owner */
#define MY_S_IXUSR 00100 /* execute permission: owner */
#define MY_S_IRWXG 00070 /* read, write, execute: group */
#define MY_S_IRGRP 00040 /* read permission: group */
#define MY_S_IWGRP 00020 /* write permission: group */
#define MY_S_IXGRP 00010 /* execute permission: group */
#define MY_S_IRWXO 00007 /* read, write, execute: other */
#define MY_S_IROTH 00004 /* read permission: other */
#define MY_S_IWOTH 00002 /* write permission: other */
#define MY_S_IXOTH 00001 /* execute permission: other */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef __BEOS__
typedef long sem_id;
typedef unsigned char uchar;
typedef short int16;
typedef unsigned short uint16;
typedef int int32;
typedef unsigned int uint32;
#define ulong unsigned long /* make it a #define to avoid conflicts */
typedef long long int64;
typedef unsigned long long uint64;
typedef unsigned int port_id;
typedef int bool;
typedef int image_id;
typedef long long bigtime_t;
typedef long thread_id;
typedef long status_t;
sem_id create_sem(long count, const char *name);
long delete_sem(sem_id sem);
long acquire_sem(sem_id sem);
long acquire_sem_etc(sem_id sem, int count, int flags,
bigtime_t microsecond_timeout);
long release_sem(sem_id sem);
long release_sem_etc(sem_id sem, long count, long flags);
long atomic_add(long *value, long addvalue);
int snooze(bigtime_t f);
bigtime_t system_time(void);
ssize_t read_pos(int fd, fs_off_t _pos, void *data, size_t nbytes);
ssize_t write_pos(int fd, fs_off_t _pos, const void *data, size_t nbytes);
ssize_t readv_pos(int fd, fs_off_t _pos, struct iovec *iov, int count);
ssize_t writev_pos(int fd, fs_off_t _pos, struct iovec *iov, int count);
#endif /* __BEOS__ */
void panic(const char *msg, ...);
int device_is_read_only(const char *device);
int get_device_block_size(int fd);
fs_off_t get_num_device_blocks(int fd);
int device_is_removeable(int fd);
int lock_removeable_device(int fd, bool on_or_off);
void hexdump(void *address, int size);
#endif /* _COMPAT_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,265 @@
/*
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef _FSPROTO_H
#define _FSPROTO_H
#include <sys/dirent.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iovec.h>
#include <OS.h>
#include <fs_attr.h>
#include <fs_info.h>
#include <BeBuild.h>
#include <Drivers.h>
#include "compat.h"
typedef dev_t nspace_id;
typedef ino_t vnode_id;
/*
* PUBLIC PART OF THE FILE SYSTEM PROTOCOL
*/
#define WSTAT_MODE 0x0001
#define WSTAT_UID 0x0002
#define WSTAT_GID 0x0004
#define WSTAT_SIZE 0x0008
#define WSTAT_ATIME 0x0010
#define WSTAT_MTIME 0x0020
#define WSTAT_CRTIME 0x0040
#define WFSSTAT_NAME 0x0001
#define B_ENTRY_CREATED 1
#define B_ENTRY_REMOVED 2
#define B_ENTRY_MOVED 3
#define B_STAT_CHANGED 4
#define B_ATTR_CHANGED 5
#define B_DEVICE_MOUNTED 6
#define B_DEVICE_UNMOUNTED 7
#define B_STOP_WATCHING 0x0000
#define B_WATCH_NAME 0x0001
#define B_WATCH_STAT 0x0002
#define B_WATCH_ATTR 0x0004
#define B_WATCH_DIRECTORY 0x0008
#define SELECT_READ 1
#define SELECT_WRITE 2
#define SELECT_EXCEPTION 3
// missing ioctl() call added
#define IOCTL_FILE_UNCACHED_IO 10000
#define IOCTL_CREATE_TIME 10002
#define IOCTL_MODIFIED_TIME 10003
// B_CUR_FS_API_VERSION is 2 for R5, but 3 on Dano, because of the
// added calls for power management - so it's set to 3 here because
// that's a requirement to let Dano boot from our fs...
#ifdef B_BEOS_VERSION_DANO
# define B_CUR_FS_API_VERSION 3
#else
# define B_CUR_FS_API_VERSION 2
#endif
struct attr_info;
struct index_info;
typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node);
typedef int op_write_vnode(void *ns, void *node, char r);
typedef int op_remove_vnode(void *ns, void *node, char r);
typedef int op_secure_vnode(void *ns, void *node);
typedef int op_wake_vnode(void *ns, void *node);
typedef int op_suspend_vnode(void *ns, void *node);
typedef int op_walk(void *ns, void *base, const char *file, char **newpath,
vnode_id *vnid);
typedef int op_access(void *ns, void *node, int mode);
typedef int op_create(void *ns, void *dir, const char *name,
int omode, int perms, vnode_id *vnid, void **cookie);
typedef int op_mkdir(void *ns, void *dir, const char *name, int perms);
typedef int op_symlink(void *ns, void *dir, const char *name,
const char *path);
typedef int op_link(void *ns, void *dir, const char *name, void *node);
typedef int op_rename(void *ns, void *olddir, const char *oldname,
void *newdir, const char *newname);
typedef int op_unlink(void *ns, void *dir, const char *name);
typedef int op_rmdir(void *ns, void *dir, const char *name);
typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize);
typedef int op_opendir(void *ns, void *node, void **cookie);
typedef int op_closedir(void *ns, void *node, void *cookie);
typedef int op_rewinddir(void *ns, void *node, void *cookie);
typedef int op_readdir(void *ns, void *node, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_open(void *ns, void *node, int omode, void **cookie);
typedef int op_close(void *ns, void *node, void *cookie);
typedef int op_free_cookie(void *ns, void *node, void *cookie);
typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf,
size_t *len);
typedef int op_write(void *ns, void *node, void *cookie, off_t pos,
const void *buf, size_t *len);
typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
size_t count, size_t *len);
typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
size_t count, size_t *len);
typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf,
size_t len);
typedef int op_setflags(void *ns, void *node, void *cookie, int flags);
typedef int op_rstat(void *ns, void *node, struct stat *);
typedef int op_wstat(void *ns, void *node, struct stat *, long mask);
typedef int op_fsync(void *ns, void *node);
typedef int op_select(void *ns, void *node, void *cookie, uint8 event,
uint32 ref, selectsync *sync);
typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event,
selectsync *sync);
typedef int op_initialize(const char *devname, void *parms, size_t len);
typedef int op_mount(nspace_id nsid, const char *devname, ulong flags,
void *parms, size_t len, void **data, vnode_id *vnid);
typedef int op_unmount(void *ns);
typedef int op_sync(void *ns);
typedef int op_rfsstat(void *ns, struct fs_info *);
typedef int op_wfsstat(void *ns, struct fs_info *, long mask);
typedef int op_open_attrdir(void *ns, void *node, void **cookie);
typedef int op_close_attrdir(void *ns, void *node, void *cookie);
typedef int op_rewind_attrdir(void *ns, void *node, void *cookie);
typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_remove_attr(void *ns, void *node, const char *name);
typedef int op_rename_attr(void *ns, void *node, const char *oldname,
const char *newname);
typedef int op_stat_attr(void *ns, void *node, const char *name,
struct attr_info *buf);
typedef int op_write_attr(void *ns, void *node, const char *name, int type,
const void *buf, size_t *len, off_t pos);
typedef int op_read_attr(void *ns, void *node, const char *name, int type,
void *buf, size_t *len, off_t pos);
typedef int op_open_indexdir(void *ns, void **cookie);
typedef int op_close_indexdir(void *ns, void *cookie);
typedef int op_rewind_indexdir(void *ns, void *cookie);
typedef int op_read_indexdir(void *ns, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef int op_create_index(void *ns, const char *name, int type, int flags);
typedef int op_remove_index(void *ns, const char *name);
typedef int op_rename_index(void *ns, const char *oldname,
const char *newname);
typedef int op_stat_index(void *ns, const char *name, struct index_info *buf);
typedef int op_open_query(void *ns, const char *query, ulong flags,
port_id port, long token, void **cookie);
typedef int op_close_query(void *ns, void *cookie);
typedef int op_read_query(void *ns, void *cookie, long *num,
struct dirent *buf, size_t bufsize);
typedef struct vnode_ops {
op_read_vnode (*read_vnode);
op_write_vnode (*write_vnode);
op_remove_vnode (*remove_vnode);
op_secure_vnode (*secure_vnode);
op_walk (*walk);
op_access (*access);
op_create (*create);
op_mkdir (*mkdir);
op_symlink (*symlink);
op_link (*link);
op_rename (*rename);
op_unlink (*unlink);
op_rmdir (*rmdir);
op_readlink (*readlink);
op_opendir (*opendir);
op_closedir (*closedir);
op_free_cookie (*free_dircookie);
op_rewinddir (*rewinddir);
op_readdir (*readdir);
op_open (*open);
op_close (*close);
op_free_cookie (*free_cookie);
op_read (*read);
op_write (*write);
op_readv (*readv);
op_writev (*writev);
op_ioctl (*ioctl);
op_setflags (*setflags);
op_rstat (*rstat);
op_wstat (*wstat);
op_fsync (*fsync);
op_initialize (*initialize);
op_mount (*mount);
op_unmount (*unmount);
op_sync (*sync);
op_rfsstat (*rfsstat);
op_wfsstat (*wfsstat);
op_select (*select);
op_deselect (*deselect);
op_open_indexdir (*open_indexdir);
op_close_indexdir (*close_indexdir);
op_free_cookie (*free_indexdircookie);
op_rewind_indexdir (*rewind_indexdir);
op_read_indexdir (*read_indexdir);
op_create_index (*create_index);
op_remove_index (*remove_index);
op_rename_index (*rename_index);
op_stat_index (*stat_index);
op_open_attrdir (*open_attrdir);
op_close_attrdir (*close_attrdir);
op_free_cookie (*free_attrdircookie);
op_rewind_attrdir (*rewind_attrdir);
op_read_attrdir (*read_attrdir);
op_write_attr (*write_attr);
op_read_attr (*read_attr);
op_remove_attr (*remove_attr);
op_rename_attr (*rename_attr);
op_stat_attr (*stat_attr);
op_open_query (*open_query);
op_close_query (*close_query);
op_free_cookie (*free_querycookie);
op_read_query (*read_query);
// for Dano compatibility only
op_wake_vnode (*wake_vnode);
op_suspend_vnode (*suspend_vnode);
} vnode_ops;
extern _IMPEXP_KERNEL int new_path(const char *path, char **copy);
extern _IMPEXP_KERNEL void free_path(char *p);
extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid,
vnode_id vnida, vnode_id vnidb,
vnode_id vnidc, const char *name);
extern _IMPEXP_KERNEL void notify_select_event(selectsync *sync, uint32 ref);
extern _IMPEXP_KERNEL int send_notification(port_id port, long token,
ulong what, long op, nspace_id nsida,
nspace_id nsidb, vnode_id vnida,
vnode_id vnidb, vnode_id vnidc,
const char *name);
extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data);
extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid);
extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data);
extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid);
extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid);
extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid);
extern _EXPORT vnode_ops fs_entry;
extern _EXPORT int32 api_version;
#endif
@@ -0,0 +1,125 @@
/*
This file contains a simple hex dump routine.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include <stdio.h>
#include <ctype.h>
#include "compat.h"
/*
* This routine is a simple memory dumper. It's nice and simple, and works
* well.
*
* The bad things about it are that it assumes roughly an 80 column output
* device and that output is fixed at BYTES_PER_LINE/2 columns (separated
* every two bytes).
*
* Obviously the bad things are fixable, but I don't need the extra
* flexibility at the moment, so I don't feel like doing it.
*
* Dominic Giampaolo
* ([email protected])
*/
#define BYTES_PER_LINE 16 /* a reasonable power of two */
void hexdump(void *address, int size)
{
int i;
int offset, num_spaces;
unsigned char *mem, *tmp;
offset = 0;
mem = (unsigned char *)address;
/*
* Each line contains BYTES_PER_LINE bytes of data (presently 16). I
* chose 16 because it is a nice power of two and makes reading the
* hex offset column much easier. I used to use a value of 18 to fit
* more info on the screen, and 20 is also doable but much too crowded.
* Ideally it should be an argument or settable parameter...
*
* The data is formatted into BYTES_PER_LINE/2 (8) columns of 2 bytes
* each (printed in hex).
*
* The offset is formatted as a 4 byte hex number (i.e. 8 characters).
*/
while(offset < size)
{
printf("%.8x: ", offset);
for(i=0,tmp=mem; i < BYTES_PER_LINE && (offset+i) < size; i++,tmp++)
{
printf("%.2x", *tmp);
if (((i+1) % 4) == 0)
printf(" ");
}
/*
* This formula for the number of spaces to print is as follows:
* 10 is the number of characters printed at the beginning of
* the line (8 hex digits, the colon and a space).
* i*2 is the number of characters of data we dumped in hex.
* i/2 is the number of blanks we printed between columns.
* i is the number of bytes we will print in ascii.
*
* Then we subtract all that from 74 (the width of the output
* device) to decide how many spaces we need to push the ascii
* column as far to the right as possible.
*
* The number 58 is the column where we start we start printing
* the ascii dump. We subtract how many characters we've already
* printed and that gets us to where we need to be to start the
* ascii portion of the dump.
*
*/
num_spaces = 58 - (12 + i*2 + i/4);
for(i=0; i < num_spaces; i++)
printf(" ");
for(i=0,tmp=mem; i < BYTES_PER_LINE && (offset+i) < size; i++, tmp++)
if (isprint(*tmp))
printf("%c", *tmp);
else
printf(".");
printf("\n");
offset += BYTES_PER_LINE;
mem = tmp;
}
}
#ifdef TEST
char buff[] = "!blah, blah blah blah blah asldfj lkasjdf lka lkjasdflasdlj"
"asdj lasdfj lasdjf lasdjf lkasjdfl kjasdlf jasldfj lasdfj l"
"asdjflkasjdflk;ja sdfljasdfjk asjkfl;kasjfl;asjdfl;azzzzzzz";
main(int argc, char **argv)
{
int i,j,k;
FILE *fp;
hexdump(buff, 171);
printf("---------\n");
hexdump(main, 57);
}
#endif /* TEST */
@@ -0,0 +1,51 @@
/*
This file contains some glue code that initializes the block cache,
the vnode layer, mounts the root file system (a simple container)
and then mounts our file system at the mount point /myfs. You could
modify this to mount other file systems or even multiple file systems
if you wanted.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include <stdio.h>
#include <stdlib.h>
#include "compat.h"
#include "fsproto.h"
#include "kprotos.h"
extern vnode_ops fs_entry;
void *
init_fs(char *disk_name)
{
int err;
void *data = NULL;
init_block_cache(16348, 0);
init_vnode_layer();
err = sys_mkdir(1, -1, "/myfs", 0);
if (install_file_system(&fs_entry, "myfs", 1, -1) == NULL) {
printf("can't install my file system\n");
exit(0);
}
data = sys_mount(1, "myfs", -1, "/myfs", disk_name, 0, NULL, 0);
if (data == NULL) {
printf("could not mount %s on /myfs\n", disk_name);
exit(0);
}
return data;
}
@@ -0,0 +1 @@
void *init_fs(char *disk_name);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,52 @@
#define my_stat stat
#define my_dirent dirent
int sys_symlink(bool kernel, const char *oldpath, int nfd,
const char *newpath);
ssize_t sys_readlink(bool kernel, int fd, const char *path, char *buf,
size_t bufsize);
int sys_mkdir(bool kernel, int fd, const char *path, int perms);
int sys_open(bool kernel, int fd, const char *path, int omode,
int perms, bool coe);
int sys_close(bool kernel, int fd);
fs_off_t sys_lseek(bool kernel, int fd, fs_off_t pos, int whence);
ssize_t sys_read(bool kernel, int fd, void *buf, size_t len);
ssize_t sys_write(bool kernel, int fd, void *buf, size_t len);
int sys_ioctl(bool kernel, int fd, int cmd, void *arg, size_t sz);
int sys_unlink(bool kernel, int fd, const char *path);
int sys_link(bool kernel, int ofd, const char *oldpath, int nfd,
const char *newpath);
int sys_rmdir(bool kernel, int fd, const char *path);
int sys_rename(bool glb, int fd, const char *oldpath,
int nfd, const char *newpath);
void *sys_mount(bool kernel, const char *filesystem, int fd,
const char *where, const char *device, ulong flags,
void *parms, size_t len);
int sys_unmount(bool kernel, int fd, const char *where);
int sys_rstat(bool kernel, int fd, const char *path, struct my_stat *st,
bool eatlink);
int sys_wstat(bool kernel, int fd, const char *path, struct my_stat *st,
long mask, bool eatlink);
int sys_ioctl(bool kernel, int fd, int cmd, void *arg, size_t sz);
int sys_opendir(bool kernel, int fd, const char *path, bool coe);
int sys_readdir(bool kernel, int fd, struct my_dirent *buf, size_t bufsize,
long count);
int sys_rewinddir(bool kernel, int fd);
int sys_closedir(bool kernel, int fd);
int sys_chdir(bool kernel, int fd, const char *path);
int sys_access(bool kernel, int fd, const char *path, int mode);
int sys_sync(void);
ssize_t sys_read_attr(bool kernel, int fd, const char *name, int type, void *buffer, size_t len, off_t pos);
ssize_t sys_write_attr(bool kernel, int fd, const char *name, int type, void *buffer, size_t len, off_t pos);
ssize_t sys_remove_attr(bool kernel, int fd, const char *name);
int sys_open_query(bool kernel, int fd, const char *path, const char *query, void **cookie);
int sys_close_query(bool kernel, int fd, const char *path, void *cookie);
int sys_read_query(bool kernel, int fd, const char *path, void *cookie,struct dirent *dent,size_t bufferSize,long num);
int init_vnode_layer(void);
void *install_file_system(vnode_ops *ops, const char *name,
bool fixed, image_id aid);
@@ -0,0 +1,28 @@
#ifndef _LOCK_H
#define _LOCK_H
typedef struct lock lock;
typedef struct mlock mlock;
struct lock {
sem_id s;
long c;
};
struct mlock {
sem_id s;
};
extern int new_lock(lock *l, const char *name);
extern int free_lock(lock *l);
#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s);
#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s);
extern int new_mlock(mlock *l, long c, const char *name);
extern int free_mlock(mlock *l);
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0.0)
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
#endif
@@ -0,0 +1,65 @@
TARGETS = fsh tstfs
all : $(TARGETS)
zip:
zip -y obfs-fskit-`date +%Y-%m-%d`.zip *.[ch]* makefile
#
# change the -O7 to -O3 if your compiler doesn't grok -O7
#
DEFINES = -DUSER=1 -DDEBUG=1
CFLAGS = -D_NO_INLINE_ASM -O0 -g -fno-exceptions -fno-rtti -I. -fcheck-memory-usage
LDFLAGS = #-p
SUPPORT_OBJS = rootfs.o initfs.o kernel.o cache.o sl.o stub.o
MISC_OBJS = sysdep.o hexdump.o argv.o
FS_OBJS = Volume.o BPlusTree.o Inode.o Index.o Query.o Journal.o \
BlockAllocator.o kernel_interface.o Utility.o Debug.o BufferPool.o cpp.o
fsh : fsh.o $(FS_OBJS) $(SUPPORT_OBJS) $(MISC_OBJS)
cc $(LDFLAGS) -o $@ fsh.o $(FS_OBJS) $(SUPPORT_OBJS) $(MISC_OBJS)
tstfs : tstfs.o $(FS_OBJS) $(SUPPORT_OBJS) $(MISC_OBJS)
cc $(LDFLAGS) -o $@ tstfs.o $(FS_OBJS) $(SUPPORT_OBJS) $(MISC_OBJS)
makefs : makefs.o $(FS_OBJS) $(SUPPORT_OBJS) $(MISC_OBJS)
cc $(LDFLAGS) -o $@ makefs.o $(FS_OBJS) $(SUPPORT_OBJS) $(MISC_OBJS)
.c.o:
$(CC) -c $(DEFINES) $(CFLAGS) -o $@ $<
.cpp.o:
$(CC) -c $(DEFINES) $(CFLAGS) -o $@ $<
#makefs.o : makefs.c bfs.h
fsh.o : fsh.c bfs.h
tstfs.o : tstfs.c bfs.h
# mount.o : mount.c myfs.h
# journal.o : journal.c myfs.h
# bitmap.o : bitmap.c myfs.h
# inode.o : inode.c myfs.h
# dstream.o : dstream.c myfs.h
# dir.o : dir.c myfs.h
# file.o : file.c myfs.h
# bitvector.o : bitvector.c bitvector.h
# util.o : util.c myfs.h
#
bfs.h : compat.h cache.h lock.h fsproto.h
sysdep.o : sysdep.c compat.h
kernel.o : kernel.c compat.h fsproto.h kprotos.h
rootfs.o : compat.h fsproto.h
initfs.o : initfs.c compat.h fsproto.h
sl.o : sl.c skiplist.h
cache.o : cache.c cache.h compat.h
stub.o : stub.c compat.h
clean:
rm -f *.o $(TARGETS)
@@ -0,0 +1,82 @@
/*
This file contains the code that will call the initialization routine
for a file system (which in turn will initialize the file system). It
also has to do a few other housekeeping chores to make sure that the
file system is unmounted properly and all that.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include "myfs.h"
#include "kprotos.h"
static int
get_value(char *str)
{
char buff[128];
printf("%s: ", str); fflush(stdout);
fgets(buff, sizeof(buff), stdin);
return strtol(buff, NULL, 0);
}
int
main(int argc, char **argv)
{
int block_size = 1024, i;
char *disk_name = "big_file";
char *volume_name = "untitled";
myfs_info *myfs;
for (i=1; i < argc; i++) {
if (isdigit(argv[i][0])) {
block_size = strtoul(argv[i], NULL, 0);
} else if (disk_name == NULL) {
disk_name = argv[i];
} else {
volume_name = argv[i];
}
}
if (disk_name == NULL) {
fprintf(stderr, "makefs error: you must specify a file name that\n");
fprintf(stderr, " will contain the file systemn");
exit(5);
}
init_block_cache(256, 0);
myfs = myfs_create_fs(disk_name, volume_name, block_size, NULL);
if (myfs != NULL)
printf("MYFS w/%d byte blocks successfully created on %s as %s\n",
block_size, disk_name, volume_name);
else {
printf("!HOLA! FAILED to create a MYFS file system on %s\n", disk_name);
exit(5);
}
myfs_unmount(myfs);
shutdown_block_cache();
return 0;
}
@@ -0,0 +1,416 @@
/*
This file contains the code that will create a file system, mount
a file system and unmount a file system.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include "myfs.h"
#ifndef min_c
#define min_c(a, b) (((a) < (b)) ? (a) : (b))
#endif /* min_c */
myfs_info *
myfs_create_fs(char *device, char *name, int block_size, char *opts)
{
int dev_block_size, bshift, warned = 0;
char *ptr;
fs_off_t num_dev_blocks;
myfs_info *myfs;
if ((block_size % sizeof(myfs_inode)) != 0) {
printf("ERROR: inode size %d is not an even divisor of the block "
"size %d\n", sizeof(myfs_inode), block_size);
printf(" check myfs.h for more details and info.\n");
return NULL;
}
if (name == NULL)
name = "untitled";
for(ptr=name; *ptr; ptr++) {
if (*ptr == '/') {
if (warned == 0) {
fprintf(stderr, "Volume name: %s contains the '/' character. "
"They are being converted to '-' for safety.\n", name);
warned = 1;
}
*ptr = '-';
}
}
if (block_size < 512) {
printf("minimum block size is 512 bytes\n");
block_size = 512;
}
for(bshift=0; bshift < sizeof(int)*8; bshift++)
if ((1 << bshift) == block_size)
break;
if (bshift >= sizeof(int)*8) {
printf("block_size %d is not a power of two!\n", block_size);
return NULL;
}
myfs = (myfs_info *)calloc(1, sizeof(myfs_info));
if (myfs == NULL) {
printf("can't allocate mem for myfs_info struct\n");
return NULL;
}
myfs->fd = -1;
myfs->nsid = (nspace_id)myfs; /* we can only do this when creating */
myfs->dsb.magic1 = SUPER_BLOCK_MAGIC1;
myfs->dsb.magic2 = SUPER_BLOCK_MAGIC2;
myfs->dsb.magic3 = SUPER_BLOCK_MAGIC3;
myfs->dsb.fs_byte_order = MYFS_BIG_ENDIAN; /* checked when mounting */
myfs->sem = create_sem(MAX_READERS, "myfs_sem");
if (myfs->sem < 0) {
printf("can't create semaphore!\n");
goto cleanup;
}
myfs->fd = open(device, O_RDWR);
if (myfs->fd < 0) {
printf("can't open device %s\n", device);
goto cleanup;
}
dev_block_size = get_device_block_size(myfs->fd);
num_dev_blocks = get_num_device_blocks(myfs->fd);
if (block_size < dev_block_size) {
printf("warning: fs block size too small, set to device block size %d\n",
dev_block_size);
block_size = dev_block_size;
}
if ((block_size % dev_block_size) != 0) {
printf("error: block size %d is not an even multiple of ",
block_size);
printf("device block size %d\n", dev_block_size);
goto cleanup;
}
myfs->dsb.block_size = block_size;
myfs->dsb.block_shift = bshift;
myfs->dev_block_conversion = block_size / dev_block_size;
myfs->dev_block_size = dev_block_size;
myfs->dsb.num_blocks = num_dev_blocks / myfs->dev_block_conversion;
init_cache_for_device(myfs->fd, num_dev_blocks / myfs->dev_block_conversion);
if (init_tmp_blocks(myfs) != 0) {
printf("init_tmp_blocks failed\n");
goto cleanup;
}
if (myfs_create_storage_map(myfs) != 0) {
printf("create storage map failed\n");
goto cleanup;
}
if (myfs_create_inodes(myfs) != 0) {
printf("create inodes failed\n");
goto cleanup;
}
if (myfs_create_journal(myfs) != 0) {
printf("create journal failed\n");
goto cleanup;
}
if (myfs_create_root_dir(myfs) != 0) {
printf("create root dir failed\n");
goto cleanup;
}
strncpy(myfs->dsb.name, name,
min_c(sizeof(myfs->dsb.name) - 1, strlen(name)));
/* now it's finally safe to write this */
if (write_super_block(myfs) != 0) {
printf("creating superblock failed\n");
goto cleanup;
}
return myfs;
cleanup:
if (myfs) {
/* making the file system failed so make sure block zero is bogus */
if (myfs->fd >= 0) {
static char block[4096];
memset(block, 0xff, sizeof(block));
write_blocks(myfs, 0, block, 1);
}
myfs_shutdown_storage_map(myfs);
myfs_shutdown_inodes(myfs);
myfs_shutdown_journal(myfs);
shutdown_tmp_blocks(myfs);
close(myfs->fd);
delete_sem(myfs->sem);
free(myfs);
}
return NULL;
}
static int
super_block_is_sane(myfs_info *myfs)
{
fs_off_t num_dev_blocks;
int block_size;
if (myfs->dsb.magic1 != SUPER_BLOCK_MAGIC1 ||
myfs->dsb.magic2 != SUPER_BLOCK_MAGIC2 ||
myfs->dsb.magic3 != SUPER_BLOCK_MAGIC3) {
printf("warning: super block magic numbers are wrong:\n");
printf("0x%x (0x%x) 0x%x (0x%x) 0x%x (0x%x)\n",
myfs->dsb.magic1, SUPER_BLOCK_MAGIC1,
myfs->dsb.magic2, SUPER_BLOCK_MAGIC2,
myfs->dsb.magic3, SUPER_BLOCK_MAGIC3);
return 0;
}
if ((myfs->dsb.block_size % myfs->dev_block_size) != 0) {
printf("warning: fs block size %d not a multiple of ",
myfs->dsb.block_size);
printf(" device block size %d\n", myfs->dev_block_size);
return 0;
}
block_size = get_device_block_size(myfs->fd);
if (block_size == 0) {
printf("warning: could not fetch block size\n");
return 0;
}
/* make sure that the partition is as big as the super block
says it is */
num_dev_blocks = get_num_device_blocks(myfs->fd);
if (myfs->dsb.num_blocks * myfs->dsb.block_size >
num_dev_blocks * block_size) {
printf("warning: fs blocks %lx larger than device blocks %lx\n",
myfs->dsb.num_blocks * (myfs->dsb.block_size/block_size),
num_dev_blocks);
return 0;
}
if (myfs->dsb.block_size != (1 << myfs->dsb.block_shift)) {
int i;
printf("warning: block_shift %d does not match block size %d\n",
myfs->dsb.block_shift, myfs->dsb.block_size);
if (myfs->dsb.block_shift > 8 && myfs->dsb.block_shift < 16) {
printf("setting block_size to %d\n", (1 << myfs->dsb.block_shift));
myfs->dsb.block_size = (1 << myfs->dsb.block_shift);
} else {
for(i=0; i < sizeof(int) * 8; i++)
if ((1 << i) == myfs->dsb.block_size)
break;
if (i >= sizeof(int) * 8 || i > 16) {
printf("neither block_size nor block_shift make sense!\n");
return 0;
}
myfs->dsb.block_shift = i;
printf("setting block_shift to %d\n", i);
}
}
return 1;
}
int
myfs_mount(nspace_id nsid, const char *device, ulong flags,
void *parms, size_t len, void **data, vnode_id *vnid)
{
int ret = 0, oflags = O_RDWR;
char buff[128];
myfs_info *myfs;
myfs = (myfs_info *)calloc(1, sizeof(myfs_info));
if (myfs == NULL) {
printf("no memory for myfs structure!\n");
return ENOMEM;
}
myfs->nsid = nsid;
*data = (void *)myfs;
sprintf(buff, "myfs:%s", device);
myfs->sem = create_sem(MAX_READERS, buff);
if (myfs->sem < 0) {
printf("could not create myfs sem!\n");
ret = ENOMEM;
goto error0;
}
myfs->fd = open(device, oflags);
if (myfs->fd < 0) {
printf("could not open %s to try and mount a myfs\n", device);
ret = ENODEV;
goto error1;
}
if (read_super_block(myfs) != 0) {
printf("could not read super block on device %s\n", device);
ret = EBADF;
goto error2;
}
if (super_block_is_sane(myfs) == 0) {
printf("bad super block\n");
ret = EBADF;
goto error2;
}
if ((myfs->dsb.block_size % sizeof(myfs_inode)) != 0) {
printf("ERROR: inode size %d is not an even divisor of the block "
"size %d\n", sizeof(myfs_inode), myfs->dsb.block_size);
printf(" check myfs.h for more details and info.\n");
ret = EINVAL;
goto error2;
}
if (init_cache_for_device(myfs->fd, myfs->dsb.num_blocks) != 0) {
printf("could not initialize cache access for fd %d\n", myfs->fd);
ret = EBADF;
goto error2;
}
if (init_tmp_blocks(myfs) != 0) {
printf("could not init tmp blocks\n");
ret = ENOMEM;
goto error2;
}
if (myfs_init_journal(myfs) != 0) {
printf("could not initialize the journal\n");
ret = EBADF;
goto error3;
}
if (myfs_init_inodes(myfs) != 0) {
printf("could not initialize inodes\n");
ret = ENOMEM;
goto error5;
}
if (myfs_init_storage_map(myfs) != 0) {
printf("could not initialize the storage map\n");
ret = EBADF;
goto error6;
}
*vnid = myfs->dsb.root_inum;
if (myfs_read_vnode(myfs, *vnid, 0, (void **)&myfs->root_dir) != 0) {
printf("could not read root dir inode\n");
ret = EBADF;
goto error7;
}
if (new_vnode(myfs->nsid, *vnid, (void *)myfs->root_dir) != 0) {
printf("could not initialize a vnode for the root directory!\n");
ret = ENOMEM;
goto error7;
}
return 0;
error7:
myfs_shutdown_storage_map(myfs);
error6:
myfs_shutdown_inodes(myfs);
error5:
myfs_shutdown_journal(myfs);
error3:
shutdown_tmp_blocks(myfs);
error2:
remove_cached_device_blocks(myfs->fd, NO_WRITES);
close(myfs->fd);
error1:
delete_sem(myfs->sem);
error0:
memset(myfs, 0xff, sizeof(*myfs)); /* yeah, I'm paranoid */
free(myfs);
return ret;
}
/*
note that the order in which things are done here is *very*
important. don't mess with it unless you know what you're doing
*/
int
myfs_unmount(void *ns)
{
myfs_info *myfs = (myfs_info *)ns;
if (myfs == NULL)
return EINVAL;
sync_journal(myfs);
myfs_shutdown_storage_map(myfs);
myfs_shutdown_inodes(myfs);
/*
have to do this after the above steps because the above steps
might actually have to do transactions
*/
sync_journal(myfs);
remove_cached_device_blocks(myfs->fd, ALLOW_WRITES);
myfs_shutdown_journal(myfs);
write_super_block(myfs);
shutdown_tmp_blocks(myfs);
close(myfs->fd);
if (myfs->sem > 0)
delete_sem(myfs->sem);
memset(myfs, 0xff, sizeof(*myfs)); /* trash it just to be sure */
free(myfs);
return 0;
}
@@ -0,0 +1,5 @@
myfs_info *myfs_create_fs(char *device, char *volname,
int block_size, char *opts);
int myfs_mount(nspace_id nsid, const char *device, ulong flags,
void *parms, size_t len, void **data, vnode_id *vnid);
int myfs_unmount(void *ns);
@@ -0,0 +1,23 @@
#ifndef MYFS_H
#define MYFS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "compat.h"
#include "fsproto.h"
#include "lock.h"
#include "cache.h"
#include "initfs.h"
typedef void myfs_info;
#ifdef __cplusplus
}
#endif
#endif /* MYFS_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,83 @@
/*
This header file contains the definitions for use with the generic
SkipList package.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#ifndef SKIPLIST_H
#define SKIPLIST_H
/* RAND_MAX should be defined if you are using an ANSI compiler system,
* but alas it isn't always. You should define it to be the correct
* value for whatever your library rand() function returns.
*
* Under unix (mach, bsd, etc), that's 2^31 - 1. On my Amiga at home
* it's 2^15 - 1. It would be wise to verify what your compiler uses
* for RAND_MAX (the maximum value returned from rand()) because otherwise
* the code will _not_ work.
*/
#ifndef RAND_MAX
#define RAND_MAX (0x7fffffff)
#endif
#define ALLOW_DUPLICATES 1 /* allow or disallow duplicates in a list */
#define NO_DUPLICATES 0
#define DUPLICATE_ITEM -1 /* ret val from InsertSL if dups not allowed */
/* typedef's */
typedef struct SLNodeStruct *SLNode;
struct SLNodeStruct
{
void *key;
SLNode forward[1]; /* variable sized array of forward pointers */
};
typedef struct _SkipList
{
struct SLNodeStruct *header; /* pointer to header */
int (*compare)();
void (*freeitem)();
int flags;
int level; /* max index+1 of the forward array */
int count; /* number of elements in the list */
} *SkipList;
/* protos */
SkipList NewSL(int (*compare)(), void (*freeitem)(), int flags);
void FreeSL(SkipList l);
int InsertSL(SkipList l, void *key);
int DeleteSL(SkipList l, void *key);
void *SearchSL(SkipList l, void *key);
void DoForSL(SkipList l, int (*function)(), void *arg);
void DoForRangeSL(SkipList l, void *key, int (*compare)(),
int (*func)(), void *arg);
int NumInSL(SkipList l);
/* These defines are to be used as return values from the function
* you pass to DoForSL(). They can be or'ed together to do multiple
* things (like delete a node and then quit going through the list).
*/
#define SL_CONTINUE 0x00
#define SL_DELETE 0x01
#define SL_QUIT 0x02
#endif /* SKIPLIST_H */
@@ -0,0 +1,401 @@
/* This file contains a heavily hacked and generalized version of the
Example skiplist code distributed on mimsy.cs.umd.edu.
Here is a short excerpt from the original comment :
Example of Skip List source code for C :
Skip Lists are a probabilistic alternative to balanced trees,
as described in the June 1990 issue of CACM and were invented by
William Pugh in 1987.
These are my additions :
This file contains my (Dominic Giampaolo's) heavily hacked version
of skip lists. These work on any arbitrary data by using callback
functions which you supply (at list creation time) to do the data
comparisons. You could instantly use this package to implement a
symbol table for a compiler which would be blazingly fast and
require zippo effort on your part.
I've changed the function names (not to protect the innocent, but
to make them easier to read :) and changed the data structures a bit.
I've ansi'fied the code, added prototypes, and changed all those ugly
do/while's to for loops. I also removed the dependance on those silly
NIL items at the end of the list (it just checks for regular NULL
pointers instead). Additionally, the code is more easily reentrant now,
and doesn't depend on any global variables. The code is quite a bit
different looking than it originally was, but the underlying algorithims
(of course) remain unchanged.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include <stdio.h>
#include <stdlib.h>
#include "skiplist.h"
/* define's */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define MaxNumberOfLevels 16
#define MaxLevel (MaxNumberOfLevels-1)
#define NewNodeOfLevel(x) (SLNode)malloc(sizeof(struct SLNodeStruct)+(x)*sizeof(SLNode *))
/* private proto */
static int RandomLevelSL(SkipList l);
/* functions */
SkipList NewSL(int (*compare)(), void (*freeitem)(), int flags)
{
SkipList l;
int i;
if (compare == NULL) /* need at least a compare function... */
return NULL;
l = (SkipList)malloc(sizeof(struct _SkipList));
if (l == NULL)
return NULL;
l->level = 1;
l->header = NewNodeOfLevel(MaxNumberOfLevels);
if (l->header == NULL)
{ free(l); return NULL; }
for(i=0; i < MaxNumberOfLevels; i++)
l->header->forward[i] = NULL;
l->header->key = NULL; /* just to be sure */
/* XXXdbg -- don't want this! srand(time(NULL) | 0x01); */ /* seed with an odd number */
l->compare = compare;
l->freeitem = freeitem;
l->flags = flags;
l->count = 0;
return(l);
}
void FreeSL(SkipList l)
{
register SLNode p,q;
void (*freeitem)() = l->freeitem;
if (l == NULL)
return;
if (l->header == NULL)
{
free(l);
return;
}
p = l->header; /* free header node first, because it doesn't */
q = p->forward[0]; /* have a real key to it */
free(p);
p = q;
while (p != NULL)
{
q = p->forward[0];
if (freeitem)
(*freeitem)(p->key);
free(p);
p = q;
}
free(l);
}
/*
* This RandomLevelSL function generates a very good representation of
* p=.25 (or p=.5, etc). The number of nodes of each level works out
* to be very very close to what they should be. I didn't check it
* statistically, but on large data sets, I imagine it's +/- 5% of what
* it should be. This P value is good for lists of up to 64K elements.
*
* For more info about the P value, see the papers by Mr. Pugh (available
* in postscript from mimsy.umd.edu).
*/
#define P_50 (RAND_MAX / 2) /* p value of .50 */
#define P_25 (RAND_MAX / 4) /* p value of .25 */
#define P_125 (RAND_MAX / 8) /* p value of .125 */
static int RandomLevelSL(SkipList l)
{
register int level = 0;
while(rand() < P_25)
{
level++;
}
return (level > MaxLevel ? MaxLevel : level);
}
int InsertSL(SkipList l, void *key)
{
register int i,k;
SLNode update[MaxNumberOfLevels];
register SLNode p,q;
int (*compare)() = l->compare;
p = l->header;
for(k = l->level-1; k >= 0; k--)
{
while((q = p->forward[k]) && (*compare)(q->key, key) < 0)
p = q;
update[k] = p;
}
if ((l->flags & ALLOW_DUPLICATES) == FALSE) /* if no duplicates allowed */
if (q && (*compare)(q->key, key) == 0) /* item is a duplicate */
{
return DUPLICATE_ITEM;
}
k = RandomLevelSL(l);
if (k >= l->level)
{
k = l->level;
l->level++;
update[k] = l->header;
}
q = NewNodeOfLevel(k); /* was k+1 */
if (q == NULL)
return FALSE;
l->count++; /* update the number of nodes in the list */
q->key = key;
for(i=0; i < k; i++)
q->forward[i] = NULL;
for(; k >= 0; k--)
{
p = update[k];
q->forward[k] = p->forward[k];
p->forward[k] = q;
}
return TRUE;
}
int DeleteSL(SkipList l, void *key)
{
register int k,m;
SLNode update[MaxNumberOfLevels];
register SLNode p,q;
int (*compare)() = l->compare;
void (*freeitem)() = l->freeitem;
p = l->header;
for(k=l->level-1; k >= 0; k--)
{
while((q = p->forward[k]) && (*compare)(q->key, key) < 0)
p = q;
update[k] = p;
}
q = p->forward[0];
if (q && (*compare)(q->key, key) == 0)
{
m = l->level;
for(k=0; k < m; k++)
{
p = update[k];
if (p == NULL || p->forward[k] != q)
break;
p->forward[k] = q->forward[k];
}
l->count--;
if (freeitem)
(*freeitem)(q->key);
free(q);
m = l->level - 1;
while(l->header->forward[m] == NULL && m > 0)
m--;
l->level = m + 1;
return TRUE;
}
else
return FALSE;
}
void *SearchSL(SkipList l, void *key)
{
register int k;
register SLNode p,q;
int (*compare)() = l->compare;
p = l->header;
for(k=l->level-1; k >= 0; k--)
{
while((q = p->forward[k]) && (*compare)(q->key, key) < 0)
p = q;
}
if (q == NULL || (*compare)(q->key, key) != 0)
return NULL;
return q->key;
}
void DoForSL(SkipList l, int (*function)(), void *arg)
{
register SLNode p,q, fix;
register int k,m, ret;
SLNode save[MaxNumberOfLevels], who[MaxNumberOfLevels];
void (*freeitem)() = l->freeitem;
if (l == NULL || l->header == NULL || function == NULL)
return;
p = l->header; /* skip header node because it isn't a real node */
/* Save the initial header info
*/
for(k=0; k < l->level; k++)
{
save[k] = p->forward[k];
who[k] = p;
}
p = p->forward[0]; /* skip to the first data node */
while (p != NULL)
{
q = p->forward[0];
ret = (*function)(p->key, arg);
if (ret & SL_DELETE)
{
k = 0;
while(save[k] == p)
{
fix = who[k];
fix->forward[k] = p->forward[k];
save[k] = p->forward[k];
k++;
}
l->count--; /* decrement the count of items */
if (freeitem)
(*freeitem)(p->key, arg);
free(p);
}
else
{
k = 0;
while(save[k] == p)
{
save[k] = p->forward[k];
who[k] = p;
k++;
}
}
if (ret & SL_QUIT)
break;
p = q; /* advance to the next one */
}
}
void DoForRangeSL(SkipList l, void *key, int (*compare)(), int (*func)(),
void *arg)
{
register int k,m;
SLNode update[MaxNumberOfLevels];
register SLNode p,q;
void (*freeitem)() = l->freeitem;
int ret;
p = l->header;
for(k=l->level-1; k >= 0; k--)
{
while((q = p->forward[k]) && (*compare)(q->key, key) < 0)
p = q;
update[k] = p;
}
p = p->forward[0];
if (p == NULL || (*compare)(p->key, key) != 0) /* then nothing matched */
return;
do
{
q = p->forward[0]; /* save next pointer */
ret = (*func)(p->key, arg);
if (ret & SL_DELETE)
{
for(k=0; k < l->level && update[k] && update[k]->forward[k] == p; k++)
update[k]->forward[k] = p->forward[k];
l->count--; /* decrement the count of items */
if (freeitem)
(*freeitem)(p->key, arg);
free(p);
}
if (ret & SL_QUIT)
break;
p = q; /* advance to the next one */
}
while(p != NULL && (*compare)(p->key, key) == 0);
}
int NumInSL(SkipList l)
{
return l->count;
}
@@ -0,0 +1,116 @@
/*
This file contains some stub routines to cover up the differences
between the BeOS and the rest of the world.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include <stdio.h>
#include <stdlib.h>
#include "myfs.h"
#ifndef __BEOS__
void
unload_kernel_addon(aid)
{
}
sem_id
create_sem(long count, const char *name)
{
int *ptr;
ptr = (int *)malloc(sizeof(int) + strlen(name) + 1); /* a hack */
*ptr = count;
memcpy(ptr+1, name, strlen(name));
return (sem_id)ptr;
}
long
delete_sem(sem_id semid)
{
int *ptr = (int *)semid;
free(ptr);
return 0;
}
long
acquire_sem(sem_id sem)
{
int *ptr = (int *)sem;
if (*ptr <= 0) {
myfs_die("You lose sucka! acquire of sem with count == %d\n", *ptr);
}
*ptr -= 1;
return 0;
}
long
acquire_sem_etc(sem_id sem, int count, int j1, bigtime_t j2)
{
int *ptr = (int *)sem;
if (*ptr <= 0) {
myfs_die("You lose sucka! acquire_sem_etc of sem with count == %d\n",
*ptr);
}
*ptr -= count;
return 0;
}
long
release_sem(sem_id sem)
{
int *ptr = (int *)sem;
*ptr += 1;
return 0;
}
long
release_sem_etc(sem_id sem, long count, long j1)
{
int *ptr = (int *)sem;
*ptr += count;
return 0;
}
long
atomic_add(long *ptr, long val)
{
int old = *ptr;
*ptr += val;
return old;
}
int
snooze(bigtime_t f)
{
sleep(1);
return 1;
}
#endif /* __BEOS__ */
@@ -0,0 +1,335 @@
/*
This file contains some routines that are #ifdef'ed based on what
system you're on. Currently it supports the BeOS and Unix. It
could be extended to support Windows NT but their posix support
is such a joke that it would probably be a real pain in the arse.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include "compat.h"
int
device_is_read_only(const char *device)
{
#ifdef unix
return 0; /* XXXdbg should do an ioctl or something */
#else
int fd;
device_geometry dg;
fd = open(device, O_RDONLY);
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0)
return 0;
close(fd);
return dg.read_only;
#endif
}
int
get_device_block_size(int fd)
{
#ifdef unix
return 512; /* XXXdbg should do an ioctl or something */
#else
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0) {
if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode))
return 0;
return 512; /* just assume it's a plain old file or something */
}
return dg.bytes_per_sector;
#endif
}
fs_off_t
get_num_device_blocks(int fd)
{
#ifdef unix
struct stat st;
fstat(fd, &st); /* XXXdbg should be an ioctl or something */
return st.st_size / get_device_block_size(fd);
#else
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) >= 0) {
return (fs_off_t)dg.cylinder_count *
(fs_off_t)dg.sectors_per_track *
(fs_off_t)dg.head_count;
}
/* if the ioctl fails, try just stat'ing in case it's a regular file */
if (fstat(fd, &st) < 0)
return 0;
return st.st_size / get_device_block_size(fd);
#endif
}
int
device_is_removeable(int fd)
{
#ifdef unix
return 0; /* XXXdbg should do an ioctl or something */
#else
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0) {
return 0;
}
return dg.removable;
#endif
}
#if defined(__BEOS__) && !defined(USER)
#include "scsi.h"
#endif
int
lock_removeable_device(int fd, bool on_or_off)
{
#if defined(unix) || defined(USER)
return 0; /* XXXdbg should do an ioctl or something */
#else
return ioctl(fd, B_SCSI_PREVENT_ALLOW, &on_or_off);
#endif
}
#ifndef __BEOS__
ssize_t
read_pos(int fd, fs_off_t _pos, void *data, size_t nbytes)
{
off_t pos = (off_t)_pos;
size_t ret;
if (lseek(fd, pos, SEEK_SET) < 0) {
perror("read lseek");
return EINVAL;
}
ret = read(fd, data, nbytes);
if (ret != nbytes) {
printf("read_pos: wanted %d, got %d\n", nbytes, ret);
return -1;
}
return ret;
}
ssize_t
write_pos(int fd, fs_off_t _pos, const void *data, size_t nbytes)
{
off_t pos = (off_t)_pos;
size_t ret;
if (lseek(fd, pos, SEEK_SET) < 0) {
perror("read lseek");
return EINVAL;
}
ret = write(fd, data, nbytes);
if (ret != nbytes) {
printf("write_pos: wanted %d, got %d\n", nbytes, ret);
return -1;
}
return ret;
}
#ifdef sun /* bloody wankers */
#include <sys/stream.h>
#ifdef DEF_IOV_MAX
#define MAX_IOV DEF_IOV_MAX
#else
#define MAX_IOV 16
#endif
#else /* the rest of the world... */
#define MAX_IOV 8192 /* something way bigger than we'll ever use */
#endif
ssize_t
readv_pos(int fd, fs_off_t _pos, struct iovec *iov, int count)
{
off_t pos = (off_t)_pos;
size_t amt = 0;
ssize_t ret;
struct iovec *tmpiov;
int i, n;
if (lseek(fd, pos, SEEK_SET) < 0) {
perror("read lseek");
return EINVAL;
}
i = 0;
tmpiov = iov;
while (i < count) {
if (i + MAX_IOV < count)
n = MAX_IOV;
else
n = (count - i);
ret = readv(fd, tmpiov, n);
amt += ret;
if (ret < 0)
break;
i += n;
tmpiov += n;
}
return amt;
}
ssize_t
writev_pos(int fd, fs_off_t _pos, struct iovec *iov, int count)
{
off_t pos = (off_t)_pos;
size_t amt = 0;
ssize_t ret;
struct iovec *tmpiov;
int i, n;
if (lseek(fd, pos, SEEK_SET) < 0) {
perror("read lseek");
return EINVAL;
}
i = 0;
tmpiov = iov;
while (i < count) {
if (i + MAX_IOV < count)
n = MAX_IOV;
else
n = (count - i);
ret = writev(fd, tmpiov, n);
amt += ret;
if (ret < 0)
break;
i += n;
tmpiov += n;
}
return amt;
}
#endif /* __BEOS__ */
#include <stdarg.h>
void
panic(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
while (TRUE)
;
}
#include "lock.h"
int
new_lock(lock *l, const char *name)
{
l->c = 1;
l->s = create_sem(0, (char *)name);
if (l->s <= 0)
return l->s;
return 0;
}
int
free_lock(lock *l)
{
delete_sem(l->s);
return 0;
}
int
new_mlock(mlock *l, long c, const char *name)
{
l->s = create_sem(c, (char *)name);
if (l->s <= 0)
return l->s;
return 0;
}
int
free_mlock(mlock *l)
{
delete_sem(l->s);
return 0;
}
#ifdef unix
#include <sys/time.h>
bigtime_t
system_time(void)
{
bigtime_t t;
struct timeval tv;
gettimeofday(&tv, NULL);
t = ((bigtime_t)tv.tv_sec * 1000000) + (bigtime_t)tv.tv_usec;
return t;
}
/*
If you're compiler/system can't deal with the version of system_time()
as defined above, use this one instead
bigtime_t
system_time(void)
{
return (bigtime_t)time(NULL);
}
*/
#endif /* unix */
@@ -0,0 +1,257 @@
/*
This file contains a simple test program that can be used as a sort
of stress test for the file system. It's not exhaustive but it provides
a decent first level sanity check on whether a file system will work.
Basically it just randomly creates and deletes files. The defines
just after the includes control how many files and how many iterations.
Be careful if you just bump up the numbers really high -- it will take
a long time to run and if you only have a 16 megabyte file system
it will probably run out of space.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO ([email protected]).
Dominic Giampaolo
[email protected]
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include "myfs.h"
#include "kprotos.h"
#define MAX_LOOPS 1024
#define MAX_FILES 512
#define MAX_NAME 24
char buf[MAX_FILES][MAX_NAME];
fs_off_t sizes[MAX_FILES];
static void
make_random_name(char *buf, int len)
{
int i, max = (rand() % (len - 7)) + 6;
for(i=0; i < max; i++) {
buf[i] = 'a' + (rand() % 26);
}
buf[i] = '\0';
}
static void
SubTime(struct timeval *a, struct timeval *b, struct timeval *c)
{
if ((long)(a->tv_usec - b->tv_usec) < 0)
{
a->tv_sec--;
a->tv_usec += 1000000;
}
c->tv_sec = a->tv_sec - b->tv_sec;
c->tv_usec = a->tv_usec - b->tv_usec;
}
static void
write_rand_data(int fd, int max_data)
{
int i, k, err;
size_t j;
static char buf[4096];
ulong sum = 0;
for(i=0; max_data > 0; i++) {
j = rand() % sizeof(buf);
if ((int)(max_data - j) < 0)
j = max_data;
memset(buf, rand() >> 8, j);
for(k=0; k < j; k++)
sum += buf[k];
/* printf("write: %d\n", j); */
err = sys_write(1, fd, buf, j);
if (err != j) {
errno = err;
perror("write_rand_data");
printf("err %d j %d\n", err, j);
if (errno != ENOSPC)
while(1)
sleep(1);
break;
}
max_data -= j;
}
#if INSANELY_SLOW_CHECKSUM
pos = 0;
err = sys_lseek(1, fd, SEEK_SET, &pos);
for(i=0; i < max; i++) {
j = sizeof(buf);
sys_read(1, fd, buf, j);
for(k=0; k < j; k++)
nsum += buf[k];
}
if (sum != nsum)
printf("sum = 0x%x, nsum 0x%x\n", sum, nsum);
#endif
}
int
main(int argc, char **argv)
{
int i, j, fd, seed, err, size, sum, name_size = 0;
struct my_stat st;
struct timeval start, end, result;
char *disk_name = "big_file";
myfs_info *myfs;
if (argv[1] != NULL && !isdigit(argv[1][0]))
disk_name = argv[1];
else if (argv[1] && isdigit(argv[1][0]))
seed = strtoul(argv[1], NULL, 0);
else
seed = getpid() * time(NULL) | 1;
printf("random seed == 0x%x\n", seed);
srand(seed);
myfs = init_fs(disk_name);
for(i=0; i < MAX_FILES; i++)
buf[i][0] = '\0';
printf("creating & deleting files...\n"); fflush(stdout);
gettimeofday(&start, NULL);
for(i=0,sum=0; i < MAX_LOOPS; i++) {
j = rand() % MAX_FILES;
size = (rand() % 65536) + 1;
#if 1
if ((i % 10) == 0) {
printf("\r \r");
printf("iteration: %7d", i);
fflush(stdout);
}
#endif
if (buf[j][0] == '\0') { /* then create a file */
strcpy(&buf[j][0], "/myfs/");
make_random_name(&buf[j][6], MAX_NAME-6);
name_size += strlen(&buf[j][6]);
sum += sizes[j] = size;
/* printf("\rcreating: %s %d bytes", &buf[j][0], size); */
fd = sys_open(1, -1, &buf[j][0], O_CREAT|O_RDWR,
MY_S_IFREG|MY_S_IRWXU, 0);
if (fd < 0) {
printf("error creating: %s\n", &buf[j][0]);
break;
}
write_rand_data(fd, size);
sys_close(1, fd);
} else { /* then delete the file */
/* printf("\runlinking %s", &buf[j][0]); */
name_size -= strlen(&buf[j][6]);
err = sys_unlink(1, -1, &buf[j][0]);
if (err != 0) {
printf("error removing: %s: %s\n", &buf[j][0], strerror(err));
break;
}
buf[j][0] = '\0';
sum -= sizes[j];
}
#if 0 /* doing this is really anal */
for(k=0; k < MAX_FILES; k++) {
if (buf[k][0] == '\0')
continue;
fd = sys_open(1, -1, &buf[k][0], O_RDWR, 0, 0);
if (fd < 0) {
printf("file: %s is not present and should be!\n", &buf[k][0]);
sys_unmount(1, -1, "/myfs");
exit(0);
}
sys_close(1, fd);
}
#endif
}
gettimeofday(&end, NULL);
SubTime(&end, &start, &result);
printf("\rcreated %d files in %2ld.%.6ld seconds (%d k data)\n", i,
result.tv_sec, result.tv_usec, sum/1024);
printf("now verifying files....\n");
for(i=0; i < MAX_FILES; i++) {
if (buf[i][0] == '\0')
continue;
printf(" \r");
printf("opening: %s\r", &buf[i][0]);
fflush(stdout);
fd = sys_open(1, -1, &buf[i][0], O_RDWR, 0, 0);
if (fd != 0) {
printf("file: %s is not present and should be!\n", &buf[i][0]);
sys_unmount(1, -1, "/myfs");
exit(0);
}
err = sys_rstat(1, -1, &buf[i][0], &st, 1);
if (err != 0) {
printf("stat failed for: %s\n", &buf[i][0]);
continue;
}
if (st.st_size != sizes[i]) {
printf("size mismatch on %s: %ld != %ld\n", &buf[i][0],
st.st_size, sizes[i]);
}
sys_close(1, fd);
}
printf("done verifying files \n");
if (sys_unmount(1, -1, "/myfs") != 0) {
printf("could not UNmount /myfs\n");
return 5;
}
shutdown_block_cache();
/* check_mem(); */
return 0;
}