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

Generated by: LCOV version 2.0-1