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:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user