From 532d4a24e2013262dfa41fd85c06a9715c99abf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 24 Oct 2022 21:03:42 +0200 Subject: New upstream version 4.7 --- src/io.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 240 insertions(+), 47 deletions(-) (limited to 'src/io.c') diff --git a/src/io.c b/src/io.c index a4dd962..b5bdc08 100644 --- a/src/io.c +++ b/src/io.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -25,12 +26,18 @@ # include # include #endif +#if __linux__ +# include +#endif #include #include #include #include #include #include "internal.h" +#ifndef O_CLOEXEC +# define O_CLOEXEC 0 +#endif struct HXdir { #if defined _WIN32 @@ -159,46 +166,72 @@ EXPORT_SYMBOL void HXdir_close(struct HXdir *d) EXPORT_SYMBOL int HX_copy_file(const char *src, const char *dest, unsigned int opts, ...) { - char buf[MAXLNLEN]; + static const size_t bufsize = 0x10000; + void *buf; unsigned int extra_flags = 0; - int dd, eax = 0, sd, l; + int srcfd, dstfd; - if ((sd = open(src, O_RDONLY | O_BINARY)) < 0) + buf = malloc(bufsize); + if (buf == nullptr) return -errno; + srcfd = open(src, O_RDONLY | O_BINARY); + if (srcfd < 0) { + free(buf); + return -errno; + } if (opts & HXF_KEEP) extra_flags = O_EXCL; - dd = open(dest, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC | - extra_flags, S_IRUGO | S_IWUGO); - if (dd < 0) { - eax = errno; - close(sd); - errno = eax; - if (extra_flags != 0 && eax == EEXIST) - return 1; - return -errno; + dstfd = open(dest, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC | + extra_flags, S_IRUGO | S_IWUGO); + if (dstfd < 0) { + int saved_errno = errno; + free(buf); + close(srcfd); + return -(errno = saved_errno); } - while ((l = read(sd, buf, MAXLNLEN)) > 0 && write(dd, buf, l) > 0) - ; - close(sd); - if (opts & (HXF_UID | HXF_GID)) { struct stat sb; long uid, gid; va_list argp; va_start(argp, opts); - fstat(dd, &sb); + if (fstat(dstfd, &sb) < 0) { + int saved_errno = errno; + unlink(dest); + close(dstfd); + close(srcfd); + return -(errno = saved_errno); + } uid = sb.st_uid; gid = sb.st_gid; if (opts & HXF_UID) uid = va_arg(argp, long); if (opts & HXF_GID) gid = va_arg(argp, long); - if (fchown(dd, uid, gid) < 0) - {}; + if (fchown(dstfd, uid, gid) < 0) { + int saved_errno = errno; + unlink(dest); + close(dstfd); + close(srcfd); + return -(errno = saved_errno); + } va_end(argp); } - close(dd); + + while (true) { + ssize_t rdret = HX_sendfile(dstfd, srcfd, SIZE_MAX); + if (rdret == 0) + break; + if (rdret < 0 && errno != EINTR) { + int saved_errno = errno; + close(srcfd); + close(dstfd); + return -(errno = saved_errno); + } + } + close(srcfd); + close(dstfd); + free(buf); return 1; } @@ -300,27 +333,42 @@ EXPORT_SYMBOL int HX_mkdir(const char *idir, unsigned int mode) /* Readlink - with a trailing zero (provided by HXmc) */ EXPORT_SYMBOL int HX_readlink(hxmc_t **target, const char *path) { - bool dnull = *target == NULL; - char *tb; - int ret; + bool allocate = *target == NULL; + size_t linkbuf_size; - if (dnull) { - *target = HXmc_meminit(NULL, PATH_MAX); + if (allocate) { + linkbuf_size = 32; + *target = HXmc_meminit(NULL, 32); if (*target == NULL) return -errno; + } else { + linkbuf_size = HXmc_length(*target); } - tb = *target; - ret = readlink(path, tb, PATH_MAX); - if (ret < 0) { - ret = -errno; - if (!dnull) { - HXmc_free(*target); - *target = NULL; + while (true) { + ssize_t ret = readlink(path, *target, linkbuf_size); + if (ret < 0) { + int saved_errno = errno; + if (allocate) { + HXmc_free(*target); + *target = nullptr; + } + return -(errno = saved_errno); + } + if (static_cast(size_t, ret) < linkbuf_size) { + HXmc_setlen(target, ret); + return ret; + } + linkbuf_size *= 2; + if (HXmc_setlen(target, linkbuf_size) == NULL) { + int saved_errno = errno; + if (allocate) { + HXmc_free(*target); + *target = nullptr; + } + return -(errno = saved_errno); } - return ret; } - HXmc_setlen(target, ret); - return ret; + return 0; } /** @@ -533,31 +581,176 @@ EXPORT_SYMBOL int HX_rrmdir(const char *dir) EXPORT_SYMBOL ssize_t HXio_fullread(int fd, void *vbuf, size_t size) { char *buf = vbuf; - size_t rem = size; - ssize_t ret; + size_t done = 0; + if (size > SSIZE_MAX) + size = SSIZE_MAX; - while (rem > 0) { - ret = read(fd, buf, rem); + while (done < size) { + ssize_t ret = read(fd, buf, size - done); if (ret < 0) return ret; - rem -= ret; + else if (ret == 0) + break; + done += ret; buf += ret; } - return size; + return done; } EXPORT_SYMBOL ssize_t HXio_fullwrite(int fd, const void *vbuf, size_t size) { const char *buf = vbuf; - size_t rem = size; - ssize_t ret; + size_t done = 0; + if (size > SSIZE_MAX) + size = SSIZE_MAX; - while (rem > 0) { - ret = write(fd, buf, rem); + while (done < size) { + ssize_t ret = write(fd, buf, size - done); if (ret < 0) return ret; - rem -= ret; + else if (ret == 0) + break; + done += ret; buf += ret; } - return size; + return done; +} + +#if __linux__ +static ssize_t HX_sendfile_linux(int dst, int src, size_t count) +{ + long pagesize = sysconf(_SC_PAGE_SIZE); + size_t xfersize; + ssize_t ret, xferd = 0; + + if (pagesize < 0) + pagesize = 4096; + xfersize = SSIZE_MAX - pagesize; + if (count > xfersize) + count = xfersize; + while ((ret = sendfile(dst, src, nullptr, count)) > 0) + xferd += ret; + if (xferd > 0) + return xferd; + if (ret < 0) + return -errno; + return 0; +} +#endif + +static ssize_t HX_sendfile_rw(int dst, int src, size_t count) +{ + static const size_t bufsize = 0x10000; + size_t xferd = 0; + ssize_t ret; + void *buf = malloc(bufsize); + if (buf == nullptr) + return -ENOMEM; + if (count > SSIZE_MAX) + count = SSIZE_MAX; + while (count > 0) { + size_t readsize = bufsize; + if (count < readsize) + readsize = count; + ret = HXio_fullread(src, buf, readsize); + if (ret < 0) { + errno = -ret; + break; + } + ret = HXio_fullwrite(dst, buf, ret); + if (ret < 0) { + errno = -ret; + break; + } + xferd += ret; + count -= ret; + } + if (xferd > 0) + return xferd; + if (ret < 0) + return -errno; + return 0; +} + +EXPORT_SYMBOL ssize_t HX_sendfile(int dst, int src, size_t count) +{ +#if __linux__ + ssize_t ret = HX_sendfile_linux(dst, src, count); + if (ret != -ENOSYS) + return ret; +#endif + return HX_sendfile_rw(dst, src, count); +} + +EXPORT_SYMBOL char *HX_slurp_fd(int fd, size_t *outsize) +{ + struct stat sb; + if (fstat(fd, &sb) < 0) + return NULL; + if (sb.st_size == 0) { + /* e.g. ttys (S_ISCHR) or special procfs files */ + size_t bufsize = 4096, offset = 0; + char *buf = malloc(bufsize); + if (buf == nullptr) + return nullptr; + ssize_t rdret; + while ((rdret = read(fd, buf, bufsize - 1 - offset)) > 0) { + offset += rdret; + if (bufsize - offset >= 4095) + /* any value would work, but >=1 is not all that efficient */ + continue; + if (bufsize > SSIZE_MAX) + /* No more doubling */ + break; + bufsize *= 2; + void *nbuf = realloc(buf, bufsize + 1); + if (nbuf == nullptr) { + int se = errno; + free(buf); + errno = se; + return nullptr; + } + buf = nbuf; + } + buf[offset] = '\0'; + if (outsize != nullptr) + *outsize = offset; + return buf; + } + size_t fsize = sb.st_size; /* may truncate from loff_t to size_t */ + if (fsize == SIZE_MAX) + --fsize; + char *buf = malloc(fsize + 1); + if (buf == NULL) + return NULL; + ssize_t rdret = HXio_fullread(fd, buf, fsize); + if (rdret < 0) { + int se = errno; + free(buf); + errno = se; + return NULL; + } + buf[rdret] = '\0'; + if (outsize != NULL) + *outsize = rdret; + return buf; +} + +EXPORT_SYMBOL char *HX_slurp_file(const char *file, size_t *outsize) +{ + int fd = open(file, O_RDONLY | O_BINARY | O_CLOEXEC); + if (fd < 0) + return NULL; + size_t tmpsize; + if (outsize == NULL) + outsize = &tmpsize; + char *buf = HX_slurp_fd(fd, outsize); + if (buf == NULL) { + int se = errno; + close(fd); + errno = se; + return NULL; + } + close(fd); + return buf; } -- cgit v1.2.3 From 8132c809273676b684f426ae8c0f8b1e6f40166e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 31 Dec 2022 10:03:34 +0100 Subject: New upstream version 4.8 --- src/io.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src/io.c') diff --git a/src/io.c b/src/io.c index b5bdc08..c797193 100644 --- a/src/io.c +++ b/src/io.c @@ -7,6 +7,9 @@ * General Public License as published by the Free Software Foundation; * either version 2.1 or (at your option) any later version. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include #include #include @@ -694,10 +697,13 @@ EXPORT_SYMBOL char *HX_slurp_fd(int fd, size_t *outsize) if (buf == nullptr) return nullptr; ssize_t rdret; - while ((rdret = read(fd, buf, bufsize - 1 - offset)) > 0) { + while ((rdret = read(fd, buf + offset, bufsize - 1 - offset)) > 0) { offset += rdret; + /* + * Make it so that the next read call is not called + * with an exceptionally small size. + */ if (bufsize - offset >= 4095) - /* any value would work, but >=1 is not all that efficient */ continue; if (bufsize > SSIZE_MAX) /* No more doubling */ @@ -720,6 +726,11 @@ EXPORT_SYMBOL char *HX_slurp_fd(int fd, size_t *outsize) size_t fsize = sb.st_size; /* may truncate from loff_t to size_t */ if (fsize == SIZE_MAX) --fsize; +#ifdef HAVE_POSIX_FADVISE + if (fsize > 0 && posix_fadvise(fd, 0, fsize, + POSIX_FADV_SEQUENTIAL) != 0) + /* ignore */; +#endif char *buf = malloc(fsize + 1); if (buf == NULL) return NULL; -- cgit v1.2.3 From bfef0924f58eab930bdd826ac0132786abc32220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 29 Jan 2023 16:17:51 +0100 Subject: New upstream version 4.10 --- src/io.c | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) (limited to 'src/io.c') diff --git a/src/io.c b/src/io.c index c797193..720a9c5 100644 --- a/src/io.c +++ b/src/io.c @@ -57,22 +57,23 @@ struct HXdir { static int mkdir_gen(const char *d, unsigned int mode) { struct stat sb; - if (lstat(d, &sb) < 0) { #if defined(_WIN32) - if (mkdir(d) < 0) + if (mkdir(d) == 0) #else - if (mkdir(d, mode) < 0) /* use umask() for permissions */ + if (mkdir(d, mode) == 0) /* use umask() for permissions */ #endif - return -errno; - } else { + return 1; + if (errno != EEXIST) + return -errno; + if (lstat(d, &sb) == 0) { #if defined(_WIN32) - if ((sb.st_mode & S_IFDIR) != S_IFDIR) + if (sb.st_mode & S_IFDIR) #else - if (!S_ISDIR(sb.st_mode)) + if (S_ISDIR(sb.st_mode)) #endif - return -errno; + return 0; } - return 1; + return -EEXIST; } EXPORT_SYMBOL struct HXdir *HXdir_open(const char *s) @@ -204,6 +205,8 @@ EXPORT_SYMBOL int HX_copy_file(const char *src, const char *dest, unlink(dest); close(dstfd); close(srcfd); + free(buf); + va_end(argp); return -(errno = saved_errno); } uid = sb.st_uid; @@ -216,6 +219,8 @@ EXPORT_SYMBOL int HX_copy_file(const char *src, const char *dest, unlink(dest); close(dstfd); close(srcfd); + free(buf); + va_end(argp); return -(errno = saved_errno); } va_end(argp); @@ -229,6 +234,7 @@ EXPORT_SYMBOL int HX_copy_file(const char *src, const char *dest, int saved_errno = errno; close(srcfd); close(dstfd); + free(buf); return -(errno = saved_errno); } } @@ -264,8 +270,8 @@ EXPORT_SYMBOL int HX_copy_dir(const char *src, const char *dest, continue; snprintf(fsrc, MAXFNLEN, "%s/%s", src, fn); snprintf(fdest, MAXFNLEN, "%s/%s", dest, fn); - - lstat(fsrc, &sb); + if (lstat(fsrc, &sb) < 0) + continue; sb.st_mode &= 0777; /* clear SUID/GUID/Sticky bits */ if (S_ISREG(sb.st_mode)) { @@ -278,17 +284,20 @@ EXPORT_SYMBOL int HX_copy_dir(const char *src, const char *dest, memset(pt, '\0', MAXFNLEN); if (readlink(fsrc, pt, MAXFNLEN - 1) < MAXFNLEN - 1) if (symlink(pt, fdest) < 0) - {}; + /* ignore */; } else if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { - mknod(fdest, sb.st_mode, sb.st_dev); + if (mknod(fdest, sb.st_mode, sb.st_dev) < 0) + /* ignore */; } else if (S_ISFIFO(sb.st_mode)) { - mkfifo(fdest, sb.st_mode); + if (mkfifo(fdest, sb.st_mode) < 0) + /* ignore */; } if (lchown(fdest, uid, gid) < 0) - {}; + /* ignore */; if (!S_ISLNK(sb.st_mode)) - chmod(fdest, sb.st_mode); + if (chmod(fdest, sb.st_mode) < 0) + /* ignore */; } HXdir_close(dt); @@ -321,12 +330,12 @@ EXPORT_SYMBOL int HX_mkdir(const char *idir, unsigned int mode) if (dir[i] == '/') { strncpy(buf, dir, i); buf[i] = '\0'; - if ((v = mkdir_gen(buf, mode)) <= 0) + if ((v = mkdir_gen(buf, mode)) < 0) return v; } else if (i == len - 1) { strncpy(buf, dir, len); buf[len] = '\0'; - if ((v = mkdir_gen(buf, mode)) <= 0) + if ((v = mkdir_gen(buf, mode)) < 0) return v; } } @@ -358,7 +367,8 @@ EXPORT_SYMBOL int HX_readlink(hxmc_t **target, const char *path) return -(errno = saved_errno); } if (static_cast(size_t, ret) < linkbuf_size) { - HXmc_setlen(target, ret); + (*target)[ret] = '\0'; // please cov-scan + HXmc_setlen(target, ret); // \0 set here anyway return ret; } linkbuf_size *= 2; @@ -500,7 +510,7 @@ EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path, ret = HX_realpath_symres(&state, path); if (ret == -EINVAL) continue; - else if (ret < 0) + else if (ret <= 0) goto out; path = state.path; } @@ -668,6 +678,7 @@ static ssize_t HX_sendfile_rw(int dst, int src, size_t count) xferd += ret; count -= ret; } + free(buf); if (xferd > 0) return xferd; if (ret < 0) -- cgit v1.2.3