This source file includes following definitions.
- fs_panic
- is_binary
- lock_creation
- unlock_creation
- lock_fat
- unlock_fat
- msdos_add_cluster
- date_dos2unix
- date_unix2dos
- msdos_get_entry
- raw_scan_sector
- raw_scan_root
- raw_scan_nonroot
- raw_scan
- msdos_parent_ino
- msdos_subdirs
- msdos_scan
1
2
3
4
5
6
7 #ifdef MODULE
8 #include <linux/module.h>
9 #endif
10
11 #include <linux/fs.h>
12 #include <linux/msdos_fs.h>
13 #include <linux/sched.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/string.h>
17 #include <linux/stat.h>
18
19 #include "msbuffer.h"
20
21 #define PRINTK(x)
22 #define Printk(x) printk x
23
24
25 static char bin_extensions[] =
26 "EXECOMBINAPPSYSDRVOVLOVROBJLIBDLLPIF"
27 "ARCZIPLHALZHZOOTARZ ARJ"
28 "TZ TAZTZPTPZ"
29 "GZ TGZDEB"
30 "GIFBMPTIFGL JPGPCX"
31 "TFMVF GF PK PXLDVI";
32
33
34
35
36
37
38
39 void fs_panic(struct super_block *s,const char *msg)
40 {
41 int not_ro;
42
43 not_ro = !(s->s_flags & MS_RDONLY);
44 if (not_ro) s->s_flags |= MS_RDONLY;
45 printk("Filesystem panic (dev 0x%04X, mounted on 0x%04X:%ld)\n %s\n",
46 s->s_dev,s->s_covered->i_dev,s->s_covered->i_ino,msg);
47 if (not_ro)
48 printk(" File system has been set read-only\n");
49 }
50
51
52
53
54
55
56
57 int is_binary(char conversion,char *extension)
58 {
59 char *walk;
60
61 switch (conversion) {
62 case 'b':
63 return 1;
64 case 't':
65 return 0;
66 case 'a':
67 for (walk = bin_extensions; *walk; walk += 3)
68 if (!strncmp(extension,walk,3)) return 1;
69 return 0;
70 default:
71 printk("Invalid conversion mode - defaulting to "
72 "binary.\n");
73 return 1;
74 }
75 }
76
77
78
79
80
81 static struct wait_queue *creation_wait = NULL;
82 static creation_lock = 0;
83
84
85 void lock_creation(void)
86 {
87 while (creation_lock) sleep_on(&creation_wait);
88 creation_lock = 1;
89 }
90
91
92 void unlock_creation(void)
93 {
94 creation_lock = 0;
95 wake_up(&creation_wait);
96 }
97
98
99 void lock_fat(struct super_block *sb)
100 {
101 while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait);
102 MSDOS_SB(sb)->fat_lock = 1;
103 }
104
105
106 void unlock_fat(struct super_block *sb)
107 {
108 MSDOS_SB(sb)->fat_lock = 0;
109 wake_up(&MSDOS_SB(sb)->fat_wait);
110 }
111
112
113
114
115
116
117
118 int msdos_add_cluster(struct inode *inode)
119 {
120 struct super_block *sb = inode->i_sb;
121 int count,nr,limit,last,current,sector,last_sector,file_cluster;
122 struct buffer_head *bh;
123 int cluster_size = MSDOS_SB(inode->i_sb)->cluster_size;
124
125 if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
126 if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
127 lock_fat(inode->i_sb);
128 limit = MSDOS_SB(inode->i_sb)->clusters;
129 nr = limit;
130 for (count = 0; count < limit; count++) {
131 nr = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2;
132 if (fat_access(inode->i_sb,nr,-1) == 0) break;
133 }
134 PRINTK (("cnt = %d --",count));
135 #ifdef DEBUG
136 printk("free cluster: %d\n",nr);
137 #endif
138 MSDOS_SB(inode->i_sb)->prev_free = (count+MSDOS_SB(inode->i_sb)->
139 prev_free+1) % limit;
140 if (count >= limit) {
141 MSDOS_SB(inode->i_sb)->free_clusters = 0;
142 unlock_fat(inode->i_sb);
143 return -ENOSPC;
144 }
145 fat_access(inode->i_sb,nr,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
146 0xff8 : 0xfff8);
147 if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
148 MSDOS_SB(inode->i_sb)->free_clusters--;
149 unlock_fat(inode->i_sb);
150 #ifdef DEBUG
151 printk("set to %x\n",fat_access(inode->i_sb,nr,-1));
152 #endif
153 last = 0;
154
155
156
157
158
159
160
161
162
163
164 file_cluster = 0;
165 if ((current = MSDOS_I(inode)->i_start) != 0) {
166 cache_lookup(inode,INT_MAX,&last,¤t);
167 file_cluster = last;
168 while (current && current != -1){
169 PRINTK (("."));
170 file_cluster++;
171 if (!(current = fat_access(inode->i_sb,
172 last = current,-1))) {
173 fs_panic(inode->i_sb,"File without EOF");
174 return -ENOSPC;
175 }
176 }
177 PRINTK ((" -- "));
178 }
179 #ifdef DEBUG
180 printk("last = %d\n",last);
181 #endif
182 if (last) fat_access(inode->i_sb,last,nr);
183 else {
184 MSDOS_I(inode)->i_start = nr;
185 inode->i_dirt = 1;
186 }
187 #ifdef DEBUG
188 if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
189 #endif
190 sector = MSDOS_SB(inode->i_sb)->data_start+(nr-2)*cluster_size;
191 last_sector = sector + cluster_size;
192 for ( ; sector < last_sector; sector++) {
193 #ifdef DEBUG
194 printk("zeroing sector %d\n",sector);
195 #endif
196 if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE)))
197 printk("getblk failed\n");
198 else {
199 memset(bh->b_data,0,SECTOR_SIZE);
200 msdos_set_uptodate(sb,bh,1);
201 mark_buffer_dirty(bh, 1);
202 brelse(bh);
203 }
204 }
205 if (file_cluster != inode->i_blocks/cluster_size){
206 printk ("file_cluster badly computed!!! %d <> %ld\n"
207 ,file_cluster,inode->i_blocks/cluster_size);
208 }else{
209 cache_add(inode,file_cluster,nr);
210 }
211 inode->i_blocks += cluster_size;
212 if (S_ISDIR(inode->i_mode)) {
213 if (inode->i_size & (SECTOR_SIZE-1)) {
214 fs_panic(inode->i_sb,"Odd directory size");
215 inode->i_size = (inode->i_size+SECTOR_SIZE) &
216 ~(SECTOR_SIZE-1);
217 }
218 inode->i_size += SECTOR_SIZE*cluster_size;
219 #ifdef DEBUG
220 printk("size is %d now (%x)\n",inode->i_size,inode);
221 #endif
222 inode->i_dirt = 1;
223 }
224 return 0;
225 }
226
227
228
229
230 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
231
232
233
234 extern struct timezone sys_tz;
235
236
237
238
239 int date_dos2unix(unsigned short time,unsigned short date)
240 {
241 int month,year,secs;
242
243 month = ((date >> 5) & 15)-1;
244 year = date >> 9;
245 secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
246 ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
247 month < 2 ? 1 : 0)+3653);
248
249 secs += sys_tz.tz_minuteswest*60;
250 return secs;
251 }
252
253
254
255
256 void date_unix2dos(int unix_date,unsigned short *time,
257 unsigned short *date)
258 {
259 int day,year,nl_day,month;
260
261 unix_date -= sys_tz.tz_minuteswest*60;
262 *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
263 (((unix_date/3600) % 24) << 11);
264 day = unix_date/86400-3652;
265 year = day/365;
266 if ((year+3)/4+365*year > day) year--;
267 day -= (year+3)/4+365*year;
268 if (day == 59 && !(year & 3)) {
269 nl_day = day;
270 month = 2;
271 }
272 else {
273 nl_day = (year & 3) || day <= 59 ? day : day-1;
274 for (month = 0; month < 12; month++)
275 if (day_n[month] > nl_day) break;
276 }
277 *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
278 }
279
280
281
282
283
284
285 int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
286 struct msdos_dir_entry **de)
287 {
288 struct super_block *sb = dir->i_sb;
289 int sector,offset;
290
291 while (1) {
292 offset = *pos;
293 PRINTK (("get_entry offset %d\n",offset));
294 if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
295 return -1;
296 PRINTK (("get_entry sector %d %p\n",sector,*bh));
297 if (!sector)
298 return -1;
299 *pos += sizeof(struct msdos_dir_entry);
300 if (*bh)
301 brelse(*bh);
302 PRINTK (("get_entry sector apres brelse\n"));
303 if (!(*bh = bread(dir->i_dev,sector,SECTOR_SIZE))) {
304 printk("Directory sread (sector %d) failed\n",sector);
305 continue;
306 }
307 PRINTK (("get_entry apres sread\n"));
308 *de = (struct msdos_dir_entry *) ((*bh)->b_data+(offset &
309 (SECTOR_SIZE-1)));
310 return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
311 MSDOS_DIR_BITS);
312 }
313 }
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341 #define RSS_NAME \
342 done = !strncmp(data[entry].name,name,MSDOS_NAME) && \
343 !(data[entry].attr & ATTR_VOLUME);
344
345 #define RSS_START \
346 done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number;
347
348 #define RSS_FREE \
349 { \
350 done = IS_FREE(data[entry].name); \
351 if (done) { \
352 inode = iget(sb,sector*MSDOS_DPS+entry); \
353 if (inode) { \
354 \
355 done = !MSDOS_I(inode)->i_busy; \
356 iput(inode); \
357 } \
358 } \
359 }
360
361 #define RSS_COUNT \
362 { \
363 done = 0; \
364 if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \
365 (*number)++; \
366 }
367
368 static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
369 int *number,int *ino,struct buffer_head **res_bh,
370 struct msdos_dir_entry **res_de)
371 {
372 struct buffer_head *bh;
373 struct msdos_dir_entry *data;
374 struct inode *inode;
375 int entry,start,done;
376
377 if (!(bh = bread(sb->s_dev,sector,SECTOR_SIZE))) return -EIO;
378 data = (struct msdos_dir_entry *) bh->b_data;
379 for (entry = 0; entry < MSDOS_DPS; entry++) {
380 if (name) RSS_NAME
381 else {
382 if (!ino) RSS_COUNT
383 else {
384 if (number) RSS_START
385 else RSS_FREE
386 }
387 }
388 if (done) {
389 if (ino) *ino = sector*MSDOS_DPS+entry;
390 start = CF_LE_W(data[entry].start);
391 if (!res_bh) brelse(bh);
392 else {
393 *res_bh = bh;
394 *res_de = &data[entry];
395 }
396 return start;
397 }
398 }
399 brelse(bh);
400 return -ENOENT;
401 }
402
403
404
405
406
407
408
409 static int raw_scan_root(struct super_block *sb,const char *name,int *number,int *ino,
410 struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
411 {
412 int count,cluster;
413
414 for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
415 if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count,
416 name,number,ino,res_bh,res_de)) >= 0) return cluster;
417 }
418 return -ENOENT;
419 }
420
421
422
423
424
425
426
427 static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
428 int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
429 **res_de)
430 {
431 int count,cluster;
432
433 #ifdef DEBUG
434 printk("raw_scan_nonroot: start=%d\n",start);
435 #endif
436 do {
437 for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
438 if ((cluster = raw_scan_sector(sb,(start-2)*
439 MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+
440 count,name,number,ino,res_bh,res_de)) >= 0)
441 return cluster;
442 }
443 if (!(start = fat_access(sb,start,-1))) {
444 fs_panic(sb,"FAT error");
445 break;
446 }
447 #ifdef DEBUG
448 printk("next start: %d\n",start);
449 #endif
450 }
451 while (start != -1);
452 return -ENOENT;
453 }
454
455
456
457
458
459
460
461
462
463 static int raw_scan(struct super_block *sb,int start,const char *name,int *number,
464 int *ino,struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
465 {
466 if (start)
467 return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de);
468 else return raw_scan_root(sb,name,number,ino,res_bh,res_de);
469 }
470
471
472
473
474
475
476
477
478 int msdos_parent_ino(struct inode *dir,int locked)
479 {
480 static int zero = 0;
481 int error,current,prev,nr;
482
483 if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
484 if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
485 if (!locked) lock_creation();
486 if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,
487 &zero,NULL,NULL,NULL)) < 0) {
488 if (!locked) unlock_creation();
489 return current;
490 }
491 if (!current) nr = MSDOS_ROOT_INO;
492 else {
493 if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,&zero,NULL,
494 NULL,NULL)) < 0) {
495 if (!locked) unlock_creation();
496 return prev;
497 }
498 if ((error = raw_scan(dir->i_sb,prev,NULL,¤t,&nr,NULL,
499 NULL)) < 0) {
500 if (!locked) unlock_creation();
501 return error;
502 }
503 }
504 if (!locked) unlock_creation();
505 return nr;
506 }
507
508
509
510
511
512
513
514 int msdos_subdirs(struct inode *dir)
515 {
516 int count;
517
518 count = 0;
519 if (dir->i_ino == MSDOS_ROOT_INO)
520 (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL);
521 else {
522 if (!MSDOS_I(dir)->i_start) return 0;
523 else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
524 NULL,&count,NULL,NULL,NULL);
525 }
526 return count;
527 }
528
529
530
531
532
533
534
535 int msdos_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
536 struct msdos_dir_entry **res_de,int *ino)
537 {
538 int res;
539
540 if (name)
541 res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,name,NULL,ino,
542 res_bh,res_de);
543 else res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,NULL,NULL,ino,
544 res_bh,res_de);
545 return res < 0 ? res : 0;
546 }