Browse Source

Add a tor_ftruncate to replace ftruncate.

(Windows doesn't have ftruncate, and some ftruncates do not move the
file pointer to the start of the file.)
Nick Mathewson 10 years ago
parent
commit
867f5e6a76
4 changed files with 73 additions and 2 deletions
  1. 17 0
      src/common/compat.c
  2. 1 0
      src/common/compat.h
  3. 6 2
      src/common/log.c
  4. 49 0
      src/test/test_util.c

+ 17 - 0
src/common/compat.c

@@ -1004,6 +1004,23 @@ tor_fd_setpos(int fd, off_t pos)
 #endif
 }
 
+/** Replacement for ftruncate(fd, 0): move to the front of the file and remove
+ * all the rest of the file. Return -1 on error, 0 on success. */
+int
+tor_ftruncate(int fd)
+{
+  /* Rumor has it that some versions of ftruncate do not move the file pointer.
+   */
+  if (tor_fd_setpos(fd, 0) < 0)
+    return -1;
+
+#ifdef _WIN32
+  return _chsize(fd, 0);
+#else
+  return ftruncate(fd, 0);
+#endif
+}
+
 #undef DEBUG_SOCKET_COUNTING
 #ifdef DEBUG_SOCKET_COUNTING
 /** A bitarray of all fds that should be passed to tor_socket_close(). Only

+ 1 - 0
src/common/compat.h

@@ -408,6 +408,7 @@ void tor_lockfile_unlock(tor_lockfile_t *lockfile);
 off_t tor_fd_getpos(int fd);
 int tor_fd_setpos(int fd, off_t pos);
 int tor_fd_seekend(int fd);
+int tor_ftruncate(int fd);
 
 #ifdef _WIN32
 #define PATH_SEPARATOR "\\"

+ 6 - 2
src/common/log.c

@@ -1305,6 +1305,10 @@ switch_logs_debug(void)
 void
 truncate_logs(void)
 {
-  for (logfile_t *lf = logfiles; lf; lf = lf->next)
-    ftruncate(lf->fd, 0);
+  for (logfile_t *lf = logfiles; lf; lf = lf->next) {
+    if (lf->fd >= 0) {
+      tor_ftruncate(lf->fd);
+    }
+  }
 }
+

+ 49 - 0
src/test/test_util.c

@@ -2385,6 +2385,54 @@ test_util_parent_dir(void *ptr)
   tor_free(cp);
 }
 
+static void
+test_util_ftruncate(void *ptr)
+{
+  char *buf = NULL;
+  const char *fname;
+  int fd = -1;
+  const char *message = "Hello world";
+  const char *message2 = "Hola mundo";
+  struct stat st;
+
+  (void) ptr;
+
+  fname = get_fname("ftruncate");
+
+  fd = tor_open_cloexec(fname, O_WRONLY|O_CREAT, 0600);
+  tt_int_op(fd, >=, 0);
+
+  /* Make the file be there. */
+  tt_int_op(strlen(message), ==, write_all(fd, message, strlen(message), 0));
+  tt_int_op(tor_fd_getpos(fd), ==, strlen(message));
+  tt_int_op(0, ==, fstat(fd, &st));
+  tt_int_op(st.st_size, ==, strlen(message));
+
+  /* Truncate and see if it got truncated */
+  tt_int_op(0, ==, tor_ftruncate(fd));
+  tt_int_op(tor_fd_getpos(fd), ==, 0);
+  tt_int_op(0, ==, fstat(fd, &st));
+  tt_int_op(st.st_size, ==, 0);
+
+  /* Replace, and see if it got replaced */
+  tt_int_op(strlen(message2), ==,
+            write_all(fd, message2, strlen(message2), 0));
+  tt_int_op(tor_fd_getpos(fd), ==, strlen(message2));
+  tt_int_op(0, ==, fstat(fd, &st));
+  tt_int_op(st.st_size, ==, strlen(message2));
+
+  close(fd);
+  fd = -1;
+
+  buf = read_file_to_str(fname, 0, NULL);
+  tt_str_op(message2, ==, buf);
+
+ done:
+  if (fd >= 0)
+    close(fd);
+  tor_free(buf);
+}
+
 #ifdef _WIN32
 static void
 test_util_load_win_lib(void *ptr)
@@ -3798,6 +3846,7 @@ struct testcase_t util_tests[] = {
   UTIL_TEST(asprintf, 0),
   UTIL_TEST(listdir, 0),
   UTIL_TEST(parent_dir, 0),
+  UTIL_TEST(ftruncate, 0),
 #ifdef _WIN32
   UTIL_TEST(load_win_lib, 0),
 #endif