|
|
1.1 root 1: /*
2: dblspace_dec.c
3:
4: DMSDOS CVF-FAT module: [dbl|drv]space cluster read and decompression 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/kernel.h>
31: #include <linux/sched.h>
32: #include <linux/errno.h>
33: #include <linux/string.h>
34: #include <linux/stat.h>
35: #include <linux/mm.h>
36: #include <linux/locks.h>
37: #include <linux/fs.h>
38: #include <linux/malloc.h>
39: #include <linux/msdos_fs.h>
40: #include <asm/system.h>
41: #include <asm/segment.h>
42: #include <asm/bitops.h>
43: #include <asm/byteorder.h>
44: #endif
45:
46: #include "dmsdos.h"
47:
48: #ifdef __DMSDOS_LIB__
49: /* some interface hacks */
50: #include"lib_interface.h"
51: #include<malloc.h>
52: #include<string.h>
53: #include<errno.h>
54: #include <asm/byteorder.h>
55: #endif
56:
57: #define INLINE static inline
58:
59: /* we always need DS decompression */
60:
61: #if defined(__GNUC__) && defined(__i386__) && defined(USE_ASM)
62: #define USE_GNU_ASM_i386
63:
64: /* copy block, overlaping part is replaced by repeat of previous part */
65: /* pointers and counter are modified to point after block */
66: #define M_MOVSB(D,S,C) \
67: __asm__ /*__volatile__*/(\
68: "cld\n\t" \
69: "rep\n\t" \
70: "movsb\n" \
71: :"=D" (D),"=S" (S),"=c" (C) \
72: :"0" (D),"1" (S),"2" (C) \
73: :"memory")
74:
75:
76: #else
77:
78: #warning USE_GNU_ASM_I386 not defined, using "C" equivalent
79:
80: #define M_MOVSB(D,S,C) for(;(C);(C)--) *((__u8*)(D)++)=*((__u8*)(S)++)
81:
82: #endif
83:
84: #if !defined(le16_to_cpu)
85: /* for old kernel versions - works only on i386 */
86: #define le16_to_cpu(v) (v)
87: #endif
88:
89: /* for reading and writting from/to bitstream */
90: typedef
91: struct {
92: __u32 buf; /* bit buffer */
93: int pb; /* already readed bits from buf */
94: __u16 *pd; /* first not readed input data */
95: __u16 *pe; /* after end of data */
96: } bits_t;
97:
98: const unsigned dblb_bmsk[]=
99: {0x0,0x1,0x3,0x7,0xF,0x1F,0x3F,0x7F,0xFF,
100: 0x1FF,0x3FF,0x7FF,0xFFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF};
101:
102: /* read next 16 bits from input */
103: #define RDN_G16(bits) \
104: { \
105: (bits).buf>>=16; \
106: (bits).pb-=16; \
107: if((bits).pd<(bits).pe) \
108: { \
109: (bits).buf|=((__u32)(le16_to_cpu(*((bits).pd++))))<<16; \
110: }; \
111: }
112:
113: /* prepares at least 16 bits for reading */
114: #define RDN_PR(bits,u) \
115: { \
116: if((bits).pb>=16) RDN_G16(bits); \
117: u=(bits).buf>>(bits).pb; \
118: }
119:
120: /* initializes reading from bitstream */
121: INLINE void dblb_rdi(bits_t *pbits,void *pin,unsigned lin)
122: {
123: pbits->pb=32;
124: pbits->pd=(__u16*)pin;
125: pbits->pe=pbits->pd+((lin+1)>>1);
126: }
127:
128: /* reads n<=16 bits from bitstream *pbits */
129: INLINE unsigned dblb_rdn(bits_t *pbits,int n)
130: {
131: unsigned u;
132: RDN_PR(*pbits,u);
133: pbits->pb+=n;
134: u&=dblb_bmsk[n];
135: return u;
136: }
137:
138: INLINE int dblb_rdoffs(bits_t *pbits)
139: { unsigned u;
140: RDN_PR(*pbits,u);
141: switch (u&3)
142: {
143: case 0: case 2:
144: pbits->pb+=1+6; return 63&(u>>1);
145: case 1:
146: pbits->pb+=2+8; return (255&(u>>2))+64;
147: }
148: pbits->pb+=2+12; return (4095&(u>>2))+320;
149: }
150:
151: INLINE int dblb_rdlen(bits_t *pbits)
152: { unsigned u;
153: RDN_PR(*pbits,u);
154: switch (u&15)
155: { case 1: case 3: case 5: case 7:
156: case 9: case 11: case 13: case 15:
157: pbits->pb++; return 3;
158: case 2: case 6:
159: case 10: case 14:
160: pbits->pb+=2+1; return (1&(u>>2))+4;
161: case 4: case 12:
162: pbits->pb+=3+2; return (3&(u>>3))+6;
163: case 8:
164: pbits->pb+=4+3; return (7&(u>>4))+10;
165: case 0: ;
166: }
167: switch ((u>>4)&15)
168: { case 1: case 3: case 5: case 7:
169: case 9: case 11: case 13: case 15:
170: pbits->pb+=5+4; return (15&(u>>5))+18;
171: case 2: case 6:
172: case 10: case 14:
173: pbits->pb+=6+5; return (31&(u>>6))+34;
174: case 4: case 12:
175: pbits->pb+=7+6; return (63&(u>>7))+66;
176: case 8:
177: pbits->pb+=8+7; return (127&(u>>8))+130;
178: case 0: ;
179: }
180: pbits->pb+=9;
181: if(u&256) return dblb_rdn(pbits,8)+258;
182: return -1;
183: }
184:
185: INLINE int dblb_decrep(bits_t *pbits, __u8 **p, void *pout, __u8 *pend,
186: int repoffs, int k, int flg)
187: { int replen;
188: __u8 *r;
189:
190: if(repoffs==0){LOG_DECOMP("DMSDOS: decrb: zero offset ?\n");return -2;}
191: if(repoffs==0x113f)
192: {
193: int pos=*p-(__u8*)pout;
194: LOG_DECOMP("DMSDOS: decrb: 0x113f sync found.\n");
195: if((pos%512) && !(flg&0x4000))
196: { LOG_DECOMP("DMSDOS: decrb: sync at decompressed pos %d ?\n",pos);
197: return -2;
198: }
199: return 0;
200: }
201: replen=dblb_rdlen(pbits)+k;
202:
203: if(replen<=0)
204: {LOG_DECOMP("DMSDOS: decrb: illegal count ?\n");return -2;}
205: if((__u8*)pout+repoffs>*p)
206: {LOG_DECOMP("DMSDOS: decrb: of>pos ?\n");return -2;}
207: if(*p+replen>pend)
208: {LOG_DECOMP("DMSDOS: decrb: output overfill ?\n");return -2;}
209: r=*p-repoffs;
210: M_MOVSB(*p,r,replen);
211: return 0;
212: }
213:
214: /* DS decompression */
215: /* flg=0x4000 is used, when called from stacker_dec.c, because of
216: stacker does not store original cluster size and it can mean,
217: that last cluster in file can be ended by garbage */
218: int ds_dec(void* pin,int lin, void* pout, int lout, int flg)
219: {
220: __u8 *p, *pend;
221: unsigned u, repoffs;
222: int r;
223: bits_t bits;
224:
225: dblb_rdi(&bits,pin,lin);
226: p=(__u8*)pout;pend=p+lout;
227: if((dblb_rdn(&bits,16))!=0x5344) return -1;
228:
229: u=dblb_rdn(&bits,16);
230: LOG_DECOMP("DMSDOS: DS decompression version %d\n",u);
231:
232: do
233: { r=0;
234: RDN_PR(bits,u);
235: switch(u&3)
236: {
237: case 0:
238: bits.pb+=2+6;
239: repoffs=(u>>2)&63;
240: r=dblb_decrep(&bits,&p,pout,pend,repoffs,-1,flg);
241: break;
242: case 1:
243: bits.pb+=2+7;
244: *(p++)=(u>>2)|128;
245: break;
246: case 2:
247: bits.pb+=2+7;
248: *(p++)=(u>>2)&127;
249: break;
250: case 3:
251: if(u&4) { bits.pb+=3+12; repoffs=((u>>3)&4095)+320; }
252: else { bits.pb+=3+8; repoffs=((u>>3)&255)+64; };
253: r=dblb_decrep(&bits,&p,pout,pend,repoffs,-1,flg);
254: break;
255: }
256: }while((r==0)&&(p<pend));
257:
258: if(r<0) return r;
259:
260: if(!(flg&0x4000))
261: {
262: u=dblb_rdn(&bits,3);if(u==7) u=dblb_rdn(&bits,12)+320;
263: if(u!=0x113f)
264: { LOG_DECOMP("DMSDOS: decrb: final sync not found?\n");
265: return -2;
266: }
267: }
268:
269: return p-(__u8*)pout;
270: }
271:
272: /* JM decompression */
273: int jm_dec(void* pin,int lin, void* pout, int lout, int flg)
274: {
275: __u8 *p, *pend;
276: unsigned u, repoffs;
277: int r;
278: bits_t bits;
279:
280: dblb_rdi(&bits,pin,lin);
281: p=(__u8*)pout;pend=p+lout;
282: if((dblb_rdn(&bits,16))!=0x4D4A) return -1;
283:
284: u=dblb_rdn(&bits,16);
285: LOG_DECOMP("DMSDOS: JM decompression version %d\n",u);
286:
287: do
288: { r=0;
289: RDN_PR(bits,u);
290: switch(u&3)
291: {
292: case 0:
293: case 2:
294: bits.pb+=8;
295: *(p++)=(u>>1)&127;
296: break;
297: case 1:
298: bits.pb+=2;
299: repoffs=dblb_rdoffs(&bits);
300: r=dblb_decrep(&bits,&p,pout,pend,repoffs,0,flg);
301: break;
302: case 3:
303: bits.pb+=9;
304: *(p++)=((u>>2)&127)|128;
305: break;
306: }
307: }
308: while((r==0)&&(p<pend));
309:
310: if(r<0) return r;
311:
312: if(!(flg&0x4000))
313: {
314: u=dblb_rdn(&bits,2);if(u==1) u=dblb_rdoffs(&bits);
315: if(u!=0x113f)
316: { LOG_DECOMP("DMSDOS: decrb: final sync not found?\n");
317: return -2;
318: }
319: }
320:
321: return p-(__u8*)pout;
322: }
323:
324:
325: /* decompress a compressed doublespace/drivespace cluster clusterk to clusterd
326: */
327: int dbl_decompress(unsigned char*clusterd, unsigned char*clusterk,
328: Mdfat_entry*mde)
329: {
330: int sekcount;
331: int r, lin, lout;
332:
333: sekcount=mde->size_hi_minus_1+1;
334: lin=(mde->size_lo_minus_1+1)*SECTOR_SIZE;
335: lout=(mde->size_hi_minus_1+1)*SECTOR_SIZE;
336:
337: switch(clusterk[0]+((int)clusterk[1]<<8)+
338: ((int)clusterk[2]<<16)+((int)clusterk[3]<<24))
339: {
340: case DS_0_0:
341: case DS_0_1:
342: case DS_0_2:
343: LOG_DECOMP("DMSDOS: decompressing DS-0-x\n");
344: r=ds_dec(clusterk,lin,clusterd,lout,0);
345: if(r<=0)
346: { printk(KERN_ERR "DMSDOS: error in DS-0-x compressed data.\n");
347: return -2;
348: }
349: LOG_DECOMP("DMSDOS: decompress finished.\n");
350: return 0;
351:
352: case JM_0_0:
353: case JM_0_1:
354: LOG_DECOMP("DMSDOS: decompressing JM-0-x\n");
355: r=jm_dec(clusterk,lin,clusterd,lout,0);
356: if(r<=0)
357: { printk(KERN_ERR "DMSDOS: error in JM-0-x compressed data.\n");
358: return -2;
359: }
360: LOG_DECOMP("DMSDOS: decompress finished.\n");
361: return 0;
362:
363: #ifdef DMSDOS_CONFIG_DRVSP3
364: case SQ_0_0:
365: LOG_DECOMP("DMSDOS: decompressing SQ-0-0\n");
366: r=sq_dec(clusterk,lin,clusterd,lout,0);
367: if(r<=0)
368: { printk(KERN_ERR "DMSDOS: SQ-0-0 decompression failed.\n");
369: return -1;
370: }
371: LOG_DECOMP("DMSDOS: decompress finished.\n");
372: return 0;
373: #endif
374:
375: default:
376: printk(KERN_ERR "DMSDOS: compression method not recognized.\n");
377: return -1;
378:
379: } /* end switch */
380:
381: return 0;
382: }
383:
384: #ifdef DMSDOS_CONFIG_DRVSP3
385: /* read the fragments of a fragmented cluster and assemble them */
386: /* warning: this is guessed from low level viewing drivespace 3 disks
387: and may be awfully wrong... we'll see... */
388: int read_fragments(struct super_block*sb,Mdfat_entry*mde, unsigned char*data)
389: { struct buffer_head*bh;
390: struct buffer_head*bh2;
391: int fragcount;
392: int fragpnt;
393: int offset;
394: int sector;
395: int seccount;
396: int membytes;
397: int safety_counter;
398: Dblsb*dblsb=MSDOS_SB(sb)->private_data;
399:
400: /* read first sector */
401: sector=mde->sector_minus_1+1;
402: bh=raw_bread(sb,sector);
403: if(bh==NULL)return -EIO;
404: fragcount=bh->b_data[0];
405: if(bh->b_data[1]!=0||bh->b_data[2]!=0||bh->b_data[3]!=0||fragcount<=0||
406: fragcount>dblsb->s_sectperclust)
407: { printk(KERN_ERR "DMSDOS: read_fragments: cluster does not look fragmented!\n");
408: raw_brelse(sb,bh);
409: return -EIO;
410: }
411: membytes=dblsb->s_sectperclust*SECTOR_SIZE;
412: if(mde->flags&1)
413: { offset=0;
414: safety_counter=0;
415: }
416: else
417: { offset=(fragcount+1)*4;
418: /* copy the rest of the sector */
419: memcpy(data,&(bh->b_data[offset]),SECTOR_SIZE-offset);
420: data+=(SECTOR_SIZE-offset);
421: safety_counter=SECTOR_SIZE-offset;
422: }
423: ++sector;
424: seccount=mde->size_lo_minus_1;
425: fragpnt=1;
426: while(fragpnt<=fragcount)
427: { if(fragpnt>1)
428: { /* read next fragment pointers */
429: seccount=bh->b_data[fragpnt*4+3];
430: seccount&=0xff;
431: seccount/=4;
432: seccount+=1;
433: sector=bh->b_data[fragpnt*4];
434: sector&=0xff;
435: sector+=bh->b_data[fragpnt*4+1]<<8;
436: sector&=0xffff;
437: sector+=bh->b_data[fragpnt*4+2]<<16;
438: sector&=0xffffff;
439: sector+=1;
440: }
441: while(seccount)
442: { bh2=raw_bread(sb,sector);
443: if(bh2==NULL){raw_brelse(sb,bh);return -EIO;}
444: /*printk(KERN_DEBUG "DMSDOS: read_fragments: data=0x%p safety_counter=0x%x sector=%d\n",
445: data,safety_counter,sector);*/
446: if(safety_counter+SECTOR_SIZE>membytes)
447: { int maxbytes=membytes-safety_counter;
448: if(maxbytes<=0)
449: { printk(KERN_WARNING "DMSDOS: read_fragments: safety_counter exceeds membytes!\n");
450: raw_brelse(sb,bh2);
451: raw_brelse(sb,bh);
452: return -EIO;
453: }
454: printk(KERN_DEBUG "DMSDOS: read_fragments: size limit reached.\n");
455: memcpy(data,bh2->b_data,maxbytes);
456: raw_brelse(sb,bh2);
457: raw_brelse(sb,bh);
458: return membytes;
459: }
460: else memcpy(data,bh2->b_data,SECTOR_SIZE);
461: raw_brelse(sb,bh2);
462: data+=SECTOR_SIZE;
463: safety_counter+=SECTOR_SIZE;
464: ++sector;
465: --seccount;
466: }
467: ++fragpnt;
468: }
469: raw_brelse(sb,bh);
470:
471: return safety_counter;
472: }
473: #endif
474:
475: #ifdef DMSDOS_CONFIG_DBL
476: /* read a complete file cluster and decompress it if necessary;
477: this function is unable to read cluster 0 (CVF root directory) */
478: /* returns cluster length in bytes or error (<0) */
479: /* this function is specific to doublespace/drivespace */
480: int dbl_read_cluster(struct super_block*sb,
481: unsigned char*clusterd, int clusternr)
482: { Mdfat_entry mde;
483: unsigned char*clusterk;
484: int nr_of_sectors;
485: int i;
486: struct buffer_head*bh;
487: int membytes;
488: int sector;
489: Dblsb*dblsb=MSDOS_SB(sb)->private_data;
490:
491: LOG_CLUST("DMSDOS: dbl_read_cluster %d\n",clusternr);
492:
493: dbl_mdfat_value(sb,clusternr,NULL,&mde);
494:
495: if((mde.flags&2)==0)
496: { /* hmm, cluster is unused (it's a lost or ghost cluster)
497: and contains undefined data, but it *is* readable */
498: /* oh no, it contains ZEROD data per definition...
499: this is really important */
500: if(clusterd) /*clusterd==NULL means read_ahead - don't do anything*/
501: memset(clusterd,0,dblsb->s_sectperclust*SECTOR_SIZE);
502: LOG_CLUST("DMSDOS: lost cluster %d detected\n",clusternr);
503: return 0; /* yes, has length zero */
504: }
505:
506: sector=mde.sector_minus_1+1;
507: nr_of_sectors=mde.size_lo_minus_1+1;/* real sectors on disk */
508: if(nr_of_sectors>dblsb->s_sectperclust)
509: { printk(KERN_WARNING "DMSDOS: read_cluster: mdfat sectors > sectperclust, cutting\n");
510: nr_of_sectors=dblsb->s_sectperclust;
511: }
512:
513: if(clusterd==NULL)
514: { /* read-ahead */
515: dblspace_reada(sb,sector,nr_of_sectors);
516: return 0;
517: }
518:
519: #ifdef DMSDOS_CONFIG_DRVSP3
520: if(mde.unknown&2)
521: { /* we suppose this bit indicates a fragmented cluster */
522: /* this is *not sure* and may be awfully wrong - reports
523: whether success or not are welcome
524: */
525:
526: LOG_CLUST("DMSDOS: cluster %d has unknown bit #1 set. Assuming fragmented cluster.\n",
527: clusternr);
528:
529: if(mde.flags&1) /* not compressed */
530: { LOG_CLUST("DMSDOS: uncompressed fragmented cluster\n");
531: i=read_fragments(sb,&mde,clusterd);
532: if(i<0)
533: { printk(KERN_ERR "DMSDOS: read_fragments failed!\n");
534: return i;
535: }
536: }
537: else
538: { LOG_CLUST("DMSDOS: compressed fragmented cluster\n");
539: membytes=SECTOR_SIZE*dblsb->s_sectperclust;
540:
541: clusterk=(unsigned char*)MALLOC(membytes);
542: if(clusterk==NULL)
543: { printk(KERN_ERR "DMSDOS: no memory for decompression!\n");
544: return -2;
545: }
546: /* returns length in bytes */
547: i=read_fragments(sb,&mde,clusterk);
548: if(i<0)
549: { printk(KERN_ERR "DMSDOS: read_fragments failed!\n");
550: return i;
551: }
552: /* correct wrong size_lo information (sq_dec needs it) */
553: if(i>0)mde.size_lo_minus_1=(i-1)/SECTOR_SIZE;
554: i=dbl_decompress(clusterd,clusterk,&mde);
555:
556: FREE(clusterk);
557:
558: if(i)
559: { printk(KERN_ERR "DMSDOS: decompression of cluster %d in CVF failed.\n",
560: clusternr);
561: return i;
562: }
563:
564: }
565:
566: /* the slack must be zerod out */
567: if(mde.size_hi_minus_1+1<dblsb->s_sectperclust)
568: { memset(clusterd+(mde.size_hi_minus_1+1)*SECTOR_SIZE,0,
569: (dblsb->s_sectperclust-mde.size_hi_minus_1-1)*
570: SECTOR_SIZE);
571: }
572:
573: return (mde.size_hi_minus_1+1)*SECTOR_SIZE;
574:
575: } /* end of read routine for fragmented cluster */
576: #endif
577:
578: if(mde.flags&1)
579: { /* cluster is not compressed */
580: for(i=0;i<nr_of_sectors;++i)
581: { bh=raw_bread(sb,sector+i);
582: if(bh==NULL)return -EIO;
583: memcpy(&clusterd[i*SECTOR_SIZE],bh->b_data,SECTOR_SIZE);
584: raw_brelse(sb,bh);
585: }
586: }
587: else
588: { /* cluster is compressed */
589:
590: membytes=SECTOR_SIZE*nr_of_sectors;
591:
592: clusterk=(unsigned char*)MALLOC(membytes);
593: if(clusterk==NULL)
594: { printk(KERN_ERR "DMSDOS: no memory for decompression!\n");
595: return -2;
596: }
597:
598: for(i=0;i<nr_of_sectors;++i)
599: { bh=raw_bread(sb,sector+i);
600: if(bh==NULL)
601: { FREE(clusterk);
602: return -EIO;
603: }
604: memcpy(&clusterk[i*SECTOR_SIZE],bh->b_data,SECTOR_SIZE);
605: raw_brelse(sb,bh);
606: }
607:
608: i=dbl_decompress(clusterd,clusterk,&mde);
609:
610: FREE(clusterk);
611:
612: if(i)
613: { printk(KERN_ERR "DMSDOS: decompression of cluster %d in CVF failed.\n",
614: clusternr);
615: return i;
616: }
617:
618: }
619:
620: /* the slack must be zerod out */
621: if(mde.size_hi_minus_1+1<dblsb->s_sectperclust)
622: { memset(clusterd+(mde.size_hi_minus_1+1)*SECTOR_SIZE,0,
623: (dblsb->s_sectperclust-mde.size_hi_minus_1-1)*
624: SECTOR_SIZE);
625: }
626:
627: return (mde.size_hi_minus_1+1)*SECTOR_SIZE;
628: }
629: #endif
630:
631: /* read a complete file cluster and decompress it if necessary;
632: it must be able to read directories
633: this function is unable to read cluster 0 (CVF root directory) */
634: /* returns cluster length in bytes or error (<0) */
635: /* this function is a generic wrapper */
636: int dmsdos_read_cluster(struct super_block*sb,
637: unsigned char*clusterd, int clusternr)
638: { int ret;
639: Dblsb*dblsb=MSDOS_SB(sb)->private_data;
640:
641: LOG_CLUST("DMSDOS: read_cluster %d\n",clusternr);
642:
643: switch(dblsb->s_cvf_version)
644: {
645: #ifdef DMSDOS_CONFIG_DBL
646: case DBLSP:
647: case DRVSP:
648: case DRVSP3:
649: ret=dbl_read_cluster(sb,clusterd,clusternr);
650: break;
651: #endif
652: #ifdef DMSDOS_CONFIG_STAC
653: case STAC3:
654: case STAC4:
655: ret=stac_read_cluster(sb,clusterd,clusternr);
656: break;
657: #endif
658: default:
659: printk(KERN_ERR "DMSDOS: read_cluster: illegal cvf version flag!\n");
660: ret=-EIO;
661: }
662:
663: return ret;
664: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.