Why is there no boost::filesystem::move_file? - c++

I'm using boost filesystem to replace windows C++ functions like CopyFile and MoveFile to get some kind of portability between windows and linux. I'm using copy_file but I have not been able to find anything that moves files like a 'move_file' function. Do boost have a move file function?
I would very much prefer to use boost, but alternative suggestions are welcome.

It's called rename, see the manual. Like the corresponding OS functions, this might or might not work if the source and destination paths are on different file systems. If it doesn't work, use a copy operation followed by a delete operation.

void add_time(ptime& gen_time, int seconds) {
boost::posix_time::millisec_posix_time_system_config::time_duration_type time_elapse(0, 0, seconds);
//time_elapse = p2 - p1;
gen_time = gen_time + time_elapse;
}

Related

Why do we need to write an own copy program while we can use copy shell command?

I want to copy huge files (~ 10 GB) in my C/C++ program and two options are on hand: 1) Write my own copy function (large buffer might be used), and 2) Call to system copy command (copy on Windows, cp on Linux).
As I see, when use "Ctrl + C" and "Ctrl + V" on Windows, huge files are copied very fast. I am not sure if we can do better than Windows OS.
Which would be the best choice?
With proper implementation, roll your own code™ give you flexibility over the shell copy. For example, it's easier to abort operation, and provide progress to user.
By the way, when you see Windows copying file fast - it's just perspective. File explorer queue the copy or otherwise do it in background. It takes about the same time with, e.g. CopyFileEx or sendfile until the copy finish and the file is usable.
The reasons for not using shell to use basic tasks in the language are not related to performance at all - it's more about safety and portability. You wouldn't use eval in your language nor try to concatenate strings to create SQL queries - and yet there you are, creating shell commands by concatenating strings.
Brett Hale's "solution" conveniently doesn't mention all these and hides the code needed to make this safe and portable behind the comment "do it yourself" - in fact, when you do this you'll end up with more code than hand-rolled copy function and it'll still be buggy. And if you have a bug there, an user can inject commands (for example, run it with a destination file a_file" || rm -rf --no-preserve-root). Also you're relying on the shell, which itself can have bugs (see Shellshock)
Calvin's answer correctly mentions why the copy operation done by the shell may work faster - it can do more tricks to make it look like it copies faster. In fact, there is no inherent magic in the shell copy operations. The "performance problem" is not a problem since the main bottleneck is in actual reading and writing.
Furthermore, you present a false dichotomy, since you fail to consider using a third option: a third-party library. One of them is Boost.Filesystem, which has a copy function.
If it were me I would avoid making system calls and do something like so:
int main()
{
std::ifstream src("from.ogv", std::ios::binary);
std::ofstream dst("to.ogv", std::ios::binary);
dst << src.rdbuf();
}

What is the best way of determining that two file paths are referring to the same file object?

I want to write a unit test that checks that two file paths are equivalent, but I don't want to assume that the string representation is the same.
For example, on Linux there could be symlinks in the path in one case and not in the other. On Windows, there could be drive notation on one (X:\foo) and network notation on the other (//serverX/foo). And most complicated, the file may have been written on Linux on an NFS share (in /path/to/file syntax) and verified on Windows using DOS syntax (X:\to\file) where X: is a NFS mount to /path.
Some ideas (found here on Stack Overflow, but not unified):
On Linux, compare the inode from stat
Use realpath (Is this Platform independent?)
On Windows, compare strings on GetFullPathName
On Windows, compare serial numbers and file index from GetFileInformationByHandle
What would be the cross-platform best solution? I'm writing this in C++, but I can drop down to C obviously.
You could check out the Boost.Filesystem library. Specifically, there is a method equivalent that seems to do exactly what you are looking for:
using namespace boost::filesystem;
path p("/path/to/file/one");
path q("/sym_link/to/one");
assert(equivalent(p, q));
Filesystem library
Since C++17 you can use the standard <filesystem> library. The function you are looking for is equivalent, under namespace std::filesystem:
bool std::filesystem::equivalent(const std::filesystem::path& p1, const filesystem::path& p2);
To summarize from the documentation: this function takes two paths as parameters and returns true if they reference the same file or directory, false otherwise. There is also a noexcept overload that takes a third parameter: an std::error_code in which to save any possible error.
For more information take a look at my complete answer to another stack overflow question.

fstream delete N bytes from the end of a binary file

Is it possible to delete N bytes from the end of a binary file in C++ using fstream (or something similar)? I don´t want to read the whole file, cut it and write it again, but since it´s from the end of a file it seems like it shouldn't be such a problem.
I'm not aware of a generic C++ (platform independent) way to do this without writing a new file. However, on POSIX systems (Linux, etc.) you can use the ftruncate() function. On Windows, you can use SetEndOfFile().
This also means you'll need to open the file using the native functions instead of fstream since you need the native descriptor/handle for those functions.
EDIT: If you are able to use the Boost library, it has a resize_file() function in its Filesystem library which would do what you want.
Update:
Now in C++17 you can use resize_file from filesystem
Live on Coliru
In case you want to use Qt, QFile also provides two resize() methods that allow to truncate a file.

boost::filesystem - how to create a boost path from a windows path string on posix platforms?

I'm reading path names from a database which are stored as relative paths in Windows format, and try to create a boost::filesystem::path from them on a Unix system. What happens is that the constructor call interprets the whole string as the filename. I need the path to be converted to a correct Posix path as it will be used locally.
I didn't find any conversion functions in the boost::filesystem reference, nor through google. Am I just blind, is there an obvious solution? If not, how would you do this?
Example:
std::string win_path("foo\\bar\\asdf.xml");
std::string posix_path("foo/bar/asdf.xml");
// loops just once, as part is the whole win_path interpreted as a filename
boost::filesystem::path boost_path(win_path);
BOOST_FOREACH(boost::filesystem::path part, boost_path) {
std::cout << part << std::endl;
}
// prints each path component separately
boost::filesystem::path boost_path_posix(posix_path);
BOOST_FOREACH(boost::filesystem::path part, boost_path_posix) {
std::cout << part << std::endl;
}
Edit: of course I can just replace the backslashes, but is there a solution that "just works(tm)" for both Windows and Unix plattforms?
Unfortunately the Windows path grammar is conditionally compiled, and only included when compiling on Windows. I don't understand why they have done this. Anyway, this means you have at most two parsers available at all times; the portable one, which is the same as the Posix one, and the native one, which depends on which platform you currently are compiling for.
What could "just work" was to have all paths stored in the portable (Posix) format. You could parse this equally simply on all platforms.
How about replacing the backslashes with slashes?
Looking at the header file, I see that if you define BOOST_WINDOWS_PATH (before including the header file) it compiles in the Windows path algorithm. I don't know if it works outside of Windows.

How can I create a temporary file for writing in C++ on a Linux platform?

In C++, on Linux, how can I write a function to return a temporary filename that I can then open for writing?
The filename should be as unique as possible, so that another process using the same function won't get the same name.
Use one of the standard library "mktemp" functions: mktemp/mkstemp/mkstemps/mkdtemp.
Edit: plain mktemp can be insecure - mkstemp is preferred.
tmpnam(), or anything that gives you a name is going to be vulnerable to race conditions. Use something designed for this purpose that returns a handle, such as tmpfile():
#include <stdio.h>
FILE *tmpfile(void);
The GNU libc manual discusses the various options available and their caveats:
http://www.gnu.org/s/libc/manual/html_node/Temporary-Files.html
Long story short, only mkstemp() or tmpfile() should be used, as others have mentioned.
man tmpfile
The tmpfile() function opens a unique temporary file in binary
read/write (w+b) mode. The file will be automatically deleted when it
is closed or the program terminates.ote
mktemp should work or else get one of the plenty of available libraries to generate a UUID.
The tmpnam() function in the C standard library is designed to solve just this problem. There's also tmpfile(), which returns an open file handle (and automatically deletes it when you close it).
You should simply check if the file you're trying to write to already exists.
This is a locking problem.
Files also have owners so if you're doing it right the wrong process will not be able to write to it.