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/adfs/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/adfs/inode.c
    3  *
    4  *  Copyright (C) 1997-1999 Russell King
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License version 2 as
    8  * published by the Free Software Foundation.
    9  */
   10 #include <linux/version.h>
   11 #include <linux/errno.h>
   12 #include <linux/fs.h>
   13 #include <linux/adfs_fs.h>
   14 #include <linux/sched.h>
   15 #include <linux/stat.h>
   16 #include <linux/string.h>
   17 #include <linux/locks.h>
   18 #include <linux/mm.h>
   19 #include <linux/smp_lock.h>
   20 #include <linux/module.h>
   21 
   22 
   23 #include "adfs.h"
   24 
   25 /*
   26  * Lookup/Create a block at offset 'block' into 'inode'.  We currently do
   27  * not support creation of new blocks, so we return -EIO for this case.
   28  */
   29 int
   30 adfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
   31 {
   32         if (block < 0)
   33                 goto abort_negative;
   34 
   35         if (!create) {
   36                 if (block >= inode->i_blocks)
   37                         goto abort_toobig;
   38 
   39                 block = __adfs_block_map(inode->i_sb, inode->i_ino, block);
   40                 if (block) {
   41                         bh->b_dev = inode->i_dev;
   42                         bh->b_blocknr = block;
   43                         bh->b_state |= (1UL << BH_Mapped);
   44                 }
   45                 return 0;
   46         }
   47         /* don't support allocation of blocks yet */
   48         return -EIO;
   49 
   50 abort_negative:
   51         adfs_error(inode->i_sb, "block %d < 0", block);
   52         return -EIO;
   53 
   54 abort_toobig:
   55         return 0;
   56 }
   57 
   58 static int adfs_writepage(struct page *page)
   59 {
   60         return block_write_full_page(page, adfs_get_block);
   61 }
   62 
   63 static int adfs_readpage(struct file *file, struct page *page)
   64 {
   65         return block_read_full_page(page, adfs_get_block);
   66 }
   67 
   68 static int adfs_prepare_write(struct file *file, struct page *page, unsigned int from, unsigned int to)
   69 {
   70         return cont_prepare_write(page, from, to, adfs_get_block,
   71                 &page->mapping->host->u.adfs_i.mmu_private);
   72 }
   73 
   74 static int _adfs_bmap(struct address_space *mapping, long block)
   75 {
   76         return generic_block_bmap(mapping, block, adfs_get_block);
   77 }
   78 
   79 static struct address_space_operations adfs_aops = {
   80         readpage:       adfs_readpage,
   81         writepage:      adfs_writepage,
   82         sync_page:      block_sync_page,
   83         prepare_write:  adfs_prepare_write,
   84         commit_write:   generic_commit_write,
   85         bmap:           _adfs_bmap
   86 };
   87 
   88 static inline unsigned int
   89 adfs_filetype(struct inode *inode)
   90 {
   91         unsigned int type;
   92 
   93         if (inode->u.adfs_i.stamped)
   94                 type = (inode->u.adfs_i.loadaddr >> 8) & 0xfff;
   95         else
   96                 type = (unsigned int) -1;
   97 
   98         return type;
   99 }
  100 
  101 /*
  102  * Convert ADFS attributes and filetype to Linux permission.
  103  */
  104 static umode_t
  105 adfs_atts2mode(struct super_block *sb, struct inode *inode)
  106 {
  107         unsigned int filetype, attr = inode->u.adfs_i.attr;
  108         umode_t mode, rmask;
  109 
  110         if (attr & ADFS_NDA_DIRECTORY) {
  111                 mode = S_IRUGO & sb->u.adfs_sb.s_owner_mask;
  112                 return S_IFDIR | S_IXUGO | mode;
  113         }
  114 
  115         filetype = adfs_filetype(inode);
  116 
  117         switch (filetype) {
  118         case 0xfc0:     /* LinkFS */
  119                 return S_IFLNK|S_IRWXUGO;
  120 
  121         case 0xfe6:     /* UnixExec */
  122                 rmask = S_IRUGO | S_IXUGO;
  123                 break;
  124 
  125         default:
  126                 rmask = S_IRUGO;
  127         }
  128 
  129         mode = S_IFREG;
  130 
  131         if (attr & ADFS_NDA_OWNER_READ)
  132                 mode |= rmask & sb->u.adfs_sb.s_owner_mask;
  133 
  134         if (attr & ADFS_NDA_OWNER_WRITE)
  135                 mode |= S_IWUGO & sb->u.adfs_sb.s_owner_mask;
  136 
  137         if (attr & ADFS_NDA_PUBLIC_READ)
  138                 mode |= rmask & sb->u.adfs_sb.s_other_mask;
  139 
  140         if (attr & ADFS_NDA_PUBLIC_WRITE)
  141                 mode |= S_IWUGO & sb->u.adfs_sb.s_other_mask;
  142         return mode;
  143 }
  144 
  145 /*
  146  * Convert Linux permission to ADFS attribute.  We try to do the reverse
  147  * of atts2mode, but there is not a 1:1 translation.
  148  */
  149 static int
  150 adfs_mode2atts(struct super_block *sb, struct inode *inode)
  151 {
  152         umode_t mode;
  153         int attr;
  154 
  155         /* FIXME: should we be able to alter a link? */
  156         if (S_ISLNK(inode->i_mode))
  157                 return inode->u.adfs_i.attr;
  158 
  159         if (S_ISDIR(inode->i_mode))
  160                 attr = ADFS_NDA_DIRECTORY;
  161         else
  162                 attr = 0;
  163 
  164         mode = inode->i_mode & sb->u.adfs_sb.s_owner_mask;
  165         if (mode & S_IRUGO)
  166                 attr |= ADFS_NDA_OWNER_READ;
  167         if (mode & S_IWUGO)
  168                 attr |= ADFS_NDA_OWNER_WRITE;
  169 
  170         mode = inode->i_mode & sb->u.adfs_sb.s_other_mask;
  171         mode &= ~sb->u.adfs_sb.s_owner_mask;
  172         if (mode & S_IRUGO)
  173                 attr |= ADFS_NDA_PUBLIC_READ;
  174         if (mode & S_IWUGO)
  175                 attr |= ADFS_NDA_PUBLIC_WRITE;
  176 
  177         return attr;
  178 }
  179 
  180 /*
  181  * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-second time
  182  * referenced to 1 Jan 1900 (til 2248)
  183  */
  184 static unsigned int
  185 adfs_adfs2unix_time(struct inode *inode)
  186 {
  187         unsigned int high, low;
  188 
  189         if (inode->u.adfs_i.stamped == 0)
  190                 return CURRENT_TIME;
  191 
  192         high = inode->u.adfs_i.loadaddr << 24;
  193         low  = inode->u.adfs_i.execaddr;
  194 
  195         high |= low >> 8;
  196         low  &= 255;
  197 
  198         /* Files dated pre  01 Jan 1970 00:00:00. */
  199         if (high < 0x336e996a)
  200                 return 0;
  201 
  202         /* Files dated post 18 Jan 2038 03:14:05. */
  203         if (high >= 0x656e9969)
  204                 return 0x7ffffffd;
  205 
  206         /* discard 2208988800 (0x336e996a00) seconds of time */
  207         high -= 0x336e996a;
  208 
  209         /* convert 40-bit centi-seconds to 32-bit seconds */
  210         return (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
  211 }
  212 
  213 /*
  214  * Convert an Unix time to ADFS time.  We only do this if the entry has a
  215  * time/date stamp already.
  216  */
  217 static void
  218 adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
  219 {
  220         unsigned int high, low;
  221 
  222         if (inode->u.adfs_i.stamped) {
  223                 /* convert 32-bit seconds to 40-bit centi-seconds */
  224                 low  = (secs & 255) * 100;
  225                 high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;
  226 
  227                 inode->u.adfs_i.loadaddr = (high >> 24) |
  228                                 (inode->u.adfs_i.loadaddr & ~0xff);
  229                 inode->u.adfs_i.execaddr = (low & 255) | (high << 8);
  230         }
  231 }
  232 
  233 /*
  234  * Fill in the inode information from the object information.
  235  *
  236  * Note that this is an inode-less filesystem, so we can't use the inode
  237  * number to reference the metadata on the media.  Instead, we use the
  238  * inode number to hold the object ID, which in turn will tell us where
  239  * the data is held.  We also save the parent object ID, and with these
  240  * two, we can locate the metadata.
  241  *
  242  * This does mean that we rely on an objects parent remaining the same at
  243  * all times - we cannot cope with a cross-directory rename (yet).
  244  */
  245 struct inode *
  246 adfs_iget(struct super_block *sb, struct object_info *obj)
  247 {
  248         struct inode *inode;
  249 
  250         inode = new_inode(sb);
  251         if (!inode)
  252                 goto out;
  253 
  254         inode->i_version = ++event;
  255         inode->i_uid     = sb->u.adfs_sb.s_uid;
  256         inode->i_gid     = sb->u.adfs_sb.s_gid;
  257         inode->i_ino     = obj->file_id;
  258         inode->i_size    = obj->size;
  259         inode->i_nlink   = 2;
  260         inode->i_blksize = PAGE_SIZE;
  261         inode->i_blocks  = (inode->i_size + sb->s_blocksize - 1) >>
  262                             sb->s_blocksize_bits;
  263 
  264         /*
  265          * we need to save the parent directory ID so that
  266          * write_inode can update the directory information
  267          * for this file.  This will need special handling
  268          * for cross-directory renames.
  269          */
  270         inode->u.adfs_i.parent_id = obj->parent_id;
  271         inode->u.adfs_i.loadaddr  = obj->loadaddr;
  272         inode->u.adfs_i.execaddr  = obj->execaddr;
  273         inode->u.adfs_i.attr      = obj->attr;
  274         inode->u.adfs_i.stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
  275 
  276         inode->i_mode    = adfs_atts2mode(sb, inode);
  277         inode->i_mtime   =
  278         inode->i_atime   =
  279         inode->i_ctime   = adfs_adfs2unix_time(inode);
  280 
  281         if (S_ISDIR(inode->i_mode)) {
  282                 inode->i_op     = &adfs_dir_inode_operations;
  283                 inode->i_fop    = &adfs_dir_operations;
  284         } else if (S_ISREG(inode->i_mode)) {
  285                 inode->i_op     = &adfs_file_inode_operations;
  286                 inode->i_fop    = &adfs_file_operations;
  287                 inode->i_mapping->a_ops = &adfs_aops;
  288                 inode->u.adfs_i.mmu_private = inode->i_size;
  289         }
  290 
  291         insert_inode_hash(inode);
  292 
  293 out:
  294         return inode;
  295 }
  296 
  297 /*
  298  * Validate and convert a changed access mode/time to their ADFS equivalents.
  299  * adfs_write_inode will actually write the information back to the directory
  300  * later.
  301  */
  302 int
  303 adfs_notify_change(struct dentry *dentry, struct iattr *attr)
  304 {
  305         struct inode *inode = dentry->d_inode;
  306         struct super_block *sb = inode->i_sb;
  307         unsigned int ia_valid = attr->ia_valid;
  308         int error;
  309 
  310         error = inode_change_ok(inode, attr);
  311 
  312         /*
  313          * we can't change the UID or GID of any file -
  314          * we have a global UID/GID in the superblock
  315          */
  316         if ((ia_valid & ATTR_UID && attr->ia_uid != sb->u.adfs_sb.s_uid) ||
  317             (ia_valid & ATTR_GID && attr->ia_gid != sb->u.adfs_sb.s_gid))
  318                 error = -EPERM;
  319 
  320         if (error)
  321                 goto out;
  322 
  323         if (ia_valid & ATTR_SIZE)
  324                 error = vmtruncate(inode, attr->ia_size);
  325 
  326         if (error)
  327                 goto out;
  328 
  329         if (ia_valid & ATTR_MTIME) {
  330                 inode->i_mtime = attr->ia_mtime;
  331                 adfs_unix2adfs_time(inode, attr->ia_mtime);
  332         }
  333         /*
  334          * FIXME: should we make these == to i_mtime since we don't
  335          * have the ability to represent them in our filesystem?
  336          */
  337         if (ia_valid & ATTR_ATIME)
  338                 inode->i_atime = attr->ia_atime;
  339         if (ia_valid & ATTR_CTIME)
  340                 inode->i_ctime = attr->ia_ctime;
  341         if (ia_valid & ATTR_MODE) {
  342                 inode->u.adfs_i.attr = adfs_mode2atts(sb, inode);
  343                 inode->i_mode = adfs_atts2mode(sb, inode);
  344         }
  345 
  346         /*
  347          * FIXME: should we be marking this inode dirty even if
  348          * we don't have any metadata to write back?
  349          */
  350         if (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MODE))
  351                 mark_inode_dirty(inode);
  352 out:
  353         return error;
  354 }
  355 
  356 /*
  357  * write an existing inode back to the directory, and therefore the disk.
  358  * The adfs-specific inode data has already been updated by
  359  * adfs_notify_change()
  360  */
  361 void adfs_write_inode(struct inode *inode, int unused)
  362 {
  363         struct super_block *sb = inode->i_sb;
  364         struct object_info obj;
  365 
  366         lock_kernel();
  367         obj.file_id     = inode->i_ino;
  368         obj.name_len    = 0;
  369         obj.parent_id   = inode->u.adfs_i.parent_id;
  370         obj.loadaddr    = inode->u.adfs_i.loadaddr;
  371         obj.execaddr    = inode->u.adfs_i.execaddr;
  372         obj.attr        = inode->u.adfs_i.attr;
  373         obj.size        = inode->i_size;
  374 
  375         adfs_dir_update(sb, &obj);
  376         unlock_kernel();
  377 }
  378 MODULE_LICENSE("GPL");

Cache object: 5ccd0785b8fd039f9e7cb8ab7258230c


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