struct Fs_t *Fs; /* Filesystem that this fat file belongs to */
Stream_t *Buffer;
- int (*map)(struct File_t *this, off_t where, size_t *len, int mode,
+ int (*map)(struct File_t *this, uint32_t where, uint32_t *len, int mode,
mt_off_t *res);
- size_t FileSize;
+ uint32_t FileSize;
- size_t preallocatedSize;
- int preallocatedClusters;
+ /* How many bytes do we project to need for this file
+ (includes those already in FileSize) */
+ uint32_t preallocatedSize;
+
+ /* How many clusters we have asked the lower layer to reserve
+ for us (only what we will need in the future, excluding already
+ allocated clusters in FileSize) */
+ uint32_t preallocatedClusters;
/* Absolute position of first cluster of file */
unsigned int FirstAbsCluNr;
/* Relative position of previous cluster */
unsigned int PreviousRelCluNr;
direntry_t direntry;
- int hint;
+ size_t hint;
struct dirCache_t *dcp;
unsigned int loopDetectRel;
} File_t;
static Class_t FileClass;
-T_HashTable *filehash;
+static T_HashTable *filehash;
static File_t *getUnbufferedFile(Stream_t *Stream)
{
return &getUnbufferedFile(Stream)->direntry;
}
+/**
+ * Overflow-safe conversion of bytes to cluster
+ */
+static uint32_t filebytesToClusters(uint32_t bytes, uint32_t clus_size) {
+ uint32_t ret = bytes / clus_size;
+ if(bytes % clus_size)
+ ret++;
+ return ret;
+}
static int recalcPreallocSize(File_t *This)
{
- size_t currentClusters, neededClusters;
- int clus_size;
- int neededPrealloc;
+ uint32_t currentClusters, neededClusters;
+ unsigned int clus_size;
+ uint32_t neededPrealloc;
Fs_t *Fs = This->Fs;
- int r;
#if 0
if(This->FileSize & 0xc0000000) {
}
#endif
clus_size = Fs->cluster_size * Fs->sector_size;
-
- currentClusters = (This->FileSize + clus_size - 1) / clus_size;
- neededClusters = (This->preallocatedSize + clus_size - 1) / clus_size;
- neededPrealloc = neededClusters - currentClusters;
- if(neededPrealloc < 0)
+ currentClusters = filebytesToClusters(This->FileSize, clus_size);
+ neededClusters = filebytesToClusters(This->preallocatedSize, clus_size);
+ if(neededClusters < currentClusters)
neededPrealloc = 0;
- r = fsPreallocateClusters(Fs, neededPrealloc - This->preallocatedClusters);
- if(r)
- return r;
+ else
+ neededPrealloc = neededClusters - currentClusters;
+ if(neededPrealloc > This->preallocatedClusters) {
+ int r = fsPreallocateClusters(Fs, neededPrealloc-
+ This->preallocatedClusters);
+ if(r)
+ return r;
+ } else {
+ fsReleasePreallocateClusters(Fs, This->preallocatedClusters -
+ neededPrealloc);
+ }
This->preallocatedClusters = neededPrealloc;
return 0;
}
unsigned int rel, oldabs, oldrel;
blocks = 0;
-
+
oldabs = oldrel = rel = 0;
while (block <= This->last_fat && block != 1 && block) {
block = fatDecode(This, block);
rel++;
if(_loopDetect(&oldrel, rel, &oldabs, block) < 0)
- block = -1;
+ block = 1;
}
return blocks;
}
/* returns number of bytes in a directory. Represents a file size, and
* can hence be not bigger than 2^32
*/
-static size_t countBytes(Stream_t *Dir, unsigned int block)
+static uint32_t countBytes(Stream_t *Dir, unsigned int block)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
void printFat(Stream_t *Stream)
{
File_t *This = getUnbufferedFile(Stream);
- unsigned long n;
- int rel;
+ uint32_t n;
+ unsigned int rel;
unsigned long begin, end;
int first;
void printFatWithOffset(Stream_t *Stream, off_t offset) {
File_t *This = getUnbufferedFile(Stream);
- unsigned long n;
- int rel;
+ uint32_t n;
+ unsigned int rel;
off_t clusSize;
n = This->FirstAbsCluNr;
offset -= clusSize;
}
- printf("%lu", n);
+ printf("%lu", (unsigned long) n);
}
-static int normal_map(File_t *This, off_t where, size_t *len, int mode,
- mt_off_t *res)
+static int normal_map(File_t *This, uint32_t where, uint32_t *len, int mode,
+ mt_off_t *res)
{
- int offset;
+ unsigned int offset;
size_t end;
- int NrClu; /* number of clusters to read */
- unsigned int RelCluNr;
- unsigned int CurCluNr;
- unsigned int NewCluNr;
- unsigned int AbsCluNr;
- int clus_size;
+ uint32_t NrClu; /* number of clusters to read */
+ uint32_t RelCluNr;
+ uint32_t CurCluNr;
+ uint32_t NewCluNr;
+ uint32_t AbsCluNr;
+ uint32_t clus_size;
Fs_t *Fs = This->Fs;
*res = 0;
}
RelCluNr = where / clus_size;
-
+
if (RelCluNr >= This->PreviousRelCluNr){
CurCluNr = This->PreviousRelCluNr;
AbsCluNr = This->PreviousAbsCluNr;
AbsCluNr, NewCluNr);
exit(1);
}
- if(CurCluNr == RelCluNr + NrClu)
+ if(CurCluNr == RelCluNr + NrClu)
break;
if (NewCluNr > Fs->last_fat && mode == MT_WRITE){
/* if at end, and writing, extend it */
}
maximize(*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
-
+
end = where + *len;
if(batchmode &&
mode == MT_WRITE &&
end >= This->FileSize) {
+ /* In batch mode, when writing at end of file, "pad"
+ * to nearest cluster boundary so that we don't have
+ * to read that data back from disk. */
*len += ROUND_UP(end, clus_size) - end;
}
exit(1);
}
- *res = sectorsToBytes((Stream_t*)Fs,
- (This->PreviousAbsCluNr-2) * Fs->cluster_size +
- Fs->clus_start) + offset;
+ *res = sectorsToBytes(Fs,
+ (This->PreviousAbsCluNr-2) * Fs->cluster_size +
+ Fs->clus_start) + to_mt_off_t(offset);
return 1;
}
-static int root_map(File_t *This, off_t where, size_t *len, int mode UNUSEDP,
- mt_off_t *res)
+static int root_map(File_t *This, uint32_t where, uint32_t *len,
+ int mode UNUSEDP, mt_off_t *res)
{
Fs_t *Fs = This->Fs;
- if(Fs->dir_len * Fs->sector_size < (size_t) where) {
+ if(Fs->dir_len * Fs->sector_size < where) {
*len = 0;
errno = ENOSPC;
return -2;
}
- smaximize(*len, Fs->dir_len * Fs->sector_size - where);
+ maximize(*len, Fs->dir_len * Fs->sector_size - where);
if (*len == 0)
return 0;
-
- *res = sectorsToBytes((Stream_t*)Fs, Fs->dir_start) + where;
+
+ *res = sectorsToBytes(Fs, Fs->dir_start) +
+ to_mt_off_t(where);
return 1;
}
-
-static int read_file(Stream_t *Stream, char *buf, mt_off_t iwhere,
- size_t len)
+
+static ssize_t read_file(Stream_t *Stream, char *buf, mt_off_t iwhere,
+ size_t ilen)
{
DeclareThis(File_t);
mt_off_t pos;
int err;
- off_t where = truncBytes32(iwhere);
+ uint32_t where = truncMtOffTo32u(iwhere);
+ uint32_t len = truncSizeTo32u(ilen);
Stream_t *Disk = This->Fs->Next;
-
+
err = This->map(This, where, &len, MT_READ, &pos);
if(err <= 0)
return err;
return READS(Disk, buf, pos, len);
}
-static int write_file(Stream_t *Stream, char *buf, mt_off_t iwhere, size_t len)
+static ssize_t write_file(Stream_t *Stream, char *buf,
+ mt_off_t iwhere, size_t ilen)
{
DeclareThis(File_t);
mt_off_t pos;
- int ret;
- size_t requestedLen;
+ ssize_t ret;
+ uint32_t requestedLen;
+ uint32_t bytesWritten;
Stream_t *Disk = This->Fs->Next;
- off_t where = truncBytes32(iwhere);
+ uint32_t where = truncMtOffTo32u(iwhere);
+ uint32_t maxLen = UINT32_MAX-where;
+ uint32_t len;
int err;
+ if(ilen > maxLen) {
+ len = maxLen;
+ } else
+ len = (uint32_t) ilen;
requestedLen = len;
err = This->map(This, where, &len, MT_WRITE, &pos);
if( err <= 0)
ret = force_write(Disk, buf, pos, len);
else
ret = WRITES(Disk, buf, pos, len);
- if(ret > (signed int) requestedLen)
- ret = requestedLen;
- if (ret > 0 &&
- where + ret > (off_t) This->FileSize )
- This->FileSize = where + ret;
+ if(ret < 0)
+ /* Error occured */
+ return ret;
+ if((uint32_t)ret > requestedLen)
+ /* More data than requested may be written to lower
+ * levels if batch mode is active, in order to "pad"
+ * the last cluster of a file, so that we don't have
+ * to read that back from disk */
+ bytesWritten = requestedLen;
+ else
+ bytesWritten = (uint32_t)ret;
+ if (where + bytesWritten > This->FileSize )
+ This->FileSize = where + bytesWritten;
recalcPreallocSize(This);
- return ret;
+ return (ssize_t)bytesWritten;
}
{
struct timeval tv;
struct timezone tz;
-
+
gettimeofday(&tv, &tz);
tzone = tz.tz_minuteswest * 60L;
}
}
-static int get_file_data(Stream_t *Stream, time_t *date, mt_size_t *size,
- int *type, int *address)
+static int get_file_data(Stream_t *Stream, time_t *date, mt_off_t *size,
+ int *type, uint32_t *address)
{
DeclareThis(File_t);
if(date)
*date = conv_stamp(& This->direntry.dir);
if(size)
- *size = (mt_size_t) This->FileSize;
+ *size = to_mt_off_t(This->FileSize);
if(type)
*type = This->direntry.dir.attr & ATTR_DIR;
if(address)
{
DeclareThis(File_t);
Fs_t *Fs = This->Fs;
- fsPreallocateClusters(Fs, -This->preallocatedClusters);
+ fsReleasePreallocateClusters(Fs, This->preallocatedClusters);
FREE(&This->direntry.Dir);
freeDirCache(Stream);
return hash_remove(filehash, (void *) Stream, This->hint);
}
-static int pre_allocate_file(Stream_t *Stream, mt_size_t isize)
+static int pre_allocate_file(Stream_t *Stream, mt_off_t isize)
{
DeclareThis(File_t);
- size_t size = truncBytes32(isize);
+ uint32_t size = truncMtOffTo32u(isize);
if(size > This->FileSize &&
size > This->preallocatedSize) {
return 1;
}
-static unsigned int func1(void *Stream)
+static uint32_t func1(void *Stream)
{
DeclareThis(File_t);
- return getAbsCluNr(This) ^ (long) This->Fs;
+ return getAbsCluNr(This) ^ (uint32_t) (unsigned long) This->Fs;
}
-static unsigned int func2(void *Stream)
+static uint32_t func2(void *Stream)
{
DeclareThis(File_t);
static void init_hash(void)
{
static int is_initialised=0;
-
+
if(!is_initialised){
make_ht(func1, func2, comp, 20, &filehash);
is_initialised = 1;
static Stream_t *_internalFileOpen(Stream_t *Dir, unsigned int first,
- size_t size, direntry_t *entry)
+ uint32_t size, direntry_t *entry)
{
Stream_t *Stream = GetFs(Dir);
DeclareThis(Fs_t);
{
unsigned int num;
direntry_t entry;
- size_t size;
+ uint32_t size;
Stream_t *file;
memset(&entry, 0, sizeof(direntry_t));
{
Stream_t *file;
unsigned int first;
- size_t size;
+ uint32_t size;
first = getStart(entry->Dir, &entry->dir);