copied dosfs R5 version to tests
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18582 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
8d99ad5edc
commit
1d130feff7
16
src/tests/add-ons/kernel/file_systems/dos/r5/Jamfile
Normal file
16
src/tests/add-ons/kernel/file_systems/dos/r5/Jamfile
Normal file
@ -0,0 +1,16 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel file_systems dos ;
|
||||
|
||||
KernelAddon dos : kernel file_systems :
|
||||
attr.c
|
||||
dir.c
|
||||
dlist.c
|
||||
dosfs.c
|
||||
encodings.cpp
|
||||
fat.c
|
||||
file.c
|
||||
iter.c
|
||||
mime_table.c
|
||||
util.c
|
||||
vcache.c
|
||||
version.c
|
||||
;
|
31
src/tests/add-ons/kernel/file_systems/dos/r5/LICENSE
Normal file
31
src/tests/add-ons/kernel/file_systems/dos/r5/LICENSE
Normal file
@ -0,0 +1,31 @@
|
||||
----------------------
|
||||
Be Sample Code License
|
||||
----------------------
|
||||
|
||||
Copyright 1991-2001, Be Incorporated.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions, and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions, and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
265
src/tests/add-ons/kernel/file_systems/dos/r5/attr.c
Normal file
265
src/tests/add-ons/kernel/file_systems/dos/r5/attr.c
Normal file
@ -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.
|
||||
*/
|
||||
/* attr.c
|
||||
* handles mime type information for dosfs
|
||||
* gets/sets mime information in vnode
|
||||
*/
|
||||
|
||||
|
||||
#define MIME_STRING_TYPE 'MIMS'
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fs_attr.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <fsproto.h>
|
||||
#include <lock.h>
|
||||
|
||||
#include "dosfs.h"
|
||||
#include "attr.h"
|
||||
#include "mime_table.h"
|
||||
|
||||
#define DPRINTF(a,b) if (debug_attr > (a)) dprintf b
|
||||
|
||||
status_t set_mime_type(vnode *node, const char *filename)
|
||||
{
|
||||
struct ext_mime *p;
|
||||
int32 namelen, ext_len;
|
||||
|
||||
DPRINTF(0, ("get_mime_type of (%s)\n", filename));
|
||||
|
||||
node->mime = NULL;
|
||||
|
||||
namelen = strlen(filename);
|
||||
|
||||
for (p=mimes;p->extension;p++) {
|
||||
ext_len = strlen(p->extension);
|
||||
|
||||
if (namelen <= ext_len)
|
||||
continue;
|
||||
|
||||
if (filename[namelen-ext_len-1] != '.')
|
||||
continue;
|
||||
|
||||
if (!strcasecmp(filename + namelen - ext_len, p->extension))
|
||||
break;
|
||||
}
|
||||
|
||||
node->mime = p->mime;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int dosfs_open_attrdir(void *_vol, void *_node, void **_cookie)
|
||||
{
|
||||
nspace *vol = (nspace *)_vol;
|
||||
|
||||
TOUCH(_node);
|
||||
|
||||
DPRINTF(0, ("dosfs_open_attrdir called\n"));
|
||||
|
||||
LOCK_VOL(vol);
|
||||
|
||||
if (check_nspace_magic(vol, "dosfs_open_attrdir")) {
|
||||
UNLOCK_VOL(vol);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if ((*_cookie = malloc(sizeof(uint32))) == NULL) {
|
||||
UNLOCK_VOL(vol);
|
||||
return ENOMEM;
|
||||
}
|
||||
*(int32 *)(*_cookie) = 0;
|
||||
|
||||
UNLOCK_VOL(vol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dosfs_close_attrdir(void *_vol, void *_node, void *_cookie)
|
||||
{
|
||||
nspace *vol = (nspace *)_vol;
|
||||
|
||||
TOUCH(_node);
|
||||
|
||||
DPRINTF(0, ("dosfs_close_attrdir called\n"));
|
||||
|
||||
LOCK_VOL(vol);
|
||||
|
||||
if (check_nspace_magic(vol, "dosfs_open_attrdir")) {
|
||||
UNLOCK_VOL(vol);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*(int32 *)_cookie = 1;
|
||||
|
||||
UNLOCK_VOL(vol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dosfs_free_attrcookie(void *_vol, void *_node, void *_cookie)
|
||||
{
|
||||
TOUCH(_vol); TOUCH(_node);
|
||||
|
||||
DPRINTF(0, ("dosfs_free_attrcookie called\n"));
|
||||
|
||||
if (_cookie == NULL) {
|
||||
dprintf("error: dosfs_free_attrcookie called with null cookie\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*(int32 *)_cookie = 0x87654321;
|
||||
free(_cookie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dosfs_rewind_attrdir(void *_vol, void *_node, void *_cookie)
|
||||
{
|
||||
TOUCH(_vol); TOUCH(_node);
|
||||
|
||||
DPRINTF(0, ("dosfs_rewind_attrdir called\n"));
|
||||
|
||||
if (_cookie == NULL) {
|
||||
dprintf("error: dosfs_rewind_attrcookie called with null cookie\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*(uint32 *)_cookie = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dosfs_read_attrdir(void *_vol, void *_node, void *_cookie, long *num,
|
||||
struct dirent *entry, size_t bufsize)
|
||||
{
|
||||
nspace *vol = (nspace *)_vol;
|
||||
vnode *node = (vnode *)_node;
|
||||
int32 *cookie = (int32 *)_cookie;
|
||||
|
||||
TOUCH(bufsize);
|
||||
|
||||
DPRINTF(0, ("dosfs_read_attrdir called\n"));
|
||||
|
||||
*num = 0;
|
||||
|
||||
LOCK_VOL(vol);
|
||||
|
||||
if (check_nspace_magic(vol, "dosfs_read_attrdir") ||
|
||||
check_vnode_magic(node, "dosfs_read_attrdir")) {
|
||||
UNLOCK_VOL(vol);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if ((*cookie == 0) && (node->mime)) {
|
||||
*num = 1;
|
||||
|
||||
entry->d_ino = node->vnid;
|
||||
entry->d_dev = vol->id;
|
||||
entry->d_reclen = 10;
|
||||
strcpy(entry->d_name, "BEOS:TYPE");
|
||||
}
|
||||
|
||||
*cookie = 1;
|
||||
|
||||
UNLOCK_VOL(vol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dosfs_stat_attr(void *_vol, void *_node, const char *name, struct attr_info *buf)
|
||||
{
|
||||
nspace *vol = (nspace *)_vol;
|
||||
vnode *node = (vnode *)_node;
|
||||
|
||||
DPRINTF(0, ("dosfs_stat_attr (%s)\n", name));
|
||||
|
||||
if (strcmp(name, "BEOS:TYPE"))
|
||||
return ENOENT;
|
||||
|
||||
LOCK_VOL(vol);
|
||||
|
||||
if (check_nspace_magic(vol, "dosfs_read_attr") ||
|
||||
check_vnode_magic(node, "dosfs_read_attr")) {
|
||||
UNLOCK_VOL(vol);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (node->mime == NULL) {
|
||||
UNLOCK_VOL(vol);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
buf->type = MIME_STRING_TYPE;
|
||||
buf->size = strlen(node->mime) + 1;
|
||||
|
||||
UNLOCK_VOL(vol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dosfs_read_attr(void *_vol, void *_node, const char *name, int type, void *buf,
|
||||
size_t *len, off_t pos)
|
||||
{
|
||||
nspace *vol = (nspace *)_vol;
|
||||
vnode *node = (vnode *)_node;
|
||||
|
||||
DPRINTF(0, ("dosfs_read_attr (%s)\n", name));
|
||||
|
||||
if (strcmp(name, "BEOS:TYPE"))
|
||||
return ENOENT;
|
||||
|
||||
if (type != MIME_STRING_TYPE)
|
||||
return ENOENT;
|
||||
|
||||
LOCK_VOL(vol);
|
||||
|
||||
if (check_nspace_magic(vol, "dosfs_read_attr") ||
|
||||
check_vnode_magic(node, "dosfs_read_attr")) {
|
||||
UNLOCK_VOL(vol);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (node->mime == NULL) {
|
||||
UNLOCK_VOL(vol);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
if ((pos < 0) || (pos > strlen(node->mime))) {
|
||||
UNLOCK_VOL(vol);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
strncpy(buf, node->mime + pos, *len - 1);
|
||||
((char *)buf)[*len - 1] = 0;
|
||||
*len = strlen(buf) + 1;
|
||||
|
||||
UNLOCK_VOL(vol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// suck up application attempts to set mime types; this hides an unsightly
|
||||
// error message printed out by zip
|
||||
int dosfs_write_attr(void *_vol, void *_node, const char *name, int type,
|
||||
const void *buf, size_t *len, off_t pos)
|
||||
{
|
||||
TOUCH(_vol); TOUCH(_node); TOUCH(name); TOUCH(type); TOUCH(buf);
|
||||
TOUCH(len); TOUCH(pos);
|
||||
|
||||
DPRINTF(0, ("dosfs_write_attr (%s)\n", name));
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (strcmp(name, "BEOS:TYPE"))
|
||||
return ENOSYS;
|
||||
|
||||
if (type != MIME_STRING_TYPE)
|
||||
return ENOSYS;
|
||||
|
||||
return 0;
|
||||
}
|
22
src/tests/add-ons/kernel/file_systems/dos/r5/attr.h
Normal file
22
src/tests/add-ons/kernel/file_systems/dos/r5/attr.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_ATTR_H_
|
||||
#define _DOSFS_ATTR_H_
|
||||
|
||||
status_t set_mime_type(vnode *node, const char *filename);
|
||||
|
||||
int dosfs_open_attrdir(void *_vol, void *_node, void **_cookie);
|
||||
int dosfs_close_attrdir(void *_vol, void *_node, void *_cookie);
|
||||
int dosfs_free_attrcookie(void *_vol, void *_node, void *_cookie);
|
||||
int dosfs_rewind_attrdir(void *_vol, void *_node, void *_cookie);
|
||||
int dosfs_read_attrdir(void *_vol, void *_node, void *_cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
int dosfs_stat_attr(void *_vol, void *_node, const char *name, struct attr_info *buf);
|
||||
int dosfs_read_attr(void *_vol, void *_node, const char *name, int type, void *buf,
|
||||
size_t *len, off_t pos);
|
||||
int dosfs_write_attr(void *_vol, void *_node, const char *name, int type,
|
||||
const void *buf, size_t *len, off_t pos);
|
||||
|
||||
#endif
|
108
src/tests/add-ons/kernel/file_systems/dos/r5/cache.h
Normal file
108
src/tests/add-ons/kernel/file_systems/dos/r5/cache.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#ifndef _CACHE_H_
|
||||
#define _CACHE_H_
|
||||
|
||||
#include <BeBuild.h>
|
||||
|
||||
typedef struct hash_ent {
|
||||
int dev;
|
||||
off_t bnum;
|
||||
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;
|
||||
off_t block_num;
|
||||
int bsize;
|
||||
volatile int flags;
|
||||
|
||||
void *data;
|
||||
void *clone; /* copy of data by set_block_info() */
|
||||
int lock;
|
||||
|
||||
void (*func)(off_t bnum, size_t num_blocks, void *arg);
|
||||
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 {
|
||||
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;
|
||||
|
||||
#if 0 /* XXXdbg -- need to deal with write through caches */
|
||||
#define DC_WRITE_THROUGH 0x0001 /* cache is write-through (for floppies) */
|
||||
#endif
|
||||
|
||||
#define ALLOW_WRITES 1
|
||||
#define NO_WRITES 0
|
||||
|
||||
extern _IMPEXP_KERNEL int init_block_cache(int max_blocks, int flags);
|
||||
extern _IMPEXP_KERNEL void shutdown_block_cache(void);
|
||||
|
||||
extern _IMPEXP_KERNEL void force_cache_flush(int dev, int prefer_log_blocks);
|
||||
extern _IMPEXP_KERNEL int flush_blocks(int dev, off_t bnum, int nblocks);
|
||||
extern _IMPEXP_KERNEL int flush_device(int dev, int warn_locked);
|
||||
|
||||
extern _IMPEXP_KERNEL int init_cache_for_device(int fd, off_t max_blocks);
|
||||
extern _IMPEXP_KERNEL int remove_cached_device_blocks(int dev, int allow_write);
|
||||
|
||||
extern _IMPEXP_KERNEL void *get_block(int dev, off_t bnum, int bsize);
|
||||
extern _IMPEXP_KERNEL void *get_empty_block(int dev, off_t bnum, int bsize);
|
||||
extern _IMPEXP_KERNEL int release_block(int dev, off_t bnum);
|
||||
extern _IMPEXP_KERNEL int mark_blocks_dirty(int dev, off_t bnum, int nblocks);
|
||||
|
||||
|
||||
extern _IMPEXP_KERNEL int cached_read(int dev, off_t bnum, void *data, off_t num_blocks, int bsize);
|
||||
extern _IMPEXP_KERNEL int cached_write(int dev, off_t bnum, const void *data,
|
||||
off_t num_blocks, int bsize);
|
||||
extern _IMPEXP_KERNEL int cached_write_locked(int dev, off_t bnum, const void *data,
|
||||
off_t num_blocks, int bsize);
|
||||
extern _IMPEXP_KERNEL int set_blocks_info(int dev, off_t *blocks, int nblocks,
|
||||
void (*func)(off_t bnum, size_t nblocks, void *arg),
|
||||
void *arg);
|
||||
|
||||
|
||||
extern _IMPEXP_KERNEL size_t read_phys_blocks (int fd, off_t bnum, void *data, uint num_blocks, int bsize);
|
||||
extern _IMPEXP_KERNEL size_t write_phys_blocks(int fd, off_t bnum, void *data, uint num_blocks, int bsize);
|
||||
|
||||
#endif /* _CACHE_H_ */
|
1236
src/tests/add-ons/kernel/file_systems/dos/r5/dir.c
Normal file
1236
src/tests/add-ons/kernel/file_systems/dos/r5/dir.c
Normal file
File diff suppressed because it is too large
Load Diff
36
src/tests/add-ons/kernel/file_systems/dos/r5/dir.h
Normal file
36
src/tests/add-ons/kernel/file_systems/dos/r5/dir.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_DIR_H_
|
||||
#define _DOSFS_DIR_H_
|
||||
|
||||
bool is_filename_legal(const char *name);
|
||||
status_t check_dir_empty(nspace *vol, vnode *dir);
|
||||
status_t findfile_case(nspace *vol, vnode *dir, const char *file,
|
||||
vnode_id *vnid, vnode **node);
|
||||
status_t findfile_nocase(nspace *vol, vnode *dir, const char *file,
|
||||
vnode_id *vnid, vnode **node);
|
||||
status_t findfile_nocase_duplicates(nspace *vol, vnode *dir, const char *file,
|
||||
vnode_id *vnid, vnode **node, bool *dups_exist);
|
||||
status_t findfile_case_duplicates(nspace *vol, vnode *dir, const char *file,
|
||||
vnode_id *vnid, vnode **node, bool *dups_exist);
|
||||
status_t erase_dir_entry(nspace *vol, vnode *node);
|
||||
status_t compact_directory(nspace *vol, vnode *dir);
|
||||
status_t create_volume_label(nspace *vol, const char name[11], uint32 *index);
|
||||
status_t create_dir_entry(nspace *vol, vnode *dir, vnode *node,
|
||||
const char *name, uint32 *ns, uint32 *ne);
|
||||
|
||||
int dosfs_read_vnode(void *_vol, vnode_id vnid, char r, void **node);
|
||||
int dosfs_walk(void *_vol, void *_dir, const char *file,
|
||||
char **newpath, vnode_id *vnid);
|
||||
int dosfs_access(void *_vol, void *_node, int mode);
|
||||
int dosfs_readlink(void *_vol, void *_node, char *buf, size_t *bufsize);
|
||||
int dosfs_opendir(void *_vol, void *_node, void **cookie);
|
||||
int dosfs_readdir(void *_vol, void *_node, void *cookie,
|
||||
long *num, struct dirent *buf, size_t bufsize);
|
||||
int dosfs_rewinddir(void *_vol, void *_node, void *cookie);
|
||||
int dosfs_closedir(void *_vol, void *_node, void *cookie);
|
||||
int dosfs_free_dircookie(void *_vol, void *_node, void *cookie);
|
||||
|
||||
#endif
|
162
src/tests/add-ons/kernel/file_systems/dos/r5/dlist.c
Normal file
162
src/tests/add-ons/kernel/file_systems/dos/r5/dlist.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
directory vnode id list
|
||||
|
||||
We only add to this list as we encounter directories; there is no need to
|
||||
scan through the directories ourselves since we aren't worried about preserving
|
||||
vnid's across reboots.
|
||||
|
||||
We don't worry about aliases for directories since their cluster values will
|
||||
always be the same -- searches are performed only on the starting cluster
|
||||
number of the directories.
|
||||
|
||||
TODO:
|
||||
XXX: make this more efficient
|
||||
*/
|
||||
|
||||
#define DPRINTF(a,b) if (debug_dlist > (a)) dprintf b
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <fsproto.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "dosfs.h"
|
||||
#include "dlist.h"
|
||||
#include "util.h"
|
||||
#include "vcache.h"
|
||||
|
||||
#if DEBUG
|
||||
#define DLIST_ENTRY_QUANTUM 1
|
||||
#else
|
||||
#define DLIST_ENTRY_QUANTUM 0x20
|
||||
#endif
|
||||
|
||||
status_t dlist_init(nspace *vol)
|
||||
{
|
||||
DPRINTF(0, ("dlist_init called\n"));
|
||||
|
||||
vol->dlist.entries = 0;
|
||||
vol->dlist.allocated = DLIST_ENTRY_QUANTUM;
|
||||
vol->dlist.vnid_list = malloc(sizeof(vnode_id) * vol->dlist.allocated);
|
||||
if (vol->dlist.vnid_list == NULL) {
|
||||
vol->dlist.allocated = 0;
|
||||
dprintf("dlist_init: out of core\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t dlist_uninit(nspace *vol)
|
||||
{
|
||||
DPRINTF(0, ("dlist_uninit called\n"));
|
||||
|
||||
if (vol->dlist.vnid_list)
|
||||
free(vol->dlist.vnid_list);
|
||||
vol->dlist.entries = vol->dlist.allocated = 0;
|
||||
vol->dlist.vnid_list = NULL;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t dlist_realloc(nspace *vol, uint32 allocate)
|
||||
{
|
||||
vnode_id *vnid_list;
|
||||
|
||||
DPRINTF(0, ("dlist_realloc %lx -> %lx\n", vol->dlist.allocated, allocate));
|
||||
|
||||
ASSERT(allocate != vol->dlist.allocated);
|
||||
ASSERT(allocate > vol->dlist.entries);
|
||||
|
||||
vnid_list = malloc(sizeof(vnode_id) * allocate);
|
||||
if (vnid_list == NULL) {
|
||||
dprintf("dlist_realloc: out of core\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(vnid_list, vol->dlist.vnid_list, sizeof(vnode_id) * vol->dlist.entries);
|
||||
free(vol->dlist.vnid_list);
|
||||
vol->dlist.vnid_list = vnid_list;
|
||||
vol->dlist.allocated = allocate;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t dlist_add(nspace *vol, vnode_id vnid)
|
||||
{
|
||||
DPRINTF(0, ("dlist_add vnid %Lx\n", vnid));
|
||||
|
||||
ASSERT(IS_DIR_CLUSTER_VNID(vnid) || IS_ARTIFICIAL_VNID(vnid));
|
||||
ASSERT(vnid != 0);
|
||||
// XXX: check for duplicate entries
|
||||
|
||||
if (vol->dlist.entries == vol->dlist.allocated) {
|
||||
if (dlist_realloc(vol, vol->dlist.allocated + DLIST_ENTRY_QUANTUM) < 0)
|
||||
return B_ERROR;
|
||||
}
|
||||
vol->dlist.vnid_list[vol->dlist.entries++] = vnid;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t dlist_remove(nspace *vol, vnode_id vnid)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
DPRINTF(0, ("dlist_remove vnid %Lx\n", vnid));
|
||||
|
||||
for (i=0;i<vol->dlist.entries;i++)
|
||||
if (vol->dlist.vnid_list[i] == vnid)
|
||||
break;
|
||||
ASSERT(i < vol->dlist.entries);
|
||||
if (i == vol->dlist.entries)
|
||||
return ENOENT;
|
||||
for (;i<vol->dlist.entries-1;i++)
|
||||
vol->dlist.vnid_list[i] = vol->dlist.vnid_list[i+1];
|
||||
vol->dlist.entries--;
|
||||
|
||||
if (vol->dlist.allocated - vol->dlist.entries > 2*DLIST_ENTRY_QUANTUM)
|
||||
return dlist_realloc(vol, vol->dlist.allocated - DLIST_ENTRY_QUANTUM);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
vnode_id dlist_find(nspace *vol, uint32 cluster)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
DPRINTF(1, ("dlist_find cluster %lx\n", cluster));
|
||||
|
||||
ASSERT(((cluster >= 2) && (cluster < vol->total_clusters + 2)) || (cluster == 1));
|
||||
|
||||
for (i=0;i<vol->dlist.entries;i++) {
|
||||
vnode_id loc;
|
||||
|
||||
if (vcache_vnid_to_loc(vol, vol->dlist.vnid_list[i], &loc) < B_OK)
|
||||
loc = vol->dlist.vnid_list[i];
|
||||
ASSERT(IS_DIR_CLUSTER_VNID(loc));
|
||||
if (CLUSTER_OF_DIR_CLUSTER_VNID(loc) == cluster)
|
||||
return vol->dlist.vnid_list[i];
|
||||
}
|
||||
|
||||
DPRINTF(1, ("dlist_find cluster %lx not found\n", cluster));
|
||||
|
||||
return -1LL;
|
||||
}
|
||||
|
||||
void dlist_dump(nspace *vol)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
dprintf("%lx/%lx dlist entries filled, QUANTUM = %x\n",
|
||||
vol->dlist.entries, vol->dlist.allocated, DLIST_ENTRY_QUANTUM);
|
||||
|
||||
for (i=0;i<vol->dlist.entries;i++)
|
||||
dprintf("%s %Lx", ((i == 0) ? "entries:" : ","), vol->dlist.vnid_list[i]);
|
||||
|
||||
dprintf("\n");
|
||||
}
|
16
src/tests/add-ons/kernel/file_systems/dos/r5/dlist.h
Normal file
16
src/tests/add-ons/kernel/file_systems/dos/r5/dlist.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_DLIST_H_
|
||||
#define _DOSFS_DLIST_H_
|
||||
|
||||
status_t dlist_init(nspace *vol);
|
||||
status_t dlist_uninit(nspace *vol);
|
||||
status_t dlist_add(nspace *vol, vnode_id vnid);
|
||||
status_t dlist_remove(nspace *vol, vnode_id vnid);
|
||||
vnode_id dlist_find(nspace *vol, uint32 cluster);
|
||||
|
||||
void dlist_dump(nspace *vol);
|
||||
|
||||
#endif
|
1080
src/tests/add-ons/kernel/file_systems/dos/r5/dosfs.c
Normal file
1080
src/tests/add-ons/kernel/file_systems/dos/r5/dosfs.c
Normal file
File diff suppressed because it is too large
Load Diff
211
src/tests/add-ons/kernel/file_systems/dos/r5/dosfs.h
Normal file
211
src/tests/add-ons/kernel/file_systems/dos/r5/dosfs.h
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_H_
|
||||
#define _DOSFS_H_
|
||||
|
||||
#if USE_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#else
|
||||
|
||||
/* allocate memory from swappable heap */
|
||||
#define malloc smalloc
|
||||
#define free sfree
|
||||
#define calloc scalloc
|
||||
#define realloc srealloc
|
||||
|
||||
#include <kalloc.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
/* for multiple reader/single writer locks */
|
||||
#define READERS 100000
|
||||
|
||||
/* Unfortunately, vnode_id's are defined as signed. This causes problems with
|
||||
* programs (notably cp) that use the modulo of a vnode_id (or ino_t) as a
|
||||
* hash function to index an array. This means the high bit of every vnode_id
|
||||
* is off-limits. Luckily, FAT32 is actually FAT28, so dosfs can make do with
|
||||
* only 63 bits.
|
||||
*/
|
||||
#define ARTIFICIAL_VNID_BITS (0x6LL << 60)
|
||||
#define DIR_CLUSTER_VNID_BITS (0x4LL << 60)
|
||||
#define DIR_INDEX_VNID_BITS 0
|
||||
#define INVALID_VNID_BITS_MASK (0x9LL << 60)
|
||||
|
||||
#define IS_DIR_CLUSTER_VNID(vnid) \
|
||||
(((vnid) & ARTIFICIAL_VNID_BITS) == DIR_CLUSTER_VNID_BITS)
|
||||
|
||||
#define IS_DIR_INDEX_VNID(vnid) \
|
||||
(((vnid) & ARTIFICIAL_VNID_BITS) == DIR_INDEX_VNID_BITS)
|
||||
|
||||
#define IS_ARTIFICIAL_VNID(vnid) \
|
||||
(((vnid) & ARTIFICIAL_VNID_BITS) == ARTIFICIAL_VNID_BITS)
|
||||
|
||||
#define IS_INVALID_VNID(vnid) \
|
||||
((!IS_DIR_CLUSTER_VNID((vnid)) && \
|
||||
!IS_DIR_INDEX_VNID((vnid)) && \
|
||||
!IS_ARTIFICIAL_VNID((vnid))) || \
|
||||
((vnid) & INVALID_VNID_BITS_MASK))
|
||||
|
||||
#define GENERATE_DIR_INDEX_VNID(dircluster, index) \
|
||||
(DIR_INDEX_VNID_BITS | ((vnode_id)(dircluster) << 32) | (index))
|
||||
|
||||
#define GENERATE_DIR_CLUSTER_VNID(dircluster, filecluster) \
|
||||
(DIR_CLUSTER_VNID_BITS | ((vnode_id)(dircluster) << 32) | (filecluster))
|
||||
|
||||
#define CLUSTER_OF_DIR_CLUSTER_VNID(vnid) \
|
||||
((uint32)((vnid) & 0xffffffff))
|
||||
|
||||
#define INDEX_OF_DIR_INDEX_VNID(vnid) \
|
||||
((uint32)((vnid) & 0xffffffff))
|
||||
|
||||
#define DIR_OF_VNID(vnid) \
|
||||
((uint32)(((vnid) >> 32) & ~0xf0000000))
|
||||
|
||||
#define VNODE_PARENT_DIR_CLUSTER(vnode) \
|
||||
CLUSTER_OF_DIR_CLUSTER_VNID((vnode)->dir_vnid)
|
||||
|
||||
#include <lock.h>
|
||||
|
||||
#define VNODE_MAGIC 'treB'
|
||||
|
||||
typedef struct vnode
|
||||
{
|
||||
uint32 magic;
|
||||
vnode_id vnid; // self id
|
||||
vnode_id dir_vnid; // parent vnode id (directory containing entry)
|
||||
|
||||
uint32 disk_image; // 0 = no, 1 = BEOS, 2 = IMAGE.BE
|
||||
|
||||
/* iteration is incremented each time the fat chain changes. it's used by
|
||||
* the file read/write code to determine if it needs to retraverse the
|
||||
* fat chain
|
||||
*/
|
||||
uint32 iteration;
|
||||
|
||||
/* any changes to this block of information should immediately be reflected
|
||||
* on the disk (or at least in the cache) so that get_next_dirent continues
|
||||
* to function properly
|
||||
*/
|
||||
uint32 sindex, eindex; // starting and ending index of directory entry
|
||||
uint32 cluster; // starting cluster of the data
|
||||
uint32 mode; // dos-style attributes
|
||||
off_t st_size; // in bytes
|
||||
time_t st_time;
|
||||
|
||||
uint32 end_cluster; // last cluster of the data
|
||||
|
||||
const char *mime; // mime type (null if none)
|
||||
|
||||
bool dirty; // track if vnode had been written to
|
||||
|
||||
#if TRACK_FILENAME
|
||||
char *filename;
|
||||
#endif
|
||||
} vnode;
|
||||
|
||||
// mode bits
|
||||
#define FAT_READ_ONLY 1
|
||||
#define FAT_HIDDEN 2
|
||||
#define FAT_SYSTEM 4
|
||||
#define FAT_VOLUME 8
|
||||
#define FAT_SUBDIR 16
|
||||
#define FAT_ARCHIVE 32
|
||||
|
||||
#define NSPACE_MAGIC 'smaI'
|
||||
|
||||
struct vcache_entry;
|
||||
|
||||
typedef struct _nspace
|
||||
{
|
||||
uint32 magic;
|
||||
nspace_id id; // ID passed in to fs_mount
|
||||
int fd; // File descriptor
|
||||
char device[256];
|
||||
uint32 flags; // see <fcntl.be.h> for modes
|
||||
|
||||
// info from bpb
|
||||
uint32 bytes_per_sector;
|
||||
uint32 sectors_per_cluster;
|
||||
uint32 reserved_sectors;
|
||||
uint32 fat_count;
|
||||
uint32 root_entries_count;
|
||||
uint32 total_sectors;
|
||||
uint32 sectors_per_fat;
|
||||
uint8 media_descriptor;
|
||||
uint16 fsinfo_sector;
|
||||
|
||||
uint32 total_clusters; // data clusters, that is
|
||||
uint32 free_clusters;
|
||||
uint8 fat_bits;
|
||||
bool fat_mirrored; // true if fat mirroring on
|
||||
uint8 active_fat;
|
||||
|
||||
uint32 root_start; // for fat12 + fat16 only
|
||||
uint32 root_sectors; // for fat12 + fat16 only
|
||||
vnode root_vnode; // root directory
|
||||
int32 vol_entry; // index in root directory
|
||||
char vol_label[12]; // lfn's need not apply
|
||||
|
||||
uint32 data_start;
|
||||
uint32 last_allocated; // last allocated cluster
|
||||
|
||||
vnode_id beos_vnid; // vnid of \BEOS directory
|
||||
bool respect_disk_image;
|
||||
|
||||
int fs_flags; // flags for this mount
|
||||
|
||||
lock vlock; // volume lock
|
||||
|
||||
// vcache state
|
||||
struct {
|
||||
sem_id vc_sem;
|
||||
vnode_id cur_vnid;
|
||||
uint32 cache_size;
|
||||
struct vcache_entry **by_vnid, **by_loc;
|
||||
} vcache;
|
||||
|
||||
struct {
|
||||
uint32 entries;
|
||||
uint32 allocated;
|
||||
vnode_id *vnid_list;
|
||||
} dlist;
|
||||
} nspace;
|
||||
|
||||
#define FS_FLAGS_OP_SYNC 0x1
|
||||
#define FS_FLAGS_LOCK_DOOR 0x2
|
||||
|
||||
#define LOCK_VOL(vol) \
|
||||
if (vol == NULL) { dprintf("null vol\n"); return EINVAL; } else LOCK((vol)->vlock)
|
||||
|
||||
#define UNLOCK_VOL(vol) \
|
||||
UNLOCK((vol)->vlock)
|
||||
|
||||
#define CHECK_MAGIC(name,struc,magick) \
|
||||
int check_##name##_magic(struc *t, char *funcname) \
|
||||
{ \
|
||||
if (t == NULL) { \
|
||||
dprintf("%s passed null " #name " pointer\n", funcname); \
|
||||
return EINVAL; \
|
||||
} else if (t->magic != magick) { \
|
||||
dprintf(#name " (%x) passed to %s has invalid magic number\n", (int)t, funcname); \
|
||||
return EINVAL; \
|
||||
} else \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
int check_vnode_magic(struct vnode *t, char *funcname);
|
||||
int check_nspace_magic(struct _nspace *t, char *funcname);
|
||||
|
||||
#define TOUCH(x) ((void)(x))
|
||||
|
||||
/* debug levels */
|
||||
extern int debug_attr, debug_dir, debug_dlist, debug_dosfs, debug_encodings,
|
||||
debug_fat, debug_file, debug_iter, debug_vcache;
|
||||
|
||||
int _dosfs_sync(nspace *vol);
|
||||
|
||||
#endif
|
1600
src/tests/add-ons/kernel/file_systems/dos/r5/encodings.cpp
Normal file
1600
src/tests/add-ons/kernel/file_systems/dos/r5/encodings.cpp
Normal file
File diff suppressed because it is too large
Load Diff
31
src/tests/add-ons/kernel/file_systems/dos/r5/encodings.h
Normal file
31
src/tests/add-ons/kernel/file_systems/dos/r5/encodings.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_ENCODINGS_H_
|
||||
#define _DOSFS_ENCODINGS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
status_t unicode_to_utf8(const uchar *uni, uint32 unilen, uint8 *utf8,
|
||||
uint32 utf8len);
|
||||
|
||||
bool requires_munged_short_name(const uchar *utf8name,
|
||||
const uchar nshort[11], int encoding);
|
||||
|
||||
bool requires_long_name(const char *utf8, const uchar *unicode);
|
||||
status_t utf8_to_unicode(const char *utf8, uchar *uni, uint32 unilen);
|
||||
status_t munge_short_name2(uchar nshort[11], int encoding);
|
||||
status_t munge_short_name1(uchar nshort[11], int iteration, int encoding);
|
||||
status_t generate_short_name(const uchar *name, const uchar *uni,
|
||||
uint32 unilen, uchar nshort[11], int *encoding);
|
||||
|
||||
status_t msdos_to_utf8(uchar *msdos, uchar *utf8, uint32 utf8len, bool toLower);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
644
src/tests/add-ons/kernel/file_systems/dos/r5/fat.c
Normal file
644
src/tests/add-ons/kernel/file_systems/dos/r5/fat.c
Normal file
@ -0,0 +1,644 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <fsproto.h>
|
||||
#include <lock.h>
|
||||
#include <cache.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#include "dosfs.h"
|
||||
#include "fat.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "file.h"
|
||||
#include "vcache.h"
|
||||
|
||||
#define END_FAT_ENTRY 0x0fffffff
|
||||
#define BAD_FAT_ENTRY 0x0ffffff1
|
||||
|
||||
#define DPRINTF(a,b) if (debug_fat > (a)) dprintf b
|
||||
|
||||
static status_t mirror_fats(nspace *vol, uint32 sector, uint8 *buffer)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
if (!vol->fat_mirrored)
|
||||
return B_OK;
|
||||
|
||||
sector -= vol->active_fat * vol->sectors_per_fat;
|
||||
|
||||
for (i=0;i<vol->fat_count;i++) {
|
||||
if (i == vol->active_fat)
|
||||
continue;
|
||||
cached_write(vol->fd, sector + i*vol->sectors_per_fat, buffer, 1, vol->bytes_per_sector);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static int32 _count_free_clusters_fat32(nspace *vol)
|
||||
{
|
||||
int32 count = 0;
|
||||
uint8 *block;
|
||||
uint32 fat_sector;
|
||||
uint32 i;
|
||||
uint32 cur_sector;
|
||||
|
||||
cur_sector = vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat;
|
||||
|
||||
for(fat_sector = 0; fat_sector < vol->sectors_per_fat; fat_sector++) {
|
||||
block = (uint8 *)get_block(vol->fd, cur_sector, vol->bytes_per_sector);
|
||||
if(block == NULL) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
for(i=0; i < vol->bytes_per_sector; i += sizeof(uint32)) {
|
||||
uint32 val = read32(block, i);
|
||||
if(val == 0) count++;
|
||||
}
|
||||
|
||||
release_block(vol->fd, cur_sector);
|
||||
cur_sector++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// count free: no parameters. returns int32
|
||||
// get_entry: cluster #. returns int32 entry/status
|
||||
// set_entry: cluster #, value. returns int32 status
|
||||
// allocate: # clusters in N, returns int32 status/starting cluster
|
||||
|
||||
enum { _IOCTL_COUNT_FREE_, _IOCTL_GET_ENTRY_, _IOCTL_SET_ENTRY_, _IOCTL_ALLOCATE_N_ENTRIES_ };
|
||||
|
||||
static int32 _fat_ioctl_(nspace *vol, uint32 action, uint32 cluster, int32 N)
|
||||
{
|
||||
int32 result = 0;
|
||||
uint32 n = 0, first = 0, last = 0;
|
||||
uint32 i;
|
||||
uint32 sector;
|
||||
uint32 off, val = 0; /* quiet warning */
|
||||
uint8 *block1, *block2 = NULL; /* quiet warning */
|
||||
|
||||
// mark end of chain for allocations
|
||||
uint32 V = (action == _IOCTL_SET_ENTRY_) ? N : 0x0fffffff;
|
||||
|
||||
ASSERT((action >= _IOCTL_COUNT_FREE_) && (action <= _IOCTL_ALLOCATE_N_ENTRIES_));
|
||||
|
||||
if (check_nspace_magic(vol, "_fat_ioctl_")) return EINVAL;
|
||||
|
||||
DPRINTF(3, ("_fat_ioctl_: action %lx, cluster %lx, N %lx\n", action, cluster, N));
|
||||
|
||||
|
||||
if (action == _IOCTL_COUNT_FREE_) {
|
||||
if(vol->fat_bits == 32)
|
||||
// use a optimized version of the cluster counting algorithms
|
||||
return _count_free_clusters_fat32(vol);
|
||||
else
|
||||
cluster = 2;
|
||||
}
|
||||
|
||||
if (action == _IOCTL_ALLOCATE_N_ENTRIES_)
|
||||
cluster = vol->last_allocated;
|
||||
|
||||
if (action != _IOCTL_COUNT_FREE_) {
|
||||
if (!IS_DATA_CLUSTER(cluster)) {
|
||||
DPRINTF(0, ("_fat_ioctl_ called with invalid cluster (%lx)\n", cluster));
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
off = cluster * vol->fat_bits / 8;
|
||||
sector = vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat +
|
||||
off / vol->bytes_per_sector;
|
||||
off %= vol->bytes_per_sector;
|
||||
|
||||
if ((block1 = (uint8 *)get_block(vol->fd, sector, vol->bytes_per_sector)) == NULL) {
|
||||
DPRINTF(0, ("_fat_ioctl_: error reading fat (sector %lx)\n", sector));
|
||||
return EIO;
|
||||
}
|
||||
|
||||
for (i=0;i<vol->total_clusters;i++) {
|
||||
ASSERT(IS_DATA_CLUSTER(cluster));
|
||||
ASSERT(off == ((cluster * vol->fat_bits / 8) % vol->bytes_per_sector));
|
||||
|
||||
if (vol->fat_bits == 12) {
|
||||
if (off == vol->bytes_per_sector - 1) {
|
||||
if ((block2 = (uint8 *)get_block(vol->fd, ++sector, vol->bytes_per_sector)) == NULL) {
|
||||
DPRINTF(0, ("_fat_ioctl_: error reading fat (sector %lx)\n", sector));
|
||||
result = EIO;
|
||||
sector--;
|
||||
goto bi;
|
||||
}
|
||||
}
|
||||
if (action != _IOCTL_SET_ENTRY_) {
|
||||
if (off == vol->bytes_per_sector - 1) {
|
||||
val = block1[off] + 0x100*block2[0];
|
||||
} else
|
||||
val = block1[off] + 0x100*block1[off+1];
|
||||
if (cluster & 1) {
|
||||
val >>= 4;
|
||||
} else {
|
||||
val &= 0xfff;
|
||||
}
|
||||
if (val > 0xff0) val |= 0x0ffff000;
|
||||
}
|
||||
if (((action == _IOCTL_ALLOCATE_N_ENTRIES_) && (val == 0)) ||
|
||||
(action == _IOCTL_SET_ENTRY_)) {
|
||||
uint32 andmask, ormask;
|
||||
if (cluster & 1) {
|
||||
ormask = (V & 0xfff) << 4;
|
||||
andmask = 0xf;
|
||||
} else {
|
||||
ormask = V & 0xfff;
|
||||
andmask = 0xf000;
|
||||
}
|
||||
block1[off] &= (andmask & 0xff);
|
||||
block1[off] |= (ormask & 0xff);
|
||||
if (off == vol->bytes_per_sector - 1) {
|
||||
mark_blocks_dirty(vol->fd, sector - 1, 1);
|
||||
mirror_fats(vol, sector - 1, block1);
|
||||
block2[0] &= (andmask >> 8);
|
||||
block2[0] |= (ormask >> 8);
|
||||
} else {
|
||||
block1[off+1] &= (andmask >> 8);
|
||||
block1[off+1] |= (ormask >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (off == vol->bytes_per_sector - 1) {
|
||||
off = (cluster & 1) ? 1 : 0;
|
||||
release_block(vol->fd, sector - 1);
|
||||
block1 = block2;
|
||||
} else {
|
||||
off += (cluster & 1) ? 2 : 1;
|
||||
}
|
||||
} else if (vol->fat_bits == 16) {
|
||||
if (action != _IOCTL_SET_ENTRY_) {
|
||||
val = read16(block1, off);
|
||||
// val = block1[off] + 0x100*block1[off+1];
|
||||
if (val > 0xfff0) val |= 0x0fff0000;
|
||||
}
|
||||
if (((action == _IOCTL_ALLOCATE_N_ENTRIES_) && (val == 0)) ||
|
||||
(action == _IOCTL_SET_ENTRY_)) {
|
||||
*(uint16 *)&block1[off] = B_HOST_TO_LENDIAN_INT16(V);
|
||||
// block1[off] = V & 0xff;
|
||||
// block1[off+1] = (V >> 8) & 0xff;
|
||||
}
|
||||
off += 2;
|
||||
} else if (vol->fat_bits == 32) {
|
||||
if (action != _IOCTL_SET_ENTRY_) {
|
||||
val = read32(block1, off) & 0x0fffffff;
|
||||
// val = block1[off] + 0x100*block1[off+1] +
|
||||
// 0x10000*block1[off+2] + 0x1000000*(block1[off+3]&0x0f);
|
||||
// if (val > 0x0ffffff0) val |= 0x00000000;
|
||||
}
|
||||
if (((action == _IOCTL_ALLOCATE_N_ENTRIES_) && (val == 0)) ||
|
||||
(action == _IOCTL_SET_ENTRY_)) {
|
||||
ASSERT((V & 0xf0000000) == 0);
|
||||
*(uint32 *)&block1[off] = B_HOST_TO_LENDIAN_INT32(V);
|
||||
// block1[off] = V & 0xff;
|
||||
// block1[off+1] = (V >> 8) & 0xff;
|
||||
// block1[off+2] = (V >> 16) & 0xff;
|
||||
// block1[off+3] = (V >> 24) & 0x0f;
|
||||
// ASSERT(V == (block1[off] + 0x100*block1[off+1] + 0x10000*block1[off+2] + 0x1000000*block1[off+3]));
|
||||
}
|
||||
off += 4;
|
||||
} else
|
||||
ASSERT(0);
|
||||
|
||||
if (action == _IOCTL_COUNT_FREE_) {
|
||||
if (val == 0)
|
||||
result++;
|
||||
} else if (action == _IOCTL_GET_ENTRY_) {
|
||||
result = val;
|
||||
goto bi;
|
||||
} else if (action == _IOCTL_SET_ENTRY_) {
|
||||
mark_blocks_dirty(vol->fd, sector, 1);
|
||||
mirror_fats(vol, sector, block1);
|
||||
goto bi;
|
||||
} else if ((action == _IOCTL_ALLOCATE_N_ENTRIES_) && (val == 0)) {
|
||||
vol->free_clusters--;
|
||||
mark_blocks_dirty(vol->fd, sector, 1);
|
||||
mirror_fats(vol, sector, block1);
|
||||
if (n == 0) {
|
||||
ASSERT(first == 0);
|
||||
first = last = cluster;
|
||||
} else {
|
||||
ASSERT(IS_DATA_CLUSTER(first));
|
||||
ASSERT(IS_DATA_CLUSTER(last));
|
||||
// set last cluster to point to us
|
||||
|
||||
if ((result = _fat_ioctl_(vol,_IOCTL_SET_ENTRY_,last,cluster)) < 0) {
|
||||
ASSERT(0);
|
||||
goto bi;
|
||||
}
|
||||
|
||||
last = cluster;
|
||||
}
|
||||
|
||||
if (++n == N)
|
||||
goto bi;
|
||||
}
|
||||
|
||||
// iterate cluster and sector if needed
|
||||
if (++cluster == vol->total_clusters + 2) {
|
||||
release_block(vol->fd, sector);
|
||||
|
||||
cluster = 2;
|
||||
off = 2 * vol->fat_bits / 8;
|
||||
sector = vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat;
|
||||
|
||||
block1 = (uint8 *)get_block(vol->fd, sector, vol->bytes_per_sector);
|
||||
}
|
||||
|
||||
if (off >= vol->bytes_per_sector) {
|
||||
release_block(vol->fd, sector);
|
||||
off -= vol->bytes_per_sector; sector++;
|
||||
ASSERT(sector < vol->reserved_sectors + (vol->active_fat + 1) * vol->sectors_per_fat);
|
||||
block1 = (uint8 *)get_block(vol->fd, sector, vol->bytes_per_sector);
|
||||
}
|
||||
|
||||
if (block1 == NULL) {
|
||||
DPRINTF(0, ("_fat_ioctl_: error reading fat (sector %lx)\n", sector));
|
||||
result = EIO;
|
||||
goto bi;
|
||||
}
|
||||
}
|
||||
|
||||
bi:
|
||||
if (block1) release_block(vol->fd, sector);
|
||||
|
||||
if (action == _IOCTL_ALLOCATE_N_ENTRIES_) {
|
||||
if (result < 0) {
|
||||
DPRINTF(0, ("pooh. there is a problem. clearing chain (%lx)\n", first));
|
||||
if (first != 0) clear_fat_chain(vol, first);
|
||||
} else if (n != N) {
|
||||
DPRINTF(0, ("not enough free entries (%lx/%lx found)\n", n, N));
|
||||
if (first != 0) clear_fat_chain(vol, first);
|
||||
result = ENOSPC;
|
||||
} else if (result == 0) {
|
||||
vol->last_allocated = cluster;
|
||||
result = first;
|
||||
ASSERT(IS_DATA_CLUSTER(first));
|
||||
}
|
||||
}
|
||||
|
||||
if (result < B_OK)
|
||||
DPRINTF(0, ("_fat_ioctl_ error: action = %lx cluster = %lx N = %lx (%s)\n", action, cluster, N, strerror(result)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 count_free_clusters(nspace *vol)
|
||||
{
|
||||
return _fat_ioctl_(vol, _IOCTL_COUNT_FREE_, 0, 0);
|
||||
}
|
||||
|
||||
static int32 get_fat_entry(nspace *vol, uint32 cluster)
|
||||
{
|
||||
int32 value = _fat_ioctl_(vol, _IOCTL_GET_ENTRY_, cluster, 0);
|
||||
|
||||
if (value < 0)
|
||||
return value;
|
||||
|
||||
if ((value == 0) || IS_DATA_CLUSTER(value))
|
||||
return value;
|
||||
|
||||
if (value > 0x0ffffff7)
|
||||
return END_FAT_ENTRY;
|
||||
|
||||
if (value > 0x0ffffff0)
|
||||
return BAD_FAT_ENTRY;
|
||||
|
||||
DPRINTF(0, ("invalid fat entry: %lx\n", value));
|
||||
return BAD_FAT_ENTRY;
|
||||
}
|
||||
|
||||
static status_t set_fat_entry(nspace *vol, uint32 cluster, int32 value)
|
||||
{
|
||||
return _fat_ioctl_(vol, _IOCTL_SET_ENTRY_, cluster, value);
|
||||
}
|
||||
|
||||
// traverse n fat entries
|
||||
int32 get_nth_fat_entry(nspace *vol, int32 cluster, uint32 n)
|
||||
{
|
||||
if (check_nspace_magic(vol, "get_nth_fat_entry")) return EINVAL;
|
||||
|
||||
while (n--) {
|
||||
cluster = get_fat_entry(vol, cluster);
|
||||
|
||||
if (!IS_DATA_CLUSTER(cluster))
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT(cluster != 0);
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
// count number of clusters in fat chain starting at given cluster
|
||||
// should only be used for calculating directory sizes because it doesn't
|
||||
// return proper error codes
|
||||
uint32 count_clusters(nspace *vol, int32 cluster)
|
||||
{
|
||||
int32 count = 0;
|
||||
|
||||
DPRINTF(2, ("count_clusters %lx\n", cluster));
|
||||
|
||||
if (check_nspace_magic(vol, "count_clusters")) return 0;
|
||||
|
||||
// not intended for use on root directory
|
||||
if (!IS_DATA_CLUSTER(cluster)) {
|
||||
DPRINTF(0, ("count_clusters called on invalid cluster (%lx)\n", cluster));
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (IS_DATA_CLUSTER(cluster)) {
|
||||
count++;
|
||||
|
||||
// break out of circular fat chains in a sketchy manner
|
||||
if (count == vol->total_clusters)
|
||||
return 0;
|
||||
|
||||
cluster = get_fat_entry(vol, cluster);
|
||||
}
|
||||
|
||||
DPRINTF(2, ("count_clusters %lx = %lx\n", cluster, count));
|
||||
|
||||
if (cluster == END_FAT_ENTRY)
|
||||
return count;
|
||||
|
||||
dprintf("cluster = %lx\n", cluster);
|
||||
ASSERT(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t clear_fat_chain(nspace *vol, uint32 cluster)
|
||||
{
|
||||
int32 c;
|
||||
status_t result;
|
||||
|
||||
if (!IS_DATA_CLUSTER(cluster)) {
|
||||
DPRINTF(0, ("clear_fat_chain called on invalid cluster (%lx)\n", cluster));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ASSERT(count_clusters(vol, cluster) != 0);
|
||||
|
||||
DPRINTF(2, ("clearing fat chain: %lx", cluster));
|
||||
while (IS_DATA_CLUSTER(cluster)) {
|
||||
if ((c = get_fat_entry(vol, cluster)) < 0) {
|
||||
DPRINTF(0, ("clear_fat_chain: error clearing fat entry for cluster %lx (%s)\n", cluster, strerror(c)));
|
||||
return c;
|
||||
}
|
||||
if ((result = set_fat_entry(vol, cluster, 0)) != B_OK) {
|
||||
DPRINTF(0, ("clear_fat_chain: error clearing fat entry for cluster %lx (%s)\n", cluster, strerror(result)));
|
||||
return result;
|
||||
}
|
||||
vol->free_clusters++;
|
||||
cluster = c;
|
||||
DPRINTF(2, (", %lx", cluster));
|
||||
}
|
||||
DPRINTF(2, ("\n"));
|
||||
|
||||
if (cluster != END_FAT_ENTRY)
|
||||
dprintf("clear_fat_chain: fat chain terminated improperly with %lx\n", cluster);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t allocate_n_fat_entries(nspace *vol, int32 n, int32 *start)
|
||||
{
|
||||
int32 c;
|
||||
|
||||
ASSERT(n > 0);
|
||||
|
||||
DPRINTF(2, ("allocating %lx fat entries\n", n));
|
||||
|
||||
c = _fat_ioctl_(vol, _IOCTL_ALLOCATE_N_ENTRIES_, 0, n);
|
||||
if (c < 0)
|
||||
return c;
|
||||
|
||||
ASSERT(IS_DATA_CLUSTER(c));
|
||||
ASSERT(count_clusters(vol, c) == n);
|
||||
|
||||
DPRINTF(2, ("allocated %lx fat entries at %lx\n", n, c));
|
||||
|
||||
*start = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t set_fat_chain_length(nspace *vol, vnode *node, uint32 clusters)
|
||||
{
|
||||
status_t result;
|
||||
int32 i, c, n;
|
||||
|
||||
DPRINTF(1, ("set_fat_chain_length: %Lx to %lx clusters (%lx)\n", node->vnid, clusters, node->cluster));
|
||||
|
||||
if (IS_FIXED_ROOT(node->cluster) || (!IS_DATA_CLUSTER(node->cluster) && (node->cluster != 0))) {
|
||||
DPRINTF(0, ("set_fat_chain_length called on invalid cluster (%lx)\n", node->cluster));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (clusters == 0) {
|
||||
DPRINTF(1, ("truncating node to zero bytes\n"));
|
||||
if (node->cluster == 0)
|
||||
return B_OK;
|
||||
c = node->cluster;
|
||||
if ((result = clear_fat_chain(vol, c)) != B_OK)
|
||||
return result;
|
||||
node->cluster = 0;
|
||||
node->end_cluster = 0;
|
||||
|
||||
// XXX: don't have to do this this way -- can clean up nicely
|
||||
do {
|
||||
result = vcache_set_entry(vol, node->vnid,
|
||||
GENERATE_DIR_INDEX_VNID(node->dir_vnid, node->sindex));
|
||||
// repeat until memory is freed up
|
||||
if (result != B_OK)
|
||||
snooze(5000LL);
|
||||
} while (result != B_OK);
|
||||
|
||||
/* write to disk so that get_next_dirent doesn't barf */
|
||||
write_vnode_entry(vol, node);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (node->cluster == 0) {
|
||||
DPRINTF(1, ("node has no clusters. adding %lx clusters\n", clusters));
|
||||
|
||||
if ((result = allocate_n_fat_entries(vol, clusters, &n)) != B_OK)
|
||||
return result;
|
||||
node->cluster = n;
|
||||
node->end_cluster = get_nth_fat_entry(vol, n, clusters - 1);
|
||||
|
||||
// XXX: don't have to do this this way -- can clean up nicely
|
||||
do {
|
||||
result = vcache_set_entry(vol, node->vnid,
|
||||
GENERATE_DIR_CLUSTER_VNID(node->dir_vnid, node->cluster));
|
||||
// repeat until memory is freed up
|
||||
if (result != B_OK)
|
||||
snooze(5000LL);
|
||||
} while (result != B_OK);
|
||||
|
||||
/* write to disk so that get_next_dirent doesn't barf */
|
||||
write_vnode_entry(vol, node);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i = (node->st_size + vol->bytes_per_sector * vol->sectors_per_cluster - 1) /
|
||||
vol->bytes_per_sector / vol->sectors_per_cluster;
|
||||
if (i == clusters) return B_OK;
|
||||
|
||||
if (clusters > i) {
|
||||
// add new fat entries
|
||||
DPRINTF(1, ("adding %lx new fat entries\n", clusters - i));
|
||||
if ((result = allocate_n_fat_entries(vol, clusters - i, &n)) != B_OK)
|
||||
return result;
|
||||
|
||||
ASSERT(IS_DATA_CLUSTER(n));
|
||||
|
||||
result = set_fat_entry(vol, node->end_cluster, n);
|
||||
if (result < B_OK) {
|
||||
clear_fat_chain(vol, n);
|
||||
return result;
|
||||
}
|
||||
|
||||
node->end_cluster = get_nth_fat_entry(vol, n, clusters - i - 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// traverse fat chain
|
||||
c = node->cluster;
|
||||
n = get_fat_entry(vol,c);
|
||||
for (i=1;i<clusters;i++) {
|
||||
if (!IS_DATA_CLUSTER(n))
|
||||
break;
|
||||
c = n;
|
||||
n = get_fat_entry(vol,c);
|
||||
}
|
||||
|
||||
ASSERT(i == clusters); ASSERT(n != END_FAT_ENTRY);
|
||||
if ((i == clusters) && (n == END_FAT_ENTRY)) return B_OK;
|
||||
|
||||
if (n < 0) return n;
|
||||
if ((n != END_FAT_ENTRY) && !IS_DATA_CLUSTER(n)) return EINVAL;
|
||||
|
||||
// clear trailing fat entries
|
||||
DPRINTF(1, ("clearing trailing fat entries\n"));
|
||||
if ((result = set_fat_entry(vol, c, 0x0fffffff)) != B_OK)
|
||||
return result;
|
||||
node->end_cluster = c;
|
||||
return clear_fat_chain(vol, n);
|
||||
}
|
||||
|
||||
void dump_fat_chain(nspace *vol, uint32 cluster)
|
||||
{
|
||||
dprintf("fat chain: %lx", cluster);
|
||||
while (IS_DATA_CLUSTER(cluster)) {
|
||||
cluster = get_fat_entry(vol, cluster);
|
||||
dprintf(" %lx", cluster);
|
||||
}
|
||||
dprintf("\n");
|
||||
}
|
||||
|
||||
status_t fragment(nspace *vol, uint32 *pattern)
|
||||
{
|
||||
uint32 sector, offset, previous_entry, i, val;
|
||||
uchar *buffer;
|
||||
bool dirty = FALSE;
|
||||
|
||||
srand(time(NULL)|1);
|
||||
|
||||
if (vol->fat_bits == 16)
|
||||
previous_entry = 0xffff;
|
||||
else if (vol->fat_bits == 32)
|
||||
previous_entry = 0x0fffffff;
|
||||
else {
|
||||
dprintf("fragment: only for FAT16 and FAT32\n");
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
sector = vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat +
|
||||
((vol->total_clusters + 2 - 1) * (vol->fat_bits / 8)) /
|
||||
vol->bytes_per_sector;
|
||||
offset = ((vol->total_clusters + 2 - 1) * (vol->fat_bits / 8)) %
|
||||
vol->bytes_per_sector;
|
||||
|
||||
buffer = (uchar *)get_block(vol->fd, sector, vol->bytes_per_sector);
|
||||
if (!buffer) {
|
||||
dprintf("fragment: error getting fat block %lx\n", sector);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
val = pattern ? *pattern : rand();
|
||||
|
||||
for (i=vol->total_clusters+1;i>=2;i--) {
|
||||
if (val & (1 << (i & 31))) {
|
||||
if (vol->fat_bits == 16) {
|
||||
if (read16(buffer, offset) == 0) {
|
||||
buffer[offset+0] = (previous_entry ) & 0xff;
|
||||
buffer[offset+1] = (previous_entry >> 8) & 0xff;
|
||||
previous_entry = i;
|
||||
dirty = TRUE;
|
||||
vol->free_clusters--;
|
||||
}
|
||||
} else {
|
||||
if (read32(buffer, offset) == 0) {
|
||||
buffer[offset+0] = (previous_entry ) & 0xff;
|
||||
buffer[offset+1] = (previous_entry >> 8) & 0xff;
|
||||
buffer[offset+2] = (previous_entry >> 16) & 0xff;
|
||||
buffer[offset+3] = (previous_entry >> 24) & 0xff;
|
||||
previous_entry = i;
|
||||
dirty = TRUE;
|
||||
vol->free_clusters--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!offset) {
|
||||
if (dirty) {
|
||||
mark_blocks_dirty(vol->fd, sector, 1);
|
||||
mirror_fats(vol, sector, buffer);
|
||||
}
|
||||
release_block(vol->fd, sector);
|
||||
|
||||
dirty = FALSE;
|
||||
sector--;
|
||||
|
||||
buffer = (uchar *)get_block(vol->fd, sector,
|
||||
vol->bytes_per_sector);
|
||||
if (!buffer) {
|
||||
dprintf("fragment: error getting fat block %lx\n", sector);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
offset = (offset - vol->fat_bits / 8 + vol->bytes_per_sector) %
|
||||
vol->bytes_per_sector;
|
||||
|
||||
if (!pattern && ((i & 31) == 31))
|
||||
val = rand();
|
||||
}
|
||||
|
||||
if (dirty) {
|
||||
mark_blocks_dirty(vol->fd, sector, 1);
|
||||
mirror_fats(vol, sector, buffer);
|
||||
}
|
||||
release_block(vol->fd, sector);
|
||||
|
||||
vol->last_allocated = (rand() % vol->total_clusters) + 2;
|
||||
|
||||
return B_OK;
|
||||
}
|
31
src/tests/add-ons/kernel/file_systems/dos/r5/fat.h
Normal file
31
src/tests/add-ons/kernel/file_systems/dos/r5/fat.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_FAT_H_
|
||||
#define _DOSFS_FAT_H_
|
||||
|
||||
#define vIS_DATA_CLUSTER(vol,cluster) (((cluster) >= 2) && ((cluster) < vol->total_clusters + 2))
|
||||
#define IS_DATA_CLUSTER(cluster) vIS_DATA_CLUSTER(vol,cluster)
|
||||
|
||||
// cluster 1 represents root directory for fat12 and fat16
|
||||
#define IS_FIXED_ROOT(cluster) ((cluster) == 1)
|
||||
|
||||
int32 count_free_clusters(nspace *vol);
|
||||
int32 get_nth_fat_entry(nspace *vol, int32 cluster, uint32 n);
|
||||
uint32 count_clusters(nspace *vol, int32 cluster);
|
||||
|
||||
/* remember to update vnode iteration after calling this function */
|
||||
status_t clear_fat_chain(nspace *vol, uint32 cluster);
|
||||
|
||||
/* remember to set end of chain field when merging into a vnode */
|
||||
status_t allocate_n_fat_entries(nspace *vol, int32 n, int32 *start);
|
||||
|
||||
/* remember to update vnode iteration after calling this function */
|
||||
status_t set_fat_chain_length(nspace *vol, vnode *node, uint32 clusters);
|
||||
|
||||
void dump_fat_chain(nspace *vol, uint32 cluster);
|
||||
|
||||
status_t fragment(nspace *vol, uint32 *pattern);
|
||||
|
||||
#endif
|
1406
src/tests/add-ons/kernel/file_systems/dos/r5/file.c
Normal file
1406
src/tests/add-ons/kernel/file_systems/dos/r5/file.c
Normal file
File diff suppressed because it is too large
Load Diff
30
src/tests/add-ons/kernel/file_systems/dos/r5/file.h
Normal file
30
src/tests/add-ons/kernel/file_systems/dos/r5/file.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_FILE_H_
|
||||
#define _DOSFS_FILE_H_
|
||||
|
||||
status_t write_vnode_entry(nspace *vol, vnode *node);
|
||||
|
||||
int dosfs_write_vnode(void *_vol, void *_node, char r);
|
||||
int dosfs_rstat(void *_vol, void *_node, struct stat *st);
|
||||
int dosfs_open(void *_vol, void *_node, int omode, void **cookie);
|
||||
int dosfs_read(void *_vol, void *_node, void *cookie, off_t pos,
|
||||
void *buf, size_t *len);
|
||||
int dosfs_free_cookie(void *vol, void *node, void *cookie);
|
||||
int dosfs_close(void *vol, void *node, void *cookie);
|
||||
|
||||
int dosfs_remove_vnode(void *vol, void *node, char r);
|
||||
int dosfs_create(void *vol, void *dir, const char *name,
|
||||
int perms, int omode, vnode_id *vnid, void **cookie);
|
||||
int dosfs_mkdir(void *vol, void *dir, const char *name, int perms);
|
||||
int dosfs_rename(void *vol, void *olddir, const char *oldname,
|
||||
void *newdir, const char *newname);
|
||||
int dosfs_unlink(void *vol, void *dir, const char *name);
|
||||
int dosfs_rmdir(void *vol, void *dir, const char *name);
|
||||
int dosfs_wstat(void *vol, void *node, struct stat *st, long mask);
|
||||
int dosfs_write(void *vol, void *node, void *cookie, off_t pos,
|
||||
const void *buf, size_t *len);
|
||||
|
||||
#endif
|
245
src/tests/add-ons/kernel/file_systems/dos/r5/fsproto.h
Normal file
245
src/tests/add-ons/kernel/file_systems/dos/r5/fsproto.h
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
#define B_CUR_FS_API_VERSION 2
|
||||
|
||||
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_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);
|
||||
} 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 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
|
310
src/tests/add-ons/kernel/file_systems/dos/r5/iter.c
Normal file
310
src/tests/add-ons/kernel/file_systems/dos/r5/iter.c
Normal file
@ -0,0 +1,310 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <fsproto.h>
|
||||
#include <lock.h>
|
||||
#include <cache.h>
|
||||
|
||||
#include "iter.h"
|
||||
#include "dosfs.h"
|
||||
#include "fat.h"
|
||||
#include "util.h"
|
||||
|
||||
#define DPRINTF(a,b) if (debug_iter > (a)) dprintf b
|
||||
|
||||
CHECK_MAGIC(diri,struct diri,DIRI_MAGIC)
|
||||
|
||||
static int _validate_cs_(nspace *vol, uint32 cluster, uint32 sector)
|
||||
{
|
||||
if (sector < 0) return -1;
|
||||
|
||||
if ((vol->fat_bits != 32) && IS_FIXED_ROOT(cluster)) { // fat12 or fat16 root
|
||||
if (sector >= vol->root_sectors)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sector >= vol->sectors_per_cluster) return -1;
|
||||
|
||||
if (!IS_DATA_CLUSTER(cluster)) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static off_t _csi_to_block_(struct csi *csi)
|
||||
{
|
||||
// presumes the caller has already called _validate_cs_ on the argument
|
||||
ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0);
|
||||
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
|
||||
return EINVAL;
|
||||
|
||||
if (IS_FIXED_ROOT(csi->cluster))
|
||||
return csi->vol->root_start + csi->sector;
|
||||
|
||||
return csi->vol->data_start +
|
||||
(off_t)(csi->cluster - 2)* csi->vol->sectors_per_cluster +
|
||||
csi->sector;
|
||||
}
|
||||
|
||||
int init_csi(nspace *vol, uint32 cluster, uint32 sector, struct csi *csi)
|
||||
{
|
||||
int ret;
|
||||
if ((ret = _validate_cs_(vol,cluster,sector)) != 0)
|
||||
return ret;
|
||||
|
||||
csi->vol = vol; csi->cluster = cluster; csi->sector = sector;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iter_csi(struct csi *csi, int sectors)
|
||||
{
|
||||
if (csi->sector == 0xffff) // check if already at end of chain
|
||||
return -1;
|
||||
|
||||
if (sectors < 0)
|
||||
return EINVAL;
|
||||
|
||||
if (sectors == 0)
|
||||
return 0;
|
||||
|
||||
if (IS_FIXED_ROOT(csi->cluster)) {
|
||||
csi->sector += sectors;
|
||||
if (csi->sector < csi->vol->root_sectors)
|
||||
return 0;
|
||||
} else {
|
||||
csi->sector += sectors;
|
||||
if (csi->sector < csi->vol->sectors_per_cluster)
|
||||
return 0;
|
||||
csi->cluster = get_nth_fat_entry(csi->vol, csi->cluster, csi->sector / csi->vol->sectors_per_cluster);
|
||||
|
||||
if ((int32)csi->cluster < 0) {
|
||||
csi->sector = 0xffff;
|
||||
return csi->cluster;
|
||||
}
|
||||
|
||||
if (vIS_DATA_CLUSTER(csi->vol,csi->cluster)) {
|
||||
csi->sector %= csi->vol->sectors_per_cluster;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
csi->sector = 0xffff;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8 *csi_get_block(struct csi *csi)
|
||||
{
|
||||
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
|
||||
return NULL;
|
||||
|
||||
return get_block(csi->vol->fd, _csi_to_block_(csi), csi->vol->bytes_per_sector);
|
||||
}
|
||||
|
||||
status_t csi_release_block(struct csi *csi)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
|
||||
return EINVAL;
|
||||
|
||||
err = release_block(csi->vol->fd, _csi_to_block_(csi));
|
||||
ASSERT(err == B_OK);
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t csi_mark_block_dirty(struct csi *csi)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0);
|
||||
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
|
||||
return EINVAL;
|
||||
|
||||
err = mark_blocks_dirty(csi->vol->fd, _csi_to_block_(csi), 1);
|
||||
ASSERT(err == B_OK);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* XXX: not the most efficient implementation, but it gets the job done */
|
||||
status_t csi_read_blocks(struct csi *csi, uint8 *buffer, ssize_t len)
|
||||
{
|
||||
struct csi old_csi;
|
||||
uint32 sectors;
|
||||
off_t block;
|
||||
status_t err;
|
||||
|
||||
ASSERT(len >= csi->vol->bytes_per_sector);
|
||||
|
||||
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
|
||||
return EINVAL;
|
||||
|
||||
sectors = 1;
|
||||
block = _csi_to_block_(csi);
|
||||
|
||||
while (1) {
|
||||
old_csi = *csi;
|
||||
err = iter_csi(csi, 1);
|
||||
if (len < (sectors + 1) * csi->vol->bytes_per_sector)
|
||||
break;
|
||||
if ((err < B_OK) || (block + sectors != _csi_to_block_(csi)))
|
||||
break;
|
||||
sectors++;
|
||||
}
|
||||
|
||||
err = cached_read(csi->vol->fd, block, buffer, sectors, csi->vol->bytes_per_sector);
|
||||
if (err < B_OK)
|
||||
return err;
|
||||
|
||||
*csi = old_csi;
|
||||
|
||||
return sectors * csi->vol->bytes_per_sector;
|
||||
}
|
||||
|
||||
status_t csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len)
|
||||
{
|
||||
struct csi old_csi;
|
||||
uint32 sectors;
|
||||
off_t block;
|
||||
status_t err;
|
||||
|
||||
ASSERT(len >= csi->vol->bytes_per_sector);
|
||||
|
||||
ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0);
|
||||
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
|
||||
return EINVAL;
|
||||
|
||||
sectors = 1;
|
||||
block = _csi_to_block_(csi);
|
||||
|
||||
while (1) {
|
||||
old_csi = *csi;
|
||||
err = iter_csi(csi, 1);
|
||||
if (len < (sectors + 1) * csi->vol->bytes_per_sector)
|
||||
break;
|
||||
if ((err < B_OK) || (block + sectors != _csi_to_block_(csi)))
|
||||
break;
|
||||
sectors++;
|
||||
}
|
||||
|
||||
err = cached_write(csi->vol->fd, block, buffer, sectors, csi->vol->bytes_per_sector);
|
||||
if (err < B_OK)
|
||||
return err;
|
||||
|
||||
/* return the last state of the iterator because that's what dosfs_write
|
||||
* expects. this lets it meaningfully cache the state even when it's
|
||||
* writing to the end of the file. */
|
||||
*csi = old_csi;
|
||||
|
||||
return sectors * csi->vol->bytes_per_sector;
|
||||
}
|
||||
|
||||
status_t csi_write_block(struct csi *csi, uint8 *buffer)
|
||||
{
|
||||
ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0);
|
||||
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
|
||||
return EINVAL;
|
||||
|
||||
return cached_write(csi->vol->fd, _csi_to_block_(csi), buffer, 1, csi->vol->bytes_per_sector);
|
||||
}
|
||||
|
||||
static void _diri_release_current_block_(struct diri *diri)
|
||||
{
|
||||
ASSERT(diri->current_block);
|
||||
if (diri->current_block == NULL)
|
||||
return;
|
||||
csi_release_block(&(diri->csi));
|
||||
diri->current_block = NULL;
|
||||
}
|
||||
|
||||
uint8 *diri_init(nspace *vol, uint32 cluster, uint32 index, struct diri *diri)
|
||||
{
|
||||
diri->magic = DIRI_MAGIC;
|
||||
diri->current_block = NULL;
|
||||
|
||||
if (cluster >= vol->total_clusters + 2)
|
||||
return NULL;
|
||||
|
||||
if (init_csi(vol,cluster,0,&(diri->csi)) != 0)
|
||||
return NULL;
|
||||
|
||||
diri->starting_cluster = cluster;
|
||||
diri->current_index = index;
|
||||
if (index >= vol->bytes_per_sector / 0x20) {
|
||||
if (iter_csi(&(diri->csi), diri->current_index / (vol->bytes_per_sector / 0x20)) != 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get current sector
|
||||
diri->current_block = csi_get_block(&(diri->csi));
|
||||
|
||||
if (diri->current_block == NULL)
|
||||
return NULL;
|
||||
|
||||
return diri->current_block + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20;
|
||||
}
|
||||
|
||||
int diri_free(struct diri *diri)
|
||||
{
|
||||
if (check_diri_magic(diri, "diri_free")) return EINVAL;
|
||||
|
||||
diri->magic = ~DIRI_MAGIC; // trash magic number
|
||||
|
||||
if (diri->current_block)
|
||||
_diri_release_current_block_(diri);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 *diri_current_entry(struct diri *diri)
|
||||
{
|
||||
if (check_diri_magic(diri, "diri_current_entry")) return NULL;
|
||||
|
||||
if (diri->current_block == NULL)
|
||||
return NULL;
|
||||
|
||||
return diri->current_block + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20;
|
||||
}
|
||||
|
||||
uint8 *diri_next_entry(struct diri *diri)
|
||||
{
|
||||
if (check_diri_magic(diri, "diri_next_entry")) return NULL;
|
||||
|
||||
if (diri->current_block == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((++diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20)) == 0) {
|
||||
_diri_release_current_block_(diri);
|
||||
if (iter_csi(&(diri->csi), 1) != 0)
|
||||
return NULL;
|
||||
diri->current_block = csi_get_block(&(diri->csi));
|
||||
if (diri->current_block == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return diri->current_block + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20;
|
||||
}
|
||||
|
||||
uint8 *diri_rewind(struct diri *diri)
|
||||
{
|
||||
if (check_diri_magic(diri, "diri_rewind")) return NULL;
|
||||
|
||||
if (diri->current_index > (diri->csi.vol->bytes_per_sector / 0x20 - 1)) {
|
||||
if (diri->current_block)
|
||||
_diri_release_current_block_(diri);
|
||||
if (init_csi(diri->csi.vol, diri->starting_cluster, 0, &(diri->csi)) != 0)
|
||||
return NULL;
|
||||
diri->current_block = csi_get_block(&(diri->csi));
|
||||
}
|
||||
diri->current_index = 0;
|
||||
return diri->current_block;
|
||||
}
|
||||
|
||||
void diri_mark_dirty(struct diri *diri)
|
||||
{
|
||||
csi_mark_block_dirty(&(diri->csi));
|
||||
}
|
47
src/tests/add-ons/kernel/file_systems/dos/r5/iter.h
Normal file
47
src/tests/add-ons/kernel/file_systems/dos/r5/iter.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_ITER_H_
|
||||
#define _DOSFS_ITER_H_
|
||||
|
||||
struct _nspace;
|
||||
|
||||
/* csi keeps track of current cluster and sector info */
|
||||
struct csi
|
||||
{
|
||||
struct _nspace *vol;
|
||||
uint32 cluster;
|
||||
uint32 sector;
|
||||
};
|
||||
|
||||
int init_csi(struct _nspace *vol, uint32 cluster, uint32 sector, struct csi *csi);
|
||||
int iter_csi(struct csi *csi, int sectors);
|
||||
uint8 *csi_get_block(struct csi *csi);
|
||||
status_t csi_release_block(struct csi *csi);
|
||||
status_t csi_mark_block_dirty(struct csi *csi);
|
||||
status_t csi_read_blocks(struct csi *csi, uint8 *buffer, ssize_t len);
|
||||
status_t csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len);
|
||||
status_t csi_write_block(struct csi *csi, uint8 *buffer);
|
||||
|
||||
/* directory entry iterator */
|
||||
#define DIRI_MAGIC '!duM'
|
||||
struct diri
|
||||
{
|
||||
uint32 magic;
|
||||
struct csi csi;
|
||||
uint32 starting_cluster;
|
||||
uint32 current_index;
|
||||
uint8 *current_block;
|
||||
};
|
||||
|
||||
uint8 *diri_init(struct _nspace *vol, uint32 cluster, uint32 index, struct diri *diri);
|
||||
int diri_free(struct diri *diri);
|
||||
uint8 *diri_current_entry(struct diri *diri);
|
||||
uint8 *diri_next_entry(struct diri *diri);
|
||||
uint8 *diri_rewind(struct diri *diri);
|
||||
void diri_mark_dirty(struct diri *diri);
|
||||
|
||||
int check_diri_magic(struct diri *t, char *funcname);
|
||||
|
||||
#endif
|
23
src/tests/add-ons/kernel/file_systems/dos/r5/kalloc.h
Normal file
23
src/tests/add-ons/kernel/file_systems/dos/r5/kalloc.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#ifndef _ALLOC_H
|
||||
#define _ALLOC_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#if KMALLOC_TRACKING
|
||||
extern bool kmalloc_tracking_enabled;
|
||||
#endif
|
||||
|
||||
extern void init_malloc(void);
|
||||
extern void init_smalloc(void);
|
||||
|
||||
extern void * smalloc(unsigned int nbytes);
|
||||
extern void sfree(void *ptr);
|
||||
extern void * scalloc(unsigned int nobj, unsigned int size);
|
||||
extern void * srealloc(void *p, unsigned int newsize);
|
||||
|
||||
#endif
|
46
src/tests/add-ons/kernel/file_systems/dos/r5/lock.h
Normal file
46
src/tests/add-ons/kernel/file_systems/dos/r5/lock.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#ifndef _LOCK_H
|
||||
#define _LOCK_H
|
||||
|
||||
#include <BeBuild.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct lock lock;
|
||||
typedef struct mlock mlock;
|
||||
|
||||
struct lock {
|
||||
sem_id s;
|
||||
long c;
|
||||
};
|
||||
|
||||
struct mlock {
|
||||
sem_id s;
|
||||
};
|
||||
|
||||
extern _IMPEXP_KERNEL int new_lock(lock *l, const char *name);
|
||||
extern _IMPEXP_KERNEL 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 _IMPEXP_KERNEL int new_mlock(mlock *l, long c, const char *name);
|
||||
extern _IMPEXP_KERNEL int free_mlock(mlock *l);
|
||||
|
||||
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0)
|
||||
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
105
src/tests/add-ons/kernel/file_systems/dos/r5/mime_table.c
Normal file
105
src/tests/add-ons/kernel/file_systems/dos/r5/mime_table.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
extended: 2001-12-11 by Marcus Overhagen
|
||||
*/
|
||||
|
||||
struct ext_mime {
|
||||
char *extension;
|
||||
char *mime;
|
||||
};
|
||||
|
||||
struct ext_mime mimes[] = {
|
||||
{ "gz", "application/x-gzip" },
|
||||
{ "hqx", "application/x-binhex40" },
|
||||
{ "lha", "application/x-lharc" },
|
||||
{ "lzh", "application/x-lharc" },
|
||||
{ "pcl", "application/x-pcl" },
|
||||
{ "pdf", "application/pdf" },
|
||||
{ "ps", "application/postscript" },
|
||||
{ "sit", "application/x-stuff-it" },
|
||||
{ "tar", "application/x-tar" },
|
||||
{ "tgz", "application/x-gzip" },
|
||||
{ "uue", "application/x-uuencode" },
|
||||
{ "z", "application/x-compress" },
|
||||
{ "zip", "application/zip" },
|
||||
{ "zoo", "application/x-zoo" },
|
||||
{ "pkg", "application/x-scode-UPkg" },
|
||||
{ "vdwn", "application/x-scode-UPkg" },
|
||||
{ "proj", "application/x-mw-project" },
|
||||
{ "swf", "application/x-shockwave-flash" },
|
||||
{ "clp", "application/x-codeliege-project" },
|
||||
|
||||
{ "aif", "audio/x-aiff" },
|
||||
{ "aifc", "audio/x-aifc" },
|
||||
{ "aiff", "audio/x-aiff" },
|
||||
{ "au", "audio/basic" },
|
||||
{ "mid", "audio/x-midi" },
|
||||
{ "midi", "audio/x-midi" },
|
||||
{ "mod", "audio/mod" },
|
||||
{ "ra", "audio/x-real-audio" },
|
||||
{ "wav", "audio/x-wav" },
|
||||
{ "mp2", "audio/x-mpeg" },
|
||||
{ "mp3", "audio/x-mpeg" },
|
||||
{ "ogg", "audio/x-vorbis" },
|
||||
{ "mpc", "audio/x-mpc" },
|
||||
{ "asf", "application/x-asf" },
|
||||
{ "riff", "application/x-riff" },
|
||||
{ "wma", "audio/x-ms-wma" },
|
||||
|
||||
{ "bmp", "image/x-bmp" },
|
||||
{ "fax", "image/g3fax" },
|
||||
{ "gif", "image/gif" },
|
||||
{ "iff", "image/x-iff" },
|
||||
{ "jpg", "image/jpeg" },
|
||||
{ "jpeg", "image/jpeg" },
|
||||
{ "pbm", "image/x-portable-bitmap" },
|
||||
{ "pcx", "image/x-pcx" },
|
||||
{ "pgm", "image/x-portable-graymap" },
|
||||
{ "png", "image/png" },
|
||||
{ "ppm", "image/x-portable-pixmap" },
|
||||
{ "rgb", "image/x-rgb" },
|
||||
{ "tga", "image/x-targa" },
|
||||
{ "tif", "image/tiff" },
|
||||
{ "tiff", "image/tiff" },
|
||||
{ "xbm", "image/x-xbitmap" },
|
||||
|
||||
{ "txt", "text/plain" },
|
||||
{ "ini", "text/plain" },
|
||||
{ "log", "text/plain" },
|
||||
{ "bat", "text/plain" },
|
||||
{ "doc", "text/plain" },
|
||||
{ "cfg", "text/plain" },
|
||||
{ "inf", "text/plain" },
|
||||
{ "htm", "text/html" },
|
||||
{ "html", "text/html" },
|
||||
{ "rtf", "text/rtf" },
|
||||
{ "c", "text/x-source-code" },
|
||||
{ "cc", "text/x-source-code" },
|
||||
{ "c++", "text/x-source-code" },
|
||||
{ "h", "text/x-source-code" },
|
||||
{ "h++", "text/x-source-code" },
|
||||
{ "hh", "text/x-source-code" },
|
||||
{ "hpp", "text/x-source-code" },
|
||||
{ "pl", "text/x-source-code" },
|
||||
{ "py", "text/x-source-code" },
|
||||
{ "cxx", "text/x-source-code" },
|
||||
{ "cpp", "text/x-source-code" },
|
||||
{ "S", "text/x-source-code" },
|
||||
{ "asm", "text/x-source-code" },
|
||||
{ "bas", "text/x-source-code" },
|
||||
{ "pas", "text/x-source-code" },
|
||||
{ "java", "text/x-source-code" },
|
||||
|
||||
{ "avi", "video/x-msvideo" },
|
||||
{ "mov", "video/quicktime" },
|
||||
{ "mpg", "video/mpeg" },
|
||||
{ "mpeg", "video/mpeg" },
|
||||
{ "ogm", "video/x-ogm" },
|
||||
{ "wmv", "video/x-ms-wmv" },
|
||||
{ "rm", "application/vnd.rn-realmedia" },
|
||||
{ "rn", "application/vnd.rn-realmedia" },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
16
src/tests/add-ons/kernel/file_systems/dos/r5/mime_table.h
Normal file
16
src/tests/add-ons/kernel/file_systems/dos/r5/mime_table.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#ifndef MIME_TYPES_H
|
||||
#define MIME_TYPES_H
|
||||
|
||||
struct ext_mime {
|
||||
char *extension;
|
||||
char *mime;
|
||||
};
|
||||
|
||||
extern struct ext_mime mimes[];
|
||||
|
||||
#endif
|
23
src/tests/add-ons/kernel/file_systems/dos/r5/rtc_info.h
Normal file
23
src/tests/add-ons/kernel/file_systems/dos/r5/rtc_info.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* ++++++++++
|
||||
FILE: rtc_info.h
|
||||
NAME: mani
|
||||
DATE: 2/1998
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
+++++ */
|
||||
|
||||
#ifndef _RTC_INFO_H
|
||||
#define _RTC_INFO_H
|
||||
|
||||
typedef struct {
|
||||
uint32 time;
|
||||
bool is_gmt;
|
||||
int32 tz_minuteswest;
|
||||
int32 tz_dsttime;
|
||||
} rtc_info;
|
||||
|
||||
#define RTC_SETTINGS_FILE "RTC_time_settings"
|
||||
|
||||
extern _IMPEXP_KERNEL status_t get_rtc_info(rtc_info *);
|
||||
|
||||
#endif /* _RTC_INFO_H */
|
17
src/tests/add-ons/kernel/file_systems/dos/r5/settings/dos
Normal file
17
src/tests/add-ons/kernel/file_systems/dos/r5/settings/dos
Normal file
@ -0,0 +1,17 @@
|
||||
# Sample settings file for the dosfs plugin
|
||||
#
|
||||
# This file should be moved to the directory
|
||||
# /boot/home/config/settings/kernel/drivers/
|
||||
#
|
||||
# lock device:
|
||||
# true = (default) locks the device's door if:
|
||||
# the filesystem is RW
|
||||
# the device is removable
|
||||
# false = no door locking
|
||||
lock_device true
|
||||
|
||||
# sync mode:
|
||||
# 0 = (default) no sync after each operation
|
||||
# 1 = sync after each operation on removable media only
|
||||
# 2 = sync after each operation always
|
||||
op_sync_mode 0
|
149
src/tests/add-ons/kernel/file_systems/dos/r5/util.c
Normal file
149
src/tests/add-ons/kernel/file_systems/dos/r5/util.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#include <SupportDefs.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <fsproto.h>
|
||||
#include <rtc_info.h>
|
||||
|
||||
#include "dosfs.h"
|
||||
#include "fat.h"
|
||||
#include "util.h"
|
||||
|
||||
static int32 tzoffset = -1; /* in minutes */
|
||||
|
||||
int _assert_(char *a, int b, char *c)
|
||||
{
|
||||
dprintf("tripped assertion in %s/%d (%s)\n", a, b, c);
|
||||
kernel_debugger("tripped assertion");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_byte(uint8 c)
|
||||
{
|
||||
dprintf("%c", ((c >= ' ') && (c <= '~')) ? c : '.');
|
||||
}
|
||||
|
||||
void dump_bytes(uint8 *buffer, uint32 count)
|
||||
{
|
||||
uint32 i, j, k;
|
||||
for (i=0;i<0x10;i++)
|
||||
dprintf(" %lX ", i);
|
||||
dprintf("\n");
|
||||
for (i=0;i<count;i+=0x10) {
|
||||
j = (i + 0x10 > count) ? count - i : 0x10;
|
||||
for (k=i;k<i+j;k++)
|
||||
dprintf("%2.2X ", buffer[k]);
|
||||
for (;k<i+0x10;k++)
|
||||
dprintf(" ");
|
||||
dprintf(" ");
|
||||
for (k=i;k<i+j;k++)
|
||||
print_byte(buffer[k]);
|
||||
dprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void dump_directory(uint8 *buffer)
|
||||
{
|
||||
dump_bytes(buffer, 32);
|
||||
}
|
||||
|
||||
static void get_tzoffset()
|
||||
{
|
||||
rtc_info info;
|
||||
|
||||
if (tzoffset != -1)
|
||||
return;
|
||||
|
||||
if (get_rtc_info(&info) < 0) {
|
||||
dprintf("error getting rtc info\n");
|
||||
} else {
|
||||
tzoffset = info.tz_minuteswest;
|
||||
}
|
||||
}
|
||||
|
||||
// If divisible by 4, but not divisible by 100, but divisible by 400, it's a leap year
|
||||
// 1996 is leap, 1900 is not, 2000 is, 2100 is not
|
||||
#define IS_LEAP_YEAR(y) ((((y) % 4) == 0) && (((y) % 100) || ((((y)) % 400) == 0)))
|
||||
|
||||
/* returns leap days since 1970 */
|
||||
static int leaps(int yr, int mon)
|
||||
{
|
||||
// yr is 1970-based, mon 0-based
|
||||
int result = (yr+2)/4 - (yr + 70) / 100;
|
||||
if((yr+70) >= 100) result++; // correct for 2000
|
||||
if (IS_LEAP_YEAR(yr + 1970))
|
||||
if (mon < 2) result--;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int daze[] = { 0,0,31,59,90,120,151,181,212,243,273,304,334,0,0,0 };
|
||||
|
||||
time_t dos2time_t(uint32 t)
|
||||
{
|
||||
time_t days;
|
||||
|
||||
get_tzoffset();
|
||||
|
||||
//dprintf("%d/%d/%d %d:%2.2d:%2.2d\n",
|
||||
// (t>>25)+1980,((t>>21)&15),((t>>16)&31),
|
||||
// (t>>11)&31,(t>>5)&63,2*(t&31));
|
||||
|
||||
days = daze[(t>>21)&15] + ((t>>25)+10)*365 + leaps((t>>25)+10,((t>>21)&15)-1)+((t>>16)&31)-1;
|
||||
|
||||
return (((days * 24) + ((t>>11)&31)) * 60 + ((t>>5)&63) + tzoffset) * 60 + 2*(t&31);
|
||||
}
|
||||
|
||||
uint32 time_t2dos(time_t s)
|
||||
{
|
||||
uint32 t, d, y;
|
||||
int days;
|
||||
|
||||
get_tzoffset();
|
||||
|
||||
t = (s % 60) / 2; s /= 60; s -= tzoffset;
|
||||
t += (s % 60) << 5; s /= 60;
|
||||
t += (s % 24) << 11;s /= 24;
|
||||
|
||||
s -= 10*365 + 2; // convert from 1970-based year to 1980-based year
|
||||
|
||||
for (y=0;;y++) {
|
||||
days = IS_LEAP_YEAR(1980+y) ? 366 : 365;
|
||||
if (s < days) break;
|
||||
s -= days;
|
||||
}
|
||||
|
||||
if (IS_LEAP_YEAR(1980+y)) {
|
||||
if (s == 59) {
|
||||
d = (1 << 5) + 28; /* 2/29, 0 based */
|
||||
goto bi;
|
||||
} else if (s > 59)
|
||||
s--;
|
||||
}
|
||||
|
||||
for (d=0;d<11;d++)
|
||||
if (daze[d+2] > s)
|
||||
break;
|
||||
d = (d << 5) + (s - daze[d+1]);
|
||||
|
||||
bi:
|
||||
d += (1 << 5) + 1; // make date 1-based
|
||||
|
||||
return t + (d << 16) + (y << 25);
|
||||
}
|
||||
|
||||
uint8 hash_msdos_name(const char *name)
|
||||
{
|
||||
const uint8 *p = (const uint8 *)name;
|
||||
int i;
|
||||
uint8 c = 0;
|
||||
for (i=0;i<11;i++)
|
||||
c = (c << 7) + (c >> 1) + *(p++);
|
||||
return c;
|
||||
}
|
43
src/tests/add-ons/kernel/file_systems/dos/r5/util.h
Normal file
43
src/tests/add-ons/kernel/file_systems/dos/r5/util.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_UTIL_H_
|
||||
#define _DOSFS_UTIL_H_
|
||||
|
||||
#include <ByteOrder.h>
|
||||
|
||||
// debugging functions
|
||||
|
||||
#ifndef DEBUG
|
||||
#define ASSERT(c) ((void)0)
|
||||
#else
|
||||
int _assert_(char *,int,char *);
|
||||
#define ASSERT(c) (!(c) ? _assert_(__FILE__,__LINE__,#c) : 0)
|
||||
#endif
|
||||
|
||||
void dump_bytes(uint8 *buffer, uint32 count);
|
||||
void dump_directory(uint8 *buffer);
|
||||
|
||||
// time
|
||||
time_t dos2time_t(uint32 t);
|
||||
uint32 time_t2dos(time_t s);
|
||||
|
||||
uint8 hash_msdos_name(const char *name);
|
||||
|
||||
#if 0
|
||||
#define read32(buffer,off) \
|
||||
(((uint8 *)buffer)[(off)] + (((uint8 *)buffer)[(off)+1] << 8) + \
|
||||
(((uint8 *)buffer)[(off)+2] << 16) + (((uint8 *)buffer)[(off)+3] << 24))
|
||||
|
||||
#define read16(buffer,off) \
|
||||
(((uint8 *)buffer)[(off)] + (((uint8 *)buffer)[(off)+1] << 8))
|
||||
#endif
|
||||
|
||||
#define read32(buffer,off) \
|
||||
B_LENDIAN_TO_HOST_INT32(*(uint32 *)&buffer[off])
|
||||
|
||||
#define read16(buffer,off) \
|
||||
B_LENDIAN_TO_HOST_INT16(*(uint16 *)&buffer[off])
|
||||
|
||||
#endif
|
443
src/tests/add-ons/kernel/file_systems/dos/r5/vcache.c
Normal file
443
src/tests/add-ons/kernel/file_systems/dos/r5/vcache.c
Normal file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
/*
|
||||
The FAT file system has no good way of assigning unique persistent values to
|
||||
nodes. The only obvious choice, storing the starting cluster number of the
|
||||
file, is unusable because 0 byte files exist as directory entries only.
|
||||
Further, even if it were usable, it would potentially require a full directory
|
||||
tree traversal to locate an arbitrary node. We must resort to some ickiness
|
||||
in order to make persistent vnode id's (at least across a given mount) work.
|
||||
|
||||
There are three ways to encode a vnode id:
|
||||
|
||||
1. Combine the starting cluster of the entry with the starting cluster of the
|
||||
directory it appears in. This is used for files with data.
|
||||
2. Combine the starting cluster of the directory the entry appears in with the
|
||||
index of the entry in the directory. This is used for 0-byte files.
|
||||
3. A unique number that doesn't match any possible values from encodings 1 or
|
||||
2.
|
||||
|
||||
With the first encoding, the vnode id is invalidated (i.e. no longer describes
|
||||
the file's location) when the file moves to a different directory or when
|
||||
its starting cluster changes (this can occur if the file is truncated and data
|
||||
is subsequently written to it).
|
||||
|
||||
With the second encoding, the vnode id is invalidated when the file position
|
||||
is moved within a directory (as a result of a renaming), when it's moved to a
|
||||
different directory, or when data is written to it.
|
||||
|
||||
The third encoding doesn't describe the file's location on disk, and so it is
|
||||
invalid from the start.
|
||||
|
||||
Since we can't change vnode id's once they are assigned, we have to create a
|
||||
mapping table to translate vnode id's to locations. This file serves this
|
||||
purpose.
|
||||
*/
|
||||
|
||||
#define DPRINTF(a,b) if (debug_vcache > (a)) dprintf b
|
||||
|
||||
#define LOCK_CACHE_R \
|
||||
acquire_sem(vol->vcache.vc_sem)
|
||||
|
||||
#define LOCK_CACHE_W \
|
||||
acquire_sem_etc(vol->vcache.vc_sem, READERS, 0, 0)
|
||||
|
||||
#define UNLOCK_CACHE_R \
|
||||
release_sem(vol->vcache.vc_sem)
|
||||
|
||||
#define UNLOCK_CACHE_W \
|
||||
release_sem_etc(vol->vcache.vc_sem, READERS, 0)
|
||||
|
||||
#include <fsproto.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dosfs.h"
|
||||
#include "vcache.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
struct vcache_entry {
|
||||
vnode_id vnid; /* originally reported vnid */
|
||||
vnode_id loc; /* where the file is now */
|
||||
struct vcache_entry *next_vnid; /* next entry in vnid hash table */
|
||||
struct vcache_entry *next_loc; /* next entry in location hash table */
|
||||
};
|
||||
|
||||
void dump_vcache(nspace *vol)
|
||||
{
|
||||
uint32 i;
|
||||
struct vcache_entry *c;
|
||||
dprintf("vnid cache size %lx, cur vnid = %Lx\n"
|
||||
"vnid loc\n",
|
||||
vol->vcache.cache_size, vol->vcache.cur_vnid);
|
||||
for (i=0;i<vol->vcache.cache_size;i++)
|
||||
for (c = vol->vcache.by_vnid[i];c;c=c->next_vnid)
|
||||
dprintf("%16Lx %16Lx\n", c->vnid, c->loc);
|
||||
}
|
||||
|
||||
#define hash(v) ((v) & (vol->vcache.cache_size-1))
|
||||
|
||||
status_t init_vcache(nspace *vol)
|
||||
{
|
||||
char name[16];
|
||||
DPRINTF(0, ("init_vcache called\n"));
|
||||
|
||||
vol->vcache.cur_vnid = ARTIFICIAL_VNID_BITS;
|
||||
#if DEBUG
|
||||
vol->vcache.cache_size = 1;
|
||||
#else
|
||||
vol->vcache.cache_size = 512; /* must be power of 2 */
|
||||
#endif
|
||||
vol->vcache.by_vnid = calloc(sizeof(struct vache_entry *), vol->vcache.cache_size);
|
||||
if (vol->vcache.by_vnid == NULL) {
|
||||
dprintf("init_vcache: out of core\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
vol->vcache.by_loc = calloc(sizeof(struct vache_entry *), vol->vcache.cache_size);
|
||||
if (vol->vcache.by_loc == NULL) {
|
||||
dprintf("init_vcache: out of core\n");
|
||||
free(vol->vcache.by_vnid);
|
||||
vol->vcache.by_vnid = NULL;
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
sprintf(name, "fat cache %lx", vol->id);
|
||||
if ((vol->vcache.vc_sem = create_sem(READERS, name)) < 0) {
|
||||
free(vol->vcache.by_vnid); vol->vcache.by_vnid = NULL;
|
||||
free(vol->vcache.by_loc); vol->vcache.by_loc = NULL;
|
||||
return vol->vcache.vc_sem;
|
||||
}
|
||||
|
||||
DPRINTF(0, ("init_vcache: initialized vnid cache with %lx entries\n", vol->vcache.cache_size));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t uninit_vcache(nspace *vol)
|
||||
{
|
||||
uint32 i, count = 0;
|
||||
struct vcache_entry *c, *n;
|
||||
DPRINTF(0, ("uninit_vcache called\n"));
|
||||
|
||||
LOCK_CACHE_W;
|
||||
|
||||
/* free entries */
|
||||
for (i=0;i<vol->vcache.cache_size;i++) {
|
||||
c = vol->vcache.by_vnid[i];
|
||||
while (c) {
|
||||
count++;
|
||||
n = c->next_vnid;
|
||||
free(c);
|
||||
c = n;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(0, ("%lx vcache entries removed\n", count));
|
||||
|
||||
free(vol->vcache.by_vnid); vol->vcache.by_vnid = NULL;
|
||||
free(vol->vcache.by_loc); vol->vcache.by_loc = NULL;
|
||||
|
||||
delete_sem(vol->vcache.vc_sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vnode_id generate_unique_vnid(nspace *vol)
|
||||
{
|
||||
DPRINTF(0, ("generate_unique_vnid\n"));
|
||||
/* only one thread per volume will be in here at any given time anyway
|
||||
* due to volume locking */
|
||||
return vol->vcache.cur_vnid++;
|
||||
}
|
||||
|
||||
static status_t _add_to_vcache_(nspace *vol, vnode_id vnid, vnode_id loc)
|
||||
{
|
||||
int hash1 = hash(vnid), hash2 = hash(loc);
|
||||
struct vcache_entry *e, *c, *p;
|
||||
|
||||
DPRINTF(0, ("add_to_vcache %Lx/%Lx\n", vnid, loc));
|
||||
|
||||
ASSERT(vnid != loc);
|
||||
|
||||
e = malloc(sizeof(struct vcache_entry));
|
||||
if (e == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
e->vnid = vnid; e->loc = loc; e->next_vnid = NULL; e->next_loc = NULL;
|
||||
|
||||
c = p = vol->vcache.by_vnid[hash1];
|
||||
while (c) {
|
||||
if (vnid < c->vnid)
|
||||
break;
|
||||
ASSERT(vnid != c->vnid); ASSERT(loc != c->loc);
|
||||
p = c;
|
||||
c = c->next_vnid;
|
||||
}
|
||||
ASSERT(!c || (vnid != c->vnid));
|
||||
|
||||
e->next_vnid = c;
|
||||
if (p == c)
|
||||
vol->vcache.by_vnid[hash1] = e;
|
||||
else
|
||||
p->next_vnid = e;
|
||||
|
||||
c = p = vol->vcache.by_loc[hash2];
|
||||
while (c) {
|
||||
if (loc < c->loc)
|
||||
break;
|
||||
ASSERT(vnid != c->vnid); ASSERT(loc != c->loc);
|
||||
p = c;
|
||||
c = c->next_loc;
|
||||
}
|
||||
ASSERT(!c || (loc != c->loc));
|
||||
|
||||
e->next_loc = c;
|
||||
if (p == c)
|
||||
vol->vcache.by_loc[hash2] = e;
|
||||
else
|
||||
p->next_loc = e;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t _remove_from_vcache_(nspace *vol, vnode_id vnid)
|
||||
{
|
||||
int hash1 = hash(vnid), hash2;
|
||||
struct vcache_entry *c, *p, *e;
|
||||
|
||||
DPRINTF(0, ("remove_from_vcache %Lx\n", vnid));
|
||||
|
||||
c = p = vol->vcache.by_vnid[hash1];
|
||||
while (c) {
|
||||
if (vnid == c->vnid)
|
||||
break;
|
||||
ASSERT(c->vnid < vnid);
|
||||
p = c;
|
||||
c = c->next_vnid;
|
||||
}
|
||||
ASSERT(c);
|
||||
if (!c) return ENOENT;
|
||||
|
||||
if (p == c)
|
||||
vol->vcache.by_vnid[hash1] = c->next_vnid;
|
||||
else
|
||||
p->next_vnid = c->next_vnid;
|
||||
|
||||
e = c;
|
||||
|
||||
hash2 = hash(c->loc);
|
||||
c = p = vol->vcache.by_loc[hash2];
|
||||
|
||||
while (c) {
|
||||
if (vnid == c->vnid)
|
||||
break;
|
||||
ASSERT(c->loc < e->loc);
|
||||
p = c;
|
||||
c = c->next_loc;
|
||||
}
|
||||
ASSERT(c);
|
||||
if (!c) return ENOENT;
|
||||
if (p == c)
|
||||
vol->vcache.by_loc[hash2] = c->next_loc;
|
||||
else
|
||||
p->next_loc = c->next_loc;
|
||||
|
||||
free(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vcache_entry *_find_vnid_in_vcache_(nspace *vol, vnode_id vnid)
|
||||
{
|
||||
int hash1 = hash(vnid);
|
||||
struct vcache_entry *c;
|
||||
c = vol->vcache.by_vnid[hash1];
|
||||
while (c) {
|
||||
if (c->vnid == vnid)
|
||||
break;
|
||||
if (c->vnid > vnid)
|
||||
return NULL;
|
||||
c = c->next_vnid;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static struct vcache_entry *_find_loc_in_vcache_(nspace *vol, vnode_id loc)
|
||||
{
|
||||
int hash2 = hash(loc);
|
||||
struct vcache_entry *c;
|
||||
c = vol->vcache.by_loc[hash2];
|
||||
while (c) {
|
||||
if (c->loc == loc)
|
||||
break;
|
||||
if (c->loc > loc)
|
||||
return NULL;
|
||||
c = c->next_loc;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
status_t add_to_vcache(nspace *vol, vnode_id vnid, vnode_id loc)
|
||||
{
|
||||
status_t result;
|
||||
|
||||
LOCK_CACHE_W;
|
||||
result = _add_to_vcache_(vol,vnid,loc);
|
||||
UNLOCK_CACHE_W;
|
||||
|
||||
if (result < 0) DPRINTF(0, ("add_to_vcache failed (%s)\n", strerror(result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* XXX: do this in a smarter fashion */
|
||||
static status_t _update_loc_in_vcache_(nspace *vol, vnode_id vnid, vnode_id loc)
|
||||
{
|
||||
status_t result;
|
||||
|
||||
result = _remove_from_vcache_(vol, vnid);
|
||||
if (result == 0)
|
||||
result = _add_to_vcache_(vol, vnid, loc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t remove_from_vcache(nspace *vol, vnode_id vnid)
|
||||
{
|
||||
status_t result;
|
||||
|
||||
LOCK_CACHE_W;
|
||||
result = _remove_from_vcache_(vol, vnid);
|
||||
UNLOCK_CACHE_W;
|
||||
|
||||
if (result < 0) DPRINTF(0, ("remove_from_vcache failed (%s)\n", strerror(result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t vcache_vnid_to_loc(nspace *vol, vnode_id vnid, vnode_id *loc)
|
||||
{
|
||||
struct vcache_entry *e;
|
||||
|
||||
DPRINTF(1, ("vcache_vnid_to_loc %Lx %lx\n", vnid, (uint32)loc));
|
||||
|
||||
LOCK_CACHE_R;
|
||||
e = _find_vnid_in_vcache_(vol, vnid);
|
||||
if (loc && e)
|
||||
*loc = e->loc;
|
||||
UNLOCK_CACHE_R;
|
||||
|
||||
return (e) ? B_OK : ENOENT;
|
||||
}
|
||||
|
||||
status_t vcache_loc_to_vnid(nspace *vol, vnode_id loc, vnode_id *vnid)
|
||||
{
|
||||
struct vcache_entry *e;
|
||||
|
||||
DPRINTF(1, ("vcache_loc_to_vnid %Lx %lx\n", loc, (uint32)vnid));
|
||||
|
||||
LOCK_CACHE_R;
|
||||
e = _find_loc_in_vcache_(vol, loc);
|
||||
if (vnid && e)
|
||||
*vnid = e->vnid;
|
||||
UNLOCK_CACHE_R;
|
||||
|
||||
return (e) ? B_OK : ENOENT;
|
||||
}
|
||||
|
||||
status_t vcache_set_entry(nspace *vol, vnode_id vnid, vnode_id loc)
|
||||
{
|
||||
struct vcache_entry *e;
|
||||
status_t result = B_OK;
|
||||
|
||||
DPRINTF(0, ("vcache_set_entry: %Lx -> %Lx\n", vnid, loc));
|
||||
|
||||
if (is_vnode_removed(vol->id, vnid) > 0) {
|
||||
if (!IS_ARTIFICIAL_VNID(loc))
|
||||
return B_OK;
|
||||
} else {
|
||||
ASSERT(is_vnode_removed(vol->id, vnid) == 0);
|
||||
}
|
||||
|
||||
LOCK_CACHE_W;
|
||||
|
||||
e = _find_vnid_in_vcache_(vol, vnid);
|
||||
|
||||
if (e) {
|
||||
if (e->vnid == loc)
|
||||
result = _remove_from_vcache_(vol, vnid);
|
||||
else
|
||||
result = _update_loc_in_vcache_(vol, vnid, loc);
|
||||
} else {
|
||||
if (vnid != loc)
|
||||
result = _add_to_vcache_(vol,vnid,loc);
|
||||
}
|
||||
|
||||
UNLOCK_CACHE_W;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
int debug_dfvnid(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
nspace *vol;
|
||||
|
||||
if (argc < 3) {
|
||||
kprintf("dfvnid nspace vnid\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
vol = (nspace *)strtoul(argv[1], NULL, 0);
|
||||
if (vol == NULL)
|
||||
return B_OK;
|
||||
|
||||
for (i=2;i<argc;i++) {
|
||||
vnode_id vnid = strtoull(argv[i], NULL, 0);
|
||||
struct vcache_entry *e;
|
||||
if ((e = _find_vnid_in_vcache_(vol, vnid)) != NULL) {
|
||||
kprintf("vnid %Lx -> loc %Lx @ %p\n", vnid, e->loc, e);
|
||||
} else {
|
||||
kprintf("vnid %Lx not found in vnid cache\n", vnid);
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int debug_dfloc(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
nspace *vol;
|
||||
|
||||
if (argc < 3) {
|
||||
kprintf("dfloc nspace vnid\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
vol = (nspace *)strtoul(argv[1], NULL, 0);
|
||||
if (vol == NULL)
|
||||
return B_OK;
|
||||
|
||||
for (i=2;i<argc;i++) {
|
||||
vnode_id loc = strtoull(argv[i], NULL, 0);
|
||||
struct vcache_entry *e;
|
||||
if ((e = _find_loc_in_vcache_(vol, loc)) != NULL) {
|
||||
kprintf("loc %Lx -> vnid %Lx @ %p\n", loc, e->vnid, e);
|
||||
} else {
|
||||
kprintf("loc %Lx not found in vnid cache\n", loc);
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
#endif
|
30
src/tests/add-ons/kernel/file_systems/dos/r5/vcache.h
Normal file
30
src/tests/add-ons/kernel/file_systems/dos/r5/vcache.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
#ifndef _DOSFS_VCACHE_H_
|
||||
#define _DOSFS_VCACHE_H_
|
||||
|
||||
void dump_vcache(nspace *vol);
|
||||
|
||||
status_t init_vcache(nspace *vol);
|
||||
status_t uninit_vcache(nspace *vol);
|
||||
|
||||
vnode_id generate_unique_vnid(nspace *vol);
|
||||
|
||||
status_t add_to_vcache(nspace *vol, vnode_id vnid, vnode_id loc);
|
||||
status_t remove_from_vcache(nspace *vol, vnode_id vnid);
|
||||
status_t vcache_vnid_to_loc(nspace *vol, vnode_id vnid, vnode_id *loc);
|
||||
status_t vcache_loc_to_vnid(nspace *vol, vnode_id loc, vnode_id *vnid);
|
||||
|
||||
status_t vcache_set_entry(nspace *vol, vnode_id vnid, vnode_id loc);
|
||||
|
||||
#define find_vnid_in_vcache(vol,vnid) vcache_vnid_to_loc(vol,vnid,NULL)
|
||||
#define find_loc_in_vcache(vol,loc) vcache_loc_to_vnid(vol,loc,NULL)
|
||||
|
||||
#if DEBUG
|
||||
int debug_dfvnid(int argc, char **argv);
|
||||
int debug_dfloc(int argc, char **argv);
|
||||
#endif
|
||||
|
||||
#endif
|
6
src/tests/add-ons/kernel/file_systems/dos/r5/version.c
Normal file
6
src/tests/add-ons/kernel/file_systems/dos/r5/version.c
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
const char *build_time = __TIME__;
|
||||
const char *build_date = __DATE__;
|
Loading…
Reference in New Issue
Block a user