* 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.
This file may be used under the terms of the Be Sample Code License.
*/
#include <KernelExport.h>
#include <stdlib.h>
@@ -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;(i<required_entries)&&buffer;i++) {
const char *p = nlong + (required_entries - i - 1)*26; // go to unicode offset
for (i = 1; i < required_entries && buffer; i++) {
const char *p = nlong + (required_entries - i - 1) * 26;
// go to unicode offset
memset(buffer, 0, 0x20);
buffer[0] = required_entries - i + ((i == 1) ? 0x40 : 0);
buffer[0x0b] = 0x0f;
@@ -714,8 +774,10 @@ static status_t _create_dir_entry_(nspace *vol, vnode *dir, struct _entry_info_
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;
uint32 dummy;
@@ -731,32 +793,43 @@ status_t create_volume_label(nspace *vol, const char name[11], uint32 *index)
if (err != ENOENT)
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 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; i<len; i++) {
if(name[i] & 0x80) continue; //belongs to an utf8 char
if(strchr(illegal, name[i])) return false;
if((unsigned char)name[i] < 32) return false;
for (i = 0; i < len; i++) {
if (name[i] & 0x80)
continue; //belongs to an utf8 char
if (strchr(illegal, name[i]))
return false;
if ((unsigned char)name[i] < 32)
return false;
}
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;
int32 len;
@@ -765,11 +838,11 @@ status_t create_dir_entry(nspace *vol, vnode *dir, vnode *node,
struct _entry_info_ info;
// check name legality before doing anything
if(!is_filename_legal(name))
if (!is_filename_legal(name))
return EINVAL;
// 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) {
DPRINTF(0, ("%s already found in directory %Lx\n", name, dir->vnid));
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;
}
+88 -33
View File
@@ -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 <KernelExport.h>
#include <fs_cache.h>
#include <fs_info.h>
#include <string.h>
#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; i<block+sectors; i++) {
for (i = block; i < block + sectors; i++) {
char *blockData = (char *)block_cache_get(csi->vol->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; 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);
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);
}