Annotation of Net2/pcfs/pcfs_conv.c, revision 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.