C++ / Qt: track filesystem changes - c++

I'm currently trying to implement a c++ program which monitors a folder on the filesystem. On initalizing the application, it scans the Directory and saves some meta information about it.
when something is chenged while the program is active, i can read changes to the folder (for examlpe changing the name of a folder or a file). But i can't track changes to the Directory while the program isn't running. Upon startup i would get
Removed folder X
Added folder Y
instead of
Renamed folder X to Y
is it possible to identify a directory in another way than it's path/name?
if yes, how would i gather that information in C++ / Qt ?

Rather than reinventing the wheel, you could just use the class QFileSystemWatcher which the Qt docs states: -
The QFileSystemWatcher class provides an interface for monitoring
files and directories for modifications
If you want the program to run all the time, then you may want to look at creating a service (in Windows) or daemon (Linux / OSX).

This is filesystem-specific, but generally yes this is possible. FAT is the main exception, I think. But you won't find code for this in the C++ Standard Library or Qt. It's just too unusual, so you'll need OS-specific code if not filesystem-specific.

Like TheDarkNight said, you need to use QFileSystemWatcher to avoid portability and so other problem.
But if you want to continue your approach:
In GNU/Linux land, you can check this with inode struct of directory (take care of symbolic link issue).
inode struct have an index for example you can get it on shell with:
ls -id /path/to/your/folder
There is an API to access inode. You can google inode struct linux for it.
In Windows garden, you can get file id when accessing handle in the struct BY_HANDLE_FILE_INFORMATION:
nFileIndexHigh
The high-order part of a unique identifier that is associated with a file.
For more information, see nFileIndexLow.
nFileIndexLow
The low-order part of a unique identifier that is associated with a file.

Related

QT5 - Detecting when new files are added to a directory and retrieving their path

My problem is relatively simple. I have an application where I need to monitor a particular folder (the downloads folder, in my case) for added files. Whenever a file is added to that folder, I want to move that file to a completely different directory. I have been looking at QFileSystemWatcher; however, none of the signals it provides seems to be ideal for my situation.
Here is my current code:
connect(&m_fileWatcher, &QFileSystemWatcher::directoryChanged, this, &FileHandler::directoryChanged);
void FileHandler::directoryChanged(const QString &dir)
{
qDebug() << "File changed...." << string;
// Some other logic
}
This signal only gives me a string to work with which is the directory that witnessed a change. I don't know what kind of change took place (add, rename, or delete), and I also have no idea which file has changed.
I understand that I could store all of the files in the directory in some sort of data structure and do some other logic when this signal is emitted, but that doesn't seem very performant in this case since I'm dealing with the user's downloads folder (which could contain thousands of files).
How can I make this work? Should I refer to a different helper class provided by QT, or is there some other way I can do this while utilizing QFileSystemWatcher? I'm simply just looking for ideas.
Thank you.
You’ve hit the limit of what the underlying OS provides: notification of change to the content of a directory.
If you wish to identify the file:
deleted you must have a prior list of files available for compare
added same as deleted
modified loop through the directory for the file with the most recent last modified date
IDK if you wish to use any specific filename container class from Qt or just a std::vector <std::filesystem::path> or the like for your cached folder contents.
QFileSystemWatcher only notifies you that a change happened, but not the details of what was changed. So you will have to resort to OS-specific APIs to get the details. For instance, on Windows, you can use ReadDirectoryChangesW() instead of QFileSystemWatcher.

How to create virtual file system that file path can be accessed same as disk

I need to create FileSystem type of thing in memory or on disk, which can be accessed same as file on disk, which path is can be used in function like fopen(),etc.
Details:
I am using AddFontResourceEx function to load font in application. Since this function require file path so that file need to present on disk. But I've requirement, that the user cannot access/see the font file.
I tried AddFontMemResourceEx function, but the loaded font is not enumable so that user cannot see the font in the application. Also I tried with some library which create VFS, but they work like database, i.e you can create file/directory and access them. But cannot use their file path in AddFontResourceEx or any other function.
Is there exist some way by which I can create a Virtual FileSystem in memory or on disk which can be accessible through my application and I can write/read file on this virtual filesystem created and it's file path can be used by AddFontResourceEx function.
It can't really work. Yes, you can add a "virtual" file system. But either it's visible to user X or it isn't. Access Control on Windows works on a per-user base, not a per-program base. So, if user X can see the font in application A, he can also see it in application B - even if B is Explorer.EXE.
If the user is an administrator, you can't really prevent them from seeing the font file if they're determined enough. They could, for example, reverse engineer your program to figure out how you're generating the file and repeat the process by hand to make their own copy. Or (even if you could somehow tie the file permissions to your process) they could insert their own code into your process to retrieve the file, or to retrieve the font information directly from memory.
If it's good enough to make it difficult for them to see the font file, you could try this:
Create a directory in the temp folder, with write-only permission for the current user and no permissions for anyone else.
Create a sub-directory with a long, complex, cryptographically random name, and with full permission for the current user. (The name should be different each time.)
Write the font file to the sub-directory and load it.
Delete the font file and remove both directories.
The entire process should take only a fraction of a second, which should make it somewhat difficult for the user to override the permissions and retrieve the file. If they use a debugger to single-step through the program then I guess you're out of luck, but as I already pointed out, nothing's going to stop everyone.
Another option, presumably, would be to just use AddFontMemResourceEx and put up with the fact that the font isn't then enumerable. You'd just need to change your code so that wherever it enumerates fonts it adds your font(s) to the list manually.
If you didn't get the right answer, maybe you didn't ask the right question
Your post title mentions "virtual filesystem", but. later, you mention "accesing a font".
"Virtual Filesystems" its an ambiguos term used in several ways.
One common case, means adding devices or networks to an O.S.
In your case, seems like accesing from a an application.
There are several ways ( "libraries" ) to emulate or work with a filesystem.
Some of them work independent of the real filesystem. You work with them, save data in those "virtual" folders & files, and copy data from the real and the virtual one.
Some of them work, as a extension layer, between the real filesystem, and the programming filesystem.
Example: I worked with an application, that required temporally fast I.O. access. Found a library, that when you want to create a folder or save a file in the real filesystem, was done.
Additionally, I could add "virtual drives" that where stored in memory, but, accessed with file system operations. When the application finished, the "hard drives" and their data where erased from memory.
Its seems that your case is similar to my example.
What do you want a "virtual filesystem" library for ?
I have seen onb the web, several libraries, for C++, open source, freeware, and commercial.
It depends what do you want to do, to find out, which library its the better for your case.
Good Luck

File system libraries that allow mounting on an application level

I have been looking into libraries for a file system that will allow path mounting on purely an application level. This may not be called just "path mounting" since that has the connotation of os level path mounting, but something else, I am not sure of the terminology. I was hoping to be able to find a few but were unable to find anything to what I am looking for (boost::filesystem was the closest I found). I wanted to be able to compare several different libraries in hopes of seeing what advantages and disadvantages they have.
What I mean by a file system with path mounting is so I would have a path such as
"SomeRoot:data\file.txt"
and the "SomeRoot" would be replaced with C:\SomeFolder", which would be set to the file mount system.
Does anyone know of a file system that will allow path mounting?
Edit:
Since it appears that there may not be many libraries for this, I would also be interested in how to construct one properly.
If you are looking for an "application level file system" then at the most basic level, you are going to need to do a string replace. On the most basic level there are two strings
MountPoint
Which will be used as the "mount point", such as your SomeRoot.
MountResolve
Which is the location to what mount point is pointed at for when "resolving" a file location. This is the same as your C:\SomeFolder.
Besides for the obvious accessor and getters for those variables, there is the need for a function to resolve the path, which is this case can be
bool ResolvePath(const String& mountPath, String& resolvedPath);
The contents of the ResolvePath are very simple, all you need to do is replace the current MountPoint string in mountPath and place the result into resolvedPath.
resolvedPath = mountPath;
resolvedPath.replace(0, mMountPoint.size() + 1, mMountResolve.c_str(), mMountResolve.size());
However, there is more that can be done in that function. The reason why I have it returning a bool is because the function should fail mountPath does not have the MountPoint. To check, just do a simple string::find.
if(mountPath.find(mMountPoint) == String::npos)
return false;
With this, you can now resolve SomeRoot:data\file.txt to C:\SomeFolder\data\file.txt if MountResolve is set to C:\SomeFolder\. However, you mentioned without the trailing slash at the end. Since there is nothing to be currently done to verify that slash, your result would be C:\SomeFolderdata\file.txt. This is wrong.
On your access for setting the mount resolve, you want to check to see if there is there is a trailing folder slash. If there is not, then add it.
void FileSystem::SetMountResolve(const String& mountResolve)
{
mMountResolve = mountResolve;
if(*(mMountResolve.end() - 1) != FOLDERSLASH)
mMountResolve += FOLDERSLASH;
}
This will allow a basic "FileSystem" class to have one MountPoint/MountResolve. It will not be very difficult to extend this to allow multiple mount points either.
I have been looking into libraries for a file system that will allow path mounting
You should forget about it. mounting a path/drive can be blocked on linux (administrator privilegies might be required), and on windows there is no built-in mechanism for that (there are directory junctions, though). On certain distros you have to be root to mount even cdrom drive. Manually.
Does anyone know of a file system that will allow path mounting?
ntfs, ext3, jfs. Operation might require root/administrator privilegies.
and the "SomeRoot" would be replaced with C:\SomeFolder"
You need to use something similar to environmental variables in your program. Use "${SomeDir}/path" and replace ${SomeDir} with whatever you want. That'll be much easier to implement than mounting.
--EDIT--
What I mean by a file system with path mounting is so I would have a path such as
"SomeRoot:data\file.txt"
Provide custom wrapper for fopen or whatever you use instead. Or make custom class that implements "File". In that class/wrapper add support for "mounting" by doing search/replace on provided file path - possibly using collection of variables stored within the program. That's the easiest solution. Of course, you'll also have to wrap other file functions you'll use, but that's still much easier than doing cross-platform mounting.
You might also want to consider PhysicsFS. In essence, it is a library that abstracts the location of files. You may define a "search path" and whenever you read a file it is searched in those locations, i.e., folders or archives. For example, if you want to read "logo.png", it might be searched in locations such as:
C:\mygame\data
E:\mygame\data (read-only CD-ROM)
C:\mygame\data.zip
When writing a file, it is always stored in a special "write path".
PhysicsFS also has a concept of application-level mounting. Citing from their webpage:
PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary
points in the search path. If a zipfile contains "maps/level.map" and
you mount that archive at "mods/mymod", then you would have to open
"mods/mymod/maps/level.map" to access the file, even though
"mods/mymod" isn't actually specified in the .zip file. Unlike the
Unix mentality of mounting a filesystem, "mods/mymod" doesn't actually
have to exist when mounting the zipfile. It's a "virtual" directory.
And, of course, the whole solution is 100% user-space and requires no kernel support nor administrative privileges.
FUSE on Unix, FUSE4X on MacOS X, our Callback File System with FUSE adapter on Windows. There's no single cross-platform solution because the architecture of file system drivers is different on those platforms.
Seems like you are looking for symbolic links functionality.
On Posix systems, e.g. Linux/Unix you can look into link()/symlink(). This functionality has been there forever and is pretty solid.
On Windows you may want to look into CreateSymbolicLink() and company. These were introduced with Windows 2000 and I'm not sure how robust they are.
Actual mounting of filesystems is trickier business and really depends on what you are mounting - NTFS, FAT, ext3, XFS, NFS, CIFS, WebDAV, etc, etc.

program to monitor read/writes PATH of a program?

I was trying to make a program for a college project, but I got stuck at this:
How will you monitor a program as to what files it writes to or reads from?
I wish to have their path names.
To make the problem more clear, here is an example:
Consider the program we wish to monitor is a.exe, and a.exe first opens a file named "a1" residing in the same folder as a.exe, and then opens another file named "a2".
The program has to give the relative or absolute path of "a1" and "a2" files, irrespective of them being opened for read/write..
How do I implement this in C++?
EDIT : Is it possible to divert the calls for a1 and a2 files to another path??
EDIT2 : ok, let me put it this way: i have moved the firefox.exe from C:\program files to D:\, now when i run firefox.exe it wont work coz it works on many files that are there in C:\program files, firefox.exe would be using relative paths for accessing the files. What i intend to do is to capture the calls for the files firefox.exe works on and then direct the call to the program files folder. Plz let me know if i have made myself clear..
On linux you can you use 'strace' wich output the different system calls performed by your application. If you need to implement a program which perfoms the same kind of output as strace, a quick implementation could consists in a simple shell program which greps the output of strace. Otherwise looking into the strace code is a good start.
On Windows 'Process monitor' from Sysinternals suite may help you out.
If you want to modify the arguments to open(2), creat(2), truncate(2), and so forth, then you could use the Linux ptrace(2) facility to intercept the systemcalls and replace the filename strings before executing the call.
ptrace(2) is dark magic, so unless it's an advanced course, it might not be what your professor intended. (If the next lecture is on writing a debugger like gdb(1), then this is exactly what your professor intended.)
Another mechanism you can use, and probably much more portably, is library or function interpositioning -- you can write little wrappers around specific functions in a library, and by loading the library with the LD_PRELOAD environment variable (see the ld.so(8) manpage for details on the environment variables that influence library loading), your functions will be called instead of the standard functions.
Library interposition is grey magic; it's better documented than ptrace(2), but still pretty easy to screw up.

Cannot access INI files in "Program Files"

I wrote this C++ application that needs to check an INI file (“preference.ini”), and eventually modify it (e.g. if the user does not want to see the introduction form anymore). I created it in WinXP, and it works fine on the system where I compiled it (in many locations, including “Program Files”).
Problem:
In Win 7, it works fine if I put the complete program folder under “C”:\” (e.g. “C:\MyProgram”), but if I put it in “C:\Program Files (x86)\MyProgram”, it just retrieves some mysterious data (values not present in my INI file). When I change some settings and save them to file, it (apparently) save the changes (get no errors, but the changes are not there when I go and open the file...
I had some similar issue on a system with another WinXP system (not the one where I compiled it.
I used 'getcwd' to define the path at runtime, and I verified that it is getting it right, even under "Program Files (x86)":
char currentPath[MAXPATH];
getcwd(currentPath, MAXPATH);
std::string licensePath(currentPath);
licensePath.append("\\dat\\preference.ini");'
Any ideas? Thanks in advance for your help.
The answer is as #Kirill has already said - Win7 won't let you write data into Program Files unless you have higher than normal permissions (Run as Administrator). In this case it may be redirecting your file writes so that they still apear to work, but the data itself is not stored in Progam Files.
To add to his answer: In general (unless you want to run your app as an administrator), you should not write any program data to the Program Files folder.
Application settings should be stored in one of the AppData folders. You can get to your user's appdata manually by going to your start menu Search box (Vista/Win7) and typing %appdata%.
To find this location in your code, use SHGetFolderPath with CSIDL_APPDATA (current user) or CSIDL_COMMON_APPDATA (all users).
It could be related to that Windows use virtualization of the file system. You could read here about it. Check if your INI file is located in <root>\Users\<User_name>\AppData\Local\VirtualStore.
Seems to me that the licensePath: getcwd() + "\\dat\\preference.ini" is not what you would expect.
Log this value (console or in a log file) and see what exactly is the value of licencePath is when running you program from different folders.
This article is about game development but has the best description of how and why this happens that I've been able to find
http://msdn.microsoft.com/en-us/library/ee419001(VS.85).aspx
This paragraph from the article describes what is happening most likely -
Attempting to create or write a file
or directory under a folder which does
not grant write permission to the
process will fail under Windows Vista
if the application does not have
administrative privileges. If your
32-bit game executable is running in
legacy mode, because it did not
declare a requested execution level,
its write operations will succeed, but
they will be subjected to
virtualization as described in the
section "UAC Compatibility with Older
Games" later in this article.