PageRenderTime 65ms CodeModel.GetById 1ms app.highlight 58ms RepoModel.GetById 1ms app.codeStats 0ms

/filesystems/unixfs/minixfs/minixfs.c

http://macfuse.googlecode.com/
C | 615 lines | 502 code | 95 blank | 18 comment | 103 complexity | 3c0e3a0ea40ea96218c97f9e5044bc0d MD5 | raw file
  1/*
  2 * Minix File System Famiy for MacFUSE
  3 * Amit Singh
  4 * http://osxbook.com
  5 *
  6 * Most of the code in this file comes from the Linux kernel implementation
  7 * of the minix file systems. See fs/minix/ in the Linux kernel source tree.
  8 *
  9 * The code is Copyright (c) its various authors. It is covered by the
 10 * GNU GENERAL PUBLIC LICENSE Version 2.
 11 */
 12
 13#include "minixfs.h"
 14
 15#include <errno.h>
 16#include <fcntl.h>
 17#include <stdio.h>
 18#include <stdlib.h>
 19#include <string.h>
 20#include <unistd.h>
 21#include <sys/ioctl.h>
 22#include <sys/stat.h>
 23
 24static unsigned long count_free(struct buffer_head*[], unsigned, __u32);
 25static unsigned long minix_count_free_blocks(struct minix_sb_info*);
 26static struct minix_inode*  minix_V1_raw_inode(struct super_block*, ino_t,
 27                                               struct buffer_head**);
 28static struct minix2_inode* minix_V2_raw_inode(struct super_block*, ino_t,
 29                                               struct buffer_head**);
 30static unsigned long minix_count_free_inodes(struct minix_sb_info*);
 31static int           minix_iget_v1(struct super_block*, struct inode*);
 32static int           minix_iget_v2(struct super_block*, struct inode*);
 33static unsigned      minix_last_byte(struct inode*, unsigned long);
 34static int           minix_get_dirpage(struct inode*, sector_t, char*);
 35static ino_t         minix_find_entry(struct inode*, const char*);
 36
 37extern int           minix_get_block_v1(struct inode*, sector_t, off_t*);
 38extern int           minix_get_block_v2(struct inode*, sector_t, off_t*);
 39
 40static const int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
 41
 42static unsigned long
 43count_free(struct buffer_head* map[], unsigned numblocks, __u32 numbits)
 44{
 45    unsigned i, j, sum = 0;
 46    struct buffer_head* bh;
 47  
 48    for (i = 0; i < numblocks - 1; i++) {
 49        if (!(bh = map[i])) 
 50            return 0;
 51        for (j = 0; j < bh->b_size; j++)
 52            sum += nibblemap[bh->b_data[j] & 0xf]
 53                + nibblemap[(bh->b_data[j] >> 4) & 0xf];
 54    }
 55
 56    if (numblocks == 0 || !(bh = map[numblocks - 1]))
 57        return 0;
 58
 59    i = ((numbits - (numblocks - 1) * bh->b_size * 8) / 16) * 2;
 60    for (j = 0; j < i; j++) {
 61        sum += nibblemap[bh->b_data[j] & 0xf]
 62            + nibblemap[(bh->b_data[j] >> 4) & 0xf];
 63    }
 64
 65    i = numbits % 16;
 66    if (i != 0) {
 67        i = *(__u16*)(&bh->b_data[j]) | ~((1 << i) - 1);
 68        sum += nibblemap[i & 0xf] + nibblemap[(i >> 4) & 0xf];
 69        sum += nibblemap[(i >> 8) & 0xf] + nibblemap[(i >> 12) & 0xf];
 70    }
 71    return(sum);
 72}
 73
 74static unsigned long
 75minix_count_free_blocks(struct minix_sb_info* sbi)
 76{
 77    return (count_free(sbi->s_zmap, sbi->s_zmap_blocks,
 78            sbi->s_nzones - sbi->s_firstdatazone + 1) << sbi->s_log_zone_size);
 79}
 80
 81struct minix_inode*
 82minix_V1_raw_inode(struct super_block* sb, ino_t ino, struct buffer_head** bh)
 83{
 84    int block;
 85    struct minix_sb_info* sbi = minix_sb(sb);
 86    struct minix_inode* p;
 87
 88    if (!ino || ino > sbi->s_ninodes) {
 89        printk("Bad inode number on dev %s: %ld is out of range\n",
 90               sb->s_id, (long)ino);
 91        return NULL;
 92    }
 93
 94    ino--;
 95    block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
 96                ino / MINIX_INODES_PER_BLOCK;
 97    int ret = sb_bread_intobh(sb, block, *bh);
 98    if (ret != 0) {
 99        printk("Unable to read inode block\n");
100        return NULL;
101    }
102    p = (void *)(*bh)->b_data;
103    return p + ino % MINIX_INODES_PER_BLOCK;
104}
105
106struct minix2_inode*
107minix_V2_raw_inode(struct super_block* sb, ino_t ino, struct buffer_head** bh)
108{
109    int block;
110    struct minix_sb_info* sbi = minix_sb(sb);
111    struct minix2_inode* p;
112    int minix2_inodes_per_block = sb->s_blocksize / sizeof(struct minix2_inode);
113
114    if (!ino || ino > sbi->s_ninodes) {
115        printk("Bad inode number on dev %s: %ld is out of range\n",
116               sb->s_id, (long)ino);
117        return NULL;
118    }
119    ino--;
120    block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
121         ino / minix2_inodes_per_block;
122    int ret = sb_bread_intobh(sb, block, *bh);
123    if (ret != 0) {
124        printk("Unable to read inode block\n");
125        return NULL;
126    }
127    p = (void *)(*bh)->b_data;
128    return p + ino % minix2_inodes_per_block;
129}
130
131static unsigned long
132minix_count_free_inodes(struct minix_sb_info* sbi)
133{
134    return count_free(sbi->s_imap, sbi->s_imap_blocks, sbi->s_ninodes + 1);
135}
136
137static int
138minix_iget_v1(struct super_block* sb, struct inode* inode)
139{
140    struct buffer_head _bh;
141    struct buffer_head* bh = &_bh;;
142    bh->b_flags.dynamic = 0;
143    struct minix_inode* raw_inode;
144    struct minix_inode_info* minix_inode = minix_i(inode);
145    int i;
146
147    raw_inode = minix_V1_raw_inode(inode->I_sb, inode->I_ino, &bh);
148    if (!raw_inode)
149        return -1;
150
151    inode->I_mode = raw_inode->di_mode;
152    inode->I_uid = (uid_t)raw_inode->di_uid;
153    inode->I_gid = (gid_t)raw_inode->di_gid;
154    inode->I_nlink = raw_inode->di_nlinks;
155    inode->I_size = raw_inode->di_size;
156    inode->I_mtime.tv_sec = inode->I_atime.tv_sec = inode->I_ctime.tv_sec =
157        raw_inode->di_time;
158    inode->I_mtime.tv_nsec = 0;
159    inode->I_atime.tv_nsec = 0;
160    inode->I_ctime.tv_nsec = 0;
161    inode->I_blocks = 0;
162    for (i = 0; i < 9; i++)
163        minix_inode->u.i1_data[i] = raw_inode->di_zone[i];
164    if (S_ISCHR(inode->I_mode) || S_ISBLK(inode->I_mode))
165        inode->I_rdev = old_decode_dev(raw_inode->di_zone[0]);
166    minix_inode->i_dir_start_lookup = 0;
167    brelse(bh);
168    return 0; 
169}
170
171static int
172minix_iget_v2(struct super_block* sb, struct inode* inode)
173{
174    struct buffer_head _bh;
175    struct buffer_head* bh = &_bh;;
176    bh->b_flags.dynamic = 0;
177    struct minix2_inode* raw_inode;
178    struct minix_inode_info* minix_inode = minix_i(inode);
179    int i;
180
181    raw_inode = minix_V2_raw_inode(inode->I_sb, inode->I_ino, &bh);
182    if (!raw_inode)
183        return -1;
184
185    inode->I_mode = raw_inode->di_mode;
186    inode->I_uid = (uid_t)raw_inode->di_uid;
187    inode->I_gid = (gid_t)raw_inode->di_gid;
188    inode->I_nlink = raw_inode->di_nlinks;
189    inode->I_size = raw_inode->di_size;
190    inode->I_mtime.tv_sec = raw_inode->di_mtime;
191    inode->I_atime.tv_sec = raw_inode->di_atime;
192    inode->I_ctime.tv_sec = raw_inode->di_ctime;
193    inode->I_mtime.tv_nsec = 0;
194    inode->I_atime.tv_nsec = 0;
195    inode->I_ctime.tv_nsec = 0;
196    inode->I_blocks = 0;
197    for (i = 0; i < 10; i++)
198        minix_inode->u.i2_data[i] = raw_inode->di_zone[i];
199    if (S_ISCHR(inode->I_mode) || S_ISBLK(inode->I_mode))
200        inode->I_rdev = old_decode_dev(raw_inode->di_zone[0]);
201    minix_inode->i_dir_start_lookup = 0;
202    brelse(bh);
203    return 0;
204}
205
206static unsigned
207minix_last_byte(struct inode* inode, unsigned long page_nr)
208{
209    unsigned last_byte = PAGE_CACHE_SIZE;
210
211    if (page_nr == (inode->I_size >> PAGE_CACHE_SHIFT))
212        last_byte = inode->I_size & (PAGE_CACHE_SIZE - 1);
213
214    return last_byte;
215}
216
217static int
218minix_get_dirpage(struct inode* dir, sector_t index, char* pagebuf)
219{
220    return minixfs_get_page(dir, index, pagebuf);
221}
222
223static inline void* minix_next_entry(void* de, struct minix_sb_info* sbi)
224{
225    return (void*)((char*)de + sbi->s_dirsize);
226}
227
228static ino_t
229minix_find_entry(struct inode* dir, const char* name)
230{
231    struct super_block* sb = dir->I_sb;
232    struct minix_sb_info* sbi = minix_sb(sb);
233    int namelen = strlen(name);
234    unsigned long n;
235    unsigned long npages = minix_dir_pages(dir);
236    char page[PAGE_SIZE];
237    char* p; 
238
239    ino_t test = 0, result = 0;
240
241    char* namx;
242
243    for (n = 0; n < npages; n++) {
244        char* kaddr;
245        char* limit;
246        if (minix_get_dirpage(dir, n, page) == 0) {
247            kaddr = page;
248            limit = kaddr + minix_last_byte(dir, n) - sbi->s_dirsize;
249            for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
250                if (sbi->s_version == MINIX_V3) {
251                    minix3_dirent* de3 = (minix3_dirent*)p;
252                    namx = de3->name;
253                    test = de3->inode;
254                } else {
255                    minix_dirent* de = (minix_dirent*)p;
256                    namx = de->name;
257                    test = de->inode;
258                }
259                if (!test)
260                    continue;
261                if (minix_namecompare(namelen, sbi->s_namelen, name, namx)) {
262                    result = test;
263                    goto found;
264                }
265            }
266        }
267    }
268
269found:
270
271    return result;
272}
273
274struct super_block*
275minixfs_fill_super(int fd, void* data, int silent)
276{
277    struct super_block* sb = NULL;
278    struct minix_sb_info *sbi = NULL;
279    struct minix_super_block* ms = NULL;
280    struct minix3_super_block* m3s = NULL;
281
282    unsigned long i, block;
283    int ret = -EINVAL;
284
285    struct buffer_head** map;
286    struct buffer_head _bh;
287    struct buffer_head* bh = &_bh;
288    bh->b_flags.dynamic = 0;
289
290    sb = calloc(1, sizeof(struct super_block));
291    if (!sb)
292        return NULL;
293
294    sb->s_bdev = fd;
295    sb->s_flags |= MS_RDONLY;
296
297    sbi = kzalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
298    if (!sbi)
299        goto failed_nomem;
300
301    sb->s_fs_info = sbi;
302
303    BUILD_BUG_ON(32 != sizeof (struct minix_inode));
304    BUILD_BUG_ON(64 != sizeof(struct minix2_inode));
305
306    sb->s_blocksize = BLOCK_SIZE;
307    sb->s_blocksize_bits = BLOCK_SIZE_BITS;
308
309    ret = sb_bread_intobh(sb, 1, bh);
310    if (ret != 0)
311        goto out_bad_sb;
312
313    ms = (struct minix_super_block*)bh->b_data;
314    sbi->s_ms = ms;
315    sbi->s_sbh = bh;
316    sbi->s_mount_state = ms->s_state;
317    sbi->s_ninodes = ms->s_ninodes;
318    sbi->s_nzones = ms->s_nzones;
319    sbi->s_imap_blocks = ms->s_imap_blocks;
320    sbi->s_zmap_blocks = ms->s_zmap_blocks;
321    sbi->s_firstdatazone = ms->s_firstdatazone;
322    sbi->s_log_zone_size = ms->s_log_zone_size;
323    sbi->s_max_size = ms->s_max_size;
324    sb->s_magic = ms->s_magic;
325    if (sb->s_magic == MINIX_SUPER_MAGIC) {
326        sbi->s_version = MINIX_V1;
327        sbi->s_dirsize = 16;
328        sbi->s_namelen = 14;
329        sbi->s_link_max = MINIX_LINK_MAX;
330    } else if (sb->s_magic == MINIX_SUPER_MAGIC2) {
331        sbi->s_version = MINIX_V1;
332        sbi->s_dirsize = 32;
333        sbi->s_namelen = 30;
334        sbi->s_link_max = MINIX_LINK_MAX;
335    } else if (sb->s_magic == MINIX2_SUPER_MAGIC) {
336        sbi->s_version = MINIX_V2;
337        sbi->s_nzones = ms->s_zones;
338        sbi->s_dirsize = 16;
339        sbi->s_namelen = 14;
340        sbi->s_link_max = MINIX2_LINK_MAX;
341    } else if (sb->s_magic == MINIX2_SUPER_MAGIC2) {
342        sbi->s_version = MINIX_V2;
343        sbi->s_nzones = ms->s_zones;
344        sbi->s_dirsize = 32;
345        sbi->s_namelen = 30;
346        sbi->s_link_max = MINIX2_LINK_MAX;
347    } else if ( *(__u16 *)(bh->b_data + 24) == MINIX3_SUPER_MAGIC) {
348        m3s = (struct minix3_super_block *) bh->b_data;
349        sb->s_magic = m3s->s_magic;
350        sbi->s_imap_blocks = m3s->s_imap_blocks;
351        sbi->s_zmap_blocks = m3s->s_zmap_blocks;
352        sbi->s_firstdatazone = m3s->s_firstdatazone;
353        sbi->s_log_zone_size = m3s->s_log_zone_size;
354        sbi->s_max_size = m3s->s_max_size;
355        sbi->s_ninodes = m3s->s_ninodes;
356        sbi->s_nzones = m3s->s_zones;
357        sbi->s_dirsize = 64;
358        sbi->s_namelen = 60;
359        sbi->s_version = MINIX_V3;
360        sbi->s_link_max = MINIX2_LINK_MAX;
361        sbi->s_mount_state = MINIX_VALID_FS;
362        sb->s_blocksize = m3s->s_blocksize;
363        sb->s_blocksize_bits = m3s->s_blocksize;
364    } else
365        goto out_no_fs;
366
367    /*
368     * Allocate the buffer map to keep the superblock small.
369     */
370    if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0)
371        goto out_illegal_sb;
372    i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh);
373    map = kzalloc(i, GFP_KERNEL);
374    if (!map)
375        goto out_no_map;
376    sbi->s_imap = &map[0];
377    sbi->s_zmap = &map[sbi->s_imap_blocks];
378
379    block=2;
380    for (i=0 ; i < sbi->s_imap_blocks ; i++) {
381        if (!(sbi->s_imap[i] = sb_bread(sb, block)))
382            goto out_no_bitmap;
383            block++;
384    }
385    for (i=0 ; i < sbi->s_zmap_blocks ; i++) {
386        if (!(sbi->s_zmap[i] = sb_bread(sb, block)))
387            goto out_no_bitmap;
388        block++;
389    }
390
391    minix_set_bit(0, sbi->s_imap[0]->b_data);
392    minix_set_bit(0, sbi->s_zmap[0]->b_data);
393
394    /* read the root inode */
395
396    if (!(sbi->s_mount_state & MINIX_VALID_FS))
397        printk("MINIX-fs: mounting unchecked file system, "
398               "running fsck is recommended\n");
399    else if (sbi->s_mount_state & MINIX_ERROR_FS)
400        printk("MINIX-fs: mounting file system with errors, "
401               "running fsck is recommended\n");
402
403    return sb;
404
405out_no_bitmap:
406    printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
407
408/* out_freemap: */
409    for (i = 0; i < sbi->s_imap_blocks; i++)
410        brelse(sbi->s_imap[i]);
411
412    for (i = 0; i < sbi->s_zmap_blocks; i++)
413        brelse(sbi->s_zmap[i]);
414
415    kfree(sbi->s_imap);
416
417    goto out_release;
418
419out_no_map:
420    ret = -ENOMEM;
421    if (!silent)
422        printk("MINIX-fs: can't allocate map\n");
423    goto out_release;
424
425out_illegal_sb:
426    if (!silent)
427        printk("MINIX-fs: bad superblock\n");
428    goto out_release;
429
430out_no_fs:
431    if (!silent)
432        printk("VFS: Can't find a Minix filesystem V1 | V2 | V3\n");
433
434out_release:
435    brelse(bh);
436    goto out;
437
438/*out_bad_hblock:*/
439    printk("MINIX-fs: blocksize too small for device\n");
440    goto out;
441
442out_bad_sb:
443    printk("MINIX-fs: unable to read superblock\n");
444
445out:
446failed_nomem:
447
448    if (sb)
449        free(sb);
450    if (sbi)
451        free(sbi);
452
453    return NULL;
454}
455
456int
457minixfs_statvfs(struct super_block* sb, struct statvfs* buf)
458{
459    struct minix_sb_info* sbi = minix_sb(sb);
460
461    buf->f_bsize   = sb->s_blocksize;
462    buf->f_frsize  = sb->s_blocksize;
463    buf->f_blocks  =
464        (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
465    buf->f_bfree   = minix_count_free_blocks(sbi);
466    buf->f_bavail  = buf->f_bfree;
467    buf->f_files   = sbi->s_ninodes;
468    buf->f_ffree   = minix_count_free_inodes(sbi);
469    buf->f_namemax = sbi->s_namelen;
470
471    return 0;
472}
473
474int
475minixfs_iget(struct super_block* sb, struct inode* inode)
476{
477    if (INODE_VERSION(inode) == MINIX_V1)
478        return minix_iget_v1(sb, inode);
479    else
480        return minix_iget_v2(sb, inode);
481}
482
483ino_t
484minix_inode_by_name(struct inode* dir, const char* name)
485{
486    return minix_find_entry(dir, name);
487}
488
489int
490minixfs_next_direntry(struct inode* dir, struct unixfs_dirbuf* dirbuf,
491                      off_t* offset, struct unixfs_direntry* dent)
492{
493    struct super_block* sb = dir->I_sb;
494    struct minix_sb_info* sbi = minix_sb(sb);
495    unsigned long start, n;
496    unsigned long npages = minix_dir_pages(dir);
497    char *dirpagebuf = dirbuf->data;
498
499    unsigned chunk_size = sbi->s_dirsize;
500    *offset = (*offset + chunk_size - 1) & ~(chunk_size - 1);
501
502    if (*offset >= dir->I_size)
503        return -1;
504
505    if (npages == 0)
506        return -1;
507
508    start = *offset >> PAGE_CACHE_SHIFT; /* which page from offset */
509
510    if (start >= npages)
511        return -1;
512    n = start;
513
514    if (!dirbuf->flags.initialized || (*offset & ((PAGE_SIZE - 1))) == 0) {
515        int ret = minixfs_get_page(dir, n, dirpagebuf);
516        if (ret)
517            return ret;
518        dirbuf->flags.initialized = 1;
519    }
520
521    char* name = NULL;
522
523    if (sbi->s_version == MINIX_V3) {
524        minix3_dirent* de3 =
525            (minix3_dirent*)((char*)dirpagebuf + (*offset & (PAGE_SIZE - 1)));
526        dent->ino = de3->inode;
527        name = de3->name;
528    } else {
529        minix_dirent* de =
530            (minix_dirent*)((char*)dirpagebuf + (*offset & (PAGE_SIZE - 1)));
531        dent->ino = de->inode;
532        name = de->name;
533    }
534
535    if (dent->ino) {
536        size_t nl = min(strlen(name), sbi->s_namelen);
537        memcpy(dent->name, name, nl);
538        dent->name[nl] = '\0';
539    }
540
541    *offset += chunk_size;
542
543    return 0;
544}
545
546int
547minixfs_get_block(struct inode* inode, sector_t iblock, off_t* result)
548{
549    if (INODE_VERSION(inode) == MINIX_V1)
550        return minix_get_block_v1(inode, iblock, result);
551    else
552        return minix_get_block_v2(inode, iblock, result);
553}
554
555int
556minixfs_get_page(struct inode* inode, sector_t index, char* pagebuf)
557{
558    sector_t iblock, lblock;
559    unsigned int blocksize;
560    int nr, i;
561
562    blocksize = 1 << inode->I_blkbits;
563
564    iblock = index << (PAGE_CACHE_SHIFT - inode->I_blkbits);
565    lblock = (inode->I_size + blocksize - 1) >> inode->I_blkbits;
566
567    nr = 0;
568    i = 0;
569
570    int bytes = 0, err = 0;
571    struct super_block* sb = inode->I_sb;
572    struct buffer_head _bh;
573    char* p = pagebuf;
574
575    do {
576        off_t phys64 = 0;
577        int ret = minixfs_get_block(inode, iblock, &phys64);
578        if (phys64) {
579            struct buffer_head* bh = &_bh;
580            bh->b_flags.dynamic = 0;
581            if (sb_bread_intobh(sb, phys64, bh) == 0) {
582                memcpy(p, bh->b_data, blocksize);
583                p += blocksize;
584                bytes += blocksize;
585                brelse(bh); 
586            } else {
587                err = EIO;
588                fprintf(stderr, "*** fatal error: I/O error reading page\n");
589                abort();
590                exit(10);
591            }
592        } else if (ret == 0) { /* zero fill */
593            memset(p, 0, blocksize);
594            p += blocksize;
595            bytes += blocksize;
596        } else {
597            err = EIO;
598            fprintf(stderr, "*** fatal error: block mapping failed\n");
599            abort();
600        }
601
602        iblock++;
603
604        if ((bytes >= PAGE_SIZE) || (iblock >= lblock))
605            break;
606
607    } while (1);
608
609    if (err)
610        return -1;
611
612    /* check page? */
613
614    return 0;
615}