"Fossies" - the Fresh Open Source Software Archive

Member "lxc-4.0.10/src/lxc/file_utils.c" (16 Jul 2021, 13792 Bytes) of package /linux/misc/lxc-4.0.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "file_utils.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.0.9_vs_4.0.10.

    1 /* SPDX-License-Identifier: LGPL-2.1+ */
    2 
    3 #ifndef _GNU_SOURCE
    4 #define _GNU_SOURCE 1
    5 #endif
    6 #include <errno.h>
    7 #include <fcntl.h>
    8 #include <linux/magic.h>
    9 #include <stdio.h>
   10 #include <stdlib.h>
   11 #include <sys/sendfile.h>
   12 #include <sys/stat.h>
   13 #include <sys/types.h>
   14 #include <time.h>
   15 
   16 #include "config.h"
   17 #include "file_utils.h"
   18 #include "macro.h"
   19 #include "memory_utils.h"
   20 #include "string_utils.h"
   21 #include "syscall_wrappers.h"
   22 #include "utils.h"
   23 
   24 int lxc_open_dirfd(const char *dir)
   25 {
   26     return open_at(-EBADF, dir, PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE & ~RESOLVE_NO_XDEV, 0);
   27 }
   28 
   29 int lxc_readat(int dirfd, const char *filename, void *buf, size_t count)
   30 {
   31     __do_close int fd = -EBADF;
   32     ssize_t ret;
   33 
   34     fd = open_at(dirfd, filename, PROTECT_OPEN, PROTECT_LOOKUP_BENEATH, 0);
   35     if (fd < 0)
   36         return -errno;
   37 
   38     ret = lxc_read_nointr(fd, buf, count);
   39     if (ret < 0)
   40         return -errno;
   41 
   42     return ret;
   43 }
   44 
   45 int lxc_writeat(int dirfd, const char *filename, const void *buf, size_t count)
   46 {
   47     __do_close int fd = -EBADF;
   48     ssize_t ret;
   49 
   50     fd = open_at(dirfd, filename, PROTECT_OPEN_W_WITH_TRAILING_SYMLINKS, PROTECT_LOOKUP_BENEATH, 0);
   51     if (fd < 0)
   52         return -1;
   53 
   54     ret = lxc_write_nointr(fd, buf, count);
   55     if (ret < 0 || (size_t)ret != count)
   56         return -1;
   57 
   58     return 0;
   59 }
   60 
   61 int lxc_write_openat(const char *dir, const char *filename, const void *buf,
   62              size_t count)
   63 {
   64     __do_close int dirfd = -EBADF;
   65 
   66     dirfd = open(dir, PROTECT_OPEN);
   67     if (dirfd < 0)
   68         return -errno;
   69 
   70     return lxc_writeat(dirfd, filename, buf, count);
   71 }
   72 
   73 int lxc_write_to_file(const char *filename, const void *buf, size_t count,
   74               bool add_newline, mode_t mode)
   75 {
   76     __do_close int fd = -EBADF;
   77     ssize_t ret;
   78 
   79     fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
   80     if (fd < 0)
   81         return -1;
   82 
   83     ret = lxc_write_nointr(fd, buf, count);
   84     if (ret < 0)
   85         return -1;
   86 
   87     if ((size_t)ret != count)
   88         return -1;
   89 
   90     if (add_newline) {
   91         ret = lxc_write_nointr(fd, "\n", 1);
   92         if (ret != 1)
   93             return -1;
   94     }
   95 
   96     return 0;
   97 }
   98 
   99 int lxc_read_from_file(const char *filename, void *buf, size_t count)
  100 {
  101     __do_close int fd = -EBADF;
  102     ssize_t ret;
  103 
  104     fd = open(filename, O_RDONLY | O_CLOEXEC);
  105     if (fd < 0)
  106         return -1;
  107 
  108     if (!buf || !count) {
  109         char buf2[100];
  110         size_t count2 = 0;
  111 
  112         while ((ret = lxc_read_nointr(fd, buf2, 100)) > 0)
  113             count2 += ret;
  114 
  115         if (ret >= 0)
  116             ret = count2;
  117     } else {
  118         memset(buf, 0, count);
  119         ret = lxc_read_nointr(fd, buf, count);
  120     }
  121 
  122     return ret;
  123 }
  124 
  125 ssize_t lxc_read_try_buf_at(int dfd, const char *path, void *buf, size_t count)
  126 {
  127     __do_close int fd = -EBADF;
  128     ssize_t ret;
  129 
  130     fd = open_at(dfd, path, PROTECT_OPEN, PROTECT_LOOKUP_BENEATH, 0);
  131     if (fd < 0)
  132         return -errno;
  133 
  134     if (!buf || !count) {
  135         char buf2[100];
  136         size_t count2 = 0;
  137 
  138         while ((ret = lxc_read_nointr(fd, buf2, 100)) > 0)
  139             count2 += ret;
  140 
  141         if (ret >= 0)
  142             ret = count2;
  143     } else {
  144         memset(buf, 0, count);
  145         ret = lxc_read_nointr(fd, buf, count);
  146     }
  147 
  148     return ret;
  149 }
  150 
  151 ssize_t lxc_write_nointr(int fd, const void *buf, size_t count)
  152 {
  153     ssize_t ret;
  154 
  155     do {
  156         ret = write(fd, buf, count);
  157     } while (ret < 0 && errno == EINTR);
  158 
  159     return ret;
  160 }
  161 
  162 ssize_t lxc_pwrite_nointr(int fd, const void *buf, size_t count, off_t offset)
  163 {
  164     ssize_t ret;
  165 
  166     do {
  167         ret = pwrite(fd, buf, count, offset);
  168     } while (ret < 0 && errno == EINTR);
  169 
  170     return ret;
  171 }
  172 
  173 ssize_t lxc_send_nointr(int sockfd, void *buf, size_t len, int flags)
  174 {
  175     ssize_t ret;
  176 
  177     do {
  178         ret = send(sockfd, buf, len, flags);
  179     } while (ret < 0 && errno == EINTR);
  180 
  181     return ret;
  182 }
  183 
  184 ssize_t lxc_read_nointr(int fd, void *buf, size_t count)
  185 {
  186     ssize_t ret;
  187 
  188     do {
  189         ret = read(fd, buf, count);
  190     } while (ret < 0 && errno == EINTR);
  191 
  192     return ret;
  193 }
  194 
  195 ssize_t lxc_recv_nointr(int sockfd, void *buf, size_t len, int flags)
  196 {
  197     ssize_t ret;
  198 
  199     do {
  200         ret = recv(sockfd, buf, len, flags);
  201     } while (ret < 0 && errno == EINTR);
  202 
  203     return ret;
  204 }
  205 
  206 ssize_t lxc_recvmsg_nointr_iov(int sockfd, struct iovec *iov, size_t iovlen,
  207                    int flags)
  208 {
  209     ssize_t ret;
  210     struct msghdr msg = {
  211         .msg_iov = iov,
  212         .msg_iovlen = iovlen,
  213     };
  214 
  215     do {
  216         ret = recvmsg(sockfd, &msg, flags);
  217     } while (ret < 0 && errno == EINTR);
  218 
  219     return ret;
  220 }
  221 
  222 ssize_t lxc_read_nointr_expect(int fd, void *buf, size_t count,
  223                    const void *expected_buf)
  224 {
  225     ssize_t ret;
  226 
  227     ret = lxc_read_nointr(fd, buf, count);
  228     if (ret < 0)
  229         return ret;
  230 
  231     if ((size_t)ret != count)
  232         return -1;
  233 
  234     if (expected_buf && memcmp(buf, expected_buf, count) != 0)
  235         return ret_set_errno(-1, EINVAL);
  236 
  237     return 0;
  238 }
  239 
  240 ssize_t lxc_read_file_expect(const char *path, void *buf, size_t count,
  241                  const void *expected_buf)
  242 {
  243     __do_close int fd = -EBADF;
  244 
  245     fd = open(path, O_RDONLY | O_CLOEXEC);
  246     if (fd < 0)
  247         return -1;
  248 
  249     return lxc_read_nointr_expect(fd, buf, count, expected_buf);
  250 }
  251 
  252 bool file_exists(const char *f)
  253 {
  254     struct stat statbuf;
  255 
  256     return stat(f, &statbuf) == 0;
  257 }
  258 
  259 int print_to_file(const char *file, const char *content)
  260 {
  261     __do_fclose FILE *f = NULL;
  262     int ret = 0;
  263 
  264     f = fopen(file, "we");
  265     if (!f)
  266         return -1;
  267 
  268     if (fprintf(f, "%s", content) != strlen(content))
  269         ret = -1;
  270 
  271     return ret;
  272 }
  273 
  274 int is_dir(const char *path)
  275 {
  276     int ret;
  277     struct stat statbuf;
  278 
  279     ret = stat(path, &statbuf);
  280     if (ret == 0 && S_ISDIR(statbuf.st_mode))
  281         return 1;
  282 
  283     return 0;
  284 }
  285 
  286 /*
  287  * Return the number of lines in file @fn, or -1 on error
  288  */
  289 int lxc_count_file_lines(const char *fn)
  290 {
  291     __do_free char *line = NULL;
  292     __do_fclose FILE *f = NULL;
  293     size_t sz = 0;
  294     int n = 0;
  295 
  296     f = fopen_cloexec(fn, "r");
  297     if (!f)
  298         return -1;
  299 
  300     while (getline(&line, &sz, f) != -1)
  301         n++;
  302 
  303     return n;
  304 }
  305 
  306 int lxc_make_tmpfile(char *template, bool rm)
  307 {
  308     __do_close int fd = -EBADF;
  309     int ret;
  310     mode_t msk;
  311 
  312     msk = umask(0022);
  313     fd = mkstemp(template);
  314     umask(msk);
  315     if (fd < 0)
  316         return -1;
  317 
  318     if (lxc_set_cloexec(fd))
  319         return -1;
  320 
  321     if (!rm)
  322         return move_fd(fd);
  323 
  324     ret = unlink(template);
  325     if (ret < 0)
  326         return -1;
  327 
  328     return move_fd(fd);
  329 }
  330 
  331 bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val)
  332 {
  333     return (fs->f_type == (fs_type_magic)magic_val);
  334 }
  335 
  336 bool has_fs_type(const char *path, fs_type_magic magic_val)
  337 {
  338     int ret;
  339     struct statfs sb;
  340 
  341     ret = statfs(path, &sb);
  342     if (ret < 0)
  343         return false;
  344 
  345     return is_fs_type(&sb, magic_val);
  346 }
  347 
  348 bool fhas_fs_type(int fd, fs_type_magic magic_val)
  349 {
  350     int ret;
  351     struct statfs sb;
  352 
  353     ret = fstatfs(fd, &sb);
  354     if (ret < 0)
  355         return false;
  356 
  357     return is_fs_type(&sb, magic_val);
  358 }
  359 
  360 FILE *fopen_cloexec(const char *path, const char *mode)
  361 {
  362     __do_close int fd = -EBADF;
  363     int open_mode = 0, step = 0;
  364     FILE *f;
  365 
  366     if (strnequal(mode, "r+", 2)) {
  367         open_mode = O_RDWR;
  368         step = 2;
  369     } else if (strnequal(mode, "r", 1)) {
  370         open_mode = O_RDONLY;
  371         step = 1;
  372     } else if (strnequal(mode, "w+", 2)) {
  373         open_mode = O_RDWR | O_TRUNC | O_CREAT;
  374         step = 2;
  375     } else if (strnequal(mode, "w", 1)) {
  376         open_mode = O_WRONLY | O_TRUNC | O_CREAT;
  377         step = 1;
  378     } else if (strnequal(mode, "a+", 2)) {
  379         open_mode = O_RDWR | O_CREAT | O_APPEND;
  380         step = 2;
  381     } else if (strnequal(mode, "a", 1)) {
  382         open_mode = O_WRONLY | O_CREAT | O_APPEND;
  383         step = 1;
  384     }
  385     for (; mode[step]; step++)
  386         if (mode[step] == 'x')
  387             open_mode |= O_EXCL;
  388 
  389     fd = open(path, open_mode | O_CLOEXEC, 0660);
  390     if (fd < 0)
  391         return NULL;
  392 
  393     f = fdopen(fd, mode);
  394     if (f)
  395         move_fd(fd);
  396     return f;
  397 }
  398 
  399 ssize_t lxc_sendfile_nointr(int out_fd, int in_fd, off_t *offset, size_t count)
  400 {
  401     ssize_t ret;
  402 
  403     do {
  404         ret = sendfile(out_fd, in_fd, offset, count);
  405     } while (ret < 0 && errno == EINTR);
  406 
  407     return ret;
  408 }
  409 
  410 ssize_t __fd_to_fd(int from, int to)
  411 {
  412     ssize_t total_bytes = 0;
  413 
  414     for (;;) {
  415         uint8_t buf[PATH_MAX];
  416         uint8_t *p = buf;
  417         ssize_t bytes_to_write;
  418         ssize_t bytes_read;
  419 
  420         bytes_read = lxc_read_nointr(from, buf, sizeof buf);
  421         if (bytes_read < 0)
  422             return -1;
  423         if (bytes_read == 0)
  424             break;
  425 
  426         bytes_to_write = (size_t)bytes_read;
  427         total_bytes += bytes_read;
  428         do {
  429             ssize_t bytes_written;
  430 
  431             bytes_written = lxc_write_nointr(to, p, bytes_to_write);
  432             if (bytes_written < 0)
  433                 return -1;
  434 
  435             bytes_to_write -= bytes_written;
  436             p += bytes_written;
  437         } while (bytes_to_write > 0);
  438     }
  439 
  440     return total_bytes;
  441 }
  442 
  443 int fd_to_buf(int fd, char **buf, size_t *length)
  444 {
  445     __do_free char *copy = NULL;
  446 
  447     if (!length)
  448         return 0;
  449 
  450     *length = 0;
  451     for (;;) {
  452         ssize_t bytes_read;
  453         char chunk[4096];
  454         char *old = copy;
  455 
  456         bytes_read = lxc_read_nointr(fd, chunk, sizeof(chunk));
  457         if (bytes_read < 0)
  458             return -errno;
  459 
  460         if (!bytes_read)
  461             break;
  462 
  463         copy = realloc(old, (*length + bytes_read) * sizeof(*old));
  464         if (!copy)
  465             return ret_errno(ENOMEM);
  466 
  467         memcpy(copy + *length, chunk, bytes_read);
  468         *length += bytes_read;
  469     }
  470 
  471     *buf = move_ptr(copy);
  472     return 0;
  473 }
  474 
  475 char *file_to_buf(const char *path, size_t *length)
  476 {
  477     __do_close int fd = -EBADF;
  478     char *buf = NULL;
  479 
  480     if (!length)
  481         return NULL;
  482 
  483     fd = open(path, O_RDONLY | O_CLOEXEC);
  484     if (fd < 0)
  485         return NULL;
  486 
  487     if (fd_to_buf(fd, &buf, length) < 0)
  488         return NULL;
  489 
  490     return buf;
  491 }
  492 
  493 FILE *fopen_cached(const char *path, const char *mode, void **caller_freed_buffer)
  494 {
  495 #ifdef HAVE_FMEMOPEN
  496     __do_free char *buf = NULL;
  497     size_t len = 0;
  498     FILE *f;
  499 
  500     buf = file_to_buf(path, &len);
  501     if (!buf)
  502         return NULL;
  503 
  504     f = fmemopen(buf, len, mode);
  505     if (!f)
  506         return NULL;
  507     *caller_freed_buffer = move_ptr(buf);
  508     return f;
  509 #else
  510     return fopen(path, mode);
  511 #endif
  512 }
  513 
  514 FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer)
  515 {
  516     FILE *f;
  517 #ifdef HAVE_FMEMOPEN
  518     __do_free char *buf = NULL;
  519     size_t len = 0;
  520 
  521     if (fd_to_buf(fd, &buf, &len) < 0)
  522         return NULL;
  523 
  524     f = fmemopen(buf, len, mode);
  525     if (!f)
  526         return NULL;
  527 
  528     *caller_freed_buffer = move_ptr(buf);
  529 
  530 #else
  531 
  532     __do_close int dupfd = -EBADF;
  533 
  534     dupfd = dup(fd);
  535     if (dupfd < 0)
  536         return NULL;
  537 
  538     f = fdopen(dupfd, "re");
  539     if (!f)
  540         return NULL;
  541 
  542     /* Transfer ownership of fd. */
  543     move_fd(dupfd);
  544 #endif
  545     return f;
  546 }
  547 
  548 int fd_cloexec(int fd, bool cloexec)
  549 {
  550     int oflags, nflags;
  551 
  552     oflags = fcntl(fd, F_GETFD, 0);
  553     if (oflags < 0)
  554         return -errno;
  555 
  556     if (cloexec)
  557         nflags = oflags | FD_CLOEXEC;
  558     else
  559         nflags = oflags & ~FD_CLOEXEC;
  560 
  561     if (nflags == oflags)
  562         return 0;
  563 
  564     if (fcntl(fd, F_SETFD, nflags) < 0)
  565         return -errno;
  566 
  567     return 0;
  568 }
  569 
  570 FILE *fdopen_at(int dfd, const char *path, const char *mode,
  571         unsigned int o_flags, unsigned int resolve_flags)
  572 {
  573     __do_close int fd = -EBADF;
  574     __do_fclose FILE *f = NULL;
  575 
  576     if (is_empty_string(path))
  577         fd = dup_cloexec(dfd);
  578     else
  579         fd = open_at(dfd, path, o_flags, resolve_flags, 0);
  580     if (fd < 0)
  581         return NULL;
  582 
  583     f = fdopen(fd, "re");
  584     if (!f)
  585         return NULL;
  586 
  587     /* Transfer ownership of fd. */
  588     move_fd(fd);
  589 
  590     return move_ptr(f);
  591 }
  592 
  593 int timens_offset_write(clockid_t clk_id, int64_t s_offset, int64_t ns_offset)
  594 {
  595     __do_close int fd = -EBADF;
  596     int ret;
  597     ssize_t len;
  598     char buf[INTTYPE_TO_STRLEN(int) +
  599          STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(int64_t) +
  600          STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(int64_t) + 1];
  601 
  602     if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW)
  603         clk_id = CLOCK_MONOTONIC;
  604 
  605     fd = open("/proc/self/timens_offsets", O_WRONLY | O_CLOEXEC);
  606     if (fd < 0)
  607         return -errno;
  608 
  609     len = strnprintf(buf, sizeof(buf), "%d %" PRId64 " %" PRId64, clk_id, s_offset, ns_offset);
  610     if (len < 0)
  611         return ret_errno(EFBIG);
  612 
  613     ret = lxc_write_nointr(fd, buf, len);
  614     if (ret < 0 || (size_t)ret != len)
  615         return -EIO;
  616 
  617     return 0;
  618 }
  619 
  620 bool exists_dir_at(int dir_fd, const char *path)
  621 {
  622     int ret;
  623     struct stat sb;
  624 
  625     ret = fstatat(dir_fd, path, &sb, 0);
  626     if (ret < 0)
  627         return false;
  628 
  629     ret = S_ISDIR(sb.st_mode);
  630     if (ret)
  631         errno = EEXIST;
  632     else
  633         errno = ENOTDIR;
  634 
  635     return ret;
  636 }
  637 
  638 bool exists_file_at(int dir_fd, const char *path)
  639 {
  640     int ret;
  641     struct stat sb;
  642 
  643     ret = fstatat(dir_fd, path, &sb, 0);
  644     if (ret == 0)
  645         errno = EEXIST;
  646     return ret == 0;
  647 }
  648 
  649 int open_at(int dfd, const char *path, unsigned int o_flags,
  650         unsigned int resolve_flags, mode_t mode)
  651 {
  652     __do_close int fd = -EBADF;
  653     struct lxc_open_how how = {
  654         .flags      = o_flags,
  655         .mode       = mode,
  656         .resolve    = resolve_flags,
  657     };
  658 
  659     fd = openat2(dfd, path, &how, sizeof(how));
  660     if (fd >= 0)
  661         return move_fd(fd);
  662 
  663     if (errno != ENOSYS)
  664         return -errno;
  665 
  666     fd = openat(dfd, path, o_flags, mode);
  667     if (fd < 0)
  668         return -errno;
  669 
  670     return move_fd(fd);
  671 }
  672 
  673 int fd_make_nonblocking(int fd)
  674 {
  675     int flags;
  676 
  677     flags = fcntl(fd, F_GETFL);
  678     if (flags < 0)
  679         return -1;
  680 
  681     flags &= ~O_NONBLOCK;
  682     return fcntl(fd, F_SETFL, flags);
  683 }
  684 
  685 #define BATCH_SIZE 50
  686 static void batch_realloc(char **mem, size_t oldlen, size_t newlen)
  687 {
  688     int newbatches = (newlen / BATCH_SIZE) + 1;
  689     int oldbatches = (oldlen / BATCH_SIZE) + 1;
  690 
  691     if (!*mem || newbatches > oldbatches)
  692         *mem = must_realloc(*mem, newbatches * BATCH_SIZE);
  693 }
  694 
  695 static void append_line(char **dest, size_t oldlen, char *new, size_t newlen)
  696 {
  697     size_t full = oldlen + newlen;
  698 
  699     batch_realloc(dest, oldlen, full + 1);
  700 
  701     memcpy(*dest + oldlen, new, newlen + 1);
  702 }
  703 
  704 /* Slurp in a whole file */
  705 char *read_file_at(int dfd, const char *fnam,
  706            unsigned int o_flags, unsigned resolve_flags)
  707 {
  708     __do_close int fd = -EBADF;
  709     __do_free char *buf = NULL, *line = NULL;
  710     __do_fclose FILE *f = NULL;
  711     size_t len = 0, fulllen = 0;
  712     int linelen;
  713 
  714     fd = open_at(dfd, fnam, o_flags, resolve_flags, 0);
  715     if (fd < 0)
  716         return NULL;
  717 
  718     f = fdopen(fd, "re");
  719     if (!f)
  720         return NULL;
  721     /* Transfer ownership to fdopen(). */
  722     move_fd(fd);
  723 
  724     while ((linelen = getline(&line, &len, f)) != -1) {
  725         append_line(&buf, fulllen, line, linelen);
  726         fulllen += linelen;
  727     }
  728 
  729     return move_ptr(buf);
  730 }
  731 
  732 bool same_file_lax(int fda, int fdb)
  733 {
  734     struct stat st_fda, st_fdb;
  735 
  736 
  737         if (fda == fdb)
  738                 return true;
  739 
  740         if (fstat(fda, &st_fda) < 0)
  741                 return false;
  742 
  743         if (fstat(fdb, &st_fdb) < 0)
  744                 return false;
  745 
  746     errno = EINVAL;
  747     if ((st_fda.st_mode & S_IFMT) != (st_fdb.st_mode & S_IFMT))
  748         return false;
  749 
  750     errno = EINVAL;
  751     return (st_fda.st_dev == st_fdb.st_dev) &&
  752            (st_fda.st_ino == st_fdb.st_ino);
  753 }