LCOV - code coverage report
Current view: top level - src - directory_open.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.4 % 22 19
Test Date: 2026-07-12 01:01:34 Functions: 100.0 % 1 1
Branches: 75.0 % 12 9

             Branch data     Line data    Source code
       1                 :             : #include "precizer.h"
       2                 :             : #include <errno.h>
       3                 :             : #include <fcntl.h>
       4                 :             : 
       5                 :             : /**
       6                 :             :  * @brief Open a directory as the base for relative path access checks
       7                 :             :  *
       8                 :             :  * @details
       9                 :             :  * Uses the platform search-only directory mode when available. macOS and
      10                 :             :  * Cygwin provide `O_SEARCH`, while Linux provides `O_PATH`. The fallback uses
      11                 :             :  * a read-only directory descriptor for platforms without either extension
      12                 :             :  *
      13                 :             :  * `O_SEARCH` and `O_PATH` allow the descriptor to serve as a path-resolution
      14                 :             :  * base without requiring directory enumeration. The descriptor is opened with
      15                 :             :  * close-on-exec and is verified to refer to a directory
      16                 :             :  *
      17                 :             :  * Test builds can force an unavailable result for a matching path. The test
      18                 :             :  * override also sets a representative `errno` value so callers exercise the
      19                 :             :  * same diagnostics as a real `open()` failure
      20                 :             :  *
      21                 :             :  * @param[in] directory_path Descriptor containing the directory path to open
      22                 :             :  * @param[out] directory_fd_out Receives the opened descriptor. Set to -1 before
      23                 :             :  *             `open()` is attempted
      24                 :             :  * @return `FILE_ACCESS_ALLOWED` when the directory was opened.
      25                 :             :  *         `FILE_NOT_FOUND` or `FILE_ACCESS_DENIED` for the corresponding
      26                 :             :  *         `open()` failure. `FILE_ACCESS_ERROR` when the output pointer is
      27                 :             :  *         invalid or another `open()` failure cannot be classified more
      28                 :             :  *         specifically
      29                 :             :  */
      30                 :         529 : FileAccessStatus directory_open(
      31                 :             :         const memory *directory_path,
      32                 :             :         int          *directory_fd_out)
      33                 :             : {
      34         [ -  + ]:         529 :         if(directory_fd_out == NULL)
      35                 :             :         {
      36                 :           0 :                 errno = EINVAL;
      37                 :           0 :                 return(FILE_ACCESS_ERROR);
      38                 :             :         }
      39                 :             : 
      40                 :         529 :         *directory_fd_out = -1;
      41                 :             : 
      42                 :         529 :         const char *runtime_directory_path = m_text(directory_path);
      43                 :             : 
      44                 :             : #ifdef TESTITALL_TEST_HOOKS
      45                 :         529 :         FileAccessStatus forced_status = FILE_ACCESS_ALLOWED;
      46                 :             : 
      47         [ +  + ]:         529 :         if(testitall_file_access_status_override(runtime_directory_path,&forced_status) == true
      48         [ +  - ]:           8 :                 && forced_status != FILE_ACCESS_ALLOWED)
      49                 :             :         {
      50         [ +  + ]:           8 :                 if(forced_status == FILE_ACCESS_DENIED)
      51                 :             :                 {
      52                 :           4 :                         errno = EACCES;
      53                 :             : 
      54         [ +  + ]:           4 :                 } else if(forced_status == FILE_NOT_FOUND){
      55                 :           2 :                         errno = ENOENT;
      56                 :             : 
      57                 :             :                 } else {
      58                 :           2 :                         errno = EIO;
      59                 :             :                 }
      60                 :             : 
      61                 :           8 :                 return(forced_status);
      62                 :             :         }
      63                 :             : #endif
      64                 :             : 
      65                 :         521 :         int open_flags = O_DIRECTORY | O_CLOEXEC;
      66                 :             : 
      67                 :             :         /*
      68                 :             :          * Open the directory with the least access required to use it as the starting
      69                 :             :          * point for relative paths:
      70                 :             :          *
      71                 :             :          * - O_SEARCH is the POSIX-style option for opening a directory so known child
      72                 :             :          *   names can be resolved without asking permission to list its contents.
      73                 :             :          * - O_PATH is the Linux alternative. It creates a lightweight descriptor that
      74                 :             :          *   refers to the directory and can be used by functions such as faccessat().
      75                 :             :          * - O_RDONLY is the portable fallback when neither specialized option exists.
      76                 :             :          *   It may require directory read permission even though this function does
      77                 :             :          *   not need to enumerate the directory
      78                 :             :          */
      79                 :             : #if defined(O_SEARCH)
      80                 :             :         open_flags |= O_SEARCH;
      81                 :             : #elif defined(O_PATH)
      82                 :         521 :         open_flags |= O_PATH;
      83                 :             : #else
      84                 :             :         open_flags |= O_RDONLY;
      85                 :             : #endif
      86                 :             : 
      87                 :         521 :         const int directory_fd = open(runtime_directory_path,open_flags);
      88                 :             : 
      89         [ +  - ]:         521 :         if(directory_fd >= 0)
      90                 :             :         {
      91                 :         521 :                 *directory_fd_out = directory_fd;
      92                 :         521 :                 return(FILE_ACCESS_ALLOWED);
      93                 :             :         }
      94                 :             : 
      95                 :           0 :         return(file_access_status(errno));
      96                 :             : }
        

Generated by: LCOV version 2.0-1