Browse Source

Set timestamps for extracted files

Implements: enhancement #5
coverity_scan
Daniel Scharrer 13 years ago
parent
commit
05cac27c11
  1. 7
      CMakeLists.txt
  2. 69
      src/cli/main.cpp
  3. 1
      src/configure.hpp.in
  4. 67
      src/util/time.cpp
  5. 6
      src/util/time.hpp

7
CMakeLists.txt

@ -122,11 +122,16 @@ add_cxxflag("-fvisibility-inlines-hidden")
check_symbol_exists(isatty "unistd.h" INNOEXTRACT_HAVE_ISATTY)
check_symbol_exists(ioctl "sys/ioctl.h" INNOEXTRACT_HAVE_IOCTL)
check_symbol_exists(timegm "time.h" INNOEXTRACT_HAVE_TIMEGM)
check_symbol_exists(_mkgmtime "time.h" INNOEXTRACT_HAVE_MKGMTIME)
if(NOT INNOEXTRACT_HAVE_TIMEGM)
check_symbol_exists(_mkgmtime "time.h" INNOEXTRACT_HAVE_MKGMTIME)
endif()
check_symbol_exists(gmtime_r "time.h" INNOEXTRACT_HAVE_GMTIME_R)
if(NOT INNOEXTRACT_HAVE_GMTIME_R)
check_symbol_exists(_gmtime_s "time.h" INNOEXTRACT_HAVE_GMTIME_S)
endif()
if(NOT WIN32)
check_symbol_exists(utimes "sys/time.h" INNOEXTRACT_HAVE_UTIMES)
endif()
check_symbol_exists(bswap_16 "byteswap.h" INNOEXTRACT_HAVE_BSWAP_16)
check_symbol_exists(bswap_32 "byteswap.h" INNOEXTRACT_HAVE_BSWAP_32)

69
src/cli/main.cpp

@ -18,15 +18,15 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <algorithm>
#include <cctype>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <cctype>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
@ -59,6 +59,7 @@
#include "util/load.hpp"
#include "util/log.hpp"
#include "util/output.hpp"
#include "util/time.hpp"
using std::cout;
using std::string;
@ -125,6 +126,26 @@ struct options {
};
struct file_output {
fs::path name;
fs::ofstream stream;
file_output(const fs::path & file) : name(file) {
try {
fs::create_directories(name.parent_path());
} catch(...) {
throw std::runtime_error("error creating directories for \""
+ name.string() + '"');
}
stream.open(name);
if(!stream.is_open()) {
throw std::runtime_error("error opening output file \"" + name.string() + '"');
}
}
};
static void process_file(const fs::path & file, const options & o) {
fs::ifstream ifs(file, std::ios_base::in | std::ios_base::binary | std::ios_base::ate);
@ -305,21 +326,11 @@ static void process_file(const fs::path & file, const options & o) {
file_source = stream::file_reader::get(*chunk_source, file, &checksum);
// Open output files
boost::ptr_vector<fs::ofstream> output;
boost::ptr_vector<file_output> output;
if(!o.test) {
output.reserve(output_names.size());
BOOST_FOREACH(const file_t & path, output_names) {
try {
fs::create_directories(path.first.parent_path());
} catch(...) {
throw std::runtime_error("error creating directories for \""
+ path.first.string() + '"');
}
output.push_back(new fs::ofstream(path.first));
if(!output.back().is_open()) {
throw std::runtime_error("error opening output file \""
+ path.first.string() + '"');
}
output.push_back(new file_output(path.first));
}
}
@ -329,15 +340,31 @@ static void process_file(const fs::path & file, const options & o) {
std::streamsize buffer_size = std::streamsize(ARRAY_SIZE(buffer));
std::streamsize n = file_source->read(buffer, buffer_size).gcount();
if(n > 0) {
BOOST_FOREACH(fs::ofstream & ofs, output) {
ofs.write(buffer, n);
BOOST_FOREACH(file_output & out, output) {
out.stream.write(buffer, n);
if(out.stream.fail()) {
throw new std::runtime_error("error writing file \""
+ out.name.string() + '"');
}
}
extract_progress.update(uint64_t(n));
}
}
// Adjust file timestamps
const setup::data_entry & data = info.data_entries[location.second];
std::time_t filetime = data.timestamp;
//if(data.options & data.TimeStampInUTC) {
// filetime = util::to_local_time(filetime);
//}
BOOST_FOREACH(file_output & out, output) {
out.stream.close();
if(!util::set_file_time(out.name, filetime, data.timestamp_nsec)) {
log_warning << "error setting timestamp on file " << out.name;
}
}
// Verify checksums
if(checksum != file.checksum) {
log_warning << "checksum mismatch:\n"
<< "actual: " << checksum << '\n'

1
src/configure.hpp.in

@ -8,6 +8,7 @@
#cmakedefine01 INNOEXTRACT_HAVE_MKGMTIME
#cmakedefine01 INNOEXTRACT_HAVE_GMTIME_R
#cmakedefine01 INNOEXTRACT_HAVE_GMTIME_S
#cmakedefine01 INNOEXTRACT_HAVE_UTIMES
#cmakedefine01 INNOEXTRACT_HAVE_LZMA
#cmakedefine01 INNOEXTRACT_IS_BIG_ENDIAN
#cmakedefine01 INNOEXTRACT_HAVE_BSWAP_16

67
src/util/time.cpp

@ -31,6 +31,14 @@
#include <stdlib.h>
#endif
#if INNOEXTRACT_HAVE_UTIMES
#include <sys/time.h>
#elif defined(_WIN32)
#include <windows.h>
#else
#include <boost/filesystem/operations.hpp>
#endif
namespace util {
std::time_t parse_time(std::tm tm) {
@ -95,4 +103,63 @@ time_t to_local_time(time_t t) {
return std::mktime(&time);
}
#if defined(_WIN32)
static HANDLE open_file(LPCSTR name) {
return CreateFileA(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
}
static HANDLE open_file(LPCWSTR name) {
return CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
}
#endif
bool set_file_time(const boost::filesystem::path & path, std::time_t t, uint32_t nsec) {
#if INNOEXTRACT_HAVE_UTIMES
struct timeval times[2];
times[0].tv_sec = t;
times[0].tv_usec = long(nsec / 1000);
times[1] = times[0];
return (utimes(path.c_str(), times) == 0);
#elif defined(_WIN32)
// Prevent unused function warnings
(void)(HANDLE(*)(LPCSTR))open_file;
(void)(HANDLE(*)(LPCWSTR))open_file;
HANDLE handle = open_file(path.c_str());
if(handle == INVALID_HANDLE_VALUE) {
return false;
}
// Convert the std::time_t and nanoseconds to a FILETIME struct
static const int64_t FiletimeOffset = 0x19DB1DED53E8000ll;
int64_t time = int64_t(t) * 10000000 + int64_t(nsec) / 100;
time += FiletimeOffset;
FILETIME filetime;
filetime.dwLowDateTime = DWORD(time);
filetime.dwHighDateTime = DWORD(time >> 32);
bool ret = SetFileTime(handle, &filetime, &filetime, &filetime);
CloseHandle(handle);
return ret;
#else
try {
(void)nsec; // sub-second precision not supported by boost
boost::filesystem::last_write_time(path, t);
return true;
} catch(...) {
return false;
}
#endif
}
} // namespace util

6
src/util/time.hpp

@ -21,8 +21,11 @@
#ifndef INNOEXTRACT_UTIL_TIME_HPP
#define INNOEXTRACT_UTIL_TIME_HPP
#include <stdint.h>
#include <ctime>
#include <boost/filesystem/path.hpp>
namespace util {
/*!
@ -43,6 +46,9 @@ std::tm format_time(std::time_t t);
*/
std::time_t to_local_time(std::time_t t);
//! Set a file's creation/modification time
bool set_file_time(const boost::filesystem::path & path, std::time_t t, uint32_t nsec);
} // namespace util
#endif // INNOEXTRACT_UTIL_TIME_HPP

Loading…
Cancel
Save