1
0
forked from 0ad/0ad

updated file mapping (was partially unimplemented)

This was SVN commit r371.
This commit is contained in:
janwas 2004-06-02 20:41:05 +00:00
parent 8b91bbc27a
commit af3949ab7a
7 changed files with 111 additions and 97 deletions

View File

@ -188,12 +188,13 @@ struct DirEnt
{
const std::string name;
const uint flags;
const ssize_t size;
const off_t size;
DirEnt(const char* const _name, const uint _flags, const ssize_t _size)
DirEnt(const char* const _name, const uint _flags, const off_t _size)
: name(_name), flags(_flags), size(_size) {}
};
// pointer to DirEnt: faster sorting, but more allocs.
typedef std::vector<const DirEnt*> DirEnts;
typedef DirEnts::const_iterator DirEntIt;
@ -253,7 +254,7 @@ int file_enum(const char* const dir, const FileCB cb, const uintptr_t user)
}
uint flags = 0;
ssize_t size = s.st_size;
off_t size = s.st_size;
// dir
if(s.st_mode & S_IFDIR)
@ -399,7 +400,7 @@ int file_open(const char* p_fn, uint flags, File* f)
{
// don't stat if opening for writing - the file may not exist yet
size_t size = 0;
off_t size = 0;
int mode = O_RDONLY;
if(flags & FILE_WRITE)
@ -466,7 +467,7 @@ struct ll_cb
};
int ll_start_io(File* f, size_t ofs, size_t size, void* p, ll_cb* lcb)
int ll_start_io(File* f, off_t ofs, size_t size, void* p, ll_cb* lcb)
{
CHECK_FILE(f)
@ -481,12 +482,14 @@ int ll_start_io(File* f, size_t ofs, size_t size, void* p, ll_cb* lcb)
return -1;
}
size_t bytes_left = f->size - ofs; // > 0
off_t bytes_left = f->size - ofs; // > 0
int op = (f->flags & FILE_WRITE)? LIO_WRITE : LIO_READ;
// don't read beyond EOF
if(size > bytes_left) // avoid min() - it wants int
size = bytes_left;
// cut off at EOF.
// avoid min() due to type conversion warnings.
if((off_t)size > bytes_left)
size = (size_t)bytes_left;
// guaranteed to fit, since size was > bytes_left
aiocb* cb = &lcb->cb;
@ -495,7 +498,7 @@ int ll_start_io(File* f, size_t ofs, size_t size, void* p, ll_cb* lcb)
cb->aio_buf = p;
cb->aio_fildes = f->fd;
cb->aio_offset = (off_t)ofs;
cb->aio_nbytes = size;
cb->aio_nbytes = (size_t)size;
return lio_listio(LIO_NOWAIT, &cb, 1, (struct sigevent*)0);
// this just issues the I/O - doesn't wait until complete.
}
@ -536,7 +539,7 @@ static Cache<void*> c;
// create an id for use with the Cache that uniquely identifies
// the block from the file <fn_hash> containing <ofs>.
static u64 block_make_id(const u32 fn_hash, const size_t ofs)
static u64 block_make_id(const u32 fn_hash, const off_t ofs)
{
// id format: filename hash | block number
// 63 32 31 0
@ -684,7 +687,7 @@ struct IO
// so we don't allocate a new cb every file_start_io.
void* user_p;
size_t user_ofs;
off_t user_ofs;
size_t user_size;
int cached : 1;
@ -700,8 +703,8 @@ H_TYPE_DEFINE(IO)
static void IO_init(IO* io, va_list args)
{
size_t size = round_up(sizeof(struct ll_cb), 16);
io->cb = (ll_cb*)mem_alloc(size, 16, MEM_ZERO);
const size_t cb_size = round_up(sizeof(struct ll_cb), 16);
io->cb = (ll_cb*)mem_alloc(cb_size, 16, MEM_ZERO);
}
static void IO_dtor(IO* io)
@ -867,7 +870,7 @@ static Handle io_find(u64 block_id)
// pads the request up to BLOCK_SIZE, and stores the original parameters in IO.
// transfers of more than 1 block (including padding) are allowed, but do not
// go through the cache. don't see any case where that's necessary, though.
Handle file_start_io(File* f, size_t user_ofs, size_t user_size, void* user_p)
Handle file_start_io(File* f, off_t user_ofs, size_t user_size, void* user_p)
{
int err;
@ -884,12 +887,13 @@ Handle file_start_io(File* f, size_t user_ofs, size_t user_size, void* user_p)
return -1;
}
const size_t bytes_left = f->size - user_ofs; // > 0
const off_t bytes_left = f->size - user_ofs; // > 0
int op = (f->flags & FILE_WRITE)? LIO_WRITE : LIO_READ;
// don't read beyond EOF
if(user_size > bytes_left) // avoid min() - it wants int
user_size = bytes_left;
if((off_t)user_size > bytes_left) // avoid min() - it wants int
user_size = (size_t)bytes_left;
// guaranteed to fit in user_size, since user_size > bytes_left
u64 block_id = block_make_id(f->fn_hash, user_ofs);
@ -919,9 +923,9 @@ debug_out("file_start_io hio=%I64x ofs=%d size=%d\n", hio, user_ofs, user_size);
// a zip archive may contain one last file in the block.
// if not, no loss - the buffer will be LRU, and reused.
size_t ofs = user_ofs;
off_t ofs = user_ofs;
size_t padding = ofs % BLOCK_SIZE;
ofs -= padding;
ofs -= (off_t)padding;
size_t size = round_up(padding + user_size, BLOCK_SIZE);
@ -1060,7 +1064,7 @@ int file_discard_io(Handle& hio)
//
// return (positive) number of raw bytes transferred if successful;
// otherwise, an error code.
ssize_t file_io(File* const f, const size_t raw_ofs, size_t raw_size, void** const p,
ssize_t file_io(File* const f, const off_t raw_ofs, size_t raw_size, void** const p,
const FILE_IO_CB cb, const uintptr_t ctx) // optional
{
#ifdef PARANOIA
@ -1078,9 +1082,14 @@ debug_out("file_io fd=%d size=%d ofs=%d\n", f->fd, raw_size, raw_ofs);
// reading: make sure we don't go beyond EOF
if(!is_write)
{
if(raw_ofs >= f->size)
// cut off at EOF.
// avoid min() due to type conversion warnings.
off_t bytes_left = f->size - raw_ofs;
if(bytes_left < 0)
return ERR_EOF;
raw_size = MIN(f->size - raw_ofs, raw_size);
if((off_t)raw_size > bytes_left)
raw_size = (size_t)bytes_left;
// guaranteed to fit, since size was > bytes_left
}
// writing: make sure buffer is valid
else
@ -1098,7 +1107,7 @@ debug_out("file_io fd=%d size=%d ofs=%d\n", f->fd, raw_size, raw_ofs);
// actual transfer start offset
// not aligned! aio takes care of initial unalignment;
// next read will be aligned, because we read up to the next block.
const size_t start_ofs = raw_ofs;
const off_t start_ofs = raw_ofs;
void* buf = 0; // I/O source or sink; assume temp buffer
@ -1187,7 +1196,7 @@ debug_out("file_io fd=%d size=%d ofs=%d\n", f->fd, raw_size, raw_ofs);
{
// calculate issue_size:
// at most, transfer up to the next block boundary.
size_t issue_ofs = start_ofs + issue_cnt;
off_t issue_ofs = (off_t)(start_ofs + issue_cnt);
const size_t left_in_block = BLOCK_SIZE - (issue_ofs % BLOCK_SIZE);
const size_t total_left = raw_size - issue_cnt;
size_t issue_size = MIN(left_in_block, total_left);

View File

@ -34,7 +34,7 @@ struct File
// it is accessed by VFS and must be the same for both (union).
// dirty, but necessary because VFile is pushing the HDATA size limit.
int flags;
size_t size;
off_t size;
u32 fn_hash;
@ -91,7 +91,7 @@ extern int file_close(File* f);
extern int file_map(File* f, void*& p, size_t& size);
extern int file_unmap(File* f);
extern Handle file_start_io(File* f, size_t ofs, size_t size, void* buf);
extern Handle file_start_io(File* f, off_t ofs, size_t size, void* buf);
extern int file_wait_io(const Handle hio, void*& p, size_t& size);
extern int file_discard_io(Handle& hio);
@ -103,7 +103,7 @@ extern int file_discard_io(Handle& hio);
// > 0: bytes output (not used ATM; useful for statistics) - continue.
typedef ssize_t(*FILE_IO_CB)(uintptr_t ctx, void* p, size_t size);
extern ssize_t file_io(File* f, size_t ofs, size_t size, void** p,
extern ssize_t file_io(File* f, off_t ofs, size_t size, void** p,
FILE_IO_CB cb = 0, uintptr_t ctx = 0);

View File

@ -94,31 +94,37 @@ struct H_VTbl
typedef H_VTbl* H_Type;
#define H_TYPE_DEFINE(t)\
#define H_TYPE_DEFINE(type)\
/* forward decls */\
static void t##_init(t*, va_list);\
static int t##_reload(t*, const char*);\
static void t##_dtor(t*);\
static H_VTbl V_##t =\
static void type##_init(type*, va_list);\
static int type##_reload(type*, const char*);\
static void type##_dtor(type*);\
static H_VTbl V_##type =\
{\
(void(*)(void*, va_list))t##_init,\
(int(*)(void*, const char*))t##_reload,\
(void(*)(void*))t##_dtor,\
sizeof(t), /* control block size */\
#t /* name */\
(void(*)(void*, va_list))type##_init,\
(int(*)(void*, const char*))type##_reload,\
(void(*)(void*))type##_dtor,\
sizeof(type), /* control block size */\
#type /* name */\
};\
static H_Type H_##t = &V_##t;
static H_Type H_##type = &V_##type;
// note: we cast to void* pointers so the functions can be declared to
// take the control block pointers, instead of requiring a cast in each.
// the forward decls ensure the function signatures are correct.
// <type>* <var> = H_USER_DATA(<h_var>, <type>)
#define H_USER_DATA(h, type) (type*)h_user_data(h, H_##type);
// convenience macro for h_user_data:
// casts its return value to the control block type.
// use if H_DEREF's returning a negative error code isn't acceptable.
#define H_USER_DATA(h, type) (type*)h_user_data(h, H_##type)
// even more convenient wrapper for h_user_data:
// declares a pointer (<var>), assigns it H_USER_DATA, and has
// the user's function return a negative error code on failure.
#define H_DEREF(h, type, var)\
type* const var = (type*)h_user_data(h, H_##type);\
/* don't use STMT - var decl must be visible to "caller" */\
type* const var = H_USER_DATA(h, type);\
if(!var)\
return ERR_INVALID_HANDLE;
@ -173,7 +179,9 @@ extern int h_free(Handle& h, H_Type type);
// currently O(n).
extern Handle h_find(H_Type type, uintptr_t key);
// return a pointer to handle data, or 0 on error
// returns a void* pointer to the control block of the resource <h>,
// or 0 on error (i.e. h is invalid or of the wrong type).
// prefer using H_DEREF or H_USER_DATA.
extern void* h_user_data(Handle h, H_Type type);
extern const char* h_filename(Handle h);

View File

@ -955,7 +955,7 @@ H_TYPE_DEFINE(VFile)
// use the functions below to insulate against change a bit.
static size_t& vf_size(VFile* vf)
static off_t& vf_size(VFile* vf)
{
assert(offsetof(struct File, size) == offsetof(struct ZFile, ucsize));
return vf->f.size;
@ -1061,7 +1061,7 @@ debug_out("vfs_close %I64x\n", h);
}
ssize_t vfs_io(Handle hf, size_t ofs, size_t size, void*& p)
ssize_t vfs_io(Handle hf, off_t ofs, size_t size, void*& p)
{
#ifdef PARANOIA
debug_out("vfs_io ofs=%d size=%d\n", ofs, size);
@ -1146,20 +1146,24 @@ int vfs_store(const char* fn, void* p, size_t size)
Handle vfs_map(const char* fn, uint flags, void*& p, size_t& size)
int vfs_map(const Handle hf, uint flags, void*& p, size_t& size)
{
Handle hf = vfs_open(fn, flags);
H_DEREF(hf, VFile, vf);
CHECK_ERR(file_map(&vf->f, p, size));
MEM_DTOR dtor = 0;
uintptr_t ctx = 0;
return mem_assign(p, size, 0, dtor, ctx);
if(vf_flags(vf) & VF_ZIP)
CHECK_ERR(zip_map(&vf->zf, p, size));
else
CHECK_ERR(file_map(&vf->f, p, size));
return 0;
}
int vfs_unmap(Handle& hm)
int vfs_unmap(Handle hf)
{
return -1;
// return h_free(hm, H_MMap);
H_DEREF(hf, VFile, vf);
if(vf_flags(vf) & VF_ZIP)
CHECK_ERR(zip_unmap(&vf->zf));
else
CHECK_ERR(file_unmap(&vf->f));
return 0;
}

View File

@ -41,7 +41,8 @@ extern Handle vfs_load(const char* fn, void*& p, size_t& size);
extern Handle vfs_open(const char* fn, uint flags = 0);
extern int vfs_close(Handle& h);
extern Handle vfs_map(Handle hf, uint flags, void*& p, size_t& size);
extern int vfs_map(Handle hf, uint flags, void*& p, size_t& size);
extern int vfs_unmap(Handle hf);
struct vfsDirEnt
@ -70,11 +71,11 @@ extern int vfs_rebuild();
// async read interface
//
extern Handle vfs_start_read(const Handle hf, size_t ofs, size_t& advance, void* buf);
extern Handle vfs_start_read(const Handle hf, off_t ofs, size_t& advance, void* buf);
extern int vfs_wait_read(Handle hr, void*& p, size_t& size);
extern int vfs_discard_read(Handle& hr);
extern ssize_t vfs_io(Handle hf, size_t ofs, size_t size, void*& p);
extern ssize_t vfs_io(Handle hf, off_t ofs, size_t size, void*& p);
// keep in sync with File flags!

View File

@ -46,9 +46,9 @@
// convenience container for location / size of file in archive.
struct ZFileLoc
{
size_t ofs;
size_t csize; // = 0 if not compressed
size_t ucsize;
off_t ofs;
off_t csize; // = 0 if not compressed
off_t ucsize;
// why csize?
// file I/O may be N-buffered, so it's good to know when the raw data
@ -108,7 +108,7 @@ static int zip_find_ecdr(const void* const file, const size_t size, const u8*& e
if(*(u32*)ecdr == *(u32*)&ecdr_id)
goto found_ecdr;
// check next 4 bytes (non aligned!!)
// check next 4 bytes (unaligned!!)
ecdr++;
bytes_left--;
}
@ -127,7 +127,7 @@ found_ecdr:
// make sure the LFH fields match those passed (from the CDFH).
// only used in PARANOIA builds - costs time when opening archives.
static int zip_verify_lfh(const void* const file, const size_t lfh_ofs, const size_t file_ofs)
static int zip_verify_lfh(const void* const file, const off_t lfh_ofs, const off_t file_ofs)
{
const char lfh_id[] = "PK\3\4"; // signature
const size_t LFH_SIZE = 30;
@ -145,7 +145,7 @@ static int zip_verify_lfh(const void* const file, const size_t lfh_ofs, const si
const u16 lfh_fn_len = read_le16(lfh+26);
const u16 lfh_e_len = read_le16(lfh+28);
const size_t lfh_file_ofs = lfh_ofs + LFH_SIZE + lfh_fn_len + lfh_e_len;
const off_t lfh_file_ofs = lfh_ofs + LFH_SIZE + lfh_fn_len + lfh_e_len;
if(file_ofs != lfh_file_ofs)
{
@ -196,9 +196,9 @@ static int zip_read_cdfh(const u8*& cdfh, const char*& fn, size_t& fn_len, ZFile
fn = fn_;
fn_len = fn_len_;
loc->ofs = lfh_ofs + LFH_SIZE + fn_len_ + e_len;
loc->csize = csize_;
loc->ucsize = ucsize_;
loc->ofs = (off_t)(lfh_ofs + LFH_SIZE + fn_len_ + e_len);
loc->csize = (off_t)csize_;
loc->ucsize = (off_t)ucsize_;
// performance issue: want to avoid seeking between LFHs and central dir.
// would be safer to calculate file offset from the LFH, since its
@ -856,7 +856,7 @@ int zip_stat(Handle ha, const char* fn, struct stat* s)
lookup_get_file_info(li, idx, fn2, &loc);
// can't fail - returned valid index above
s->st_size = (off_t)loc.ucsize;
s->st_size = loc.ucsize;
return 0;
}
@ -874,7 +874,7 @@ static inline bool is_compressed(ZFile* zf)
// note: we go to a bit of trouble to make sure the buffer we allocated
// (if p == 0) is freed when the read fails.
ssize_t zip_read(ZFile* zf, size_t raw_ofs, size_t size, void*& p)
ssize_t zip_read(ZFile* zf, off_t raw_ofs, size_t size, void*& p)
{
CHECK_ZFILE(zf)
@ -885,7 +885,7 @@ ssize_t zip_read(ZFile* zf, size_t raw_ofs, size_t size, void*& p)
if(!za)
return ERR_INVALID_HANDLE;
const size_t ofs = zf->ofs + raw_ofs;
const off_t ofs = zf->ofs + raw_ofs;
// not compressed - just pass it on to file_io
// (avoid the Zip inflate start/finish stuff below)
@ -946,7 +946,7 @@ fail:
}
int zip_map(ZFile* zf, void*& p, size_t& size)
int zip_map(ZFile* const zf, void*& p, size_t& size)
{
CHECK_ZFILE(zf)
@ -958,5 +958,17 @@ int zip_map(ZFile* zf, void*& p, size_t& size)
}
H_DEREF(zf->ha, ZArchive, za)
// increase refs
return file_map(&za->f, p, size);
}
int zip_unmap(ZFile* const zf)
{
CHECK_ZFILE(zf)
H_DEREF(zf->ha, ZArchive, za)
// decrement refs
// unmap archive if 0
return 0;
}

View File

@ -77,9 +77,9 @@ struct ZFile
size_t ucsize;
// size of logical file
size_t ofs;
size_t csize;
size_t last_raw_ofs;
off_t ofs;
off_t csize;
off_t last_raw_ofs;
Handle ha;
uintptr_t read_ctx;
@ -96,30 +96,10 @@ extern int zip_close(ZFile* zf);
extern int zip_map(ZFile* zf, void*& p, size_t& size);
extern int zip_unmap(ZFile* zf);
extern ssize_t zip_read(ZFile* zf, size_t ofs, size_t size, void*& p);
//--------
// read from file <hz>, starting at offset <ofs> in the compressed data
// (typically only used if the file is known to be stored).
// p == 0: allocate, read into, and return the output buffer
// p != 0: read into given output buffer, return handle to it
// if file is compressed, size must be >= uncompressed file size
// size: no input value, unless specifying an output buffer (p != 0)
// out:
//extern void* zip_mmap(
// read from file <zf>, starting at offset <ofs> in the compressed data
extern ssize_t zip_read(ZFile* zf, off_t ofs, size_t size, void*& p);
#endif // #ifndef __ZIP_H__