Support setting last modification time for file in archive.
diff --git a/NEWS b/NEWS
index 23c4ab2..d3ea626 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+X.XX.X [XXXX/XX/XX]
+
+* Support setting last modification time for file.
+
 0.11.2 [2013/12/19]
 
 * Support querying/setting operating system and external attributes.
diff --git a/TODO b/TODO
index 66bd0d4..1892ff6 100644
--- a/TODO
+++ b/TODO
@@ -36,7 +36,6 @@
 * I/O methods
 * support streaming output (creating new archive to e.g. stdout)
 * add functions to:
-  . set last modification time for entry
   . read/set ASCII file flag? (wiz: more general options?)
 * zip_commit (to finish changes without closing archive)
 * add custom compression function support
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 358e212..b145230 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -83,6 +83,7 @@
   zip_file_replace.c
   zip_file_set_comment.c
   zip_file_set_external_attributes.c
+  zip_file_set_mtime.c
   zip_file_strerror.c
   zip_filerange_crc.c
   zip_fopen.c
diff --git a/lib/Makefile.am b/lib/Makefile.am
index a74f409..c258f0c 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -41,6 +41,7 @@
 	zip_file_replace.c \
 	zip_file_set_comment.c \
 	zip_file_set_external_attributes.c \
+	zip_file_set_mtime.c \
 	zip_file_strerror.c \
 	zip_filerange_crc.c \
 	zip_fopen.c \
diff --git a/lib/zip.h b/lib/zip.h
index ba38ac8..644af2f 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -285,6 +285,7 @@
 ZIP_EXTERN int zip_file_replace(struct zip *, zip_uint64_t, struct zip_source *, zip_flags_t);
 ZIP_EXTERN int zip_file_set_comment(struct zip *, zip_uint64_t, const char *, zip_uint16_t, zip_flags_t);
 ZIP_EXTERN int zip_file_set_external_attributes(struct zip *, zip_uint64_t, zip_flags_t, zip_uint8_t, zip_uint32_t);
+ZIP_EXTERN int zip_file_set_mtime(struct zip *, zip_uint64_t, time_t, zip_flags_t);
 ZIP_EXTERN const char *zip_file_strerror(struct zip_file *);
 ZIP_EXTERN struct zip_file *zip_fopen(struct zip *, const char *, zip_flags_t);
 ZIP_EXTERN struct zip_file *zip_fopen_encrypted(struct zip *, const char *, zip_flags_t, const char *);
diff --git a/lib/zip_close.c b/lib/zip_close.c
index 577e921..84ff9f9 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -423,10 +423,12 @@
 	return -1;
     }
 
-    if (st.valid & ZIP_STAT_MTIME)
-	de->last_mod = st.mtime;
-    else
-	time(&de->last_mod);
+    if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {
+        if (st.valid & ZIP_STAT_MTIME)
+            de->last_mod = st.mtime;
+        else
+            time(&de->last_mod);
+    }
     de->comp_method = st.comp_method;
     de->crc = st.crc;
     de->uncomp_size = st.size;
diff --git a/lib/zip_file_set_mtime.c b/lib/zip_file_set_mtime.c
new file mode 100644
index 0000000..f5ea0e8
--- /dev/null
+++ b/lib/zip_file_set_mtime.c
@@ -0,0 +1,74 @@
+/*
+ zip_file_set_mtime.c -- set modification time of entry.
+ Copyright (C) 2014 Dieter Baron and Thomas Klausner
+ 
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+ 
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "zipint.h"
+
+ZIP_EXTERN int zip_file_set_mtime(struct zip *za, zip_uint64_t idx, time_t mtime, zip_flags_t flags)
+{
+    struct zip_entry *e;
+    int changed;
+    
+    if (_zip_get_dirent(za, idx, 0, NULL) == NULL)
+        return -1;
+    
+    if (ZIP_IS_RDONLY(za)) {
+        _zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
+        return -1;
+    }
+    
+    e = za->entry+idx;
+
+    changed = mtime != e->orig->last_mod;
+    
+    if (changed) {
+        if (e->changes == NULL) {
+            if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) {
+                _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+                return -1;
+            }
+        }
+        e->changes->last_mod = mtime;
+        e->changes->changed |= ZIP_DIRENT_LAST_MOD;
+    }
+    else {
+        if (e->changes) {
+            e->changes->changed &= ~ZIP_DIRENT_LAST_MOD;
+            if (e->changes->changed == 0) {
+		_zip_dirent_free(e->changes);
+                e->changes = NULL;
+            }
+        }
+    }
+    
+    return 0;
+}
diff --git a/lib/zipint.h b/lib/zipint.h
index 7b7220c..e4cb066 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -307,6 +307,7 @@
 #define ZIP_DIRENT_COMMENT	0x0004u
 #define ZIP_DIRENT_EXTRA_FIELD	0x0008u
 #define ZIP_DIRENT_ATTRIBUTES	0x0010u
+#define ZIP_DIRENT_LAST_MOD	0x0020u
 #define ZIP_DIRENT_ALL		0xffffu
 
 struct zip_dirent {
diff --git a/man/Makefile.am b/man/Makefile.am
index f2c4c99..4541545 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -30,6 +30,7 @@
 	zip_file_rename.mdoc \
 	zip_file_set_comment.mdoc \
 	zip_file_set_external_attributes.mdoc \
+	zip_file_set_mtime.mdoc \
 	zip_file_strerror.mdoc \
 	zip_fopen.mdoc \
 	zip_fopen_encrypted.mdoc \
diff --git a/man/zip_file_set_mtime.man b/man/zip_file_set_mtime.man
new file mode 100644
index 0000000..b821bf0
--- /dev/null
+++ b/man/zip_file_set_mtime.man
@@ -0,0 +1,55 @@
+.TH "ZIP_FILE_SET_MTIME" "3" "August 5, 2014" "NiH" "Library Functions Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBzip_file_set_mtime\fR
+\- set last modification time (mtime) for file in zip
+.SH "LIBRARY"
+libzip (-lzip)
+.SH "SYNOPSIS"
+\fB#include <zip.h>\fR
+.sp
+\fIint\fR
+.PD 0
+.HP 4n
+\fBzip_set_file_mtime\fR(\fIstruct\ zip\ *archive\fR, \fIzip_uint64_t\ index\fR, \fItime_t\ mtime\fR, \fIzip_flags_t\ flags\fR);
+.PD
+.SH "DESCRIPTION"
+The
+\fBzip_file_set_mtime\fR()
+function sets the last modification time (mtime) for the file at
+position
+\fIindex\fR
+in the zip archive to
+\fImtime\fR.
+Currently, no support for any
+\fIflags\fR
+is implemented.
+.SH "RETURN VALUES"
+Upon successful completion 0 is returned.
+Otherwise, \-1 is returned and the error information in
+\fIarchive\fR
+is set to indicate the error.
+.SH "ERRORS"
+\fBzip_file_set_mtime\fR()
+fails if:
+.TP 19n
+[\fRZIP_ER_INVAL\fR]
+\fIindex\fR
+is not a valid file index in
+\fIarchive\fR.
+.TP 19n
+[\fRZIP_ER_MEMORY\fR]
+Required memory could not be allocated.
+.TP 19n
+[\fRZIP_ER_RDONLY\fR]
+The
+\fIarchive\fR
+was opened in read-only mode.
+.SH "SEE ALSO"
+libzip(3),
+zip_stat(3)
+.SH "AUTHORS"
+Dieter Baron <\fIdillo@nih.at\fR>
+and
+Thomas Klausner <\fItk@giga.or.at\fR>
diff --git a/man/zip_file_set_mtime.mdoc b/man/zip_file_set_mtime.mdoc
new file mode 100644
index 0000000..ac435eb
--- /dev/null
+++ b/man/zip_file_set_mtime.mdoc
@@ -0,0 +1,83 @@
+.\" zip_file_set_mtime.mdoc -- set mtime for file in zip
+.\" Copyright (C) 2014 Dieter Baron and Thomas Klausner
+.\"
+.\" This file is part of libzip, a library to manipulate ZIP files.
+.\" The authors can be contacted at <libzip@nih.at>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. The names of the authors may not be used to endorse or promote
+.\"    products derived from this software without specific prior
+.\"    written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 5, 2014
+.Dt ZIP_FILE_SET_MTIME 3
+.Os
+.Sh NAME
+.Nm zip_file_set_mtime
+.Nd set last modification time (mtime) for file in zip
+.Sh LIBRARY
+libzip (-lzip)
+.Sh SYNOPSIS
+.In zip.h
+.Ft int
+.Fn zip_set_file_mtime "struct zip *archive" "zip_uint64_t index" \
+"time_t mtime" "zip_flags_t flags"
+.Sh DESCRIPTION
+The
+.Fn zip_file_set_mtime
+function sets the last modification time (mtime) for the file at
+position
+.Ar index
+in the zip archive to
+.Ar mtime .
+Currently, no support for any
+.Ar flags
+is implemented.
+.Sh RETURN VALUES
+Upon successful completion 0 is returned.
+Otherwise, \-1 is returned and the error information in
+.Ar archive
+is set to indicate the error.
+.Sh ERRORS
+.Fn zip_file_set_mtime
+fails if:
+.Bl -tag -width Er
+.It Bq Er ZIP_ER_INVAL
+.Ar index
+is not a valid file index in
+.Ar archive .
+.It Bq Er ZIP_ER_MEMORY
+Required memory could not be allocated.
+.It Bq Er ZIP_ER_RDONLY
+The
+.Ar archive
+was opened in read-only mode.
+.El
+.Sh SEE ALSO
+.Xr libzip 3 ,
+.Xr zip_stat 3
+.Sh AUTHORS
+.An -nosplit
+.An Dieter Baron Aq Mt dillo@nih.at
+and
+.An Thomas Klausner Aq Mt tk@giga.or.at
diff --git a/regress/Makefile.am b/regress/Makefile.am
index 70da41c..671a258 100644
--- a/regress/Makefile.am
+++ b/regress/Makefile.am
@@ -96,6 +96,7 @@
 	testfile-cp437.zip \
 	testfile-plus-extra.zip \
 	testfile-UTF8.zip \
+	testfile2014.zip \
 	testnottorrent.zip \
 	teststdin.zip \
 	teststored.zip \
diff --git a/regress/modify.c b/regress/modify.c
index b98f319..5d6e5ff 100644
--- a/regress/modify.c
+++ b/regress/modify.c
@@ -73,6 +73,7 @@
     "\tset_extra index extra_id extra_index flags value\n"
     "\tset_file_comment index comment\n"
     "\tset_file_compression index method flags\n"
+    "\tset_file_mtime index timestamp\n"
     "\tzin_close\n"
     "\nThe index is zero-based.\n";
 
@@ -423,6 +424,18 @@
 		break;
             }
             arg += 4;
+	} else if (strcmp(argv[arg], "set_mtime") == 0 && arg+2 < argc) {
+	    /* set file last modification time (mtime) */
+	    time_t mtime;
+	    idx = atoi(argv[arg+1]);
+	    /* TODO: add configure check for strtoll or similar, and use it */
+	    mtime = atoi(argv[arg+2]);
+	    if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
+		fprintf(stderr, "can't set file mtime at index '%d' to `%ld': %s\n", idx, mtime, zip_strerror(za));
+		err = 1;
+		break;
+	    }
+	    arg += 3;
         } else if (strcmp(argv[arg], "zin_close") == 0) {
 	    if (zip_close(z_in) < 0) {
 		fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in));
diff --git a/regress/set_mtime.test b/regress/set_mtime.test
new file mode 100644
index 0000000..d88195a
--- /dev/null
+++ b/regress/set_mtime.test
@@ -0,0 +1,5 @@
+# change mtime in a zip archive
+program modify
+return 0
+args testfile set_mtime 0 1407272201
+file testfile testfile.zip testfile2014.zip
diff --git a/regress/testfile2014.zip b/regress/testfile2014.zip
new file mode 100644
index 0000000..1d91853
--- /dev/null
+++ b/regress/testfile2014.zip
Binary files differ