|
|
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.