Line data Source code
1 : /* Copyright (c) 2003-2004, Roger Dingledine
2 : * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 : * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 : /* See LICENSE for licensing information */
5 :
6 : /**
7 : * \file files.h
8 : *
9 : * \brief Wrappers for reading and writing data to files on disk.
10 : **/
11 :
12 : #ifdef _WIN32
13 : #include <windows.h>
14 : #endif
15 :
16 : #include "lib/fs/files.h"
17 : #include "lib/fs/path.h"
18 : #include "lib/container/smartlist.h"
19 : #include "lib/log/log.h"
20 : #include "lib/log/util_bug.h"
21 : #include "lib/log/escape.h"
22 : #include "lib/err/torerr.h"
23 : #include "lib/malloc/malloc.h"
24 : #include "lib/sandbox/sandbox.h"
25 : #include "lib/string/printf.h"
26 : #include "lib/string/util_string.h"
27 : #include "lib/fdio/fdio.h"
28 :
29 : #ifdef HAVE_SYS_TYPES_H
30 : #include <sys/types.h>
31 : #endif
32 : #ifdef HAVE_SYS_STAT_H
33 : #include <sys/stat.h>
34 : #endif
35 : #ifdef HAVE_UTIME_H
36 : #include <utime.h>
37 : #endif
38 : #ifdef HAVE_SYS_TIME_H
39 : #include <sys/time.h>
40 : #endif
41 : #ifdef HAVE_FCNTL_H
42 : #include <fcntl.h>
43 : #endif
44 : #ifdef HAVE_UNISTD_H
45 : #include <unistd.h>
46 : #endif
47 : #include <errno.h>
48 : #include <stdio.h>
49 : #include <string.h>
50 :
51 : /** As open(path, flags, mode), but return an fd with the close-on-exec mode
52 : * set. */
53 : int
54 2765 : tor_open_cloexec(const char *path, int flags, unsigned mode)
55 : {
56 2765 : int fd;
57 2765 : const char *p = sandbox_intern_string(path);
58 : #ifdef O_CLOEXEC
59 2765 : fd = open(p, flags|O_CLOEXEC, mode);
60 2765 : if (fd >= 0)
61 : return fd;
62 : /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
63 : * even though we were built on a system with O_CLOEXEC support, we
64 : * are running on one without. */
65 172 : if (errno != EINVAL)
66 : return -1;
67 : #endif /* defined(O_CLOEXEC) */
68 :
69 0 : log_debug(LD_FS, "Opening %s with flags %x", p, flags);
70 0 : fd = open(p, flags, mode);
71 : #ifdef FD_CLOEXEC
72 0 : if (fd >= 0) {
73 0 : if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
74 0 : log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
75 0 : close(fd);
76 0 : return -1;
77 : }
78 : }
79 : #endif /* defined(FD_CLOEXEC) */
80 : return fd;
81 : }
82 :
83 : /** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the
84 : * underlying file handle. */
85 : FILE *
86 36 : tor_fopen_cloexec(const char *path, const char *mode)
87 : {
88 36 : FILE *result = fopen(path, mode);
89 : #ifdef FD_CLOEXEC
90 36 : if (result != NULL) {
91 24 : if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) {
92 0 : log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
93 0 : fclose(result);
94 0 : return NULL;
95 : }
96 : }
97 : #endif /* defined(FD_CLOEXEC) */
98 : return result;
99 : }
100 :
101 : /** As rename(), but work correctly with the sandbox. */
102 : int
103 800 : tor_rename(const char *path_old, const char *path_new)
104 : {
105 800 : log_debug(LD_FS, "Renaming %s to %s", path_old, path_new);
106 800 : return rename(sandbox_intern_string(path_old),
107 : sandbox_intern_string(path_new));
108 : }
109 :
110 : /**
111 : * Rename the file <b>from</b> to the file <b>to</b>. On Unix, this is
112 : * the same as rename(2). On windows, this removes <b>to</b> first if
113 : * it already exists.
114 : * Returns 0 on success. Returns -1 and sets errno on failure.
115 : */
116 : int
117 800 : replace_file(const char *from, const char *to)
118 : {
119 : #ifndef _WIN32
120 800 : return tor_rename(from, to);
121 : #else
122 : switch (file_status(to))
123 : {
124 : case FN_NOENT:
125 : break;
126 : case FN_FILE:
127 : case FN_EMPTY:
128 : if (unlink(to)) return -1;
129 : break;
130 : case FN_ERROR:
131 : return -1;
132 : case FN_DIR:
133 : errno = EISDIR;
134 : return -1;
135 : }
136 : return tor_rename(from,to);
137 : #endif /* !defined(_WIN32) */
138 : }
139 :
140 : /** Change <b>fname</b>'s modification time to now. */
141 : int
142 1 : touch_file(const char *fname)
143 : {
144 1 : if (utime(fname, NULL)!=0)
145 0 : return -1;
146 : return 0;
147 : }
148 :
149 : /** Wrapper for unlink() to make it mockable for the test suite; returns 0
150 : * if unlinking the file succeeded, -1 and sets errno if unlinking fails.
151 : */
152 :
153 1 : MOCK_IMPL(int,
154 : tor_unlink,(const char *pathname))
155 : {
156 1 : return unlink(pathname);
157 : }
158 :
159 : /** Write <b>count</b> bytes from <b>buf</b> to <b>fd</b>. Return the number
160 : * of bytes written, or -1 on error. Only use if fd is a blocking fd. */
161 : ssize_t
162 2629 : write_all_to_fd(int fd, const char *buf, size_t count)
163 : {
164 2629 : size_t written = 0;
165 2629 : ssize_t result;
166 2629 : raw_assert(count < SSIZE_MAX);
167 :
168 5240 : while (written != count) {
169 2611 : result = write(fd, buf+written, count-written);
170 2611 : if (result<0)
171 : return -1;
172 2611 : written += result;
173 : }
174 2629 : return (ssize_t)count;
175 : }
176 :
177 : /** Read from <b>fd</b> to <b>buf</b>, until we get <b>count</b> bytes or
178 : * reach the end of the file. Return the number of bytes read, or -1 on
179 : * error. Only use if fd is a blocking fd. */
180 : ssize_t
181 913 : read_all_from_fd(int fd, char *buf, size_t count)
182 : {
183 913 : size_t numread = 0;
184 913 : ssize_t result;
185 :
186 913 : if (count > SIZE_T_CEILING || count > SSIZE_MAX) {
187 0 : errno = EINVAL;
188 0 : return -1;
189 : }
190 :
191 1547 : while (numread < count) {
192 637 : result = read(fd, buf+numread, count-numread);
193 637 : if (result<0)
194 : return -1;
195 636 : else if (result == 0)
196 : break;
197 634 : numread += result;
198 : }
199 912 : return (ssize_t)numread;
200 : }
201 :
202 : /** Return:
203 : * FN_ERROR if filename can't be read, is NULL, or is zero-length,
204 : * FN_NOENT if it doesn't exist,
205 : * FN_FILE if it is a non-empty regular file, or a FIFO on unix-like systems,
206 : * FN_EMPTY for zero-byte regular files,
207 : * FN_DIR if it's a directory, and
208 : * FN_ERROR for any other file type.
209 : * On FN_ERROR and FN_NOENT, sets errno. (errno is not set when FN_ERROR
210 : * is returned due to an unhandled file type.) */
211 : file_status_t
212 1121 : file_status(const char *fname)
213 : {
214 1121 : struct stat st;
215 1121 : char *f;
216 1121 : int r;
217 1121 : if (!fname || strlen(fname) == 0) {
218 : return FN_ERROR;
219 : }
220 1121 : f = tor_strdup(fname);
221 1121 : clean_fname_for_stat(f);
222 1121 : log_debug(LD_FS, "stat()ing %s", f);
223 1121 : r = stat(sandbox_intern_string(f), &st);
224 1121 : tor_free(f);
225 1121 : if (r) {
226 421 : if (errno == ENOENT) {
227 : return FN_NOENT;
228 : }
229 0 : return FN_ERROR;
230 : }
231 700 : if (st.st_mode & S_IFDIR) {
232 : return FN_DIR;
233 645 : } else if (st.st_mode & S_IFREG) {
234 645 : if (st.st_size > 0) {
235 : return FN_FILE;
236 284 : } else if (st.st_size == 0) {
237 : return FN_EMPTY;
238 : } else {
239 0 : return FN_ERROR;
240 : }
241 : #ifndef _WIN32
242 0 : } else if (st.st_mode & S_IFIFO) {
243 : return FN_FILE;
244 : #endif
245 : } else {
246 0 : return FN_ERROR;
247 : }
248 : }
249 :
250 : /** Returns true if <b>file_type</b> represents an existing file (even if
251 : * empty). Returns false otherwise. */
252 : bool
253 0 : is_file(file_status_t file_type)
254 : {
255 0 : return file_type != FN_ERROR && file_type != FN_NOENT && file_type != FN_DIR;
256 : }
257 :
258 : /** Returns true if <b>file_type</b> represents an existing directory. Returns
259 : * false otherwise. */
260 : bool
261 6 : is_dir(file_status_t file_type)
262 : {
263 6 : return file_type == FN_DIR;
264 : }
265 :
266 : /** Create a file named <b>fname</b> with the contents <b>str</b>. Overwrite
267 : * the previous <b>fname</b> if possible. Return 0 on success, -1 on failure.
268 : *
269 : * This function replaces the old file atomically, if possible. This
270 : * function, and all other functions in util.c that create files, create them
271 : * with mode 0600.
272 : */
273 438 : MOCK_IMPL(int,
274 : write_str_to_file,(const char *fname, const char *str, int bin))
275 : {
276 : #ifdef _WIN32
277 : if (!bin && strchr(str, '\r')) {
278 : log_warn(LD_BUG,
279 : "We're writing a text string that already contains a CR to %s",
280 : escaped(fname));
281 : }
282 : #endif /* defined(_WIN32) */
283 438 : return write_bytes_to_file(fname, str, strlen(str), bin);
284 : }
285 :
286 : /** Represents a file that we're writing to, with support for atomic commit:
287 : * we can write into a temporary file, and either remove the file on
288 : * failure, or replace the original file on success. */
289 : struct open_file_t {
290 : char *tempname; /**< Name of the temporary file. */
291 : char *filename; /**< Name of the original file. */
292 : unsigned rename_on_close:1; /**< Are we using the temporary file or not? */
293 : unsigned binary:1; /**< Did we open in binary mode? */
294 : int fd; /**< fd for the open file. */
295 : FILE *stdio_file; /**< stdio wrapper for <b>fd</b>. */
296 : };
297 :
298 : /** Try to start writing to the file in <b>fname</b>, passing the flags
299 : * <b>open_flags</b> to the open() syscall, creating the file (if needed) with
300 : * access value <b>mode</b>. If the O_APPEND flag is set, we append to the
301 : * original file. Otherwise, we open a new temporary file in the same
302 : * directory, and either replace the original or remove the temporary file
303 : * when we're done.
304 : *
305 : * Return the fd for the newly opened file, and store working data in
306 : * *<b>data_out</b>. The caller should not close the fd manually:
307 : * instead, call finish_writing_to_file() or abort_writing_to_file().
308 : * Returns -1 on failure.
309 : *
310 : * NOTE: When not appending, the flags O_CREAT and O_TRUNC are treated
311 : * as true and the flag O_EXCL is treated as false.
312 : *
313 : * NOTE: Ordinarily, O_APPEND means "seek to the end of the file before each
314 : * write()". We don't do that.
315 : */
316 : int
317 920 : start_writing_to_file(const char *fname, int open_flags, int mode,
318 : open_file_t **data_out)
319 : {
320 920 : open_file_t *new_file = tor_malloc_zero(sizeof(open_file_t));
321 920 : const char *open_name;
322 920 : int append = 0;
323 :
324 920 : tor_assert(fname);
325 920 : tor_assert(data_out);
326 : #if (O_BINARY != 0 && O_TEXT != 0)
327 : tor_assert((open_flags & (O_BINARY|O_TEXT)) != 0);
328 : #endif
329 920 : new_file->fd = -1;
330 920 : new_file->filename = tor_strdup(fname);
331 920 : if (open_flags & O_APPEND) {
332 119 : open_name = fname;
333 119 : new_file->rename_on_close = 0;
334 119 : append = 1;
335 119 : open_flags &= ~O_APPEND;
336 : } else {
337 801 : tor_asprintf(&new_file->tempname, "%s.tmp", fname);
338 801 : open_name = new_file->tempname;
339 : /* We always replace an existing temporary file if there is one. */
340 801 : open_flags |= O_CREAT|O_TRUNC;
341 801 : open_flags &= ~O_EXCL;
342 801 : new_file->rename_on_close = 1;
343 : }
344 : #if O_BINARY != 0
345 : if (open_flags & O_BINARY)
346 : new_file->binary = 1;
347 : #endif
348 :
349 920 : new_file->fd = tor_open_cloexec(open_name, open_flags, mode);
350 920 : if (new_file->fd < 0) {
351 1 : log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s",
352 : open_name, fname, strerror(errno));
353 1 : goto err;
354 : }
355 919 : if (append) {
356 119 : if (tor_fd_seekend(new_file->fd) < 0) {
357 0 : log_warn(LD_FS, "Couldn't seek to end of file \"%s\": %s", open_name,
358 : strerror(errno));
359 0 : goto err;
360 : }
361 : }
362 :
363 919 : *data_out = new_file;
364 :
365 919 : return new_file->fd;
366 :
367 1 : err:
368 1 : if (new_file->fd >= 0)
369 0 : close(new_file->fd);
370 1 : *data_out = NULL;
371 1 : tor_free(new_file->filename);
372 1 : tor_free(new_file->tempname);
373 1 : tor_free(new_file);
374 1 : return -1;
375 : }
376 :
377 : /** Given <b>file_data</b> from start_writing_to_file(), return a stdio FILE*
378 : * that can be used to write to the same file. The caller should not mix
379 : * stdio calls with non-stdio calls. */
380 : FILE *
381 2 : fdopen_file(open_file_t *file_data)
382 : {
383 2 : tor_assert(file_data);
384 2 : if (file_data->stdio_file)
385 : return file_data->stdio_file;
386 2 : tor_assert(file_data->fd >= 0);
387 2 : if (!(file_data->stdio_file = fdopen(file_data->fd,
388 2 : file_data->binary?"ab":"a"))) {
389 0 : log_warn(LD_FS, "Couldn't fdopen \"%s\" [%d]: %s", file_data->filename,
390 : file_data->fd, strerror(errno));
391 : }
392 2 : return file_data->stdio_file;
393 : }
394 :
395 : /** Combines start_writing_to_file with fdopen_file(): arguments are as
396 : * for start_writing_to_file, but */
397 : FILE *
398 2 : start_writing_to_stdio_file(const char *fname, int open_flags, int mode,
399 : open_file_t **data_out)
400 : {
401 2 : FILE *res;
402 2 : if (start_writing_to_file(fname, open_flags, mode, data_out)<0)
403 : return NULL;
404 2 : if (!(res = fdopen_file(*data_out))) {
405 0 : abort_writing_to_file(*data_out);
406 0 : *data_out = NULL;
407 : }
408 : return res;
409 : }
410 :
411 : /** Helper function: close and free the underlying file and memory in
412 : * <b>file_data</b>. If we were writing into a temporary file, then delete
413 : * that file (if abort_write is true) or replaces the target file with
414 : * the temporary file (if abort_write is false). */
415 : static int
416 919 : finish_writing_to_file_impl(open_file_t *file_data, int abort_write)
417 : {
418 919 : int r = 0;
419 :
420 919 : tor_assert(file_data && file_data->filename);
421 919 : if (file_data->stdio_file) {
422 2 : if (fclose(file_data->stdio_file)) {
423 0 : log_warn(LD_FS, "Error closing \"%s\": %s", file_data->filename,
424 : strerror(errno));
425 0 : abort_write = r = -1;
426 : }
427 917 : } else if (file_data->fd >= 0 && close(file_data->fd) < 0) {
428 0 : log_warn(LD_FS, "Error flushing \"%s\": %s", file_data->filename,
429 : strerror(errno));
430 0 : abort_write = r = -1;
431 : }
432 :
433 919 : if (file_data->rename_on_close) {
434 800 : tor_assert(file_data->tempname && file_data->filename);
435 800 : if (!abort_write) {
436 800 : tor_assert(strcmp(file_data->filename, file_data->tempname));
437 800 : if (replace_file(file_data->tempname, file_data->filename)) {
438 0 : log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename,
439 : strerror(errno));
440 0 : abort_write = r = -1;
441 : }
442 : }
443 800 : if (abort_write) {
444 0 : int res = unlink(file_data->tempname);
445 0 : if (res != 0) {
446 : /* We couldn't unlink and we'll leave a mess behind */
447 0 : log_warn(LD_FS, "Failed to unlink %s: %s",
448 : file_data->tempname, strerror(errno));
449 0 : r = -1;
450 : }
451 : }
452 : }
453 :
454 919 : tor_free(file_data->filename);
455 919 : tor_free(file_data->tempname);
456 919 : tor_free(file_data);
457 :
458 919 : return r;
459 : }
460 :
461 : /** Finish writing to <b>file_data</b>: close the file handle, free memory as
462 : * needed, and if using a temporary file, replace the original file with
463 : * the temporary file. */
464 : int
465 919 : finish_writing_to_file(open_file_t *file_data)
466 : {
467 919 : return finish_writing_to_file_impl(file_data, 0);
468 : }
469 :
470 : /** Finish writing to <b>file_data</b>: close the file handle, free memory as
471 : * needed, and if using a temporary file, delete it. */
472 : int
473 0 : abort_writing_to_file(open_file_t *file_data)
474 : {
475 0 : return finish_writing_to_file_impl(file_data, 1);
476 : }
477 :
478 : /** Helper: given a set of flags as passed to open(2), open the file
479 : * <b>fname</b> and write all the sized_chunk_t structs in <b>chunks</b> to
480 : * the file. Do so as atomically as possible e.g. by opening temp files and
481 : * renaming. */
482 : static int
483 906 : write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks,
484 : int open_flags)
485 : {
486 906 : open_file_t *file = NULL;
487 906 : int fd;
488 906 : ssize_t result;
489 906 : fd = start_writing_to_file(fname, open_flags, 0600, &file);
490 906 : if (fd<0)
491 : return -1;
492 3493 : SMARTLIST_FOREACH(chunks, sized_chunk_t *, chunk,
493 : {
494 : result = write_all_to_fd(fd, chunk->bytes, chunk->len);
495 : if (result < 0) {
496 : log_warn(LD_FS, "Error writing to \"%s\": %s", fname,
497 : strerror(errno));
498 : goto err;
499 : }
500 : tor_assert((size_t)result == chunk->len);
501 : });
502 :
503 905 : return finish_writing_to_file(file);
504 0 : err:
505 0 : abort_writing_to_file(file);
506 0 : return -1;
507 : }
508 :
509 : /** Given a smartlist of sized_chunk_t, write them to a file
510 : * <b>fname</b>, overwriting or creating the file as necessary.
511 : * If <b>no_tempfile</b> is 0 then the file will be written
512 : * atomically. */
513 : int
514 310 : write_chunks_to_file(const char *fname, const smartlist_t *chunks, int bin,
515 : int no_tempfile)
516 : {
517 310 : int flags = OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT);
518 :
519 310 : if (no_tempfile) {
520 : /* O_APPEND stops write_chunks_to_file from using tempfiles */
521 1 : flags |= O_APPEND;
522 : }
523 310 : return write_chunks_to_file_impl(fname, chunks, flags);
524 : }
525 :
526 : /** Write <b>len</b> bytes, starting at <b>str</b>, to <b>fname</b>
527 : using the open() flags passed in <b>flags</b>. */
528 : static int
529 596 : write_bytes_to_file_impl(const char *fname, const char *str, size_t len,
530 : int flags)
531 : {
532 596 : int r;
533 596 : sized_chunk_t c = { str, len };
534 596 : smartlist_t *chunks = smartlist_new();
535 596 : smartlist_add(chunks, &c);
536 596 : r = write_chunks_to_file_impl(fname, chunks, flags);
537 596 : smartlist_free(chunks);
538 596 : return r;
539 : }
540 :
541 : /** As write_str_to_file, but does not assume a NUL-terminated
542 : * string. Instead, we write <b>len</b> bytes, starting at <b>str</b>. */
543 487 : MOCK_IMPL(int,
544 : write_bytes_to_file,(const char *fname, const char *str, size_t len,
545 : int bin))
546 : {
547 487 : return write_bytes_to_file_impl(fname, str, len,
548 : OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT));
549 : }
550 :
551 : /** As write_bytes_to_file, but if the file already exists, append the bytes
552 : * to the end of the file instead of overwriting it. */
553 : int
554 109 : append_bytes_to_file(const char *fname, const char *str, size_t len,
555 : int bin)
556 : {
557 109 : return write_bytes_to_file_impl(fname, str, len,
558 : OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT));
559 : }
560 :
561 : /** Like write_str_to_file(), but also return -1 if there was a file
562 : already residing in <b>fname</b>. */
563 : int
564 0 : write_bytes_to_new_file(const char *fname, const char *str, size_t len,
565 : int bin)
566 : {
567 0 : return write_bytes_to_file_impl(fname, str, len,
568 : OPEN_FLAGS_DONT_REPLACE|
569 : (bin?O_BINARY:O_TEXT));
570 : }
571 :
572 : /**
573 : * Read the contents of the open file <b>fd</b> presuming it is a FIFO
574 : * (or similar) file descriptor for which the size of the file isn't
575 : * known ahead of time. Return NULL on failure, and a NUL-terminated
576 : * string on success. On success, set <b>sz_out</b> to the number of
577 : * bytes read.
578 : */
579 : char *
580 6005 : read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out)
581 : {
582 6005 : ssize_t r;
583 6005 : size_t pos = 0;
584 6005 : char *string = NULL;
585 6005 : size_t string_max = 0;
586 :
587 6005 : if (max_bytes_to_read+1 >= SIZE_T_CEILING) {
588 0 : errno = EINVAL;
589 0 : return NULL;
590 : }
591 :
592 31546 : do {
593 : /* XXXX This "add 1K" approach is a little goofy; if we care about
594 : * performance here, we should be doubling. But in practice we shouldn't
595 : * be using this function on big files anyway. */
596 31546 : string_max = pos + 1024;
597 31546 : if (string_max > max_bytes_to_read)
598 47 : string_max = max_bytes_to_read + 1;
599 31546 : string = tor_realloc(string, string_max);
600 31546 : r = read(fd, string + pos, string_max - pos - 1);
601 31546 : if (r < 0) {
602 0 : int save_errno = errno;
603 0 : tor_free(string);
604 0 : errno = save_errno;
605 0 : return NULL;
606 : }
607 :
608 31546 : pos += r;
609 31546 : } while (r > 0 && pos < max_bytes_to_read);
610 :
611 6005 : tor_assert(pos < string_max);
612 6005 : *sz_out = pos;
613 6005 : string[pos] = '\0';
614 6005 : return string;
615 : }
616 :
617 : /** Read the contents of <b>filename</b> into a newly allocated
618 : * string; return the string on success or NULL on failure.
619 : *
620 : * If <b>stat_out</b> is provided, store the result of stat()ing the
621 : * file into <b>stat_out</b>.
622 : *
623 : * If <b>flags</b> & RFTS_BIN, open the file in binary mode.
624 : * If <b>flags</b> & RFTS_IGNORE_MISSING, don't warn if the file
625 : * doesn't exist.
626 : *
627 : * Unless the RFTS_BIN flag is set in <b>flags</b>, this function will strip
628 : * any CR characters in the return value on all platforms.
629 : */
630 : /*
631 : * This function <em>may</em> return an erroneous result if the file
632 : * is modified while it is running, but must not crash or overflow.
633 : * Right now, the error case occurs when the file length grows between
634 : * the call to stat and the call to read_all: the resulting string will
635 : * be truncated.
636 : */
637 963 : MOCK_IMPL(char *,
638 : read_file_to_str, (const char *filename, int flags, struct stat *stat_out))
639 : {
640 963 : int fd; /* router file */
641 963 : struct stat statbuf;
642 963 : char *string;
643 963 : ssize_t r;
644 963 : int bin = flags & RFTS_BIN;
645 :
646 963 : tor_assert(filename);
647 :
648 963 : fd = tor_open_cloexec(filename,O_RDONLY|(bin?O_BINARY:O_TEXT),0);
649 963 : if (fd<0) {
650 152 : int severity = LOG_WARN;
651 152 : int save_errno = errno;
652 152 : if (errno == ENOENT && (flags & RFTS_IGNORE_MISSING))
653 149 : severity = LOG_INFO;
654 152 : log_fn(severity, LD_FS,"Could not open \"%s\": %s",filename,
655 : strerror(errno));
656 152 : errno = save_errno;
657 152 : return NULL;
658 : }
659 :
660 811 : if (fstat(fd, &statbuf)<0) {
661 0 : int save_errno = errno;
662 0 : close(fd);
663 0 : log_warn(LD_FS,"Could not fstat \"%s\".",filename);
664 0 : errno = save_errno;
665 0 : return NULL;
666 : }
667 :
668 : #ifndef _WIN32
669 : /** When we detect that we're reading from a FIFO, don't read more than
670 : * this many bytes. It's insane overkill for most uses. */
671 : #define FIFO_READ_MAX (1024*1024)
672 811 : if (S_ISFIFO(statbuf.st_mode)) {
673 0 : size_t sz = 0;
674 0 : string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz);
675 0 : int save_errno = errno;
676 0 : if (string && stat_out) {
677 0 : statbuf.st_size = sz;
678 0 : memcpy(stat_out, &statbuf, sizeof(struct stat));
679 : }
680 0 : close(fd);
681 0 : if (!string)
682 0 : errno = save_errno;
683 0 : return string;
684 : }
685 : #endif /* !defined(_WIN32) */
686 :
687 811 : if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING) {
688 0 : close(fd);
689 0 : errno = EINVAL;
690 0 : return NULL;
691 : }
692 :
693 811 : string = tor_malloc((size_t)(statbuf.st_size+1));
694 :
695 811 : r = read_all_from_fd(fd,string,(size_t)statbuf.st_size);
696 811 : if (r<0) {
697 1 : int save_errno = errno;
698 1 : log_warn(LD_FS,"Error reading from file \"%s\": %s", filename,
699 : strerror(errno));
700 1 : tor_free(string);
701 1 : close(fd);
702 1 : errno = save_errno;
703 1 : return NULL;
704 : }
705 810 : string[r] = '\0'; /* NUL-terminate the result. */
706 :
707 810 : if (!bin && strchr(string, '\r')) {
708 1 : log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped "
709 : "when reading %s. Coping.",
710 : filename);
711 1 : tor_strstrip(string, "\r");
712 1 : r = strlen(string);
713 : }
714 810 : if (!bin) {
715 660 : statbuf.st_size = (size_t) r;
716 : } else {
717 150 : if (r != statbuf.st_size) {
718 : /* Unless we're using text mode on win32, we'd better have an exact
719 : * match for size. */
720 0 : int save_errno = errno;
721 0 : log_warn(LD_FS,"Could read only %d of %ld bytes of file \"%s\".",
722 : (int)r, (long)statbuf.st_size,filename);
723 0 : tor_free(string);
724 0 : close(fd);
725 0 : errno = save_errno;
726 0 : return NULL;
727 : }
728 : }
729 810 : close(fd);
730 810 : if (stat_out) {
731 158 : memcpy(stat_out, &statbuf, sizeof(struct stat));
732 : }
733 :
734 : return string;
735 : }
736 :
737 : /** Attempt to read a file <b>fname</b>. If the file's contents is
738 : * equal to the string <b>str</b>, return 0. Otherwise, attempt to
739 : * overwrite the file with the contents of <b>str</b> and return
740 : * the value of write_str_to_file().
741 : */
742 : int
743 50 : write_str_to_file_if_not_equal(const char *fname, const char *str)
744 : {
745 50 : char *fstr = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
746 50 : int rv;
747 :
748 50 : if (!fstr || strcmp(str, fstr)) {
749 31 : rv = write_str_to_file(fname, str, 0);
750 : } else {
751 : rv = 0;
752 : }
753 50 : tor_free(fstr);
754 50 : return rv;
755 : }
756 :
757 : #if !defined(HAVE_GETDELIM) || defined(TOR_UNIT_TESTS)
758 : #include "ext/getdelim.c"
759 : #endif
|