The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/hfsplus/wrapper.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  linux/fs/hfsplus/wrapper.c
    3  *
    4  * Copyright (C) 2001
    5  * Brad Boyer (flar@allandria.com)
    6  * (C) 2003 Ardis Technologies <roman@ardistech.com>
    7  *
    8  * Handling of HFS wrappers around HFS+ volumes
    9  */
   10 
   11 #include <linux/fs.h>
   12 #include <linux/blkdev.h>
   13 #include <linux/version.h>
   14 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
   15 #include <linux/buffer_head.h>
   16 #endif
   17 
   18 #include "hfsplus_fs.h"
   19 #include "hfsplus_raw.h"
   20 
   21 struct hfsplus_wd {
   22         u32 ablk_size;
   23         u16 ablk_start;
   24         u16 embed_start;
   25         u16 embed_count;
   26 };
   27 
   28 static int hfsplus_read_mdb(unsigned char *bufptr, struct hfsplus_wd *wd)
   29 {
   30         u32 extent;
   31         u16 attrib;
   32 
   33         if (be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG)) != HFSPLUS_VOLHEAD_SIG)
   34                 return 0;
   35 
   36         attrib = be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_ATTRIB));
   37         if (!(attrib & HFSP_WRAP_ATTRIB_SLOCK) ||
   38            !(attrib & HFSP_WRAP_ATTRIB_SPARED))
   39                 return 0;
   40 
   41         wd->ablk_size = be32_to_cpu(*(u32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
   42         if (wd->ablk_size < HFSPLUS_SECTOR_SIZE)
   43                 return 0;
   44         if (wd->ablk_size % HFSPLUS_SECTOR_SIZE)
   45                 return 0;
   46         wd->ablk_start = be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
   47 
   48         extent = be32_to_cpu(*(u32 *)(bufptr + HFSP_WRAPOFF_EMBEDEXT));
   49         wd->embed_start = (extent >> 16) & 0xFFFF;
   50         wd->embed_count = extent & 0xFFFF;
   51 
   52         return 1;
   53 }
   54 
   55 /* Find the volume header and fill in some minimum bits in superblock */
   56 /* Takes in super block, returns true if good data read */
   57 int hfsplus_read_wrapper(struct super_block *sb)
   58 {
   59         struct buffer_head *bh;
   60         struct hfsplus_vh *vhdr;
   61         char *bufptr;
   62         unsigned long block, offset, vhsect;
   63         struct hfsplus_wd wd;
   64         u32 blocksize, blockoffset;
   65         u16 sig;
   66 
   67         blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE);
   68         if (!blocksize) {
   69                 printk("HFS+-fs: unable to configure block size\n");
   70                 return -EINVAL;
   71         }
   72 
   73         block = (HFSPLUS_VOLHEAD_SECTOR * HFSPLUS_SECTOR_SIZE) / blocksize;
   74         offset = (HFSPLUS_VOLHEAD_SECTOR * HFSPLUS_SECTOR_SIZE) % blocksize;
   75 
   76         bh = sb_bread(sb, block);
   77         if (!bh) {
   78                 printk("HFS+-fs: unable to read VHDR or MDB\n");
   79                 return -EIO;
   80         }
   81 
   82         bufptr = bh->b_data + offset;
   83         sig = be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_SIG));
   84         if (sig == HFSP_WRAP_MAGIC) {
   85                 if (!hfsplus_read_mdb(bufptr, &wd))
   86                         goto error;
   87                 vhsect = (wd.ablk_start + wd.embed_start * (wd.ablk_size >> 9))
   88                         + HFSPLUS_VOLHEAD_SECTOR;
   89                 block = (vhsect * HFSPLUS_SECTOR_SIZE) / blocksize;
   90                 offset = (vhsect * HFSPLUS_SECTOR_SIZE) % blocksize;
   91                 brelse(bh);
   92                 bh = sb_bread(sb, block);
   93                 if (!bh) {
   94                         printk("HFS+-fs: unable to read VHDR\n");
   95                         return -EIO;
   96                 }
   97                 HFSPLUS_SB(sb).sect_count = wd.embed_count * (wd.ablk_size >> 9);
   98         } else {
   99                 wd.ablk_start = 0;
  100                 wd.ablk_size = blocksize;
  101                 wd.embed_start = 0;
  102                 HFSPLUS_SB(sb).sect_count = sb->s_bdev->bd_inode->i_size >> 9;
  103         }
  104         vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
  105         if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG)
  106                 goto error;
  107         blocksize = be32_to_cpu(vhdr->blocksize);
  108         brelse(bh);
  109 
  110         /* block size must be at least as large as a sector
  111          * and a multiple of 2
  112          */
  113         if (blocksize < HFSPLUS_SECTOR_SIZE ||
  114             ((blocksize - 1) & blocksize))
  115                 return -EINVAL;
  116 
  117         /* block offset must be a multiple of the block size */
  118         blockoffset = wd.ablk_start + wd.embed_start * (wd.ablk_size >> 9);
  119         if (blockoffset % (blocksize / HFSPLUS_SECTOR_SIZE)) {
  120                 printk("HFS+-fs: embedded blocks not aligned with wrapper\n");
  121                 return -EINVAL;
  122         }
  123         blockoffset /= blocksize / HFSPLUS_SECTOR_SIZE;
  124         HFSPLUS_SB(sb).blockoffset = blockoffset;
  125 
  126         if (sb_set_blocksize(sb, blocksize) != blocksize)
  127                 return -EINVAL;
  128 
  129         block = blockoffset + HFSPLUS_VOLHEAD_SECTOR /
  130                 (blocksize / HFSPLUS_SECTOR_SIZE);
  131         offset = (HFSPLUS_VOLHEAD_SECTOR * HFSPLUS_SECTOR_SIZE) % blocksize;
  132         bh = sb_bread(sb, block);
  133         if (!bh) {
  134                 printk("HFS+-fs: unable to read VHDR or MDB\n");
  135                 return -EIO;
  136         }
  137         vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
  138         /* should still be the same... */
  139         if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG)
  140                 goto error;
  141         HFSPLUS_SB(sb).s_vhbh = bh;
  142         HFSPLUS_SB(sb).s_vhdr = vhdr;
  143 
  144         return 0;
  145  error:
  146         brelse(bh);
  147         return -EINVAL;
  148 }

Cache object: 8dadea8fafe2d2d34284b00cee2b3dd5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.