Annotation of dmsdos/src/dstacker_alloc.c, revision 1.1.1.2

1.1       root        1: /*
                      2: dstacker_alloc.c
                      3: 
                      4: DMSDOS CVF-FAT module: stacker allocation routines.
                      5: 
                      6: ******************************************************************************
                      7: DMSDOS (compressed MSDOS filesystem support) for Linux
                      8: written 1995-1998 by Frank Gockel and Pavel Pisa
                      9: 
                     10:     (C) Copyright 1995-1998 by Frank Gockel
                     11:     (C) Copyright 1996-1998 by Pavel Pisa
                     12: 
                     13: Some code of dmsdos has been copied from the msdos filesystem
                     14: so there are the following additional copyrights:
                     15: 
                     16:     (C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem)
                     17:     (C) Copyright 1994,1995 by Jacques Gelinas (mmap code)
                     18:     (C) Copyright 1992-1995 by Linus Torvalds
                     19: 
                     20: DMSDOS was inspired by the THS filesystem (a simple doublespace
                     21: DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann.
                     22: 
                     23: The DMSDOS code is distributed under the Gnu General Public Licence.
                     24: See file COPYING for details.
                     25: ******************************************************************************
                     26: 
                     27: */
                     28: 
                     29: #ifdef __KERNEL__
                     30: #include <linux/sched.h>
                     31: #include <linux/ctype.h>
                     32: #include <linux/major.h>
                     33: #include <linux/blkdev.h>
                     34: #include <linux/fs.h>
                     35: #include <linux/stat.h>
                     36: #include <linux/locks.h>
                     37: #include <asm/segment.h>
                     38: #include <linux/mm.h>
                     39: #include <linux/malloc.h>
                     40: #include <linux/string.h>
                     41: #include <linux/msdos_fs.h>
                     42: #include <linux/errno.h>
                     43: #include <linux/kernel.h>
                     44: #include <linux/shm.h>
                     45: #include <linux/mman.h>
                     46: #include <asm/system.h>
                     47: #endif
                     48: 
                     49: #include "dmsdos.h"
                     50: 
                     51: #ifdef __DMSDOS_LIB__
                     52: /* some interface hacks */
                     53: #include"lib_interface.h"
                     54: #include<malloc.h>
                     55: #include<errno.h>
                     56: #endif
                     57: 
                     58: #ifdef DMSDOS_CONFIG_STAC
                     59: 
                     60: /* initializes Stac_cwalk structure, which can be used for sequential
                     61:    access to all sectors of cluster and when needed informs about
                     62:    all data areas in every sector. flg parameter speedups initialization
                     63:    when some informations are not necessarry
                     64:        flg = 0 .. only sector numbers
                     65:        flg = 1 .. sector numbers and data without ending suballocation
                     66:        flg = 2 .. sector numbers and exact data areas
                     67:        flg = 3 .. same as 2 but more checking
                     68: */
                     69: int stac_cwalk_init(Stac_cwalk *cw,struct super_block*sb,
                     70:                 int clusternr,int flg)
                     71: {
                     72:   __u8 *pp;
                     73:   unsigned u,v;
                     74:   int i;
                     75:   int last_sect;
                     76:   Mdfat_entry mde;
                     77:   struct buffer_head *bh;
                     78:   Dblsb*dblsb=MSDOS_SB(sb)->private_data;
                     79:   cw->finfo=NULL;
                     80:   cw->fbh=NULL;
                     81:   cw->sect=0;
                     82:   cw->sb=sb;
                     83:   cw->clusternr=clusternr;
                     84:   /* -------------------------------------------- */
                     85:   dbl_mdfat_value(sb,clusternr,NULL,&mde);
                     86:   cw->start_sect=mde.sector_minus_1+1;
                     87:   cw->sect_cnt=cw->start_len=mde.size_lo_minus_1+1;
                     88:   cw->flags=mde.flags;
                     89:   if(!cw->start_sect) {cw->fcnt=0;return 0;};
                     90:   /* -------------------------------------------- */
                     91:   cw->fcnt=1;
                     92:   cw->flen=cw->sect_cnt=cw->start_len;
                     93:   cw->bytes_in_clust=cw->sect_cnt*SECTOR_SIZE;
                     94:   cw->offset=0;
                     95:   cw->bytes=SECTOR_SIZE;
                     96:   cw->bytes_in_last=0;
                     97:   last_sect=cw->start_sect+cw->sect_cnt-1;
                     98:   /* -------------------------------------------- */
                     99:   u=(cw->flags&0xe0)>>5;
                    100:   if(cw->start_len==dblsb->s_sectperclust) u|=0x8;
                    101:   switch(u)
                    102:   {  case 0x0: /* ffff=000x, len<ClustSize, compressed, regular file/dir */
                    103:      case 0x2: /* ffff=010x, deleted 0 */
                    104:        cw->compressed=1;
                    105:        break;
                    106: 
                    107:      case 0x1: /* ffff=001x, not compressed but not full size, regular file/dir */
                    108:      case 0x3: /* ffff=011x, deleted 1 */
                    109:      case 0x8: /* ffff=000x, len=ClustSize, not compressed, regular file/dir */
                    110:      case 0xa: /* ffff=010x, deleted 8 */
                    111:      case 0xc: /* ffff=100x, len=ClustSize, directory, never compressed */
                    112:      case 0xe: /* ffff=110x, deleted c */
                    113:        cw->compressed=0;
                    114:        break;
                    115: 
                    116:      case 0x4: /* ffff=100x, len<ClustSize, fragmented, regular file/dir */
                    117:      case 0x6: /* ffff=110x, deleted 4 */
                    118:        bh=raw_bread(sb,cw->start_sect);
                    119:        if(bh==NULL)return -1;
                    120:        pp=bh->b_data;
                    121:        if(pp[0]!=0xed) /* check fragment signature */
                    122:        { printk(KERN_ERR "DMSDOS: stac_cwalk_init: fragment signature not found cluster=%d\n",
                    123:                  clusternr);
                    124:          raw_brelse(sb,bh);
                    125:          return -1;
                    126:        }
                    127:        cw->fcnt=pp[1]+1; /* number of pieces */
                    128:        if((cw->fcnt>dblsb->s_sectperclust)||(cw->fcnt*4>SECTOR_SIZE))
                    129:        { printk(KERN_ERR "DMSDOS: stac_cwalk_init: too much fragmented cluster=%d!\n",
                    130:                  clusternr);
                    131:          raw_brelse(sb,bh);
                    132:          return -1;
                    133:        };
                    134:        cw->compressed=!(pp[2]&0x80);
                    135:        v=cw->sect_cnt;
                    136:        cw->sect_cnt+=(pp[2]&0x3F)+1;
                    137:        for(i=1;i<cw->fcnt;++i)
                    138:        { pp+=4;
                    139:          u=(pp[2]&0xf)+((pp[3]>>2)&0x30);
                    140:          v+=u+1;
                    141:        };
                    142:        last_sect=pp[0]+(pp[1]<<8)+((pp[3]&0x3f)<<16)+u; /* for suballocation tests */
                    143:        if(v!=cw->sect_cnt)
                    144:        { printk(KERN_ERR "DMSDOS: stac_cwalk_init: sector count mismash fragmented cluster=%d!\n",
                    145:                  clusternr);
                    146:          raw_brelse(sb,bh);
                    147:          return -1;
                    148:        }
                    149:        cw->fbh=bh;
                    150:        cw->finfo=bh->b_data+4;
                    151:        cw->offset=4*cw->fcnt;
                    152:        cw->bytes=SECTOR_SIZE-cw->offset;
                    153:        cw->bytes_in_clust=(cw->sect_cnt-1)*SECTOR_SIZE+cw->bytes;       
                    154:        break;
                    155: 
                    156:      case 0x5: /* ffff=101x, len<ClustSize, suballocated, regular file/dir(?) */
                    157:      case 0x7: /* ffff=111x, deleted 5 */
                    158:      case 0xd: /* ffff=101x, len=ClustSize, suballocated, regular file/dir(?) */
                    159:      case 0xf: /* ffff=111x, deleted d */
                    160:        if(flg==0) {cw->bytes_in_clust=0;cw->bytes=0;return 1;};
                    161:        bh=raw_bread(sb,cw->start_sect);
                    162:        if(bh==NULL)return -1;
                    163:        pp=&(bh->b_data[SECTOR_SIZE-2]);
                    164:        if(CHS(pp)!=0x1234)
                    165:        { printk(KERN_ERR "DMSDOS: stac_cwalk_init: suballocation signature not found cluster=%d\n",
                    166:                 clusternr);
                    167:          raw_brelse(sb,bh);
                    168:          return -1;
                    169:        }
                    170:        if(cw->start_len==1)
                    171:        { /* short suballocation */
                    172:          pp = &(bh->b_data[SECTOR_SIZE-6]);
                    173:          cw->offset= CHS(pp) & (SECTOR_SIZE - 1);   /* begin of area */
                    174:          cw->compressed= !(CHS(pp) & 0x8000);
                    175:          if(CHS(pp)&0x4000)
                    176:          { printk(KERN_ERR "DMSDOS: stac_cwalk_init: suballocation not present, cluster %d\n",
                    177:            clusternr);
                    178:            raw_brelse(sb,bh); return -1;
                    179:          };
                    180:          pp = &(bh->b_data[SECTOR_SIZE-8]);
                    181:          cw->bytes=CHS(pp) & (SECTOR_SIZE - 1); /* end of area */
                    182:          /* some more paranoic checking of allocated space */
                    183:          if (cw->bytes&&(cw->bytes<=SECTOR_SIZE-8)&&(cw->bytes>cw->offset)) 
                    184:            cw->bytes-=cw->offset; 
                    185:          else 
                    186:          { printk(KERN_ERR "DMSDOS: stac_cwalk_init: count = %d < 0 in short subalocated\n", cw->bytes);
                    187:            printk(KERN_ERR "DMSDOS: cluster %d read error\n",clusternr);
                    188:            raw_brelse(sb,bh); return -1;
                    189:          }
                    190:          cw->bytes_in_clust=cw->bytes;
                    191:          last_sect=0;
                    192:        } 
                    193:        else
                    194:        { /* long suballocation */
                    195:          pp = &(bh->b_data[SECTOR_SIZE-8]);
                    196:          cw->offset = CHS(pp) & (SECTOR_SIZE - 1);
                    197:          cw->compressed = !(CHS(pp) & 0x8000);
                    198:          if(CHS(pp)&0x4000)
                    199:          { printk(KERN_ERR "DMSDOS: stac_cwalk_init: suballocation not present, cluster %d\n",
                    200:            clusternr);
                    201:            raw_brelse(sb,bh); return -1;
                    202:          };
                    203:          cw->bytes=SECTOR_SIZE-cw->offset-8;
                    204:          cw->bytes_in_clust+=cw->bytes-SECTOR_SIZE;
                    205:          if (cw->bytes < 0) {
                    206:            printk(KERN_ERR "DMSDOS: stac_cwalk_init: count = %d < 0 in long subalocated\n", cw->bytes);
                    207:            printk(KERN_ERR "DMSDOS: cluster %d read error\n",clusternr);
                    208:            raw_brelse(sb,bh); return -1;
                    209:          }
                    210:        };
                    211:        raw_brelse(sb,bh);
                    212:        break;
                    213: 
                    214:      case 0x9: /* ffff=001x, contradiction ??? */
                    215:      case 0xb: /* ffff=011x, deleted 9 */
                    216:      default:
                    217:        printk(KERN_ERR "DMSDOS: stac_cwalk_init: unknown flags 0x%2x cluster %d\n",
                    218:                mde.flags,clusternr);
                    219:        return -1;
                    220:   };
                    221: 
                    222:   /* if flg>=2 we are checking subalocated end of cluster */
                    223:   /* because of we did not know if stacker can subalocate clusters
                    224:      which are not in order we must check nonlinear
                    225:      suballocation */
                    226:   /* text above is question but now I know that stacker is able to do everything
                    227:      nonlinear suballocation regulary exist */
                    228:   if(last_sect&&(dblsb->s_cvf_version>=STAC4)&&(flg>=2))
                    229:   { /* check for subalocated end of cluster */
                    230:     /* 1) check start of next cluster for linear subalocation */
                    231:     if(clusternr<dblsb->s_max_cluster)
                    232:     { dbl_mdfat_value(sb,clusternr+1,NULL,&mde);
                    233:       i=(mde.sector_minus_1+1)==last_sect;
                    234:       if(i&&((mde.flags&0xA0)!=0xA0))
                    235:       { printk(KERN_ERR "DMSDOS: stac_cwalk_init: wrong cluster types for subalocation, cluster %d\n",
                    236:               clusternr);
                    237:         return -1;
                    238:       };
                    239:     } else i=0;
                    240:     /* 2) check for nonlinear subalocation */
                    241:     if((u=dbl_bitfat_value(sb,last_sect,NULL))==0) if(flg>=3)goto error1;
                    242:     if((u>1)||(i))
                    243:     { if((u<=1)&&(flg>=3))
                    244:       { printk(KERN_ERR "DMSDOS: stac_cwalk_init: suballocation error 1, cluster %d\n",
                    245:               clusternr);
                    246:         return -1;
                    247:       };
                    248:       if(!i)LOG_ALLOC("DMSDOS: stac_cwalk_init: nonlinear suballocation, cluster %d\n",
                    249:            clusternr);
                    250:       /* now we know that our cluster is subalocated, we must find
                    251:          number of bytes in last sector of cluster */
                    252:       bh=raw_bread(sb,last_sect);
                    253:       if(bh==NULL)return -1;
                    254:       pp=&(bh->b_data[SECTOR_SIZE-2]);
                    255:       if(CHS(pp)!=0x1234) 
                    256:       { printk(KERN_ERR "DMSDOS: stac_cwalk_init: suballocation error 2, cluster %d\n",
                    257:               clusternr);
                    258:         raw_brelse(sb,bh);
                    259:         return -1;
                    260:       };
                    261:       pp = &(bh->b_data[SECTOR_SIZE-6]);  /* begin of short suball. clust */
                    262:       u = CHS(pp) & (SECTOR_SIZE - 1);
                    263:       pp = &(bh->b_data[SECTOR_SIZE-8]);  /* begin of long suball. clust */
                    264:       v = CHS(pp) & (SECTOR_SIZE - 1);
                    265:       raw_brelse(sb,bh);
                    266:       /* u contains number of bytes of our cluster in last_sect */
                    267:       if(v<u)
                    268:       { 
                    269:         pp = &(bh->b_data[SECTOR_SIZE-6]);u = CHS(pp);
                    270:         pp = &(bh->b_data[SECTOR_SIZE-8]);v = CHS(pp);
                    271:         printk(KERN_ERR "DMSDOS: stac_cwalk_init: suballocation error 3, cluster %d, zerro offset 0x%X 0x%X\n",
                    272:                 clusternr,u,v);
                    273:         return -1;
                    274:       };
                    275:       cw->bytes_in_last=u;
                    276:       if(cw->sect_cnt>1)
                    277:         cw->bytes_in_clust-=SECTOR_SIZE-u;
                    278:       else if((i=cw->bytes+cw->offset-cw->bytes_in_last)>0)
                    279:       { if((cw->bytes-=i)<=0)
                    280:         { printk(KERN_ERR "DMSDOS: stac_cwalk_init: suballocation error 4, cluster %d\n",
                    281:                 clusternr);
                    282:           return -1;
                    283:         };
                    284:         cw->bytes_in_clust-=i;
                    285:       };
                    286:       cw->bytes_in_last|=0x4000;
                    287:     };
                    288:   };
                    289: 
                    290:   if ((i=cw->bytes_in_clust-dblsb->s_sectperclust*SECTOR_SIZE)>0)
                    291:   { cw->bytes_in_clust-=i;
                    292:     if(!cw->bytes_in_last) cw->bytes_in_last=SECTOR_SIZE-i;
                    293:     else if((cw->bytes_in_last-=i)<0x4000) 
                    294:     { error1:
                    295:       printk(KERN_ERR "DMSDOS: stac_cwalk_init: bad bytes_in_cluster %d\n",
                    296:               clusternr);
                    297:       return -1;
                    298:     };
                    299:   };
                    300: 
                    301:   return cw->bytes_in_clust;
                    302: };
                    303: 
                    304: /* returns in order all sectors of cluster */
                    305: /* in Stac_cwalk updates fields sect, offset and bytes */
                    306: int stac_cwalk_sector(Stac_cwalk *cw)
                    307: { if(!cw->sect)
                    308:   { if(!cw->fcnt) return 0;
                    309:     cw->fcnt--;
                    310:     cw->flen--;
                    311:     cw->sect=cw->start_sect;
                    312:   }
                    313:   else
                    314:   { if(!cw->flen)
                    315:     { if(!cw->fcnt) return 0;
                    316:       cw->fcnt--;
                    317:       if(cw->finfo==NULL)
                    318:       { printk(KERN_ERR "DMSDOS: stac_cwalk_sector: finfo==NULL, cluster %d\n",
                    319:                 cw->clusternr);
                    320:         return 0;
                    321:       };
                    322:       cw->sect=cw->finfo[0]+(cw->finfo[1]<<8)+((cw->finfo[3]&0x3f)<<16);
                    323:       cw->flen=(cw->finfo[2]&0xf)+((cw->finfo[3]>>2)&0x30);
                    324:       cw->finfo+=4;
                    325:     }
                    326:     else
                    327:     { cw->sect++;
                    328:       cw->flen--;
                    329:     };
                    330:     cw->offset=0;
                    331:     if(!cw->flen&&!cw->fcnt&&cw->bytes_in_last)
                    332:       cw->bytes=cw->bytes_in_last&(SECTOR_SIZE-1);
                    333:     else cw->bytes=SECTOR_SIZE;
                    334:   };
                    335:   return cw->sect;
                    336: };
                    337: 
                    338: void stac_cwalk_done(Stac_cwalk *cw)
                    339: {
                    340:   if(cw->fbh!=NULL) raw_brelse(cw->sb,cw->fbh);
                    341: };
                    342: 
                    343: 
                    344: void stac_special_free(struct super_block*sb, int clusternr)
                    345: { 
                    346:   int val;
                    347:   int sect;
                    348:   Mdfat_entry newmde,dummy_mde;
                    349:   Stac_cwalk cw;
                    350:   Dblsb*dblsb=MSDOS_SB(sb)->private_data;
                    351:   
                    352:   val=stac_cwalk_init(&cw,sb,clusternr,0);
                    353:   if(val<=0)
                    354:   { if(val<0)
                    355:       printk(KERN_ERR "DMSDOS: stac_special_free: alloc error in cluster %d\n", clusternr);
                    356:     else
                    357:       LOG_CLUST("DMSDOS: stac_special_free: already free cluster %d\n", clusternr);
                    358:     return;
                    359:   };
                    360:   newmde.sector_minus_1=-1;
                    361:   newmde.size_lo_minus_1=0;
                    362:   newmde.size_hi_minus_1=0;
                    363:   newmde.flags=0;
                    364:   
                    365:   dbl_mdfat_value(sb,clusternr,&newmde,&dummy_mde);
                    366:   if((cw.flags&0xA0)==0xA0)
                    367:   { /* mark part of suballocated sector as free */
                    368:     struct buffer_head *bh;
                    369:     bh=raw_bread(sb,cw.start_sect);
                    370:     if(bh!=NULL)
                    371:     { if(cw.start_len==1)
                    372:         bh->b_data[SECTOR_SIZE-6+1] |= 0x40;
                    373:       else
                    374:         bh->b_data[SECTOR_SIZE-8+1] |= 0x40;
                    375:       raw_mark_buffer_dirty(sb,bh,1);
                    376:       raw_brelse(sb,bh);
                    377:     }
                    378:   }
                    379:   /* free sectors from BITFAT */
                    380:   while((sect=stac_cwalk_sector(&cw))>0)
                    381:   {
                    382:     val=dbl_bitfat_value(sb,sect,NULL);
                    383:     if(val>0)
                    384:     { --val;
                    385:       dbl_bitfat_value(sb,sect,&val);
                    386:       dblsb->s_full=0;
                    387:       /* adapt s_free_sectors, -1 unknown */
                    388:       /*if(val==0&&dblsb->s_free_sectors>=0) dblsb->s_free_sectors++;*/
                    389:       /* Hi Pavel,
                    390:          I have commented this out since free sector count is now
                    391:          maintained in dbl_bitfat_value.
                    392:       */
                    393:     } else LOG_CLUST("DMSDOS: stac_special_free: sector not alocated\n");
                    394:   }
                    395:   
                    396:   stac_cwalk_done(&cw);
                    397:   
                    398: }
                    399: 
                    400: /* replaces an existing cluster for stacker;
                    401:    this unusual function must be called before rewriting any file cluster;
                    402:    *** size must be known (encoded in mde) ***
                    403:    it does nothing if called too often;
                    404:    returns first sector nr
                    405: */
                    406: 
                    407: int stac_replace_existing_cluster(struct super_block*sb, int cluster, 
                    408:                              int near_sector,
                    409:                              Mdfat_entry*mde)
                    410: { Mdfat_entry old_mde,new_mde,dummy;
                    411:   int i;
                    412:   int newval;
                    413:   int sector;
                    414:   int old_sector;
                    415:   int old_size;
                    416:   int new_size;
                    417:   Dblsb*dblsb=MSDOS_SB(sb)->private_data;
                    418: 
                    419:   lock_mdfat_alloc(dblsb);
                    420: 
                    421:   LOG_ALLOC("DMSDOS: stac_replace_existing_cluster cluster=%d near_sector=%d\n",
                    422:          cluster,near_sector);
                    423:   dbl_mdfat_value(sb,cluster,NULL,&old_mde);
                    424:   old_size=old_mde.size_lo_minus_1+1;
                    425:   old_sector=old_mde.sector_minus_1+1;
                    426:   new_size=mde->size_lo_minus_1+1;
                    427:   if(old_mde.flags&2)
                    428:   {
                    429:     /* stacker routines always replace mdfat entry */
                    430:     newval=0;
                    431:     LOG_ALLOC("DMSDOS: stac_replace_existing_cluster: freeing old sectors...\n");
                    432:     stac_special_free(sb,cluster);
                    433:     LOG_ALLOC("DMSDOS: stac_replace_existing_cluster: freeing finished\n");
                    434:   }
                    435:   LOG_ALLOC("DMSDOS: stac_replace_existing_cluster: call find_free_bitfat...\n");
                    436:   sector=find_free_bitfat(sb,near_sector,new_size);
                    437:   LOG_ALLOC("DMSDOS: stac_replace_existing_cluster: find_free_bitfat returned %d\n",
                    438:          sector);
                    439:   if(sector<=0)
                    440:   { if(old_mde.flags&2)
                    441:     { /* Stacker routines don't have an undo list for now.
                    442:          We cannot restore the state before. Sorry data are lost now. */
                    443:       new_mde.sector_minus_1=0;
                    444:       new_mde.size_lo_minus_1=0;
                    445:       new_mde.size_hi_minus_1=0;
                    446:       new_mde.flags=mde->flags=0;
                    447:       LOG_ALLOC("DMSDOS: stac_replace_existing_cluster: deleting mdfat entry...\n");
                    448:       dbl_mdfat_value(sb,cluster,&new_mde,&dummy);
                    449:     }
                    450:     unlock_mdfat_alloc(dblsb);
                    451:     return -ENOSPC; /* disk full */
                    452:   }
                    453:   /* check whether really free (bug supposed in find_free_bitfat) */
                    454:   for(i=0;i<new_size;++i)
                    455:   { if(dbl_bitfat_value(sb,sector+i,NULL))
                    456:     { printk(KERN_EMERG "DMSDOS: find_free_bitfat returned sector %d size %d but they are not all free!\n",
                    457:              sector,new_size);
                    458:       unlock_mdfat_alloc(dblsb);
                    459:       panic("DMSDOS: stac_replace_existing_cluster: This is a bug - reboot and check filesystem\n");
                    460:       return -EIO;
                    461:     }
                    462:   }
                    463:   newval=1;
                    464:   LOG_ALLOC("DMSDOS: stac_replace_existing_cluster: allocating in bitfat...\n");
                    465:   for(i=0;i<new_size;++i)dbl_bitfat_value(sb,sector+i,&newval);
                    466:   
                    467:   new_mde.sector_minus_1=sector-1;
                    468:   new_mde.size_lo_minus_1=mde->size_lo_minus_1;
                    469:   new_mde.size_hi_minus_1=mde->size_hi_minus_1;
                    470:   new_mde.flags=mde->flags|2;
                    471:   LOG_ALLOC("DMSDOS: stac_replace_existing_cluster: writing mdfat...\n");
                    472:   dbl_mdfat_value(sb,cluster,&new_mde,&dummy);
                    473:   unlock_mdfat_alloc(dblsb);
                    474:   return sector; /* okay */
                    475: }
                    476: 
                    477: #endif /* DMSDOS_CONFIG_STAC */

unix.superglobalmegacorp.com

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