[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r11300: Refactor write_chunks_to_file_impl: break out the "pick a te (in tor/trunk: . src/common)



Author: nickm
Date: 2007-08-29 15:02:37 -0400 (Wed, 29 Aug 2007)
New Revision: 11300

Modified:
   tor/trunk/
   tor/trunk/src/common/util.c
   tor/trunk/src/common/util.h
Log:
 r14831@catbus:  nickm | 2007-08-29 14:17:42 -0400
 Refactor write_chunks_to_file_impl: break out the "pick a temporary name if it makes sense, and open the right filename" logic and the "close the file and unlink or rename if necessary" logic.  This will let us write big files in a smarter way than "Build a big string" or "make a list of chunks", once we get around to using it.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r14831] on 8246c3cf-6607-4228-993b-4d95d33730f1

Modified: tor/trunk/src/common/util.c
===================================================================
--- tor/trunk/src/common/util.c	2007-08-29 19:02:33 UTC (rev 11299)
+++ tor/trunk/src/common/util.c	2007-08-29 19:02:37 UTC (rev 11300)
@@ -1459,61 +1459,132 @@
   return write_bytes_to_file(fname, str, strlen(str), bin);
 }
 
-/** Helper: given a set of flags as passed to open(2), open the file
- * <b>fname</b> and write all the sized_chunk_t structs in <b>chunks</b> to
- * the file.  Do so as atomically as possible e.g. by opening temp files and
- * renaming. */
-static int
-write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks,
-                          int open_flags)
-{
-  size_t tempname_len;
+/** DOCDOC */
+struct open_file_t {
   char *tempname;
+  char *filename;
+  int rename_on_close;
   int fd;
-  int result;
+};
+
+/** DOCDOC */
+int
+start_writing_to_file(const char *fname, int open_flags, int mode,
+                      open_file_t **data_out)
+{
+  size_t tempname_len = strlen(fname)+16;
+  open_file_t *new_file = tor_malloc_zero(sizeof(open_file_t));
+  const char *open_name;
+  tor_assert(fname);
+  tor_assert(data_out);
+  new_file->fd = -1;
   tempname_len = strlen(fname)+16;
   tor_assert(tempname_len > strlen(fname)); /*check for overflow*/
-  tempname = tor_malloc(tempname_len);
+  new_file->filename = tor_strdup(fname);
   if (open_flags & O_APPEND) {
-    strlcpy(tempname, fname, tempname_len);
+    open_name = fname;
+    new_file->rename_on_close = 0;
   } else {
-    if (tor_snprintf(tempname, tempname_len, "%s.tmp", fname)<0) {
+    new_file->tempname = tor_malloc(tempname_len);
+    if (tor_snprintf(new_file->tempname, tempname_len, "%s.tmp", fname)<0) {
       log(LOG_WARN, LD_GENERAL, "Failed to generate filename");
       goto err;
     }
+    new_file->rename_on_close = 1;
   }
-  if ((fd = open(tempname, open_flags, 0600))
+
+  if ((new_file->fd = open(new_file->tempname, open_flags, mode))
       < 0) {
-    log(LOG_WARN, LD_FS, "Couldn't open \"%s\" for writing: %s", tempname,
-        strerror(errno));
+    log(LOG_WARN, LD_FS, "Couldn't open \"%s\" for writing: %s",
+        new_file->tempname, strerror(errno));
     goto err;
   }
+
+  *data_out = new_file;
+
+  return new_file->fd;
+ err:
+  *data_out = NULL;
+  tor_free(new_file->filename);
+  tor_free(new_file->tempname);
+  tor_free(new_file);
+  return -1;
+}
+
+/** DOCDOC */
+static int
+finish_writing_to_file_impl(open_file_t *file_data, int abort_write)
+{
+  int r = 0;
+  tor_assert(file_data && file_data->filename);
+  if (file_data->fd >= 0 && close(file_data->fd) < 0) {
+    log_warn(LD_FS, "Error flushing \"%s\": %s", file_data->filename,
+             strerror(errno));
+    abort_write = 1;
+    r = -1;
+  }
+
+  if (file_data->rename_on_close) {
+    tor_assert(file_data->tempname && file_data->filename);
+    if (abort_write) {
+      unlink(file_data->tempname);
+    } else {
+      tor_assert(strcmp(file_data->filename, file_data->tempname));
+      if (replace_file(file_data->tempname, file_data->filename)) {
+        log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename,
+                 strerror(errno));
+        r = -1;
+      }
+    }
+  }
+
+  tor_free(file_data->filename);
+  tor_free(file_data->tempname);
+  tor_free(file_data);
+
+  return r;
+}
+
+/** DOCDOC */
+int
+finish_writing_to_file(open_file_t *file_data)
+{
+  return finish_writing_to_file_impl(file_data, 0);
+}
+
+/** DOCDOC */
+int
+abort_writing_to_file(open_file_t *file_data)
+{
+  return finish_writing_to_file_impl(file_data, 1);
+}
+
+/** Helper: given a set of flags as passed to open(2), open the file
+ * <b>fname</b> and write all the sized_chunk_t structs in <b>chunks</b> to
+ * the file.  Do so as atomically as possible e.g. by opening temp files and
+ * renaming. */
+static int
+write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks,
+                          int open_flags)
+{
+  open_file_t *file = NULL;
+  int fd, result;
+  fd = start_writing_to_file(fname, open_flags, 0600, &file);
+  if (fd<0)
+    return -1;
   SMARTLIST_FOREACH(chunks, sized_chunk_t *, chunk,
   {
     result = write_all(fd, chunk->bytes, chunk->len, 0);
     if (result < 0 || (size_t)result != chunk->len) {
-      log(LOG_WARN, LD_FS, "Error writing to \"%s\": %s", tempname,
+      log(LOG_WARN, LD_FS, "Error writing to \"%s\": %s", fname,
           strerror(errno));
-      close(fd);
       goto err;
     }
   });
-  if (close(fd)) {
-    log(LOG_WARN, LD_FS, "Error flushing to \"%s\": %s", tempname,
-        strerror(errno));
-    goto err;
-  }
-  if (!(open_flags & O_APPEND)) {
-    if (replace_file(tempname, fname)) {
-      log(LOG_WARN, LD_FS, "Error replacing \"%s\": %s", fname,
-          strerror(errno));
-      goto err;
-    }
-  }
-  tor_free(tempname);
-  return 0;
+
+  return finish_writing_to_file(file);
  err:
-  tor_free(tempname);
+  abort_writing_to_file(file);
   return -1;
 }
 

Modified: tor/trunk/src/common/util.h
===================================================================
--- tor/trunk/src/common/util.h	2007-08-29 19:02:33 UTC (rev 11299)
+++ tor/trunk/src/common/util.h	2007-08-29 19:02:37 UTC (rev 11300)
@@ -213,6 +213,11 @@
  * directory; see that function's documentation for details. */
 typedef enum { CPD_NONE, CPD_CREATE, CPD_CHECK } cpd_check_t;
 int check_private_dir(const char *dirname, cpd_check_t check);
+typedef struct open_file_t open_file_t;
+int start_writing_to_file(const char *fname, int open_flags, int mode,
+                          open_file_t **data_out);
+int finish_writing_to_file(open_file_t *file_data);
+int abort_writing_to_file(open_file_t *file_data);
 int write_str_to_file(const char *fname, const char *str, int bin);
 int write_bytes_to_file(const char *fname, const char *str, size_t len,
                         int bin);