|
|
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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.