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