C++ how to copy a FILE * pointer - c++

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.

Related

How to convert Qt file path from resource to absolute path?

I need to receive the absolute file path like
C:/Users/Dima/YandexDisk/_Application/WeldAnalysis/ExperimentDefaults.xlsx
from path of QRC file like
:/Data/ExperimentDefaults.xlsx.
How can I do this?
Resources are packed all together into the QRC file, they are not exposed to the filesystem, thus they cannot be converted to a standard path; it is like accessing a file inside a zip file.
What are you willing to do with such file path? QFile can deal with resource paths (":/...") and open such files, but other file handling APIs don't (such as C's fopen or C++'s std::ifstream). Also, and for the same reason, non-Qt application won't be able to open such files if passed as a parameter.
Options you have include:
opening the file using QFile and read it using related Qt classes (given you are dealing with an Excel file I think it doesn't worth the effort, unless you have some library to read it from a memory buffer).
copying the file out of the resources container to a temporary directory (you can use QTemporaryDir to create one), and use the file from there:
QTemporaryDir tempDir;
if (tempDir.isValid()) {
const QString tempFile = tempDir.path() + "/yourfile.xlsx";
if (QFile::copy(":/yourfile.xlsx", tempFile)) {
// your file is now extracted to the filesystem
}
}
Only be aware that when tempDir is destroyed, the temporary directory is also deleted, therefore your file. You can avoid this by disabling the auto-remove feature: tempDir.setAutoRemove(false) and manually deleting the temporary directory when you finish with the extracted file.

Recovering Files on Windows and C

Well this time I'm trying to write a program in C which recover deleted files from a disk, it could be an external disk, I have an idea than i had used before on linux, it is to open the disk as a kind of file and scaning the Headers and file footers of everything within the disk, the point is I'm not sure if there's allow on windows to open a disk as an File, basiclly I have the logic how to develope this program, but I'm not sure how to implement it on windows, anybody can give me a hand with this?.
The code I used on linux to open a disk as a file was:
Edit: That was a sample of what I was using guys, it's just to give you an idea of what I was doing, the correct syntax I used was the next:
direccion = ui->linea->text().toLatin1().constData();
f = fopen(direccion,"rb");
I used QT creator on linux, and direccion variable was a TextField value which contained the file path of the disk through a button function that open a QFileDialog...
could I use it in windows as well?
Thank you before hand..
"The code I used on linux to open a disk as a file was:"
File *f = fopen("E:\", "rb");
I seriously doubt you ever got this code working on any linux system (or windows either).
You'll need to escape the backslash path delimiter, if it's presented in any string literal:
FILE* f = fopen("E:\\", "rb");
// ^
Also all that filesystem path style you are presenting to access a particular disk, is about accessing a windows file path/disk.
No linux file system has notion about drive characters, and the file path delimiter value used is '/', not '\\'.
To recover deleted files, you can't use fopen or fstream::open because the file was deleted. Check the return value from the function or test the stream state.
The way to recover deleted files is:
Get the Master File Table as raw data.
Search for the record containing a string similar to the deleted
filename.
Change the entry in the Master File Table to "undeleted".
Write the Master File Table back to the drive.
The above usually requires platform specific API, which is different on Linux and Windows platforms.

QT copy to QTemporaryFile

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.

What does fd represent when typing: int fd = open("file");?

I am looking at I/O operations in C++ and I have a question.
When opening a file like:
#include <fcntl.h>
int main() {
unsigned char buffer[16];
int fd = open (argv[1], O_RDONLY);
read(fd, buffer, sizeof(buffer));
return 0;
}
How can the variable fd represent a file as an integer when passing it to the open method? Is it repesenting a file in current folder? If I print the ´fd´variable, it prints 3. What does that mean?
Ps. I know there are several other ways to handle files, like stdio.h, fstream etc but that is out of the scope of this question. Ds.
How can the variable fd represent a file as an integer when passing it to the open method?
It's a handle that identifies the open file; it's generally called a file descriptor, hence the name fd.
When you open the file, the operating system creates some resources that are needed to access it. These are stored in some kind of data structure (perhaps a simple array) that uses an integer as a key; the call to open returns that integer so that when you pass it read, the operating system can use it to find the resources it needs.
Is it repesenting a file in current folder?
It's representing the file that you opened; its filename was argv[1], the first of the arguments that was passed to the program when it was launched. If that file doesn't exist, or open failed for some reason, then it has the value -1 and doesn't represent any file; you really should check for that before you try to do anything with it.
If I print the fd variable, it prints 3. What does that mean?
It doesn't have any particular meaning; but it has that value because it was the fourth file (or file-like thing) that was opened, after the input (0), output (1) and error (2) streams that are used by cin, cout and cerr in C++.
Because that is the index of the table of resources stored for your current process.
Each process has it own resources table, so you just need to pass the index to read/write/etc function
Generally, a file descriptor is an index for an entry in a kernel-resident data structure containing the details of all open files. In POSIX this data structure is called a file descriptor table, and each process has its own file descriptor table. The user application passes the abstract key to the kernel through a system call, and the kernel will access the file on behalf of the application, based on the key. The application itself cannot read or write the file descriptor table directly.
from: http://en.wikipedia.org/wiki/File_descriptor
open() returns the file descriptor of the file which is the C type int. To know more about File Descriptor refer http://en.wikipedia.org/wiki/File_descriptor.
"fd" stands for file descriptor. It is a value identifying a file. It is often an index (in the global table), an offset, or a pointer. Different APIs use different types. WinAPI, for example, uses different types of handles (HANDLE, HGDI, etc.), which are essentially typedefs for int/void*/long, and so on.
Using naked types like "int" is usually not a good idea, but if the implementation tells you to do so (like POSIX in this case), you should keep it.
The simplified answer is that fd is just an index into some array of file descriptors.
When most processes are started, they are given three open file descriptors to begin with: stdin (0), stdout (1), and stderr (2). So when you open your first file, the next available array entry is 3.

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.