when to call _findclose? - c++

Note: Since problem is solved, I've added comments to my original posts.
According to "http://msdn.microsoft.com/en-us/library/6tkkkc1y%28v=vs.90%29.aspx", it stated as this:
*You must call _findclose after you are finished using either the _findfirst or _findnext function (or any variants). This frees up resources used by these functions in your application.*
--comment: it is vague, but what microsoft is trying to say is: some users just need to find the first file(they don't need to call _findnext), then call _findclose; some users called _findnext (they MUST have already called _findfirst), after finished using that, call _findclose. Actually _findnext can be called multiple times, while _findclose is only responsible to a handle, which is created by _findfirst.
And following is a piece of code that is widely used to list files in the directory. -- comment: it is correct.
For example, if there are 2 files and 1 directory in the directory, then:
.
..
ddd
file1.txt
file2.txt
_findfirst is called once. the handle's corresponding fileinfo is system directory "." (is that right?)
--comment: no. the handle is a group of files+directories, the fileinfo is acting as the "cursor". (fileinfo always contained the "name" field, I bet the implementation of _findnext is using the "name" to find the next in a group of files+directories specified by the handle)
_findnext is called 4 times. (the first argument is always the handle corresponding to ".", is that right?)
--comment: yes + no. The first argument is always the same handle; the handle is NOT corresponding to any fileinfo, but to a group of them.
My questions are:
Does "_findclose" be called ONCE is enough?
*--comment:* yes.
if _findnext will not change the handle value, how can it "remember" where to start to find the next file(or directory)? (sorry, maybe I was thinking in the "linked list" pattern.)
*--comment:* I bet is using fileinfo's name field. Just as in Windows Explorer, we sort the contents in a folder, given a file name, we can know their position in the list, so we can "find next".
Are there any harm to call _findclose more times than needed? (like crash or something)
*--comment:* a stupid question. Sorry!
Or is the following code wrong at all? If yes, what's the correct way to implement it?
--It is correct code.
// List the files in the directory
intptr_t file;
_finddata_t filedata;
file = _findfirst(desc.c_str(),&filedata);
if (file != -1)
{
do
{
cout << filedata.name << endl;
// Or put the file name in a vector here
} while (_findnext(file,&filedata) == 0);
}
else
{
cout << "No described files found" << endl;
}
_findclose(file);
I asked this because I've met an issue that an application is freezing a directory which can not be deleted if the process is alive. However, I can guaranteed that "_findclose" is called on every return value from "_findfirst". If I add "_findclose" after calling "_findnext", then will fix the issue perfectly. How can you help me to explain it?
--comment: pardon. don't use "guarantee" too easy. That's where the bug is.
Note: I don't have problem to understand what is a handle, like open a file, read/write/read/write..., close the file handle. I just find the documentations describing these three APIs are vague.
--comment: go to improve your english.
Thank you in advance.

Your calls to _findclose should match with your calls to _findfirst -- i.e., each time you call _findfirst, you should have a matching call to _findclose.
In the code above, since you have only one call to _findfirst, it's correct to have only one call to _findclose.
If you were doing a recursive search of subdirectories, then you'd end up with multiple calls to _findfirst as you descend the hierarchy, and matching calls to _findclose as you finish and ascend back up the hierarchy.

You only need to call _findclose once, when you are finished.
On Windows, a directory may be locked if it is the current directory of your process. Try calling _chdir.
If that doesn't work... are you opening any of the files in the directory you're searching? An open file may lock the directory as well.
It may be useful to let Process Explorer get a look at your app. It can tell you for sure what handle you have left open.

Related

create a unique temporary directory [duplicate]

This question already has answers here:
How to create a temporary directory in C++?
(6 answers)
Closed 3 years ago.
I'm trying to create a unique temporary directory in the system temp folder and have been reading about the security and file creation issues of tmpnam().
I've written the below code and was wondering whether it would satisfy these issues, is my use of the tmpnam() function correct and the throwing of the filesystem_error? Should I be adding checks for other things (e.g. temp_directory_path, which also throws an exception)?
// Unique temporary directory path in the system temporary directory path.
std::filesystem::path tmp_dir_path {std::filesystem::temp_directory_path() /= std::tmpnam(nullptr)};
// Attempt to create the directory.
if (std::filesystem::create_directories(tmp_dir_path)) {
// Directory successfully created.
return tmp_dir_path;
} else {
// Directory could not be created.
throw std::filesystem_error("directory could not be created.");
}
From cppreference.com:
Although the names generated by std::tmpnam are difficult to guess, it is possible that a file with that name is created by another process between the moment std::tmpnam returns and the moment this program attempts to use the returned name to create a file.
The problem is not with how you use it, but the fact that you do.
For example, in your code sample, if a malicious user successfully guesses and creates the directory right in between the first and second line, it might deny service (DOS) from your application, which might be critical, or not.
Instead, there is a way to do this without races on POSIX-compliant systems:
For files see mkstemp(3) for more information
For dirs see mkdtemp(3) for more information.
Your code is fine. Because you try to create the directory the OS will arbitrate between your process and another process trying to create the same file so, if you win, you own the file and if you lose you get an error.
I wrote a similar function recently. Whether you throw an exception or not depends on how you want to use this function. You could, for example simply return either an open or closed std::fstream and use std::fstream::is_open as a measure of success or return an empty pathname on failure.
Looking up std::filesystem::create_directories it will throw its own exception if you don't supply a std::error_code parameter so you don't need to throw your own exception:
std::filesystem::path tmp_dir_path {std::filesystem::temp_directory_path() /= std::tmpnam(nullptr)};
// Attempt to create the directory.
std::filesystem::create_directories(tmp_dir_path));
// If that failed an exception will have been thrown
// so no need to check or throw your own
// Directory successfully created.
return tmp_dir_path;

C++: Rename instead of Delete & Copy when using Sync

Currently I have the following part code in my Sync:
...
int index = file.find(remoteDir);
if(index >= 0){
file.erase(index, remoteDir.size());
file.insert(index, localDir);
}
...
// Uses PUT command on the file
Now I want to do the following instead:
If a file is the same as before, except for a rename, don't use the PUT command, but use the Rename command instead
TL;DR: Is there a way to check whether a file is the same as before except for a rename that occurred? So a way to compare both files (with different names) to see if they are the same?
check the md5sum, if it is different then the file is modified.
md5 check sum of a renamed file will remain same. Any change in content of file will give a different value.
I first tried to use Renjith method with md5, but I couldn't get it working (maybe it's because my C++ is for windows instead of Linux, I dunno.)
So instead I wrote my own function that does the following:
First check if the file is the exact same size (if this isn't the case we can just return false for the function instead of continuing).
If the sizes do match, continue checking the file-buffer per BUFFER_SIZE (in my case this is 1024). If the entire buffer of the file matches, return true.
PS: Make sure to close any open streams before returning.. My mistake here was that I had the code to close one stream after the return-statement (so it was never called), and therefore I had errno 13 when trying to rename the file.

Diagnosing QDir::rmdir failure

I’m using the following code to delete an empty folder on Linux:
bool removeFolder (const QString& path)
{
QDir dir(path);
assert(dir.exists());
return dir.rmdir(".");
}
For some reason it sometimes returns false (for specific folders, but those folders don’t seem to be wrong in any way). If I subsequently use ::rmdir from <unistd.h> to remove the same folder, it succeeds.
How can I tell why QDir::rmdir is failing?
This never happened on Windows so far, QDir::rmdir just works.
Confirming: works on windown, fails on linux.
Reading the "rmdir" doc in <unistd>, here https://pubs.opengroup.org/onlinepubs/007904875/functions/rmdir.html, it says there that "If the path argument refers to a path whose final component is either dot or dot-dot, rmdir() shall fail." So what's probably happening is that QDir::rmdir() is calling the unistd rmdir() function in linux, and this one fails with ".".
I tried to just use the full absolute path ( QDir::rmdir(absolutePath) ) and it worked; however, i see basically no point in using QDir::rmdir() over unistd's rmdir(), so i''ll stick w/ the unistd rmdir() from now on.
note: QDir::removeRecursively() is a different story: it seems to work okay, and it's way more convenient than going through opendir() and then successive readdir()'s (or the nftw(...FTW_DEPTH...) thingie).
I had the same problem but on Windows, I could not delete an empty directory with QDir().rmdir(path);. This happened on some older hard drive so may be the ancient file system was to blame. But I found a hack:
QFile(path).setPermissions(QFile::WriteOther); // this works even for dirs
bool success = QDir().rmdir(path);
Of course, you should revert the permissions back to original values if the deletion was unsuccessful anyway, but that's a different story.
Try to use this one:
dir.rmdir(dir.absolutePath())

how to JUDGE other program's result via cpp?

I've got a series of cpp source file and I want to write another program to JUDGE if they can run correctly (give input and compare their output with standart output) . so how to:
call/spawn another program, and give a file to be its standard input
limit the time and memory of the child process (maybe setrlimit thing? is there any examples?)
donot let the process to read/write any file
use a file to be its standard output
compare the output with the standard output.
I think the 2nd and 3rd are the core part of this prob. Is there any way to do this?
ps. system is Linux
To do this right, you probably want to spawn the child program with fork, not system.
This allows you to do a few things. First of all, you can set up some pipes to the parent process so the parent can supply the input to the child, and capture the output from the child to compare to the expected result.
Second, it will let you call seteuid (or one of its close relatives like setreuid) to set the child process to run under a (very) limited user account, to prevent it from writing to files. When fork returns in the parent, you'll want to call setrlimit to limit the child's CPU usage.
Just to be clear: rather than directing the child's output to a file, then comparing that to the expected output, I'd capture the child's output directly via a pipe to the parent. From there the parent can write the data to a file if desired, but can also compare the output directly to what's expected, without going through a file.
std::string command = "/bin/local/app < my_input.txt > my_output_file.txt 2> my_error_file.txt";
int rv = std::system( command.c_str() );
1) The system function from the STL allows you to execute a program (basically as if invoked from a shell). Note that this approach is inherenly insecure, so only use it in a trusted environment.
2) You will need to use threads to be able to achieve this. There are a number of thread libraries available for C++, but I cannot give you recommendation.
[After edit in OP's post]
3) This one is harder. You either have to write a wrapper that monitors read/write access to files or do some Linux/Unix privilege magic to prevent it from accessing files.
4) You can redirect the output of a program (that it thinks goes to the standard output) by adding > outFile.txt after the way you would normally invoke the program (see 1)) -- e.g. otherapp > out.txt
5) You could run diff on the saved file (from 3)) to the "golden standard"/expected output captured in another file. Or use some other method that better fits your need (for example you don't care about certain formatting as long as the "content" is there). -- This part is really dependent on your needs. diff does a basic comparing job well.

QSettings - Sync issue between two process

I am using Qsettings for non gui products to store its settings into xml files. This is written as a library which gets used in C, C++ programs. There will be 1 xml file file for each product. Each product might have more than one sub products and they are written into xml by subproduct grouping as follows -
File: "product1.xml"
<product1>
<subproduct1>
<settings1>..</settings1>
....
<settingsn>..</settingsn>
</subproduct1>
...
<subproductn>
<settings1>..</settings1>
....
<settingsn>..</settingsn>
</subproductn>
</product1>
File: productn.xml
<productn>
<subproduct1>
<settings1>..</settings1>
....
<settingsn>..</settingsn>
</subproduct1>
...
<subproductn>
<settings1>..</settings1>
....
<settingsn>..</settingsn>
</subproductn>
</productn>
The code in one process does the following -
settings = new QSettings("product1.xml", XmlFormat);
settings.setValue("settings1",<value>)
sleep(20);
settings.setValue("settings2", <value2>)
settings.sync();
When the first process goes to sleep, I start another process which does the following -
settings = new QSettings("product1.xml", XmlFormat);
settings.remove("settings1")
settings.setValue("settings3", <value3>)
settings.sync();
I would expect the settings1 to go away from product1.xml file but it still persist in the file - product1.xml at the end of above two process. I am not using QCoreApplication(..) in my settings library. Please point issues if there is anything wrong in the above design.
This is kind of an odd thing that you're doing, but one thing to note is that the sync() call is what actually writes the file to disk. In this case if you want your second process to actually see the changes you've made, then you'll need to call sync() before your second process accesses the file in order to guarantee that it will actually see your modifications. Thus I would try putting a settings.sync() call right before your sleep(20)
Maybe you have to do delete settings; after the sync() to make sure it is not open, then do the writing in the other process?
Does this compile? What implementation of XmlFormat are you using and which OS? There must be some special code in your project for storing / reading to and from Xml - there must be something in this code which works differently from what you expect.