LCOV - code coverage report
Current view: top level - core - io.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 138 0
Test Date: 2025-05-09 22:39:08 Functions: 0.0 % 10 0

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "core/io.h"
       7              : 
       8              : #include <dirent.h>
       9              : #include <errno.h>
      10              : #include <fcntl.h>
      11              : #include <stdio.h>
      12              : #include <stdlib.h>
      13              : #include <string.h>
      14              : #include <sys/stat.h>
      15              : #include <unistd.h>
      16              : 
      17              : #include "core/helper.h"
      18              : #include "core/logger.h"
      19              : #include "core/request.h"
      20              : #include "core/response.h"
      21              : 
      22              : #define BF_PERM_755 (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
      23              : 
      24            0 : static ssize_t _bf_recv_in_buff(int fd, void *buf, size_t buf_len)
      25              : {
      26              :     ssize_t bytes_read = 0;
      27              :     ssize_t r;
      28              : 
      29            0 :     bf_assert(buf);
      30              : 
      31              :     do {
      32              :         /// @todo Add a timeout to the socket to prevent blocking forever.
      33            0 :         r = read(fd, buf + bytes_read, buf_len - bytes_read);
      34            0 :         if (r < 0) {
      35            0 :             (void)fprintf(stderr, "can't read from the socket: %s\n",
      36            0 :                           bf_strerror(errno));
      37            0 :             return -errno;
      38              :         }
      39              : 
      40            0 :         bytes_read += r;
      41            0 :     } while (r && (size_t)bytes_read != buf_len);
      42              : 
      43              :     return bytes_read;
      44              : }
      45              : 
      46            0 : static ssize_t _bf_send_from_buff(int fd, void *buf, size_t buf_len)
      47              : {
      48              :     ssize_t bytes_sent = 0;
      49              :     ssize_t r;
      50              : 
      51            0 :     bf_assert(buf);
      52              : 
      53            0 :     while ((size_t)bytes_sent < buf_len) {
      54            0 :         r = write(fd, buf + bytes_sent, buf_len - bytes_sent);
      55            0 :         if (r < 0) {
      56            0 :             (void)fprintf(stderr, "can't write to socket: %s\n",
      57            0 :                           bf_strerror(errno));
      58            0 :             return -errno;
      59              :         }
      60              : 
      61            0 :         bytes_sent += r;
      62              :     }
      63              : 
      64              :     return bytes_sent;
      65              : }
      66              : 
      67            0 : int bf_send_request(int fd, const struct bf_request *request)
      68              : {
      69              :     ssize_t r;
      70              : 
      71            0 :     bf_assert(request);
      72              : 
      73            0 :     r = _bf_send_from_buff(fd, (void *)request, bf_request_size(request));
      74            0 :     if (r < 0) {
      75            0 :         (void)fprintf(stderr, "Failed to send request: %s\n",
      76            0 :                       bf_strerror(errno));
      77            0 :         return -errno;
      78              :     }
      79              : 
      80            0 :     if ((size_t)r != bf_request_size(request)) {
      81            0 :         (void)fprintf(stderr,
      82              :                       "Failed to send request: %lu bytes sent, %ld expected\n",
      83              :                       (size_t)r, bf_request_size(request));
      84            0 :         return -EIO;
      85              :     }
      86              : 
      87              :     return 0;
      88              : }
      89              : 
      90            0 : int bf_recv_request(int fd, struct bf_request **request)
      91              : {
      92              :     struct bf_request req;
      93            0 :     _cleanup_bf_request_ struct bf_request *_request = NULL;
      94              :     ssize_t r;
      95              : 
      96            0 :     bf_assert(request);
      97              : 
      98            0 :     r = _bf_recv_in_buff(fd, &req, sizeof(req));
      99            0 :     if (r < 0)
     100            0 :         return (int)r;
     101              : 
     102            0 :     if ((size_t)r != sizeof(req)) {
     103            0 :         (void)fprintf(stderr,
     104              :                       "failed to read request: %lu bytes read, %lu expected\n",
     105              :                       (size_t)r, sizeof(req));
     106            0 :         return -EIO;
     107              :     }
     108              : 
     109            0 :     _request = malloc(bf_request_size(&req));
     110            0 :     if (!_request) {
     111            0 :         (void)fprintf(stderr, "failed to allocate request: %s\n",
     112            0 :                       bf_strerror(errno));
     113            0 :         return -errno;
     114              :     }
     115              : 
     116            0 :     memcpy(_request, &req, sizeof(req));
     117              : 
     118            0 :     r = _bf_recv_in_buff(fd, _request->data, _request->data_len);
     119            0 :     if (r < 0)
     120            0 :         return (int)r;
     121              : 
     122            0 :     if ((size_t)r != _request->data_len) {
     123            0 :         (void)fprintf(stderr,
     124              :                       "failed to read request: %lu bytes read, %lu expected\n",
     125              :                       (size_t)r, _request->data_len);
     126            0 :         return -EIO;
     127              :     }
     128              : 
     129            0 :     *request = TAKE_PTR(_request);
     130              : 
     131            0 :     return 0;
     132              : }
     133              : 
     134            0 : int bf_send_response(int fd, struct bf_response *response)
     135              : {
     136              :     ssize_t r;
     137              : 
     138            0 :     bf_assert(response);
     139              : 
     140            0 :     r = _bf_send_from_buff(fd, (void *)response, bf_response_size(response));
     141            0 :     if (r < 0) {
     142            0 :         (void)fprintf(stderr, "Failed to send response: %s\n",
     143            0 :                       bf_strerror(errno));
     144            0 :         return -errno;
     145              :     }
     146              : 
     147            0 :     if ((size_t)r != bf_response_size(response)) {
     148            0 :         (void)fprintf(stderr,
     149              :                       "Failed to send response: %lu bytes sent, %ld expected\n",
     150              :                       r, bf_response_size(response));
     151            0 :         return -EIO;
     152              :     }
     153              : 
     154              :     return 0;
     155              : }
     156              : 
     157            0 : int bf_recv_response(int fd, struct bf_response **response)
     158              : {
     159              :     struct bf_response res;
     160            0 :     _cleanup_bf_response_ struct bf_response *_response = NULL;
     161              :     ssize_t r;
     162              : 
     163            0 :     bf_assert(response);
     164              : 
     165            0 :     r = _bf_recv_in_buff(fd, &res, sizeof(res));
     166            0 :     if (r < 0)
     167            0 :         return -errno;
     168              : 
     169            0 :     if ((size_t)r != sizeof(res)) {
     170            0 :         (void)fprintf(stderr,
     171              :                       "failed to read response: %lu bytes read, %lu expected\n",
     172              :                       (size_t)r, sizeof(res));
     173            0 :         return -EIO;
     174              :     }
     175              : 
     176            0 :     _response = malloc(bf_response_size(&res));
     177            0 :     if (!_response) {
     178            0 :         (void)fprintf(stderr, "failed to allocate response: %s\n",
     179            0 :                       bf_strerror(errno));
     180            0 :         return -errno;
     181              :     }
     182              : 
     183            0 :     memcpy(_response, &res, sizeof(res));
     184              : 
     185            0 :     r = _bf_recv_in_buff(fd, _response->data, _response->data_len);
     186            0 :     if (r < 0)
     187            0 :         return (int)r;
     188              : 
     189            0 :     if (_response->type == BF_RES_SUCCESS && (size_t)r != _response->data_len) {
     190            0 :         (void)fprintf(stderr,
     191              :                       "failed to read response: %lu bytes read, %lu expected\n",
     192              :                       (size_t)r, _response->data_len);
     193            0 :         return -EIO;
     194              :     }
     195              : 
     196            0 :     *response = TAKE_PTR(_response);
     197              : 
     198            0 :     return 0;
     199              : }
     200              : 
     201            0 : int bf_ensure_dir(const char *dir)
     202              : {
     203              :     struct stat stats;
     204              :     int r;
     205              : 
     206            0 :     bf_assert(dir);
     207              : 
     208            0 :     r = access(dir, R_OK | W_OK);
     209            0 :     if (r && errno == ENOENT) {
     210            0 :         if (mkdir(dir, BF_PERM_755) == 0)
     211              :             return 0;
     212              : 
     213            0 :         return bf_err_r(errno, "failed to create directory '%s'", dir);
     214              :     }
     215              :     if (r)
     216            0 :         return bf_err_r(errno, "no R/W permissions on '%s'", dir);
     217              : 
     218            0 :     if (stat(dir, &stats) != 0 || !S_ISDIR(stats.st_mode))
     219            0 :         return bf_err_r(-EINVAL, "'%s' is not a valid directory", dir);
     220              : 
     221              :     return 0;
     222              : }
     223              : 
     224            0 : int bf_opendir(const char *path)
     225              : {
     226            0 :     _cleanup_close_ int fd = -1;
     227              : 
     228            0 :     bf_assert(path);
     229              : 
     230            0 :     fd = open(path, O_DIRECTORY);
     231            0 :     if (fd < 0)
     232            0 :         return -errno;
     233              : 
     234            0 :     return TAKE_FD(fd);
     235              : }
     236              : 
     237            0 : int bf_opendir_at(int parent_fd, const char *dir_name, bool mkdir_if_missing)
     238              : {
     239            0 :     _cleanup_close_ int fd = -1;
     240              :     int r;
     241              : 
     242            0 :     bf_assert(dir_name);
     243              : 
     244            0 : retry:
     245            0 :     fd = openat(parent_fd, dir_name, O_DIRECTORY);
     246            0 :     if (fd < 0) {
     247            0 :         if (errno != ENOENT || !mkdir_if_missing)
     248            0 :             return -errno;
     249              : 
     250            0 :         r = mkdirat(parent_fd, dir_name, BF_PERM_755);
     251            0 :         if (r)
     252            0 :             return -errno;
     253              : 
     254            0 :         goto retry;
     255              :     }
     256              : 
     257            0 :     return TAKE_FD(fd);
     258              : }
     259              : 
     260              : static void bf_free_dir(DIR **dir)
     261              : {
     262            0 :     if (!*dir)
     263              :         return;
     264              : 
     265            0 :     closedir(*dir);
     266              :     *dir = NULL;
     267              : }
     268              : 
     269              : #define _free_dir_ __attribute__((__cleanup__(bf_free_dir)))
     270              : 
     271            0 : int bf_rmdir_at(int parent_fd, const char *dir_name, bool recursive)
     272              : {
     273              :     int r;
     274              : 
     275            0 :     bf_assert(dir_name);
     276              : 
     277            0 :     if (recursive) {
     278            0 :         _cleanup_close_ int child_fd = -1;
     279              :         _free_dir_ DIR *dir = NULL;
     280              :         struct dirent *entry;
     281              : 
     282            0 :         child_fd = openat(parent_fd, dir_name, O_DIRECTORY);
     283            0 :         if (child_fd < 0) {
     284            0 :             return bf_err_r(errno,
     285              :                             "failed to open child directory for removal");
     286              :         }
     287              : 
     288            0 :         dir = fdopendir(child_fd);
     289            0 :         if (!dir)
     290            0 :             return bf_err_r(errno, "failed to open DIR from file descriptor");
     291              : 
     292            0 :         while ((entry = readdir(dir))) {
     293              :             struct stat stat;
     294              : 
     295            0 :             if (bf_streq(entry->d_name, ".") || bf_streq(entry->d_name, ".."))
     296            0 :                 continue;
     297              : 
     298            0 :             if (fstatat(child_fd, entry->d_name, &stat, 0) < 0) {
     299            0 :                 return bf_err_r(errno,
     300              :                                 "failed to fstatat() file '%s' for removal",
     301              :                                 entry->d_name);
     302              :             }
     303              : 
     304            0 :             if (S_ISDIR(stat.st_mode))
     305            0 :                 r = bf_rmdir_at(child_fd, entry->d_name, true);
     306              :             else
     307            0 :                 r = unlinkat(child_fd, entry->d_name, 0) == 0 ? 0 : -errno;
     308            0 :             if (r)
     309            0 :                 return bf_err_r(r, "failed to remove '%s'", entry->d_name);
     310              :         }
     311              :     }
     312              : 
     313            0 :     r = unlinkat(parent_fd, dir_name, AT_REMOVEDIR);
     314            0 :     if (r)
     315            0 :         return -errno;
     316              : 
     317              :     return 0;
     318              : }
        

Generated by: LCOV version 2.0-1