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

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