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 : }
|