/trunk/uspace/srv/fs/fat/fat.h |
---|
33,6 → 33,7 |
#ifndef FAT_FAT_H_ |
#define FAT_FAT_H_ |
#include "fat_fat.h" |
#include <ipc/ipc.h> |
#include <libfs.h> |
#include <atomic.h> |
44,6 → 45,11 |
#define dprintf(...) printf(__VA_ARGS__) |
#endif |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
#define BS_BLOCK 0 |
#define BS_SIZE 512 |
typedef struct { |
uint8_t ji[3]; /**< Jump instruction. */ |
uint8_t oem_name[8]; |
115,7 → 121,7 |
}; |
} __attribute__ ((packed)) fat_bs_t; |
typedef uint16_t fat_cluster_t; |
#define FAT_BS(b) ((fat_bs_t *)((b)->data)) |
typedef enum { |
FAT_INVALID, |
191,6 → 197,16 |
bool dirty; |
} fat_node_t; |
/* TODO move somewhere else */ |
typedef struct block { |
void *data; |
size_t size; |
bool dirty; |
} block_t; |
extern block_t *block_get(dev_handle_t, off_t, size_t); |
extern void block_put(block_t *); |
extern fs_reg_t fat_reg; |
extern void fat_mounted(ipc_callid_t, ipc_call_t *); |
/trunk/uspace/srv/fs/fat/fat_fat.c |
---|
35,7 → 35,265 |
* @brief Functions that manipulate the file allocation tables. |
*/ |
#include "fat_fat.h" |
#include "fat_dentry.h" |
#include "fat.h" |
#include "../../vfs/vfs.h" |
#include <libfs.h> |
#include <errno.h> |
#include <byteorder.h> |
#include <align.h> |
#include <assert.h> |
block_t * |
_fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset) |
{ |
block_t *bb; |
block_t *b; |
unsigned bps; |
unsigned spc; |
unsigned rscnt; /* block address of the first FAT */ |
unsigned fatcnt; |
unsigned rde; |
unsigned rds; /* root directory size */ |
unsigned sf; |
unsigned ssa; /* size of the system area */ |
unsigned clusters; |
fat_cluster_t clst = firstc; |
unsigned i; |
bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
spc = FAT_BS(bb)->spc; |
rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
fatcnt = FAT_BS(bb)->fatcnt; |
rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max); |
sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat); |
block_put(bb); |
rds = (sizeof(fat_dentry_t) * rde) / bps; |
rds += ((sizeof(fat_dentry_t) * rde) % bps != 0); |
ssa = rscnt + fatcnt * sf + rds; |
if (firstc == FAT_CLST_ROOT) { |
/* root directory special case */ |
assert(offset < rds); |
b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps); |
return b; |
} |
clusters = offset / spc; |
for (i = 0; i < clusters; i++) { |
unsigned fsec; /* sector offset relative to FAT1 */ |
unsigned fidx; /* FAT1 entry index */ |
assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD); |
fsec = (clst * sizeof(fat_cluster_t)) / bps; |
fidx = clst % (bps / sizeof(fat_cluster_t)); |
/* read FAT1 */ |
b = block_get(dev_handle, rscnt + fsec, bps); |
clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
assert(clst != FAT_CLST_BAD); |
assert(clst < FAT_CLST_LAST1); |
block_put(b); |
} |
b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc + |
offset % spc, bps); |
return b; |
} |
/** Return number of blocks allocated to a file. |
* |
* @param dev_handle Device handle of the device with the file. |
* @param firstc First cluster of the file. |
* |
* @return Number of blocks allocated to the file. |
*/ |
uint16_t |
_fat_blcks_get(dev_handle_t dev_handle, fat_cluster_t firstc) |
{ |
block_t *bb; |
block_t *b; |
unsigned bps; |
unsigned spc; |
unsigned rscnt; /* block address of the first FAT */ |
unsigned clusters = 0; |
fat_cluster_t clst = firstc; |
bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
spc = FAT_BS(bb)->spc; |
rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
block_put(bb); |
if (firstc == FAT_CLST_RES0) { |
/* No space allocated to the file. */ |
return 0; |
} |
while (clst < FAT_CLST_LAST1) { |
unsigned fsec; /* sector offset relative to FAT1 */ |
unsigned fidx; /* FAT1 entry index */ |
assert(clst >= FAT_CLST_FIRST); |
fsec = (clst * sizeof(fat_cluster_t)) / bps; |
fidx = clst % (bps / sizeof(fat_cluster_t)); |
/* read FAT1 */ |
b = block_get(dev_handle, rscnt + fsec, bps); |
clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
assert(clst != FAT_CLST_BAD); |
block_put(b); |
clusters++; |
} |
return clusters * spc; |
} |
uint16_t fat_bps_get(dev_handle_t dev_handle) |
{ |
block_t *bb; |
uint16_t bps; |
bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
assert(bb != NULL); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
block_put(bb); |
return bps; |
} |
/** Fill the gap between EOF and a new file position. |
* |
* @param nodep FAT node with the gap. |
* @param mcl First cluster in an independent cluster chain that will |
* be later appended to the end of the node's own cluster |
* chain. If pos is still in the last allocated cluster, |
* this argument is ignored. |
* @param pos Position in the last node block. |
*/ |
void fat_fill_gap(fat_node_t *nodep, fat_cluster_t mcl, off_t pos) |
{ |
uint16_t bps; |
unsigned spc; |
block_t *bb, *b; |
off_t o, boundary; |
bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
spc = FAT_BS(bb)->spc; |
block_put(bb); |
boundary = ROUND_UP(nodep->size, bps * spc); |
/* zero out already allocated space */ |
for (o = nodep->size - 1; o < pos && o < boundary; |
o = ALIGN_DOWN(o + bps, bps)) { |
b = fat_block_get(nodep, o / bps); |
memset(b->data + o % bps, 0, bps - o % bps); |
b->dirty = true; /* need to sync node */ |
block_put(b); |
} |
if (o >= pos) |
return; |
/* zero out the initial part of the new cluster chain */ |
for (o = boundary; o < pos; o += bps) { |
b = _fat_block_get(nodep->idx->dev_handle, mcl, |
(o - boundary) / bps); |
memset(b->data, 0, min(bps, pos - o)); |
b->dirty = true; /* need to sync node */ |
block_put(b); |
} |
} |
void |
fat_mark_cluster(dev_handle_t dev_handle, unsigned fatno, fat_cluster_t clst, |
fat_cluster_t value) |
{ |
/* TODO */ |
} |
void |
fat_alloc_shadow_clusters(dev_handle_t dev_handle, fat_cluster_t *lifo, |
unsigned nclsts) |
{ |
/* TODO */ |
} |
int |
fat_alloc_clusters(dev_handle_t dev_handle, unsigned nclsts, fat_cluster_t *mcl, |
fat_cluster_t *lcl) |
{ |
uint16_t bps; |
uint16_t rscnt; |
uint16_t sf; |
block_t *bb, *blk; |
fat_cluster_t *lifo; /* stack for storing free cluster numbers */ |
unsigned found = 0; /* top of the free cluster number stack */ |
unsigned b, c, cl; |
lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t)); |
if (lifo) |
return ENOMEM; |
bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat); |
block_put(bb); |
/* |
* Search FAT1 for unused clusters. |
*/ |
for (b = 0, cl = 0; b < sf; blk++) { |
blk = block_get(dev_handle, rscnt + b, bps); |
for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) { |
fat_cluster_t *clst = (fat_cluster_t *)blk->data + c; |
if (*clst == FAT_CLST_RES0) { |
/* |
* The cluster is free. Put it into our stack |
* of found clusters and mark it as non-free. |
*/ |
lifo[found] = cl; |
if (found == 0) |
*clst = FAT_CLST_LAST1; |
else |
*clst = lifo[found - 1]; |
blk->dirty = true; /* need to sync block */ |
if (++found == nclsts) { |
/* we are almost done */ |
block_put(blk); |
/* update the shadow copies of FAT */ |
fat_alloc_shadow_clusters(dev_handle, |
lifo, nclsts); |
*mcl = lifo[found - 1]; |
*lcl = lifo[0]; |
free(lifo); |
return EOK; |
} |
} |
} |
block_put(blk); |
} |
/* |
* We could not find enough clusters. Now we need to free the clusters |
* we have allocated so far. |
*/ |
while (found--) |
fat_mark_cluster(dev_handle, FAT1, lifo[found], FAT_CLST_RES0); |
free(lifo); |
return ENOSPC; |
} |
void fat_append_clusters(fat_node_t *nodep, fat_cluster_t mcl) |
{ |
} |
/** |
* @} |
*/ |
/trunk/uspace/srv/fs/fat/fat_fat.h |
---|
33,6 → 33,45 |
#ifndef FAT_FAT_FAT_H_ |
#define FAT_FAT_FAT_H_ |
#include "../../vfs/vfs.h" |
#include <stdint.h> |
#define FAT1 0 |
#define FAT_CLST_RES0 0x0000 |
#define FAT_CLST_RES1 0x0001 |
#define FAT_CLST_FIRST 0x0002 |
#define FAT_CLST_BAD 0xfff7 |
#define FAT_CLST_LAST1 0xfff8 |
#define FAT_CLST_LAST8 0xffff |
/* internally used to mark root directory's parent */ |
#define FAT_CLST_ROOTPAR FAT_CLST_RES0 |
/* internally used to mark root directory */ |
#define FAT_CLST_ROOT FAT_CLST_RES1 |
/* forward declarations */ |
struct block; |
struct fat_node; |
typedef uint16_t fat_cluster_t; |
#define fat_block_get(np, off) \ |
_fat_block_get((np)->idx->dev_handle, (np)->firstc, (off)) |
extern struct block *_fat_block_get(dev_handle_t, fat_cluster_t, off_t); |
extern uint16_t _fat_blcks_get(dev_handle_t, fat_cluster_t); |
extern uint16_t fat_bps_get(dev_handle_t); |
extern void fat_append_clusters(struct fat_node *, fat_cluster_t); |
extern int fat_alloc_clusters(dev_handle_t, unsigned, fat_cluster_t *, |
fat_cluster_t *); |
extern void fat_alloc_shadow_clusters(dev_handle_t, fat_cluster_t *, unsigned); |
extern void fat_mark_cluster(dev_handle_t, unsigned, fat_cluster_t, |
fat_cluster_t); |
extern void fat_fill_gap(struct fat_node *, fat_cluster_t, off_t); |
#endif |
/** |
/trunk/uspace/srv/fs/fat/fat_ops.c |
---|
54,9 → 54,6 |
#include <sys/mman.h> |
#include <align.h> |
#define BS_BLOCK 0 |
#define BS_SIZE 512 |
/** Futex protecting the list of cached free FAT nodes. */ |
static futex_t ffn_futex = FUTEX_INITIALIZER; |
63,19 → 60,10 |
/** List of cached free FAT nodes. */ |
static LIST_INITIALIZE(ffn_head); |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
static int dev_phone = -1; /* FIXME */ |
static void *dev_buffer = NULL; /* FIXME */ |
/* TODO move somewhere else */ |
typedef struct { |
void *data; |
size_t size; |
bool dirty; |
} block_t; |
static block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs) |
block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs) |
{ |
/* FIXME */ |
block_t *b; |
107,7 → 95,7 |
return b; |
} |
static void block_put(block_t *block) |
void block_put(block_t *block) |
{ |
/* FIXME */ |
free(block->data); |
114,131 → 102,6 |
free(block); |
} |
#define FAT1 0 |
#define FAT_BS(b) ((fat_bs_t *)((b)->data)) |
#define FAT_CLST_RES0 0x0000 |
#define FAT_CLST_RES1 0x0001 |
#define FAT_CLST_FIRST 0x0002 |
#define FAT_CLST_BAD 0xfff7 |
#define FAT_CLST_LAST1 0xfff8 |
#define FAT_CLST_LAST8 0xffff |
/* internally used to mark root directory's parent */ |
#define FAT_CLST_ROOTPAR FAT_CLST_RES0 |
/* internally used to mark root directory */ |
#define FAT_CLST_ROOT FAT_CLST_RES1 |
#define fat_block_get(np, off) \ |
_fat_block_get((np)->idx->dev_handle, (np)->firstc, (off)) |
static block_t * |
_fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset) |
{ |
block_t *bb; |
block_t *b; |
unsigned bps; |
unsigned spc; |
unsigned rscnt; /* block address of the first FAT */ |
unsigned fatcnt; |
unsigned rde; |
unsigned rds; /* root directory size */ |
unsigned sf; |
unsigned ssa; /* size of the system area */ |
unsigned clusters; |
fat_cluster_t clst = firstc; |
unsigned i; |
bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
spc = FAT_BS(bb)->spc; |
rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
fatcnt = FAT_BS(bb)->fatcnt; |
rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max); |
sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat); |
block_put(bb); |
rds = (sizeof(fat_dentry_t) * rde) / bps; |
rds += ((sizeof(fat_dentry_t) * rde) % bps != 0); |
ssa = rscnt + fatcnt * sf + rds; |
if (firstc == FAT_CLST_ROOT) { |
/* root directory special case */ |
assert(offset < rds); |
b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps); |
return b; |
} |
clusters = offset / spc; |
for (i = 0; i < clusters; i++) { |
unsigned fsec; /* sector offset relative to FAT1 */ |
unsigned fidx; /* FAT1 entry index */ |
assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD); |
fsec = (clst * sizeof(fat_cluster_t)) / bps; |
fidx = clst % (bps / sizeof(fat_cluster_t)); |
/* read FAT1 */ |
b = block_get(dev_handle, rscnt + fsec, bps); |
clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
assert(clst != FAT_CLST_BAD); |
assert(clst < FAT_CLST_LAST1); |
block_put(b); |
} |
b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc + |
offset % spc, bps); |
return b; |
} |
/** Return number of blocks allocated to a file. |
* |
* @param dev_handle Device handle of the device with the file. |
* @param firstc First cluster of the file. |
* |
* @return Number of blocks allocated to the file. |
*/ |
static uint16_t |
_fat_blcks_get(dev_handle_t dev_handle, fat_cluster_t firstc) |
{ |
block_t *bb; |
block_t *b; |
unsigned bps; |
unsigned spc; |
unsigned rscnt; /* block address of the first FAT */ |
unsigned clusters = 0; |
fat_cluster_t clst = firstc; |
bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
spc = FAT_BS(bb)->spc; |
rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
block_put(bb); |
if (firstc == FAT_CLST_RES0) { |
/* No space allocated to the file. */ |
return 0; |
} |
while (clst < FAT_CLST_LAST1) { |
unsigned fsec; /* sector offset relative to FAT1 */ |
unsigned fidx; /* FAT1 entry index */ |
assert(clst >= FAT_CLST_FIRST); |
fsec = (clst * sizeof(fat_cluster_t)) / bps; |
fidx = clst % (bps / sizeof(fat_cluster_t)); |
/* read FAT1 */ |
b = block_get(dev_handle, rscnt + fsec, bps); |
clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
assert(clst != FAT_CLST_BAD); |
block_put(b); |
clusters++; |
} |
return clusters * spc; |
} |
static void fat_node_initialize(fat_node_t *node) |
{ |
futex_initialize(&node->lock, 1); |
251,19 → 114,6 |
node->dirty = false; |
} |
static uint16_t fat_bps_get(dev_handle_t dev_handle) |
{ |
block_t *bb; |
uint16_t bps; |
bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
assert(bb != NULL); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
block_put(bb); |
return bps; |
} |
static void fat_node_sync(fat_node_t *node) |
{ |
/* TODO */ |
786,138 → 636,6 |
ipc_answer_1(rid, EOK, (ipcarg_t)bytes); |
} |
/** Fill the gap between EOF and a new file position. |
* |
* @param nodep FAT node with the gap. |
* @param mcl First cluster in an independent cluster chain that will |
* be later appended to the end of the node's own cluster |
* chain. If pos is still in the last allocated cluster, |
* this argument is ignored. |
* @param pos Position in the last node block. |
*/ |
static void |
fat_fill_gap(fat_node_t *nodep, fat_cluster_t mcl, off_t pos) |
{ |
uint16_t bps; |
unsigned spc; |
block_t *bb, *b; |
off_t o, boundary; |
bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
spc = FAT_BS(bb)->spc; |
block_put(bb); |
boundary = ROUND_UP(nodep->size, bps * spc); |
/* zero out already allocated space */ |
for (o = nodep->size - 1; o < pos && o < boundary; |
o = ALIGN_DOWN(o + bps, bps)) { |
b = fat_block_get(nodep, o / bps); |
memset(b->data + o % bps, 0, bps - o % bps); |
b->dirty = true; /* need to sync node */ |
block_put(b); |
} |
if (o >= pos) |
return; |
/* zero out the initial part of the new cluster chain */ |
for (o = boundary; o < pos; o += bps) { |
b = _fat_block_get(nodep->idx->dev_handle, mcl, |
(o - boundary) / bps); |
memset(b->data, 0, min(bps, pos - o)); |
b->dirty = true; /* need to sync node */ |
block_put(b); |
} |
} |
static void |
fat_mark_cluster(dev_handle_t dev_handle, unsigned fatno, fat_cluster_t clst, |
fat_cluster_t value) |
{ |
/* TODO */ |
} |
static void |
fat_alloc_shadow_clusters(dev_handle_t dev_handle, fat_cluster_t *lifo, |
unsigned nclsts) |
{ |
/* TODO */ |
} |
static int |
fat_alloc_clusters(dev_handle_t dev_handle, unsigned nclsts, fat_cluster_t *mcl, |
fat_cluster_t *lcl) |
{ |
uint16_t bps; |
uint16_t rscnt; |
uint16_t sf; |
block_t *bb, *blk; |
fat_cluster_t *lifo; /* stack for storing free cluster numbers */ |
unsigned found = 0; /* top of the free cluster number stack */ |
unsigned b, c, cl; |
lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t)); |
if (lifo) |
return ENOMEM; |
bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
bps = uint16_t_le2host(FAT_BS(bb)->bps); |
rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat); |
block_put(bb); |
/* |
* Search FAT1 for unused clusters. |
*/ |
for (b = 0, cl = 0; b < sf; blk++) { |
blk = block_get(dev_handle, rscnt + b, bps); |
for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) { |
fat_cluster_t *clst = (fat_cluster_t *)blk->data + c; |
if (*clst == FAT_CLST_RES0) { |
/* |
* The cluster is free. Put it into our stack |
* of found clusters and mark it as non-free. |
*/ |
lifo[found] = cl; |
if (found == 0) |
*clst = FAT_CLST_LAST1; |
else |
*clst = lifo[found - 1]; |
blk->dirty = true; /* need to sync block */ |
if (++found == nclsts) { |
/* we are almost done */ |
block_put(blk); |
/* update the shadow copies of FAT */ |
fat_alloc_shadow_clusters(dev_handle, |
lifo, nclsts); |
*mcl = lifo[found - 1]; |
*lcl = lifo[0]; |
free(lifo); |
return EOK; |
} |
} |
} |
block_put(blk); |
} |
/* |
* We could not find enough clusters. Now we need to free the clusters |
* we have allocated so far. |
*/ |
while (found--) |
fat_mark_cluster(dev_handle, FAT1, lifo[found], FAT_CLST_RES0); |
free(lifo); |
return ENOSPC; |
} |
static void |
fat_append_clusters(fat_node_t *nodep, fat_cluster_t mcl) |
{ |
} |
void fat_write(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |