I'm looking for the Unix equivalent of Win32's CopyFile, I don't want to reinvent the wheel by writing my own version.
One option is that you could use system()
to execute cp
. This just re-uses the cp(1)
command to do the work. If you only need to make another link the the file, this can be done with link()
or symlink()
.
this is tagged as C, if you're in c++, but happened to mis-tag this question there is: http://stackoverflow.com/questions/829468/how-to-perform-boostfilesystem-copyfile-with-overwrite
in C, maybe there is something in GLib.
sprintf( cmd, "/bin/cp -p \'%s\' \'%s\'", old, new);
system( cmd);
Add some error checks...
Otherwise, open both and loop on read/write, but probably not what you want.
There is no baked-in equivalent CopyFile function in the APIs. But sendfile can be used to copy a file in kernel mode which is a faster and better solution (for numerous reasons) than opening a file, looping over it to read into a buffer, and writing the output to another file.
Here's some code I grabbed from a project I'm working on:
#include <sys/socket.h>
#include <fcntl.h>
int inline BLCopyFile(const char* source, const char* destination)
{
//Here we use kernel-space copying for performance reasons
int input, output;
if( (input = open(source, O_RDONLY)) == -1)
return 0;
if( (output = open(destination, O_WRONLY | O_CREAT)) == -1)
{
close(input);
return 0;
}
off_t bytesCopied;
int result = sendfile(output, input, 0, &bytesCopied, 0, 0) == -1;
close(input);
close(output);
return result;
}
It's straight forward to use fork/execl to run cp to do the work for you. This has advantages over system in that it is not prone to a Bobby Tables attack and you don't need to sanitize the arguments to the same degree. Further, since system() requires you to cobble together the command argument, you are not likely to have a buffer overflow issue due to sloppy sprintf() checking.
The advantage to calling cp directly instead of writing it is not having to worry about elements of the target path existing in the destination. Doing that in roll-you-own code is error-prone and tedious.
I wrote this example in ANSI C and only stubbed out the barest error handling, other than that it's straight forward code.
void copy(char *source, char *dest)
{
int childExitStatus;
pid_t pid;
if (!source || !dest) {
/* handle as you wish */
}
pid = fork();
if (pid == 0) { /* child */
execl("/bin/cp", "/bin/cp", source, dest, (char *)0);
}
else if (pid < 0) {
/* error - couldn't start process - you decide how to handle */
}
else {
/* parent - wait for child - this has all error handling, you
* could just call wait() as long as you are only expecting to
* have one child process at a time.
*/
pid_t ws = waitpid( pid, &childExitStatus, WNOHANG);
if (ws == -1)
{ /* error - handle as you wish */
}
if( WIFEXITED(childExitStatus)) /* exit code in childExitStatus */
{
int status = WEXITSTATUS(childExitStatus); /* zero is normal exit */
/* handle non-zero as you wish */
}
else if (WIFSIGNALED(status)) /* killed */
{
}
else if (WIFSTOPPED(status)) /* stopped */
{
}
}
}
There is no need to either call non-portable APIs like sendfile
, or shell out to external utilities. The same method that worked back in the 70s still works now:
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int cp(const char *to, const char *from)
{
int fd_to, fd_from;
char buf[4096];
ssize_t nread;
int saved_errno;
fd_from = open(from, O_RDONLY);
if (fd_from < 0)
return -1;
fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd_to < 0)
goto out_error;
while (nread = read(fd_from, buf, sizeof buf), nread > 0)
{
char *out_ptr = buf;
ssize_t nwritten;
do {
nwritten = write(fd_to, out_ptr, nread);
if (nwritten >= 0)
{
nread -= nwritten;
out_ptr += nwritten;
}
else if (errno != EINTR)
{
goto out_error;
}
} while (nread > 0);
}
if (nread == 0)
{
if (close(fd_to) < 0)
{
fd_to = -1;
goto out_error;
}
close(fd_from);
/* Success! */
return 0;
}
out_error:
saved_errno = errno;
close(fd_from);
if (fd_to >= 0)
close(fd_to);
errno = saved_errno;
return -1;
}