LCOV - code coverage report
Current view: top level - app/platform - fd_file_util.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 23 187 12.3 %
Date: 2026-06-29 05:51:35 Functions: 1 8 12.5 %

          Line data    Source code
       1             : #include "fd_file_util.h"
       2             : 
       3             : #include <stdio.h>
       4             : #include <errno.h>
       5             : #include <limits.h>
       6             : #include <dirent.h>
       7             : #include <fcntl.h>
       8             : #include <stdlib.h>
       9             : #include <unistd.h>
      10             : #include <sys/stat.h>
      11             : #include <sys/mman.h>
      12             : 
      13             : int
      14             : fd_file_util_read_ulong( char const * path,
      15           0 :                          ulong *      value ) {
      16           0 :   int fd = open( path, O_RDONLY );
      17           0 :   if( FD_UNLIKELY( -1==fd ) ) return -1;
      18             : 
      19           0 :   char buf[ 32UL ];
      20           0 :   long bytes_read = read(fd, buf, sizeof(buf)-1UL );
      21           0 :   if( FD_UNLIKELY( -1==bytes_read ) ) {
      22           0 :     close(fd);
      23           0 :     return -1;
      24           0 :   }
      25             : 
      26           0 :   if( FD_UNLIKELY( !bytes_read || (ulong)bytes_read>=sizeof(buf)-1UL ) ) {
      27           0 :     errno = EINVAL;
      28           0 :     close(fd);
      29           0 :     return -1;
      30           0 :   }
      31             : 
      32           0 :   buf[ bytes_read ] = '\0';
      33             : 
      34           0 :   if( FD_UNLIKELY( -1==close( fd ) ) ) return -1;
      35             : 
      36           0 :   char *endptr;
      37           0 :   errno = 0;
      38           0 :   ulong _value = strtoul( buf, &endptr, 10 );
      39           0 :   if( FD_UNLIKELY( errno==ERANGE ) ) return -1;
      40           0 :   if( FD_UNLIKELY( *endptr!='\n' && *endptr!='\0' ) ) {
      41           0 :     errno = EINVAL;
      42           0 :     return -1;
      43           0 :   }
      44             : 
      45           0 :   *value = _value;
      46           0 :   return 0;
      47           0 : }
      48             : 
      49             : int
      50             : fd_file_util_read_uint( char const * path,
      51           0 :                         uint *       value ) {
      52           0 :   ulong _value;
      53           0 :   int rc = fd_file_util_read_ulong( path, &_value );
      54           0 :   if( FD_UNLIKELY( -1==rc ) ) return -1;
      55           0 :   if( FD_UNLIKELY( _value>UINT_MAX ) ) {
      56           0 :     errno = ERANGE;
      57           0 :     return -1;
      58           0 :   }
      59           0 :   *value = (uint)_value;
      60           0 :   return 0;
      61           0 : }
      62             : 
      63             : int
      64             : fd_file_util_write_ulong( char const * path,
      65           0 :                           ulong        value ) {
      66           0 :   int fd = open( path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR );
      67           0 :   if( FD_UNLIKELY( -1==fd ) ) return -1;
      68             : 
      69           0 :   char buf[ 32UL ];
      70           0 :   int len = snprintf( buf, sizeof(buf), "%lu\n", value );
      71           0 :   FD_TEST( len>=0 && (ulong)len<sizeof(buf) );
      72             : 
      73           0 :   long written = write( fd, buf, (ulong)len );
      74           0 :   if( FD_UNLIKELY( -1==written ) ) {
      75           0 :     close( fd );
      76           0 :     return -1;
      77           0 :   } else if( FD_UNLIKELY( written!=len ) ) {
      78           0 :     errno = EINTR;
      79           0 :     close( fd );
      80           0 :     return -1;
      81           0 :   }
      82             : 
      83           0 :   if( FD_UNLIKELY( -1==close( fd ) ) ) return -1;
      84           0 :   return 0;
      85           0 : }
      86             : 
      87             : int
      88             : fd_file_util_mkdir_all( const char * _path,
      89             :                         uint         uid,
      90             :                         uint         gid,
      91           0 :                         int          is_dir ) {
      92           0 :   char path[ PATH_MAX+1UL ] = {0};
      93           0 :   strncpy( path, _path, PATH_MAX );
      94             : 
      95           0 :   char * p = path;
      96           0 :   if( FD_LIKELY( *p == '/' ) ) p++;
      97             : 
      98           0 :   while( FD_LIKELY( *p ) ) {
      99           0 :     if( FD_UNLIKELY( *p == '/' ) ) {
     100           0 :       *p = '\0';
     101             : 
     102           0 :       int error = mkdir( path, 0777 );
     103           0 :       if( FD_UNLIKELY( -1==error && errno!=EEXIST ) ) return -1;
     104           0 :       if( FD_LIKELY( !error ) ) {
     105             :         /* Only take ownership of directories that we actually created
     106             :            (to avoid, for example, chowning the root directory). */
     107           0 :         if( FD_UNLIKELY( -1==chown( path, uid, gid ) ) ) return -1;
     108           0 :         if( FD_UNLIKELY( -1==chmod( path, S_IRUSR | S_IWUSR | S_IXUSR ) ) ) return -1;
     109           0 :       }
     110             : 
     111           0 :       *p = '/';
     112           0 :     }
     113           0 :     p++;
     114           0 :   }
     115             : 
     116           0 :   if( FD_LIKELY( is_dir ) ) {
     117           0 :     int error = mkdir( path, 0777 );
     118           0 :     if( FD_UNLIKELY( error && errno!=EEXIST ) ) return -1;
     119           0 :     if( FD_LIKELY( !error ) ) {
     120           0 :       if( FD_UNLIKELY( chown( path, uid, gid ) ) ) return -1;
     121           0 :       if( FD_UNLIKELY( chmod( path, S_IRUSR | S_IWUSR | S_IXUSR ) ) ) return -1;
     122           0 :     }
     123           0 :   }
     124           0 :   return 0;
     125           0 : }
     126             : 
     127             : int
     128             : fd_file_util_rmtree( char const * path,
     129           6 :                      int          remove_root ) {
     130           6 :   DIR * dir = opendir( path );
     131           6 :   if( FD_UNLIKELY( !dir ) ) {
     132           0 :     if( FD_LIKELY( errno==ENOENT ) ) return 0;
     133           0 :     return -1;
     134           0 :   }
     135             : 
     136           6 :   struct dirent * entry;
     137          39 :   for(;;) {
     138          39 :     errno = 0;
     139          39 :     entry = readdir( dir );
     140          39 :     if( FD_UNLIKELY( !entry ) ) break;
     141          33 :     if( FD_LIKELY( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) ) ) continue;
     142             : 
     143          21 :     char path1[ PATH_MAX ];
     144          21 :     if( FD_UNLIKELY( !fd_cstr_printf_check( path1, PATH_MAX, NULL, "%s/%s", path, entry->d_name ) ) ) {
     145           0 :       errno = ERANGE;
     146           0 :       closedir( dir ); /* Ignore error code, fd is always closed */
     147           0 :       return -1;
     148           0 :     }
     149             : 
     150          21 :     struct stat st;
     151          21 :     if( FD_UNLIKELY( lstat( path1, &st ) ) ) {
     152           0 :       if( FD_LIKELY( errno==ENOENT ) ) continue;
     153           0 :       closedir( dir ); /* Ignore error code, fd is always closed */
     154           0 :       return -1;
     155           0 :     }
     156             : 
     157          21 :     if( FD_UNLIKELY( S_ISDIR( st.st_mode ) ) ) {
     158           0 :       fd_file_util_rmtree( path1, 1 );
     159          21 :     } else {
     160          21 :       if( FD_UNLIKELY( -1==unlink( path1 ) && errno!=ENOENT ) ) {
     161           0 :         closedir( dir ); /* Ignore error code, fd is always closed */
     162           0 :         return -1;
     163           0 :       }
     164          21 :     }
     165          21 :   }
     166             : 
     167           6 :   if( FD_UNLIKELY( errno ) )                    return -1;
     168           6 :   if( FD_UNLIKELY( -1==closedir( dir ) ) )      return -1;
     169           6 :   if( FD_LIKELY( remove_root && -1==rmdir( path ) ) ) return -1;
     170             : 
     171           6 :   return 0;
     172           6 : }
     173             : 
     174             : int
     175           0 : fd_file_util_self_exe( char path[ static PATH_MAX ] ) {
     176           0 :   long count = readlink( "/proc/self/exe", path, PATH_MAX );
     177           0 :   if( FD_UNLIKELY( -1==count ) ) return -1;
     178           0 :   if( FD_UNLIKELY( count>=PATH_MAX ) ) {
     179           0 :     errno = ERANGE;
     180           0 :     return -1;
     181           0 :   }
     182             : 
     183           0 :   path[ count ] = '\0';
     184           0 :   return 0;
     185           0 : }
     186             : 
     187             : char *
     188             : fd_file_util_read_all( char const * path,
     189           0 :                        ulong *      out_sz ) {
     190           0 :   int fd = open( path, O_RDONLY );
     191           0 :   if( FD_UNLIKELY( -1==fd ) ) return MAP_FAILED;
     192             : 
     193           0 :   struct stat st;
     194           0 :   if( FD_UNLIKELY( fstat( fd, &st ) ) ) {
     195           0 :     if( FD_UNLIKELY( -1==close( fd ) ) ) FD_LOG_WARNING(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     196           0 :     return MAP_FAILED;
     197           0 :   }
     198             : 
     199           0 :   ulong toml_sz = (ulong)st.st_size;
     200           0 :   if( FD_UNLIKELY( toml_sz==0UL ) ) {
     201           0 :     if( FD_UNLIKELY( -1==close( fd ) ) ) FD_LOG_WARNING(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     202           0 :     errno = EINVAL;
     203           0 :     return MAP_FAILED;
     204           0 :   }
     205             : 
     206           0 :   void * mem = mmap( NULL, toml_sz, PROT_READ, MAP_PRIVATE, fd, 0 );
     207           0 :   if( FD_UNLIKELY( mem==MAP_FAILED ) ) {
     208           0 :     if( FD_UNLIKELY( -1==close( fd ) ) ) FD_LOG_WARNING(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     209           0 :     return MAP_FAILED;
     210           0 :   }
     211             : 
     212           0 :   if( FD_UNLIKELY( -1==close( fd ) ) ) FD_LOG_WARNING(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     213             : 
     214           0 :   *out_sz = toml_sz;
     215           0 :   return (char *)mem;
     216           0 : }
     217             : 
     218             : char *
     219             : fd_file_util_read_cstr( char const * path,
     220             :                         char *       dst,
     221             :                         ulong        dst_max,
     222           0 :                         ulong *      dst_len ) {
     223           0 :   if( FD_UNLIKELY( !dst_max ) ) {
     224           0 :     errno = ENOMEM;
     225           0 :     return NULL;
     226           0 :   }
     227             : 
     228           0 :   char * ret = NULL;
     229           0 :   int fd = open( path, O_RDONLY );
     230           0 :   if( FD_UNLIKELY( -1==fd ) ) return NULL;
     231           0 :   ulong off = 0UL;
     232           0 :   for(;;) {
     233           0 :     if( FD_UNLIKELY( off>=dst_max-1UL ) ) {
     234           0 :       char extra;
     235           0 :       long more = read( fd, &extra, 1UL );
     236           0 :       if( FD_UNLIKELY( -1==more ) ) goto cleanup;
     237           0 :       if( FD_UNLIKELY( more>0L ) ) { errno = ENOMEM; goto cleanup; }
     238           0 :       break;
     239           0 :     }
     240             : 
     241           0 :     long bytes_read = read( fd, dst+off, dst_max-off-1UL );
     242           0 :     if( FD_UNLIKELY( -1==bytes_read ) ) {
     243           0 :       goto cleanup;
     244           0 :     } else if( FD_UNLIKELY( !bytes_read ) ) {
     245           0 :       break;
     246           0 :     }
     247             : 
     248           0 :     off += (ulong)bytes_read;
     249           0 :   }
     250           0 :   dst[ off ] = '\0';
     251           0 :   if( dst_len ) *dst_len = off;
     252           0 :   ret = dst;
     253             : 
     254           0 : cleanup:
     255           0 :   if( FD_UNLIKELY( -1==close( fd ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     256           0 :   return ret;
     257           0 : }

Generated by: LCOV version 1.14