[tor-commits] [tor/master] Handle FIFOs in read_file_to_str
nickm at torproject.org
nickm at torproject.org
Mon Sep 17 14:05:48 UTC 2012
commit d64bf286a175f590fc07f51f49584cf246eac9b2
Author: meejah <meejah at meejah.ca>
Date: Wed Sep 12 13:26:34 2012 -0600
Handle FIFOs in read_file_to_str
add read_file_to_str_until_eof which is used by read_file_to_str
if the file happens to be a FIFO.
change file_status() to return FN_FILE if st_mode matches S_IFIFO
(on not-windows) so that init_key_from_file() will read from a FIFO.
---
src/common/util.c | 60 ++++++++++++++++++++++++++
src/common/util.h | 3 +
src/test/test_util.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 177 insertions(+), 0 deletions(-)
diff --git a/src/common/util.c b/src/common/util.c
index 3efc253..feeaf74 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1807,6 +1807,10 @@ file_status(const char *fname)
return FN_DIR;
else if (st.st_mode & S_IFREG)
return FN_FILE;
+#ifndef _WIN32
+ else if (st.st_mode & S_IFIFO)
+ return FN_FILE;
+#endif
else
return FN_ERROR;
}
@@ -2237,6 +2241,46 @@ write_bytes_to_new_file(const char *fname, const char *str, size_t len,
(bin?O_BINARY:O_TEXT));
}
+/**
+ * Read the contents of the open file <b>fd</b> presuming it is a FIFO
+ * (or similar) file descriptor for which the size of the file isn't
+ * known ahead of time. Return NULL on failure, and a NUL-terminated
+ * string on success. On success, set <b>sz_out</b> to the number of
+ * bytes read.
+ */
+char *
+read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out)
+{
+ ssize_t r;
+ size_t pos = 0;
+ char *string = NULL;
+ size_t string_max = 0;
+
+ if (max_bytes_to_read+1 >= SIZE_T_CEILING)
+ return NULL;
+
+ do {
+ /* XXXX This "add 1K" approach is a little goofy; if we care about
+ * performance here, we should be doubling. But in practice we shouldn't
+ * be using this function on big files anyway. */
+ string_max = pos + 1024;
+ if (string_max > max_bytes_to_read)
+ string_max = max_bytes_to_read + 1;
+ string = tor_realloc(string, string_max);
+ r = read(fd, string + pos, string_max - pos - 1);
+ if (r < 0) {
+ tor_free(string);
+ return NULL;
+ }
+
+ pos += r;
+ } while (r > 0 && pos < max_bytes_to_read);
+
+ *sz_out = pos;
+ string[pos] = '\0';
+ return string;
+}
+
/** Read the contents of <b>filename</b> into a newly allocated
* string; return the string on success or NULL on failure.
*
@@ -2285,6 +2329,22 @@ read_file_to_str(const char *filename, int flags, struct stat *stat_out)
return NULL;
}
+#ifndef _WIN32
+/** When we detect that we're reading from a FIFO, don't read more than
+ * this many bytes. It's insane overkill for most uses. */
+#define FIFO_READ_MAX (1024*1024)
+ if (S_ISFIFO(statbuf.st_mode)) {
+ size_t sz = 0;
+ string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz);
+ if (string && stat_out) {
+ statbuf.st_size = sz;
+ memcpy(stat_out, &statbuf, sizeof(struct stat));
+ }
+ close(fd);
+ return string;
+ }
+#endif
+
if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING)
return NULL;
diff --git a/src/common/util.h b/src/common/util.h
index a6944ac..0cfc1b9 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -360,6 +360,9 @@ struct stat;
#endif
char *read_file_to_str(const char *filename, int flags, struct stat *stat_out)
ATTR_MALLOC;
+char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read,
+ size_t *sz_out)
+ ATTR_MALLOC;
const char *parse_config_line_from_str(const char *line,
char **key_out, char **value_out);
char *expand_filename(const char *filename);
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 64976f3..cc3a03f 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -19,6 +19,117 @@
#endif
static void
+test_util_read_file_fifo_tiny_limit(void *arg)
+{
+#ifndef _WIN32
+ char *fifo_name = NULL;
+ char *str = NULL;
+ int fd = -1;
+ int read_fd = -1;
+ size_t sz;
+ (void)arg;
+
+ fifo_name = tor_strdup(get_fname("tor_test_fifo_tiny"));
+ fd = open(fifo_name, O_WRONLY | O_CREAT, 0600);
+ test_neq(fd, -1);
+ test_eq(write(fd, "short", 6), 6);
+ close(fd);
+
+ // purposely set limit shorter than what we wrote to the FIFO to
+ // test the maximum, and that it puts the NUL in the right spot
+
+ read_fd = open(fifo_name, O_RDONLY);
+ str = read_file_to_str_until_eof(read_fd, 4, &sz);
+ close(read_fd);
+
+ test_eq(str[0], 's');
+ test_eq(str[1], 'h');
+ test_eq(str[2], 'o');
+ test_eq(str[3], 'r');
+ test_eq(str[4], '\0');
+
+ done:
+ unlink(fifo_name);
+ tor_free(fifo_name);
+ tor_free(str);
+#endif
+}
+
+static void
+test_util_read_file_fifo_two_loops(void *arg)
+{
+#ifndef _WIN32
+ char *fifo_name = NULL;
+ char *str = NULL;
+ char data[2048];
+ int i = 0;
+ int fd = -1;
+ int read_fd = -1;
+ size_t sz;
+ (void)arg;
+
+ while (i < 2048) {
+ data[i] = (char)(i & 0xff);
+ ++i;
+ }
+
+ // write more than 1024 bytes to the FIFO to test two passes through
+ // the loop in the method; if the re-alloc size is changed this
+ // should be updated as well.
+
+ fifo_name = tor_strdup(get_fname("tor_fifo_test_2k"));
+ fd = open(fifo_name, O_WRONLY | O_CREAT, 0600);
+ test_neq(fd, -1);
+ test_eq(write(fd, data, 2048), 2048);
+ close(fd);
+
+ read_fd = open(fifo_name, O_RDONLY);
+ str = read_file_to_str_until_eof(read_fd, 1024*1024, &sz);
+ close(read_fd);
+
+ for (i = 0; i < 2048; ++i) {
+ test_eq(str[i], (char)(i & 0xff));
+ }
+
+ done:
+ unlink(fifo_name);
+ tor_free(fifo_name);
+ tor_free(str);
+#endif
+}
+
+static void
+test_util_read_file_fifo_zero_bytes(void *arg)
+{
+#ifndef _WIN32
+ char *fifo_name = NULL;
+ char *str = NULL;
+ int fd = -1;
+ int read_fd = -1;
+ size_t sz;
+ (void)arg;
+
+ fifo_name = tor_strdup(get_fname("tor_fifo_test_zero_bytes"));
+ // zero-byte fifo
+ fd = open(fifo_name, O_WRONLY | O_CREAT, 0600);
+ test_neq(fd, -1);
+ close(fd);
+
+ read_fd = open(fifo_name, O_RDONLY);
+ str = read_file_to_str_until_eof(read_fd, 1024, &sz);
+ close(read_fd);
+
+ test_neq(str, NULL);
+ test_eq(str[0], '\0');
+
+ done:
+ unlink(fifo_name);
+ tor_free(fifo_name);
+ tor_free(str);
+#endif
+}
+
+static void
test_util_time(void)
{
struct timeval start, end;
@@ -3191,6 +3302,9 @@ struct testcase_t util_tests[] = {
UTIL_TEST(envnames, 0),
UTIL_TEST(make_environment, 0),
UTIL_TEST(set_env_var_in_sl, 0),
+ UTIL_TEST(read_file_fifo_tiny_limit, 0),
+ UTIL_TEST(read_file_fifo_two_loops, 0),
+ UTIL_TEST(read_file_fifo_zero_bytes, 0),
END_OF_TESTCASES
};
More information about the tor-commits
mailing list