xref: /illumos-gate/usr/src/uts/common/fs/pcfs/pc_subr.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1989, 1998 by Sun Microsystems, Inc.
3*7c478bd9Sstevel@tonic-gate  * All rights reserved.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*
7*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
8*7c478bd9Sstevel@tonic-gate  * All rights reserved. The Berkeley software License Agreement
9*7c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
10*7c478bd9Sstevel@tonic-gate  */
11*7c478bd9Sstevel@tonic-gate 
12*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
13*7c478bd9Sstevel@tonic-gate 
14*7c478bd9Sstevel@tonic-gate #ifndef KERNEL
15*7c478bd9Sstevel@tonic-gate #define	KERNEL
16*7c478bd9Sstevel@tonic-gate #endif
17*7c478bd9Sstevel@tonic-gate 
18*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
19*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
20*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
21*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
22*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
23*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
24*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
25*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
26*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
27*7c478bd9Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
28*7c478bd9Sstevel@tonic-gate #include <sys/fs/pc_label.h>
29*7c478bd9Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/fs/pc_node.h>
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate  * Structure returned by gmtime and localtime calls (see ctime(3)).
34*7c478bd9Sstevel@tonic-gate  */
35*7c478bd9Sstevel@tonic-gate struct tm {
36*7c478bd9Sstevel@tonic-gate 	short	tm_sec;
37*7c478bd9Sstevel@tonic-gate 	short	tm_min;
38*7c478bd9Sstevel@tonic-gate 	short	tm_hour;
39*7c478bd9Sstevel@tonic-gate 	short	tm_mday;
40*7c478bd9Sstevel@tonic-gate 	short	tm_mon;
41*7c478bd9Sstevel@tonic-gate 	short	tm_year;
42*7c478bd9Sstevel@tonic-gate 	short	tm_wday;
43*7c478bd9Sstevel@tonic-gate 	short	tm_yday;
44*7c478bd9Sstevel@tonic-gate 	short	tm_isdst;
45*7c478bd9Sstevel@tonic-gate };
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate void pc_tvtopct(timestruc_t *, struct pctime *);
48*7c478bd9Sstevel@tonic-gate void pc_pcttotv(struct pctime *, timestruc_t *);
49*7c478bd9Sstevel@tonic-gate int pc_validchar(char);
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate static struct tm *localtime(time_t *tim);
52*7c478bd9Sstevel@tonic-gate static int sunday(struct tm *, int);
53*7c478bd9Sstevel@tonic-gate static int dysize(int);
54*7c478bd9Sstevel@tonic-gate static struct tm *gmtime(int);
55*7c478bd9Sstevel@tonic-gate static time_t ctime(struct tm *);
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /* The cm struct defines tm_year relative to 1900 */
58*7c478bd9Sstevel@tonic-gate #define	YEAR_ZERO	1900
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /*
61*7c478bd9Sstevel@tonic-gate  * convert timestruct to pctime
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate void
64*7c478bd9Sstevel@tonic-gate pc_tvtopct(
65*7c478bd9Sstevel@tonic-gate 	timestruc_t	*tvp,			/* time input */
66*7c478bd9Sstevel@tonic-gate 	struct pctime *pctp)		/* pctime output */
67*7c478bd9Sstevel@tonic-gate {
68*7c478bd9Sstevel@tonic-gate 	struct tm *ctp;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	ctp = localtime(&tvp->tv_sec);
71*7c478bd9Sstevel@tonic-gate #define	setfield(S, FIELD, SFT, MSK)	\
72*7c478bd9Sstevel@tonic-gate 	S = (ltohs(S) & ~(MSK << SFT)) | (((FIELD) & MSK) << SFT); S = htols(S);
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate 	setfield(pctp->pct_time, ctp->tm_sec / 2, SECSHIFT, SECMASK);
75*7c478bd9Sstevel@tonic-gate 	setfield(pctp->pct_time, ctp->tm_min, MINSHIFT, MINMASK);
76*7c478bd9Sstevel@tonic-gate 	setfield(pctp->pct_time, ctp->tm_hour, HOURSHIFT, HOURMASK);
77*7c478bd9Sstevel@tonic-gate 	setfield(pctp->pct_date, ctp->tm_mday, DAYSHIFT, DAYMASK);
78*7c478bd9Sstevel@tonic-gate 	setfield(pctp->pct_date, ctp->tm_mon + 1, MONSHIFT, MONMASK);
79*7c478bd9Sstevel@tonic-gate 	setfield(pctp->pct_date, ctp->tm_year - 80, YEARSHIFT, YEARMASK);
80*7c478bd9Sstevel@tonic-gate #undef setfield
81*7c478bd9Sstevel@tonic-gate }
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate /*
84*7c478bd9Sstevel@tonic-gate  * convert pctime to timeval
85*7c478bd9Sstevel@tonic-gate  */
86*7c478bd9Sstevel@tonic-gate void
87*7c478bd9Sstevel@tonic-gate pc_pcttotv(
88*7c478bd9Sstevel@tonic-gate 	struct pctime *pctp,		/* ptime input */
89*7c478bd9Sstevel@tonic-gate 	timestruc_t *tvp)		/* tinmeval output */
90*7c478bd9Sstevel@tonic-gate {
91*7c478bd9Sstevel@tonic-gate 	struct tm tm;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate #define	getfield(S, SFT, M)	(((int)(ltohs(S)) >> SFT) & M)
94*7c478bd9Sstevel@tonic-gate 	tm.tm_sec = getfield(pctp->pct_time, SECSHIFT, SECMASK) * 2;
95*7c478bd9Sstevel@tonic-gate 	tm.tm_min = getfield(pctp->pct_time, MINSHIFT, MINMASK);
96*7c478bd9Sstevel@tonic-gate 	tm.tm_hour = getfield(pctp->pct_time, HOURSHIFT, HOURMASK);
97*7c478bd9Sstevel@tonic-gate 	tm.tm_mday =  getfield(pctp->pct_date, DAYSHIFT, DAYMASK);
98*7c478bd9Sstevel@tonic-gate 	tm.tm_mon = getfield(pctp->pct_date, MONSHIFT, MONMASK) - 1;
99*7c478bd9Sstevel@tonic-gate 	tm.tm_year = 80 + getfield(pctp->pct_date, YEARSHIFT, YEARMASK);
100*7c478bd9Sstevel@tonic-gate #undef getfield
101*7c478bd9Sstevel@tonic-gate 	tvp->tv_nsec = 0;
102*7c478bd9Sstevel@tonic-gate 	tvp->tv_sec = ctime(&tm);
103*7c478bd9Sstevel@tonic-gate }
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /*
106*7c478bd9Sstevel@tonic-gate  * This routine converts time as follows.
107*7c478bd9Sstevel@tonic-gate  * The epoch is 0000 Jan 1 1970 GMT.
108*7c478bd9Sstevel@tonic-gate  * The argument time is in seconds since then.
109*7c478bd9Sstevel@tonic-gate  * The localtime(t) entry returns a pointer to an array
110*7c478bd9Sstevel@tonic-gate  * containing
111*7c478bd9Sstevel@tonic-gate  *  seconds (0-59)
112*7c478bd9Sstevel@tonic-gate  *  minutes (0-59)
113*7c478bd9Sstevel@tonic-gate  *  hours (0-23)
114*7c478bd9Sstevel@tonic-gate  *  day of month (1-31)
115*7c478bd9Sstevel@tonic-gate  *  month (0-11)
116*7c478bd9Sstevel@tonic-gate  *  year-1900
117*7c478bd9Sstevel@tonic-gate  *  weekday (0-6, Sun is 0)
118*7c478bd9Sstevel@tonic-gate  *  day of the year
119*7c478bd9Sstevel@tonic-gate  *  daylight savings flag
120*7c478bd9Sstevel@tonic-gate  *
121*7c478bd9Sstevel@tonic-gate  * The routine calls the system to determine the local
122*7c478bd9Sstevel@tonic-gate  * timezone and whether Daylight Saving Time is permitted locally.
123*7c478bd9Sstevel@tonic-gate  * (DST is then determined by the current local rules)
124*7c478bd9Sstevel@tonic-gate  *
125*7c478bd9Sstevel@tonic-gate  * The routine does not work
126*7c478bd9Sstevel@tonic-gate  * in Saudi Arabia which runs on Solar time.
127*7c478bd9Sstevel@tonic-gate  *
128*7c478bd9Sstevel@tonic-gate  */
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate static	int	dmsize[12] =
131*7c478bd9Sstevel@tonic-gate {
132*7c478bd9Sstevel@tonic-gate 	31,
133*7c478bd9Sstevel@tonic-gate 	28,
134*7c478bd9Sstevel@tonic-gate 	31,
135*7c478bd9Sstevel@tonic-gate 	30,
136*7c478bd9Sstevel@tonic-gate 	31,
137*7c478bd9Sstevel@tonic-gate 	30,
138*7c478bd9Sstevel@tonic-gate 	31,
139*7c478bd9Sstevel@tonic-gate 	31,
140*7c478bd9Sstevel@tonic-gate 	30,
141*7c478bd9Sstevel@tonic-gate 	31,
142*7c478bd9Sstevel@tonic-gate 	30,
143*7c478bd9Sstevel@tonic-gate 	31
144*7c478bd9Sstevel@tonic-gate };
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate /*
147*7c478bd9Sstevel@tonic-gate  * The following table is used for 1974 and 1975 and
148*7c478bd9Sstevel@tonic-gate  * gives the day number of the first day after the Sunday of the
149*7c478bd9Sstevel@tonic-gate  * change.
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate struct dstab {
152*7c478bd9Sstevel@tonic-gate 	int	dayyr;
153*7c478bd9Sstevel@tonic-gate 	int	daylb;
154*7c478bd9Sstevel@tonic-gate 	int	dayle;
155*7c478bd9Sstevel@tonic-gate };
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate static struct dstab usdaytab[] = {
158*7c478bd9Sstevel@tonic-gate 	1974,	5,	333,	/* 1974: Jan 6 - last Sun. in Nov */
159*7c478bd9Sstevel@tonic-gate 	1975,	58,	303,	/* 1975: Last Sun. in Feb - last Sun in Oct */
160*7c478bd9Sstevel@tonic-gate 	0,	119,	303,	/* all other years: end Apr - end Oct */
161*7c478bd9Sstevel@tonic-gate };
162*7c478bd9Sstevel@tonic-gate static struct dstab ausdaytab[] = {
163*7c478bd9Sstevel@tonic-gate 	1970,	400,	0,	/* 1970: no daylight saving at all */
164*7c478bd9Sstevel@tonic-gate 	1971,	303,	0,	/* 1971: daylight saving from Oct 31 */
165*7c478bd9Sstevel@tonic-gate 	1972,	303,	58,	/* 1972: Jan 1 -> Feb 27 & Oct 31 -> dec 31 */
166*7c478bd9Sstevel@tonic-gate 	0,	303,	65,	/* others: -> Mar 7, Oct 31 -> */
167*7c478bd9Sstevel@tonic-gate };
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate /*
170*7c478bd9Sstevel@tonic-gate  * The European tables ... based on hearsay
171*7c478bd9Sstevel@tonic-gate  * Believed correct for:
172*7c478bd9Sstevel@tonic-gate  *	WE:	Great Britain, Ireland, Portugal
173*7c478bd9Sstevel@tonic-gate  *	ME:	Belgium, Luxembourg, Netherlands, Denmark, Norway,
174*7c478bd9Sstevel@tonic-gate  *		Austria, Poland, Czechoslovakia, Sweden, Switzerland,
175*7c478bd9Sstevel@tonic-gate  *		DDR, DBR, France, Spain, Hungary, Italy, Jugoslavia
176*7c478bd9Sstevel@tonic-gate  * Eastern European dst is unknown, we'll make it ME until someone speaks up.
177*7c478bd9Sstevel@tonic-gate  *	EE:	Bulgaria, Finland, Greece, Rumania, Turkey, Western Russia
178*7c478bd9Sstevel@tonic-gate  */
179*7c478bd9Sstevel@tonic-gate static struct dstab wedaytab[] = {
180*7c478bd9Sstevel@tonic-gate 	1983,	86,	303,	/* 1983: end March - end Oct */
181*7c478bd9Sstevel@tonic-gate 	1984,	86,	303,	/* 1984: end March - end Oct */
182*7c478bd9Sstevel@tonic-gate 	1985,	86,	303,	/* 1985: end March - end Oct */
183*7c478bd9Sstevel@tonic-gate 	0,	400,	0,	/* others: no daylight saving at all ??? */
184*7c478bd9Sstevel@tonic-gate };
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate static struct dstab medaytab[] = {
187*7c478bd9Sstevel@tonic-gate 	1983,	86,	272,	/* 1983: end March - end Sep */
188*7c478bd9Sstevel@tonic-gate 	1984,	86,	272,	/* 1984: end March - end Sep */
189*7c478bd9Sstevel@tonic-gate 	1985,	86,	272,	/* 1985: end March - end Sep */
190*7c478bd9Sstevel@tonic-gate 	0,	400,	0,	/* others: no daylight saving at all ??? */
191*7c478bd9Sstevel@tonic-gate };
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate static struct dayrules {
194*7c478bd9Sstevel@tonic-gate 	int		dst_type;	/* number obtained from system */
195*7c478bd9Sstevel@tonic-gate 	int		dst_hrs;	/* hours to add when dst on */
196*7c478bd9Sstevel@tonic-gate 	struct	dstab	*dst_rules;	/* one of the above */
197*7c478bd9Sstevel@tonic-gate 	enum {STH, NTH}	dst_hemi;	/* southern, northern hemisphere */
198*7c478bd9Sstevel@tonic-gate } dayrules [] = {
199*7c478bd9Sstevel@tonic-gate 	DST_USA,	1,	usdaytab,	NTH,
200*7c478bd9Sstevel@tonic-gate 	DST_AUST,	1,	ausdaytab,	STH,
201*7c478bd9Sstevel@tonic-gate 	DST_WET,	1,	wedaytab,	NTH,
202*7c478bd9Sstevel@tonic-gate 	DST_MET,	1,	medaytab,	NTH,
203*7c478bd9Sstevel@tonic-gate 	DST_EET,	1,	medaytab,	NTH,	/* XXX */
204*7c478bd9Sstevel@tonic-gate 	-1,
205*7c478bd9Sstevel@tonic-gate };
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate struct pcfs_args pc_tz; /* this is set by pcfs_mount */
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate static struct tm *
210*7c478bd9Sstevel@tonic-gate localtime(time_t *tim)
211*7c478bd9Sstevel@tonic-gate {
212*7c478bd9Sstevel@tonic-gate 	int dayno;
213*7c478bd9Sstevel@tonic-gate 	struct tm *ct;
214*7c478bd9Sstevel@tonic-gate 	int	dalybeg, daylend;
215*7c478bd9Sstevel@tonic-gate 	struct dayrules *dr;
216*7c478bd9Sstevel@tonic-gate 	struct dstab *ds;
217*7c478bd9Sstevel@tonic-gate 	int year;
218*7c478bd9Sstevel@tonic-gate 	int copyt;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 	copyt = *tim - (int)pc_tz.secondswest;
221*7c478bd9Sstevel@tonic-gate 	ct = gmtime(copyt);
222*7c478bd9Sstevel@tonic-gate 	dayno = ct->tm_yday;
223*7c478bd9Sstevel@tonic-gate 	for (dr = dayrules; dr->dst_type >= 0; dr++)
224*7c478bd9Sstevel@tonic-gate 		if (dr->dst_type == pc_tz.dsttime)
225*7c478bd9Sstevel@tonic-gate 			break;
226*7c478bd9Sstevel@tonic-gate 	if (dr->dst_type >= 0) {
227*7c478bd9Sstevel@tonic-gate 		year = ct->tm_year + 1900;
228*7c478bd9Sstevel@tonic-gate 		for (ds = dr->dst_rules; ds->dayyr; ds++) {
229*7c478bd9Sstevel@tonic-gate 			if (ds->dayyr == year) {
230*7c478bd9Sstevel@tonic-gate 				break;
231*7c478bd9Sstevel@tonic-gate 			}
232*7c478bd9Sstevel@tonic-gate 		}
233*7c478bd9Sstevel@tonic-gate 		dalybeg = ds->daylb;	/* first Sun after dst starts */
234*7c478bd9Sstevel@tonic-gate 		daylend = ds->dayle;	/* first Sun after dst ends */
235*7c478bd9Sstevel@tonic-gate 		dalybeg = sunday(ct, dalybeg);
236*7c478bd9Sstevel@tonic-gate 		daylend = sunday(ct, daylend);
237*7c478bd9Sstevel@tonic-gate 		switch (dr->dst_hemi) {
238*7c478bd9Sstevel@tonic-gate 		case NTH:
239*7c478bd9Sstevel@tonic-gate 			if (!(
240*7c478bd9Sstevel@tonic-gate 			    (dayno > dalybeg ||
241*7c478bd9Sstevel@tonic-gate 			    (dayno == dalybeg && ct->tm_hour >= 2)) &&
242*7c478bd9Sstevel@tonic-gate 			    (dayno < daylend ||
243*7c478bd9Sstevel@tonic-gate 			    (dayno == daylend && ct->tm_hour < 1)))) {
244*7c478bd9Sstevel@tonic-gate 				return (ct);
245*7c478bd9Sstevel@tonic-gate 			}
246*7c478bd9Sstevel@tonic-gate 			break;
247*7c478bd9Sstevel@tonic-gate 		case STH:
248*7c478bd9Sstevel@tonic-gate 			if (!(
249*7c478bd9Sstevel@tonic-gate 			    (dayno > dalybeg ||
250*7c478bd9Sstevel@tonic-gate 			    (dayno == dalybeg && ct->tm_hour >= 2)) ||
251*7c478bd9Sstevel@tonic-gate 			    (dayno < daylend ||
252*7c478bd9Sstevel@tonic-gate 			    (dayno == daylend && ct->tm_hour < 2)))) {
253*7c478bd9Sstevel@tonic-gate 				return (ct);
254*7c478bd9Sstevel@tonic-gate 			}
255*7c478bd9Sstevel@tonic-gate 			break;
256*7c478bd9Sstevel@tonic-gate 		default:
257*7c478bd9Sstevel@tonic-gate 		    return (ct);
258*7c478bd9Sstevel@tonic-gate 		}
259*7c478bd9Sstevel@tonic-gate 		copyt += dr->dst_hrs*60*60;
260*7c478bd9Sstevel@tonic-gate 		ct = gmtime(copyt);
261*7c478bd9Sstevel@tonic-gate 		ct->tm_isdst++;
262*7c478bd9Sstevel@tonic-gate 	}
263*7c478bd9Sstevel@tonic-gate 	return (ct);
264*7c478bd9Sstevel@tonic-gate }
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate /*
267*7c478bd9Sstevel@tonic-gate  * The argument is a 0-origin day number.
268*7c478bd9Sstevel@tonic-gate  * The value is the day number of the first
269*7c478bd9Sstevel@tonic-gate  * Sunday on or after the day.
270*7c478bd9Sstevel@tonic-gate  */
271*7c478bd9Sstevel@tonic-gate static int
272*7c478bd9Sstevel@tonic-gate sunday(struct tm *t, int d)
273*7c478bd9Sstevel@tonic-gate {
274*7c478bd9Sstevel@tonic-gate 	if (d >= 58)
275*7c478bd9Sstevel@tonic-gate 		d += dysize(YEAR_ZERO + t->tm_year) - 365;
276*7c478bd9Sstevel@tonic-gate 	return (d - (d - t->tm_yday + t->tm_wday + 700) % 7);
277*7c478bd9Sstevel@tonic-gate }
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate static int
280*7c478bd9Sstevel@tonic-gate dysize(int y)
281*7c478bd9Sstevel@tonic-gate {
282*7c478bd9Sstevel@tonic-gate 	if (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
283*7c478bd9Sstevel@tonic-gate 		return (366);
284*7c478bd9Sstevel@tonic-gate 	return (365);
285*7c478bd9Sstevel@tonic-gate }
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate static struct tm *
288*7c478bd9Sstevel@tonic-gate gmtime(int tim)
289*7c478bd9Sstevel@tonic-gate {
290*7c478bd9Sstevel@tonic-gate 	int d0, d1;
291*7c478bd9Sstevel@tonic-gate 	int hms, day;
292*7c478bd9Sstevel@tonic-gate 	short *tp;
293*7c478bd9Sstevel@tonic-gate 	static struct tm xtime;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	/*
296*7c478bd9Sstevel@tonic-gate 	 * break initial number into days
297*7c478bd9Sstevel@tonic-gate 	 */
298*7c478bd9Sstevel@tonic-gate 	hms = tim % 86400;
299*7c478bd9Sstevel@tonic-gate 	day = tim / 86400;
300*7c478bd9Sstevel@tonic-gate 	if (hms < 0) {
301*7c478bd9Sstevel@tonic-gate 		hms += 86400;
302*7c478bd9Sstevel@tonic-gate 		day -= 1;
303*7c478bd9Sstevel@tonic-gate 	}
304*7c478bd9Sstevel@tonic-gate 	tp = (short *)&xtime;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	/*
307*7c478bd9Sstevel@tonic-gate 	 * generate hours:minutes:seconds
308*7c478bd9Sstevel@tonic-gate 	 */
309*7c478bd9Sstevel@tonic-gate 	*tp++ = hms%60;
310*7c478bd9Sstevel@tonic-gate 	d1 = hms/60;
311*7c478bd9Sstevel@tonic-gate 	*tp++ = d1%60;
312*7c478bd9Sstevel@tonic-gate 	d1 /= 60;
313*7c478bd9Sstevel@tonic-gate 	*tp++ = (short)d1;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/*
316*7c478bd9Sstevel@tonic-gate 	 * day is the day number.
317*7c478bd9Sstevel@tonic-gate 	 * generate day of the week.
318*7c478bd9Sstevel@tonic-gate 	 * The addend is 4 mod 7 (1/1/1970 was Thursday)
319*7c478bd9Sstevel@tonic-gate 	 */
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	xtime.tm_wday = (day+7340036)%7;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	/*
324*7c478bd9Sstevel@tonic-gate 	 * year number
325*7c478bd9Sstevel@tonic-gate 	 */
326*7c478bd9Sstevel@tonic-gate 	if (day >= 0)
327*7c478bd9Sstevel@tonic-gate 		for (d1 = 70; day >= dysize(YEAR_ZERO + d1); d1++)
328*7c478bd9Sstevel@tonic-gate 			day -= dysize(YEAR_ZERO + d1);
329*7c478bd9Sstevel@tonic-gate 	else
330*7c478bd9Sstevel@tonic-gate 		for (d1 = 70; day < 0; d1--)
331*7c478bd9Sstevel@tonic-gate 			day += dysize(YEAR_ZERO + d1 - 1);
332*7c478bd9Sstevel@tonic-gate 	xtime.tm_year = (short)d1;
333*7c478bd9Sstevel@tonic-gate 	xtime.tm_yday = d0 = day;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	/*
336*7c478bd9Sstevel@tonic-gate 	 * generate month
337*7c478bd9Sstevel@tonic-gate 	 */
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	if (dysize(YEAR_ZERO + d1) == 366)
340*7c478bd9Sstevel@tonic-gate 		dmsize[1] = 29;
341*7c478bd9Sstevel@tonic-gate 	for (d1 = 0; d0 >= dmsize[d1]; d1++)
342*7c478bd9Sstevel@tonic-gate 		d0 -= dmsize[d1];
343*7c478bd9Sstevel@tonic-gate 	dmsize[1] = 28;
344*7c478bd9Sstevel@tonic-gate 	*tp++ = d0+1;
345*7c478bd9Sstevel@tonic-gate 	*tp++ = (short)d1;
346*7c478bd9Sstevel@tonic-gate 	xtime.tm_isdst = 0;
347*7c478bd9Sstevel@tonic-gate 	return (&xtime);
348*7c478bd9Sstevel@tonic-gate }
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate /*
351*7c478bd9Sstevel@tonic-gate  * convert year, month, day, hour, minute, sec to (int)time.
352*7c478bd9Sstevel@tonic-gate  */
353*7c478bd9Sstevel@tonic-gate static time_t
354*7c478bd9Sstevel@tonic-gate ctime(struct tm *tp)
355*7c478bd9Sstevel@tonic-gate {
356*7c478bd9Sstevel@tonic-gate 	int i;
357*7c478bd9Sstevel@tonic-gate 	time_t ct;
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	if (tp->tm_mon < 0 || tp->tm_mon > 11 ||
360*7c478bd9Sstevel@tonic-gate 	    tp->tm_mday < 1 || tp->tm_mday > 31 ||
361*7c478bd9Sstevel@tonic-gate 	    tp->tm_hour < 0 || tp->tm_hour > 23 ||
362*7c478bd9Sstevel@tonic-gate 	    tp->tm_min < 0 || tp->tm_min > 59 ||
363*7c478bd9Sstevel@tonic-gate 	    tp->tm_sec < 0 || tp->tm_sec > 59) {
364*7c478bd9Sstevel@tonic-gate 		return (0);
365*7c478bd9Sstevel@tonic-gate 	}
366*7c478bd9Sstevel@tonic-gate 	ct = 0;
367*7c478bd9Sstevel@tonic-gate 	for (i = /* 19 */ 70; i < tp->tm_year; i++)
368*7c478bd9Sstevel@tonic-gate 		ct += dysize(YEAR_ZERO + i);
369*7c478bd9Sstevel@tonic-gate 	/* Leap year */
370*7c478bd9Sstevel@tonic-gate 	if (dysize(YEAR_ZERO + tp->tm_year) == 366 && tp->tm_mon >= 2)
371*7c478bd9Sstevel@tonic-gate 		ct++;
372*7c478bd9Sstevel@tonic-gate 	i = tp->tm_mon + 1;
373*7c478bd9Sstevel@tonic-gate 	while (--i)
374*7c478bd9Sstevel@tonic-gate 		ct += dmsize[i-1];
375*7c478bd9Sstevel@tonic-gate 	ct += tp->tm_mday-1;
376*7c478bd9Sstevel@tonic-gate 	ct = 24*ct + tp->tm_hour;
377*7c478bd9Sstevel@tonic-gate 	ct = 60*ct + tp->tm_min;
378*7c478bd9Sstevel@tonic-gate 	ct = 60*ct + tp->tm_sec;
379*7c478bd9Sstevel@tonic-gate 	/* convert to GMT assuming local time */
380*7c478bd9Sstevel@tonic-gate 	ct += (int)pc_tz.secondswest;
381*7c478bd9Sstevel@tonic-gate 	/* now fix up local daylight time */
382*7c478bd9Sstevel@tonic-gate 	if (localtime(&ct)->tm_isdst)
383*7c478bd9Sstevel@tonic-gate 		ct -= 60*60;
384*7c478bd9Sstevel@tonic-gate 	return (ct);
385*7c478bd9Sstevel@tonic-gate }
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate /*
388*7c478bd9Sstevel@tonic-gate  * Determine whether a character is valid for a pc 8.3 file system file name.
389*7c478bd9Sstevel@tonic-gate  * The Windows 95 Resource Kit claims that these are valid:
390*7c478bd9Sstevel@tonic-gate  *	uppercase letters and numbers
391*7c478bd9Sstevel@tonic-gate  *	blank
392*7c478bd9Sstevel@tonic-gate  *	ASCII characters greater than 127
393*7c478bd9Sstevel@tonic-gate  *	$%'-_@~`!()^#&
394*7c478bd9Sstevel@tonic-gate  * Long file names can also have
395*7c478bd9Sstevel@tonic-gate  *	lowercase letters
396*7c478bd9Sstevel@tonic-gate  *	+,;=[]
397*7c478bd9Sstevel@tonic-gate  */
398*7c478bd9Sstevel@tonic-gate int
399*7c478bd9Sstevel@tonic-gate pc_validchar(char c)
400*7c478bd9Sstevel@tonic-gate {
401*7c478bd9Sstevel@tonic-gate 	char *cp;
402*7c478bd9Sstevel@tonic-gate 	int n;
403*7c478bd9Sstevel@tonic-gate 	static char valtab[] = {
404*7c478bd9Sstevel@tonic-gate 		"$#&@!%()-{}<>`_^~|' "
405*7c478bd9Sstevel@tonic-gate 	};
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	/*
408*7c478bd9Sstevel@tonic-gate 	 * Should be "$#&@!%()-{}`_^~' " ??
409*7c478bd9Sstevel@tonic-gate 	 * From experiment in DOSWindows, *+=|\[];:",<>.?/ are illegal.
410*7c478bd9Sstevel@tonic-gate 	 * See IBM DOS4.0 Tech Ref. B-57.
411*7c478bd9Sstevel@tonic-gate 	 */
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	if (c >= 'A' && c <= 'Z')
414*7c478bd9Sstevel@tonic-gate 		return (1);
415*7c478bd9Sstevel@tonic-gate 	if (c >= '0' && c <= '9')
416*7c478bd9Sstevel@tonic-gate 		return (1);
417*7c478bd9Sstevel@tonic-gate 	cp = valtab;
418*7c478bd9Sstevel@tonic-gate 	n = sizeof (valtab);
419*7c478bd9Sstevel@tonic-gate 	while (n--) {
420*7c478bd9Sstevel@tonic-gate 		if (c == *cp++)
421*7c478bd9Sstevel@tonic-gate 			return (1);
422*7c478bd9Sstevel@tonic-gate 	}
423*7c478bd9Sstevel@tonic-gate 	return (0);
424*7c478bd9Sstevel@tonic-gate }
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate /*
427*7c478bd9Sstevel@tonic-gate  * Determine whether a character is valid for a pc 8.3 file system file name.
428*7c478bd9Sstevel@tonic-gate  * The Windows 95 Resource Kit claims that these are valid:
429*7c478bd9Sstevel@tonic-gate  *	uppercase letters and numbers
430*7c478bd9Sstevel@tonic-gate  *	blank
431*7c478bd9Sstevel@tonic-gate  *	ASCII characters greater than 127
432*7c478bd9Sstevel@tonic-gate  *	$%'-_@~`!()^#&
433*7c478bd9Sstevel@tonic-gate  * Long file names can also have
434*7c478bd9Sstevel@tonic-gate  *	lowercase letters
435*7c478bd9Sstevel@tonic-gate  *	+,;=[].
436*7c478bd9Sstevel@tonic-gate  */
437*7c478bd9Sstevel@tonic-gate int
438*7c478bd9Sstevel@tonic-gate pc_valid_lfn_char(char c)
439*7c478bd9Sstevel@tonic-gate {
440*7c478bd9Sstevel@tonic-gate 	char *cp;
441*7c478bd9Sstevel@tonic-gate 	int n;
442*7c478bd9Sstevel@tonic-gate 	static char valtab[] = {
443*7c478bd9Sstevel@tonic-gate 		"+,;=[].$#&@!%()-{}<>`_^~|' "
444*7c478bd9Sstevel@tonic-gate 	};
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	if (c >= 'a' && c <= 'z')
447*7c478bd9Sstevel@tonic-gate 		return (1);
448*7c478bd9Sstevel@tonic-gate 	if (c >= 'A' && c <= 'Z')
449*7c478bd9Sstevel@tonic-gate 		return (1);
450*7c478bd9Sstevel@tonic-gate 	if (c >= '0' && c <= '9')
451*7c478bd9Sstevel@tonic-gate 		return (1);
452*7c478bd9Sstevel@tonic-gate 	cp = valtab;
453*7c478bd9Sstevel@tonic-gate 	n = sizeof (valtab);
454*7c478bd9Sstevel@tonic-gate 	while (n--) {
455*7c478bd9Sstevel@tonic-gate 		if (c == *cp++)
456*7c478bd9Sstevel@tonic-gate 			return (1);
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 	return (0);
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate int
462*7c478bd9Sstevel@tonic-gate pc_valid_long_fn(char *namep)
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	char *tmp;
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	for (tmp = namep; *tmp != '\0'; tmp++)
467*7c478bd9Sstevel@tonic-gate 		if (!pc_valid_lfn_char(*tmp))
468*7c478bd9Sstevel@tonic-gate 			return (0);
469*7c478bd9Sstevel@tonic-gate 	if ((tmp - namep) >= PCMAXNAMLEN)
470*7c478bd9Sstevel@tonic-gate 		return (0);
471*7c478bd9Sstevel@tonic-gate 	return (1);
472*7c478bd9Sstevel@tonic-gate }
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate int
475*7c478bd9Sstevel@tonic-gate pc_fname_ext_to_name(char *namep, char *fname, char *ext, int foldcase)
476*7c478bd9Sstevel@tonic-gate {
477*7c478bd9Sstevel@tonic-gate 	int	i;
478*7c478bd9Sstevel@tonic-gate 	char	*tp = namep;
479*7c478bd9Sstevel@tonic-gate 	char	c;
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	i = PCFNAMESIZE;
482*7c478bd9Sstevel@tonic-gate 	while (i-- && ((c = *fname) != ' ')) {
483*7c478bd9Sstevel@tonic-gate 		if (!(c == '.' || pc_validchar(c))) {
484*7c478bd9Sstevel@tonic-gate 			return (-1);
485*7c478bd9Sstevel@tonic-gate 		}
486*7c478bd9Sstevel@tonic-gate 		if (foldcase)
487*7c478bd9Sstevel@tonic-gate 			*tp++ = tolower(c);
488*7c478bd9Sstevel@tonic-gate 		else
489*7c478bd9Sstevel@tonic-gate 			*tp++ = c;
490*7c478bd9Sstevel@tonic-gate 		fname++;
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate 	if (*ext != ' ') {
493*7c478bd9Sstevel@tonic-gate 		*tp++ = '.';
494*7c478bd9Sstevel@tonic-gate 		i = PCFEXTSIZE;
495*7c478bd9Sstevel@tonic-gate 		while (i-- && ((c = *ext) != ' ')) {
496*7c478bd9Sstevel@tonic-gate 			if (!pc_validchar(c)) {
497*7c478bd9Sstevel@tonic-gate 				return (-1);
498*7c478bd9Sstevel@tonic-gate 			}
499*7c478bd9Sstevel@tonic-gate 			if (foldcase)
500*7c478bd9Sstevel@tonic-gate 				*tp++ = tolower(c);
501*7c478bd9Sstevel@tonic-gate 			else
502*7c478bd9Sstevel@tonic-gate 				*tp++ = c;
503*7c478bd9Sstevel@tonic-gate 			ext++;
504*7c478bd9Sstevel@tonic-gate 		}
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate 	*tp = '\0';
507*7c478bd9Sstevel@tonic-gate 	return (0);
508*7c478bd9Sstevel@tonic-gate }
509