blob: 51f5155ab885271e15d414907b7866e214ba9289 [file] [log] [blame]
/*++
Copyright (c) 2004 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
SetStamp.c
Abstract:
Set Date/Time Stamp of Portable Executable (PE) format file
--*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#define LINE_MAXLEN 80
//
// Utility Name
//
#define UTILITY_NAME "SetStamp"
//
// Utility version information
//
#define UTILITY_MAJOR_VERSION 0
#define UTILITY_MINOR_VERSION 1
void
Version (
void
)
/*++
Routine Description:
Displays the standard utility information to SDTOUT
Arguments:
None
Returns:
None
--*/
{
printf ("%s v%d.%d -Utility to set Date/Time Stamp for Portable Executable (PE) format file.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");
}
void
Usage (
void
)
/*++
Routine Description:
print usage of setstamp command
Arguments:
void
Returns:
None
--*/
{
Version();
//
// print usage of command
//
printf ("\nUsage: SetStamp <PE-File> <TIME-File>\n");
}
int
GetDateTime (
FILE *fp,
time_t *ltime
)
/*++
Routine Description:
Read the date and time from TIME file. If the date/time string is
"NOW NOW", write the current date and time to TIME file and set it to
ltime. Else, set the date and time of TIME file to ltime.
Arguments:
fp - The pointer of TIME file
ltime - Date and time
Returns:
= 0 - Success
= -1 - Failed
--*/
{
char buffer[LINE_MAXLEN];
struct tm stime;
struct tm *now;
if (fgets (buffer, LINE_MAXLEN, fp) == NULL) {
printf ("Error: Cannot read TIME file.\n");
return -1;
}
//
// compare the value with "NOW NOW", write TIME file if equal
//
if (strncmp (buffer, "NOW NOW", 7) == 0) {
//
// get system current time and date
//
time (ltime);
now = localtime (ltime);
if (now == NULL) {
printf ("Error: Cannot get local time.\n");
return -1;
}
if (strftime (buffer, LINE_MAXLEN, "%Y-%m-%d %H:%M:%S", now) == 0) {
printf ("Error: Cannot format time string.\n");
return -1;
}
//
// write TIME file
//
if (fseek (fp, 0, SEEK_SET) != 0) {
printf ("Error: Cannot move location of TIME file.\n");
return -1;
}
if (fputs (buffer, fp) == EOF) {
printf ("Error: Cannot write time string to TIME file.\n");
return -1;
}
//
// ltime has been set as current time and date, return
//
return 0;
}
//
// get the date and time from buffer
//
if (6 != sscanf (
buffer,
"%d-%d-%d %d:%d:%d",
&stime.tm_year,
&stime.tm_mon,
&stime.tm_mday,
&stime.tm_hour,
&stime.tm_min,
&stime.tm_sec
)) {
printf ("Error: Invaild date or time!\n");
return -1;
}
//
// in struct, Month (0 - 11; Jan = 0). So decrease 1 from it
//
stime.tm_mon -= 1;
//
// in struct, Year (current year minus 1900)
// and only the dates can be handled from Jan 1, 1970 to Jan 18, 2038
//
//
// convert 0 -> 100 (2000), 1 -> 101 (2001), ..., 38 -> 138 (2038)
//
if (stime.tm_year <= 38) {
stime.tm_year += 100;
}
//
// convert 1970 -> 70, 2000 -> 100, ...
//
else if (stime.tm_year >= 1970) {
stime.tm_year -= 1900;
}
//
// convert the date and time to time_t format
//
*ltime = mktime (&stime);
if (*ltime == (time_t) - 1) {
printf ("Error: Invalid date or time!\n");
return -1;
}
return 0;
}
int
ReadFromFile (
FILE *fp,
long offset,
void *buffer,
int size
)
/*++
Routine Description:
read data from a specified location of file
Arguments:
fp - file pointer
offset - number of bytes from beginning of file
buffer - buffer used to store data
size - size of buffer
Returns:
= 0 - Success
= -1 - Failed
--*/
{
//
// set file pointer to the specified location of file
//
if (fseek (fp, offset, SEEK_SET) != 0) {
printf ("Error: Cannot move the current location of the file.\n");
return -1;
}
//
// read data from the file
//
if (fread (buffer, size, 1, fp) != 1) {
printf ("Error: Cannot read data from the file.\n");
return -1;
}
return 0;
}
int
WriteToFile (
FILE *fp,
long offset,
void *buffer,
int size
)
/*++
Routine Description:
write data to a specified location of file
Arguments:
fp - file pointer
offset - number of bytes from beginning of file
buffer - buffer used to store data
size - size of buffer
Returns:
= 0 - Success
= -1 - Failed
--*/
{
//
// set file pointer to the specified location of file
//
if (fseek (fp, offset, SEEK_SET) != 0) {
printf ("Error: Cannot move the current location of the file.\n");
return -1;
}
//
// write data to the file
//
if (fwrite (buffer, size, 1, fp) != 1) {
perror ("Error: Cannot write data to the file.\n");
return -1;
}
return 0;
}
int
SetStamp (
FILE *fp,
time_t ltime
)
/*++
Routine Description:
set Date/Time Stamp of the file
Arguments:
fp - file pointer
ltime - time and date
Returns:
= 0 - Success
= -1 - Failed
--*/
{
unsigned char header[4];
unsigned long offset;
unsigned long NumberOfRvaAndSizes;
unsigned int nvalue;
unsigned long lvalue;
//
// read the header of file
//
if (ReadFromFile (fp, 0, header, 2) != 0) {
return -1;
}
//
// "MZ" -- the header of image file (PE)
//
if (strncmp ((char *) header, "MZ", 2) != 0) {
printf ("Error: Invalid Image file.\n");
return -1;
}
//
// At location 0x3C, the stub has the file offset to the
// PE signature.
//
if (ReadFromFile (fp, 0x3C, &offset, 4) != 0) {
return -1;
}
//
// read the header of optional
//
if (ReadFromFile (fp, offset, header, 4) != 0) {
return -1;
}
//
// "PE\0\0" -- the signature of optional header
//
if (strncmp ((char *) header, "PE\0\0", 4) != 0) {
printf ("Error: Invalid PE format file.\n");
return -1;
}
//
// Add 8 to skip PE signature (4-byte), Machine (2-byte) and
// NumberOfSection (2-byte)
//
offset += 8;
if (WriteToFile (fp, offset, &ltime, 4) != 0) {
return -1;
}
//
// Add 16 to skip COFF file header, and get to optional header.
//
offset += 16;
//
// Check the magic field, 0x10B for PE32 and 0x20B for PE32+
//
if (ReadFromFile (fp, offset, &nvalue, 2) != 0) {
return -1;
}
//
// If this is PE32 image file, offset of NumberOfRvaAndSizes is 92.
// Else it is 108.
//
switch (nvalue & 0xFFFF) {
case 0x10B:
offset += 92;
break;
case 0x20B:
offset += 108;
break;
default:
printf ("Error: Sorry! The Magic value is unknown.\n");
return -1;
}
//
// get the value of NumberOfRvaAndSizes
//
if (ReadFromFile (fp, offset, &NumberOfRvaAndSizes, 4) != 0) {
return -1;
}
//
// Date/time stamp exists in Export Table, Import Table, Resource Table,
// Debug Table and Delay Import Table. And in Import Table and Delay Import
// Table, it will be set when bound. So here only set the date/time stamp
// of Export Table, Resource Table and Debug Table.
//
//
// change date/time stamp of Export Table, the offset of Export Table
// is 4 + 0 * 8 = 4. And the offset of stamp is 4.
//
if (NumberOfRvaAndSizes >= 1) {
if (ReadFromFile (fp, offset + 4, &lvalue, 4) != 0) {
return -1;
}
if (lvalue != 0) {
if (WriteToFile (fp, lvalue + 4, &ltime, 4) != 0) {
return -1;
}
}
}
//
// change date/time stamp of Resource Table, the offset of Resource Table
// is 4 + 2 * 8 = 20. And the offset of stamp is 4.
//
if (NumberOfRvaAndSizes >= 3) {
if (ReadFromFile (fp, offset + 20, &lvalue, 4) != 0) {
return -1;
}
if (lvalue != 0) {
if (WriteToFile (fp, lvalue + 4, &ltime, 4) != 0) {
return -1;
}
}
}
//
// change date/time stamp of Debug Table, offset of Debug Table
// is 4 + 6 * 8 = 52. And the offset of stamp is 4.
//
if (NumberOfRvaAndSizes >= 7) {
if (ReadFromFile (fp, offset + 52, &lvalue, 4) != 0) {
return -1;
}
if (lvalue != 0) {
if (WriteToFile (fp, lvalue + 4, &ltime, 4) != 0) {
return -1;
}
}
//
// change the date/time stamp of Debug Data
//
if (ReadFromFile (fp, lvalue + 24, &lvalue, 4) != 0) {
return -1;
}
//
// get the signature of debug data
//
if (ReadFromFile (fp, lvalue, header, 2) != 0) {
return -1;
}
//
// "NB" - the signature of Debug Data
// Need Review: (From Spec. is "NB05", From .dll is "NB10")
//
if (strncmp ((char *) header, "NB", 2) == 0) {
if (WriteToFile (fp, lvalue + 8, &ltime, 4) != 0) {
return -1;
}
}
}
return 0;
}
int
main (
int argc,
char *argv[]
)
{
FILE *fp;
time_t ltime;
if (argc == 1) {
Usage();
return -1;
}
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||
(strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {
Usage();
return -1;
}
if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {
Version();
return -1;
}
//
// check the number of parameters
//
if (argc != 3) {
Usage ();
return -1;
}
//
// open the TIME file, if not exists, return
//
fp = fopen (argv[2], "r+");
if (fp == NULL) {
return 0;
}
//
// get time and date from file
//
if (GetDateTime (fp, &ltime) != 0) {
fclose (fp);
return -1;
}
//
// close the TIME file
//
fclose (fp);
//
// open the PE file
//
fp = fopen (argv[1], "r+b");
if (fp == NULL) {
printf ("Error: Cannot open the PE file!\n");
return -1;
}
//
// set time and date stamp to the PE file
//
if (SetStamp (fp, ltime) != 0) {
fclose (fp);
return -1;
}
printf ("Set Date/Time Stamp to %s", ctime (&ltime));
//
// close the PE file
//
fclose (fp);
return 0;
}