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/inode.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/inode.c
    3  *
    4  * Copyright (C) 2001
    5  * Brad Boyer (flar@allandria.com)
    6  * (C) 2003 Ardis Technologies <roman@ardistech.com>
    7  *
    8  * Inode handling routines
    9  */
   10 
   11 #include <linux/mm.h>
   12 #include <linux/fs.h>
   13 #include <linux/pagemap.h>
   14 #include <linux/version.h>
   15 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
   16 #include <linux/buffer_head.h>
   17 #endif
   18 
   19 #include "hfsplus_fs.h"
   20 #include "hfsplus_raw.h"
   21 
   22 static int hfsplus_readpage(struct file *file, struct page *page)
   23 {
   24         //printk("readpage: %lu\n", page->index);
   25         return block_read_full_page(page, hfsplus_get_block);
   26 }
   27 
   28 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
   29 static int hfsplus_writepage(struct page *page, struct writeback_control *wbc)
   30 {
   31         //printk("writepage: %lu\n", page->index);
   32         return block_write_full_page(page, hfsplus_get_block, wbc);
   33 }
   34 #else
   35 static int hfsplus_writepage(struct page *page)
   36 {
   37         //printk("writepage: %lu\n", page->index);
   38         return block_write_full_page(page, hfsplus_get_block);
   39 }
   40 #endif
   41 
   42 static int hfsplus_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
   43 {
   44         return cont_prepare_write(page, from, to, hfsplus_get_block,
   45                 &HFSPLUS_I(page->mapping->host).mmu_private);
   46 }
   47 
   48 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
   49 static int hfsplus_bmap(struct address_space *mapping, long block)
   50 #else
   51 static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
   52 #endif
   53 {
   54         return generic_block_bmap(mapping, block, hfsplus_get_block);
   55 }
   56 
   57 int hfsplus_releasepage(struct page *page, int mask)
   58 {
   59         struct inode *inode = page->mapping->host;
   60         struct super_block *sb = inode->i_sb;
   61         struct hfsplus_btree *tree;
   62         hfsplus_bnode *node;
   63         u32 nidx;
   64         int i, res = 1;
   65 
   66         switch (inode->i_ino) {
   67         case HFSPLUS_EXT_CNID:
   68                 tree = HFSPLUS_SB(sb).ext_tree;
   69                 break;
   70         case HFSPLUS_CAT_CNID:
   71                 tree = HFSPLUS_SB(sb).cat_tree;
   72                 break;
   73         case HFSPLUS_ATTR_CNID:
   74                 tree = HFSPLUS_SB(sb).attr_tree;
   75                 break;
   76         default:
   77                 BUG();
   78                 return 0;
   79         }
   80         if (tree->node_size >= PAGE_CACHE_SIZE) {
   81                 nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
   82                 spin_lock(&tree->hash_lock);
   83                 node = __hfsplus_find_bnode(tree, nidx);
   84                 if (!node)
   85                         ;
   86                 else if (atomic_read(&node->refcnt))
   87                         res = 0;
   88                 else for (i = 0; i < tree->pages_per_bnode; i++) {
   89                         if (PageActive(node->page[i])) {
   90                                 res = 0;
   91                                 break;
   92                         }
   93                 }
   94                 if (res && node) {
   95                         __hfsplus_bnode_remove(node);
   96                         hfsplus_bnode_free(node);
   97                 }
   98                 spin_unlock(&tree->hash_lock);
   99         } else {
  100                 nidx = page->index >> (PAGE_CACHE_SHIFT - tree->node_size_shift);
  101                 i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
  102                 spin_lock(&tree->hash_lock);
  103                 do {
  104                         node = __hfsplus_find_bnode(tree, nidx++);
  105                         if (!node)
  106                                 continue;
  107                         if (atomic_read(&node->refcnt)) {
  108                                 res = 0;
  109                                 break;
  110                         }
  111                         __hfsplus_bnode_remove(node);
  112                         hfsplus_bnode_free(node);
  113                 } while (--i);
  114                 spin_unlock(&tree->hash_lock);
  115         }
  116         //printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
  117         return res;
  118 }
  119 
  120 struct address_space_operations hfsplus_btree_aops = {
  121         .readpage       = hfsplus_readpage,
  122         .writepage      = hfsplus_writepage,
  123         .sync_page      = block_sync_page,
  124         .prepare_write  = hfsplus_prepare_write,
  125         .commit_write   = generic_commit_write,
  126         .bmap           = hfsplus_bmap,
  127         .releasepage    = hfsplus_releasepage,
  128 };
  129 
  130 struct address_space_operations hfsplus_aops = {
  131         .readpage       = hfsplus_readpage,
  132         .writepage      = hfsplus_writepage,
  133         .sync_page      = block_sync_page,
  134         .prepare_write  = hfsplus_prepare_write,
  135         .commit_write   = generic_commit_write,
  136         .bmap           = hfsplus_bmap,
  137 };
  138 
  139 static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry)
  140 {
  141         struct hfsplus_find_data fd;
  142         struct super_block *sb = dir->i_sb;
  143         struct inode *inode = NULL;
  144         int err;
  145 
  146         if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
  147                 goto out;
  148 
  149         inode = HFSPLUS_I(dir).rsrc_inode;
  150         if (inode)
  151                 goto out;
  152 
  153         inode = new_inode(sb);
  154         if (!inode)
  155                 return ERR_PTR(-ENOMEM);
  156 
  157         inode->i_ino = dir->i_ino;
  158         HFSPLUS_I(inode).flags = HFSPLUS_FLG_RSRC;
  159 
  160         hfsplus_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
  161         err = hfsplus_find_cat(sb, dir->i_ino, &fd);
  162         if (!err)
  163                 err = hfsplus_cat_read_inode(inode, &fd);
  164         hfsplus_find_exit(&fd);
  165         if (err) {
  166                 iput(inode);
  167                 return ERR_PTR(err);
  168         }
  169         HFSPLUS_I(inode).rsrc_inode = dir;
  170         HFSPLUS_I(dir).rsrc_inode = inode;
  171         igrab(dir);
  172 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
  173         list_add(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes);
  174 #else
  175         hlist_add_head(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes);
  176 #endif
  177         mark_inode_dirty(inode);
  178         {
  179         void hfsplus_inode_check(struct super_block *sb);
  180         atomic_inc(&HFSPLUS_SB(sb).inode_cnt);
  181         hfsplus_inode_check(sb);
  182         }
  183 out:
  184         d_add(dentry, inode);
  185         return NULL;
  186 }
  187 
  188 static void hfsplus_get_perms(struct inode *inode, hfsplus_perm *perms, int dir)
  189 {
  190         struct super_block *sb = inode->i_sb;
  191         int mode;
  192 
  193         mode = be32_to_cpu(perms->mode) & 0xffff;
  194 
  195         inode->i_uid = be32_to_cpu(perms->owner);
  196         if (!inode->i_uid && !mode)
  197                 inode->i_uid = HFSPLUS_SB(sb).uid;
  198 
  199         inode->i_gid = be32_to_cpu(perms->group);
  200         if (!inode->i_gid && !mode)
  201                 inode->i_gid = HFSPLUS_SB(sb).gid;
  202 
  203         if (dir) {
  204                 mode = mode ? (mode & S_IALLUGO) :
  205                         (S_IRWXUGO & ~(HFSPLUS_SB(sb).umask));
  206                 mode |= S_IFDIR;
  207         } else if (!mode)
  208                 mode = S_IFREG | ((S_IRUGO|S_IWUGO) &
  209                         ~(HFSPLUS_SB(sb).umask));
  210         inode->i_mode = mode;
  211 }
  212 
  213 static void hfsplus_set_perms(struct inode *inode, hfsplus_perm *perms)
  214 {
  215         perms->mode = cpu_to_be32(inode->i_mode);
  216         perms->owner = cpu_to_be32(inode->i_uid);
  217         perms->group = cpu_to_be32(inode->i_gid);
  218         perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
  219 }
  220 
  221 static int hfsplus_file_open(struct inode *inode, struct file *file)
  222 {
  223         if (HFSPLUS_IS_RSRC(inode))
  224                 inode = HFSPLUS_I(inode).rsrc_inode;
  225         if (atomic_read(&file->f_count) != 1)
  226                 return 0;
  227         atomic_inc(&HFSPLUS_I(inode).opencnt);
  228         return 0;
  229 }
  230 
  231 static int hfsplus_file_release(struct inode *inode, struct file *file)
  232 {
  233         struct super_block *sb = inode->i_sb;
  234 
  235         if (HFSPLUS_IS_RSRC(inode))
  236                 inode = HFSPLUS_I(inode).rsrc_inode;
  237         if (atomic_read(&file->f_count) != 0)
  238                 return 0;
  239         if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) {
  240                 down(&inode->i_sem);
  241                 if (inode->i_flags & S_DEAD) {
  242                         hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL);
  243                         hfsplus_delete_inode(inode);
  244                 }
  245                 up(&inode->i_sem);
  246         }
  247         return 0;
  248 }
  249 
  250 extern struct inode_operations hfsplus_dir_inode_operations;
  251 extern struct file_operations hfsplus_dir_operations;
  252 
  253 struct inode_operations hfsplus_file_inode_operations = {
  254         .lookup         = hfsplus_file_lookup,
  255         .truncate       = hfsplus_truncate,
  256 };
  257 
  258 struct file_operations hfsplus_file_operations = {
  259         .llseek         = generic_file_llseek,
  260         .read           = generic_file_read,
  261         //.write        = hfsplus_file_write,
  262         .write          = generic_file_write,
  263         .mmap           = generic_file_mmap,
  264         .fsync          = file_fsync,
  265         .open           = hfsplus_file_open,
  266         .release        = hfsplus_file_release,
  267 };
  268 
  269 struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
  270 {
  271         struct inode *inode = new_inode(sb);
  272         if (!inode)
  273                 return NULL;
  274 
  275         {
  276         void hfsplus_inode_check(struct super_block *sb);
  277         atomic_inc(&HFSPLUS_SB(sb).inode_cnt);
  278         hfsplus_inode_check(sb);
  279         }
  280         inode->i_ino = HFSPLUS_SB(sb).next_cnid++;
  281         inode->i_mode = mode;
  282         inode->i_uid = current->fsuid;
  283         inode->i_gid = current->fsgid;
  284         inode->i_nlink = 1;
  285         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
  286         if (S_ISDIR(inode->i_mode)) {
  287                 inode->i_size = 2;
  288                 HFSPLUS_SB(sb).folder_count++;
  289                 inode->i_op = &hfsplus_dir_inode_operations;
  290                 inode->i_fop = &hfsplus_dir_operations;
  291                 INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
  292         } else if (S_ISREG(inode->i_mode)) {
  293                 HFSPLUS_SB(sb).file_count++;
  294                 inode->i_op = &hfsplus_file_inode_operations;
  295                 inode->i_fop = &hfsplus_file_operations;
  296                 inode->i_mapping->a_ops = &hfsplus_aops;
  297         } else if (S_ISLNK(inode->i_mode)) {
  298                 HFSPLUS_SB(sb).file_count++;
  299                 inode->i_op = &page_symlink_inode_operations;
  300                 inode->i_mapping->a_ops = &hfsplus_aops;
  301         } else
  302                 HFSPLUS_SB(sb).file_count++;
  303         insert_inode_hash(inode);
  304         mark_inode_dirty(inode);
  305         sb->s_dirt = 1;
  306 
  307         return inode;
  308 }
  309 
  310 void hfsplus_delete_inode(struct inode *inode)
  311 {
  312         struct super_block *sb = inode->i_sb;
  313 
  314         if (S_ISDIR(inode->i_mode)) {
  315                 HFSPLUS_SB(sb).folder_count--;
  316                 sb->s_dirt = 1;
  317                 return;
  318         }
  319         HFSPLUS_SB(sb).file_count--;
  320         if (S_ISREG(inode->i_mode)) {
  321                 if (!inode->i_nlink) {
  322                         inode->i_size = 0;
  323                         hfsplus_truncate(inode);
  324                 }
  325         } else if (S_ISLNK(inode->i_mode)) {
  326                 inode->i_size = 0;
  327                 hfsplus_truncate(inode);
  328         }
  329         sb->s_dirt = 1;
  330 }
  331 
  332 void hfsplus_inode_read_fork(struct inode *inode, hfsplus_fork_raw *fork)
  333 {
  334         u32 count;
  335         int i;
  336 
  337         memcpy(&HFSPLUS_I(inode).extents, &fork->extents,
  338                sizeof(hfsplus_extent_rec));
  339         for (count = 0, i = 0; i < 8; i++)
  340                 count += be32_to_cpu(fork->extents[i].block_count);
  341         HFSPLUS_I(inode).extent_blocks = count;
  342         HFSPLUS_I(inode).total_blocks = HFSPLUS_I(inode).alloc_blocks =
  343                 be32_to_cpu(fork->total_blocks);
  344         inode->i_size = HFSPLUS_I(inode).mmu_private = be64_to_cpu(fork->total_size);
  345         inode->i_blocks = be32_to_cpu(fork->total_blocks);
  346 }
  347 
  348 void hfsplus_inode_write_fork(struct inode *inode, hfsplus_fork_raw *fork)
  349 {
  350         memcpy(&fork->extents, &HFSPLUS_I(inode).extents,
  351                sizeof(hfsplus_extent_rec));
  352         fork->total_size = cpu_to_be64(inode->i_size);
  353         fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode).alloc_blocks);
  354 }
  355 
  356 int hfsplus_cat_read_inode(struct inode *inode, struct hfsplus_find_data *fd)
  357 {
  358         hfsplus_cat_entry entry;
  359         int res = 0;
  360         u16 type;
  361 
  362         type = hfsplus_bnode_read_u16(fd->bnode, fd->entryoffset);
  363 
  364         HFSPLUS_I(inode).dev = 0;
  365         inode->i_blksize = PAGE_SIZE; /* Doesn't seem to be useful... */
  366         if (type == HFSPLUS_FOLDER) {
  367                 hfsplus_cat_folder *folder = &entry.folder;
  368 
  369                 if (fd->entrylength < sizeof(hfsplus_cat_folder))
  370                         /* panic? */;
  371                 hfsplus_bnode_readbytes(fd->bnode, &entry, fd->entryoffset,
  372                                         sizeof(hfsplus_cat_folder));
  373                 memset(&HFSPLUS_I(inode).extents, 0,
  374                        sizeof(hfsplus_extent_rec));
  375                 hfsplus_get_perms(inode, &folder->permissions, 1);
  376                 inode->i_nlink = 1;
  377                 inode->i_size = 2 + be32_to_cpu(folder->valence);
  378                 inode->i_atime = hfsp_mt2ut(folder->access_date);
  379                 inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
  380                 inode->i_ctime = inode->i_mtime;
  381                 inode->i_blocks = 0;
  382                 inode->i_op = &hfsplus_dir_inode_operations;
  383                 inode->i_fop = &hfsplus_dir_operations;
  384                 INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
  385         } else if (type == HFSPLUS_FILE) {
  386                 hfsplus_cat_file *file = &entry.file;
  387 
  388                 if (fd->entrylength < sizeof(hfsplus_cat_file))
  389                         /* panic? */;
  390                 hfsplus_bnode_readbytes(fd->bnode, &entry, fd->entryoffset,
  391                                         sizeof(hfsplus_cat_file));
  392 
  393                 hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ?
  394                                         &file->data_fork : &file->rsrc_fork);
  395                 hfsplus_get_perms(inode, &file->permissions, 0);
  396                 inode->i_nlink = 1;
  397                 if (S_ISREG(inode->i_mode)) {
  398                         if (file->permissions.dev)
  399                                 inode->i_nlink = be32_to_cpu(file->permissions.dev);
  400                         inode->i_op = &hfsplus_file_inode_operations;
  401                         inode->i_fop = &hfsplus_file_operations;
  402                         inode->i_mapping->a_ops = &hfsplus_aops;
  403                 } else if (S_ISLNK(inode->i_mode)) {
  404                         inode->i_op = &page_symlink_inode_operations;
  405                         inode->i_mapping->a_ops = &hfsplus_aops;
  406                 } else {
  407                         init_special_inode(inode, inode->i_mode,
  408                                            be32_to_cpu(file->permissions.dev));
  409                 }
  410                 inode->i_atime = hfsp_mt2ut(file->access_date);
  411                 inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
  412                 inode->i_ctime = inode->i_mtime;
  413         } else {
  414                 printk("HFS+-fs: bad catalog entry used to create inode\n");
  415                 res = -EIO;
  416         }
  417         return res;
  418 }
  419 
  420 void hfsplus_cat_write_inode(struct inode *inode)
  421 {
  422         struct hfsplus_find_data fd;
  423         hfsplus_cat_entry entry;
  424 
  425         if (HFSPLUS_IS_RSRC(inode)) {
  426                 mark_inode_dirty(HFSPLUS_I(inode).rsrc_inode);
  427                 return;
  428         }
  429 
  430         if (!inode->i_nlink)
  431                 return;
  432 
  433         if (hfsplus_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd))
  434                 /* panic? */
  435                 return;
  436 
  437         if (hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd))
  438                 /* panic? */
  439                 goto out;
  440 
  441         if (S_ISDIR(inode->i_mode)) {
  442                 hfsplus_cat_folder *folder = &entry.folder;
  443 
  444                 if (fd.entrylength < sizeof(hfsplus_cat_folder))
  445                         /* panic? */;
  446                 hfsplus_bnode_readbytes(fd.bnode, &entry, fd.entryoffset,
  447                                         sizeof(hfsplus_cat_folder));
  448                 /* simple node checks? */
  449                 hfsplus_set_perms(inode, &folder->permissions);
  450                 folder->access_date = hfsp_ut2mt(inode->i_atime);
  451                 folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
  452                 folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
  453                 folder->valence = cpu_to_be32(inode->i_size - 2);
  454                 hfsplus_bnode_writebytes(fd.bnode, &entry, fd.entryoffset,
  455                                          sizeof(hfsplus_cat_folder));
  456         } else {
  457                 hfsplus_cat_file *file = &entry.file;
  458 
  459                 if (fd.entrylength < sizeof(hfsplus_cat_file))
  460                         /* panic? */;
  461                 hfsplus_bnode_readbytes(fd.bnode, &entry, fd.entryoffset,
  462                                         sizeof(hfsplus_cat_file));
  463                 hfsplus_inode_write_fork(inode, &file->data_fork);
  464                 if (HFSPLUS_I(inode).rsrc_inode)
  465                         hfsplus_inode_write_fork(HFSPLUS_I(inode).rsrc_inode, &file->rsrc_fork);
  466                 if (S_ISREG(inode->i_mode))
  467                         HFSPLUS_I(inode).dev = inode->i_nlink;
  468                 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
  469                         HFSPLUS_I(inode).dev = kdev_t_to_nr(inode->i_rdev);
  470                 hfsplus_set_perms(inode, &file->permissions);
  471                 file->access_date = hfsp_ut2mt(inode->i_atime);
  472                 file->content_mod_date = hfsp_ut2mt(inode->i_mtime);
  473                 file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
  474                 hfsplus_bnode_writebytes(fd.bnode, &entry, fd.entryoffset,
  475                                          sizeof(hfsplus_cat_file));
  476         }
  477 out:
  478         hfsplus_find_exit(&fd);
  479 }

Cache object: 524159f08e0deddde80530ecfc098077


[ 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.