Example #1
0
int OSCopyFile(const char* source, const char* destination, bool overwrite)
{
	/* This function was taken from http://stackoverflow.com/questions/2180079/how-can-i-copy-a-file-on-unix-using-c */

	int input, output;
	if ((input = open(source, O_RDONLY)) == -1)
	{
		return -1;
	}
	if ((output = open(destination, O_WRONLY | O_CREAT | (overwrite ? O_TRUNC : O_EXCL), 0666)) == -1)
	{
		close(input);
		return -1;
	}

	//Here we use kernel-space copying for performance reasons
#if defined(__APPLE__) || defined(__FreeBSD__)
	//fcopyfile works on FreeBSD and OS X 10.5+ 
	int result = fcopyfile(input, output, 0, COPYFILE_ALL);
#else
	//sendfile will work with non-socket output (i.e. regular file) on Linux 2.6.33+
	off_t bytesCopied = 0;
	struct stat fileinfo = { 0 };
	fstat(input, &fileinfo);
	int result = sendfile(output, input, &bytesCopied, fileinfo.st_size) == -1 ? -1 : 0;
#endif

	close(input);
	close(output);

	return result;
}
Example #2
0
// `rename`, but works across devices
static int move(const char *oldpath, const char *newpath) {
    if (rename(oldpath, newpath) < 0) {
        if (errno == EXDEV) {
            int src = open(oldpath, O_RDONLY);
            if (src < 0)
                return -1;
            int dst = open(newpath, O_WRONLY|O_TRUNC|O_CREAT, 0644);
            if (dst < 0) {
                close(src);
                return -1;
            }
            int r;
#if defined(__APPLE__) || defined(__FreeBSD__)
            r = fcopyfile(src, dst, NULL, COPYFILE_DATA);
#else
            struct stat st;
            if (fstat(src, &st) < 0) {
                close(dst);
                close(src);
                return -1;
            }
            r = sendfile(dst, src, NULL, st.st_size);
#endif
            close(dst);
            close(src);
            if (r == 0)
                unlink(oldpath);
            return r;
        }
        return -1;
    }
    return 0;
}
Example #3
0
int main(void)
{
	int i = 0;
	char *files[] = {
		"/etc/passwd", "/tmp/mypwd", "/tmp/mypwd",
		"/etc/passwd", "/tmp/", "/tmp/passwd",
		"/etc/passwd", "/tmp", "/tmp/passwd",
		NULL
	};
	FILE *src, *dst;

	printf("=>Start testing fcopyfile()\n");
	while (files[i]) {
		printf("fcopyfile(%s, %s)\t", files[i], files[i + 1]);
		src = fopen(files[i], "r");
		dst = fopen(files[i + 1], "w");
		if (fcopyfile(src, dst)) {
			if (!fisdir(files[i + 1]))
			    err(1, "Failed fcopyfile(%s, %s)", files[i], files[i + 1]);
		}

		if (src)
			fclose(src);
		if (dst)
			fclose(dst);

		if (fexist(files[i + 2]))
			printf("OK => %s", files[i + 2]);
		printf("\n");

		erase(files[i + 2]);
		i += 3;
	}

	printf("\n=>Start testing copyfile()\n");
	i = 0;
	while (files[i]) {
		printf("copyfile(%s, %s)\t", files[i], files[i + 1]);
		if (!copyfile(files[i], files[i + 1], 0, 0))
			err(1, "Failed copyfile(%s, %s)", files[i], files[i + 1]);

		if (fexist(files[i + 2]))
			printf("OK => %s", files[i + 2]);
		printf("\n");

		erase(files[i + 2]);
		i += 3;
	}

	return 0;
}
Example #4
0
extern "C" int32_t SystemNative_CopyFile(intptr_t sourceFd, intptr_t destinationFd)
{
    int inFd = ToFileDescriptor(sourceFd);
    int outFd = ToFileDescriptor(destinationFd);

#if HAVE_FCOPYFILE
    // If fcopyfile is available (OS X), try to use it, as the whole copy
    // can be performed in the kernel, without lots of unnecessary copying.
    // Copy data and metadata.
    return fcopyfile(inFd, outFd, nullptr, COPYFILE_ALL) == 0 ? 0 : -1;
#else
    // Get the stats on the source file.
    int ret;
    struct stat_ sourceStat;
    bool copied = false;
#if HAVE_SENDFILE
    // If sendfile is available (Linux), try to use it, as the whole copy
    // can be performed in the kernel, without lots of unnecessary copying.
    while (CheckInterrupted(ret = fstat_(inFd, &sourceStat)));
    if (ret != 0)
    {
        return -1;
    }


    // We use `auto' here to adapt the type of `size' depending on the running platform.
    // On 32-bit, if you use 64-bit offsets, the last argument of `sendfile' will be a
    // `size_t' a 32-bit integer while the `st_size' field of the stat structure will be off64_t.
    // So `size' will have to be `uint64_t'. In all other cases, it will be `size_t'.
    auto size = UnsignedCast(sourceStat.st_size);

    // Note that per man page for large files, you have to iterate until the
    // whole file is copied (Linux has a limit of 0x7ffff000 bytes copied).
    while (size > 0)
    {
        ssize_t sent = sendfile(outFd, inFd, nullptr, (size >= SSIZE_MAX ? SSIZE_MAX : static_cast<size_t>(size)));
        if (sent < 0)
        {
            if (errno != EINVAL && errno != ENOSYS)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else
        {
            assert(UnsignedCast(sent) <= size);
            size -= UnsignedCast(sent);
        }
    }
    if (size == 0)
    {
        copied = true;
    }
    // sendfile couldn't be used; fall back to a manual copy below. This could happen
    // if we're on an old kernel, for example, where sendfile could only be used
    // with sockets and not regular files.
#endif // HAVE_SENDFILE

    // Manually read all data from the source and write it to the destination.
    if (!copied && CopyFile_ReadWrite(inFd, outFd) != 0)
    {
        return -1;
    }

    // Now that the data from the file has been copied, copy over metadata
    // from the source file.  First copy the file times.
    while (CheckInterrupted(ret = fstat_(inFd, &sourceStat)));
    if (ret == 0)
    {
        struct timeval origTimes[2];
        origTimes[0].tv_sec = sourceStat.st_atime;
        origTimes[0].tv_usec = 0;
        origTimes[1].tv_sec = sourceStat.st_mtime;
        origTimes[1].tv_usec = 0;
        while (CheckInterrupted(ret = futimes(outFd, origTimes)));
    }
    if (ret != 0)
    {
        return -1;
    }

    // Then copy permissions.
    while (CheckInterrupted(ret = fchmod(outFd, sourceStat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO))));
    if (ret != 0)
    {
        return -1;
    }

    return 0;
#endif // HAVE_FCOPYFILE
}
Example #5
0
int32_t SystemNative_CopyFile(intptr_t sourceFd, intptr_t destinationFd)
{
    int inFd = ToFileDescriptor(sourceFd);
    int outFd = ToFileDescriptor(destinationFd);

#if HAVE_FCOPYFILE
    // If fcopyfile is available (OS X), try to use it, as the whole copy
    // can be performed in the kernel, without lots of unnecessary copying.
    // Copy data and metadata.
    return fcopyfile(inFd, outFd, NULL, COPYFILE_ALL) == 0 ? 0 : -1;
#else
    // Get the stats on the source file.
    int ret;
    struct stat_ sourceStat;
    bool copied = false;
#if HAVE_SENDFILE_4
    // If sendfile is available (Linux), try to use it, as the whole copy
    // can be performed in the kernel, without lots of unnecessary copying.
    while ((ret = fstat_(inFd, &sourceStat)) < 0 && errno == EINTR);
    if (ret != 0)
    {
        return -1;
    }


    // On 32-bit, if you use 64-bit offsets, the last argument of `sendfile' will be a
    // `size_t' a 32-bit integer while the `st_size' field of the stat structure will be off64_t.
    // So `size' will have to be `uint64_t'. In all other cases, it will be `size_t'.
    uint64_t size = (uint64_t)sourceStat.st_size;

    // Note that per man page for large files, you have to iterate until the
    // whole file is copied (Linux has a limit of 0x7ffff000 bytes copied).
    while (size > 0)
    {
        ssize_t sent = sendfile(outFd, inFd, NULL, (size >= SSIZE_MAX ? SSIZE_MAX : (size_t)size));
        if (sent < 0)
        {
            if (errno != EINVAL && errno != ENOSYS)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else
        {
            assert((size_t)sent <= size);
            size -= (size_t)sent;
        }
    }
    if (size == 0)
    {
        copied = true;
    }
    // sendfile couldn't be used; fall back to a manual copy below. This could happen
    // if we're on an old kernel, for example, where sendfile could only be used
    // with sockets and not regular files.
#endif // HAVE_SENDFILE_4

    // Manually read all data from the source and write it to the destination.
    if (!copied && CopyFile_ReadWrite(inFd, outFd) != 0)
    {
        return -1;
    }

    // Now that the data from the file has been copied, copy over metadata
    // from the source file.  First copy the file times.
    // If futimes nor futimes are available on this platform, file times will
    // not be copied over.
    while ((ret = fstat_(inFd, &sourceStat)) < 0 && errno == EINTR);
    if (ret == 0)
    {
#if HAVE_FUTIMES
        struct timeval origTimes[2];
        origTimes[0].tv_sec = sourceStat.st_atime;
        origTimes[0].tv_usec = ST_ATIME_NSEC(&sourceStat) / 1000;
        origTimes[1].tv_sec = sourceStat.st_mtime;
        origTimes[1].tv_usec = ST_MTIME_NSEC(&sourceStat) / 1000;
        while ((ret = futimes(outFd, origTimes)) < 0 && errno == EINTR);
#elif HAVE_FUTIMENS
        // futimes is not a POSIX function, and not available on Android,
        // but futimens is
        struct timespec origTimes[2];
        origTimes[0].tv_sec = (time_t)sourceStat.st_atime;
        origTimes[0].tv_nsec = ST_ATIME_NSEC(&sourceStat);
        origTimes[1].tv_sec = (time_t)sourceStat.st_mtime;
        origTimes[1].tv_nsec = ST_MTIME_NSEC(&sourceStat);
        while ((ret = futimens(outFd, origTimes)) < 0 && errno == EINTR);
#endif
    }
    if (ret != 0)
    {
        return -1;
    }

    // Then copy permissions.
    while ((ret = fchmod(outFd, sourceStat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO))) < 0 && errno == EINTR);
    if (ret != 0)
    {
        return -1;
    }

    return 0;
#endif // HAVE_FCOPYFILE
}
Example #6
0
/*
 * compress the given file: create a corresponding .gz file and remove the
 * original.
 */
static off_t
file_compress(char *file, char *outfile, size_t outsize)
{
	int in;
	int out;
	off_t size, insize;
#ifndef SMALL
	struct stat isb, osb;
	const suffixes_t *suff;
#endif

	in = open(file, O_RDONLY);
	if (in == -1) {
		maybe_warn("can't open %s", file);
		return (-1);
	}

#ifndef SMALL
	bzero(&isb, sizeof(isb));
	if (fstat(in, &isb) != 0) {
		maybe_warn("couldn't stat: %s", file);
		close(in);
		return (-1);
	}
#endif

	if (cflag == 0) {
#ifndef SMALL
		if (isb.st_nlink > 1 && fflag == 0) {
			maybe_warnx("%s has %d other link%s -- skipping",
			    file, isb.st_nlink - 1,
			    (isb.st_nlink - 1) == 1 ? "" : "s");
			close(in);
			return (-1);
		}

		if (fflag == 0 && (suff = check_suffix(file, 0)) &&
		    suff->zipped[0] != 0) {
			maybe_warnx("%s already has %s suffix -- unchanged",
			    file, suff->zipped);
			close(in);
			return (-1);
		}
#endif

		/* Add (usually) .gz to filename */
		if ((size_t)snprintf(outfile, outsize, "%s%s",
		    file, suffixes[0].zipped) >= outsize)
			memcpy(outfile + outsize - suffixes[0].ziplen - 1,
			    suffixes[0].zipped, suffixes[0].ziplen + 1);

#ifndef SMALL
		if (check_outfile(outfile) == 0) {
			close(in);
			return (-1);
		}
#endif
	}

	if (cflag == 0) {
		out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
		if (out == -1) {
			maybe_warn("could not create output: %s", outfile);
			fclose(stdin);
			return (-1);
		}
#ifndef SMALL
		remove_file = outfile;
#endif
	} else
		out = fileno(stdout);

	insize = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime);

#ifndef __APPLE__
	(void)close(in);
#endif /* !__APPLE__ */

	/*
	 * If there was an error, insize will be -1.
	 * If we compressed to stdout, just return the size.
	 * Otherwise stat the file and check it is the correct size.
	 * We only blow away the file if we can stat the output and it
	 * has the expected size.
	 */
	if (cflag != 0)
		return (insize == -1 ? -1 : size);

#ifndef SMALL
	if (fstat(out, &osb) != 0) {
		maybe_warn("couldn't stat: %s", outfile);
		goto bad_outfile;
	}

	if (osb.st_size != size) {
		maybe_warnx("output file: %s wrong size (%ju != %ju), deleting",
		    outfile, (uintmax_t)osb.st_size, (uintmax_t)size);
		goto bad_outfile;
	}

#ifdef __APPLE__
	fcopyfile(in, out, 0, COPYFILE_ACL | COPYFILE_XATTR);
	clear_type_and_creator(out);
#endif /* __APPLE__ */
	copymodes(out, &isb, outfile);
	remove_file = NULL;
#endif
#ifdef __APPLE__
	(void)close(in);
#endif /* __APPLE__ */
	if (close(out) == -1)
		maybe_warn("couldn't close output");

	/* output is good, ok to delete input */
	unlink_input(file, &isb);
	return (size);

#ifndef SMALL
    bad_outfile:
	if (close(out) == -1)
		maybe_warn("couldn't close output");

	maybe_warnx("leaving original %s", file);
	unlink(outfile);
	return (size);
#endif
}