pax: update date parsing code (from OpenBSD)

Sponsored by:	Klara, Inc.
MFC after:	1 week
This commit is contained in:
Dag-Erling Smørgrav 2022-10-19 17:02:45 +00:00
parent 555a861d68
commit d05e43bc0d
3 changed files with 78 additions and 65 deletions

View file

@ -33,7 +33,7 @@
.\" @(#)pax.1 8.4 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd December 29, 2018
.Dd October 19, 2022
.Dt PAX 1
.Os
.Sh NAME
@ -933,28 +933,31 @@ changed during a specified time range will be archived).
A time range is made up of six different fields and each field must contain two
digits.
The format is:
.Dl [yy[mm[dd[hh]]]]mm[.ss]
.Pp
.Dl [[[[[cc]yy]mm]dd]HH]MM[.SS]
.Pp
Where
.Cm yy
.Ar cc
is the first two digits of the year (the century),
.Ar yy
is the last two digits of the year,
the first
.Cm mm
.Ar mm
is the month (from 01 to 12),
.Cm dd
.Ar dd
is the day of the month (from 01 to 31),
.Cm hh
.Ar HH
is the hour of the day (from 00 to 23),
the second
.Cm mm
.Ar MM
is the minute (from 00 to 59),
and
.Cm ss
.Ar SS
is the seconds (from 00 to 59).
The minute field
.Cm mm
.Ar MM
is required, while the other fields are optional and must be added in the
following order:
.Dl Cm hh , dd , mm , yy .
.Ar HH , dd , mm , yy , cc .
The
.Cm ss
field may be added independently of the other fields.

View file

@ -44,17 +44,20 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <pwd.h>
#include <ctype.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include "pax.h"
#include "sel_subs.h"
#include "extern.h"
static int str_sec(char *, time_t *);
static int str_sec(const char *, time_t *);
static int usr_match(ARCHD *);
static int grp_match(ARCHD *);
static int trng_match(ARCHD *);
@ -309,7 +312,7 @@ grp_match(ARCHD *arcn)
* trng_add()
* add a time range match to the time range list.
* This is a non-standard pax option. Lower and upper ranges are in the
* format: [yy[mm[dd[hh]]]]mm[.ss] and are comma separated.
* format: [[[[[cc]yy]mm]dd]HH]MM[.SS] and are comma separated.
* Time ranges are based on current time, so 1234 would specify a time of
* 12:34 today.
* Return:
@ -446,7 +449,7 @@ trng_add(char *str)
return(0);
out:
paxwarn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]");
paxwarn(1, "Time range format is: [[[[[cc]yy]mm]dd]HH]MM[.SS][/[c][m]]");
return(-1);
}
@ -520,80 +523,87 @@ trng_match(ARCHD *arcn)
/*
* str_sec()
* Convert a time string in the format of [[[[yy[mm[dd[hh]mm[.ss] to gmt
* seconds. Tval already has current time loaded into it at entry.
* Convert a time string in the format of [[[[[cc]yy]mm]dd]HH]MM[.SS] to
* seconds UTC. Tval already has current time loaded into it at entry.
* Return:
* 0 if converted ok, -1 otherwise
*/
static int
str_sec(char *str, time_t *tval)
str_sec(const char *p, time_t *tval)
{
struct tm *lt;
char *dot = NULL;
const char *dot, *t;
size_t len;
int bigyear;
int yearset;
yearset = 0;
len = strlen(p);
for (t = p, dot = NULL; *t; ++t) {
if (isdigit((unsigned char)*t))
continue;
if (*t == '.' && dot == NULL) {
dot = t;
continue;
}
return(-1);
}
lt = localtime(tval);
if ((dot = strchr(str, '.')) != NULL) {
/*
* seconds (.ss)
*/
*dot++ = '\0';
if (strlen(dot) != 2)
if (dot != NULL) { /* .SS */
if (strlen(++dot) != 2)
return(-1);
if ((lt->tm_sec = ATOI2(dot)) > 61)
lt->tm_sec = ATOI2(dot);
if (lt->tm_sec > 61)
return(-1);
len -= 3;
} else
lt->tm_sec = 0;
switch (strlen(str)) {
case 10:
/*
* year (yy)
* watch out for year 2000
*/
if ((lt->tm_year = ATOI2(str)) < 69)
lt->tm_year += 100;
str += 2;
switch (len) {
case 12: /* cc */
bigyear = ATOI2(p);
lt->tm_year = (bigyear * 100) - 1900;
yearset = 1;
/* FALLTHROUGH */
case 8:
/*
* month (mm)
* watch out months are from 0 - 11 internally
*/
if ((lt->tm_mon = ATOI2(str)) > 12)
case 10: /* yy */
if (yearset) {
lt->tm_year += ATOI2(p);
} else {
lt->tm_year = ATOI2(p);
if (lt->tm_year < 69) /* hack for 2000 ;-} */
lt->tm_year += (2000 - 1900);
}
/* FALLTHROUGH */
case 8: /* mm */
lt->tm_mon = ATOI2(p);
if ((lt->tm_mon > 12) || !lt->tm_mon)
return(-1);
--lt->tm_mon;
str += 2;
--lt->tm_mon; /* time struct is 0 - 11 */
/* FALLTHROUGH */
case 6:
/*
* day (dd)
*/
if ((lt->tm_mday = ATOI2(str)) > 31)
case 6: /* dd */
lt->tm_mday = ATOI2(p);
if ((lt->tm_mday > 31) || !lt->tm_mday)
return(-1);
str += 2;
/* FALLTHROUGH */
case 4:
/*
* hour (hh)
*/
if ((lt->tm_hour = ATOI2(str)) > 23)
case 4: /* HH */
lt->tm_hour = ATOI2(p);
if (lt->tm_hour > 23)
return(-1);
str += 2;
/* FALLTHROUGH */
case 2:
/*
* minute (mm)
*/
if ((lt->tm_min = ATOI2(str)) > 59)
case 2: /* MM */
lt->tm_min = ATOI2(p);
if (lt->tm_min > 59)
return(-1);
break;
default:
return(-1);
}
/*
* convert broken-down time to GMT clock time seconds
*/
/* convert broken-down time to UTC clock time seconds */
if ((*tval = mktime(lt)) == -1)
return(-1);
return(0);

View file

@ -57,7 +57,7 @@ typedef struct grpt {
* data structure for storing user supplied time ranges (-T option)
*/
#define ATOI2(s) ((((s)[0] - '0') * 10) + ((s)[1] - '0'))
#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
typedef struct time_rng {
time_t low_time; /* lower inclusive time limit */