|
|
1.1 root 1: /*
2: * Written by Paul Popelka ([email protected])
3: *
4: * You can do anything you want with this software,
5: * just don't say you wrote it,
6: * and don't remove this notice.
7: *
8: * This software is provided "as is".
9: *
10: * The author supplies this software to be publicly
11: * redistributed on the understanding that the author
12: * is not responsible for the correct functioning of
13: * this software in any circumstances and is not liable
14: * for any damages caused by this software.
15: *
16: * October 1992
17: *
18: * pcfs_conv.c,v 1.2 1993/05/20 03:34:09 cgd Exp
19: */
20:
21: /*
22: * System include files.
23: */
24: #include "param.h"
25: #include "time.h"
26: #include "kernel.h" /* defines tz */
27:
28: /*
29: * PCFS include files.
30: */
31: #include "direntry.h"
32:
33: /*
34: * Days in each month in a regular year.
35: */
36: u_short regyear[] = {
37: 31, 28, 31, 30, 31, 30,
38: 31, 31, 30, 31, 30, 31
39: };
40:
41: /*
42: * Days in each month in a leap year.
43: */
44: u_short leapyear[] = {
45: 31, 29, 31, 30, 31, 30,
46: 31, 31, 30, 31, 30, 31
47: };
48:
49: /*
50: * Variables used to remember parts of the last time
51: * conversion. Maybe we can avoid a full conversion.
52: */
53: u_long lasttime;
54: u_long lastday;
55: union dosdate lastddate;
56: union dostime lastdtime;
57:
58: /*
59: * Convert the unix version of time to dos's idea of time
60: * to be used in file timestamps.
61: * The passed in unix time is assumed to be in GMT.
62: */
63: void
64: unix2dostime(tvp, ddp, dtp)
65: struct timeval *tvp;
66: union dosdate *ddp;
67: union dostime *dtp;
68: {
69: u_long days;
70: u_long inc;
71: u_long year;
72: u_long month;
73: u_short *months;
74:
75: /*
76: * If the time from the last conversion is the same
77: * as now, then skip the computations and use the
78: * saved result.
79: */
80: if (lasttime != tvp->tv_sec) {
81: lasttime = tvp->tv_sec - (tz.tz_minuteswest * 60)
82: /* +- daylight savings time correction */;
83: lastdtime.dts.dt_2seconds = (lasttime % 60) >> 1;
84: lastdtime.dts.dt_minutes = (lasttime / 60) % 60;
85: lastdtime.dts.dt_hours = (lasttime / (60 * 60)) % 24;
86:
87: /*
88: * If the number of days since 1970 is the same as the
89: * last time we did the computation then skip all this
90: * leap year and month stuff.
91: */
92: days = lasttime / (24 * 60 * 60);
93: if (days != lastday) {
94: lastday = days;
95: for (year = 1970; ; year++) {
96: inc = year & 0x03 ? 365 : 366;
97: if (days < inc) break;
98: days -= inc;
99: }
100: months = year & 0x03 ? regyear : leapyear;
101: for (month = 0; month < 12; month++) {
102: if (days < months[month]) break;
103: days -= months[month];
104: }
105: lastddate.dds.dd_day = days + 1;
106: lastddate.dds.dd_month = month+1;
107: /*
108: * Remember dos's idea of time is relative to 1980.
109: * unix's is relative to 1970. If somehow we get a
110: * time before 1980 then don't give totally crazy
111: * results.
112: */
113: lastddate.dds.dd_year = year < 1980 ? 0 : year - 1980;
114: }
115: }
116: dtp->dti = lastdtime.dti;
117: ddp->ddi = lastddate.ddi;
118: }
119:
120: /*
121: * The number of seconds between Jan 1, 1970 and
122: * Jan 1, 1980.
123: * In that interval there were 8 regular years and
124: * 2 leap years.
125: */
126: #define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
127:
128: union dosdate lastdosdate;
129: u_long lastseconds;
130:
131: /*
132: * Convert from dos' idea of time to unix'.
133: * This will probably only be called from the
134: * stat(), and fstat() system calls
135: * and so probably need not be too efficient.
136: */
137: void
138: dos2unixtime(ddp, dtp, tvp)
139: union dosdate *ddp;
140: union dostime *dtp;
141: struct timeval *tvp;
142: {
143: u_long seconds;
144: u_long month;
145: u_long yr;
146: u_long days;
147: u_short *months;
148:
149: seconds = (dtp->dts.dt_2seconds << 1) +
150: (dtp->dts.dt_minutes * 60) +
151: (dtp->dts.dt_hours * 60 * 60);
152: /*
153: * If the year, month, and day from the last conversion
154: * are the same then use the saved value.
155: */
156: if (lastdosdate.ddi != ddp->ddi) {
157: lastdosdate.ddi = ddp->ddi;
158: days = 0;
159: for (yr = 0; yr < ddp->dds.dd_year; yr++) {
160: days += yr & 0x03 ? 365 : 366;
161: }
162: months = yr & 0x03 ? regyear : leapyear;
163: /*
164: * Prevent going from 0 to 0xffffffff in the following
165: * loop.
166: */
167: if (ddp->dds.dd_month == 0) {
168: printf("dos2unixtime(): month value out of range (%d)\n",
169: ddp->dds.dd_month);
170: ddp->dds.dd_month = 1;
171: }
172: for (month = 0; month < ddp->dds.dd_month-1; month++) {
173: days += months[month];
174: }
175: days += ddp->dds.dd_day - 1;
176: lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
177: }
178: tvp->tv_sec = seconds + lastseconds + (tz.tz_minuteswest * 60)
179: /* -+ daylight savings time correction */;
180: tvp->tv_usec = 0;
181: }
182:
183: /*
184: * Cheezy macros to do case detection and conversion
185: * for the ascii character set. DOESN'T work for ebcdic.
186: */
187: #define isupper(c) (c >= 'A' && c <= 'Z')
188: #define islower(c) (c >= 'a' && c <= 'z')
189: #define toupper(c) (c & ~' ')
190: #define tolower(c) (c | ' ')
191:
192: /*
193: * DOS filenames are made of 2 parts, the name part and
194: * the extension part. The name part is 8 characters
195: * long and the extension part is 3 characters long. They
196: * may contain trailing blanks if the name or extension
197: * are not long enough to fill their respective fields.
198: */
199:
200: /*
201: * Convert a DOS filename to a unix filename.
202: * And, return the number of characters in the
203: * resulting unix filename excluding the terminating
204: * null.
205: */
206: int
207: dos2unixfn(dn, un)
208: u_char dn[11];
209: u_char *un;
210: {
211: int i;
212: int ni;
213: int ei;
214: int thislong = 0;
215: u_char c;
216: u_char *origun = un;
217:
218: /*
219: * Find the last character in the name portion
220: * of the dos filename.
221: */
222: for (ni = 7; ni >= 0; ni--)
223: if (dn[ni] != ' ') break;
224:
225: /*
226: * Find the last character in the extension
227: * portion of the filename.
228: */
229: for (ei = 10; ei >= 8; ei--)
230: if (dn[ei] != ' ') break;
231:
232: /*
233: * Copy the name portion into the unix filename
234: * string.
235: * NOTE: DOS filenames are usually kept in upper
236: * case. To make it more unixy we convert all
237: * DOS filenames to lower case. Some may like
238: * this, some may not.
239: */
240: for (i = 0; i <= ni; i++) {
241: c = dn[i];
242: *un++ = isupper(c) ? tolower(c) : c;
243: thislong++;
244: }
245:
246: /*
247: * Now, if there is an extension then put in a period
248: * and copy in the extension.
249: */
250: if (ei >= 8) {
251: *un++ = '.';
252: thislong++;
253: for (i = 8; i <= ei; i++) {
254: c = dn[i];
255: *un++ = isupper(c) ? tolower(c) : c;
256: thislong++;
257: }
258: }
259: *un++ = 0;
260:
261: /*
262: * If first char of the filename is SLOT_E5 (0x05), then
263: * the real first char of the filename should be 0xe5.
264: * But, they couldn't just have a 0xe5 mean 0xe5 because
265: * that is used to mean a freed directory slot.
266: * Another dos quirk.
267: */
268: if (*origun == SLOT_E5)
269: *origun = 0xe5;
270:
271: return thislong;
272: }
273:
274: /*
275: * Convert a unix filename to a DOS filename.
276: * This function does not ensure that valid
277: * characters for a dos filename are supplied.
278: */
279: void
280: unix2dosfn(un, dn, unlen)
281: u_char *un;
282: u_char dn[11];
283: int unlen;
284: {
285: int i;
286: u_char c;
287:
288: /*
289: * Fill the dos filename string with blanks.
290: * These are DOS's pad characters.
291: */
292: for (i = 0; i <= 10; i++)
293: dn[i] = ' ';
294:
295: /*
296: * The filenames "." and ".." are handled specially,
297: * since they don't follow dos filename rules.
298: */
299: if (un[0] == '.' && un[1] == '\0') {
300: dn[0] = '.';
301: return;
302: }
303: if (un[0] == '.' && un[1] == '.' && un[2] == '\0') {
304: dn[0] = '.';
305: dn[1] = '.';
306: return;
307: }
308:
309: /*
310: * Copy the unix filename into the dos filename string
311: * upto the end of string, a '.', or 8 characters.
312: * Whichever happens first stops us.
313: * This forms the name portion of the dos filename.
314: * Fold to upper case.
315: */
316: for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
317: dn[i] = islower(c) ? toupper(c) : c;
318: un++;
319: unlen--;
320: }
321:
322: /*
323: * If the first char of the filename is 0xe5, then translate
324: * it to 0x05. This is because 0xe5 is the marker for a
325: * deleted directory slot. I guess this means you can't
326: * have filenames that start with 0x05. I suppose we should
327: * check for this and doing something about it.
328: */
329: if (dn[0] == SLOT_DELETED)
330: dn[0] = SLOT_E5;
331:
332: /*
333: * Strip any further characters up to a '.' or the
334: * end of the string.
335: */
336: while (unlen && (c = *un) && c != '.') {
337: un++;
338: unlen--;
339: }
340:
341: /*
342: * If we stopped on a '.', then get past it.
343: */
344: if (c == '.') un++;
345:
346: /*
347: * Copy in the extension part of the name, if any.
348: * Force to upper case.
349: * Note that the extension is allowed to contain '.'s.
350: * Filenames in this form are probably inaccessable
351: * under dos.
352: */
353: for (i = 8; i <= 10 && unlen && (c = *un); i++) {
354: dn[i] = islower(c) ? toupper(c) : c;
355: un++;
356: unlen--;
357: }
358: }
359:
360: /*
361: * Get rid of these macros before someone discovers
362: * we are using such hideous things.
363: */
364: #undef isupper
365: #undef islower
366: #undef toupper
367: #undef tolower
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.