Re: Mogrify -preserve implementation

Niko Rosvall <[email protected]> Wed, 24 Feb 2016 11:32:32 +0200
Newsgroups gmane.comp.video.graphicsmagick.core
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--------------050209000100040906050103
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: 7bit

On 02/23/2016 07:19 PM, Niko Rosvall wrote:
> On 02/23/2016 04:47 PM, Bob Friesenhahn wrote:
>> On Tue, 23 Feb 2016, Niko Rosvall wrote:
>>
>>> Hi,
>>>
>>> I wrote a fairly naive implementation to keep file timestamps when
>>> running mogrify. I added an option -preserve to the command mogrify.
>>>
>>> By no means it's not perfect as it does not care about Windows. I hardly
>>> use Windows at all, so it fairly hard for me to implement support for
>>> it. However, I'm willing to do it, if this is a feature that GM wants to
>>> include.
>>
>> Few of us love Windows, but we are dedicated to making sure that 
>> GraphicsMagick Windows users are well supported within the 
>> capabilities of the operating system.
>>
>>> Some questions: Would it be better to implement the actual code into
>>> separate files (now it's just all in magick/command.c). Maybe
>>> magic/preserve.c?
>>
>> What is currently typically done is to put Unix-specific code in 
>> magick/unix_port.c and Windows-specific code in magick/nt_base.c. 
>> Similar functions added to each place can allow a common 
>> implementation in magick/command.c to work.
>>
>> The magick/studio.h header provides a MagickFstat() macro which 
>> provides porting definitions.  Windows does provide fstat as well as a 
>> a _fstati64() function (for large files).  I am not sure how one sets 
>> file timestamps under Windows.
>>
>> Bob
>>
> 
> Thanks!
> 
> I did take a look, and it's not too hard to set timetamps on Windows, so
> I will take a closer look and send a better patch later! Thanks for the
> instructions. :)
> 
> Niko

Hi,

Here's a patch which works on Windows too (and it better written in
general). In the end, setting the file timestamps on Windows is almost
the same as on Posix systems.

Niko

--------------050209000100040906050103
Content-Type: text/x-patch;
 name="mogrify-preserve.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="mogrify-preserve.diff"

diff -r 43a59a8ef281 magick/command.c
--- a/magick/command.c	Sun Feb 21 18:35:51 2016 -0600
+++ b/magick/command.c	Wed Feb 24 11:24:02 2016 +0200
@@ -8983,7 +8983,7 @@
 
   unsigned int
     matte;
-
+ 
   /*
     Verify option length.
   */
@@ -11663,6 +11663,7 @@
   const char *output_directory;
   MagickBool create_directories;
   MagickBool global_colormap;
+  MagickBool preserve_file_attr;
   MagickPassFail status;
   ExceptionInfo exception;
 } TransmogrifyOptions;
@@ -11677,6 +11678,14 @@
   MagickPassFail
     status = MagickPass;
 
+  int
+    fileatt_error;
+  
+  MagickStatStruct_t
+    statbuf;
+
+  fileatt_error = -1;
+  
   assert(options != (TransmogrifyOptions *) NULL);
   assert(options->input_filename != (char *) NULL);
 
@@ -11717,7 +11726,7 @@
         }
       if (status == MagickFail)
         break;
-          
+
       /*
         Write transmogrified image to disk.
       */
@@ -11751,6 +11760,10 @@
           AppendImageFormat(options->output_format,output_filename);
           (void) strlcpy(image->magick,options->output_format,MaxTextExtent);
         }
+      
+      if (options->preserve_file_attr)
+        fileatt_error = MagicGetFileAttributes(image->filename, &statbuf);
+
       if (options->create_directories)
         {
           /*
@@ -11805,7 +11818,21 @@
         Write the output file.
       */
       (void) strlcpy(image->filename,output_filename,MaxTextExtent);
+
+     
       status = WriteImages(image_info,image,image->filename,&options->exception);
+
+      if (options->preserve_file_attr)
+        {
+          if (fileatt_error == 0)
+            {
+              if (MagickSetFileAttributes(image->filename, &statbuf) != 0)
+                {
+                  fprintf(stderr, "Error preserving file timestamps\n");
+                }
+            }
+	      }
+	    
       if ((status != MagickFail) && (temporary_filename[0] != 0))
         {
           /*
@@ -11907,7 +11934,8 @@
 
   MagickBool
     create_directories,
-    global_colormap;
+    global_colormap,
+    preserve_file_attr;  
 
   unsigned int
     status;
@@ -11939,6 +11967,7 @@
   output_directory[0]='\0';
   create_directories=MagickFalse;
   global_colormap=MagickFalse;
+  preserve_file_attr=MagickFalse;
   status=True;
 
   /*
@@ -11971,6 +12000,7 @@
         transmogrify_options.output_directory=output_directory;
         transmogrify_options.create_directories=create_directories;
         transmogrify_options.global_colormap=global_colormap;
+        transmogrify_options.preserve_file_attr=preserve_file_attr;
         transmogrify_options.status=MagickPass;
         GetExceptionInfo(&transmogrify_options.exception);
         status &= *TransmogrifyImage(&transmogrify_options);
@@ -13112,6 +13142,11 @@
               ThrowMogrifyException(OptionError,MissingArgument,option);
             break;
           }
+        if (LocaleCompare("preserve", option+1) == 0)
+          {
+            preserve_file_attr = MagickTrue;
+            break;
+          }
         ThrowMogrifyException(OptionError,UnrecognizedOption,option)
       }
       case 'q':
@@ -13772,6 +13807,7 @@
       "-fill color           color for annotating or changing opaque color",
       "-pointsize value     font point size",
       "-profile filename    add ICM or IPTC information profile to image",
+      "-preserve            preverve original modification timestamp of the file",
       "-quality value       JPEG/MIFF/PNG compression level",
       "-raise value         lighten/darken image edges to create a 3-D effect",
       "-random-threshold channeltype LOWxHIGH",
diff -r 43a59a8ef281 magick/nt_base.c
--- a/magick/nt_base.c	Sun Feb 21 18:35:51 2016 -0600
+++ b/magick/nt_base.c	Wed Feb 24 11:24:02 2016 +0200
@@ -36,6 +36,8 @@
 /*
   Include declarations.
 */
+#include <sys/types.h>
+#include <sys/utime.h>
 #include "magick/log.h"
 #include "magick/magick.h"
 #include "magick/utility.h"
@@ -256,7 +258,32 @@
 {
   return 4096;
 }
-
+
+MagickExport int MagicGetFileAttributes(const char *filename, MagickStatStruct_t *statbuf)
+{
+  if (MagickStat(filename, statbuf) != 0)
+    return -1;
+  
+  return 0;
+}
+
+MagickExport int MagickSetFileAttributes(const char *filename, MagickStatStruct_t *statbuf)
+{
+  /*
+    Setting file timestamps on Windows is actually almost the same as on Posix systems.
+    https://msdn.microsoft.com/en-us/library/4wacf567.aspx
+   */
+  struct _utimbuf ut;
+  
+  ut.actime = statbuf->st_atime;
+  ut.modtime = statbuf->st_mtime;
+  
+  if (_utime(filename, &utbuf) == -1)
+    return -1;
+    
+  return 0;
+}
+
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
diff -r 43a59a8ef281 magick/nt_base.h
--- a/magick/nt_base.h	Sun Feb 21 18:35:51 2016 -0600
+++ b/magick/nt_base.h	Wed Feb 24 11:24:02 2016 +0200
@@ -356,6 +356,12 @@
   NTftruncate(int filedes, off_t length),
   NTmsync(void *addr, size_t len, int flags),
   NTmunmap(void *addr, size_t len);
+  
+extern MagickExport int
+  MagicGetFileAttributes(const char *filename, MagickStatStruct_t *statbuf);
+  
+extern MagickExport int
+  MagickSetFileAttributes(const char *filename, MagickStatStruct_t *statbuf);
 
 #define MagickMmap(address,length,protection,access,file,offset) \
   NTmmap(address,length,protection,access,file,offset)
diff -r 43a59a8ef281 magick/unix_port.c
--- a/magick/unix_port.c	Sun Feb 21 18:35:51 2016 -0600
+++ b/magick/unix_port.c	Wed Feb 24 11:24:02 2016 +0200
@@ -43,7 +43,8 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/wait.h>
-
+#include <sys/types.h>
+#include <utime.h>
 #include "magick/utility.h"
 
 /*
@@ -86,4 +87,26 @@
   return pagesize;
 }
 
+MagickExport int MagicGetFileAttributes(const char *filename, MagickStatStruct_t *statbuf)
+{
+  if (MagickStat(filename, statbuf) != 0)
+    return -1;
+  
+  return 0;
+}
+
+MagickExport int MagickSetFileAttributes(const char *filename, MagickStatStruct_t *statbuf)
+{
+  struct utimbuf
+    utbuf;
+  
+  utbuf.actime = statbuf->st_atime;
+  utbuf.modtime = statbuf->st_mtime;
+    
+  if (utime(filename, &utbuf) != 0)
+    return -1;
+    
+  return 0;
+}
+
 #endif /* defined(POSIX) */
diff -r 43a59a8ef281 magick/unix_port.h
--- a/magick/unix_port.h	Sun Feb 21 18:35:51 2016 -0600
+++ b/magick/unix_port.h	Wed Feb 24 11:24:02 2016 +0200
@@ -18,6 +18,12 @@
 extern MagickExport long
   MagickGetMMUPageSize(void);
 
+extern MagickExport int
+  MagicGetFileAttributes(const char *filename, struct stat *statbuf);
+  
+extern MagickExport int
+  MagickSetFileAttributes(const char *filename, struct stat *statbuf);
+
 /*
   Size type passed to read/write
 */

--------------050209000100040906050103
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
--------------050209000100040906050103
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Graphicsmagick-core mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/graphicsmagick-core

--------------050209000100040906050103--