LCOV - code coverage report
Current view: top level - libbpfilter - io.c (source / functions) Coverage Total Hit
Test: coverage.lcov Lines: 84.5 % 58 49
Test Date: 2026-04-17 15:45:04 Functions: 100.0 % 5 5
Branches: 58.1 % 62 36

             Branch data     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 "bpfilter/io.h"
       7                 :             : 
       8                 :             : #include <dirent.h>
       9                 :             : #include <errno.h>
      10                 :             : #include <fcntl.h>
      11                 :             : #include <sys/file.h>
      12                 :             : #include <sys/stat.h>
      13                 :             : #include <unistd.h>
      14                 :             : 
      15                 :             : #include "bpfilter/helper.h"
      16                 :             : #include "bpfilter/logger.h"
      17                 :             : 
      18                 :             : #define BF_PERM_755 (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
      19                 :             : 
      20                 :           4 : int bf_ensure_dir(const char *dir)
      21                 :             : {
      22                 :             :     struct stat stats;
      23                 :             :     int r;
      24                 :             : 
      25                 :             :     assert(dir);
      26                 :             : 
      27                 :           4 :     r = access(dir, R_OK | W_OK);
      28   [ +  +  +  - ]:           4 :     if (r && errno == ENOENT) {
      29         [ +  - ]:           1 :         if (mkdir(dir, BF_PERM_755) == 0)
      30                 :             :             return 0;
      31                 :             : 
      32         [ #  # ]:           0 :         return bf_err_r(errno, "failed to create directory '%s'", dir);
      33                 :             :     }
      34                 :             :     if (r)
      35         [ #  # ]:           0 :         return bf_err_r(errno, "no R/W permissions on '%s'", dir);
      36                 :             : 
      37   [ +  -  +  + ]:           3 :     if (stat(dir, &stats) != 0 || !S_ISDIR(stats.st_mode))
      38         [ +  - ]:           1 :         return bf_err_r(-EINVAL, "'%s' is not a valid directory", dir);
      39                 :             : 
      40                 :             :     return 0;
      41                 :             : }
      42                 :             : 
      43                 :        4853 : int bf_opendir(const char *path)
      44                 :             : {
      45                 :        4853 :     _cleanup_close_ int fd = -1;
      46                 :             : 
      47                 :             :     assert(path);
      48                 :             : 
      49                 :        4853 :     fd = open(path, O_DIRECTORY);
      50         [ +  + ]:        4853 :     if (fd < 0)
      51                 :           1 :         return -errno;
      52                 :             : 
      53                 :        4852 :     return TAKE_FD(fd);
      54                 :             : }
      55                 :             : 
      56                 :        7528 : int bf_opendir_at(int parent_fd, const char *dir_name, bool mkdir_if_missing)
      57                 :             : {
      58                 :       15056 :     _cleanup_close_ int fd = -1;
      59                 :             :     int r;
      60                 :             : 
      61                 :             :     assert(dir_name);
      62                 :             : 
      63                 :        8732 : retry:
      64                 :        8732 :     fd = openat(parent_fd, dir_name, O_DIRECTORY);
      65         [ +  + ]:        8732 :     if (fd < 0) {
      66   [ +  -  +  + ]:        1205 :         if (errno != ENOENT || !mkdir_if_missing)
      67                 :           1 :             return -errno;
      68                 :             : 
      69                 :        1204 :         r = mkdirat(parent_fd, dir_name, BF_PERM_755);
      70         [ -  + ]:        1204 :         if (r)
      71                 :           0 :             return -errno;
      72                 :             : 
      73                 :        1204 :         goto retry;
      74                 :             :     }
      75                 :             : 
      76                 :        7527 :     return TAKE_FD(fd);
      77                 :             : }
      78                 :             : 
      79                 :             : static void bf_free_dir(DIR **dir)
      80                 :             : {
      81         [ #  # ]:           0 :     if (!*dir)
      82                 :             :         return;
      83                 :             : 
      84                 :           2 :     closedir(*dir);
      85                 :             :     *dir = NULL;
      86                 :             : }
      87                 :             : 
      88                 :             : #define _free_dir_ __attribute__((__cleanup__(bf_free_dir)))
      89                 :             : 
      90                 :        1500 : int bf_rmdir_at(int parent_fd, const char *dir_name, bool recursive)
      91                 :             : {
      92                 :             :     int r;
      93                 :             : 
      94                 :             :     assert(dir_name);
      95                 :             : 
      96         [ +  + ]:        1500 :     if (recursive) {
      97                 :           3 :         _cleanup_close_ int child_fd = -1;
      98                 :             :         _free_dir_ DIR *dir = NULL;
      99                 :             :         struct dirent *entry;
     100                 :             : 
     101                 :           3 :         child_fd = openat(parent_fd, dir_name, O_DIRECTORY);
     102         [ +  + ]:           3 :         if (child_fd < 0) {
     103         [ +  - ]:           1 :             return bf_err_r(errno,
     104                 :             :                             "failed to open child directory for removal");
     105                 :             :         }
     106                 :             : 
     107                 :           2 :         dir = fdopendir(child_fd);
     108         [ -  + ]:           2 :         if (!dir)
     109         [ #  # ]:           0 :             return bf_err_r(errno, "failed to open DIR from file descriptor");
     110                 :             : 
     111         [ +  + ]:           7 :         while ((entry = readdir(dir))) {
     112                 :             :             struct stat stat;
     113                 :             : 
     114   [ +  +  +  + ]:           5 :             if (bf_streq(entry->d_name, ".") || bf_streq(entry->d_name, ".."))
     115                 :           4 :                 continue;
     116                 :             : 
     117         [ -  + ]:           1 :             if (fstatat(child_fd, entry->d_name, &stat, 0) < 0) {
     118         [ #  # ]:           0 :                 return bf_err_r(errno,
     119                 :             :                                 "failed to fstatat() file '%s' for removal",
     120                 :             :                                 entry->d_name);
     121                 :             :             }
     122                 :             : 
     123         [ +  - ]:           1 :             if (S_ISDIR(stat.st_mode))
     124                 :           1 :                 r = bf_rmdir_at(child_fd, entry->d_name, true);
     125                 :             :             else
     126         [ #  # ]:           0 :                 r = unlinkat(child_fd, entry->d_name, 0) == 0 ? 0 : -errno;
     127         [ -  + ]:           1 :             if (r)
     128         [ #  # ]:           0 :                 return bf_err_r(r, "failed to remove '%s'", entry->d_name);
     129                 :             :         }
     130                 :             :     }
     131                 :             : 
     132                 :        1499 :     r = unlinkat(parent_fd, dir_name, AT_REMOVEDIR);
     133         [ +  + ]:        1499 :     if (r)
     134                 :         341 :         return -errno;
     135                 :             : 
     136                 :             :     return 0;
     137                 :             : }
     138                 :             : 
     139                 :           2 : int bf_acquire_lock(const char *path)
     140                 :             : {
     141                 :           2 :     _cleanup_close_ int fd = -1;
     142                 :             : 
     143                 :             :     assert(path);
     144                 :             : 
     145                 :           2 :     fd = open(path, O_CREAT | O_RDWR, BF_PERM_755);
     146         [ -  + ]:           2 :     if (fd < 0)
     147                 :           0 :         return -errno;
     148                 :             : 
     149         [ +  + ]:           2 :     if (flock(fd, LOCK_EX | LOCK_NB) < 0)
     150                 :           1 :         return -errno;
     151                 :             : 
     152                 :           1 :     return TAKE_FD(fd);
     153                 :             : }
        

Generated by: LCOV version 2.0-1