Running a process inside a virtual file system? - c++

What I'm trying to achieve is to run a program, which thinks a folder exists within its own folder while actually the folder is somewhere else on the system.
So my program would launch a process and say to the process: Folder A which is at C:\A is within your own directory at C:\Program Files (x86)\SomeProgram\A
So the "virtual" directory would only be visible to that process.
I'm using Qt to program my program, so if there are any Qt functions I could use that would be great (in relation to portability). However, plan C++ or any windows-bound API's would be fine.
I was thinking about NTFS junctions or symbolic links but I would have no idea how to create either of those in C++, let alone bind them to a specific process.
Thanks in advance!
EDIT:
In relation to the above, I've found this question: https://superuser.com/questions/234422/does-windows7-support-symbolic-links-folder-shortcuts. However, it only shows how to perform the required actions from the command-line and it wouldn't be process bound.
EDIT 2:
Some extra information: I'm trying to create a virtual directory that is made up of a couple of other directories but then merged (I'm using a priority system to decide which files "win" from other files). These merged directories would then appear to the target process as one directory containing the merged files.

I think I'm going to stick with Window's mklink command. It seems to suit my needs the best.
What I'm going to do is use QFile::link() on all operating systems that aren't Windows, and QProcess with mklink on windows. This should work on every operating system.
For a good example look here: https://stackoverflow.com/a/21013935/979732

Such tasks are accomplished by use of a filesystem filter driver. The driver intercepts OS requests going to the filesystem and lets you insert your own virtual files and directories into the existing directory on the disk. Filter driver can be an overkill for your particular task, though.
Detours approach mentioned in comments requires system-wide hooking of file APIs and will slowdown the whole system(filesystem filter driver is attached to one disk and it's a documented approach, so it's faster and more robust).

Related

How to specify a standard directory in a Qt project file

I have developed an application that I plan to deploy on Windows, Mac, and Linux. The program requires access to some files (scripts and the like) at run-time.
The installation process should install the files to a location that my application can later determine without user-intervention (or perhaps just a prompt allowing the user to change the location, if desired).
What is the best way to achieve this? I can't seem to find any way to:
1. Use a "standardized path" variable in the project file's INSTALLS statement. (e.g., my application could use QStandardPaths to initialize the location, but I can't figure out how to access this path from the INSTALLS statement)
2. Save the path to my project's QSettings (.plist, registry, whatever) for later retrieval
That leaves me with creating a custom project file and INSTALLS command for each environment, and then I still can't install to the user's directory because I don't know the user's name when I deploy the make command. It seems as if there must be a better way, but I can't seem to find any documentation for this. Am I just using the wrong keywords in my searches? Thanks in advance!
What standard directory? What type of getting that standard directory?
For instance, you can put such thing in your windows branch of .pro file:
win32 {
APPDATA_DIR = $$system(echo %APPDATA%) # should be %LOCALAPPDATA% as requested
message($$APPDATA_DIR)
}
Just unsure of what exact kind of standartized path you are talking about. QStandardPaths knows many. It makes sense to be more concrete to find the correspondence with concrete OS.
Also somewhat relative reply on mine, on how to check the correspondence with certain variable, etc: Qt .pro file - how to add conditioning on OSX version?
Maybe this class will help you
QStandardPaths documentation
But your problem is still little bit unclear for me.

c++ find main operation system directory

I am trying to create file in main directory of operation system(for example Windows in my "c" disk) using c++.
Is there any better way than iterating all disks and search for "Windows" folder? Also its similar in mac and linux?
In Windows, you can call GetWindowsDirectory function (link). In Linux and Mac (I think), there's no such thing as main system directory.
However, as David noted, you should not put any files there:
This function is provided primarily for compatibility with legacy applications. New applications should store code in the Program Files folder and persistent data in the Application Data folder in the user's profile. For more information, see ShGetFolderPath.

g++: Use ZIP files as input

We have the Boost library in our side. It consists of a huge number of files which never change and only a tiny portion of it is used. We swap the whole boost directory if we are changing versions. Currently we have the Boost sources in our SVN, file by file which makes the checkout operations very slow, especially on Windows.
It would be nice if there were a notation / plugin to address C++ files inside ZIP files, something like:
// #ZIPFS ASSIGN 'boost' 'boost.zip/boost'
#include <boost/smart_ptr/shared_ptr.hpp>
Are there any support for compiler hooks in g++? Are there any effort regarding ZIP support? Other ideas?
I assume that make or a similar buildsystem is involved in the process of building your software. I'd put the zip file in the repository, and add a rule to the Makefile to extract it before the actual build starts.
For example, suppose your zip file is in the source tree at "external/boost.zip", and it shall be extracted to "external/boost", and it contains at its toplevel a file "boost_version.h".
# external/Makefile
unpack_boost: boost/boost_version.h
boost/boost_version.h: boost.zip
unzip $<
I don't know the exact syntax of the unzip call, ask your manpage about this.
Then in other Makefiles, you can let your source files depend on the unpack_boost target in order to have make unpack Boost before a source file is compiled.
# src/Makefile (excerpt)
unpack_boost:
make -C ../external unpack_boost
source_file.cpp: unpack_boost
If you're using a Makefile generator (or an entirely different buildsystem), please check the documentation for these programs for how to create something like the custom target unpack_boost. For example, in CMake, you can use the add_custom_command directive.
The fine print: The boost/boost_version.h file is not strictly necessary for the Makefile to work. You could just put the unzip command into the unpack_boost target, but then the target would effectively be phony, that is: it would be executed during each build. The file inbetween (which of course you need to replace by a file which is actually present in the zip archive) ensures that unzip only runs if necessary.
A year ago I was in the same position as you. We kept our source in SVN and, even worse, included boost in the same repository (same branch) as our own code. Trying to work on multiple branches was impossible, as it would take most of a day to check-out a fresh working copy. Moving boost into a separate vendor repository helped, but it would still take hours to check-out.
I switched the team over to git. To give you an idea of how much better it is than SVN, I have just created a repository containing the boost 1.45.0 release, then cloned it over the network. (Cloning copies all of the repository history, which in this case is a single commit, and creates a working copy.)
That clone took six minutes.
In the first six seconds a compressed copy of the repository was copied to my machine. The rest of the time was spent writing all of those tiny files.
I heartily recommend that you try git. The learning curve is steep, but I doubt you'll get much pre-compiler hacking done in the time it would take to clone a copy of boost.
We've been facing similar issues in our company. Managing boost versions in build environments is never going to be easy. With 10+ developers, all coding on their own system(s), you will need some kind of automation.
First, I don't think it's good idea to store copies of big libraries like boost in SVN or any SCM system for that matter, that's not what those systems are designed for, except if you plan to modify code in boost yourself. But let's assume you're not doing that.
Here's how we manage it now, after trying lots of different methods, this works best for us.
For every version of boost that we use, we put the whole tree (unzipped) on a file server and we add extra subdirectories, one for each architecture/compiler-combination, where we put the compiled libraries.
We keep copies of these trees on every build system and in the global system environment we add variables like:
BOOST_1_48=C:\boost\1.48 # Windows environment var
or
BOOST_1_48=/usr/local/boost/1.48 # Linux environment var, e.g. in /etc/profile.d/boost.sh
This directory contains the boost tree (boost/*.hpp) and the added precompiled libs (e.g. lib/win/x64/msvc2010/libboost_system*.lib, ...)
All build configurations (vs solutions, vs property files, gnu makefiles, ...) define an internal variable, importing the environment vars, like:
BOOSTROOT=$(BOOST_1_48) # e.g. in a Makefile, or an included Makefile
and further build rules all use the BOOSTROOT setting for defining include paths and library search paths, e.g.
CXXFLAGS += -I$(BOOSTROOT)
LFLAGS += -L$(BOOSTROOT)/lib/linux/x64/ubuntu/precise
LFLAGS += -lboost_date_time
The reason for keeping local copies of boost is compilation speed. It takes up quite a bit of disk space, especially the compiled libs, but storage is cheap and a developer losing lots of time compiling code is not. Plus, this only needs to be copied once.
The reason for using global environment vars is that build configurations are transferrable from one system to another, and can thus be safely checked in to your SCM system.
To smoothen things a bit, we've developed a little tool that takes care of the copying and setting the global environment. With a CLI, this can even be included in the build process.
Different working environments mean different rules and cultures, but believe me, we've tried lots of things and finally, we decided to define some kind of convention. Maybe ours can inspire you...
This is something you would not do in g++, because any other application that wants to do it would also have to be modified.
Store the files on a compressed filesystem. Then every application gets the benefit automatically.
It should be possible in an OS to allow transparent access to files inside a ZIP file. I know that I put it in the design of my own OS a long time ago (2004 or so) but never got it to a point where it was usable. The downside is that seeking backwards in a file inside a ZIP is slower as it's compressed (and you can't rewind the compressor state, so you have to seek from the start instead). This also makes using a zip-inside-a-zip slow for rewinding and reading. Fortunately, most cases just read a file sequentially.
It should also be retrofittable to current OSes, at least in client space. You can hook the filesystem access functions used (fopen, open, ...) and add a set of virtual file descriptors that your own software would return for a given filename. If it's a real file just pass it on, if it's not open the underlying file (possibly again via this very function) and pass a virtual handle. When accessing the file contents, read directly from the zip file without caching.
On Linux you would use an LD_PRELOAD to inject it into existing software (at usage time), on Windows you can hook the system calls or inject a DLL into the space of software to hook the same functions.
Does anybody know if this already exists? I can't see any clear reason it wouldn't...

I can't go to a directory with C++

I need to change working directory of my project, so that output files go to a certain folder, not where all the project files are.
I'm using
system("cd secretdir/");
system("ls");
However, what I get, is the list of files in current project directory, not the "secretdir" one.
I'm on Mac OS X 10.6/Qt Creator 4.7 64 bit
Thanks!
You have to change the current working directory
http://www.linuxquestions.org/questions/programming-9/how-to-change-current-working-directory-in-c-550031/
Also, you should consider saving your output files with full path names instead of changing the working directory.
Your current code will spawn a subshell that will change its current directory to ./secretdir, then proceed to exit() without doing anything else.
Only then will ls run in another subshell, whose current directory is, of course, completely independent of what you did during your previous call to system().
That's probably where your problem lies. Are you looking for the chdir() function?
chdir("secretdir");
// From now on, the current directory of the process is `./secretdir`.
system("ls"); // Will probably behave as expected.
edit See Falmarri's response as I glossed over the first sentence of your question.
You can also use chdir
the following is crufty
The first system spawns a new process that does the cd. The second system spawns a completely different process that doesn't know what happened previously.
One thing you could do is:
system("ls secretdir/");
I'd highly recommend checking out QDir, QFile, and QProcess objects in the QT Creator help or online documentation since you are using it. They have very detailed and easy to understand documentation and using the tools available to you in QT should be a primary reason for choosing that tool much of QT rivals boost in portability and usability in my limited experience.
Also there is a great community for QT related questions at QTForum worth bookmarking especially if QT Creator is your primary development environment.
Using system should be avoided as general rule of thumb it is inefficient and insecure in many cases.
EDIT: Sorry I too glossed over your first sentence and jumped to the code bits. You can modify the project settings via the Projects tab in QT Creator to add a Custom Process step to the build where you can specify a working directory and then do a copy command to wherever you would like your output to go. You also may be able to specify a build output option within your .pro file directly ... once again the help and documentation is your friend however.
The function on Mac OSX is chdir("./secretdir"), although since it's a POSIX API it actually works the same on many other platforms as well.
Using system() is not portable so try to avoid to use directly "cd" like that. My advice is to use Boost filesystem.
There is a Two-minutes Tutorial !
Do
system("cd secretdir/; ls");
Or better yet use boost's filesystem library. Maybe just opendir.

Detect executable folder from SDL

I am creating a C++ SDL game engine, and it is relevant to know the executable path since images and other resources are not stored within the executable - they are in a separated folder("res/").
Under Linux, I am using a shell script "rungame.sh" that cd's to the executable path and then runs the executable(using then "./" to reference the executable folder).
However, I believe this is an "ugly" approach and I want it to be Windows-compatible.
Also, the current approach is not very good as it may change the meaning of some command line arguments.
I want a cross-platform(*NIX, Windows and Mac OS X, if possible) solution to get the current path of the executable. The game path/executable name may change.
What is the cleanest way to solve my problem (preferrably using std::string and as few platform-dependent APIs as possible)?
Since SDL 2.0.1 there's SDL_GetBasePath.
I strongly suggest searching before posting: How do I get the directory that a program is running from?
physicsfs has PHYSFS_getBaseDir():
Get the path where the application resides.
Helper function.
Get the "base dir". This is the directory where the application was
run from, which is probably the installation directory, and may or may
not be the process's current working directory.
You should probably use the base dir in your search path.