[libgsf] Modtime improvements.



commit 590b1eb86adc1fe15f6e2675d0027344b9856571
Author: Morten Welinder <terra gnome org>
Date:   Mon Mar 4 12:39:57 2013 -0500

    Modtime improvements.
    
    GsfInputStdio: usec precision.
    GsfOutputStdio: set timestamp on file.
    GsfOutput: implement setting modtime as property.

 ChangeLog              |   10 ++++++++
 configure.ac           |    4 ++-
 gsf/gsf-input-stdio.c  |   15 ++++++++++++
 gsf/gsf-output-stdio.c |   59 ++++++++++++++++++++++++++++++++++-------------
 gsf/gsf-output.c       |   11 +++++++-
 tests/test-cp.c        |   27 +++++++++++++--------
 6 files changed, 96 insertions(+), 30 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 058a221..8a463c0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,21 @@
 2013-03-04  Morten Welinder  <terra gnome org>
 
+       * configure.ac: Check for utime.h and sys/utime.h.  Check for
+       stat.st_mtimensec and stat.st_mtim.tv_nsec.
+
+       * tests/test-cp.c (test): Copy modtime too.
+
        * gsf/gsf-input.c (gsf_input_get_property): Add new modtime
        property.
        * gsf/gsf-output.c (gsf_output_get_property): Ditto.
 
        * gsf/gsf-input-gzip.c (check_header): Set modtime when available.
 
+       * gsf/gsf-input-stdio.c (gsf_input_stdio_new): Set modtime.
+
+       * gsf/gsf-output-stdio.c (gsf_output_stdio_close): Set modtime of
+       resulting file.
+
        * gsf/gsf-input.c (gsf_input_uncompress): Fix potential failure
        with bzip'd input.
 
diff --git a/configure.ac b/configure.ac
index a3c2879..0ada77a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -259,6 +259,8 @@ if test $struct_timeval_works = no ; then
        AC_MSG_ERROR([struct timeval is not available])
 fi
 
+AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec])
+
 AC_MSG_CHECKING([whether -D_BSD_SOURCE is needed for caddr_t])
 AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM([[#include <sys/types.h>]], [[caddr_t ca]])],
@@ -279,7 +281,7 @@ if test $need_bsd1 = yes -o $need_bsd2 = yes; then
 fi
 
 AC_TYPE_MODE_T
-AC_CHECK_HEADERS(fcntl.h malloc.h unistd.h io.h sys/statfs.h sys/param.h sys/mount.h)
+AC_CHECK_HEADERS(fcntl.h malloc.h unistd.h io.h sys/statfs.h sys/param.h sys/mount.h utime.h sys/utime.h)
 AC_FUNC_MMAP
 
 AC_MSG_CHECKING([form of statfs])
diff --git a/gsf/gsf-input-stdio.c b/gsf/gsf-input-stdio.c
index b99c74c..c20be0e 100644
--- a/gsf/gsf-input-stdio.c
+++ b/gsf/gsf-input-stdio.c
@@ -148,6 +148,21 @@ gsf_input_stdio_new (char const *filename, GError **err)
        input->keep_open = FALSE;
        gsf_input_set_size (GSF_INPUT (input), size);
        gsf_input_set_name_from_filename (GSF_INPUT (input), filename);
+       if (st.st_mtime != (time_t)-1) {
+               GTimeVal tv;
+
+               tv.tv_sec = st.st_mtime;
+#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
+               tv.tv_usec = st.st_mtimensec / 1000;
+#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
+               tv.tv_usec =  st.st_mtim.tv_nsec / 1000;
+#else
+               tv.tv_usec = 0;
+#endif
+
+               gsf_input_set_modtime (GSF_INPUT (input),
+                                      g_date_time_new_from_timeval_utc (&tv));
+       }
 
        return GSF_INPUT (input);
 }
diff --git a/gsf/gsf-output-stdio.c b/gsf/gsf-output-stdio.c
index bf89aef..3bcb54f 100644
--- a/gsf/gsf-output-stdio.c
+++ b/gsf/gsf-output-stdio.c
@@ -36,6 +36,14 @@
 #include <sys/statfs.h>
 #endif
 
+#ifdef HAVE_UTIME_H
+#define UTIME_AVAILABLE
+#include <utime.h>
+#elif defined(HAVE_SYS_UTIME_H)
+#define UTIME_AVAILABLE
+#include <sys/utime.h>
+#endif
+
 #ifdef G_OS_WIN32
 #include <wchar.h>
 #include <direct.h>
@@ -193,6 +201,7 @@ gsf_output_stdio_close (GsfOutput *output)
        GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (output);
        gboolean res;
        char *backup_filename = NULL;
+       GDateTime *modtime;
 
        if (stdio->file == NULL)
                return FALSE;
@@ -238,9 +247,9 @@ gsf_output_stdio_close (GsfOutput *output)
                                              "Could not backup the original as %s.",
                                              utf8name);
                        g_free (utf8name);
-                       g_free (backup_filename);
                        g_unlink (stdio->temp_filename);
-                       return FALSE;
+                       res = FALSE;
+                       goto out;
                }
        }
 
@@ -253,24 +262,40 @@ gsf_output_stdio_close (GsfOutput *output)
                res = gsf_output_set_error (output,
                                            saved_errno,
                                            "%s", g_strerror (saved_errno));
-       } else {
-               /* Restore permissions.  There is not much error checking we
-                * can do here, I'm afraid.  The final data is saved anyways.
-                * Note the order: mode, uid+gid, gid, uid, mode.
-                */
-               g_chmod (stdio->real_filename, stdio->st.st_mode);
-#ifdef HAVE_CHOWN
-               if (chown_wrapper (stdio->real_filename,
-                                  stdio->st.st_uid,
-                                  stdio->st.st_gid)) {
-                       /* We cannot set both.  Maybe we can set one.  */
-                       chown_wrapper (stdio->real_filename, -1, stdio->st.st_gid);
-                       chown_wrapper (stdio->real_filename, stdio->st.st_uid, -1);
-               }
-               g_chmod (stdio->real_filename, stdio->st.st_mode);
+               goto out;
+       }
+
+       modtime = gsf_output_get_modtime (output);
+       if (modtime) {
+#ifdef UTIME_AVAILABLE
+               struct utimbuf ut;
+
+               ut.actime = time (NULL);
+               ut.modtime = g_date_time_to_unix (modtime);
+               /* Ignore errors */
+               /* utimes() provides better accuracy, but doesn't have 
+                  gstdio version.  gio seems to provide access.  */
+               (void)utime (stdio->real_filename, &ut);
 #endif
        }
 
+       /* Restore permissions.  There is not much error checking we
+        * can do here, I'm afraid.  The final data is saved anyways.
+        * Note the order: mode, uid+gid, gid, uid, mode.
+        */
+       g_chmod (stdio->real_filename, stdio->st.st_mode);
+#ifdef HAVE_CHOWN
+       if (chown_wrapper (stdio->real_filename,
+                          stdio->st.st_uid,
+                          stdio->st.st_gid)) {
+               /* We cannot set both.  Maybe we can set one.  */
+               chown_wrapper (stdio->real_filename, -1, stdio->st.st_gid);
+               chown_wrapper (stdio->real_filename, stdio->st.st_uid, -1);
+       }
+       g_chmod (stdio->real_filename, stdio->st.st_mode);
+#endif
+
+out:
        g_free (backup_filename);
 
        return res;
diff --git a/gsf/gsf-output.c b/gsf/gsf-output.c
index 2439190..a40d7e5 100644
--- a/gsf/gsf-output.c
+++ b/gsf/gsf-output.c
@@ -58,7 +58,16 @@ gsf_output_set_property (GObject      *object,
         G_GNUC_UNUSED   GValue const *value,
                         GParamSpec   *pspec)
 {
+       GsfOutput *output = GSF_OUTPUT (object);
+
        switch (property_id) {
+       case PROP_MODTIME: {
+               GDateTime *modtime = g_value_get_boxed (value);
+               if (modtime)
+                       modtime = g_date_time_add (modtime, 0); // Copy
+               gsf_output_set_modtime (output, modtime);
+               break;
+       }
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
                break;
@@ -133,8 +142,6 @@ gsf_output_init (GObject *obj)
        output->is_closed       = FALSE;
        output->printf_buf      = NULL;
        output->printf_buf_size = 0;
-
-       gsf_output_set_modtime (output, g_date_time_new_now_utc ());
 }
 
 static void
diff --git a/tests/test-cp.c b/tests/test-cp.c
index b1a6881..6c16e2d 100644
--- a/tests/test-cp.c
+++ b/tests/test-cp.c
@@ -29,10 +29,11 @@
 static int
 test (char *argv[])
 {
-       GsfInput   *input;
-       GsfOutput  *output;
+       GsfInput   *input = NULL;
+       GsfOutput  *output = NULL;
        GError     *err = NULL;
        int         rval = 0;
+       GDateTime  *modtime;
 
        input = gsf_input_stdio_new (argv[1], &err);
        if (input == NULL) {
@@ -43,31 +44,37 @@ test (char *argv[])
                g_error_free (err);
                return 1;
        }
+       modtime = gsf_input_get_modtime (input);
 
-       output = gsf_output_stdio_new (argv[2], &err);
+       output = gsf_output_stdio_new_full
+               (argv[2], &err, "modtime", modtime, NULL);
        if (output == NULL) {
-
                g_return_val_if_fail (err != NULL, 1);
 
                g_warning ("'%s' error: %s\n", argv[2], err->message);
                g_error_free (err);
 
-               g_object_unref (G_OBJECT (input));
-               return 1;
+               rval = 1;
+               goto out;
        }
 
        if (gsf_input_copy (input, output) == FALSE) {
-               rval = 1;
                err = (GError*) gsf_output_error (output);
                if (err != NULL) {
                        g_warning ("'%s' error: %s\n", argv[2], err->message);
                }
+               rval = 1;
+               goto out;
        }
 
-       g_object_unref (G_OBJECT (input));
+out:
+       if (input)
+               g_object_unref (input);
 
-       gsf_output_close (output);
-       g_object_unref (G_OBJECT (output));
+       if (output) {
+               gsf_output_close (output);
+               g_object_unref (output);
+       }
 
        return rval;
 }


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