|
|
1.1 root 1: /*
2: dblspace_interface.c
3:
4: DMSDOS CVF-FAT module: high-level interface functions.
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/fs.h>
31: # include <linux/blkdev.h>
32: # include <linux/msdos_fs.h>
33: # include <linux/msdos_fs_sb.h>
34: # include <linux/fat_cvf.h>
35: # include <linux/string.h>
36: # include <linux/malloc.h>
37: # include <asm/semaphore.h>
38: # include <linux/module.h>
39: #endif
40:
41: #include"dmsdos.h"
42:
43: #ifdef __DMSDOS_LIB__
44: /* some interface hacks */
45: # include"lib_interface.h"
46: # include<string.h>
47: # include<malloc.h>
48: # define MAJOR(x) 0
49: # define MINOR(x) 0
50: extern long int blk_size[0][0];
51: #endif
52:
53: extern Acache mdfat[];
54: extern Acache dfat[];
55: extern Acache bitfat[];
56:
57: unsigned long loglevel=DEFAULT_LOGLEVEL;
58: unsigned long dmsdos_speedup=DEFAULT_SPEEDUP;
59:
60: /* evaluate numbers from options */
61: char* read_number(char*p, unsigned long* n, int*error)
62: { *n=0;
63: *error=-1;
64: if(*p=='b'||*p=='B'||*p=='%')
65: { /*binary*/
66: ++p;
67: while(*p=='0'||*p=='1')
68: { (*n)*=2;
69: if(*p=='1')++(*n);
70: ++p;
71: *error=0;
72: }
73: }
74: else if(*p=='0'&&(*(p+1)=='x'||*(p+1)=='X'))
75: { /*hexadecimal*/
76: p+=2;
77: while((*p>='0'&&*p<='9')||(*p>='a'&&*p<='f')||(*p>='A'&&*p<='F'))
78: { (*n)*=16;
79: (*n)+=((*p<='9')?(*p):(*p)-'a'+10)&0xf;
80: ++p;
81: *error=0;
82: }
83: }
84: else if(*p=='0'||*p=='O'||*p=='o')
85: { /*octal*/
86: ++p;
87: while(*p>='0'&&*p<='8')
88: { (*n)*=8;
89: (*n)+=(*p)-'0';
90: ++p;
91: *error=0;
92: }
93: }
94: else
95: { /*decimal*/
96: while(*p>='0'&&*p<='9')
97: { (*n)*=10;
98: (*n)+=(*p)-'0';
99: ++p;
100: *error=0;
101: }
102: }
103: LOG_REST("DMSDOS: read_number: n=%lu=0x%lx error=%d\n",*n,*n,*error);
104: return p;
105: }
106:
107: /* evaluates a single option (needn't be '\0' terminated) */
108: int evaluate_option(char*option,Dblsb*dblsb,int*repair)
109: { int ret=0;
110:
111: LOG_REST("DMSDOS: evaluate option: %s\n",option);
112: if(strncmp(option,"comp=",5)==0||strncmp(option,"comp:",5)==0)
113: { if(strncmp(option+5,"no",2)==0)dblsb->s_comp=UNCOMPRESSED;
114: /*else if(strncmp(option+5,"ro",2)==0)*comp=READ_ONLY;*/
115: else if(strncmp(option+5,"ds00",4)==0)dblsb->s_comp=DS_0_0;
116: else if(strncmp(option+5,"ds01",4)==0)dblsb->s_comp=DS_0_1;
117: else if(strncmp(option+5,"ds02",4)==0)dblsb->s_comp=DS_0_2;
118: else if(strncmp(option+5,"jm00",4)==0)dblsb->s_comp=JM_0_0;
119: else if(strncmp(option+5,"jm01",4)==0)dblsb->s_comp=JM_0_1;
120: else if(strncmp(option+5,"sq00",4)==0)dblsb->s_comp=SQ_0_0;
121: else if(strncmp(option+5,"sd3",3)==0)dblsb->s_comp=SD_3;
122: else if(strncmp(option+5,"sd4",3)==0)dblsb->s_comp=SD_4;
123: else if(strncmp(option+5,"guess",5)==0)dblsb->s_comp=GUESS;
124: else ret=-1;
125: }
126: else if(strncmp(option,"cf=",3)==0||strncmp(option,"cf:",3)==0)
127: { if(option[3]=='1'&&option[4]>='0'&&option[4]<='2')
128: dblsb->s_cfaktor=option[4]-'0'+9;
129: else if(option[3]>='1'&&option[3]<='9')
130: dblsb->s_cfaktor=option[3]-'0'-1;
131: else ret=-1;
132: }
133: else if(strncmp(option,"loglevel=",9)==0||strncmp(option,"loglevel:",9)==0)
134: { /* must be decimal or hexadecimal (0x preceeded) number */
135: read_number(option+9,&loglevel,&ret);
136: if(ret>=0)
137: LOG_REST("DMSDOS: evaluate_option: loglevel set to 0x%lx.\n",loglevel);
138: }
139: else if(strncmp(option,"speedup=",8)==0||strncmp(option,"speedup:",8)==0)
140: { /* must be decimal or hexadecimal (0x preceeded) number */
141: read_number(option+8,&dmsdos_speedup,&ret);
142: if(ret>=0)
143: LOG_REST("DMSDOS: evaluate_option: speedup set to 0x%lx.\n",dmsdos_speedup);
144: }
145: else if(strncmp(option,"bitfaterrs=",11)==0||strncmp(option,"bitfaterrs:",11)==0)
146: { if(strncmp(option+11,"repair",6)==0)*repair=1;
147: else if(strncmp(option+11,"ignore",6)==0)*repair=2;
148: else if(strncmp(option+11,"setro",5)==0)*repair=0;
149: else if(strncmp(option+11,"nocheck",7)==0)*repair=-1;
150: else ret=-1;
151: }
152: else
153: { printk(KERN_ERR "DMSDOS: unknown option %s, rejected\n",option);
154: ret=-1;
155: }
156: return ret;
157: }
158:
159: int parse_dmsdos_options(char*options,Dblsb*dblsb,int*repair)
160: { if(options==NULL)return 0;
161:
162: while(*options)
163: { if(evaluate_option(options,dblsb,repair)<0)return -1;
164: while(*options!='\0'&&*options!='.'&&*options!='+')++options;
165: while(*options=='.'||*options=='+')++options;
166: }
167: return 0;
168: }
169:
170: int ilog2(int arg)
171: { /* integer log2 */
172: int i=0;
173:
174: if(arg<=0)return -1;
175:
176: while(arg>>=1)++i;
177: return i;
178: }
179:
180: #ifndef __DMSDOS_LIB__
181: void do_spc_init(void)
182: { /* first call of DMSDOS filesystem, initialising variables */
183: int i;
184:
185: printk(KERN_NOTICE "DMSDOS CVF-FAT extension version %d.%d.%d" DMSDOS_VLT
186: " compiled " __DATE__ " " __TIME__ " with options:"
187: #ifndef DBL_WRITEACCESS
188: " read-only"
189: #else
190: " read-write"
191: #endif
192: #ifdef USE_XMALLOC
193: ", xmalloc"
194: #else
195: #ifdef USE_VMALLOC
196: ", vmalloc"
197: #else
198: ", kmalloc"
199: #endif
200: #endif
201: #ifdef DMSDOS_USE_READPAGE
202: ", readpage"
203: #endif
204: #ifdef USE_READA_LIST
205: ", reada list"
206: #endif
207: #ifdef INTERNAL_DAEMON
208: ", internal daemon"
209: #endif
210: #ifdef DMSDOS_CONFIG_DBLSP_DRVSP
211: ", doublespace/drivespace(<3)"
212: #endif
213: #ifdef DMSDOS_CONFIG_DRVSP3
214: ", drivespace 3"
215: #endif
216: #ifdef DMSDOS_CONFIG_STAC3
217: ", stacker 3"
218: #endif
219: #ifdef DMSDOS_CONFIG_STAC4
220: ", stacker 4"
221: #endif
222: "\n",
223: DMSDOS_MAJOR,DMSDOS_MINOR,DMSDOS_ACT_REL);
224:
225: /* init cluster cache */
226: ccache_init();
227:
228: /* no this is done by mount ... and removed by unmount
229: otherwise the module cannot be unloaded again if the
230: internal daemon is running
231: init_daemon();
232: */
233:
234: #ifdef USE_READA_LIST
235: init_reada_list();
236: #endif
237:
238: for(i=0;i<MDFATCACHESIZE;++i)
239: { mdfat[i].a_time=0;
240: mdfat[i].a_acc=0;
241: mdfat[i].a_buffer=NULL;
242: }
243: for(i=0;i<DFATCACHESIZE;++i)
244: { dfat[i].a_time=0;
245: dfat[i].a_acc=0;
246: dfat[i].a_buffer=NULL;
247: }
248: for(i=0;i<BITFATCACHESIZE;++i)
249: { bitfat[i].a_time=0;
250: bitfat[i].a_acc=0;
251: bitfat[i].a_buffer=NULL;
252: }
253: }
254:
255: void do_spc_exit(void)
256: {
257: force_exit_daemon();
258: }
259: #endif
260:
261: #ifdef DMSDOS_CONFIG_DBL
262: int detect_dblspace(struct super_block*sb)
263: { struct buffer_head*bh;
264:
265: MOD_INC_USE_COUNT;
266: bh=raw_bread(sb,0);
267: if(bh==NULL)
268: { printk(KERN_ERR "DMSDOS: unable to read super block\n");
269: MOD_DEC_USE_COUNT;
270: return 0;
271: }
272: if(strncmp(bh->b_data+3,"MSDBL6.0",8)==0
273: ||strncmp(bh->b_data+3,"MSDSP6.0",8)==0)
274: { raw_brelse(sb,bh);
275: MOD_DEC_USE_COUNT;
276: return 1;
277: }
278: raw_brelse(sb,bh);
279: MOD_DEC_USE_COUNT;
280: return 0;
281: }
282:
283: int mount_dblspace(struct super_block*sb,char*options)
284: { struct buffer_head*bh;
285: struct buffer_head*bh2;
286: int i,mdfatb,fatb;
287: unsigned int version_flag;
288: unsigned char * pp;
289: Dblsb* dblsb;
290: int repair=0;
291: int mdrc,m_sector=0;
292:
293: MOD_INC_USE_COUNT;
294: LOG_REST("DMSDOS: dblspace/drvspace module mounting...\n");
295: bh=raw_bread(sb,0);
296: if(bh==NULL)
297: { printk(KERN_ERR "DMSDOS: unable to read super block\n");
298: MOD_DEC_USE_COUNT;
299: return -1;
300: }
301: if(strncmp(bh->b_data+3,"MSDBL6.0",8)&&strncmp(bh->b_data+3,"MSDSP6.0",8))
302: { printk(KERN_ERR "DMSDOS: MSDBL/MSDSP signature not found, CVF skipped\n");
303: raw_brelse(sb,bh);
304: MOD_DEC_USE_COUNT;
305: return -1;
306: }
307: dblsb=kmalloc(sizeof(Dblsb),GFP_KERNEL);
308: if(dblsb==NULL)
309: { printk(KERN_ERR "DMSDOS: mount_dblspace: out of memory\n");
310: raw_brelse(sb,bh);
311: MOD_DEC_USE_COUNT;
312: return -1;
313: }
314: MSDOS_SB(sb)->private_data=dblsb;
315: /*dblsb->mdfat_alloc_sem=MUTEX;*/
316:
317: #ifdef __KERNEL__
318: { struct semaphore* sem;
319:
320: sem=kmalloc(sizeof(struct semaphore),GFP_KERNEL);
321: if(sem==NULL)
322: { printk(KERN_ERR "DMSDOS: mount_dblspace: out of memory\n");
323: raw_brelse(sb,bh);
324: MOD_DEC_USE_COUNT;
325: return -1;
326: }
327: *sem=MUTEX;
328: dblsb->mdfat_alloc_semp=sem;
329: }
330: #endif
331:
332: /* find out size */
333: dblsb->s_dataend=blk_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)]*2;
334:
335: dblsb->s_comp=GUESS;
336: dblsb->s_cfaktor=DEFAULT_CF;
337:
338: if(parse_dmsdos_options(options,dblsb,&repair))
339: {
340: raw_brelse(sb,bh);
341: MOD_DEC_USE_COUNT;
342: return -1;
343: }
344:
345:
346: if(sb->s_flags & MS_RDONLY)dblsb->s_comp=READ_ONLY;
347: printk(KERN_INFO "DMSDOS: mounting CVF on device 0x%x %s...\n",
348: sb->s_dev,
349: dblsb->s_comp==READ_ONLY?"read-only":"read-write");
350:
351: /* dblspace correction was relocated. Pavel */
352: dblsb->s_dataend-=1;
353:
354: pp=&(bh->b_data[45]);
355: dblsb->s_dcluster=CHS(pp);
356: if(dblsb->s_dcluster&0x8000)dblsb->s_dcluster|=0xffff0000;
357: pp=&(bh->b_data[36]);
358: dblsb->s_mdfatstart=CHS(pp)+1;
359: pp=&(bh->b_data[17]);
360: dblsb->s_rootdirentries=CHS(pp);
361: dblsb->s_sectperclust=((unsigned long)(bh->b_data[13]));
362: dblsb->s_spc_bits=ilog2(dblsb->s_sectperclust);
363: pp=&(bh->b_data[39]);i=CHS(pp);/*i=res0*/
364: dblsb->s_bootblock=i;
365: pp=&(bh->b_data[14]);
366: dblsb->s_fatstart=i+CHS(pp);
367: pp=&(bh->b_data[41]);
368: dblsb->s_rootdir=i+CHS(pp);
369: pp=&(bh->b_data[43]);
370: dblsb->s_datastart=i+CHS(pp)+2;
371: dblsb->s_2nd_fat_offset=0; /* dblsp doesn't have a second fat */
372: dblsb->s_cvf_version=DBLSP;
373: version_flag=bh->b_data[51];
374: if(version_flag==2)dblsb->s_cvf_version=DRVSP;
375: if(version_flag==3||dblsb->s_sectperclust>16)dblsb->s_cvf_version=DRVSP3;
376: if(version_flag>3)printk(KERN_WARNING "DMSDOS: strange version flag %d, assuming 0.\n",
377: version_flag);
378:
379: #ifndef DMSDOS_CONFIG_DBLSP_DRVSP
380: if(dblsb->s_cvf_version<=DRVSP)
381: { printk(KERN_ERR "DMSDOS: support for doublespace/drivespace(<3) not compiled in.\n");
382: raw_brelse(sb,bh);
383: MOD_DEC_USE_COUNT;
384: return -1;
385: }
386: #endif
387: #ifndef DMSDOS_CONFIG_DRVSP3
388: if(dblsb->s_cvf_version==DRVSP3)
389: { printk(KERN_ERR "DMSDOS: support for drivespace 3 not compiled in.\n");
390: raw_brelse(sb,bh);
391: MOD_DEC_USE_COUNT;
392: return -1;
393: }
394: #endif
395:
396: bh2=raw_bread(sb,dblsb->s_bootblock);
397: if(bh2==NULL)
398: { printk(KERN_ERR "DMSDOS: unable to read emulated boot block\n");
399: raw_brelse(sb,bh);
400: MOD_DEC_USE_COUNT;
401: return -1;
402: }
403: pp=&(bh2->b_data[57]);
404: if(CHL(pp)==0x20203631)dblsb->s_16bitfat=1;
405: else if(CHL(pp)==0x20203231)dblsb->s_16bitfat=0;
406: else if(CHL(pp)==0x20203233)
407: { printk(KERN_ERR "DMSDOS: CVF has FAT32 signature, not mounted. Please report this.\n");
408: raw_brelse(sb,bh2);
409: raw_brelse(sb,bh);
410: MOD_DEC_USE_COUNT;
411: return -1;
412: }
413: else
414: { pp=&(bh->b_data[62]);
415: dblsb->s_16bitfat=(CHS(pp)>32) ? 1 : 0;
416: printk(KERN_WARNING "DMSDOS: FAT bit size not recognized, guessed %d bit\n",
417: CHS(pp)>32 ? 16 : 12 );
418: }
419: raw_brelse(sb,bh2);
420:
421: /* try to verify correct end of CVF */
422: mdrc=0;
423: for(i=-1;i<=1;++i)
424: { bh2=raw_bread(sb,dblsb->s_dataend+i);
425: if(bh2==NULL)
426: { LOG_REST("DMSDOS: MDR test breaks at i=%d\n",i);
427: break;
428: }
429: if(strcmp(bh2->b_data,"MDR")==0)
430: { ++mdrc;
431: m_sector=dblsb->s_dataend+i;
432: LOG_REST("DMSDOS: MDR signature found at sector %d\n",m_sector);
433: }
434: raw_brelse(sb,bh2);
435: }
436: if(mdrc!=1)
437: printk(KERN_WARNING "DMSDOS: could not find MDR signature or found more than one, mdrc=%d (ignored)\n",
438: mdrc);
439: else
440: { if(dblsb->s_dataend!=m_sector-1)
441: { LOG_REST("DMSDOS: dataend corrected due to MDR signature old=%d new=%d\n",
442: dblsb->s_dataend,m_sector-1);
443: dblsb->s_dataend=m_sector-1;
444: }
445: }
446:
447: dblsb->s_full=0;
448:
449: /* calculate maximum cluster nr (fixes lost cluster messages) */
450: mdfatb=(dblsb->s_bootblock-dblsb->s_mdfatstart);
451: mdfatb*=((dblsb->s_sectperclust>16)?102:128);
452: mdfatb-=dblsb->s_dcluster;
453: fatb=512*(dblsb->s_rootdir-dblsb->s_fatstart);
454: if(dblsb->s_16bitfat)fatb/=2; else fatb=(2*fatb)/3;
455: dblsb->s_max_cluster=((mdfatb<fatb)?mdfatb:fatb)-1;
456: if(dblsb->s_16bitfat)
457: { if(dblsb->s_max_cluster>0xFFF6)dblsb->s_max_cluster=0xFFF6;
458: }
459: else
460: { if(dblsb->s_max_cluster>0xFF6)dblsb->s_max_cluster=0xFF6;
461: }
462:
463: /* adapt max_cluster according to dos' limits */
464: dblsb->s_max_cluster2=dblsb->s_max_cluster;
465: pp=&(bh->b_data[32]);
466: i=CHL(pp);
467: pp=&(bh->b_data[22]);
468: i-=CHS(pp);
469: pp=&(bh->b_data[14]);
470: i-=CHS(pp);
471: i-=dblsb->s_rootdirentries>>4;
472: /*i=(i>>4)+1;*/
473: i=(i/dblsb->s_sectperclust)+1;
474: if(i<=dblsb->s_max_cluster)
475: { dblsb->s_max_cluster=i;
476: }
477: else
478: { printk(KERN_WARNING "DMSDOS: dos max_cluster=%d too large, cutting to %d.\n",
479: i,dblsb->s_max_cluster);
480: }
481:
482: LOG_REST("DMSDOS: dcluster=%d\n",dblsb->s_dcluster);
483: LOG_REST("DMSDOS: mdfatstart=%d\n",dblsb->s_mdfatstart);
484: LOG_REST("DMSDOS: rootdirentries=%d\n",dblsb->s_rootdirentries);
485: LOG_REST("DMSDOS: sectperclust=%d\n",dblsb->s_sectperclust);
486: LOG_REST("DMSDOS: fatstart=%d\n",dblsb->s_fatstart);
487: LOG_REST("DMSDOS: rootdir=%d\n",dblsb->s_rootdir);
488: LOG_REST("DMSDOS: %d bit FAT\n",dblsb->s_16bitfat ? 16 : 12);
489:
490: dblsb->s_lastnear=0;
491: dblsb->s_lastbig=0;
492: dblsb->s_free_sectors=-1; /* -1 means unknown */
493:
494: /* error test (counts sectors) */
495: if(repair!=-1) /* repair==-1 means do not even check */
496: {
497: i=simple_check(sb,repair&1);
498: if(i==-1||i==-2)
499: { printk(KERN_WARNING "DMSDOS: CVF has serious errors or compatibility problems, setting to read-only.\n");
500: dblsb->s_comp=READ_ONLY;
501: }
502: if(i==-3)
503: { if(repair&2)
504: { printk(KERN_WARNING "DMSDOS: CVF has bitfat mismatches, ignored.\n");
505: }
506: else
507: { printk(KERN_WARNING "DMSDOS: CVF has bitfat mismatches, setting to read-only.\n");
508: dblsb->s_comp=READ_ONLY;
509: }
510: }
511: }
512:
513: /* if still unknown then count now */
514: if(dblsb->s_free_sectors<0)check_free_sectors(sb);
515:
516: /* print doublespace version */
517: if(dblsb->s_cvf_version==DBLSP&&dblsb->s_sectperclust==16)
518: { printk(KERN_INFO "DMSDOS: CVF is in doublespace format (version 1).\n");
519: }
520: else if(dblsb->s_cvf_version==DRVSP&&dblsb->s_sectperclust==16)
521: { printk(KERN_INFO "DMSDOS: CVF is in drivespace format (version 2).\n");
522: }
523: else if(dblsb->s_cvf_version==DRVSP3&&dblsb->s_sectperclust==64)
524: { printk(KERN_INFO "DMSDOS: CVF is in drivespace 3 format.\n");
525: }
526: else
527: { printk(KERN_INFO "DMSDOS: CVF is in unknown (new?) format, please report.\n");
528: printk(KERN_INFO "DMSDOS: version_flag=%d sectperclust=%d\n",version_flag,
529: dblsb->s_sectperclust);
530: printk(KERN_NOTICE "DMSDOS: CVF set to read-only.\n");
531: dblsb->s_comp=READ_ONLY;
532: }
533:
534: raw_brelse(sb,bh);
535:
536: /* set some msdos fs important stuff */
537: MSDOS_SB(sb)->dir_start=FAKED_ROOT_DIR_OFFSET;
538: MSDOS_SB(sb)->dir_entries=dblsb->s_rootdirentries;
539: MSDOS_SB(sb)->data_start=FAKED_DATA_START_OFFSET; /*begin of virtual cluster 2*/
540: MSDOS_SB(sb)->clusters=dblsb->s_max_cluster;
541: if(MSDOS_SB(sb)->fat_bits!=dblsb->s_16bitfat?16:12)
542: { LOG_REST("DMSDOS: fat bit size mismatch in fat driver, trying to correct\n");
543: MSDOS_SB(sb)->fat_bits=dblsb->s_16bitfat?16:12;
544: }
545: MSDOS_SB(sb)->cluster_size=dblsb->s_sectperclust;
546:
547: /* these *must* always match */
548: if(dblsb->s_comp==READ_ONLY)sb->s_flags |= MS_RDONLY;
549:
550: /* we allow using the daemon - calling this more than once doesn't matter */
551: init_daemon();
552:
553: return 0;
554: }
555: #endif
556:
557: int unmount_dblspace(struct super_block*sb)
558: { int j;
559: #if defined(__KERNEL__)||defined(DMSDOS_CONFIG_STAC)
560: Dblsb*dblsb=MSDOS_SB(sb)->private_data;
561: #endif
562:
563: LOG_REST("DMSDOS: CVF on device 0x%x unmounted.\n",sb->s_dev);
564:
565: /* discard/write cached clusters */
566: free_ccache_dev(sb);
567: /* the same for the daemon if it is running */
568: clear_list_dev(sb);
569:
570: #ifdef DMSDOS_CONFIG_STAC
571: /* mark stacker bitfat as up to date and unmounted */
572: if(dblsb->s_cvf_version>=STAC3)
573: stac_bitfat_state(sb,1);
574: #endif
575:
576: /* kill buffers used by unmounted cvf */
577: for(j=0;j<MDFATCACHESIZE;++j)
578: { if(mdfat[j].a_buffer!=NULL)
579: { if(mdfat[j].a_sb->s_dev==sb->s_dev)
580: { raw_brelse(sb,mdfat[j].a_buffer);
581: mdfat[j].a_buffer=NULL;
582: }
583: mdfat[j].a_time=0;
584: mdfat[j].a_acc=0;
585: }
586: }
587: for(j=0;j<DFATCACHESIZE;++j)
588: { if(dfat[j].a_buffer!=NULL)
589: { if(dfat[j].a_sb->s_dev==sb->s_dev)
590: { raw_brelse(sb,dfat[j].a_buffer);
591: dfat[j].a_buffer=NULL;
592: }
593: dfat[j].a_time=0;
594: dfat[j].a_acc=0;
595: }
596: }
597: for(j=0;j<BITFATCACHESIZE;++j)
598: { if(bitfat[j].a_buffer!=NULL)
599: { if(bitfat[j].a_sb->s_dev==sb->s_dev)
600: { raw_brelse(sb,bitfat[j].a_buffer);
601: bitfat[j].a_buffer=NULL;
602: }
603: bitfat[j].a_time=0;
604: bitfat[j].a_acc=0;
605: }
606: }
607:
608: #ifdef __KERNEL__
609: #ifdef USE_READA_LIST
610: /* throw away all stacked reada entries for this dev */
611: kill_reada_list_dev(sb->s_dev);
612: #endif
613: /* this is unused in the library */
614: kfree(dblsb->mdfat_alloc_semp);
615: #endif
616: kfree(MSDOS_SB(sb)->private_data);
617: MSDOS_SB(sb)->private_data=NULL;
618: /*MSDOS_SB(sb)->cvf_format=NULL;*/ /*this causes a segfault in
619: dec_cvf_format_use_count_by_version*/
620: exit_daemon();
621: MOD_DEC_USE_COUNT;
622: return 0;
623: }
624:
625: #ifdef DMSDOS_CONFIG_STAC
626: int detect_stacker(struct super_block*sb)
627: { struct buffer_head*bh;
628:
629: MOD_INC_USE_COUNT;
630: bh=raw_bread(sb,0);
631: if(bh==NULL)
632: { printk(KERN_ERR "DMSDOS: unable to read super block\n");
633: MOD_DEC_USE_COUNT;
634: return 0;
635: }
636: if(strncmp(bh->b_data,"STACKER",7)==0)
637: { raw_brelse(sb,bh);
638: MOD_DEC_USE_COUNT;
639: return 1;
640: }
641: raw_brelse(sb,bh);
642: MOD_DEC_USE_COUNT;
643: return 0;
644: }
645:
646: int mount_stacker(struct super_block*sb,char*options)
647: {
648: struct buffer_head*bh;
649: struct buffer_head*bh2;
650: int i;
651: unsigned char * pp, *p;
652: unsigned char buf[512];
653: unsigned char b,c;
654: int SectSize, ClustSects, ClustSize, ReservSects, FATCnt;
655: int RootDirEnt, TotalSects, FATSize, HidenSects, FirstRootSect;
656: int FirstDataSect, FirstDataSect2, FAT12, FirstFATSect;
657: int StacVersion;
658: /* parameters of virtual DOS drive */
659: int BB_FirstDataSect, BB_ClustCnt, BB_SectSize, BB_TotalSects;
660: Dblsb*dblsb;
661: int repair=0;
662:
663: MOD_INC_USE_COUNT;
664: LOG_REST("DMSDOS: stacker 3/4 module mounting...\n");
665:
666: LOG_REST("DMSDOS: reading super block...\n");
667: bh=raw_bread(sb,0);
668: if(bh==NULL)
669: { printk(KERN_ERR "DMSDOS: unable to read super block of CVF\n");
670: MOD_DEC_USE_COUNT;
671: return -1;
672: }
673: LOG_REST("DMSDOS: super block read finished\n");
674: pp=&(bh->b_data[0]);
675: if(strncmp(pp,"STACKER",7)!=0)
676: { printk(KERN_ERR "DMSDOS: STACKER signature not found\n");
677: raw_brelse(sb,bh);
678: MOD_DEC_USE_COUNT;
679: return -1;
680: }
681:
682: /* copy block (must not directly modify kernel buffer!!!) */
683: memcpy(buf,bh->b_data,SECTOR_SIZE);
684: /* decode super block */
685: for(i=0x30,p=buf+0x50,b=buf[0x4c];i--;p++)
686: { b=0xc4-b;
687: b=b<0x80?b*2:b*2+1;
688: b^=c=*p;
689: *p=b;b=c;
690: }
691: if(buf[0x4e]!=0xa||buf[0x4f]!=0x1a)
692: { printk(KERN_ERR "DMSDOS: Stacker 0x1A0A signature not found\n");
693: raw_brelse(sb,bh);
694: MOD_DEC_USE_COUNT;
695: return -1;
696: }
697:
698: dblsb=kmalloc(sizeof(Dblsb),GFP_KERNEL);
699: if(dblsb==NULL)
700: { printk(KERN_ERR "DMSDOS: mount_stacker: out of memory\n");
701: raw_brelse(sb,bh);
702: MOD_DEC_USE_COUNT;
703: return -1;
704: }
705: MSDOS_SB(sb)->private_data=dblsb;
706: /*dblsb->mdfat_alloc_sem=MUTEX;*/
707:
708: #ifdef __KERNEL__
709: { struct semaphore* sem;
710:
711: sem=kmalloc(sizeof(struct semaphore),GFP_KERNEL);
712: if(sem==NULL)
713: { printk(KERN_ERR "DMSDOS: mount_stacker: out of memory\n");
714: raw_brelse(sb,bh);
715: MOD_DEC_USE_COUNT;
716: return -1;
717: }
718: *sem=MUTEX;
719: dblsb->mdfat_alloc_semp=sem;
720: }
721: #endif
722:
723: /* find out size */
724: dblsb->s_dataend=blk_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)]*2;
725:
726: dblsb->s_comp=GUESS;
727: dblsb->s_cfaktor=DEFAULT_CF;
728:
729: if(parse_dmsdos_options(options,dblsb,&repair))
730: {
731: raw_brelse(sb,bh);
732: MOD_DEC_USE_COUNT;
733: return -1;
734: }
735:
736: if(sb->s_flags & MS_RDONLY)dblsb->s_comp=READ_ONLY;
737: printk(KERN_NOTICE "DMSDOS: mounting CVF on device 0x%x %s...\n",
738: sb->s_dev,
739: dblsb->s_comp==READ_ONLY?"read-only":"read-write");
740:
741: /* extract important info */
742: pp=&(buf[0x6C]);
743: TotalSects=CHL(pp);
744: pp=&(buf[0x70]);
745: dblsb->s_bootblock=CHS(pp);
746: pp=&(buf[0x74]);
747: dblsb->s_mdfatstart=CHS(pp); /* here it's AMAP start !!! */
748: pp=&(buf[0x76]);
749: FirstFATSect=dblsb->s_fatstart=CHS(pp);
750: pp=&(buf[0x7a]);
751: FirstDataSect2=dblsb->s_datastart=CHS(pp);
752: pp=&(buf[0x60]);
753: StacVersion=CHS(pp);
754: if(StacVersion>=410)dblsb->s_cvf_version=STAC4;
755: else dblsb->s_cvf_version=STAC3;
756: /* if(buf[0x64]==9)dblsb->s_cvf_version=STAC4;
757: else dblsb->s_cvf_version=STAC3; */
758:
759: #ifndef DMSDOS_CONFIG_STAC3
760: if(dblsb->s_cvf_version==STAC3)
761: { printk(KERN_ERR "DMSDOS: support for stacker 3 not compiled in.\n");
762: raw_brelse(sb,bh);
763: MOD_DEC_USE_COUNT;
764: return -1;
765: }
766: #endif
767: #ifndef DMSDOS_CONFIG_STAC4
768: if(dblsb->s_cvf_version==STAC4)
769: { printk(KERN_ERR "DMSDOS: support for stacker 4 not compiled in.\n");
770: raw_brelse(sb,bh);
771: MOD_DEC_USE_COUNT;
772: return -1;
773: }
774: #endif
775:
776: /* now we need the boot block */
777: bh2=raw_bread(sb,dblsb->s_bootblock);
778: if(bh2==NULL)
779: { printk(KERN_ERR "DMSDOS: unable to read emulated boot block of CVF\n");
780: raw_brelse(sb,bh);
781: MOD_DEC_USE_COUNT;
782: return -1;
783: }
784: /* read values */
785: dblsb->s_sectperclust=bh2->b_data[0xd];
786: dblsb->s_spc_bits=ilog2(dblsb->s_sectperclust);
787: pp=&(bh2->b_data[0x11]);
788: dblsb->s_rootdirentries=CHS(pp);
789:
790: pp=&(buf[0x62]); SectSize=CHS(pp);
791: pp=&(bh2->b_data[0xB]); BB_SectSize=CHS(pp);
792: if(SectSize!=SECTOR_SIZE||BB_SectSize!=SECTOR_SIZE)
793: printk(KERN_WARNING "DMSDOS: Stacker sector size not 512 bytes, hmm...\n");
794: ClustSects=bh2->b_data[0xD];
795: ClustSize=ClustSects*SectSize;
796: pp=&(bh2->b_data[0xE]); ReservSects=CHS(pp);
797: FATCnt=bh2->b_data[0x10];
798: pp=&(bh2->b_data[0x11]); RootDirEnt=CHS(pp);
799: pp=&(bh2->b_data[0x13]); BB_TotalSects=CHS(pp);
800: if(!BB_TotalSects)
801: { pp=&(bh2->b_data[0x20]); BB_TotalSects=CHL(pp);};
802: pp=&(bh2->b_data[0x16]); FATSize=CHS(pp);
803: pp=&(bh2->b_data[0x1B]); HidenSects=CHS(pp);
804: if(BB_SectSize!=SectSize)printk(KERN_WARNING "DMSDOS: Inconsistent sector length\n");
805: FirstRootSect=FirstFATSect+3*FATCnt*FATSize;
806:
807: dblsb->s_2nd_fat_offset=3*(FATCnt-1)*FATSize;
808:
809: /* Number of sectors in root directory */
810: FirstDataSect=((long)RootDirEnt*0x20+SectSize-1)/SectSize;
811: /* Emulated data start sector for DOS */
812: BB_FirstDataSect=FirstDataSect+FATCnt*FATSize+ReservSects;
813: /* ??? +HidenSects; */
814: /* Real data start sector */
815: FirstDataSect+=FirstRootSect;
816: /* Counting BB_ClustCnt from emulated boot block */
817: BB_ClustCnt=(BB_TotalSects-BB_FirstDataSect)/ClustSects;
818: if(BB_ClustCnt>=0xFED)FAT12=0; else FAT12=1;
819: if(BB_ClustCnt<2||BB_ClustCnt>0xfff7)
820: { printk(KERN_ERR "DMSDOS: BB_ClustCnt=0x%x impossible (FAT32?)\n",BB_ClustCnt);
821: raw_brelse(sb,bh2);
822: raw_brelse(sb,bh);
823: MOD_DEC_USE_COUNT;
824: return -1;
825: }
826: if(FirstDataSect2!=FirstDataSect)
827: { printk(KERN_WARNING "DMSDOS: Inconsistent first data sector number. Mounting READ ONLY.\n");
828: printk(KERN_WARNING "In header found %u but computed %u\n",(unsigned)FirstDataSect2,(unsigned)FirstDataSect);
829: dblsb->s_comp=READ_ONLY;
830: }
831:
832: LOG_REST("DMSDOS: Stac version %u start of FAT %u, root %u, data %u; FATSize %u; FATCnt %u; clusts %u; sects %u\n",
833: (unsigned)StacVersion,(unsigned)FirstFATSect,(unsigned)FirstRootSect,
834: (unsigned)FirstDataSect,(unsigned)FATSize,(unsigned)FATCnt,
835: (unsigned)BB_ClustCnt,(unsigned)BB_TotalSects);
836:
837: /* try dos standard method to detect fat bit size - does not work */
838: /* pp=&(bh2->b_data[57]); */
839: /* if(CHL(pp)==0x20203631)dblsb->s_16bitfat=1; */
840: /* else if(CHL(pp)==0x20203231)dblsb->s_16bitfat=0; else */
841:
842: /* used only stacker method for fat entry size now */
843: dblsb->s_16bitfat=FAT12? 0: 1;
844: LOG_REST("DMSDOS: FAT bit size of CVF is %d bit\n",
845: (FAT12) ? 12 : 16 );
846:
847: /* check if clusters fits in FAT */
848: if(BB_ClustCnt+2>(FAT12?(SECTOR_SIZE*FATSize*2)/3:(SECTOR_SIZE*FATSize)/2))
849: { printk(KERN_WARNING "DMSDOS: FAT size does not match cluster count. Mounting READ ONLY.\n");
850: dblsb->s_comp=READ_ONLY;
851: }
852:
853: /* check size of physical media against stacvol parameters */
854: if((TotalSects<=0)||(TotalSects-1)>dblsb->s_dataend)
855: { printk(KERN_WARNING "DMSDOS: CVF is shorter about %d sectors. Mounting READ ONLY.\n",
856: (int)TotalSects-1-dblsb->s_dataend);
857: dblsb->s_comp=READ_ONLY;
858: }
859: else if((TotalSects-1)<dblsb->s_dataend)
860: { printk(KERN_INFO "DMSDOS: CVF end padding %d sectors.\n",
861: (int)dblsb->s_dataend-TotalSects+1);
862: dblsb->s_dataend=TotalSects-1;
863: }
864:
865: raw_brelse(sb,bh2);
866: dblsb->s_full=0;
867: raw_brelse(sb,bh);
868:
869: dblsb->s_rootdir=FirstRootSect;
870: dblsb->s_max_cluster=dblsb->s_max_cluster2=BB_ClustCnt+1;
871:
872: LOG_REST("DMSDOS: mdfatstart=%d\n",dblsb->s_mdfatstart);
873: LOG_REST("DMSDOS: rootdirentries=%d\n",dblsb->s_rootdirentries);
874: LOG_REST("DMSDOS: sectperclust=%d\n",dblsb->s_sectperclust);
875: LOG_REST("DMSDOS: fatstart=%d\n",dblsb->s_fatstart);
876: LOG_REST("DMSDOS: rootdir=%d\n",dblsb->s_rootdir);
877: LOG_REST("DMSDOS: %d bit FAT\n",dblsb->s_16bitfat ? 16 : 12);
878:
879: /* allocation informations */
880: dblsb->s_lastnear=0;
881: dblsb->s_lastbig=0;
882: dblsb->s_free_sectors=-1; /* -1 means unknown */
883:
884: /* set some msdos fs important stuff */
885: MSDOS_SB(sb)->dir_start=FAKED_ROOT_DIR_OFFSET;
886: MSDOS_SB(sb)->dir_entries=dblsb->s_rootdirentries;
887: MSDOS_SB(sb)->data_start=FAKED_DATA_START_OFFSET; /*begin of virtual cluster 2*/
888: MSDOS_SB(sb)->clusters=BB_ClustCnt;
889: if(MSDOS_SB(sb)->fat_bits!=dblsb->s_16bitfat?16:12)
890: { LOG_REST("DMSDOS: fat bit size mismatch in fat driver, trying to correct\n");
891: MSDOS_SB(sb)->fat_bits=dblsb->s_16bitfat?16:12;
892: }
893: MSDOS_SB(sb)->cluster_size=dblsb->s_sectperclust;
894:
895: /* error test */
896: if(repair!=-1) /* repair==-1 means do not even check */
897: {
898: i=simple_check(sb,repair&1);
899: if(i==-1||i==-2)
900: { printk(KERN_WARNING "DMSDOS: CVF has serious errors or compatibility problems, setting to read-only.\n");
901: dblsb->s_comp=READ_ONLY;
902: }
903: if(i==-3)
904: { if(repair&2)
905: { printk(KERN_WARNING "DMSDOS: CVF has bitfat mismatches, ignored.\n");
906: }
907: else
908: { printk(KERN_WARNING "DMSDOS: CVF has bitfat mismatches, setting to read-only.\n");
909: dblsb->s_comp=READ_ONLY;
910: }
911: }
912: }
913:
914: /* print stacker version */
915: if(dblsb->s_cvf_version==STAC3)
916: { printk(KERN_NOTICE "DMSDOS: CVF is in stacker 3 format.\n");
917: }
918: else if(dblsb->s_cvf_version==STAC4)
919: { printk(KERN_NOTICE "DMSDOS: CVF is in stacker 4 format.\n");
920: }
921:
922: /* if still unknown then count now */
923: if(dblsb->s_free_sectors<0)check_free_sectors(sb);
924:
925: /* these *must* always match */
926: if(dblsb->s_comp==READ_ONLY)sb->s_flags |= MS_RDONLY;
927:
928: /* mark stacker bitfat as mounted and changing */
929: /* if not regulary unmounted, it must be repaired before */
930: /* next write access */
931: if((sb->s_flags&MS_RDONLY)==0)stac_bitfat_state(sb,2);
932:
933: /* we allow using the daemon - calling this more than once doesn't matter */
934: init_daemon();
935:
936: return 0;
937: }
938: #endif
939:
940: #ifdef DMSDOS_USE_READPAGE
941: #define READPAGE dblspace_readpage
942: #define MMAP NULL
943: #define RMFLAG CVF_USE_READPAGE
944: #else
945: #define READPAGE NULL
946: #define MMAP dblspace_mmap
947: #define RMFLAG 0
948: #endif
949:
950: #ifndef __DMSDOS_LIB__
951: #ifdef DMSDOS_CONFIG_DBL
952: struct cvf_format dblspace_format = {
953: 0x0001, /* version id */
954: "dblspace", /* version text */
955: RMFLAG, /* flags */
956: detect_dblspace, /* detect */
957: mount_dblspace, /* mount */
958: unmount_dblspace, /* unmount */
959: dblspace_bread, /* bread */
960: dblspace_getblk, /* getblk */
961: dblspace_brelse, /* brelse */
962: dblspace_mark_buffer_dirty, /* mark_buffer_dirty */
963: dblspace_set_uptodate, /* set_uptodate */
964: dblspace_is_uptodate, /* is_uptodate */
965: dblspace_ll_rw_block, /* ll_rw_block */
966: dblspace_fat_access, /* fat_access */
967: NULL, /* statfs */
968: dblspace_bmap, /* bmap */
969: dblspace_smap, /* smap */
970: dblspace_file_read, /* file_read */
971: dblspace_file_write, /* file_write */
972: MMAP, /* mmap */
973: READPAGE, /* readpage */
974: NULL, /* writepage */
975: dmsdos_ioctl_dir, /* dir ioctl */
976: dblspace_zero_new_cluster /* zero_new_cluster */
977: };
978: #endif
979:
980: #ifdef DMSDOS_CONFIG_STAC
981: struct cvf_format stacker_format = {
982: 0x0002, /* version id */ /**** only ****/
983: "stacker", /* version text */ /**** these ****/
984: RMFLAG, /* flags */
985: detect_stacker, /* detect */ /**** four ****/
986: mount_stacker, /* mount */ /**** differ :) ****/
987: unmount_dblspace, /* unmount */
988: dblspace_bread, /* bread */
989: dblspace_getblk, /* getblk */
990: dblspace_brelse, /* brelse */
991: dblspace_mark_buffer_dirty, /* mark_buffer_dirty */
992: dblspace_set_uptodate, /* set_uptodate */
993: dblspace_is_uptodate, /* is_uptodate */
994: dblspace_ll_rw_block, /* ll_rw_block */
995: dblspace_fat_access, /* fat_access */
996: NULL, /* statfs */
997: dblspace_bmap, /* bmap */
998: dblspace_smap, /* smap */
999: dblspace_file_read, /* file_read */
1000: dblspace_file_write, /* file_write */
1001: MMAP, /* mmap */
1002: READPAGE, /* readpage */
1003: NULL, /* writepage */
1004: dmsdos_ioctl_dir, /* dir ioctl */
1005: dblspace_zero_new_cluster /* zero_new_cluster */
1006: };
1007: #endif
1008:
1009: int init_module(void)
1010: { int i;
1011:
1012: do_spc_init();
1013: #ifdef DMSDOS_CONFIG_DBL
1014: i=register_cvf_format(&dblspace_format);
1015: if(i<0)
1016: { printk(KERN_ERR "register_cvf_format failed, module not loaded successfully\n");
1017: do_spc_exit();
1018: return i;
1019: }
1020: #endif
1021: #ifdef DMSDOS_CONFIG_STAC
1022: i=register_cvf_format(&stacker_format);
1023: if(i<0)
1024: { printk(KERN_ERR "register_cvf_format failed, module not loaded successfully\n");
1025: do_spc_exit();
1026: #ifdef DMSDOS_CONFIG_DBL
1027: unregister_cvf_format(&dblspace_format);
1028: #endif
1029: return i;
1030: }
1031: #endif
1032: LOG_REST("CVF format(s) successfully registered\n");
1033:
1034: return 0;
1035: }
1036:
1037: void cleanup_module(void)
1038: { do_spc_exit();
1039: #ifdef DMSDOS_CONFIG_DBL
1040: unregister_cvf_format(&dblspace_format);
1041: #endif
1042: #ifdef DMSDOS_CONFIG_STAC
1043: unregister_cvf_format(&stacker_format);
1044: #endif
1045: }
1046: #endif /* ifndef __DMSDOS_LIB__ */
1047:
1048: char seq[]="000000";
1049:
1050: #ifdef __DMSDOS_LIB__
1051: /* we don't need locking in the library */
1052: void lock_prseq(void) {}
1053: void unlock_prseq(void) {}
1054: #else
1055: struct semaphore prseq_sem=MUTEX; /* Must be initialized to green light */
1056: void lock_prseq(void) {down(&prseq_sem);}
1057: void unlock_prseq(void) {up(&prseq_sem);}
1058: #endif
1059:
1060: int log_prseq(void)
1061: { int i;
1062:
1063: lock_prseq();
1064:
1065: i=5;
1066: while(i>=0)
1067: { ++seq[i];
1068: if(seq[i]<='9')break;
1069: seq[i]='0';
1070: --i;
1071: }
1072:
1073: printk(seq);
1074:
1075: unlock_prseq();
1076:
1077: return 1;
1078: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.