Annotation of Net2/pcfs/pcfs_conv.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.