Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3598 → Rev 3674

/branches/dynload/uspace/srv/fs/tmpfs/tmpfs_dump.c
59,6 → 59,7
{
struct rdentry entry;
libfs_ops_t *ops = &tmpfs_libfs_ops;
int rc;
do {
char *fname;
93,7 → 94,8
}
fname[entry.len] = 0;
if (!ops->link((void *) parent, (void *) node, fname)) {
rc = ops->link((void *) parent, (void *) node, fname);
if (rc != EOK) {
ops->destroy((void *) node);
free(fname);
return false;
134,8 → 136,9
return false;
}
fname[entry.len] = 0;
if (!ops->link((void *) parent, (void *) node, fname)) {
 
rc = ops->link((void *) parent, (void *) node, fname);
if (rc != EOK) {
ops->destroy((void *) node);
free(fname);
return false;
/branches/dynload/uspace/srv/fs/tmpfs/tmpfs_ops.c
75,7 → 75,7
static void *tmpfs_node_get(dev_handle_t, fs_index_t);
static void tmpfs_node_put(void *);
static void *tmpfs_create_node(dev_handle_t, int);
static bool tmpfs_link_node(void *, void *, const char *);
static int tmpfs_link_node(void *, void *, const char *);
static int tmpfs_unlink_node(void *, void *);
static int tmpfs_destroy_node(void *);
 
308,7 → 308,7
return (void *) node;
}
 
bool tmpfs_link_node(void *prnt, void *chld, const char *nm)
int tmpfs_link_node(void *prnt, void *chld, const char *nm)
{
tmpfs_dentry_t *parentp = (tmpfs_dentry_t *) prnt;
tmpfs_dentry_t *childp = (tmpfs_dentry_t *) chld;
317,13 → 317,13
 
tmpfs_name_t *namep = malloc(sizeof(tmpfs_name_t));
if (!namep)
return false;
return ENOMEM;
tmpfs_name_initialize(namep);
size_t len = strlen(nm);
namep->name = malloc(len + 1);
if (!namep->name) {
free(namep);
return false;
return ENOMEM;
}
strcpy(namep->name, nm);
namep->parent = parentp;
343,7 → 343,7
parentp->child = childp;
}
 
return true;
return EOK;
}
 
int tmpfs_unlink_node(void *prnt, void *chld)
/branches/dynload/uspace/srv/fs/fat/fat_idx.c
214,7 → 214,7
};
 
/** Allocate a VFS index which is not currently in use. */
static bool fat_idx_alloc(dev_handle_t dev_handle, fs_index_t *index)
static bool fat_index_alloc(dev_handle_t dev_handle, fs_index_t *index)
{
unused_t *u;
276,7 → 276,7
}
 
/** Free a VFS index, which is no longer in use. */
static void fat_idx_free(dev_handle_t dev_handle, fs_index_t index)
static void fat_index_free(dev_handle_t dev_handle, fs_index_t index)
{
unused_t *u;
 
338,7 → 338,7
futex_up(&unused_futex);
}
 
static fat_idx_t *fat_idx_get_new_core(dev_handle_t dev_handle)
static fat_idx_t *fat_idx_create(dev_handle_t dev_handle)
{
fat_idx_t *fidx;
 
345,7 → 345,7
fidx = (fat_idx_t *) malloc(sizeof(fat_idx_t));
if (!fidx)
return NULL;
if (!fat_idx_alloc(dev_handle, &fidx->index)) {
if (!fat_index_alloc(dev_handle, &fidx->index)) {
free(fidx);
return NULL;
}
366,7 → 366,7
fat_idx_t *fidx;
 
futex_down(&used_futex);
fidx = fat_idx_get_new_core(dev_handle);
fidx = fat_idx_create(dev_handle);
if (!fidx) {
futex_up(&used_futex);
return NULL;
400,7 → 400,7
if (l) {
fidx = hash_table_get_instance(l, fat_idx_t, uph_link);
} else {
fidx = fat_idx_get_new_core(dev_handle);
fidx = fat_idx_create(dev_handle);
if (!fidx) {
futex_up(&used_futex);
return NULL;
423,6 → 423,32
return fidx;
}
 
void fat_idx_hashin(fat_idx_t *idx)
{
unsigned long pkey[] = {
[UPH_DH_KEY] = idx->dev_handle,
[UPH_PFC_KEY] = idx->pfc,
[UPH_PDI_KEY] = idx->pdi,
};
 
futex_down(&used_futex);
hash_table_insert(&up_hash, pkey, &idx->uph_link);
futex_up(&used_futex);
}
 
void fat_idx_hashout(fat_idx_t *idx)
{
unsigned long pkey[] = {
[UPH_DH_KEY] = idx->dev_handle,
[UPH_PFC_KEY] = idx->pfc,
[UPH_PDI_KEY] = idx->pdi,
};
 
futex_down(&used_futex);
hash_table_remove(&up_hash, pkey, 3);
futex_up(&used_futex);
}
 
fat_idx_t *
fat_idx_get_by_index(dev_handle_t dev_handle, fs_index_t index)
{
444,6 → 470,33
return fidx;
}
 
/** Destroy the index structure.
*
* @param idx The index structure to be destroyed.
*/
void fat_idx_destroy(fat_idx_t *idx)
{
unsigned long ikey[] = {
[UIH_DH_KEY] = idx->dev_handle,
[UIH_INDEX_KEY] = idx->index,
};
 
assert(idx->pfc == FAT_CLST_RES0);
 
futex_down(&used_futex);
/*
* Since we can only free unlinked nodes, the index structure is not
* present in the position hash (uph). We therefore hash it out from
* the index hash only.
*/
hash_table_remove(&ui_hash, ikey, 2);
futex_up(&used_futex);
/* Release the VFS index. */
fat_index_free(idx->dev_handle, idx->index);
/* Deallocate the structure. */
free(idx);
}
 
int fat_idx_init(void)
{
if (!hash_table_create(&up_hash, UPH_BUCKETS, 3, &uph_ops))
/branches/dynload/uspace/srv/fs/fat/fat.h
203,9 → 203,14
extern void fat_read(ipc_callid_t, ipc_call_t *);
extern void fat_write(ipc_callid_t, ipc_call_t *);
extern void fat_truncate(ipc_callid_t, ipc_call_t *);
extern void fat_destroy(ipc_callid_t, ipc_call_t *);
 
extern fat_idx_t *fat_idx_get_new(dev_handle_t);
extern fat_idx_t *fat_idx_get_by_pos(dev_handle_t, fat_cluster_t, unsigned);
extern fat_idx_t *fat_idx_get_by_index(dev_handle_t, fs_index_t);
extern void fat_idx_destroy(fat_idx_t *);
extern void fat_idx_hashin(fat_idx_t *);
extern void fat_idx_hashout(fat_idx_t *);
 
extern int fat_idx_init(void);
extern void fat_idx_fini(void);
/branches/dynload/uspace/srv/fs/fat/fat_dentry.c
36,16 → 36,81
*/
 
#include "fat_dentry.h"
#include <ctype.h>
#include <string.h>
 
#define FAT_PAD ' '
static bool is_d_char(const char ch)
{
if (isalnum(ch) || ch == '_')
return true;
else
return false;
}
 
#define FAT_DENTRY_UNUSED 0x00
#define FAT_DENTRY_E5_ESC 0x05
#define FAT_DENTRY_DOT 0x2e
#define FAT_DENTRY_ERASED 0xe5
/** Compare path component with the name read from the dentry.
*
* This function compares the path component with the name read from the dentry.
* The comparison is case insensitive and tolerates a mismatch on the trailing
* dot character at the end of the name (i.e. when there is a dot, but no
* extension).
*
* @param name Node name read from the dentry.
* @param component Path component.
*
* @return Zero on match, non-zero otherwise.
*/
int fat_dentry_namecmp(char *name, const char *component)
{
int rc;
if (!(rc = stricmp(name, component)))
return rc;
if (!strchr(name, '.')) {
/*
* There is no '.' in the name, so we know that there is enough
* space for appending an extra '.' to name.
*/
name[strlen(name)] = '.';
name[strlen(name) + 1] = '\0';
rc = stricmp(name, component);
}
return rc;
}
 
void dentry_name_canonify(fat_dentry_t *d, char *buf)
bool fat_dentry_name_verify(const char *name)
{
unsigned i, dot;
bool dot_found = false;
 
for (i = 0; name[i]; i++) {
if (name[i] == '.') {
if (dot_found) {
return false;
} else {
dot_found = true;
dot = i;
}
} else {
if (!is_d_char(name[i]))
return false;
}
}
 
if (dot_found) {
if (dot > FAT_NAME_LEN)
return false;
if (i - dot > FAT_EXT_LEN + 1)
return false;
} else {
if (i > FAT_NAME_LEN)
return false;
}
 
return true;
}
 
void fat_dentry_name_get(const fat_dentry_t *d, char *buf)
{
int i;
 
for (i = 0; i < FAT_NAME_LEN; i++) {
71,8 → 136,47
*buf = '\0';
}
 
fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
void fat_dentry_name_set(fat_dentry_t *d, const char *name)
{
int i;
const char fake_ext[] = " ";
 
 
for (i = 0; i < FAT_NAME_LEN; i++) {
switch ((uint8_t) *name) {
case 0xe5:
d->name[i] = FAT_DENTRY_E5_ESC;
name++;
break;
case '\0':
case '.':
d->name[i] = FAT_PAD;
break;
default:
d->name[i] = toupper(*name++);
break;
}
}
if (*name++ != '.')
name = fake_ext;
for (i = 0; i < FAT_EXT_LEN; i++) {
switch ((uint8_t) *name) {
case 0xe5:
d->ext[i] = FAT_DENTRY_E5_ESC;
name++;
break;
case '\0':
d->ext[i] = FAT_PAD;
break;
default:
d->ext[i] = toupper(*name++);
break;
}
}
}
 
fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *d)
{
if (d->attr & FAT_ATTR_VOLLABEL) {
/* volume label entry */
return FAT_DENTRY_SKIP;
79,7 → 183,7
}
if (d->name[0] == FAT_DENTRY_ERASED) {
/* not-currently-used entry */
return FAT_DENTRY_SKIP;
return FAT_DENTRY_FREE;
}
if (d->name[0] == FAT_DENTRY_UNUSED) {
/* never used entry */
/branches/dynload/uspace/srv/fs/fat/fat_dentry.h
34,17 → 34,30
#define FAT_FAT_DENTRY_H_
 
#include <stdint.h>
#include <bool.h>
 
#define FAT_NAME_LEN 8
#define FAT_EXT_LEN 3
 
#define FAT_NAME_DOT ". "
#define FAT_NAME_DOT_DOT ".. "
#define FAT_EXT_PAD " "
 
#define FAT_ATTR_RDONLY (1 << 0)
#define FAT_ATTR_VOLLABEL (1 << 3)
#define FAT_ATTR_SUBDIR (1 << 4)
 
#define FAT_PAD ' '
 
#define FAT_DENTRY_UNUSED 0x00
#define FAT_DENTRY_E5_ESC 0x05
#define FAT_DENTRY_DOT 0x2e
#define FAT_DENTRY_ERASED 0xe5
 
typedef enum {
FAT_DENTRY_SKIP,
FAT_DENTRY_LAST,
FAT_DENTRY_FREE,
FAT_DENTRY_VALID
} fat_dentry_clsf_t;
 
70,8 → 83,11
uint32_t size;
} __attribute__ ((packed)) fat_dentry_t;
 
extern void dentry_name_canonify(fat_dentry_t *, char *);
extern fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *);
extern int fat_dentry_namecmp(char *, const char *);
extern bool fat_dentry_name_verify(const char *);
extern void fat_dentry_name_get(const fat_dentry_t *, char *);
extern void fat_dentry_name_set(fat_dentry_t *, const char *);
extern fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *);
 
#endif
 
/branches/dynload/uspace/srv/fs/fat/fat_fat.c
182,7 → 182,7
boundary = ROUND_UP(nodep->size, bps * spc);
 
/* zero out already allocated space */
for (o = nodep->size - 1; o < pos && o < boundary;
for (o = nodep->size; o < pos && o < boundary;
o = ALIGN_DOWN(o + bps, bps)) {
int flags = (o % bps == 0) ?
BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE;
285,10 → 285,10
}
}
 
/** Allocate clusters in FAT1.
/** Allocate clusters in all copies of FAT.
*
* This function will attempt to allocate the requested number of clusters in
* the first FAT instance. The FAT will be altered so that the allocated
* all instances of the FAT. The FAT will be altered so that the allocated
* clusters form an independent chain (i.e. a chain which does not belong to any
* file yet).
*
315,7 → 315,7
unsigned b, c, cl;
 
lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
if (lifo)
if (!lifo)
return ENOMEM;
bps = uint16_t_le2host(bs->bps);
326,8 → 326,8
* Search FAT1 for unused clusters.
*/
futex_down(&fat_alloc_lock);
for (b = 0, cl = 0; b < sf; blk++) {
blk = block_get(dev_handle, rscnt + b, BLOCK_FLAGS_NOREAD);
for (b = 0, cl = 0; b < sf; b++) {
blk = block_get(dev_handle, rscnt + b, BLOCK_FLAGS_NONE);
for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) {
fat_cluster_t *clst = (fat_cluster_t *)blk->data + c;
if (uint16_t_le2host(*clst) == FAT_CLST_RES0) {
385,8 → 385,8
 
/* Mark all clusters in the chain as free in all copies of FAT. */
while (firstc < FAT_CLST_LAST1) {
assert(firstc >= FAT_CLST_FIRST && firstc < FAT_CLST_BAD);
nextc = fat_get_cluster(bs, dev_handle, firstc);
assert(nextc >= FAT_CLST_FIRST && nextc < FAT_CLST_BAD);
for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
fat_set_cluster(bs, dev_handle, fatno, firstc,
FAT_CLST_RES0);
409,7 → 409,7
if (fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl,
(uint16_t) -1) == 0) {
/* No clusters allocated to the node yet. */
nodep->firstc = host2uint16_t_le(mcl);
nodep->firstc = mcl;
nodep->dirty = true; /* need to sync node */
return;
}
/branches/dynload/uspace/srv/fs/fat/fat.c
116,6 → 116,9
case VFS_TRUNCATE:
fat_truncate(callid, &call);
break;
case VFS_DESTROY:
fat_destroy(callid, &call);
break;
default:
ipc_answer_0(callid, ENOTSUP);
break;
/branches/dynload/uspace/srv/fs/fat/fat_ops.c
94,10 → 94,14
d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
 
d->firstc = host2uint16_t_le(node->firstc);
if (node->type == FAT_FILE)
if (node->type == FAT_FILE) {
d->size = host2uint32_t_le(node->size);
/* TODO: update other fields? (e.g time fields, attr field) */
} else if (node->type == FAT_DIRECTORY) {
d->attr = FAT_ATTR_SUBDIR;
}
/* TODO: update other fields? (e.g time fields) */
b->dirty = true; /* need to sync block */
block_put(b);
}
216,8 → 220,31
return nodep;
}
 
/*
* Forward declarations of FAT libfs operations.
*/
static void *fat_node_get(dev_handle_t, fs_index_t);
static void fat_node_put(void *);
static void *fat_create_node(dev_handle_t, int);
static int fat_destroy_node(void *);
static int fat_link(void *, void *, const char *);
static int fat_unlink(void *, void *);
static void *fat_match(void *, const char *);
static fs_index_t fat_index_get(void *);
static size_t fat_size_get(void *);
static unsigned fat_lnkcnt_get(void *);
static bool fat_has_children(void *);
static void *fat_root_get(dev_handle_t);
static char fat_plb_get_char(unsigned);
static bool fat_is_directory(void *);
static bool fat_is_file(void *node);
 
/*
* FAT libfs operations.
*/
 
/** Instantiate a FAT in-core node. */
static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
{
void *node;
fat_idx_t *idxp;
231,40 → 258,297
return node;
}
 
static void fat_node_put(void *node)
void fat_node_put(void *node)
{
fat_node_t *nodep = (fat_node_t *)node;
bool destroy = false;
 
futex_down(&nodep->lock);
if (!--nodep->refcnt) {
futex_down(&ffn_futex);
list_append(&nodep->ffn_link, &ffn_head);
futex_up(&ffn_futex);
if (nodep->idx) {
futex_down(&ffn_futex);
list_append(&nodep->ffn_link, &ffn_head);
futex_up(&ffn_futex);
} else {
/*
* The node does not have any index structure associated
* with itself. This can only mean that we are releasing
* the node after a failed attempt to allocate the index
* structure for it.
*/
destroy = true;
}
}
futex_up(&nodep->lock);
if (destroy)
free(node);
}
 
static void *fat_create(dev_handle_t dev_handle, int flags)
void *fat_create_node(dev_handle_t dev_handle, int flags)
{
return NULL; /* not supported at the moment */
fat_idx_t *idxp;
fat_node_t *nodep;
fat_bs_t *bs;
fat_cluster_t mcl, lcl;
uint16_t bps;
int rc;
 
bs = block_bb_get(dev_handle);
bps = uint16_t_le2host(bs->bps);
if (flags & L_DIRECTORY) {
/* allocate a cluster */
rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
if (rc != EOK)
return NULL;
}
 
nodep = fat_node_get_new();
if (!nodep) {
fat_free_clusters(bs, dev_handle, mcl);
return NULL;
}
idxp = fat_idx_get_new(dev_handle);
if (!idxp) {
fat_free_clusters(bs, dev_handle, mcl);
fat_node_put(nodep);
return NULL;
}
/* idxp->lock held */
if (flags & L_DIRECTORY) {
int i;
block_t *b;
 
/*
* Populate the new cluster with unused dentries.
*/
for (i = 0; i < bs->spc; i++) {
b = _fat_block_get(bs, dev_handle, mcl, i,
BLOCK_FLAGS_NOREAD);
/* mark all dentries as never-used */
memset(b->data, 0, bps);
b->dirty = false;
block_put(b);
}
nodep->type = FAT_DIRECTORY;
nodep->firstc = mcl;
nodep->size = bps * bs->spc;
} else {
nodep->type = FAT_FILE;
nodep->firstc = FAT_CLST_RES0;
nodep->size = 0;
}
nodep->lnkcnt = 0; /* not linked anywhere */
nodep->refcnt = 1;
nodep->dirty = true;
 
nodep->idx = idxp;
idxp->nodep = nodep;
 
futex_up(&idxp->lock);
return nodep;
}
 
static int fat_destroy(void *node)
int fat_destroy_node(void *node)
{
return ENOTSUP; /* not supported at the moment */
fat_node_t *nodep = (fat_node_t *)node;
fat_bs_t *bs;
 
/*
* The node is not reachable from the file system. This means that the
* link count should be zero and that the index structure cannot be
* found in the position hash. Obviously, we don't need to lock the node
* nor its index structure.
*/
assert(nodep->lnkcnt == 0);
 
/*
* The node may not have any children.
*/
assert(fat_has_children(node) == false);
 
bs = block_bb_get(nodep->idx->dev_handle);
if (nodep->firstc != FAT_CLST_RES0) {
assert(nodep->size);
/* Free all clusters allocated to the node. */
fat_free_clusters(bs, nodep->idx->dev_handle, nodep->firstc);
}
 
fat_idx_destroy(nodep->idx);
free(nodep);
return EOK;
}
 
static bool fat_link(void *prnt, void *chld, const char *name)
int fat_link(void *prnt, void *chld, const char *name)
{
return false; /* not supported at the moment */
fat_node_t *parentp = (fat_node_t *)prnt;
fat_node_t *childp = (fat_node_t *)chld;
fat_dentry_t *d;
fat_bs_t *bs;
block_t *b;
int i, j;
uint16_t bps;
unsigned dps;
unsigned blocks;
 
futex_down(&childp->lock);
if (childp->lnkcnt == 1) {
/*
* On FAT, we don't support multiple hard links.
*/
futex_up(&childp->lock);
return EMLINK;
}
assert(childp->lnkcnt == 0);
futex_up(&childp->lock);
 
if (!fat_dentry_name_verify(name)) {
/*
* Attempt to create unsupported name.
*/
return ENOTSUP;
}
 
/*
* Get us an unused parent node's dentry or grow the parent and allocate
* a new one.
*/
futex_down(&parentp->idx->lock);
bs = block_bb_get(parentp->idx->dev_handle);
bps = uint16_t_le2host(bs->bps);
dps = bps / sizeof(fat_dentry_t);
 
blocks = parentp->size / bps;
 
for (i = 0; i < blocks; i++) {
b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
for (j = 0; j < dps; j++) {
d = ((fat_dentry_t *)b->data) + j;
switch (fat_classify_dentry(d)) {
case FAT_DENTRY_SKIP:
case FAT_DENTRY_VALID:
/* skipping used and meta entries */
continue;
case FAT_DENTRY_FREE:
case FAT_DENTRY_LAST:
/* found an empty slot */
goto hit;
}
}
block_put(b);
}
/*
* We need to grow the parent in order to create a new unused dentry.
*/
futex_up(&parentp->idx->lock);
return ENOTSUP; /* XXX */
 
hit:
/*
* At this point we only establish the link between the parent and the
* child. The dentry, except of the name and the extension, will remain
* uninitialized until the the corresponding node is synced. Thus the
* valid dentry data is kept in the child node structure.
*/
memset(d, 0, sizeof(fat_dentry_t));
fat_dentry_name_set(d, name);
b->dirty = true; /* need to sync block */
block_put(b);
futex_up(&parentp->idx->lock);
 
futex_down(&childp->idx->lock);
/*
* If possible, create the Sub-directory Identifier Entry and the
* Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
* are not mandatory according to Standard ECMA-107 and HelenOS VFS does
* not use them anyway, so this is rather a sign of our good will.
*/
b = fat_block_get(bs, childp, 0, BLOCK_FLAGS_NONE);
d = (fat_dentry_t *)b->data;
if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
strcmp(d->name, FAT_NAME_DOT) == 0) {
memset(d, 0, sizeof(fat_dentry_t));
strcpy(d->name, FAT_NAME_DOT);
strcpy(d->ext, FAT_EXT_PAD);
d->attr = FAT_ATTR_SUBDIR;
d->firstc = host2uint16_t_le(childp->firstc);
/* TODO: initialize also the date/time members. */
}
d++;
if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
strcmp(d->name, FAT_NAME_DOT_DOT) == 0) {
memset(d, 0, sizeof(fat_dentry_t));
strcpy(d->name, FAT_NAME_DOT_DOT);
strcpy(d->ext, FAT_EXT_PAD);
d->attr = FAT_ATTR_SUBDIR;
d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
host2uint16_t_le(FAT_CLST_RES0) :
host2uint16_t_le(parentp->firstc);
/* TODO: initialize also the date/time members. */
}
b->dirty = true; /* need to sync block */
block_put(b);
 
childp->idx->pfc = parentp->firstc;
childp->idx->pdi = i * dps + j;
futex_up(&childp->idx->lock);
 
futex_down(&childp->lock);
childp->lnkcnt = 1;
childp->dirty = true; /* need to sync node */
futex_up(&childp->lock);
 
/*
* Hash in the index structure into the position hash.
*/
fat_idx_hashin(childp->idx);
 
return EOK;
}
 
static int fat_unlink(void *prnt, void *chld)
int fat_unlink(void *prnt, void *chld)
{
return ENOTSUP; /* not supported at the moment */
fat_node_t *parentp = (fat_node_t *)prnt;
fat_node_t *childp = (fat_node_t *)chld;
fat_bs_t *bs;
fat_dentry_t *d;
uint16_t bps;
block_t *b;
 
futex_down(&parentp->lock);
futex_down(&childp->lock);
assert(childp->lnkcnt == 1);
futex_down(&childp->idx->lock);
bs = block_bb_get(childp->idx->dev_handle);
bps = uint16_t_le2host(bs->bps);
 
b = _fat_block_get(bs, childp->idx->dev_handle, childp->idx->pfc,
(childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
BLOCK_FLAGS_NONE);
d = (fat_dentry_t *)b->data +
(childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
/* mark the dentry as not-currently-used */
d->name[0] = FAT_DENTRY_ERASED;
b->dirty = true; /* need to sync block */
block_put(b);
 
/* remove the index structure from the position hash */
fat_idx_hashout(childp->idx);
/* clear position information */
childp->idx->pfc = FAT_CLST_RES0;
childp->idx->pdi = 0;
futex_up(&childp->idx->lock);
childp->lnkcnt = 0;
childp->dirty = true;
futex_up(&childp->lock);
futex_up(&parentp->lock);
 
return EOK;
}
 
static void *fat_match(void *prnt, const char *component)
void *fat_match(void *prnt, const char *component)
{
fat_bs_t *bs;
fat_node_t *parentp = (fat_node_t *)prnt;
287,6 → 571,7
d = ((fat_dentry_t *)b->data) + j;
switch (fat_classify_dentry(d)) {
case FAT_DENTRY_SKIP:
case FAT_DENTRY_FREE:
continue;
case FAT_DENTRY_LAST:
block_put(b);
294,10 → 579,10
return NULL;
default:
case FAT_DENTRY_VALID:
dentry_name_canonify(d, name);
fat_dentry_name_get(d, name);
break;
}
if (stricmp(name, component) == 0) {
if (fat_dentry_namecmp(name, component) == 0) {
/* hit */
void *node;
/*
331,7 → 616,7
return NULL;
}
 
static fs_index_t fat_index_get(void *node)
fs_index_t fat_index_get(void *node)
{
fat_node_t *fnodep = (fat_node_t *)node;
if (!fnodep)
339,17 → 624,17
return fnodep->idx->index;
}
 
static size_t fat_size_get(void *node)
size_t fat_size_get(void *node)
{
return ((fat_node_t *)node)->size;
}
 
static unsigned fat_lnkcnt_get(void *node)
unsigned fat_lnkcnt_get(void *node)
{
return ((fat_node_t *)node)->lnkcnt;
}
 
static bool fat_has_children(void *node)
bool fat_has_children(void *node)
{
fat_bs_t *bs;
fat_node_t *nodep = (fat_node_t *)node;
377,6 → 662,7
d = ((fat_dentry_t *)b->data) + j;
switch (fat_classify_dentry(d)) {
case FAT_DENTRY_SKIP:
case FAT_DENTRY_FREE:
continue;
case FAT_DENTRY_LAST:
block_put(b);
399,22 → 685,22
return false;
}
 
static void *fat_root_get(dev_handle_t dev_handle)
void *fat_root_get(dev_handle_t dev_handle)
{
return fat_node_get(dev_handle, 0);
}
 
static char fat_plb_get_char(unsigned pos)
char fat_plb_get_char(unsigned pos)
{
return fat_reg.plb_ro[pos % PLB_SIZE];
}
 
static bool fat_is_directory(void *node)
bool fat_is_directory(void *node)
{
return ((fat_node_t *)node)->type == FAT_DIRECTORY;
}
 
static bool fat_is_file(void *node)
bool fat_is_file(void *node)
{
return ((fat_node_t *)node)->type == FAT_FILE;
}
424,8 → 710,8
.match = fat_match,
.node_get = fat_node_get,
.node_put = fat_node_put,
.create = fat_create,
.destroy = fat_destroy,
.create = fat_create_node,
.destroy = fat_destroy_node,
.link = fat_link,
.unlink = fat_unlink,
.index_get = fat_index_get,
438,6 → 724,10
.is_file = fat_is_file
};
 
/*
* VFS operations.
*/
 
void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
{
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
607,6 → 897,7
d = ((fat_dentry_t *)b->data) + o;
switch (fat_classify_dentry(d)) {
case FAT_DENTRY_SKIP:
case FAT_DENTRY_FREE:
continue;
case FAT_DENTRY_LAST:
block_put(b);
613,7 → 904,7
goto miss;
default:
case FAT_DENTRY_VALID:
dentry_name_canonify(d, name);
fat_dentry_name_get(d, name);
block_put(b);
goto hit;
}
799,6 → 1090,22
return;
}
 
void fat_destroy(ipc_callid_t rid, ipc_call_t *request)
{
dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
int rc;
 
fat_node_t *nodep = fat_node_get(dev_handle, index);
if (!nodep) {
ipc_answer_0(rid, ENOENT);
return;
}
 
rc = fat_destroy_node(nodep);
ipc_answer_0(rid, rc);
}
 
/**
* @}
*/