diff --git a/src/add-ons/kernel/file_systems/dos/dir.c b/src/add-ons/kernel/file_systems/dos/dir.c index c209547a59..17e370fbd5 100644 --- a/src/add-ons/kernel/file_systems/dos/dir.c +++ b/src/add-ons/kernel/file_systems/dos/dir.c @@ -2,6 +2,7 @@ Copyright 1999-2001, Be Incorporated. All Rights Reserved. This file may be used under the terms of the Be Sample Code License. */ + #include #include @@ -31,8 +32,7 @@ const char illegal[] = "\\/:*?\"<>|"; #define DIRCOOKIE_MAGIC 'AiC ' -typedef struct dircookie -{ +typedef struct dircookie { uint32 magic; uint32 current_index; } dircookie; @@ -53,19 +53,21 @@ struct _dirent_info_ { }; // scans dir for the next entry, using the state stored in a struct diri. -static status_t _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo, - char *filename, int len) +static status_t +_next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo, char *filename, + int len) { - uint8 *buffer, hash = 0; /* quiet warning */ - uchar uni[1024]; - uint16 *puni; - uint32 i; + uint8 *buffer, hash = 0; /* quiet warning */ + uchar uni[1024]; + uint16 *puni; + uint32 i; // lfn state - uint32 start_index = 0xffff, filename_len = 0 /* quiet warning */, - lfn_count = 0 /* quiet warning */; + uint32 start_index = 0xffff, filename_len = 0; /* quiet warning */ + uint32 lfn_count = 0 /* quiet warning */; - if (check_diri_magic(iter, "_next_dirent_")) return EINVAL; + if (check_diri_magic(iter, "_next_dirent_")) + return EINVAL; if (iter->current_block == NULL) return ENOENT; @@ -75,10 +77,12 @@ static status_t _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo, return ENOMEM; } - buffer = iter->current_block + ((iter->current_index) % (iter->csi.vol->bytes_per_sector / 0x20)) * 0x20; + buffer = iter->current_block + + ((iter->current_index) % (iter->csi.vol->bytes_per_sector / 0x20)) * 0x20; - for (;buffer != NULL;buffer = diri_next_entry(iter)) { - DPRINTF(2, ("_next_dirent_: %lx/%lx/%lx\n", iter->csi.cluster, iter->csi.sector, iter->current_index)); + for (; buffer != NULL; buffer = diri_next_entry(iter)) { + DPRINTF(2, ("_next_dirent_: %lx/%lx/%lx\n", iter->csi.cluster, + iter->csi.sector, iter->current_index)); if (buffer[0] == 0) { // quit if at end of table if (start_index != 0xffff) { dprintf("lfn entry (%s) with no alias\n", filename); @@ -110,7 +114,7 @@ static status_t _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo, lfn_count = buffer[0] & 0x1f; start_index = iter->current_index; puni = (uint16 *)(uni + 2*13*(lfn_count - 1)); - for (i=1;i<0x20;i+=2) { + for (i = 1; i < 0x20; i += 2) { if (*(uint16 *)&buffer[i] == 0xffff) break; *puni++ = *(uint16 *)&buffer[i]; @@ -134,7 +138,7 @@ static status_t _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo, } puni = (uint16 *)(uni + 2*13*(lfn_count - 1)); - for (i=1;i<0x20;i+=2) { + for (i = 1; i < 0x20; i += 2) { if ((buffer[i] == 0xff) && (buffer[i+1] == 0xff)) { dprintf("bad lfn entry in directory\n"); start_index = 0xffff; @@ -169,7 +173,8 @@ static status_t _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo, diri_init(iter->csi.vol, iter->starting_cluster, start_index, iter); return ENAMETOOLONG; } else if (hash_msdos_name((const char *)buffer) != hash) { - dprintf("error: long file name (%s) hash and short file name don't match\n", filename); + dprintf("error: long file name (%s) hash and short file name don't match\n", + filename); start_index = 0xffff; } } @@ -198,21 +203,24 @@ static status_t _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo, return B_NO_ERROR; } -static status_t get_next_dirent(nspace *vol, vnode *dir, struct diri *iter, - vnode_id *vnid, char *filename, int len) + +static status_t +get_next_dirent(nspace *vol, vnode *dir, struct diri *iter, vnode_id *vnid, + char *filename, int len) { struct _dirent_info_ info; status_t result; - if (check_nspace_magic(vol, "get_next_dirent")) return EINVAL; + if (check_nspace_magic(vol, "get_next_dirent")) + return EINVAL; do { result = _next_dirent_(iter, &info, filename, len); - - if (result < 0) return result; + if (result < 0) + return result; // only hide volume label entries in the root directory } while ((info.mode & FAT_VOLUME) && (dir->vnid == vol->root_vnode.vnid)); - + if (!strcmp(filename, ".")) { // assign vnode based on parent if (vnid) *vnid = dir->vnid; @@ -221,9 +229,9 @@ static status_t get_next_dirent(nspace *vol, vnode *dir, struct diri *iter, if (vnid) *vnid = dir->dir_vnid; } else { if (vnid) { - vnode_id loc = (IS_DATA_CLUSTER(info.cluster)) ? - GENERATE_DIR_CLUSTER_VNID(dir->vnid, info.cluster) : - GENERATE_DIR_INDEX_VNID(dir->vnid, info.sindex); + vnode_id loc = (IS_DATA_CLUSTER(info.cluster)) + ? GENERATE_DIR_CLUSTER_VNID(dir->vnid, info.cluster) + : GENERATE_DIR_INDEX_VNID(dir->vnid, info.sindex); bool added_to_vcache = false; /* if it matches a loc in the lookup table, we are done. */ @@ -264,36 +272,39 @@ static status_t get_next_dirent(nspace *vol, vnode *dir, struct diri *iter, return B_NO_ERROR; } -status_t check_dir_empty(nspace *vol, vnode *dir) + +status_t +check_dir_empty(nspace *vol, vnode *dir) { uint32 i; struct diri iter; status_t result = B_ERROR; /* quiet warning */ - if (check_nspace_magic(vol, "check_dir_empty")) return EINVAL; - if (check_vnode_magic(dir, "check_dir_empty")) return EINVAL; + if (check_nspace_magic(vol, "check_dir_empty")) + return EINVAL; + if (check_vnode_magic(dir, "check_dir_empty")) + return EINVAL; if (diri_init(vol, dir->cluster, 0, &iter) == NULL) { dprintf("check_dir_empty: error opening directory\n"); - ASSERT(0); return B_ERROR; } i = (dir->vnid == vol->root_vnode.vnid) ? 2 : 0; - for (;i<3;i++) { + for (; i < 3; i++) { char filename[512]; result = _next_dirent_(&iter, NULL, filename, 512); - if (result < 0) { - if ((i == 2) && (result == ENOENT)) result = B_OK; + if (i == 2 && result == ENOENT) + result = B_OK; break; } - if (((i == 0) && strcmp(filename, ".")) || - ((i == 1) && strcmp(filename, "..")) || + if ((i == 0 && strcmp(filename, ".")) + || (i == 1 && strcmp(filename, "..")) // weird case where ./.. are stored as long file names - ((i < 2) && (iter.current_index != i+1))) { + || (i < 2 && iter.current_index != i + 1)) { dprintf("check_dir_empty: malformed directory\n"); result = ENOTDIR; break; @@ -307,33 +318,42 @@ status_t check_dir_empty(nspace *vol, vnode *dir) return result; } -status_t findfile_case(nspace *vol, vnode *dir, const char *file, - vnode_id *vnid, vnode **node) + +status_t +findfile_case(nspace *vol, vnode *dir, const char *file, vnode_id *vnid, + vnode **node) { return findfile(vol, dir, file, vnid, node, true, false, NULL); } -status_t findfile_nocase(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) { return findfile(vol, dir, file, vnid, node, false, false, NULL); } -status_t findfile_nocase_duplicates(nspace *vol, vnode *dir, const char *file, - vnode_id *vnid, vnode **node, bool *dups_exist) + +status_t +findfile_nocase_duplicates(nspace *vol, vnode *dir, const char *file, + vnode_id *vnid, vnode **node, bool *dups_exist) { return findfile(vol, dir, file, vnid, node, false, true, dups_exist); } -status_t findfile_case_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) { return findfile(vol, dir, file, vnid, node, true, true, dups_exist); } -static status_t findfile(nspace *vol, vnode *dir, const char *file, - vnode_id *vnid, vnode **node, bool check_case, - bool check_dups, bool *dups_exist) + +static status_t +findfile(nspace *vol, vnode *dir, const char *file, vnode_id *vnid, + vnode **node, bool check_case, bool check_dups, bool *dups_exist) { /* Starting at the base, find the file in the subdir and return its vnode id */ @@ -351,62 +371,68 @@ static status_t findfile(nspace *vol, vnode *dir, const char *file, // 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; + if (check_nspace_magic(vol, "findfile")) + return EINVAL; + if (check_vnode_magic(dir, "findfile")) + return EINVAL; DPRINTF(1, ("findfile: %s in %Lx\n", file, dir->vnid)); - if(dups_exist != NULL) *dups_exist = false; - else check_dups = false; + if (dups_exist != NULL) + *dups_exist = false; + else + check_dups = false; - if ((strcmp(file,".") == 0) && (dir->vnid == vol->root_vnode.vnid)) { + if (strcmp(file,".") == 0 && dir->vnid == vol->root_vnode.vnid) { found_file = true; found_vnid = dir->vnid; - } else if ((strcmp(file, "..") == 0) && (dir->vnid == vol->root_vnode.vnid)) { + } else if (strcmp(file, "..") == 0 && dir->vnid == vol->root_vnode.vnid) { found_file = true; found_vnid = dir->dir_vnid; } else { struct diri diri; // XXX: do it in a smarter way - diri_init(vol, dir->cluster, 0, &diri); + if (diri_init(vol, dir->cluster, 0, &diri) == NULL) { + dprintf("findfile: error opening directory\n"); + return ENOENT; + } - while (1) - { + while (1) { char filename[512]; - vnode_id _vnid; + vnode_id _vnid; result = get_next_dirent(vol, dir, &diri, &_vnid, filename, 512); - if (result != B_NO_ERROR) break; - if(check_case) { + if (check_case) { if (!found_file && !strcmp(filename, file)) { found_file = true; found_vnid = _vnid; - } else if(check_dups && !strcasecmp(filename, file)) { + } else if (check_dups && !strcasecmp(filename, file)) { *dups_exist = true; } } else { if (!strcasecmp(filename, file)) { - if(check_dups && found_file) { + if (check_dups && found_file) *dups_exist = true; - } + found_file = true; found_vnid = _vnid; } } - if(found_file && (!check_dups || (check_dups && *dups_exist))) { + if (found_file && (!check_dups || (check_dups && *dups_exist))) break; - } } diri_free(&diri); } if (found_file) { - if (vnid) *vnid = found_vnid; - if (node) result = get_vnode(vol->id, found_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; @@ -421,7 +447,9 @@ static status_t findfile(nspace *vol, vnode *dir, const char *file, return result; } -status_t erase_dir_entry(nspace *vol, vnode *node) + +status_t +erase_dir_entry(nspace *vol, vnode *node) { status_t result; uint32 i; @@ -430,7 +458,8 @@ status_t erase_dir_entry(nspace *vol, vnode *node) struct _dirent_info_ info; struct diri diri; - DPRINTF(0, ("erasing directory entries %lx through %lx\n", node->sindex, node->eindex)); + DPRINTF(0, ("erasing directory entries %lx through %lx\n", + node->sindex, node->eindex)); buffer = diri_init(vol,VNODE_PARENT_DIR_CLUSTER(node), node->sindex, &diri); // first pass: check if the entry is still valid @@ -442,10 +471,10 @@ status_t erase_dir_entry(nspace *vol, vnode *node) result = _next_dirent_(&diri, &info, filename, 512); diri_free(&diri); - if (result < 0) return result; + if (result < 0) + return result; - if ((info.sindex != node->sindex) || - (info.eindex != node->eindex)) { + if (info.sindex != node->sindex || info.eindex != node->eindex) { // any other attributes may be in a state of flux due to wstat calls dprintf("erase_dir_entry: directory entry doesn't match\n"); return B_ERROR; @@ -453,7 +482,8 @@ status_t erase_dir_entry(nspace *vol, vnode *node) // second pass: actually erase the entry buffer = diri_init(vol, VNODE_PARENT_DIR_CLUSTER(node), node->sindex, &diri); - for (i=node->sindex;(i<=node->eindex)&&(buffer);buffer=diri_next_entry(&diri),i++) { + for (i = node->sindex; i <= node->eindex && buffer; + buffer = diri_next_entry(&diri), i++) { buffer[0] = 0xe5; // mark entry erased diri_mark_dirty(&diri); } @@ -462,11 +492,14 @@ status_t erase_dir_entry(nspace *vol, vnode *node) return 0; } -// shrink directory to the size needed -// errors here are neither likely nor problematic -// w95 doesn't seem to do this, so it's possible to create a -// really large directory that consumes all available space! -status_t compact_directory(nspace *vol, vnode *dir) + +/*! shrink directory to the size needed + errors here are neither likely nor problematic + w95 doesn't seem to do this, so it's possible to create a + really large directory that consumes all available space! +*/ +status_t +compact_directory(nspace *vol, vnode *dir) { uint32 last = 0; struct diri diri; @@ -478,7 +511,11 @@ status_t compact_directory(nspace *vol, vnode *dir) if (IS_FIXED_ROOT(dir->cluster)) return 0; - diri_init(vol, dir->cluster, 0, &diri); + if (diri_init(vol, dir->cluster, 0, &diri) == NULL) { + dprintf("compact_directory: cannot open dir at cluster (%lx)\n", + dir->cluster); + return EIO; + } while (diri.current_block) { char filename[512]; struct _dirent_info_ info; @@ -490,12 +527,15 @@ status_t compact_directory(nspace *vol, vnode *dir) if (!(info.mode & FAT_VOLUME) || (dir->vnid != vol->root_vnode.vnid)) last = diri.current_index; } else if (error == ENOENT) { - uint32 clusters = (last + vol->bytes_per_sector / 0x20 * vol->sectors_per_cluster - 1) / (vol->bytes_per_sector / 0x20) / vol->sectors_per_cluster; + uint32 clusters = (last + vol->bytes_per_sector / 0x20 + * vol->sectors_per_cluster - 1) / (vol->bytes_per_sector / 0x20) + / vol->sectors_per_cluster; error = 0; // special case for fat32 root directory; we don't want // it to disappear - if (clusters == 0) clusters = 1; + if (clusters == 0) + clusters = 1; if (clusters * vol->bytes_per_sector * vol->sectors_per_cluster < dir->st_size) { DPRINTF(0, ("shrinking directory to %lx clusters\n", clusters)); @@ -505,7 +545,8 @@ status_t compact_directory(nspace *vol, vnode *dir) } break; } else { - dprintf("compact_directory: unknown error from _next_dirent_ (%s)\n", strerror(error)); + dprintf("compact_directory: unknown error from _next_dirent_ (%s)\n", + strerror(error)); break; } } @@ -514,8 +555,10 @@ status_t compact_directory(nspace *vol, vnode *dir) return error; } -// name is array of char[11] as returned by findfile -static status_t find_short_name(nspace *vol, vnode *dir, const uchar *name) + +//! name is array of char[11] as returned by findfile +static status_t +find_short_name(nspace *vol, vnode *dir, const uchar *name) { struct diri diri; uint8 *buffer; @@ -541,6 +584,7 @@ static status_t find_short_name(nspace *vol, vnode *dir, const uchar *name) return result; } + struct _entry_info_ { uint32 mode; uint32 cluster; @@ -548,8 +592,11 @@ struct _entry_info_ { time_t time; }; -static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_ *info, - const char nshort[11], const char *nlong, uint32 len, uint32 *ns, uint32 *ne) + +static status_t +_create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_ *info, + const char nshort[11], const char *nlong, uint32 len, uint32 *ns, + uint32 *ne) { status_t error = B_ERROR; /* quiet warning */ uint32 required_entries, i; @@ -576,13 +623,13 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_ }; // check short name against device names - for (i=0;device_names[i];i++) { + for (i = 0; device_names[i]; i++) { // only first 8 characters seem to matter if (!memcmp(nshort, device_names[i], 8)) return EPERM; } - if ((info->cluster != 0) && !IS_DATA_CLUSTER(info->cluster)) { + if (info->cluster != 0 && !IS_DATA_CLUSTER(info->cluster)) { dprintf("_create_dir_entry_ for bad cluster (%lx)\n", info->cluster); return EINVAL; } @@ -593,7 +640,11 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_ // find a place to put the entries *ns = 0; last_entry = true; - diri_init(vol, dir->cluster, 0, &diri); + if (diri_init(vol, dir->cluster, 0, &diri) == NULL) { + dprintf("_create_dir_entry_: cannot open dir at cluster (%lx)\n", dir->cluster); + return EIO; + } + while (diri.current_block) { char filename[512]; struct _dirent_info_ info; @@ -608,7 +659,8 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_ // hit end of directory marker break; } else { - dprintf("_create_dir_entry_: unknown error from _next_dirent_ (%s)\n", strerror(error)); + dprintf("_create_dir_entry_: unknown error from _next_dirent_ (%s)\n", + strerror(error)); break; } } @@ -617,11 +669,12 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_ diri_free(&diri); - if ((error != B_OK) && (error != ENOENT)) return error; + if (error != B_OK && error != ENOENT) + return error; *ne = *ns + required_entries - 1; - for (i=*ns;i<=*ne;i++) { + for (i = *ns; i <= *ne; i++) { ASSERT(find_loc_in_vcache(vol, \ GENERATE_DIR_INDEX_VNID(dir->cluster, i)) == ENOENT); } @@ -643,7 +696,8 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_ vol->bytes_per_sector*vol->sectors_per_cluster - 1) / vol->bytes_per_sector / vol->sectors_per_cluster; - DPRINTF(0, ("expanding directory from %Lx to %lx clusters\n", dir->st_size/vol->bytes_per_sector/vol->sectors_per_cluster, clusters_needed)); + DPRINTF(0, ("expanding directory from %Lx to %lx clusters\n", + dir->st_size/vol->bytes_per_sector/vol->sectors_per_cluster, clusters_needed)); if ((error = set_fat_chain_length(vol, dir, clusters_needed)) < 0) return error; dir->st_size = vol->bytes_per_sector*vol->sectors_per_cluster*clusters_needed; @@ -652,11 +706,17 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_ // starting blitting entries buffer = diri_init(vol,dir->cluster, *ns, &diri); + if (buffer == NULL) { + dprintf("_create_dir_entry_: cannot open dir at (%lx, %lu)\n", + dir->cluster, *ns); + return EIO; + } hash = hash_msdos_name(nshort); // write lfn entries - for (i=1;(iroot_vnode), &info, name, NULL, 0, index, &dummy); + return _create_dir_entry_(vol, &(vol->root_vnode), &info, name, NULL, + 0, index, &dummy); } -bool is_filename_legal(const char *name) + +bool +is_filename_legal(const char *name) { unsigned int i; unsigned int len = strlen(name); - if (len <= 0) return false; + if (len <= 0) + return false; // names ending with a dot are not allowed - if (name[len - 1] == '.') return false; + if (name[len - 1] == '.') + return false; // names ending with a space are not allowed - if (name[len - 1] == ' ') return false; + if (name[len - 1] == ' ') + return false; // XXX illegal character search can be made faster - for(i=0; ivnid)); return EEXIST; @@ -815,10 +888,11 @@ status_t create_dir_entry(nspace *vol, vnode *dir, vnode *node, memcpy(nshort, tshort, 11); DPRINTF(0, ("trying short name %11.11s\n", nshort)); munge_short_name1(nshort, iter, encoding); - } while (((error = find_short_name(vol, dir, nshort)) == B_OK) && (++iter < 10)); + } while ((error = find_short_name(vol, dir, nshort)) == B_OK && ++iter < 10); } - if ((error != B_OK) && (error != ENOENT)) return error; + if (error != B_OK && error != ENOENT) + return error; if (error == B_OK) { // XXX: possible infinite loop here @@ -828,7 +902,8 @@ status_t create_dir_entry(nspace *vol, vnode *dir, vnode *node, munge_short_name2(nshort, encoding); } while ((error = find_short_name(vol, dir, nshort)) == B_OK); - if (error != ENOENT) return error; + if (error != ENOENT) + return error; } } else { len = 0; /* entry doesn't need a long name */ @@ -841,22 +916,25 @@ status_t create_dir_entry(nspace *vol, vnode *dir, vnode *node, info.size = node->st_size; info.time = node->st_time; - return _create_dir_entry_(vol, dir, &info, (char *)nshort, (char *)nlong, len, ns, ne); + return _create_dir_entry_(vol, dir, &info, (char *)nshort, + (char *)nlong, len, ns, ne); } status_t dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter) { - nspace *vol = (nspace*)_vol; - int result = B_NO_ERROR; + nspace *vol = (nspace*)_vol; + int result = B_NO_ERROR; vnode_id loc, dir_vnid; vnode *entry; struct _dirent_info_ info; struct diri iter; char filename[512]; /* need this for setting mime type */ - if (!reenter) { LOCK_VOL(vol); } + if (!reenter) { + LOCK_VOL(vol); + } *_node = NULL; @@ -867,8 +945,7 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter) DPRINTF(0, ("dosfs_read_vnode (vnode id %Lx)\n", vnid)); - if (vnid == vol->root_vnode.vnid) - { + if (vnid == vol->root_vnode.vnid) { dprintf("??? dosfs_read_vnode called on root node ???\n"); *_node = (void *)&(vol->root_vnode); goto bi; @@ -884,7 +961,8 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter) } if ((dir_vnid = dlist_find(vol, DIR_OF_VNID(loc))) == -1LL) { - DPRINTF(0, ("dosfs_read_vnode: unknown directory at cluster %lx\n", DIR_OF_VNID(loc))); + DPRINTF(0, ("dosfs_read_vnode: unknown directory at cluster %lx\n", + DIR_OF_VNID(loc))); result = ENOENT; goto bi; } @@ -892,7 +970,8 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter) if (diri_init(vol, DIR_OF_VNID(loc), IS_DIR_CLUSTER_VNID(loc) ? 0 : INDEX_OF_DIR_INDEX_VNID(loc), &iter) == NULL) { - dprintf("dosfs_read_vnode: error initializing directory for vnid %Lx (loc %Lx)\n", vnid, loc); + dprintf("dosfs_read_vnode: error initializing directory for vnid %Lx (loc %Lx)\n", + vnid, loc); result = ENOENT; goto bi; } @@ -900,7 +979,8 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter) while (1) { result = _next_dirent_(&iter, &info, filename, 512); if (result < 0) { - dprintf("dosfs_read_vnode: error finding vnid %Lx (loc %Lx) (%s)\n", vnid, loc, strerror(result)); + dprintf("dosfs_read_vnode: error finding vnid %Lx (loc %Lx) (%s)\n", + vnid, loc, strerror(result)); goto bi2; } @@ -910,7 +990,8 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter) } else { if (info.sindex == INDEX_OF_DIR_INDEX_VNID(loc)) break; - dprintf("dosfs_read_vnode: error finding vnid %Lx (loc %Lx) (%s)\n", vnid, loc, strerror(result)); + dprintf("dosfs_read_vnode: error finding vnid %Lx (loc %Lx) (%s)\n", + vnid, loc, strerror(result)); result = ENOENT; goto bi2; } @@ -943,7 +1024,8 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter) 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; + entry->st_size = count_clusters(vol,entry->cluster) + * vol->sectors_per_cluster * vol->bytes_per_sector; } if (entry->cluster) entry->end_cluster = get_nth_fat_entry(vol, info.cluster, @@ -1003,6 +1085,7 @@ dosfs_walk(void *_vol, void *_dir, const char *file, vnode_id *_vnid, int *_type return result; } + status_t dosfs_access(void *_vol, void *_node, int mode) { @@ -1012,15 +1095,15 @@ dosfs_access(void *_vol, void *_node, int mode) LOCK_VOL(vol); - if (check_nspace_magic(vol, "dosfs_access") || - check_vnode_magic(node, "dosfs_access")) { + if (check_nspace_magic(vol, "dosfs_access") + || check_vnode_magic(node, "dosfs_access")) { UNLOCK_VOL(vol); return EINVAL; } DPRINTF(0, ("dosfs_access (vnode id %Lx, mode %x)\n", node->vnid, mode)); - if ((mode & O_RWMASK) != O_RDONLY) { + if (mode & W_OK) { if (vol->flags & B_FS_IS_READONLY) { dprintf("dosfs_access: can't write on read-only volume\n"); result = EROFS; @@ -1054,10 +1137,10 @@ dosfs_readlink(void *_vol, void *_node, char *buf, size_t *bufsize) status_t dosfs_opendir(void *_vol, void *_node, void **_cookie) { - nspace *vol = (nspace*)_vol; - vnode *node = (vnode*)_node; - dircookie *cookie = NULL; - int result; + nspace *vol = (nspace*)_vol; + vnode *node = (vnode*)_node; + dircookie *cookie = NULL; + int result; if (_cookie == NULL) { dprintf("dosfs_opendir called with null _cookie\n"); @@ -1066,8 +1149,8 @@ dosfs_opendir(void *_vol, void *_node, void **_cookie) LOCK_VOL(vol); - if (check_nspace_magic(vol, "dosfs_opendir") || - check_vnode_magic(node, "dosfs_opendir")) { + if (check_nspace_magic(vol, "dosfs_opendir") + || check_vnode_magic(node, "dosfs_opendir")) { UNLOCK_VOL(vol); return EINVAL; } @@ -1100,7 +1183,8 @@ dosfs_opendir(void *_vol, void *_node, void **_cookie) bi: *_cookie = (void*)cookie; - if (result != B_OK) DPRINTF(0, ("dosfs_opendir (%s)\n", strerror(result))); + if (result != B_OK) + DPRINTF(0, ("dosfs_opendir (%s)\n", strerror(result))); UNLOCK_VOL(vol); @@ -1127,7 +1211,8 @@ dosfs_readdir(void *_vol, void *_dir, void *_cookie, return EINVAL; } - DPRINTF(0, ("dosfs_readdir: vnode id %Lx, index %lx\n", dir->vnid, cookie->current_index)); + DPRINTF(0, ("dosfs_readdir: vnode id %Lx, index %lx\n", + dir->vnid, cookie->current_index)); // simulate '.' and '..' entries for root directory if (dir->vnid == vol->root_vnode.vnid) { @@ -1149,8 +1234,16 @@ dosfs_readdir(void *_vol, void *_dir, void *_cookie, } } - diri_init(vol, dir->cluster, cookie->current_index, &diri); - result = get_next_dirent(vol, dir, &diri, &(entry->d_ino), entry->d_name, bufsize - sizeof(struct dirent) - 1); + if (diri_init(vol, dir->cluster, cookie->current_index, &diri) == NULL) { + DPRINTF(0, ("dosfs_readdir: no more entries!\n")); + // When you get to the end, don't return an error, just return 0 + // in *num. + *num = 0; + result = B_NO_ERROR; + goto bi; + } + result = get_next_dirent(vol, dir, &diri, &(entry->d_ino), entry->d_name, + bufsize - sizeof(struct dirent) - 1); cookie->current_index = diri.current_index; diri_free(&diri); @@ -1168,7 +1261,8 @@ dosfs_readdir(void *_vol, void *_dir, void *_cookie, *num = 0; result = B_NO_ERROR; } else { - dprintf("dosfs_readdir: error returned by get_next_dirent (%s)\n", strerror(result)); + dprintf("dosfs_readdir: error returned by get_next_dirent (%s)\n", + strerror(result)); } bi: if (result != B_OK) DPRINTF(0, ("dosfs_readdir (%s)\n", strerror(result))); @@ -1188,9 +1282,9 @@ dosfs_rewinddir(void *_vol, void *_node, void* _cookie) LOCK_VOL(vol); - if (check_nspace_magic(vol, "dosfs_rewinddir") || - check_vnode_magic(node, "dosfs_rewinddir") || - check_dircookie_magic(cookie, "dosfs_rewinddir")) { + if (check_nspace_magic(vol, "dosfs_rewinddir") + || check_vnode_magic(node, "dosfs_rewinddir") + || check_dircookie_magic(cookie, "dosfs_rewinddir")) { UNLOCK_VOL(vol); return EINVAL; } @@ -1224,9 +1318,9 @@ dosfs_free_dircookie(void *_vol, void *node, void *_cookie) LOCK_VOL(vol); - if (check_nspace_magic(vol, "dosfs_free_dircookie") || - check_vnode_magic((vnode *)node, "dosfs_free_dircookie") || - check_dircookie_magic((dircookie *)cookie, "dosfs_free_dircookie")) { + if (check_nspace_magic(vol, "dosfs_free_dircookie") + || check_vnode_magic((vnode *)node, "dosfs_free_dircookie") + || check_dircookie_magic((dircookie *)cookie, "dosfs_free_dircookie")) { UNLOCK_VOL(vol); return EINVAL; } diff --git a/src/add-ons/kernel/file_systems/dos/iter.c b/src/add-ons/kernel/file_systems/dos/iter.c index bc06070278..a60366dd0f 100644 --- a/src/add-ons/kernel/file_systems/dos/iter.c +++ b/src/add-ons/kernel/file_systems/dos/iter.c @@ -2,9 +2,11 @@ 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 "iter.h" @@ -16,7 +18,9 @@ CHECK_MAGIC(diri,struct diri,DIRI_MAGIC) -static int _validate_cs_(nspace *vol, uint32 cluster, uint32 sector) + +static int +_validate_cs_(nspace *vol, uint32 cluster, uint32 sector) { if (sector < 0) return -1; @@ -33,7 +37,9 @@ static int _validate_cs_(nspace *vol, uint32 cluster, uint32 sector) return 0; } -off_t csi_to_block(struct csi *csi) + +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); @@ -48,7 +54,9 @@ off_t csi_to_block(struct csi *csi) csi->sector; } -int init_csi(nspace *vol, uint32 cluster, uint32 sector, struct csi *csi) + +int +init_csi(nspace *vol, uint32 cluster, uint32 sector, struct csi *csi) { int ret; if ((ret = _validate_cs_(vol,cluster,sector)) != 0) @@ -59,7 +67,9 @@ int init_csi(nspace *vol, uint32 cluster, uint32 sector, struct csi *csi) return 0; } -int iter_csi(struct csi *csi, int sectors) + +int +iter_csi(struct csi *csi, int sectors) { if (csi->sector == 0xffff) // check if already at end of chain return -1; @@ -78,7 +88,8 @@ int iter_csi(struct csi *csi, int sectors) 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); + 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; @@ -96,16 +107,28 @@ int iter_csi(struct csi *csi, int sectors) return -1; } -uint8 *csi_get_block(struct csi *csi, int32 tid) + +uint8 * +csi_get_block(struct csi *csi, int32 tid) { if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) return NULL; - return block_cache_get_writable_etc(csi->vol->fBlockCache, csi_to_block(csi), - 1, csi->vol->bytes_per_sector, tid); + // TODO: the file system should be a bit smarter than this + // (ie. it should know when it needs a writable block) + + if (csi->vol->flags & B_FS_IS_READONLY) { + return (uint8 *)block_cache_get_etc(csi->vol->fBlockCache, csi_to_block(csi), + 1, csi->vol->bytes_per_sector); + } else { + return block_cache_get_writable_etc(csi->vol->fBlockCache, csi_to_block(csi), + 1, csi->vol->bytes_per_sector, tid); + } } -status_t csi_release_block(struct csi *csi) + +status_t +csi_release_block(struct csi *csi) { if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) return EINVAL; @@ -114,7 +137,9 @@ status_t csi_release_block(struct csi *csi) return B_OK; } -status_t csi_mark_block_dirty(struct csi *csi, int32 tid) + +status_t +csi_mark_block_dirty(struct csi *csi, int32 tid) { ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0); if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) @@ -126,8 +151,10 @@ status_t csi_mark_block_dirty(struct csi *csi, int32 tid) return B_OK; } + /* 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) +status_t +csi_read_blocks(struct csi *csi, uint8 *buffer, ssize_t len) { struct csi old_csi; uint32 sectors; @@ -154,7 +181,7 @@ status_t csi_read_blocks(struct csi *csi, uint8 *buffer, ssize_t len) sectors++; } - for (i=block; ivol->fBlockCache, i); memcpy(buf, blockData, csi->vol->bytes_per_sector); buf += csi->vol->bytes_per_sector; @@ -166,7 +193,9 @@ status_t csi_read_blocks(struct csi *csi, uint8 *buffer, ssize_t len) return sectors * csi->vol->bytes_per_sector; } -status_t csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len) + +status_t +csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len) { struct csi old_csi; uint32 sectors; @@ -193,9 +222,9 @@ status_t csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len) break; sectors++; } - + tid = cache_start_transaction(csi->vol->fBlockCache); - for(i=block; ivol->fBlockCache, i, 0, 1, tid); memcpy(blockData, buf, csi->vol->bytes_per_sector); buf += csi->vol->bytes_per_sector; @@ -211,7 +240,9 @@ status_t csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len) return sectors * csi->vol->bytes_per_sector; } -status_t csi_write_block(struct csi *csi, uint8 *buffer) + +status_t +csi_write_block(struct csi *csi, uint8 *buffer) { off_t block; int32 tid; @@ -232,7 +263,9 @@ status_t csi_write_block(struct csi *csi, uint8 *buffer) return B_OK; } -static void _diri_release_current_block_(struct diri *diri) + +static void +_diri_release_current_block_(struct diri *diri) { ASSERT(diri->current_block); if (diri->current_block == NULL) @@ -241,9 +274,11 @@ static void _diri_release_current_block_(struct diri *diri) diri->current_block = NULL; } -uint8 *diri_init(nspace *vol, uint32 cluster, uint32 index, struct diri *diri) + +uint8 * +diri_init(nspace *vol, uint32 cluster, uint32 index, struct diri *diri) { - diri->magic = DIRI_MAGIC; + diri->magic = ~DIRI_MAGIC; // trash magic number diri->current_block = NULL; if (cluster >= vol->total_clusters + 2) @@ -254,23 +289,32 @@ uint8 *diri_init(nspace *vol, uint32 cluster, uint32 index, struct diri *diri) 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; - } + if (index >= vol->bytes_per_sector / 0x20 + && iter_csi(&(diri->csi), diri->current_index + / (vol->bytes_per_sector / 0x20)) != 0) + return NULL; diri->tid = cache_start_transaction(diri->csi.vol->fBlockCache); + if (diri->tid < B_OK) + return NULL; // get current sector diri->current_block = csi_get_block(&(diri->csi), diri->tid); - if (diri->current_block == NULL) + if (diri->current_block == NULL) { + cache_end_transaction(diri->csi.vol->fBlockCache, diri->tid, NULL, NULL); return NULL; + } - return diri->current_block + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20; + // now the diri is valid + diri->magic = DIRI_MAGIC; + return diri->current_block + + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20; } -int diri_free(struct diri *diri) + +int +diri_free(struct diri *diri) { if (check_diri_magic(diri, "diri_free")) return EINVAL; @@ -284,17 +328,22 @@ int diri_free(struct diri *diri) return 0; } -uint8 *diri_current_entry(struct diri *diri) + +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; + return diri->current_block + + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20; } -uint8 *diri_next_entry(struct diri *diri) + +uint8 * +diri_next_entry(struct diri *diri) { if (check_diri_magic(diri, "diri_next_entry")) return NULL; @@ -310,12 +359,16 @@ uint8 *diri_next_entry(struct diri *diri) return NULL; } - return diri->current_block + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20; + return diri->current_block + + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20; } -uint8 *diri_rewind(struct diri *diri) + +uint8 * +diri_rewind(struct diri *diri) { - if (check_diri_magic(diri, "diri_rewind")) return NULL; + 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) @@ -328,7 +381,9 @@ uint8 *diri_rewind(struct diri *diri) return diri->current_block; } -void diri_mark_dirty(struct diri *diri) + +void +diri_mark_dirty(struct diri *diri) { csi_mark_block_dirty(&(diri->csi), diri->tid); }