* Applied patch by Jan Kloetzke - thanks!:

- possible panic in the directory retrieval code because of an invalid
    transaction ID. This should fix bug #1025.
  - could not been mounted read-only as it was always getting writable
    blocks from the cache.
  - dosfs_access() tested for O_RDONLY instead of W_OK.
* Added TODO comment about always using writable blocks: this is highly
  inefficient.
* Some code cleanup to make it a tiny bit more complying to our coding
  style.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21213 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-05-23 07:54:57 +00:00
parent 1b2db790c0
commit 7e4dc23a7e
2 changed files with 325 additions and 176 deletions
+237 -143
View File
@@ -2,6 +2,7 @@
Copyright 1999-2001, Be Incorporated. All Rights Reserved. Copyright 1999-2001, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License. This file may be used under the terms of the Be Sample Code License.
*/ */
#include <KernelExport.h> #include <KernelExport.h>
#include <stdlib.h> #include <stdlib.h>
@@ -31,8 +32,7 @@ const char illegal[] = "\\/:*?\"<>|";
#define DIRCOOKIE_MAGIC 'AiC ' #define DIRCOOKIE_MAGIC 'AiC '
typedef struct dircookie typedef struct dircookie {
{
uint32 magic; uint32 magic;
uint32 current_index; uint32 current_index;
} dircookie; } dircookie;
@@ -53,19 +53,21 @@ struct _dirent_info_ {
}; };
// scans dir for the next entry, using the state stored in a struct diri. // 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, static status_t
char *filename, int len) _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo, char *filename,
int len)
{ {
uint8 *buffer, hash = 0; /* quiet warning */ uint8 *buffer, hash = 0; /* quiet warning */
uchar uni[1024]; uchar uni[1024];
uint16 *puni; uint16 *puni;
uint32 i; uint32 i;
// lfn state // lfn state
uint32 start_index = 0xffff, filename_len = 0 /* quiet warning */, uint32 start_index = 0xffff, filename_len = 0; /* quiet warning */
lfn_count = 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) if (iter->current_block == NULL)
return ENOENT; return ENOENT;
@@ -75,10 +77,12 @@ static status_t _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo,
return ENOMEM; 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)) { 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)); 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 (buffer[0] == 0) { // quit if at end of table
if (start_index != 0xffff) { if (start_index != 0xffff) {
dprintf("lfn entry (%s) with no alias\n", filename); 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; lfn_count = buffer[0] & 0x1f;
start_index = iter->current_index; start_index = iter->current_index;
puni = (uint16 *)(uni + 2*13*(lfn_count - 1)); 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) if (*(uint16 *)&buffer[i] == 0xffff)
break; break;
*puni++ = *(uint16 *)&buffer[i]; *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)); 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)) { if ((buffer[i] == 0xff) && (buffer[i+1] == 0xff)) {
dprintf("bad lfn entry in directory\n"); dprintf("bad lfn entry in directory\n");
start_index = 0xffff; 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); diri_init(iter->csi.vol, iter->starting_cluster, start_index, iter);
return ENAMETOOLONG; return ENAMETOOLONG;
} else if (hash_msdos_name((const char *)buffer) != hash) { } 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; start_index = 0xffff;
} }
} }
@@ -198,21 +203,24 @@ static status_t _next_dirent_(struct diri *iter, struct _dirent_info_ *oinfo,
return B_NO_ERROR; 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; struct _dirent_info_ info;
status_t result; status_t result;
if (check_nspace_magic(vol, "get_next_dirent")) return EINVAL; if (check_nspace_magic(vol, "get_next_dirent"))
return EINVAL;
do { do {
result = _next_dirent_(iter, &info, filename, len); result = _next_dirent_(iter, &info, filename, len);
if (result < 0)
if (result < 0) return result; return result;
// only hide volume label entries in the root directory // only hide volume label entries in the root directory
} while ((info.mode & FAT_VOLUME) && (dir->vnid == vol->root_vnode.vnid)); } while ((info.mode & FAT_VOLUME) && (dir->vnid == vol->root_vnode.vnid));
if (!strcmp(filename, ".")) { if (!strcmp(filename, ".")) {
// assign vnode based on parent // assign vnode based on parent
if (vnid) *vnid = dir->vnid; 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; if (vnid) *vnid = dir->dir_vnid;
} else { } else {
if (vnid) { if (vnid) {
vnode_id loc = (IS_DATA_CLUSTER(info.cluster)) ? vnode_id loc = (IS_DATA_CLUSTER(info.cluster))
GENERATE_DIR_CLUSTER_VNID(dir->vnid, info.cluster) : ? GENERATE_DIR_CLUSTER_VNID(dir->vnid, info.cluster)
GENERATE_DIR_INDEX_VNID(dir->vnid, info.sindex); : GENERATE_DIR_INDEX_VNID(dir->vnid, info.sindex);
bool added_to_vcache = false; bool added_to_vcache = false;
/* if it matches a loc in the lookup table, we are done. */ /* 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; return B_NO_ERROR;
} }
status_t check_dir_empty(nspace *vol, vnode *dir)
status_t
check_dir_empty(nspace *vol, vnode *dir)
{ {
uint32 i; uint32 i;
struct diri iter; struct diri iter;
status_t result = B_ERROR; /* quiet warning */ status_t result = B_ERROR; /* quiet warning */
if (check_nspace_magic(vol, "check_dir_empty")) return EINVAL; if (check_nspace_magic(vol, "check_dir_empty"))
if (check_vnode_magic(dir, "check_dir_empty")) return EINVAL; return EINVAL;
if (check_vnode_magic(dir, "check_dir_empty"))
return EINVAL;
if (diri_init(vol, dir->cluster, 0, &iter) == NULL) { if (diri_init(vol, dir->cluster, 0, &iter) == NULL) {
dprintf("check_dir_empty: error opening directory\n"); dprintf("check_dir_empty: error opening directory\n");
ASSERT(0);
return B_ERROR; return B_ERROR;
} }
i = (dir->vnid == vol->root_vnode.vnid) ? 2 : 0; i = (dir->vnid == vol->root_vnode.vnid) ? 2 : 0;
for (;i<3;i++) { for (; i < 3; i++) {
char filename[512]; char filename[512];
result = _next_dirent_(&iter, NULL, filename, 512); result = _next_dirent_(&iter, NULL, filename, 512);
if (result < 0) { if (result < 0) {
if ((i == 2) && (result == ENOENT)) result = B_OK; if (i == 2 && result == ENOENT)
result = B_OK;
break; break;
} }
if (((i == 0) && strcmp(filename, ".")) || if ((i == 0 && strcmp(filename, "."))
((i == 1) && strcmp(filename, "..")) || || (i == 1 && strcmp(filename, ".."))
// weird case where ./.. are stored as long file names // 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"); dprintf("check_dir_empty: malformed directory\n");
result = ENOTDIR; result = ENOTDIR;
break; break;
@@ -307,33 +318,42 @@ status_t check_dir_empty(nspace *vol, vnode *dir)
return result; 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); 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); 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); 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); 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, static status_t
bool check_dups, bool *dups_exist) 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 /* Starting at the base, find the file in the subdir
and return its vnode id */ 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); // 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_nspace_magic(vol, "findfile"))
if (check_vnode_magic(dir, "findfile")) return EINVAL; return EINVAL;
if (check_vnode_magic(dir, "findfile"))
return EINVAL;
DPRINTF(1, ("findfile: %s in %Lx\n", file, dir->vnid)); DPRINTF(1, ("findfile: %s in %Lx\n", file, dir->vnid));
if(dups_exist != NULL) *dups_exist = false; if (dups_exist != NULL)
else check_dups = false; *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_file = true;
found_vnid = dir->vnid; 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_file = true;
found_vnid = dir->dir_vnid; found_vnid = dir->dir_vnid;
} else { } else {
struct diri diri; struct diri diri;
// XXX: do it in a smarter way // 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]; char filename[512];
vnode_id _vnid; vnode_id _vnid;
result = get_next_dirent(vol, dir, &diri, &_vnid, filename, 512); result = get_next_dirent(vol, dir, &diri, &_vnid, filename, 512);
if (result != B_NO_ERROR) if (result != B_NO_ERROR)
break; break;
if(check_case) { if (check_case) {
if (!found_file && !strcmp(filename, file)) { if (!found_file && !strcmp(filename, file)) {
found_file = true; found_file = true;
found_vnid = _vnid; found_vnid = _vnid;
} else if(check_dups && !strcasecmp(filename, file)) { } else if (check_dups && !strcasecmp(filename, file)) {
*dups_exist = true; *dups_exist = true;
} }
} else { } else {
if (!strcasecmp(filename, file)) { if (!strcasecmp(filename, file)) {
if(check_dups && found_file) { if (check_dups && found_file)
*dups_exist = true; *dups_exist = true;
}
found_file = true; found_file = true;
found_vnid = _vnid; found_vnid = _vnid;
} }
} }
if(found_file && (!check_dups || (check_dups && *dups_exist))) { if (found_file && (!check_dups || (check_dups && *dups_exist)))
break; break;
}
} }
diri_free(&diri); diri_free(&diri);
} }
if (found_file) { if (found_file) {
if (vnid) *vnid = found_vnid; if (vnid)
if (node) result = get_vnode(vol->id, found_vnid, (void **)node); *vnid = found_vnid;
if (node)
result = get_vnode(vol->id, found_vnid, (void **)node);
result = B_OK; result = B_OK;
} else { } else {
result = ENOENT; result = ENOENT;
@@ -421,7 +447,9 @@ static status_t findfile(nspace *vol, vnode *dir, const char *file,
return result; return result;
} }
status_t erase_dir_entry(nspace *vol, vnode *node)
status_t
erase_dir_entry(nspace *vol, vnode *node)
{ {
status_t result; status_t result;
uint32 i; uint32 i;
@@ -430,7 +458,8 @@ status_t erase_dir_entry(nspace *vol, vnode *node)
struct _dirent_info_ info; struct _dirent_info_ info;
struct diri diri; 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); buffer = diri_init(vol,VNODE_PARENT_DIR_CLUSTER(node), node->sindex, &diri);
// first pass: check if the entry is still valid // 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); result = _next_dirent_(&diri, &info, filename, 512);
diri_free(&diri); diri_free(&diri);
if (result < 0) return result; if (result < 0)
return result;
if ((info.sindex != node->sindex) || if (info.sindex != node->sindex || info.eindex != node->eindex) {
(info.eindex != node->eindex)) {
// any other attributes may be in a state of flux due to wstat calls // any other attributes may be in a state of flux due to wstat calls
dprintf("erase_dir_entry: directory entry doesn't match\n"); dprintf("erase_dir_entry: directory entry doesn't match\n");
return B_ERROR; return B_ERROR;
@@ -453,7 +482,8 @@ status_t erase_dir_entry(nspace *vol, vnode *node)
// second pass: actually erase the entry // second pass: actually erase the entry
buffer = diri_init(vol, VNODE_PARENT_DIR_CLUSTER(node), node->sindex, &diri); 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 buffer[0] = 0xe5; // mark entry erased
diri_mark_dirty(&diri); diri_mark_dirty(&diri);
} }
@@ -462,11 +492,14 @@ status_t erase_dir_entry(nspace *vol, vnode *node)
return 0; return 0;
} }
// shrink directory to the size needed
// errors here are neither likely nor problematic /*! shrink directory to the size needed
// w95 doesn't seem to do this, so it's possible to create a errors here are neither likely nor problematic
// really large directory that consumes all available space! w95 doesn't seem to do this, so it's possible to create a
status_t compact_directory(nspace *vol, vnode *dir) really large directory that consumes all available space!
*/
status_t
compact_directory(nspace *vol, vnode *dir)
{ {
uint32 last = 0; uint32 last = 0;
struct diri diri; struct diri diri;
@@ -478,7 +511,11 @@ status_t compact_directory(nspace *vol, vnode *dir)
if (IS_FIXED_ROOT(dir->cluster)) if (IS_FIXED_ROOT(dir->cluster))
return 0; 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) { while (diri.current_block) {
char filename[512]; char filename[512];
struct _dirent_info_ info; 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)) if (!(info.mode & FAT_VOLUME) || (dir->vnid != vol->root_vnode.vnid))
last = diri.current_index; last = diri.current_index;
} else if (error == ENOENT) { } 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; error = 0;
// special case for fat32 root directory; we don't want // special case for fat32 root directory; we don't want
// it to disappear // 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) { if (clusters * vol->bytes_per_sector * vol->sectors_per_cluster < dir->st_size) {
DPRINTF(0, ("shrinking directory to %lx clusters\n", clusters)); DPRINTF(0, ("shrinking directory to %lx clusters\n", clusters));
@@ -505,7 +545,8 @@ status_t compact_directory(nspace *vol, vnode *dir)
} }
break; break;
} else { } 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; break;
} }
} }
@@ -514,8 +555,10 @@ status_t compact_directory(nspace *vol, vnode *dir)
return error; 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; struct diri diri;
uint8 *buffer; uint8 *buffer;
@@ -541,6 +584,7 @@ static status_t find_short_name(nspace *vol, vnode *dir, const uchar *name)
return result; return result;
} }
struct _entry_info_ { struct _entry_info_ {
uint32 mode; uint32 mode;
uint32 cluster; uint32 cluster;
@@ -548,8 +592,11 @@ struct _entry_info_ {
time_t time; 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 */ status_t error = B_ERROR; /* quiet warning */
uint32 required_entries, i; 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 // 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 // only first 8 characters seem to matter
if (!memcmp(nshort, device_names[i], 8)) if (!memcmp(nshort, device_names[i], 8))
return EPERM; 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); dprintf("_create_dir_entry_ for bad cluster (%lx)\n", info->cluster);
return EINVAL; 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 // find a place to put the entries
*ns = 0; *ns = 0;
last_entry = true; 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) { while (diri.current_block) {
char filename[512]; char filename[512];
struct _dirent_info_ info; 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 // hit end of directory marker
break; break;
} else { } 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; break;
} }
} }
@@ -617,11 +669,12 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_
diri_free(&diri); diri_free(&diri);
if ((error != B_OK) && (error != ENOENT)) return error; if (error != B_OK && error != ENOENT)
return error;
*ne = *ns + required_entries - 1; *ne = *ns + required_entries - 1;
for (i=*ns;i<=*ne;i++) { for (i = *ns; i <= *ne; i++) {
ASSERT(find_loc_in_vcache(vol, \ ASSERT(find_loc_in_vcache(vol, \
GENERATE_DIR_INDEX_VNID(dir->cluster, i)) == ENOENT); 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 - 1) /
vol->bytes_per_sector / vol->sectors_per_cluster; 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) if ((error = set_fat_chain_length(vol, dir, clusters_needed)) < 0)
return error; return error;
dir->st_size = vol->bytes_per_sector*vol->sectors_per_cluster*clusters_needed; 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 // starting blitting entries
buffer = diri_init(vol,dir->cluster, *ns, &diri); 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); hash = hash_msdos_name(nshort);
// write lfn entries // write lfn entries
for (i=1;(i<required_entries)&&buffer;i++) { for (i = 1; i < required_entries && buffer; i++) {
const char *p = nlong + (required_entries - i - 1)*26; // go to unicode offset const char *p = nlong + (required_entries - i - 1) * 26;
// go to unicode offset
memset(buffer, 0, 0x20); memset(buffer, 0, 0x20);
buffer[0] = required_entries - i + ((i == 1) ? 0x40 : 0); buffer[0] = required_entries - i + ((i == 1) ? 0x40 : 0);
buffer[0x0b] = 0x0f; buffer[0x0b] = 0x0f;
@@ -714,8 +774,10 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_
return 0; return 0;
} }
// doesn't do any name checking
status_t create_volume_label(nspace *vol, const char name[11], uint32 *index) //! doesn't do any name checking
status_t
create_volume_label(nspace *vol, const char name[11], uint32 *index)
{ {
status_t err; status_t err;
uint32 dummy; uint32 dummy;
@@ -731,32 +793,43 @@ status_t create_volume_label(nspace *vol, const char name[11], uint32 *index)
if (err != ENOENT) if (err != ENOENT)
return err; return err;
return _create_dir_entry_(vol, &(vol->root_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 i;
unsigned int len = strlen(name); unsigned int len = strlen(name);
if (len <= 0) return false; if (len <= 0)
return false;
// names ending with a dot are not allowed // 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 // 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 // XXX illegal character search can be made faster
for(i=0; i<len; i++) { for (i = 0; i < len; i++) {
if(name[i] & 0x80) continue; //belongs to an utf8 char if (name[i] & 0x80)
if(strchr(illegal, name[i])) return false; continue; //belongs to an utf8 char
if((unsigned char)name[i] < 32) return false; if (strchr(illegal, name[i]))
return false;
if ((unsigned char)name[i] < 32)
return false;
} }
return true; return true;
} }
status_t create_dir_entry(nspace *vol, vnode *dir, vnode *node,
const char *name, uint32 *ns, uint32 *ne) status_t
create_dir_entry(nspace *vol, vnode *dir, vnode *node, const char *name,
uint32 *ns, uint32 *ne)
{ {
status_t error; status_t error;
int32 len; int32 len;
@@ -765,11 +838,11 @@ status_t create_dir_entry(nspace *vol, vnode *dir, vnode *node,
struct _entry_info_ info; struct _entry_info_ info;
// check name legality before doing anything // check name legality before doing anything
if(!is_filename_legal(name)) if (!is_filename_legal(name))
return EINVAL; return EINVAL;
// check if name already exists // check if name already exists
error = findfile_nocase(vol,dir,name,NULL,NULL); error = findfile_nocase(vol, dir, name, NULL, NULL);
if (error == B_OK) { if (error == B_OK) {
DPRINTF(0, ("%s already found in directory %Lx\n", name, dir->vnid)); DPRINTF(0, ("%s already found in directory %Lx\n", name, dir->vnid));
return EEXIST; return EEXIST;
@@ -815,10 +888,11 @@ status_t create_dir_entry(nspace *vol, vnode *dir, vnode *node,
memcpy(nshort, tshort, 11); memcpy(nshort, tshort, 11);
DPRINTF(0, ("trying short name %11.11s\n", nshort)); DPRINTF(0, ("trying short name %11.11s\n", nshort));
munge_short_name1(nshort, iter, encoding); 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) { if (error == B_OK) {
// XXX: possible infinite loop here // 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); munge_short_name2(nshort, encoding);
} while ((error = find_short_name(vol, dir, nshort)) == B_OK); } while ((error = find_short_name(vol, dir, nshort)) == B_OK);
if (error != ENOENT) return error; if (error != ENOENT)
return error;
} }
} else { } else {
len = 0; /* entry doesn't need a long name */ 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.size = node->st_size;
info.time = node->st_time; 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 status_t
dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter) dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter)
{ {
nspace *vol = (nspace*)_vol; nspace *vol = (nspace*)_vol;
int result = B_NO_ERROR; int result = B_NO_ERROR;
vnode_id loc, dir_vnid; vnode_id loc, dir_vnid;
vnode *entry; vnode *entry;
struct _dirent_info_ info; struct _dirent_info_ info;
struct diri iter; struct diri iter;
char filename[512]; /* need this for setting mime type */ char filename[512]; /* need this for setting mime type */
if (!reenter) { LOCK_VOL(vol); } if (!reenter) {
LOCK_VOL(vol);
}
*_node = NULL; *_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)); 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"); dprintf("??? dosfs_read_vnode called on root node ???\n");
*_node = (void *)&(vol->root_vnode); *_node = (void *)&(vol->root_vnode);
goto bi; 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) { 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; result = ENOENT;
goto bi; 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), if (diri_init(vol, DIR_OF_VNID(loc),
IS_DIR_CLUSTER_VNID(loc) ? 0 : INDEX_OF_DIR_INDEX_VNID(loc), IS_DIR_CLUSTER_VNID(loc) ? 0 : INDEX_OF_DIR_INDEX_VNID(loc),
&iter) == NULL) { &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; result = ENOENT;
goto bi; goto bi;
} }
@@ -900,7 +979,8 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter)
while (1) { while (1) {
result = _next_dirent_(&iter, &info, filename, 512); result = _next_dirent_(&iter, &info, filename, 512);
if (result < 0) { 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; goto bi2;
} }
@@ -910,7 +990,8 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter)
} else { } else {
if (info.sindex == INDEX_OF_DIR_INDEX_VNID(loc)) if (info.sindex == INDEX_OF_DIR_INDEX_VNID(loc))
break; 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; result = ENOENT;
goto bi2; goto bi2;
} }
@@ -943,7 +1024,8 @@ dosfs_read_vnode(void *_vol, vnode_id vnid, void **_node, bool reenter)
entry->st_size = info.size; entry->st_size = info.size;
entry->dirty = false; entry->dirty = false;
if (info.mode & FAT_SUBDIR) { 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) if (entry->cluster)
entry->end_cluster = get_nth_fat_entry(vol, info.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; return result;
} }
status_t status_t
dosfs_access(void *_vol, void *_node, int mode) dosfs_access(void *_vol, void *_node, int mode)
{ {
@@ -1012,15 +1095,15 @@ dosfs_access(void *_vol, void *_node, int mode)
LOCK_VOL(vol); LOCK_VOL(vol);
if (check_nspace_magic(vol, "dosfs_access") || if (check_nspace_magic(vol, "dosfs_access")
check_vnode_magic(node, "dosfs_access")) { || check_vnode_magic(node, "dosfs_access")) {
UNLOCK_VOL(vol); UNLOCK_VOL(vol);
return EINVAL; return EINVAL;
} }
DPRINTF(0, ("dosfs_access (vnode id %Lx, mode %x)\n", node->vnid, mode)); 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) { if (vol->flags & B_FS_IS_READONLY) {
dprintf("dosfs_access: can't write on read-only volume\n"); dprintf("dosfs_access: can't write on read-only volume\n");
result = EROFS; result = EROFS;
@@ -1054,10 +1137,10 @@ dosfs_readlink(void *_vol, void *_node, char *buf, size_t *bufsize)
status_t status_t
dosfs_opendir(void *_vol, void *_node, void **_cookie) dosfs_opendir(void *_vol, void *_node, void **_cookie)
{ {
nspace *vol = (nspace*)_vol; nspace *vol = (nspace*)_vol;
vnode *node = (vnode*)_node; vnode *node = (vnode*)_node;
dircookie *cookie = NULL; dircookie *cookie = NULL;
int result; int result;
if (_cookie == NULL) { if (_cookie == NULL) {
dprintf("dosfs_opendir called with null _cookie\n"); dprintf("dosfs_opendir called with null _cookie\n");
@@ -1066,8 +1149,8 @@ dosfs_opendir(void *_vol, void *_node, void **_cookie)
LOCK_VOL(vol); LOCK_VOL(vol);
if (check_nspace_magic(vol, "dosfs_opendir") || if (check_nspace_magic(vol, "dosfs_opendir")
check_vnode_magic(node, "dosfs_opendir")) { || check_vnode_magic(node, "dosfs_opendir")) {
UNLOCK_VOL(vol); UNLOCK_VOL(vol);
return EINVAL; return EINVAL;
} }
@@ -1100,7 +1183,8 @@ dosfs_opendir(void *_vol, void *_node, void **_cookie)
bi: bi:
*_cookie = (void*)cookie; *_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); UNLOCK_VOL(vol);
@@ -1127,7 +1211,8 @@ dosfs_readdir(void *_vol, void *_dir, void *_cookie,
return EINVAL; 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 // simulate '.' and '..' entries for root directory
if (dir->vnid == vol->root_vnode.vnid) { 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); if (diri_init(vol, dir->cluster, cookie->current_index, &diri) == NULL) {
result = get_next_dirent(vol, dir, &diri, &(entry->d_ino), entry->d_name, bufsize - sizeof(struct dirent) - 1); 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; cookie->current_index = diri.current_index;
diri_free(&diri); diri_free(&diri);
@@ -1168,7 +1261,8 @@ dosfs_readdir(void *_vol, void *_dir, void *_cookie,
*num = 0; *num = 0;
result = B_NO_ERROR; result = B_NO_ERROR;
} else { } 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: bi:
if (result != B_OK) DPRINTF(0, ("dosfs_readdir (%s)\n", strerror(result))); 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); LOCK_VOL(vol);
if (check_nspace_magic(vol, "dosfs_rewinddir") || if (check_nspace_magic(vol, "dosfs_rewinddir")
check_vnode_magic(node, "dosfs_rewinddir") || || check_vnode_magic(node, "dosfs_rewinddir")
check_dircookie_magic(cookie, "dosfs_rewinddir")) { || check_dircookie_magic(cookie, "dosfs_rewinddir")) {
UNLOCK_VOL(vol); UNLOCK_VOL(vol);
return EINVAL; return EINVAL;
} }
@@ -1224,9 +1318,9 @@ dosfs_free_dircookie(void *_vol, void *node, void *_cookie)
LOCK_VOL(vol); LOCK_VOL(vol);
if (check_nspace_magic(vol, "dosfs_free_dircookie") || if (check_nspace_magic(vol, "dosfs_free_dircookie")
check_vnode_magic((vnode *)node, "dosfs_free_dircookie") || || check_vnode_magic((vnode *)node, "dosfs_free_dircookie")
check_dircookie_magic((dircookie *)cookie, "dosfs_free_dircookie")) { || check_dircookie_magic((dircookie *)cookie, "dosfs_free_dircookie")) {
UNLOCK_VOL(vol); UNLOCK_VOL(vol);
return EINVAL; return EINVAL;
} }
+88 -33
View File
@@ -2,9 +2,11 @@
Copyright 1999-2001, Be Incorporated. All Rights Reserved. Copyright 1999-2001, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License. This file may be used under the terms of the Be Sample Code License.
*/ */
#include <KernelExport.h> #include <KernelExport.h>
#include <fs_cache.h> #include <fs_cache.h>
#include <fs_info.h>
#include <string.h> #include <string.h>
#include "iter.h" #include "iter.h"
@@ -16,7 +18,9 @@
CHECK_MAGIC(diri,struct diri,DIRI_MAGIC) 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; if (sector < 0) return -1;
@@ -33,7 +37,9 @@ static int _validate_cs_(nspace *vol, uint32 cluster, uint32 sector)
return 0; 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 // presumes the caller has already called _validate_cs_ on the argument
ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0); ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0);
@@ -48,7 +54,9 @@ off_t csi_to_block(struct csi *csi)
csi->sector; 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; int ret;
if ((ret = _validate_cs_(vol,cluster,sector)) != 0) 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; 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 if (csi->sector == 0xffff) // check if already at end of chain
return -1; return -1;
@@ -78,7 +88,8 @@ int iter_csi(struct csi *csi, int sectors)
csi->sector += sectors; csi->sector += sectors;
if (csi->sector < csi->vol->sectors_per_cluster) if (csi->sector < csi->vol->sectors_per_cluster)
return 0; 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) { if ((int32)csi->cluster < 0) {
csi->sector = 0xffff; csi->sector = 0xffff;
@@ -96,16 +107,28 @@ int iter_csi(struct csi *csi, int sectors)
return -1; 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) if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
return NULL; return NULL;
return block_cache_get_writable_etc(csi->vol->fBlockCache, csi_to_block(csi), // TODO: the file system should be a bit smarter than this
1, csi->vol->bytes_per_sector, tid); // (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) if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
return EINVAL; return EINVAL;
@@ -114,7 +137,9 @@ status_t csi_release_block(struct csi *csi)
return B_OK; 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); ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0);
if (_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; return B_OK;
} }
/* XXX: not the most efficient implementation, but it gets the job done */ /* 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; struct csi old_csi;
uint32 sectors; uint32 sectors;
@@ -154,7 +181,7 @@ status_t csi_read_blocks(struct csi *csi, uint8 *buffer, ssize_t len)
sectors++; sectors++;
} }
for (i=block; i<block+sectors; i++) { for (i = block; i < block + sectors; i++) {
char *blockData = (char *)block_cache_get(csi->vol->fBlockCache, i); char *blockData = (char *)block_cache_get(csi->vol->fBlockCache, i);
memcpy(buf, blockData, csi->vol->bytes_per_sector); memcpy(buf, blockData, csi->vol->bytes_per_sector);
buf += 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; 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; struct csi old_csi;
uint32 sectors; uint32 sectors;
@@ -193,9 +222,9 @@ status_t csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len)
break; break;
sectors++; sectors++;
} }
tid = cache_start_transaction(csi->vol->fBlockCache); tid = cache_start_transaction(csi->vol->fBlockCache);
for(i=block; i<block+sectors; i++) { for (i = block; i < block + sectors; i++) {
char *blockData = block_cache_get_writable_etc(csi->vol->fBlockCache, i, 0, 1, tid); char *blockData = block_cache_get_writable_etc(csi->vol->fBlockCache, i, 0, 1, tid);
memcpy(blockData, buf, csi->vol->bytes_per_sector); memcpy(blockData, buf, csi->vol->bytes_per_sector);
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; 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; off_t block;
int32 tid; int32 tid;
@@ -232,7 +263,9 @@ status_t csi_write_block(struct csi *csi, uint8 *buffer)
return B_OK; 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); ASSERT(diri->current_block);
if (diri->current_block == NULL) if (diri->current_block == NULL)
@@ -241,9 +274,11 @@ static void _diri_release_current_block_(struct diri *diri)
diri->current_block = NULL; 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; diri->current_block = NULL;
if (cluster >= vol->total_clusters + 2) 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->starting_cluster = cluster;
diri->current_index = index; diri->current_index = index;
if (index >= vol->bytes_per_sector / 0x20) { if (index >= vol->bytes_per_sector / 0x20
if (iter_csi(&(diri->csi), diri->current_index / (vol->bytes_per_sector / 0x20)) != 0) && iter_csi(&(diri->csi), diri->current_index
return NULL; / (vol->bytes_per_sector / 0x20)) != 0)
} return NULL;
diri->tid = cache_start_transaction(diri->csi.vol->fBlockCache); diri->tid = cache_start_transaction(diri->csi.vol->fBlockCache);
if (diri->tid < B_OK)
return NULL;
// get current sector // get current sector
diri->current_block = csi_get_block(&(diri->csi), diri->tid); 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 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; if (check_diri_magic(diri, "diri_free")) return EINVAL;
@@ -284,17 +328,22 @@ int diri_free(struct diri *diri)
return 0; 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 (check_diri_magic(diri, "diri_current_entry")) return NULL;
if (diri->current_block == NULL) if (diri->current_block == NULL)
return 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; if (check_diri_magic(diri, "diri_next_entry")) return NULL;
@@ -310,12 +359,16 @@ uint8 *diri_next_entry(struct diri *diri)
return 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_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_index > (diri->csi.vol->bytes_per_sector / 0x20 - 1)) {
if (diri->current_block) if (diri->current_block)
@@ -328,7 +381,9 @@ uint8 *diri_rewind(struct diri *diri)
return diri->current_block; 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); csi_mark_block_dirty(&(diri->csi), diri->tid);
} }