[comp.sources.misc] Program to set file access and modification times.

allbery@ncoast.UUCP (07/09/87)

I wrote this one day trying to solve the problem of the file modification
dates of restored files.  Someone in comp.unix.questions wanted something
like this, so here it is.

Bugs - doesn't know about DST, and barely knows how to get the hours
in the first place.  No manual page, this program works kind of like the
settime command that I remember from Version 7 days.  Also, the inode
changed time will always be set to the time you changed the file times.

Enjoy!

John.		(jfh@killer.UUCP)
------------------------  cut somewheres near here ----------------------

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

/*
 * settime - change the access and modification dates of files
 *
 *	This is mine.  You steal, and you die.  Ha, Ha.
 */

static	char	sccsid[] = "@(#)settime.c	1.0	John F. Haugh	08/05/86";

#define	SECPERMIN	60
#define	MINPERHR	60
#define	HRPERDAY	24
#define	SECPERHR	(MINPERHR*SECPERMIN)
#define	SECPERDAY	(HRPERDAY*MINPERHR*SECPERMIN)
#define	YEAR(y)		(y & 03 ? 365:366)
#define	MONTH(m,y)	(m != 2  ? months[(m - 1)]:(y & 03 ? 28:29))

extern	long	timezone;

int	months[12] = {
	31, 28, 31, 30,
	31, 30, 31, 31,
	30, 31, 30, 31
};

conversion ()
{
	fprintf (stderr, "settime: conversion error\n");
	exit (1);
}

usage ()
{
	fprintf (stderr, "usage: settime [ mmddHHMMyy | -f file ] name ...\n");
	exit (1);
}

twodigits (s)
char	*s;
{
	if (s[0] == 0 || s[1] == 0) {
		fprintf (stderr, "settime: bad date string\n");
		exit (1);
	}
	return ((s[0] - '0') * 10 + s[1] - '0');
}

month (m, y)
int	m,
	y;
{
	int	i;
	int	days = 0;

	for (i = 1; i < m;i++)
		days += MONTH (i, y);

	return (SECPERDAY * days);
}

year (y)
int	y;
{
	int	i;
	int	days = 0;

	for (i = 70;i < y;i++)
		days += YEAR (i);

	return (days * SECPERDAY);
}

time_t	date (ds)
char	*ds;
{
	time_t	seconds = 0;
	int	len;
	int	mm,
		dd,
		HH,
		MM,
		yy;

	len = strlen (ds);
	if (len & 01) {
		mm = ds[0] - '0';	
		ds++;
	}
	else {
		mm = twodigits (ds);
		ds += 2;
	}
	dd = twodigits (ds);
	ds += 2;
	HH = twodigits (ds);
	ds += 2;
	MM = twodigits (ds);
	ds += 2;
	yy = twodigits (ds);
	if (MM > 59)
		conversion ();
	if (mm > 12 || mm == 0)
		conversion ();
	if (HH > 23)
		 conversion ();
	if (yy < 70)
		conversion ();
	if (dd > MONTH (mm, yy) || dd == 0)
		conversion ();
	seconds = year (yy) + month (mm, yy) + (SECPERDAY * (dd - 1)) + (SECPERHR * HH) + (SECPERMIN * MM) + timezone;
	return (seconds);
}

main (argc, argv)
int	argc;
char	**argv;
{
	struct	utimbuf {
		time_t	actime;
		time_t	modtime;
	} utimbuf;
	struct	stat	statbuf;
	int	i;

	if (argc < 3)
		usage ();

	tzset ();
	if (argv[1][0] == '-') {
		if (argv[1][1] != 'f')
			usage ();
		if (stat (argv[2], &statbuf) != 0) {
			perror (argv[2]);
			exit (2);
		}
		utimbuf.actime = statbuf.st_atime;
		utimbuf.modtime = statbuf.st_mtime;
		i = 3;
	}
	else {
		utimbuf.actime = utimbuf.modtime = date (argv[1]);
		i = 2;
	}
	for (;argv[i] != (char *) 0;i++)
		if (utime (argv[i], &utimbuf) != 0)
			perror (argv[i]);
}