From ba5d0baeeed66c3e23c4457c4c85814ec34bd477 Mon Sep 17 00:00:00 2001 From: beveloper Date: Fri, 21 Mar 2003 21:03:51 +0000 Subject: [PATCH] Updated as of April 2, 2001. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2983 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/file_systems/dos/dir.c | 39 ++++++---- src/add-ons/kernel/file_systems/dos/dosfs.c | 73 ++++++++++++++----- src/add-ons/kernel/file_systems/dos/dosfs.h | 10 ++- src/add-ons/kernel/file_systems/dos/file.c | 79 ++++++++++++++++++--- 4 files changed, 157 insertions(+), 44 deletions(-) diff --git a/src/add-ons/kernel/file_systems/dos/dir.c b/src/add-ons/kernel/file_systems/dos/dir.c index e08b6dd787..3a0b4154a3 100644 --- a/src/add-ons/kernel/file_systems/dos/dir.c +++ b/src/add-ons/kernel/file_systems/dos/dir.c @@ -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 #include #include #include +#include #include #include #include @@ -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; } diff --git a/src/add-ons/kernel/file_systems/dos/dosfs.c b/src/add-ons/kernel/file_systems/dos/dosfs.c index d9095e9c4b..4f389bc54c 100644 --- a/src/add-ons/kernel/file_systems/dos/dosfs.c +++ b/src/add-ons/kernel/file_systems/dos/dosfs.c @@ -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 #include #include @@ -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) diff --git a/src/add-ons/kernel/file_systems/dos/dosfs.h b/src/add-ons/kernel/file_systems/dos/dosfs.h index b2b3cd2fea..5def75b212 100644 --- a/src/add-ons/kernel/file_systems/dos/dosfs.h +++ b/src/add-ons/kernel/file_systems/dos/dosfs.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/dos/file.c b/src/add-ons/kernel/file_systems/dos/file.c index 7a44eed56f..b86821633e 100644 --- a/src/add-ons/kernel/file_systems/dos/file.c +++ b/src/add-ons/kernel/file_systems/dos/file.c @@ -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 #include @@ -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);