QT copy to QTemporaryFile - c++

I'd like to make a copy of some/path/myfile in $TMPDIR/myprog-<random-string>.ext, such that I can then pass it on to a 3rd party procedure that chokes on extensionless files.
Here's what I'd like to work:
QString originalPath = "some/path/myfile";
QTemporaryFile f(
QDir::temp().absoluteFilePath("mprog-XXXXXX.ext")
);
// f.open(); ?
QFile(originalPath).copy(f.fileName());
However, I now have a problem - either the file doesn't yet exist, and thus hasn't been assigned a temporary fileName(), or the file name has been assigned but the file itself already exists, preventing the new file being copied on top.
How can I copy a file to a temporary location in QT, and have the temporary copy removed when the destructor of QTemporaryFile is called?

If the file doesn't exist, create the QTemporaryFile object exactly as you have done, open it and then close it immediately. This will generate the random filename and create it on the disk.
When your QTemporaryFile object gets destroyed, the file will be deleted from the disk.

Unfortunately, Qt (5.3) doesn't support copying to an existing file. The only correct, race-free use of QTemporaryFile is to open() it, creating it in the process, and then operate on it.
You'll need to implement the copy yourself, I'm afraid :(
On Windows, if you expect there to be some gain from using CopyFileEx, I have a complete example that wraps it for Qt's perusal, with progress signals.
The real question is: do you really need to create a copy? Wouldn't a hard link do? Since Qt runs, for the most part, on Unices and Windows, you can create a symbolic link wrapper that will wrap POSIX link() and winapi CreateHardLink. If hard link creation fails, or the temporary folder is on a different volume, you can then try CreateSymbolicLink. Of course you'd need to look up CreateSymbolicLinkW using QLibrary if you intend your executable to start un XP at all. If that fails, you're either running on XP or on a FAT partition, and the final fallback is copying.
Would it be out of the question to rename the file, run the 3rd-party application on it, then rename it back?

If you're not going to be actually using the file / stream to the file QTemporaryFile created for you, you're better off using QUuid instead to just generate a guaranteed unique filename. This generates a unique filename, roughly equivalent to QTemporaryFile:
QUuid uuid = QUuid::createUuid();
QString tempFileFullPath = QDir::toNativeSeparators(QDir::tempPath() + "/" + qApp->applicationName().replace(" ", "") + "_" + uuid.toString(QUuid::WithoutBraces) + ".dat");
I like the temporary filename to not contain spaces, so I removed that from the app name used for the filename prefix. (You should call QApplication::setApplicationName in your main() function so this will work.)
Also, you should probably change the .dat extension to something suitable for your file type.

Related

C++ how to copy a FILE * pointer

I found a solution here Duplicating file pointers?
FILE *fp2 = fdopen (dup (fileno (fp)), "r");
but according to http://man7.org/linux/man-pages/man2/dup.2.html,
the new file descriptor created by dup, they refer to the same open file descriptor, and thus share status. That's not what I want. I want to create a totally new IO object which refers to the file pointed by the old FILE *
Is there any way to do this?
Add:
I don't have the filename actually. I'm doing a deep copy of an object, which hold an open FILE pointer, so I have to copy that also.
I want to create a totally new IO object which refers to the file pointed by the old FILE *
You're assuming that the file associated with the original FILE * has some form of identity distinct from the IO object by which it is accessed. That is true for regular files and some other objects, but false for others, such as sockets and pipes. Thus, there is no general-purpose mechanism for doing what you ask.
For the special case of objects that can be accessed via the file system, the way to create a new IO object associated with the same file is to open() or fopen() the file via a path to it. That's what these functions do. There is no standard way to get a path from a FILE * or file descriptor number, but on Linux (since you tagged that) you can use readlink() on the open file's entry in /proc, as described here.
Do be aware that even for regular files, the readlink approach is not guaranteed to work. In particular, it will not work if the path with which the original file was opened has since been unlinked, and in fact, in that case it could lead to the wrong file being opened instead. You can check for that by running fstat() on both the old and new file descriptor numbers -- if the files are in fact the same, then they will have the same inode numbers on the same host device.

Is it safe to use a QTemporaryFile with a QProcess?

I have to read a script from the user and call a QProcess passing that script as a file.
For example, the user insert this, say, Python script
import sys
print(sys.copyright)
and I have to put that script in a file, and call the python interpreter using that file.
I thought to use a QTemporaryFile, because that file will serve just when launching the process, and I have no need to keep it open.
The question is: is it safe to open a QTemporaryFile, write something in it, pass that file to a process (which will continue indefinitely) and then destroy the temporary file? What if the process will need that file again? What if the process keep the file open?
I reckon that, if kept open by the process, no problem will arise: probably the QTemporaryFile will unlink the path, but data will still be accessible in memory.
But what if the process will try to open the file again?
Here a snippet as example (wrote on the fly)
QString script = QInputDialog::getText(blah);
QTemporaryFile tmp;
if (tmp.open()) {
tmp.write(script.toUtf8());
QStringList params;
params << tmp.fileName();
QProcess *proc = new QProcess("/usr/bin/python3");
proc->start(params);
}
As I understand it, in the case of the 'autoRemove' flag (which is on by default), the QTemporaryFile will exist so long as the instance of QTemporaryFile exists. Therefore, in the code you originally presented, when tmp goes out of scope, the file will be removed. Calling open / close on the object will not delete the file.
You could dynamically allocate the file with QTemporaryFile* pTmp = new QTemporaryFile and then delete it later, if you know when the python script has finished with it.
Ouch, I just noted the autoRemove flag in the QTemporaryFile. I guess this could be a solution: if set to false, the file will not be removed from the disk, so the process is free to reuse the file - I think.
Temporary files should be stored in system's default location, so I guess that the files are not removed until a reboot (at least, I believe Linux works this way).
This is just an idea, but I will wait for other answers or confirmations.

C++ Directory Watching - How to detect copy has ended

I have a folder to which files are copied. I want to watch it and process files as soon as they are copied to the directory. I can detect when a file is in the directory, whether through polling (my current implementation) or in some tests using Windows APIs from a few samples I've found online.
The problem is that I detect when the file is first created and its still being copied. This makes my program, that needs to access the file, through errors (because the file is not yet complete). How can I detect not when the copying started but when the copying ended? I'm using C++ on Windows, so the answer may be platform dependent but, if possible, I'd prefer it to be platform agnostic.
You could use either lock files or a special naming convention. The easiest is the latter and would work something like this:
Say you want to move a file named "fileA.txt" When copying it to the destination directory, instead, copy it to "fileA.txt.partial" or something like that. When the copy is complete, rename the file from "fileA.txt.partial" to "fileA.txt". So the appearance of "fileA.txt" is atomic as far as the watching program can see.
The other option as mentioned earlier is lock files. So when you copy a file named "fileA.txt", you first create a file called "fileA.txt.lock". When the copying is done, you simply delete the lock file. When the watching program see "fileA.txt", it should check if "fileA.txt.lock" exists, if it does, it can wait or revisit that file in the future as needed.
You should not be polling. Use FindFirstChangeNotification (http://msdn.microsoft.com/en-us/library/windows/desktop/aa364417%28v=vs.85%29.aspx) to watch a directory for changes.
Then use the Wait functions (http://msdn.microsoft.com/en-us/library/windows/desktop/ms687069%28v=vs.85%29.aspx) to wait on change notifications to happen.
Overview and examples here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365261%28v=vs.85%29.aspx
I'm not sure how exactly file write completion can be determined. Evan Teran's answer is a good idea.
You can use something like this, This is tested and working
bool IsFileDownloadComplete(const std::wstring& dir, const std::wstring& fileName)
{
std::wstring originalFileName = dir + fileName;
std::wstring tempFileName = dir + L"temp";
while(true)
{
int ret = rename(convertWstringToString(originalFileName).c_str(), convertWstringToString(tempFileName).c_str());
if(ret == 0)
break;
Sleep(10);
}
/** File is not open. Rename to original. */
int ret = rename(convertWstringToString(tempFileName).c_str(), convertWstringToString(originalFileName).c_str());
if(ret != 0)
throw std::exception("File rename failed");
return true;
}

How can I delete a file upon its close in C++ on Linux?

I wish for a file to be deleted from disk only when it is closed. Up until that point, other processes should be able to see the file on disk and read its contents, but eventually after the close of the file, it should be deleted from disk and no longer visible on disk to other processes.
Open the file, then delete it while it's open. Other processes will be able to use the file, but as soon as all handles to file are closed, it will be deleted.
Edit: based on the comments WilliamKF added later, this won't accomplish what he wants -- it'll keep the file itself around until all handles to it are closed, but the directory entry for the file name will disappear as soon as you call unlink/remove.
Open files in Unix are reference-counted. Every open(2) increments the counter, every close(2) decrements it. The counter is shared by all processes on the system.
Then there's a link count for a disk file. Brand-new file gets a count of one. The count is incremented by the link(2) system call. The unlink(2) decrements it. File is removed from the file system when this count drops to zero.
The only way to accomplish what you ask is to open the file in one process, then unlink(2) it. Other processes will be able to open(2) or stat(2) it between open(2) and unlink(2). Assuming the file had only one link, it'll be removed when all processes that have it open close it.
Use unlink
#include <unistd.h>
int unlink(const char *pathname);
unlink() deletes a name from the
filesystem. If that name was the last
link to a file and no processes have
the file open the file is deleted and
the space it was using is made
available for reuse.
If the name was the last link to a
file but any processes still have the
file open the file will remain in
existence until the last file
descriptor referring to it is closed.
If the name referred to a symbolic
link the link is removed.
If the name referred to a socket, fifo
or device the name for it is removed
but processes which have the object
open may continue to use it.
Not sure, but you could try remove, but it looks more like c-style.
Maybe boost::filesystem::remove?
bool remove( const path & ph );
Precondition: !ph.empty()
Returns: The value of exists( ph )
prior to the establishment of the
postcondition.
Postcondition: !exists( ph )
Throws: if ph.empty() || (exists(ph)
&& is_directory(ph) && !is_empty(ph)).
See empty path rationale.
Note: Symbolic links are themselves
deleted, rather than what they point
to being deleted.
Rationale: Does not throw when
!exists( ph ) because not throwing:
Works correctly if ph is a dangling
symbolic link. Is slightly
easier-to-use for many common use
cases. Is slightly higher-level
because it implies use of
postcondition semantics rather than
effects semantics, which would be
specified in the somewhat lower-level
terms of interactions with the
operating system. There is, however, a
slight decrease in safety because some
errors will slip by which otherwise
would have been detected. For example,
a misspelled path name could go
undetected for a long time.
The initial version of the library
threw an exception when the path did
not exist; it was changed to reflect
user complaints.
You could create a wrapper class that counts references, using one of the above methods to delete de file .
class MyFileClass{
static unsigned _count;
public:
MyFileClass(std::string& path){
//open file with path
_count++;
}
//other methods
~MyFileClass(){
if (! (--_count)){
//delete file
}
}
};
unsigned MyFileClass::_count = 0; //elsewhere
I think you need to extend your notion of “closing the file” beyond fclose or std::fstream::close to whatever you intend to do. That might be as simple as
class MyFile : public std::fstream {
std::string filename;
public:
MyFile(const std::string &fname) : std::fstream(fname), filename(fname) {}
~MyFile() { unlink(filename); }
}
or it may be something much more elaborate. For all I know, it may even be much simpler – if you close files only at one or two places in your code, the best thing to do may be to simply unlink the file there (or use boost::filesystem::remove, as Tom suggests).
OTOH, if all you want to achieve is that processes started from your process can use the file, you may not need to keep it lying around on disk at all. forked processes inherit open files. Don't forget to dup them, lest seeking in the child influences the position in the parent or vice versa.

How to create a temporary text file in C++?

I'm trying to create a temporary text file in C++ and then delete it at the end
of the program. I haven't had much luck with Google.
Could you tell me which functions to use?
The answers below tell me how to create a temp file. What if I just want to
create a file (tmp.txt) and then delete it? How would I do that?
Here's a complete example:
#include <unistd.h>
int main(void) {
char filename[] = "/tmp/mytemp.XXXXXX"; // template for our file.
int fd = mkstemp(filename); // Creates and opens a new temp file r/w.
// Xs are replaced with a unique number.
if (fd == -1) return 1; // Check we managed to open the file.
write(fd, "abc", 4); // note 4 bytes total: abc terminating '\0'
/* ...
do whatever else you want.
... */
close(fd);
unlink(filename); // Delete the temporary file.
}
If you know the name of the file you want to create (and are sure it won't already exist) then you can obviously just use open to open the file.
tmpnam and tmpfile should probably be avoided as they can suffer from race conditions - see man tmpfile(3) for the details.
Maybe this will help
FILE * tmpfile ( void );
http://www.cplusplus.com/reference/clibrary/cstdio/tmpfile/
Open a temporary file
Creates a temporary binary file, open
for update (wb+ mode -- see fopen for
details). The filename is guaranteed
to be different from any other
existing file. The temporary file
created is automatically deleted when
the stream is closed (fclose) or when
the program terminates normally.
See also
char * tmpnam ( char * str );
Generate temporary filename
A string containing a filename
different from any existing file is
generated. This string can be used to
create a temporary file without
overwriting any other existing file.
http://www.cplusplus.com/reference/clibrary/cstdio/tmpnam/
This may be a little off-topic because the author wanted to create a tmp.txt and delete it after using it, but that is trivial - you can simple open() it and delete it (using boost::filesystem of course).
mkstemp() is UNIX-based. With Windows you use GetTempFileName() and GetTempPath() to generate a path to a temp file. Sample code from MSDN:
http://msdn.microsoft.com/en-us/library/aa363875%28VS.85%29.aspx
On Linux (starting with kernel 3.11), there's flag to open(2) O_TMPFILE that creates a temporary file that doesn't have a name (i.e. it doesn't show up in the filesystem). This has a few interesting features:
No worries about unique names, it's just an inode, there is no name.
No race conditions during creation (e.g. symlink attacks).
No stray files if your app crashes, it's always automatically deleted.
I wonder why most of you guys showed him the C way of doing it instead of the C++ way.
Here's fstream.
Try that, deleting a file is OS depended but you can use boost.filesystem to make things easy for you.
If you need a named file (for example, so you can pass the name to another process, perhaps a compiler or editor), then register a cleanup function that removes the file with atexit(). You can use either C++ <iostream> or C FILE * (<cstdio>) to create the file. The not completely standard but widely available mkstemp() function creates a file and tells you its name as well as returning a file descriptor (a third I/O mechanism); you could use the fdopen() function to convert the file descriptor into a FILE *.
If you don't need a named file a C-style FILE * is OK, then look at tmpfile() as suggested by #Tom.
A clean, portable and non-deprecated way of creating a temporary file is provided by Boost:
auto temporary_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
Well, assuming you have been successful in creating the temporary file, you can use the remove function to delete it.
The function is declared in stdio.h -
#include <stdio.h>
int remove(const char *pathname);
For example, if you want to delete a file named myfile.txt the code will be
#include<stdio.h>
int main()
{
if(remove("myfile.txt") == -1)
{
fprintf(stderr,"Remove failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
I hope by now, you already know how to create the temp file, so this should resolve your query.
Hope it helps.