#further VFS refactor (dirent enumeration interface unified, more code sharing)

- file: make DirIterator opaque struct with type field, as with
File/FileIo in recent commit. unifies all dir enum interfaces.
- add dir open/nextent/close functions to FileProvider_VTbl
- allocators: change signature of SingleAllocator to that of the
templated type (avoids need for cast)
  (affects archive, compression, zip)
- file_util: move dirent filter logic here so it can be used by file.cpp
also, not only vfs.

This was SVN commit r3822.
This commit is contained in:
janwas 2006-04-26 22:38:25 +00:00
parent 2e1374c3ed
commit 641e55fefd
13 changed files with 333 additions and 233 deletions

View File

@ -293,12 +293,12 @@ public:
is_in_use = 0;
}
void* alloc()
T* alloc()
{
return single_calloc(&storage, &is_in_use, sizeof(storage));
return (T*)single_calloc(&storage, &is_in_use, sizeof(storage));
}
void release(void* p)
void release(T* p)
{
single_free(&storage, &is_in_use, p);
}

View File

@ -413,7 +413,7 @@ LibError afile_io_issue(File* f, off_t user_ofs, size_t max_output_size, void* u
H_DEREF(af->ha, Archive, a);
ArchiveFileIo* aio = (ArchiveFileIo*)io->opaque;
aio->io = (FileIo*)io_allocator.alloc();
aio->io = io_allocator.alloc();
if(!aio->io)
WARN_RETURN(ERR_NO_MEM);

View File

@ -421,11 +421,12 @@ public:
// allocator
static const size_t MAX_COMPRESSOR_SIZE = sizeof(ZLibCompressor);
typedef u8 CompressorMem[MAX_COMPRESSOR_SIZE];
static SingleAllocator<u8[MAX_COMPRESSOR_SIZE]> compressor_allocator;
uintptr_t comp_alloc(ContextType type, CompressionMethod method)
{
void* c_mem = compressor_allocator.alloc();
CompressorMem* c_mem = compressor_allocator.alloc();
if(!c_mem)
return 0;
Compressor* c;
@ -500,5 +501,5 @@ void comp_free(uintptr_t c_)
c->release();
c->~Compressor();
compressor_allocator.release(c);
compressor_allocator.release((CompressorMem*)c);
}

View File

@ -59,7 +59,7 @@
// and additionally returns the file status (size and mtime).
// rationale: see DirIterator definition in header.
struct DirIterator_
struct PosixDirIterator
{
DIR* os_dir;
@ -68,18 +68,23 @@ struct DirIterator_
// we latch dir_open's path and append entry name every dir_next_ent call.
// this is also the storage to which DirEnt.name points!
// PathPackage avoids repeated memory allocs and strlen() overhead.
PathPackage pp;
//
// it can't be stored here directly because then the struct would
// no longer fit in HDATA; we'll allocate it separately.
PathPackage* pp;
};
cassert(sizeof(DirIterator_) <= sizeof(DirIterator));
cassert(sizeof(PosixDirIterator) <= DIR_ITERATOR_OPAQUE_SIZE);
static SingleAllocator<PathPackage> pp_allocator;
// prepare to iterate (once) over entries in the given directory.
// if ERR_OK is returned, <d> is ready for subsequent dir_next_ent calls and
// must be freed via dir_close.
LibError dir_open(const char* P_path, DirIterator* d_)
LibError dir_open(const char* P_path, DirIterator* di)
{
DirIterator_* d = (DirIterator_*)d_;
PosixDirIterator* pdi = (PosixDirIterator*)di->opaque;
char n_path[PATH_MAX];
// HACK: allow calling with a full (absolute) native path.
@ -95,11 +100,16 @@ LibError dir_open(const char* P_path, DirIterator* d_)
RETURN_ERR(file_make_full_native_path(P_path, n_path));
}
d->os_dir = opendir(n_path);
if(!d->os_dir)
pdi->pp = pp_allocator.alloc();
if(!pdi->pp)
WARN_RETURN(ERR_NO_MEM);
errno = 0;
pdi->os_dir = opendir(n_path);
if(!pdi->os_dir)
return LibError_from_errno();
RETURN_ERR(path_package_set_dir(&d->pp, n_path));
(void)path_package_set_dir(pdi->pp, n_path);
return ERR_OK;
}
@ -107,13 +117,13 @@ LibError dir_open(const char* P_path, DirIterator* d_)
// return ERR_DIR_END if all entries have already been returned once,
// another negative error code, or ERR_OK on success, in which case <ent>
// describes the next (order is unspecified) directory entry.
LibError dir_next_ent(DirIterator* d_, DirEnt* ent)
LibError dir_next_ent(DirIterator* di, DirEnt* ent)
{
DirIterator_* d = (DirIterator_*)d_;
PosixDirIterator* pdi = (PosixDirIterator*)di->opaque;
get_another_entry:
errno = 0;
struct dirent* os_ent = readdir(d->os_dir);
struct dirent* os_ent = readdir(pdi->os_dir);
if(!os_ent)
{
// no error, just no more entries to return
@ -124,21 +134,21 @@ get_another_entry:
// copy os_ent.name[]; we need it for stat() #if !OS_WIN and
// return it as ent.name (since os_ent.name[] is volatile).
path_package_append_file(&d->pp, os_ent->d_name);
const char* name = d->pp.end;
path_package_append_file(pdi->pp, os_ent->d_name);
const char* name = pdi->pp->end;
// get file information (mode, size, mtime)
struct stat s;
#if OS_WIN
// .. wposix readdir has enough information to return dirent
// status directly (much faster than calling stat).
CHECK_ERR(readdir_stat_np(d->os_dir, &s));
CHECK_ERR(readdir_stat_np(pdi->os_dir, &s));
#else
// .. call regular stat().
// we need the full pathname for this. don't use path_append because
// it would unnecessarily call strlen.
CHECK_ERR(stat(d->pp.path, &s));
CHECK_ERR(stat(pdi->pp.path, &s));
#endif
// skip "undesirable" entries that POSIX readdir returns:
@ -163,10 +173,14 @@ get_another_entry:
// indicate the directory iterator is no longer needed; all resources it
// held are freed.
LibError dir_close(DirIterator* d_)
LibError dir_close(DirIterator* di)
{
DirIterator_* d = (DirIterator_*)d_;
WARN_ERR(closedir(d->os_dir));
PosixDirIterator* pdi = (PosixDirIterator*)di->opaque;
pp_allocator.release(pdi->pp);
errno = 0;
if(closedir(pdi->os_dir) < 0)
return LibError_from_errno();
return ERR_OK;
}

View File

@ -28,6 +28,9 @@
extern LibError file_init();
// used by vfs_redirector to call various file objects' methods.
struct FileProvider_VTbl;
//
// path conversion functions (native <--> portable),
@ -78,6 +81,8 @@ extern const char* file_get_random_name();
// dir_next_ent
//
const size_t DIR_ITERATOR_OPAQUE_SIZE = 40;
// layer on top of POSIX opendir/readdir/closedir that handles
// portable -> native path conversion, ignores non-file/directory entries,
// and additionally returns the file status (size and mtime).
@ -94,7 +99,15 @@ extern const char* file_get_random_name();
// instantiate this.
struct DirIterator
{
char opaque[PATH_MAX+32];
// safety check - used to verify correct calling of dir_filtered_next_ent
const char* filter;
// .. has filter been assigned? this flag is necessary because
// there are no "invalid" filter values we can use.
uint filter_latched : 1;
const FileProvider_VTbl* type;
char opaque[DIR_ITERATOR_OPAQUE_SIZE];
};
class TFile;
@ -165,8 +178,6 @@ typedef LibError (*FileCB)(const char* name, const struct stat* s, uintptr_t mem
// return first error encountered while listing files, or 0 on success.
extern LibError file_enum(const char* dir, FileCB cb, uintptr_t user);
struct FileProvider_VTbl;
// chosen for semi-nice 48 byte total struct File size.
// each implementation checks if this is enough.
const size_t FILE_OPAQUE_SIZE = 52;

View File

@ -63,6 +63,27 @@ const size_t FILE_BLOCK_SIZE = 32*KiB;
extern LibError file_io_call_back(const void* block, size_t size,
FileIOCB cb, uintptr_t ctx, size_t& bytes_processed);
// retrieve the next (order is unspecified) dir entry matching <filter>.
// return 0 on success, ERR_DIR_END if no matching entry was found,
// or a negative error code on failure.
// filter values:
// - 0: anything;
// - "/": any subdirectory;
// - "/|<pattern>": any subdirectory, or as below with <pattern>;
// - <pattern>: any file whose name matches; ? and * wildcards are allowed.
//
// note that the directory entries are only scanned once; after the
// end is reached (-> ERR_DIR_END returned), no further entries can
// be retrieved, even if filter changes (which shouldn't happen - see impl).
//
// rationale: we do not sort directory entries alphabetically here.
// most callers don't need it and the overhead is considerable
// (we'd have to store all entries in a vector). it is left up to
// higher-level code such as VfsUtil.
extern LibError dir_filtered_next_ent(DirIterator* di, DirEnt* ent, const char* filter);
// used by file.cpp and file_io.cpp
struct PosixFile
{

View File

@ -88,6 +88,154 @@ LibError file_enum(const char* P_path, const FileCB cb, const uintptr_t user)
// retrieve the next (order is unspecified) dir entry matching <filter>.
// return 0 on success, ERR_DIR_END if no matching entry was found,
// or a negative error code on failure.
// filter values:
// - 0: anything;
// - "/": any subdirectory;
// - "/|<pattern>": any subdirectory, or as below with <pattern>;
// - <pattern>: any file whose name matches; ? and * wildcards are allowed.
//
// note that the directory entries are only scanned once; after the
// end is reached (-> ERR_DIR_END returned), no further entries can
// be retrieved, even if filter changes (which shouldn't happen - see impl).
//
// rationale: we do not sort directory entries alphabetically here.
// most callers don't need it and the overhead is considerable
// (we'd have to store all entries in a vector). it is left up to
// higher-level code such as VfsUtil.
LibError dir_filtered_next_ent(DirIterator* di, DirEnt* ent, const char* filter)
{
// warn if scanning the directory twice with different filters
// (this used to work with dir/file because they were stored separately).
// it is imaginable that someone will want to change it, but until
// there's a good reason, leave this check in. note: only comparing
// pointers isn't 100% certain, but it's safe enough and easy.
if(!di->filter_latched)
{
di->filter = filter;
di->filter_latched = 1;
}
if(di->filter != filter)
debug_warn("filter has changed for this directory. are you scanning it twice?");
bool want_dir = true;
if(filter)
{
// directory
if(filter[0] == '/')
{
// .. and also files
if(filter[1] == '|')
filter += 2;
}
// file only
else
want_dir = false;
}
// loop until ent matches what is requested, or end of directory.
for(;;)
{
RETURN_ERR(xdir_next_ent(di, ent));
if(DIRENT_IS_DIR(ent))
{
if(want_dir)
break;
}
else
{
// (note: filter = 0 matches anything)
if(match_wildcard(ent->name, filter))
break;
}
}
return ERR_OK;
}
// call <cb> for each entry matching <user_filter> (see vfs_next_dirent) in
// directory <path>; if flags & VFS_DIR_RECURSIVE, entries in
// subdirectories are also returned.
//
// note: EnumDirEntsCB path and ent are only valid during the callback.
LibError vfs_dir_enum(const char* start_path, uint flags, const char* user_filter,
DirEnumCB cb, void* context)
{
debug_assert((flags & ~(VFS_DIR_RECURSIVE)) == 0);
const bool recursive = (flags & VFS_DIR_RECURSIVE) != 0;
char filter_buf[PATH_MAX];
const char* filter = user_filter;
bool user_filter_wants_dirs = true;
if(user_filter)
{
if(user_filter[0] != '/')
user_filter_wants_dirs = false;
// we need subdirectories and the caller hasn't already requested them
if(recursive && !user_filter_wants_dirs)
{
snprintf(filter_buf, sizeof(filter_buf), "/|%s", user_filter);
filter = filter_buf;
}
}
// note: FIFO queue instead of recursion is much more efficient
// (less stack usage; avoids seeks by reading all entries in a
// directory consecutively)
std::queue<const char*> dir_queue;
dir_queue.push(file_make_unique_fn_copy(start_path));
// for each directory:
do
{
// get current directory path from queue
// note: can't refer to the queue contents - those are invalidated
// as soon as a directory is pushed onto it.
PathPackage pp;
(void)path_package_set_dir(&pp, dir_queue.front());
dir_queue.pop();
Handle hdir = vfs_dir_open(pp.path);
if(hdir <= 0)
{
debug_warn("vfs_open_dir failed");
continue;
}
// for each entry (file, subdir) in directory:
DirEnt ent;
while(vfs_dir_next_ent(hdir, &ent, filter) == 0)
{
// build complete path (DirEnt only stores entry name)
(void)path_package_append_file(&pp, ent.name);
const char* atom_path = file_make_unique_fn_copy(pp.path);
if(DIRENT_IS_DIR(&ent))
{
if(recursive)
dir_queue.push(atom_path);
if(user_filter_wants_dirs)
cb(atom_path, &ent, context);
}
else
cb(atom_path, &ent, context);
}
vfs_dir_close(hdir);
}
while(!dir_queue.empty());
return ERR_OK;
}
// fill V_next_fn (which must be big enough for PATH_MAX chars) with
// the next numbered filename according to the pattern defined by V_fn_fmt.

View File

@ -92,14 +92,8 @@
struct VDir
{
TreeDirIterator it;
uint it_valid : 1; // <it> will be closed iff == 1
// safety check
const char* filter;
// has filter been assigned? this flag is necessary because there are no
// "invalid" filter values we can use.
uint filter_latched : 1;
DirIterator di;
uint di_valid : 1; // <di> will be closed iff == 1
};
H_TYPE_DEFINE(VDir);
@ -110,12 +104,12 @@ static void VDir_init(VDir* UNUSED(vd), va_list UNUSED(args))
static void VDir_dtor(VDir* vd)
{
// note: TreeDirIterator has no way of checking if it's valid;
// note: DirIterator has no way of checking if it's valid;
// we must therefore only free it if reload() succeeded.
if(vd->it_valid)
if(vd->di_valid)
{
tree_dir_close(&vd->it);
vd->it_valid = 0;
xdir_close(&vd->di);
vd->di_valid = 0;
}
}
@ -126,23 +120,23 @@ static LibError VDir_reload(VDir* vd, const char* path, Handle UNUSED(hvd))
char V_path_slash[PATH_MAX];
RETURN_ERR(path_append(V_path_slash, path, ""));
RETURN_ERR(tree_dir_open(V_path_slash, &vd->it));
vd->it_valid = 1;
RETURN_ERR(xdir_open(V_path_slash, &vd->di));
vd->di_valid = 1;
return ERR_OK;
}
static LibError VDir_validate(const VDir* vd)
{
// note: <it> is opaque and cannot be validated.
if(vd->filter && !isprint(vd->filter[0]))
// note: <di> is mostly opaque and cannot be validated.
if(vd->di.filter && !isprint(vd->di.filter[0]))
WARN_RETURN(ERR_1);
return ERR_OK;
}
static LibError VDir_to_string(const VDir* d, char* buf)
static LibError VDir_to_string(const VDir* vd, char* buf)
{
const char* filter = d->filter;
if(!d->filter_latched)
const char* filter = vd->di.filter;
if(!vd->di.filter_latched)
filter = "?";
if(!filter)
filter = "*";
@ -153,11 +147,11 @@ static LibError VDir_to_string(const VDir* d, char* buf)
// open a directory for reading its entries via vfs_next_dirent.
// <v_dir> need not end in '/'; we add it if not present.
Handle vfs_dir_open(const char* v_dir)
Handle vfs_dir_open(const char* V_dir)
{
// must disallow handle caching because this object is not
// copy-equivalent (since the iterator is advanced by each user).
return h_alloc(H_VDir, v_dir, RES_NO_CACHE);
return h_alloc(H_VDir, V_dir, RES_NO_CACHE);
}
@ -188,136 +182,10 @@ LibError vfs_dir_close(Handle& hd)
LibError vfs_dir_next_ent(const Handle hd, DirEnt* ent, const char* filter)
{
H_DEREF(hd, VDir, vd);
// warn if scanning the directory twice with different filters
// (this used to work with dir/file because they were stored separately).
// it is imaginable that someone will want to change it, but until
// there's a good reason, leave this check in. note: only comparing
// pointers isn't 100% certain, but it's safe enough and easy.
if(!vd->filter_latched)
{
vd->filter = filter;
vd->filter_latched = 1;
}
if(vd->filter != filter)
debug_warn("filter has changed for this directory. are you scanning it twice?");
bool want_dir = true;
if(filter)
{
// directory
if(filter[0] == '/')
{
// .. and also files
if(filter[1] == '|')
filter += 2;
}
// file only
else
want_dir = false;
}
// loop until ent matches what is requested, or end of directory.
for(;;)
{
RETURN_ERR(tree_dir_next_ent(&vd->it, ent));
if(DIRENT_IS_DIR(ent))
{
if(want_dir)
break;
}
else
{
// (note: filter = 0 matches anything)
if(match_wildcard(ent->name, filter))
break;
}
}
return ERR_OK;
return dir_filtered_next_ent(&vd->di, ent, filter);
}
// call <cb> for each entry matching <user_filter> (see vfs_next_dirent) in
// directory <path>; if flags & VFS_DIR_RECURSIVE, entries in
// subdirectories are also returned.
//
// note: EnumDirEntsCB path and ent are only valid during the callback.
LibError vfs_dir_enum(const char* start_path, uint flags, const char* user_filter,
DirEnumCB cb, void* context)
{
debug_assert((flags & ~(VFS_DIR_RECURSIVE)) == 0);
const bool recursive = (flags & VFS_DIR_RECURSIVE) != 0;
char filter_buf[PATH_MAX];
const char* filter = user_filter;
bool user_filter_wants_dirs = true;
if(user_filter)
{
if(user_filter[0] != '/')
user_filter_wants_dirs = false;
// we need subdirectories and the caller hasn't already requested them
if(recursive && !user_filter_wants_dirs)
{
snprintf(filter_buf, sizeof(filter_buf), "/|%s", user_filter);
filter = filter_buf;
}
}
// note: FIFO queue instead of recursion is much more efficient
// (less stack usage; avoids seeks by reading all entries in a
// directory consecutively)
std::queue<const char*> dir_queue;
dir_queue.push(file_make_unique_fn_copy(start_path));
// for each directory:
do
{
// get current directory path from queue
// note: can't refer to the queue contents - those are invalidated
// as soon as a directory is pushed onto it.
PathPackage pp;
(void)path_package_set_dir(&pp, dir_queue.front());
dir_queue.pop();
Handle hdir = vfs_dir_open(pp.path);
if(hdir <= 0)
{
debug_warn("vfs_open_dir failed");
continue;
}
// for each entry (file, subdir) in directory:
DirEnt ent;
while(vfs_dir_next_ent(hdir, &ent, filter) == 0)
{
// build complete path (DirEnt only stores entry name)
(void)path_package_append_file(&pp, ent.name);
const char* atom_path = file_make_unique_fn_copy(pp.path);
if(DIRENT_IS_DIR(&ent))
{
if(recursive)
dir_queue.push(atom_path);
if(user_filter_wants_dirs)
cb(atom_path, &ent, context);
}
else
cb(atom_path, &ent, context);
}
vfs_dir_close(hdir);
}
while(!dir_queue.empty());
return ERR_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
@ -643,7 +511,7 @@ static LibError VIo_reload(VIo* vio, const char* UNUSED(fn), Handle UNUSED(h))
off_t ofs = vf->ofs;
vf->ofs += (off_t)size;
return xfile_io_validate(&vf->f, ofs, size, buf, &vio->io);
return xfile_io_issue(&vf->f, ofs, size, buf, &vio->io);
}
static LibError VIo_validate(const VIo* vio)

View File

@ -56,6 +56,7 @@ LibError file_open_vfs(const char* V_path, uint flags, TFile* tf,
static const FileProvider_VTbl archive_vtbl =
{
vtbl_magic,
0,0,0, // not supported for archives ATM
afile_open_vfs, afile_close, afile_validate,
afile_io_issue, afile_io_has_completed, afile_io_wait, afile_io_discard, afile_io_validate,
afile_read,
@ -65,12 +66,24 @@ static const FileProvider_VTbl archive_vtbl =
static const FileProvider_VTbl file_vtbl =
{
vtbl_magic,
dir_open, dir_next_ent, dir_close,
file_open_vfs, file_close, file_validate,
file_io_issue, file_io_has_completed, file_io_wait, file_io_discard, file_io_validate,
file_io,
file_map, file_unmap
};
// see FileProvider_VTbl decl for details on why this is so empty.
static const FileProvider_VTbl tree_vtbl =
{
vtbl_magic,
tree_dir_open, tree_dir_next_ent, tree_dir_close,
0, 0, 0,
0, 0, 0, 0, 0,
0,
0, 0
};
// rationale for not using virtual functions for file_open vs afile_open:
@ -91,6 +104,36 @@ static LibError vtbl_validate(const FileProvider_VTbl* vtbl)
#define CHECK_VTBL(type) RETURN_ERR(vtbl_validate(type))
//
// directory entry enumeration
//
LibError xdir_open(const char* dir, DirIterator* di)
{
// HACK: it is unclear ATM how to set this properly. assume tree_dir_* is
// the only user ATM.
di->type = &tree_vtbl;
CHECK_VTBL(di->type);
return di->type->dir_open(dir, di);
}
LibError xdir_next_ent(DirIterator* di, DirEnt* ent)
{
CHECK_VTBL(di->type);
return di->type->dir_next_ent(di, ent);
}
LibError xdir_close(DirIterator* di)
{
CHECK_VTBL(di->type);
return di->type->dir_close(di);
}
//
// file object
//
bool xfile_is_open(const File* f)
{
// not currently in use
@ -101,11 +144,6 @@ bool xfile_is_open(const File* f)
return true;
}
//
// file object
//
LibError xfile_open(const char* V_path, uint flags, TFile* tf, File* f)
{
// find out who is providing this file
@ -116,7 +154,7 @@ char c = mount_get_type(m);
const FileProvider_VTbl* vtbl = (c == 'F')? &file_vtbl : &archive_vtbl;
CHECK_VTBL(vtbl);
RETURN_ERR(vtbl->open(V_path, flags, tf, f));
RETURN_ERR(vtbl->file_open(V_path, flags, tf, f));
// success
// note: don't assign these unless we succeed to avoid the
@ -133,7 +171,7 @@ LibError xfile_close(File* f)
// note: this takes care of checking the vtbl.
if(!xfile_is_open(f))
return ERR_OK;
LibError ret = f->type->close(f);
LibError ret = f->type->file_close(f);
f->type = 0;
return ret;
}
@ -141,15 +179,15 @@ LibError xfile_close(File* f)
LibError xfile_validate(const File* f)
{
CHECK_VTBL(f->type);
return f->type->validate(f);
return f->type->file_validate(f);
}
//
// async IO
// IO
//
LibError xfile_io_validate(File* f, off_t ofs, size_t size, void* buf, FileIo* io)
LibError xfile_io_issue(File* f, off_t ofs, size_t size, void* buf, FileIo* io)
{
io->type = f->type;
CHECK_VTBL(io->type);
@ -180,11 +218,6 @@ LibError xfile_io_validate(const FileIo* io)
return io->type->io_validate(io);
}
//
// sync IO
//
ssize_t xfile_io(File* f, off_t ofs, size_t size, FileIOBuf* pbuf, FileIOCB cb, uintptr_t ctx)
{
CHECK_VTBL(f->type);

View File

@ -30,20 +30,28 @@ struct FileProvider_VTbl
// note: no need to store name of this provider for debugging purposes;
// that can be deduced from the function pointers below.
// directory entry enumeration
// note: these don't really fit in with the other methods.
// they make sense for both the VFS tree as well as the concrete
// file providers underlying it. due to this overlap and to allow
// file.cpp's next_ent function to access dir_filtered_next_ent,
// it is included anyway.
LibError (*dir_open)(const char* dir, DirIterator* di);
LibError (*dir_next_ent)(DirIterator* di, DirEnt* ent);
LibError (*dir_close)(DirIterator* di);
// file objects
LibError (*open)(const char* V_path, uint flags, TFile* tf, File* f);
LibError (*close)(File* f);
LibError (*validate)(const File* f);
LibError (*file_open)(const char* V_path, uint flags, TFile* tf, File* f);
LibError (*file_close)(File* f);
LibError (*file_validate)(const File* f);
// async IO
LibError (*io_issue)(File* f, off_t ofs, size_t size, void* buf, FileIo* xio);
int (*io_has_completed)(FileIo* xio);
LibError (*io_wait)(FileIo* xio, void*& p, size_t& size);
LibError (*io_discard)(FileIo* xio);
LibError (*io_validate)(const FileIo* xio);
// sync IO
ssize_t (*io)(File* f, off_t ofs, size_t size, FileIOBuf* pbuf, FileIOCB cb, uintptr_t ctx);
// IO
LibError (*io_issue)(File* f, off_t ofs, size_t size, void* buf, FileIo* io);
int (*io_has_completed)(FileIo* io);
LibError (*io_wait)(FileIo* io, void*& p, size_t& size);
LibError (*io_discard)(FileIo* io);
LibError (*io_validate)(const FileIo* io);
ssize_t (*io)(File* f, off_t ofs, size_t size, FileIOBuf* pbuf, FileIOCB cb, uintptr_t ctx);
// file mapping
LibError (*map)(File* f, void*& p, size_t& size);
@ -51,19 +59,21 @@ struct FileProvider_VTbl
};
extern bool xfile_is_open(const File* f);
extern LibError xdir_open(const char* dir, DirIterator* di);
extern LibError xdir_next_ent(DirIterator* di, DirEnt* ent);
extern LibError xdir_close(DirIterator* di);
extern bool xfile_is_open(const File* f);
extern LibError xfile_open(const char* V_path, uint flags, TFile* tf, File* f);
extern LibError xfile_close(File* f);
extern LibError xfile_validate(const File* f);
extern LibError xfile_io_validate(File* f, off_t ofs, size_t size, void* buf, FileIo* xio);
extern int xfile_io_has_completed(FileIo* xio);
extern LibError xfile_io_wait(FileIo* xio, void*& p, size_t& size);
extern LibError xfile_io_discard(FileIo* xio);
extern LibError xfile_io_validate(const FileIo* xio);
extern ssize_t xfile_io(File* f, off_t ofs, size_t size, FileIOBuf* pbuf, FileIOCB cb, uintptr_t ctx);
extern LibError xfile_io_issue(File* f, off_t ofs, size_t size, void* buf, FileIo* io);
extern int xfile_io_has_completed(FileIo* io);
extern LibError xfile_io_wait(FileIo* io, void*& p, size_t& size);
extern LibError xfile_io_discard(FileIo* io);
extern LibError xfile_io_validate(const FileIo* io);
extern ssize_t xfile_io(File* f, off_t ofs, size_t size, FileIOBuf* pbuf, FileIOCB cb, uintptr_t ctx);
extern LibError xfile_map(File* f, void*& p, size_t& size);
extern LibError xfile_unmap(File* f);

View File

@ -600,7 +600,7 @@ LibError tree_lookup(const char* path, TFile** pfile, uint flags)
// rationale: see DirIterator definition in file.h.
struct TreeDirIterator_
struct TreeDirIterator
{
TChildren::iterator it;
@ -612,12 +612,12 @@ struct TreeDirIterator_
TDir* td;
};
cassert(sizeof(TreeDirIterator_) <= sizeof(TreeDirIterator));
cassert(sizeof(TreeDirIterator) <= DIR_ITERATOR_OPAQUE_SIZE);
LibError tree_dir_open(const char* path_slash, TreeDirIterator* d_)
LibError tree_dir_open(const char* path_slash, DirIterator* di)
{
TreeDirIterator_* d = (TreeDirIterator_*)d_;
TreeDirIterator* tdi = (TreeDirIterator*)di->opaque;
TDir* td;
CHECK_ERR(tree_lookup_dir(path_slash, &td));
@ -631,21 +631,21 @@ LibError tree_dir_open(const char* path_slash, TreeDirIterator* d_)
// more overhead (we have hundreds of directories) and is unnecessary.
tree_lock();
d->it = td->begin();
d->end = td->end();
d->td = td;
tdi->it = td->begin();
tdi->end = td->end();
tdi->td = td;
return ERR_OK;
}
LibError tree_dir_next_ent(TreeDirIterator* d_, DirEnt* ent)
LibError tree_dir_next_ent(DirIterator* di, DirEnt* ent)
{
TreeDirIterator_* d = (TreeDirIterator_*)d_;
TreeDirIterator* tdi = (TreeDirIterator*)di->opaque;
if(d->it == d->end)
if(tdi->it == tdi->end)
return ERR_DIR_END; // NOWARN
const TNode* node = *(d->it++);
const TNode* node = *(tdi->it++);
ent->name = node->name;
// set size and mtime fields depending on node type:
@ -672,7 +672,7 @@ LibError tree_dir_next_ent(TreeDirIterator* d_, DirEnt* ent)
}
LibError tree_dir_close(TreeDirIterator* UNUSED(d))
LibError tree_dir_close(DirIterator* UNUSED(d))
{
tree_unlock();

View File

@ -91,15 +91,9 @@ extern LibError tree_lookup(const char* path, TFile** ptf, uint flags = 0);
extern LibError tree_lookup_dir(const char* path, TDir** ptd, uint flags = 0);
// documentation and rationale: see file.h's dir_next_ent interface
struct TreeDirIterator
{
char opaque[32];
};
extern LibError tree_dir_open(const char* path_slash, TreeDirIterator* d);
extern LibError tree_dir_next_ent(TreeDirIterator* d, DirEnt* ent);
extern LibError tree_dir_close(TreeDirIterator* d);
extern LibError tree_dir_open(const char* path_slash, DirIterator* di);
extern LibError tree_dir_next_ent(DirIterator* di, DirEnt* ent);
extern LibError tree_dir_close(DirIterator* di);
// given a file that is stored on disk and its VFS path,

View File

@ -600,7 +600,7 @@ LibError zip_archive_create(const char* zip_filename, ZipArchive** pza)
RETURN_ERR(file_open(zip_filename, FILE_WRITE|FILE_NO_AIO, &za_copy.f));
RETURN_ERR(pool_create(&za_copy.cdfhs, 10*MiB, 0));
ZipArchive* za = (ZipArchive*)za_mgr.alloc();
ZipArchive* za = za_mgr.alloc();
if(!za)
WARN_RETURN(ERR_NO_MEM);
*za = za_copy;