Updated as of April 2, 2001.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2983 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper 2003-03-21 21:03:51 +00:00
parent 9168ef4ba7
commit ba5d0baeee
4 changed files with 157 additions and 44 deletions

View File

@ -2,13 +2,13 @@
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 <dirent.h>
#include <stdio.h>
#include <string.h>
@ -347,9 +347,11 @@ static status_t findfile(nspace *vol, vnode *dir, const char *file,
any other case-insensitive matches. If there are, the
dups_exist flag is set to true. */
int result = 0;
vnode_id _vnid;
vnode_id found_vnid = 0;
bool found_file = false;
// dprintf("findfile: %s in %Lx, case %d dups %d\n", file, dir->vnid, check_case, check_dups);
if (check_nspace_magic(vol, "findfile")) return EINVAL;
if (check_vnode_magic(dir, "findfile")) return EINVAL;
@ -360,12 +362,11 @@ static status_t findfile(nspace *vol, vnode *dir, const char *file,
if ((strcmp(file,".") == 0) && (dir->vnid == vol->root_vnode.vnid)) {
found_file = true;
_vnid = dir->vnid;
found_vnid = dir->vnid;
} else if ((strcmp(file, "..") == 0) && (dir->vnid == vol->root_vnode.vnid)) {
found_file = true;
_vnid = dir->dir_vnid;
found_vnid = dir->dir_vnid;
} else {
char filename[512];
struct diri diri;
// XXX: do it in a smarter way
@ -373,6 +374,9 @@ static status_t findfile(nspace *vol, vnode *dir, const char *file,
while (1)
{
char filename[512];
vnode_id _vnid;
result = get_next_dirent(vol, dir, &diri, &_vnid, filename, 512);
if (result != B_NO_ERROR)
@ -380,37 +384,41 @@ static status_t findfile(nspace *vol, vnode *dir, const char *file,
if(check_case) {
if (!found_file && !strcmp(filename, file)) {
result = B_OK;
found_file = true;
found_vnid = _vnid;
} else if(check_dups && !strcasecmp(filename, file)) {
*dups_exist = true;
}
} else {
if (!strcasecmp(filename, file)) {
result = B_OK;
if(check_dups && found_file) {
*dups_exist = true;
}
found_file = true;
found_vnid = _vnid;
}
}
if(found_file) {
if(!check_dups) {
break;
} else if(*dups_exist) {
break;
}
if(found_file && (!check_dups || (check_dups && *dups_exist))) {
break;
}
}
diri_free(&diri);
}
if (found_file) {
if (vnid) *vnid = _vnid;
if (node) result = get_vnode(vol->id, _vnid, (void **)node);
if (vnid) *vnid = found_vnid;
if (node) result = get_vnode(vol->id, found_vnid, (void **)node);
result = B_OK;
} else {
result = ENOENT;
}
#if 0
dprintf("findfile: returning %d", result);
if(dups_exist)
dprintf(" dups_exist %d\n", *dups_exist);
else
dprintf("\n");
#endif
return result;
}
@ -916,6 +924,7 @@ int dosfs_read_vnode(void *_vol, vnode_id vnid, char reenter, void **_node)
entry->cluster = info.cluster;
entry->mode = info.mode;
entry->st_size = info.size;
entry->dirty = false;
if (info.mode & FAT_SUBDIR) {
entry->st_size = count_clusters(vol,entry->cluster) * vol->sectors_per_cluster * vol->bytes_per_sector;
}

View File

@ -2,7 +2,6 @@
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -143,7 +142,7 @@ static int lock_removable_device(int fd, bool state)
}
static status_t mount_fat_disk(const char *path, nspace_id nsid,
const int flags, nspace** newVol)
const int flags, nspace** newVol, int fs_flags, int op_sync_mode)
{
nspace *vol = NULL;
uint8 buf[512];
@ -159,6 +158,7 @@ static status_t mount_fat_disk(const char *path, nspace_id nsid,
vol->magic = NSPACE_MAGIC;
vol->flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME;
vol->fs_flags = fs_flags;
// open read-only for now
if ((err = (vol->fd = open(path, O_RDONLY))) < 0) {
@ -201,10 +201,27 @@ static status_t mount_fat_disk(const char *path, nspace_id nsid,
dprintf("dosfs: unable to open %s (%s)\n", path, strerror(err));
goto error0;
}
if (vol->flags & B_FS_IS_REMOVABLE)
if ((vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))
lock_removable_device(vol->fd, true);
}
// see if we need to go into op sync mode
vol->fs_flags &= ~FS_FLAGS_OP_SYNC;
switch(op_sync_mode) {
case 1:
if((vol->flags & B_FS_IS_REMOVABLE) == 0) {
// we're not removable, so skip op_sync
break;
}
case 2:
dprintf("dosfs: mounted with op_sync enabled\n");
vol->fs_flags |= FS_FLAGS_OP_SYNC;
break;
case 0:
default:
;
}
// read in the boot sector
if ((err = read_pos(vol->fd, 0, (void*)buf, 512)) != 512) {
dprintf("dosfs: error reading boot sector\n");
@ -467,6 +484,7 @@ static status_t mount_fat_disk(const char *path, nspace_id nsid,
vol->root_vnode.mode = FAT_SUBDIR;
time(&(vol->root_vnode.st_time));
vol->root_vnode.mime = NULL;
vol->root_vnode.dirty = false;
dlist_add(vol, vol->root_vnode.vnid);
// find volume label (supercedes any label in the bpb)
@ -502,7 +520,7 @@ error2:
error1:
remove_cached_device_blocks(vol->fd, NO_WRITES);
error:
if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE))
if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))
lock_removable_device(vol->fd, false);
error0:
close(vol->fd);
@ -516,6 +534,8 @@ static int dosfs_mount(nspace_id nsid, const char *device, ulong flags, void *pa
int result;
nspace *vol;
void *handle;
int op_sync_mode;
int fs_flags = 0;
handle = load_driver_settings("dos");
debug_attr = strtoul(get_driver_parameter(handle, "debug_attr", "0", "0"), NULL, 0);
@ -527,6 +547,18 @@ static int dosfs_mount(nspace_id nsid, const char *device, ulong flags, void *pa
debug_file = strtoul(get_driver_parameter(handle, "debug_file", "0", "0"), NULL, 0);
debug_iter = strtoul(get_driver_parameter(handle, "debug_iter", "0", "0"), NULL, 0);
debug_vcache = strtoul(get_driver_parameter(handle, "debug_vcache", "0", "0"), NULL, 0);
op_sync_mode = strtoul(get_driver_parameter(handle, "op_sync_mode", "0", "0"), NULL, 0);
if (op_sync_mode < 0 || op_sync_mode > 2) {
op_sync_mode = 0;
}
if (strcasecmp(get_driver_parameter(handle, "lock_device", "true", "true"), "false") == 0) {
dprintf("dosfs: mounted with lock_device = false\n");
} else {
dprintf("dosfs: mounted with lock_device = true\n");
fs_flags |= FS_FLAGS_LOCK_DOOR;
}
unload_driver_settings(handle);
/* parms and len are command line options; dosfs doesn't use any so
@ -544,7 +576,7 @@ static int dosfs_mount(nspace_id nsid, const char *device, ulong flags, void *pa
}
// Try and mount volume as a FAT volume
if ((result = mount_fat_disk(device, nsid, flags, &vol)) == B_NO_ERROR) {
if ((result = mount_fat_disk(device, nsid, flags, &vol, fs_flags, op_sync_mode)) == B_NO_ERROR) {
char name[32];
if (check_nspace_magic(vol, "dosfs_mount")) return EINVAL;
@ -643,7 +675,7 @@ static int dosfs_unmount(void *_vol)
dlist_uninit(vol);
uninit_vcache(vol);
if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE))
if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))
lock_removable_device(vol->fd, false);
result = close(vol->fd);
free_lock(&(vol->vlock));
@ -798,6 +830,9 @@ static int dosfs_wfsstat(void *_vol, struct fs_info * fss, long mask)
memcpy(vol->vol_label, name, 11);
}
if (vol->fs_flags & FS_FLAGS_OP_SYNC)
_dosfs_sync(vol);
bi: UNLOCK_VOL(vol);
return result;
@ -896,25 +931,29 @@ static int dosfs_ioctl(void *_vol, void *_node, void *cookie, int code,
return result;
}
static int dosfs_sync(void *_vol)
int _dosfs_sync(nspace *vol)
{
nspace *vol = (nspace *)_vol;
LOCK_VOL(vol);
if (check_nspace_magic((nspace*)_vol, "dosfs_sync")) {
UNLOCK_VOL(vol);
if (check_nspace_magic(vol, "dosfs_sync"))
return EINVAL;
}
DPRINTF(0, ("dosfs_sync called on volume %lx\n", vol->id));
update_fsinfo(vol);
flush_device(vol->fd, 0);
return 0;
}
static int dosfs_sync(void *_vol)
{
nspace *vol = (nspace *)_vol;
int err;
DPRINTF(0, ("dosfs_sync called on volume %lx\n", vol->id));
LOCK_VOL(vol);
err = _dosfs_sync(vol);
UNLOCK_VOL(vol);
return 0;
return err;
}
static int dosfs_fsync(void *vol, void *node)

View File

@ -2,7 +2,6 @@
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_
@ -101,6 +100,8 @@ typedef struct vnode
const char *mime; // mime type (null if none)
bool dirty; // track if vnode had been written to
#if TRACK_FILENAME
char *filename;
#endif
@ -155,6 +156,8 @@ typedef struct _nspace
vnode_id beos_vnid; // vnid of \BEOS directory
bool respect_disk_image;
int fs_flags; // flags for this mount
lock vlock;
// vcache state
@ -172,6 +175,9 @@ typedef struct _nspace
} 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)
@ -200,4 +206,6 @@ int check_nspace_magic(struct _nspace *t, char *funcname);
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

View File

@ -2,7 +2,6 @@
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#include <string.h>
#include <sys/stat.h>
@ -113,6 +112,12 @@ int dosfs_write_vnode(void *_vol, void *_node, char reenter)
DPRINTF(0, ("dosfs_write_vnode (vnode_id %Lx)\n", ((vnode *)_node)->vnid));
if ((vol->fs_flags & FS_FLAGS_OP_SYNC) && node->dirty) {
LOCK_VOL(vol);
_dosfs_sync(vol);
UNLOCK_VOL(vol);
}
if (node != NULL) {
#if TRACK_FILENAME
if (node->filename) free(node->filename);
@ -229,6 +234,12 @@ int dosfs_wstat(void *_vol, void *_node, struct stat *st, long mask)
if (dirty) {
write_vnode_entry(vol, node);
notify_listener(B_STAT_CHANGED, vol->id, 0, 0, node->vnid, NULL);
if (vol->fs_flags & FS_FLAGS_OP_SYNC) {
// sync the filesystem
_dosfs_sync(vol);
node->dirty = false;
}
}
if (err != B_OK) DPRINTF(0, ("dosfs_wstat (%s)\n", strerror(err)));
@ -537,6 +548,7 @@ int dosfs_write(void *_vol, void *_node, void *_cookie, off_t pos,
write_vnode_entry(vol, node);
DPRINTF(0, ("setting file size to %Lx (%lx clusters)\n", node->st_size, clusters));
node->dirty = true;
}
if (cluster1 == 0xffffffff) {
@ -558,6 +570,9 @@ int dosfs_write(void *_vol, void *_node, void *_cookie, off_t pos,
ASSERT(iter.cluster == get_nth_fat_entry(vol, node->cluster, pos / vol->bytes_per_sector / vol->sectors_per_cluster));
if(*len > 0)
node->dirty = true;
// write partial first sector if necessary
if ((pos % vol->bytes_per_sector) != 0) {
size_t amt;
@ -655,6 +670,11 @@ int dosfs_close(void *_vol, void *_node, void *_cookie)
DPRINTF(0, ("dosfs_close (vnode id %Lx)\n", ((vnode *)_node)->vnid));
if ((vol->fs_flags & FS_FLAGS_OP_SYNC) && node->dirty) {
_dosfs_sync(vol);
node->dirty = false;
}
UNLOCK_VOL(vol);
return 0;
@ -788,17 +808,22 @@ int dosfs_create(void *_vol, void *_dir, const char *name, int omode,
// XXX: dangerous construct
if (find_vnid_in_vcache(vol, dummy.vnid) == B_OK) {
dummy.vnid = generate_unique_vnid(vol);
if ((result = add_to_vcache(vol, dummy.vnid, GENERATE_DIR_INDEX_VNID(dummy.dir_vnid, dummy.sindex))) < 0)
if ((result = add_to_vcache(vol, dummy.vnid, GENERATE_DIR_INDEX_VNID(dummy.dir_vnid, dummy.sindex))) < 0) {
// XXX: should remove entry on failure
if (vol->fs_flags & FS_FLAGS_OP_SYNC)
_dosfs_sync(vol);
goto bi;
}
}
*vnid = dummy.vnid;
dummy.magic = ~VNODE_MAGIC;
result = get_vnode(vol->id, *vnid, (void **)&file);
if (result < B_OK)
if (result < B_OK) {
if (vol->fs_flags & FS_FLAGS_OP_SYNC)
_dosfs_sync(vol);
goto bi;
}
} else {
goto bi;
}
@ -814,6 +839,9 @@ int dosfs_create(void *_vol, void *_dir, const char *name, int omode,
result = 0;
if (vol->fs_flags & FS_FLAGS_OP_SYNC)
_dosfs_sync(vol);
bi: if (result != B_OK) free(cookie);
UNLOCK_VOL(vol);
@ -953,6 +981,9 @@ int dosfs_mkdir(void *_vol, void *_dir, const char *name, int perms)
result = B_OK;
if (vol->fs_flags & FS_FLAGS_OP_SYNC)
_dosfs_sync(vol);
UNLOCK_VOL(vol);
return result;
@ -960,6 +991,8 @@ bi5:free(buffer);
bi4:dlist_remove(vol, dummy.vnid);
bi3:if (IS_ARTIFICIAL_VNID(dummy.vnid)) remove_from_vcache(vol, dummy.vnid);
bi2:clear_fat_chain(vol, dummy.cluster);
if (vol->fs_flags & FS_FLAGS_OP_SYNC)
_dosfs_sync(vol);
bi: dummy.magic = ~VNODE_MAGIC;
UNLOCK_VOL(vol);
@ -975,6 +1008,7 @@ int dosfs_rename(void *_vol, void *_odir, const char *oldname,
vnode *odir = (vnode *)_odir, *ndir = (vnode *)_ndir, *file, *file2;
uint32 ns, ne;
bool dups_exist;
bool dirty = false;
LOCK_VOL(vol);
@ -1080,20 +1114,25 @@ int dosfs_rename(void *_vol, void *_odir, const char *oldname,
remove_vnode(vol->id, file2->vnid); // must be done in this order
put_vnode(vol->id, file2->vnid);
dirty = true;
// erase old directory entry
if ((result = erase_dir_entry(vol, file)) != B_OK) {
dprintf("dosfs_rename: error erasing old directory entry for %s (%s)\n", newname, strerror(result));
goto bi1;
}
} else if (result == ENOENT && (!dups_exist || odir->vnid == ndir->vnid)) {
// there isn't an entry and there is no duplicates in the target dir or
// there isn't an entry and the target dir is the same as the source dir
} else if (result == ENOENT && (!dups_exist || (odir->vnid == ndir->vnid && !strcasecmp(oldname, newname)))) {
// there isn't an entry and there are no duplicates in the target dir or
// there isn't an entry and the target dir is the same as the source dir and
// the source and target name are the same, case-insensitively
// erase old directory entry
if ((result = erase_dir_entry(vol, file)) != B_OK) {
dprintf("dosfs_rename: error erasing old directory entry for %s (%s)\n", newname, strerror(result));
goto bi1;
}
dirty = true;
// create the new directory entry
if ((result = create_dir_entry(vol, ndir, file, newname, &ns, &ne)) != B_OK) {
@ -1111,6 +1150,8 @@ int dosfs_rename(void *_vol, void *_odir, const char *oldname,
// shrink the directory (an error here is not disastrous)
compact_directory(vol, odir);
dirty = true;
// update vnode information
file->dir_vnid = ndir->vnid;
file->sindex = ns;
@ -1173,9 +1214,14 @@ int dosfs_rename(void *_vol, void *_odir, const char *oldname,
result = 0;
bi2:if (result != B_OK) put_vnode(vol->id, file2->vnid);
bi1:put_vnode(vol->id, file->vnid);
bi: UNLOCK_VOL(vol);
bi2:
if (result != B_OK) put_vnode(vol->id, file2->vnid);
bi1:
put_vnode(vol->id, file->vnid);
bi:
if ((vol->fs_flags & FS_FLAGS_OP_SYNC) && dirty)
_dosfs_sync(vol);
UNLOCK_VOL(vol);
if (result != B_OK) DPRINTF(0, ("dosfs_rename (%s)\n", strerror(result)));
return result;
}
@ -1219,7 +1265,15 @@ int dosfs_remove_vnode(void *_vol, void *_node, char reenter)
node->magic = ~VNODE_MAGIC; // munge magic number to be safe
free(node);
if (!reenter) UNLOCK_VOL(vol);
if (!reenter) {
if (vol->fs_flags & FS_FLAGS_OP_SYNC) {
// sync the entire filesystem,
// but only if we're not reentrant. Presumably the
// function that called this will sync.
_dosfs_sync(vol);
}
UNLOCK_VOL(vol);
}
return 0;
}
@ -1321,6 +1375,9 @@ static int do_unlink(void *_vol, void *_dir, const char *name, bool is_file)
remove_vnode(vol->id, file->vnid);
result = 0;
if (vol->fs_flags & FS_FLAGS_OP_SYNC)
_dosfs_sync(vol);
bi1:put_vnode(vol->id, vnid); // get 1 free
bi: UNLOCK_VOL(vol);