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