mirror of https://github.com/acidanthera/audk.git
476 lines
10 KiB
C
476 lines
10 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2004, 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
|
||
|
|
||
|
void
|
||
|
PrintUsage (
|
||
|
void
|
||
|
)
|
||
|
/*++
|
||
|
Routine Description:
|
||
|
print usage of setstamp command
|
||
|
|
||
|
Arguments:
|
||
|
void
|
||
|
|
||
|
Returns:
|
||
|
None
|
||
|
--*/
|
||
|
{
|
||
|
//
|
||
|
// print usage of command
|
||
|
//
|
||
|
printf ("Usage: 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, <ime, 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, <ime, 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, <ime, 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, <ime, 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, <ime, 4) != 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
main (
|
||
|
int argc,
|
||
|
char *argv[]
|
||
|
)
|
||
|
{
|
||
|
FILE *fp;
|
||
|
time_t ltime;
|
||
|
|
||
|
//
|
||
|
// check the number of parameters
|
||
|
//
|
||
|
if (argc != 3) {
|
||
|
PrintUsage ();
|
||
|
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, <ime) != 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 (<ime));
|
||
|
|
||
|
//
|
||
|
// close the PE file
|
||
|
//
|
||
|
fclose (fp);
|
||
|
|
||
|
return 0;
|
||
|
}
|