X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Fcopy.c;h=3744797b9502788b8d16335085ec3ca89a7492f5;hb=78c958f82e929f015169ce1ed614d1e9c50928aa;hp=867e49bf89ee5a7d92d869ef31e270bd5a6f0f58;hpb=e156347e0480d3eee4877463297149ae96e34f8c;p=elogind.git diff --git a/src/shared/copy.c b/src/shared/copy.c index 867e49bf8..3744797b9 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -22,15 +22,25 @@ #include "util.h" #include "copy.h" -int copy_bytes(int fdf, int fdt) { +int copy_bytes(int fdf, int fdt, off_t max_bytes) { assert(fdf >= 0); assert(fdt >= 0); for (;;) { char buf[PIPE_BUF]; ssize_t n, k; + size_t m = sizeof(buf); - n = read(fdf, buf, sizeof(buf)); + if (max_bytes != (off_t) -1) { + + if (max_bytes <= 0) + return -E2BIG; + + if ((off_t) m > max_bytes) + m = (size_t) max_bytes; + } + + n = read(fdf, buf, m); if (n < 0) return -errno; if (n == 0) @@ -42,6 +52,11 @@ int copy_bytes(int fdf, int fdt) { return k; if (k != n) return errno ? -errno : -EIO; + + if (max_bytes != (off_t) -1) { + assert(max_bytes >= n); + max_bytes -= n; + } } return 0; @@ -84,7 +99,7 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int if (fdt < 0) return -errno; - r = copy_bytes(fdf, fdt); + r = copy_bytes(fdf, fdt, (off_t) -1); if (r < 0) { unlinkat(dt, to, 0); return r; @@ -179,6 +194,8 @@ static int fd_copy_directory(int df, const char *from, const struct stat *st, in if (fdt < 0) return -errno; + r = 0; + if (created) { if (fchown(fdt, st->st_uid, st->st_gid) < 0) r = -errno; @@ -187,7 +204,6 @@ static int fd_copy_directory(int df, const char *from, const struct stat *st, in r = -errno; } - r = 0; FOREACH_DIRENT(de, d, return -errno) { struct stat buf; int q; @@ -261,7 +277,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode) { if (fdt < 0) return -errno; - r = copy_bytes(fdf, fdt); + r = copy_bytes(fdf, fdt, (off_t) -1); if (r < 0) { unlink(to); return r;