aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2012-09-17 10:03:11 -0400
committerNick Mathewson <nickm@torproject.org>2012-09-17 10:03:11 -0400
commitc3f526ed64012f64589b926082ff5e542ec7d18d (patch)
treee85837f0956622fb222ab30a82232e37eecba726 /src
parent2939cc3ba3afe5ef2c6a273eef18577274e6867b (diff)
parentfaab7881894e55e71c0a19654f3c733c8b0d2920 (diff)
downloadtor-c3f526ed64012f64589b926082ff5e542ec7d18d.tar
tor-c3f526ed64012f64589b926082ff5e542ec7d18d.tar.gz
Merge branch '6044_nm_squashed'
Diffstat (limited to 'src')
-rw-r--r--src/common/util.c60
-rw-r--r--src/common/util.h3
-rw-r--r--src/test/test_util.c71
3 files changed, 134 insertions, 0 deletions
diff --git a/src/common/util.c b/src/common/util.c
index 5329a0504..4e203e7de 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1833,6 +1833,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;
}
@@ -2263,6 +2267,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.
*
@@ -2311,6 +2355,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 04812df7c..6667978d1 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -361,6 +361,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 2c65903dd..f615ead7d 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -32,6 +32,74 @@ tor_timegm_wrapper(const struct tm *tm)
#define tor_timegm tor_timegm_wrapper
static void
+test_util_read_until_eof_impl(const char *fname, size_t file_len,
+ size_t read_limit)
+{
+ char *fifo_name = NULL;
+ char *test_str = NULL;
+ char *str = NULL;
+ size_t sz = 9999999;
+ int fd = -1;
+ int r;
+
+ fifo_name = tor_strdup(get_fname(fname));
+ test_str = tor_malloc(file_len);
+ crypto_rand(test_str, file_len);
+
+ r = write_bytes_to_file(fifo_name, test_str, file_len, 1);
+ tt_int_op(r, ==, 0);
+
+ fd = open(fifo_name, O_RDONLY|O_BINARY);
+ tt_int_op(fd, >=, 0);
+ str = read_file_to_str_until_eof(fd, read_limit, &sz);
+ close(fd);
+ tt_assert(str != NULL);
+
+ if (read_limit < file_len)
+ tt_int_op(sz, ==, read_limit);
+ else
+ tt_int_op(sz, ==, file_len);
+
+ test_mem_op(test_str, ==, str, sz);
+ test_assert(str[sz] == '\0');
+
+ done:
+ unlink(fifo_name);
+ tor_free(fifo_name);
+ tor_free(test_str);
+ tor_free(str);
+}
+
+static void
+test_util_read_file_eof_tiny_limit(void *arg)
+{
+ (void)arg;
+ // 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
+
+ test_util_read_until_eof_impl("tor_test_fifo_tiny", 5, 4);
+}
+
+static void
+test_util_read_file_eof_two_loops(void *arg)
+{
+ (void)arg;
+ // 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.
+
+ test_util_read_until_eof_impl("tor_test_fifo_2k", 2048, 10000);
+}
+
+static void
+test_util_read_file_eof_zero_bytes(void *arg)
+{
+ (void)arg;
+ // zero-byte fifo
+ test_util_read_until_eof_impl("tor_test_fifo_empty", 0, 10000);
+}
+
+static void
test_util_time(void)
{
struct timeval start, end;
@@ -3214,6 +3282,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_eof_tiny_limit, 0),
+ UTIL_TEST(read_file_eof_two_loops, 0),
+ UTIL_TEST(read_file_eof_zero_bytes, 0),
END_OF_TESTCASES
};