From 2bd370833961ac8d19c5644b87b1f1667db731cb Mon Sep 17 00:00:00 2001 From: janwas Date: Tue, 25 Apr 2006 17:35:35 +0000 Subject: [PATCH] # VFS: add support for redirecting writes of files that are in archives to writable mod directory (required for editor) This was SVN commit r3818. --- source/lib/lib_errors.h | 5 +-- source/lib/res/file/file.h | 10 ++++-- source/lib/res/file/vfs.cpp | 7 ++-- source/lib/res/file/vfs.h | 9 +++++ source/lib/res/file/vfs_mount.cpp | 56 ++++++++++++++++++++++++++++++- source/lib/res/file/vfs_mount.h | 4 +++ source/lib/res/file/vfs_tree.cpp | 5 +++ source/lib/res/file/vfs_tree.h | 1 + 8 files changed, 88 insertions(+), 9 deletions(-) diff --git a/source/lib/lib_errors.h b/source/lib/lib_errors.h index 66b81f6202..dea8aa70b1 100644 --- a/source/lib/lib_errors.h +++ b/source/lib/lib_errors.h @@ -438,8 +438,9 @@ ERR(-100330, ERR_IO, "Error during IO") ERR(-100331, ERR_EOF, "Reading beyond end of file") // .. mount ERR(-100340, ERR_ALREADY_MOUNTED, "Directory (tree) already mounted") -ERR(-100341, ERR_INVALID_MOUNT_TYPE, "Invalid mount type (memory corruption?)") -ERR(-100342, ERR_ROOT_DIR_ALREADY_SET, "Attempting to set FS root dir more than once") +ERR(-100341, ERR_NOT_MOUNTED, "Specified directory is not mounted") +ERR(-100342, ERR_INVALID_MOUNT_TYPE, "Invalid mount type (memory corruption?)") +ERR(-100343, ERR_ROOT_DIR_ALREADY_SET, "Attempting to set FS root dir more than once") // .. misc ERR(-100350, ERR_UNKNOWN_CMETHOD, "Unknown/unsupported compression method") ERR(-100351, ERR_IS_COMPRESSED, "Invalid operation for a compressed file") diff --git a/source/lib/res/file/file.h b/source/lib/res/file/file.h index 007ca26065..b961f0cc38 100644 --- a/source/lib/res/file/file.h +++ b/source/lib/res/file/file.h @@ -269,9 +269,13 @@ enum FileFlags // promising they will set atom_fn). FILE_DONT_SET_FN = 0x80, - // sum of all flags above. used when validating flag parameters and - // by zip.cpp because its flags live alongside these. - FILE_FLAG_ALL = 0xFF + // (only relevant for VFS) file will be written into the + // appropriate subdirectory of the mount point established by + // vfs_mod_set_write_target. see documentation there. + FILE_WRITE_TO_MOD = FILE_WRITE|0x100, + + // sum of all flags above. used when validating flag parameters. + FILE_FLAG_ALL = 0x1FF }; diff --git a/source/lib/res/file/vfs.cpp b/source/lib/res/file/vfs.cpp index d8eecfca5c..375f8b0704 100644 --- a/source/lib/res/file/vfs.cpp +++ b/source/lib/res/file/vfs.cpp @@ -360,9 +360,7 @@ LibError vfs_stat(const char* V_path, struct stat* s) } - - - +//----------------------------------------------------------------------------- struct VFile { @@ -423,6 +421,9 @@ static LibError VFile_reload(VFile* vf, const char* V_path, Handle) return err; } + if(flags & FILE_WRITE_TO_MOD) + RETURN_ERR(set_mount_to_mod_target(tf)); + RETURN_ERR(xfile_open(V_path, flags, tf, &vf->f)); stats_open(vf->f.atom_fn, vf->f.size); diff --git a/source/lib/res/file/vfs.h b/source/lib/res/file/vfs.h index 37f99173a2..7b3cc0ec51 100644 --- a/source/lib/res/file/vfs.h +++ b/source/lib/res/file/vfs.h @@ -288,6 +288,15 @@ extern LibError vfs_mount(const char* V_mount_point, const char* P_real_dir, uin // unmount a previously mounted item, and rebuild the VFS afterwards. extern LibError vfs_unmount(const char* name); +// set current "mod write directory" to P_target_dir, which must +// already have been mounted into the VFS. +// all files opened for writing with the FILE_WRITE_TO_MOD flag set will +// be written into the appropriate subdirectory of this mount point. +// +// this allows e.g. the editor to write files that are already +// stored in archives, which are read-only. +extern LibError vfs_mod_set_write_target(const char* P_target_dir); + // // directory entry diff --git a/source/lib/res/file/vfs_mount.cpp b/source/lib/res/file/vfs_mount.cpp index 2df8e5b6d3..afc2060c34 100644 --- a/source/lib/res/file/vfs_mount.cpp +++ b/source/lib/res/file/vfs_mount.cpp @@ -676,7 +676,7 @@ struct IsArchiveMount { bool operator()(const Mount& m) const { - return (m.archive > 0); + return (m.type == MT_ARCHIVE); } }; @@ -740,6 +740,60 @@ LibError mount_make_vfs_path(const char* P_path, char* V_path) } + + +static const Mount* mod_target; + +// set current "mod write directory" to P_target_dir, which must +// already have been mounted into the VFS. +// all files opened for writing with the FILE_WRITE_TO_MOD flag set will +// be written into the appropriate subdirectory of this mount point. +// +// this allows e.g. the editor to write files that are already +// stored in archives, which are read-only. +LibError vfs_mod_set_write_target(const char* P_target_dir) +{ + for(MountIt it = mounts.begin(); it != mounts.end(); ++it) + { + const Mount& m = *it; + // skip if not a directory mounting + if(m.type != MT_FILE) + continue; + + // found it in list of mounted dirs + if(!strcmp(m.P_name.c_str(), P_target_dir)) + { + mod_target = &m; + return ERR_OK; + } + } + + WARN_RETURN(ERR_NOT_MOUNTED); +} + + +// 'relocate' tf to the mounting established by vfs_mod_set_write_target. +// call if is being opened with FILE_WRITE_TO_MOD flag set. +LibError set_mount_to_mod_target(TFile* tf) +{ + if(!mod_target) + WARN_RETURN(ERR_NOT_MOUNTED); + + tfile_set_mount(tf, mod_target); + + // invalidate the previous values. we don't need to be clever and + // set size to that of the file in the new mod_target mount point. + // this is because we're only called for files that are being + // opened for writing, which will change these values anyway. + tree_update_file(tf, 0, 0); + + return ERR_OK; +} + + + + + void mount_init() { tree_init(); diff --git a/source/lib/res/file/vfs_mount.h b/source/lib/res/file/vfs_mount.h index d4413b08b7..bac16da9f0 100644 --- a/source/lib/res/file/vfs_mount.h +++ b/source/lib/res/file/vfs_mount.h @@ -95,6 +95,10 @@ extern LibError mount_populate(TDir* td, RealDir* rd); // because this call leaves the VFS in limbo!! extern void mount_release_all_archives(); +// 'relocate' tf to the mounting established by vfs_mod_set_write_target. +// call if is being opened with FILE_WRITE_TO_MOD flag set. +extern LibError set_mount_to_mod_target(TFile* tf); + // rebuild the VFS, i.e. re-mount everything. open files are not affected. // necessary after loose files or directories change, so that the VFS diff --git a/source/lib/res/file/vfs_tree.cpp b/source/lib/res/file/vfs_tree.cpp index efb19b09ba..42a9150fa3 100644 --- a/source/lib/res/file/vfs_tree.cpp +++ b/source/lib/res/file/vfs_tree.cpp @@ -702,6 +702,11 @@ const char* tfile_get_atom_fn(const TFile* tf) +void tfile_set_mount(TFile* tf, const Mount* m) +{ + tf->m = m; +} + void tree_update_file(TFile* tf, off_t size, time_t mtime) { tf->size = size; diff --git a/source/lib/res/file/vfs_tree.h b/source/lib/res/file/vfs_tree.h index 00b783cdc0..fc4e878b7d 100644 --- a/source/lib/res/file/vfs_tree.h +++ b/source/lib/res/file/vfs_tree.h @@ -113,6 +113,7 @@ extern const Mount* tfile_get_mount(const TFile* tf); extern uintptr_t tfile_get_memento(const TFile* tf); extern const char* tfile_get_atom_fn(const TFile* tf); +extern void tfile_set_mount(TFile* tf, const Mount* m); extern void tree_update_file(TFile* tf, off_t size, time_t mtime); struct RealDir;