OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [fat/] [misc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/fat/misc.c
3
 *
4
 *  Written 1992,1993 by Werner Almesberger
5
 *  22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
6
 *               and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
7
 */
8
 
9
#include <linux/fs.h>
10
#include <linux/msdos_fs.h>
11
#include <linux/sched.h>
12
#include <linux/kernel.h>
13
#include <linux/errno.h>
14
#include <linux/string.h>
15
#include <linux/stat.h>
16
 
17
#if 0
18
#  define PRINTK(x)     printk x
19
#else
20
#  define PRINTK(x)
21
#endif
22
#define Printk(x)       printk x
23
 
24
/* Well-known binary file extensions - of course there are many more */
25
 
26
static char ascii_extensions[] =
27
  "TXT" "ME " "HTM" "1ST" "LOG" "   "   /* text files */
28
  "C  " "H  " "CPP" "LIS" "PAS" "FOR"  /* programming languages */
29
  "F  " "MAK" "INC" "BAS"               /* programming languages */
30
  "BAT" "SH "                           /* program code :) */
31
  "INI"                                 /* config files */
32
  "PBM" "PGM" "DXF"                     /* graphics */
33
  "TEX";                                /* TeX */
34
 
35
 
36
/*
37
 * fat_fs_panic reports a severe file system problem and sets the file system
38
 * read-only. The file system can be made writable again by remounting it.
39
 */
40
 
41
void fat_fs_panic(struct super_block *s,const char *msg)
42
{
43
        int not_ro;
44
 
45
        not_ro = !(s->s_flags & MS_RDONLY);
46
        if (not_ro) s->s_flags |= MS_RDONLY;
47
        printk("Filesystem panic (dev %s).\n  %s\n", kdevname(s->s_dev), msg);
48
        if (not_ro)
49
                printk("  File system has been set read-only\n");
50
}
51
 
52
 
53
/*
54
 * fat_is_binary selects optional text conversion based on the conversion mode
55
 * and the extension part of the file name.
56
 */
57
 
58
int fat_is_binary(char conversion,char *extension)
59
{
60
        char *walk;
61
 
62
        switch (conversion) {
63
                case 'b':
64
                        return 1;
65
                case 't':
66
                        return 0;
67
                case 'a':
68
                        for (walk = ascii_extensions; *walk; walk += 3)
69
                                if (!strncmp(extension,walk,3)) return 0;
70
                        return 1;       /* default binary conversion */
71
                default:
72
                        printk("Invalid conversion mode - defaulting to "
73
                            "binary.\n");
74
                        return 1;
75
        }
76
}
77
 
78
void lock_fat(struct super_block *sb)
79
{
80
        down(&(MSDOS_SB(sb)->fat_lock));
81
}
82
 
83
void unlock_fat(struct super_block *sb)
84
{
85
        up(&(MSDOS_SB(sb)->fat_lock));
86
}
87
 
88
/* Flushes the number of free clusters on FAT32 */
89
/* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
90
void fat_clusters_flush(struct super_block *sb)
91
{
92
        struct buffer_head *bh;
93
        struct fat_boot_fsinfo *fsinfo;
94
 
95
        bh = fat_bread(sb, MSDOS_SB(sb)->fsinfo_sector);
96
        if (bh == NULL) {
97
                printk("FAT bread failed in fat_clusters_flush\n");
98
                return;
99
        }
100
 
101
        fsinfo = (struct fat_boot_fsinfo *)bh->b_data;
102
        /* Sanity check */
103
        if (!IS_FSINFO(fsinfo)) {
104
                printk("FAT: Did not find valid FSINFO signature.\n"
105
                       "Found signature1 0x%x signature2 0x%x sector=%ld.\n",
106
                       CF_LE_L(fsinfo->signature1), CF_LE_L(fsinfo->signature2),
107
                       MSDOS_SB(sb)->fsinfo_sector);
108
                return;
109
        }
110
        fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
111
        fsinfo->next_cluster = CF_LE_L(MSDOS_SB(sb)->prev_free);
112
        fat_mark_buffer_dirty(sb, bh);
113
        fat_brelse(sb, bh);
114
}
115
 
116
/*
117
 * fat_add_cluster tries to allocate a new cluster and adds it to the
118
 * file represented by inode.
119
 */
120
int fat_add_cluster(struct inode *inode)
121
{
122
        struct super_block *sb = inode->i_sb;
123
        int count, nr, limit, last, curr, file_cluster;
124
        int cluster_size = MSDOS_SB(sb)->cluster_size;
125
        int res = -ENOSPC;
126
 
127
        lock_fat(sb);
128
 
129
        if (MSDOS_SB(sb)->free_clusters == 0) {
130
                unlock_fat(sb);
131
                return res;
132
        }
133
        limit = MSDOS_SB(sb)->clusters;
134
        nr = limit; /* to keep GCC happy */
135
        for (count = 0; count < limit; count++) {
136
                nr = ((count + MSDOS_SB(sb)->prev_free) % limit) + 2;
137
                if (fat_access(sb, nr, -1) == 0)
138
                        break;
139
        }
140
        if (count >= limit) {
141
                MSDOS_SB(sb)->free_clusters = 0;
142
                unlock_fat(sb);
143
                return res;
144
        }
145
 
146
        MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
147
        fat_access(sb, nr, EOF_FAT(sb));
148
        if (MSDOS_SB(sb)->free_clusters != -1)
149
                MSDOS_SB(sb)->free_clusters--;
150
        if (MSDOS_SB(sb)->fat_bits == 32)
151
                fat_clusters_flush(sb);
152
 
153
        unlock_fat(sb);
154
 
155
        /* We must locate the last cluster of the file to add this
156
           new one (nr) to the end of the link list (the FAT).
157
 
158
           Here file_cluster will be the number of the last cluster of the
159
           file (before we add nr).
160
 
161
           last is the corresponding cluster number on the disk. We will
162
           use last to plug the nr cluster. We will use file_cluster to
163
           update the cache.
164
        */
165
        last = file_cluster = 0;
166
        if ((curr = MSDOS_I(inode)->i_start) != 0) {
167
                fat_cache_lookup(inode, INT_MAX, &last, &curr);
168
                file_cluster = last;
169
                while (curr && curr != -1){
170
                        file_cluster++;
171
                        if (!(curr = fat_access(sb, last = curr,-1))) {
172
                                fat_fs_panic(sb, "File without EOF");
173
                                return res;
174
                        }
175
                }
176
        }
177
        if (last) {
178
                fat_access(sb, last, nr);
179
                fat_cache_add(inode, file_cluster, nr);
180
        } else {
181
                MSDOS_I(inode)->i_start = nr;
182
                MSDOS_I(inode)->i_logstart = nr;
183
                mark_inode_dirty(inode);
184
        }
185
        if (file_cluster
186
            != inode->i_blocks / cluster_size / (sb->s_blocksize / 512)) {
187
                printk ("file_cluster badly computed!!! %d <> %ld\n",
188
                        file_cluster,
189
                        inode->i_blocks / cluster_size / (sb->s_blocksize / 512));
190
                fat_cache_inval_inode(inode);
191
        }
192
        inode->i_blocks += (1 << MSDOS_SB(sb)->cluster_bits) / 512;
193
 
194
        return nr;
195
}
196
 
197
struct buffer_head *fat_extend_dir(struct inode *inode)
198
{
199
        struct super_block *sb = inode->i_sb;
200
        int nr, sector, last_sector;
201
        struct buffer_head *bh, *res = NULL;
202
        int cluster_size = MSDOS_SB(sb)->cluster_size;
203
 
204
        if (MSDOS_SB(sb)->fat_bits != 32) {
205
                if (inode->i_ino == MSDOS_ROOT_INO)
206
                        return res;
207
        }
208
 
209
        nr = fat_add_cluster(inode);
210
        if (nr < 0)
211
                return res;
212
 
213
        sector = MSDOS_SB(sb)->data_start + (nr - 2) * cluster_size;
214
        last_sector = sector + cluster_size;
215
        if (MSDOS_SB(sb)->cvf_format && MSDOS_SB(sb)->cvf_format->zero_out_cluster)
216
                MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode, nr);
217
        else {
218
                for ( ; sector < last_sector; sector++) {
219
#ifdef DEBUG
220
                        printk("zeroing sector %d\n", sector);
221
#endif
222
                        if (!(bh = fat_getblk(sb, sector)))
223
                                printk("getblk failed\n");
224
                        else {
225
                                memset(bh->b_data, 0, sb->s_blocksize);
226
                                fat_set_uptodate(sb, bh, 1);
227
                                fat_mark_buffer_dirty(sb, bh);
228
                                if (!res)
229
                                        res = bh;
230
                                else
231
                                        fat_brelse(sb, bh);
232
                        }
233
                }
234
        }
235
        if (inode->i_size & (sb->s_blocksize - 1)) {
236
                fat_fs_panic(sb, "Odd directory size");
237
                inode->i_size = (inode->i_size + sb->s_blocksize)
238
                        & ~(sb->s_blocksize - 1);
239
        }
240
        inode->i_size += 1 << MSDOS_SB(sb)->cluster_bits;
241
        MSDOS_I(inode)->mmu_private += 1 << MSDOS_SB(sb)->cluster_bits;
242
        mark_inode_dirty(inode);
243
 
244
        return res;
245
}
246
 
247
/* Linear day numbers of the respective 1sts in non-leap years. */
248
 
249
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
250
                  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
251
 
252
 
253
extern struct timezone sys_tz;
254
 
255
 
256
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
257
 
258
int date_dos2unix(unsigned short time,unsigned short date)
259
{
260
        int month,year,secs;
261
 
262
        /* first subtract and mask after that... Otherwise, if
263
           date == 0, bad things happen */
264
        month = ((date >> 5) - 1) & 15;
265
        year = date >> 9;
266
        secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
267
            ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
268
            month < 2 ? 1 : 0)+3653);
269
                        /* days since 1.1.70 plus 80's leap day */
270
        secs += sys_tz.tz_minuteswest*60;
271
        return secs;
272
}
273
 
274
 
275
/* Convert linear UNIX date to a MS-DOS time/date pair. */
276
 
277
void fat_date_unix2dos(int unix_date,unsigned short *time,
278
    unsigned short *date)
279
{
280
        int day,year,nl_day,month;
281
 
282
        unix_date -= sys_tz.tz_minuteswest*60;
283
 
284
        /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
285
        if (unix_date < 315532800)
286
                unix_date = 315532800;
287
 
288
        *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
289
            (((unix_date/3600) % 24) << 11);
290
        day = unix_date/86400-3652;
291
        year = day/365;
292
        if ((year+3)/4+365*year > day) year--;
293
        day -= (year+3)/4+365*year;
294
        if (day == 59 && !(year & 3)) {
295
                nl_day = day;
296
                month = 2;
297
        }
298
        else {
299
                nl_day = (year & 3) || day <= 59 ? day : day-1;
300
                for (month = 0; month < 12; month++)
301
                        if (day_n[month] > nl_day) break;
302
        }
303
        *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
304
}
305
 
306
 
307
/* Returns the inode number of the directory entry at offset pos. If bh is
308
   non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
309
   returned in bh.
310
   AV. Most often we do it item-by-item. Makes sense to optimize.
311
   AV. OK, there we go: if both bh and de are non-NULL we assume that we just
312
   AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
313
   AV. It's done in fat_get_entry() (inlined), here the slow case lives.
314
   AV. Additionally, when we return -1 (i.e. reached the end of directory)
315
   AV. we make bh NULL.
316
 */
317
 
318
int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
319
                   struct msdos_dir_entry **de, loff_t *i_pos)
320
{
321
        struct super_block *sb = dir->i_sb;
322
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
323
        int sector;
324
        loff_t offset;
325
 
326
        while (1) {
327
                offset = *pos;
328
                PRINTK (("get_entry offset %d\n",offset));
329
                if (*bh)
330
                        fat_brelse(sb, *bh);
331
                *bh = NULL;
332
                if ((sector = fat_bmap(dir,offset >> sb->s_blocksize_bits)) == -1)
333
                        return -1;
334
                PRINTK (("get_entry sector %d %p\n",sector,*bh));
335
                PRINTK (("get_entry sector apres brelse\n"));
336
                if (!sector)
337
                        return -1; /* beyond EOF */
338
                *pos += sizeof(struct msdos_dir_entry);
339
                if (!(*bh = fat_bread(sb, sector))) {
340
                        printk("Directory sread (sector 0x%x) failed\n",sector);
341
                        continue;
342
                }
343
                PRINTK (("get_entry apres sread\n"));
344
 
345
                offset &= sb->s_blocksize - 1;
346
                *de = (struct msdos_dir_entry *) ((*bh)->b_data + offset);
347
                *i_pos = ((loff_t)sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
348
 
349
                return 0;
350
        }
351
}
352
 
353
 
354
/*
355
 * Now an ugly part: this set of directory scan routines works on clusters
356
 * rather than on inodes and sectors. They are necessary to locate the '..'
357
 * directory "inode". raw_scan_sector operates in four modes:
358
 *
359
 * name     number   ino      action
360
 * -------- -------- -------- -------------------------------------------------
361
 * non-NULL -        X        Find an entry with that name
362
 * NULL     non-NULL non-NULL Find an entry whose data starts at *number
363
 * NULL     non-NULL NULL     Count subdirectories in *number. (*)
364
 * NULL     NULL     non-NULL Find an empty entry
365
 *
366
 * (*) The return code should be ignored. It DOES NOT indicate success or
367
 *     failure. *number has to be initialized to zero.
368
 *
369
 * - = not used, X = a value is returned unless NULL
370
 *
371
 * If res_bh is non-NULL, the buffer is not deallocated but returned to the
372
 * caller on success. res_de is set accordingly.
373
 *
374
 * If cont is non-zero, raw_found continues with the entry after the one
375
 * res_bh/res_de point to.
376
 */
377
 
378
 
379
#define RSS_NAME /* search for name */ \
380
    done = !strncmp(data[entry].name,name,MSDOS_NAME) && \
381
     !(data[entry].attr & ATTR_VOLUME);
382
 
383
#define RSS_START /* search for start cluster */ \
384
    done = !IS_FREE(data[entry].name) \
385
      && ( \
386
           ( \
387
             (sbi->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
388
           ) \
389
           | CF_LE_W(data[entry].start) \
390
         ) == *number;
391
 
392
#define RSS_FREE /* search for free entry */ \
393
    { \
394
        done = IS_FREE(data[entry].name); \
395
    }
396
 
397
#define RSS_COUNT /* count subdirectories */ \
398
    { \
399
        done = 0; \
400
        if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \
401
            (*number)++; \
402
    }
403
 
404
static int raw_scan_sector(struct super_block *sb, int sector,
405
                           const char *name, int *number, loff_t *i_pos,
406
                           struct buffer_head **res_bh,
407
                           struct msdos_dir_entry **res_de)
408
{
409
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
410
        struct buffer_head *bh;
411
        struct msdos_dir_entry *data;
412
        int entry,start,done;
413
 
414
        if (!(bh = fat_bread(sb, sector)))
415
                return -EIO;
416
        data = (struct msdos_dir_entry *) bh->b_data;
417
        for (entry = 0; entry < sbi->dir_per_block; entry++) {
418
/* RSS_COUNT:  if (data[entry].name == name) done=true else done=false. */
419
                if (name) {
420
                        RSS_NAME
421
                } else {
422
                        if (!i_pos) RSS_COUNT
423
                        else {
424
                                if (number) RSS_START
425
                                else RSS_FREE
426
                        }
427
                }
428
                if (done) {
429
                        if (i_pos) {
430
                                *i_pos = ((loff_t)sector << sbi->dir_per_block_bits) + entry;
431
                        }
432
                        start = CF_LE_W(data[entry].start);
433
                        if (sbi->fat_bits == 32)
434
                                start |= (CF_LE_W(data[entry].starthi) << 16);
435
 
436
                        if (!res_bh)
437
                                fat_brelse(sb, bh);
438
                        else {
439
                                *res_bh = bh;
440
                                *res_de = &data[entry];
441
                        }
442
                        return start;
443
                }
444
        }
445
        fat_brelse(sb, bh);
446
        return -ENOENT;
447
}
448
 
449
 
450
/*
451
 * raw_scan_root performs raw_scan_sector on the root directory until the
452
 * requested entry is found or the end of the directory is reached.
453
 */
454
 
455
static int raw_scan_root(struct super_block *sb, const char *name,
456
                         int *number, loff_t *i_pos,
457
                         struct buffer_head **res_bh,
458
                         struct msdos_dir_entry **res_de)
459
{
460
        int count,cluster;
461
 
462
        for (count = 0;
463
             count < MSDOS_SB(sb)->dir_entries / MSDOS_SB(sb)->dir_per_block;
464
             count++) {
465
                cluster = raw_scan_sector(sb, MSDOS_SB(sb)->dir_start + count,
466
                                          name, number, i_pos, res_bh, res_de);
467
                if (cluster >= 0)
468
                        return cluster;
469
        }
470
        return -ENOENT;
471
}
472
 
473
 
474
/*
475
 * raw_scan_nonroot performs raw_scan_sector on a non-root directory until the
476
 * requested entry is found or the end of the directory is reached.
477
 */
478
 
479
static int raw_scan_nonroot(struct super_block *sb, int start, const char *name,
480
                            int *number, loff_t *i_pos,
481
                            struct buffer_head **res_bh,
482
                            struct msdos_dir_entry **res_de)
483
{
484
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
485
        int count, cluster, sector;
486
 
487
#ifdef DEBUG
488
        printk("raw_scan_nonroot: start=%d\n",start);
489
#endif
490
        do {
491
                for (count = 0; count < sbi->cluster_size; count++) {
492
                        sector = (start - 2) * sbi->cluster_size
493
                                + count + sbi->data_start;
494
                        cluster = raw_scan_sector(sb, sector, name, number,
495
                                                  i_pos, res_bh, res_de);
496
                        if (cluster >= 0)
497
                                return cluster;
498
                }
499
                if (!(start = fat_access(sb,start,-1))) {
500
                        fat_fs_panic(sb,"FAT error");
501
                        break;
502
                }
503
#ifdef DEBUG
504
        printk("next start: %d\n",start);
505
#endif
506
        }
507
        while (start != -1);
508
        return -ENOENT;
509
}
510
 
511
 
512
/*
513
 * raw_scan performs raw_scan_sector on any sector.
514
 *
515
 * NOTE: raw_scan must not be used on a directory that is is the process of
516
 *       being created.
517
 */
518
 
519
static int raw_scan(struct super_block *sb, int start, const char *name,
520
                    loff_t *i_pos, struct buffer_head **res_bh,
521
                    struct msdos_dir_entry **res_de)
522
{
523
        if (start)
524
                return raw_scan_nonroot(sb,start,name,NULL,i_pos,res_bh,res_de);
525
        else
526
                return raw_scan_root(sb,name,NULL,i_pos,res_bh,res_de);
527
}
528
 
529
/*
530
 * fat_subdirs counts the number of sub-directories of dir. It can be run
531
 * on directories being created.
532
 */
533
int fat_subdirs(struct inode *dir)
534
{
535
        struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
536
        int number;
537
 
538
        number = 0;
539
        if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
540
                raw_scan_root(dir->i_sb, NULL, &number, NULL, NULL, NULL);
541
        else {
542
                if ((dir->i_ino != MSDOS_ROOT_INO) && !MSDOS_I(dir)->i_start)
543
                        return 0; /* in mkdir */
544
                else {
545
                        raw_scan_nonroot(dir->i_sb, MSDOS_I(dir)->i_start,
546
                                         NULL, &number, NULL, NULL, NULL);
547
                }
548
        }
549
        return number;
550
}
551
 
552
 
553
/*
554
 * Scans a directory for a given file (name points to its formatted name) or
555
 * for an empty directory slot (name is NULL). Returns an error code or zero.
556
 */
557
 
558
int fat_scan(struct inode *dir, const char *name, struct buffer_head **res_bh,
559
             struct msdos_dir_entry **res_de, loff_t *i_pos)
560
{
561
        int res;
562
 
563
        res = raw_scan(dir->i_sb, MSDOS_I(dir)->i_start, name, i_pos,
564
                       res_bh, res_de);
565
        return (res < 0) ? res : 0;
566
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.