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/hfs/file.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/hfs/file.c
    3  *
    4  * Copyright (C) 1995, 1996  Paul H. Hargrove
    5  * This file may be distributed under the terms of the GNU General Public License.
    6  *
    7  * This file contains the file-related functions which are independent of
    8  * which scheme is being used to represent forks.
    9  *
   10  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
   11  *
   12  * "XXX" in a comment is a note to myself to consider changing something.
   13  *
   14  * In function preconditions the term "valid" applied to a pointer to
   15  * a structure means that the pointer is non-NULL and the structure it
   16  * points to has all fields initialized to consistent values.
   17  */
   18 
   19 #include "hfs.h"
   20 #include <linux/hfs_fs_sb.h>
   21 #include <linux/hfs_fs_i.h>
   22 #include <linux/hfs_fs.h>
   23 
   24 /*================ Forward declarations ================*/
   25 
   26 static hfs_rwret_t hfs_file_read(struct file *, char *, hfs_rwarg_t,
   27                                  loff_t *);
   28 static hfs_rwret_t hfs_file_write(struct file *, const char *, hfs_rwarg_t,
   29                                   loff_t *);
   30 static void hfs_file_truncate(struct inode *);
   31 
   32 /*================ Global variables ================*/
   33 
   34 struct file_operations hfs_file_operations = {
   35         llseek:         generic_file_llseek,
   36         read:           hfs_file_read,
   37         write:          hfs_file_write,
   38         mmap:           generic_file_mmap,
   39         fsync:          file_fsync,
   40 };
   41 
   42 struct inode_operations hfs_file_inode_operations = {
   43         truncate:       hfs_file_truncate,
   44         setattr:        hfs_notify_change,
   45 };
   46 
   47 /*================ Variable-like macros ================*/
   48 
   49 /* maximum number of blocks to try to read in at once */
   50 #define NBUF 32
   51 
   52 /*================ File-local functions ================*/
   53 
   54 /*
   55  * hfs_getblk()
   56  *
   57  * Given an hfs_fork and a block number return the buffer_head for
   58  * that block from the fork.  If 'create' is non-zero then allocate
   59  * the necessary block(s) to the fork.
   60  */
   61 struct buffer_head *hfs_getblk(struct hfs_fork *fork, int block, int create)
   62 {
   63         int tmp;
   64         struct super_block *sb = fork->entry->mdb->sys_mdb;
   65 
   66         tmp = hfs_extent_map(fork, block, create);
   67 
   68         if (create) {
   69                 /* If writing the block, then we have exclusive access
   70                    to the file until we return, so it can't have moved.
   71                 */
   72                 if (tmp) {
   73                         hfs_cat_mark_dirty(fork->entry);
   74                         return sb_getblk(sb, tmp);
   75                 }
   76                 return NULL;
   77         } else {
   78                 /* If reading the block, then retry since the
   79                    location on disk could have changed while
   80                    we waited on the I/O in getblk to complete.
   81                 */
   82                 do {
   83                         struct buffer_head *bh = sb_getblk(sb, tmp);
   84                         int tmp2 = hfs_extent_map(fork, block, 0);
   85 
   86                         if (tmp2 == tmp) {
   87                                 return bh;
   88                         } else {
   89                                 /* The block moved or no longer exists. */
   90                                 brelse(bh);
   91                                 tmp = tmp2;
   92                         }
   93                 } while (tmp != 0);
   94 
   95                 /* The block no longer exists. */
   96                 return NULL;
   97         }
   98 }
   99 
  100 /*
  101  * hfs_get_block
  102  *
  103  * This is the hfs_get_block() field in the inode_operations structure for
  104  * "regular" (non-header) files.  The purpose is to translate an inode
  105  * and a block number within the corresponding file into a physical
  106  * block number.  This function just calls hfs_extent_map() to do the
  107  * real work and then stuffs the appropriate info into the buffer_head.
  108  */
  109 int hfs_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
  110 {
  111         unsigned long phys;
  112 
  113         phys = hfs_extent_map(HFS_I(inode)->fork, iblock, create);
  114         if (phys) {
  115                 bh_result->b_dev = inode->i_dev;
  116                 bh_result->b_blocknr = phys;
  117                 bh_result->b_state |= (1UL << BH_Mapped);
  118                 if (create)
  119                         bh_result->b_state |= (1UL << BH_New);
  120                 return 0;
  121         }
  122 
  123         if (!create)
  124                 return 0;
  125 
  126         /* we tried to add stuff, but we couldn't. send back an out-of-space
  127          * error. */
  128         return -ENOSPC;
  129 }
  130 
  131 
  132 /*
  133  * hfs_file_read()
  134  *
  135  * This is the read field in the inode_operations structure for
  136  * "regular" (non-header) files.  The purpose is to transfer up to
  137  * 'count' bytes from the file corresponding to 'inode', beginning at
  138  * 'filp->offset' bytes into the file.  The data is transferred to
  139  * user-space at the address 'buf'.  Returns the number of bytes
  140  * successfully transferred.  This function checks the arguments, does
  141  * some setup and then calls hfs_do_read() to do the actual transfer.  */
  142 static hfs_rwret_t hfs_file_read(struct file * filp, char * buf, 
  143                                  hfs_rwarg_t count, loff_t *ppos)
  144 {
  145         struct inode *inode = filp->f_dentry->d_inode;
  146         hfs_s32 read, left, pos, size;
  147 
  148         if (!S_ISREG(inode->i_mode)) {
  149                 hfs_warn("hfs_file_read: mode = %07o\n",inode->i_mode);
  150                 return -EINVAL;
  151         }
  152         pos = *ppos;
  153         if (pos >= HFS_FORK_MAX) {
  154                 return 0;
  155         }
  156         size = inode->i_size;
  157         if (pos > size) {
  158                 left = 0;
  159         } else {
  160                 left = size - pos;
  161         }
  162         if (left > count) {
  163                 left = count;
  164         }
  165         if (left <= 0) {
  166                 return 0;
  167         }
  168         if ((read = hfs_do_read(inode, HFS_I(inode)->fork, pos,
  169                                 buf, left, filp->f_reada != 0)) > 0) {
  170                 *ppos += read;
  171                 filp->f_reada = 1;
  172         }
  173 
  174         return read;
  175 }
  176 
  177 /*
  178  * hfs_file_write()
  179  *
  180  * This is the write() entry in the file_operations structure for
  181  * "regular" files.  The purpose is to transfer up to 'count' bytes
  182  * to the file corresponding to 'inode' beginning at offset
  183  * 'file->f_pos' from user-space at the address 'buf'.  The return
  184  * value is the number of bytes actually transferred.
  185  */
  186 static hfs_rwret_t hfs_file_write(struct file * filp, const char * buf,
  187                                   hfs_rwarg_t count, loff_t *ppos)
  188 {
  189         struct inode    *inode = filp->f_dentry->d_inode;
  190         struct hfs_fork *fork = HFS_I(inode)->fork;
  191         hfs_s32 written, pos;
  192 
  193         if (!S_ISREG(inode->i_mode)) {
  194                 hfs_warn("hfs_file_write: mode = %07o\n", inode->i_mode);
  195                 return -EINVAL;
  196         }
  197 
  198         pos = (filp->f_flags & O_APPEND) ? inode->i_size : *ppos;
  199 
  200         if (pos >= HFS_FORK_MAX) {
  201                 return 0;
  202         }
  203         if (count > HFS_FORK_MAX) {
  204                 count = HFS_FORK_MAX;
  205         }
  206         if ((written = hfs_do_write(inode, fork, pos, buf, count)) > 0)
  207                 pos += written;
  208 
  209         *ppos = pos;
  210         if (*ppos > inode->i_size) {
  211                 inode->i_size = *ppos;
  212                 mark_inode_dirty(inode);
  213         }
  214 
  215         return written;
  216 }
  217 
  218 /*
  219  * hfs_file_truncate()
  220  *
  221  * This is the truncate() entry in the file_operations structure for
  222  * "regular" files.  The purpose is to change the length of the file
  223  * corresponding to the given inode.  Changes can either lengthen or
  224  * shorten the file.
  225  */
  226 static void hfs_file_truncate(struct inode * inode)
  227 {
  228         struct hfs_fork *fork = HFS_I(inode)->fork;
  229 
  230         fork->lsize = inode->i_size;
  231         hfs_extent_adj(fork);
  232         hfs_cat_mark_dirty(HFS_I(inode)->entry);
  233 
  234         inode->i_size = fork->lsize;
  235         inode->i_blocks = fork->psize;
  236         mark_inode_dirty(inode);
  237 }
  238 
  239 /*
  240  * xlate_to_user()
  241  *
  242  * Like copy_to_user() while translating CR->NL.
  243  */
  244 static inline void xlate_to_user(char *buf, const char *data, int count)
  245 {
  246         char ch;
  247 
  248         while (count--) {
  249                 ch = *(data++);
  250                 put_user((ch == '\r') ? '\n' : ch, buf++);
  251         }
  252 }
  253 
  254 /*
  255  * xlate_from_user()
  256  *
  257  * Like copy_from_user() while translating NL->CR;
  258  */
  259 static inline int xlate_from_user(char *data, const char *buf, int count)
  260 {
  261         int i;
  262 
  263         i = copy_from_user(data, buf, count);
  264         count -= i;
  265         while (count--) {
  266                 if (*data == '\n') {
  267                         *data = '\r';
  268                 }
  269                 ++data;
  270         }
  271         return i;
  272 }
  273 
  274 /*================ Global functions ================*/
  275 
  276 /*
  277  * hfs_do_read()
  278  *
  279  * This function transfers actual data from disk to user-space memory,
  280  * returning the number of bytes successfully transferred.  'fork' tells
  281  * which file on the disk to read from.  'pos' gives the offset into
  282  * the Linux file at which to begin the transfer.  Note that this will
  283  * differ from 'filp->offset' in the case of an AppleDouble header file
  284  * due to the block of metadata at the beginning of the file, which has
  285  * no corresponding place in the HFS file.  'count' tells how many
  286  * bytes to transfer.  'buf' gives an address in user-space to transfer
  287  * the data to.
  288  * 
  289  * This is based on Linus's minix_file_read().
  290  * It has been changed to take into account that HFS files have no holes.
  291  */
  292 hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
  293                     char * buf, hfs_u32 count, int reada)
  294 {
  295         kdev_t dev = inode->i_dev;
  296         hfs_s32 size, chars, offset, block, blocks, read = 0;
  297         int bhrequest, uptodate;
  298         int convert = HFS_I(inode)->convert;
  299         struct buffer_head ** bhb, ** bhe;
  300         struct buffer_head * bhreq[NBUF];
  301         struct buffer_head * buflist[NBUF];
  302 
  303         /* split 'pos' in to block and (byte) offset components */
  304         block = pos >> HFS_SECTOR_SIZE_BITS;
  305         offset = pos & (HFS_SECTOR_SIZE-1);
  306 
  307         /* compute the logical size of the fork in blocks */
  308         size = (fork->lsize + (HFS_SECTOR_SIZE-1)) >> HFS_SECTOR_SIZE_BITS;
  309 
  310         /* compute the number of physical blocks to be transferred */
  311         blocks = (count+offset+HFS_SECTOR_SIZE-1) >> HFS_SECTOR_SIZE_BITS;
  312 
  313         bhb = bhe = buflist;
  314         if (reada) {
  315                 if (blocks < read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9)) {
  316                         blocks = read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9);
  317                 }
  318                 if (block + blocks > size) {
  319                         blocks = size - block;
  320                 }
  321         }
  322 
  323         /* We do this in a two stage process.  We first try and
  324            request as many blocks as we can, then we wait for the
  325            first one to complete, and then we try and wrap up as many
  326            as are actually done.
  327            
  328            This routine is optimized to make maximum use of the
  329            various buffers and caches. */
  330 
  331         do {
  332                 bhrequest = 0;
  333                 uptodate = 1;
  334                 while (blocks) {
  335                         --blocks;
  336                         *bhb = hfs_getblk(fork, block++, 0);
  337 
  338                         if (!(*bhb)) {
  339                                 /* Since there are no holes in HFS files
  340                                    we must have encountered an error.
  341                                    So, stop adding blocks to the queue. */
  342                                 blocks = 0;
  343                                 break;
  344                         }
  345 
  346                         if (!buffer_uptodate(*bhb)) {
  347                                 uptodate = 0;
  348                                 bhreq[bhrequest++] = *bhb;
  349                         }
  350 
  351                         if (++bhb == &buflist[NBUF]) {
  352                                 bhb = buflist;
  353                         }
  354 
  355                         /* If the block we have on hand is uptodate,
  356                            go ahead and complete processing. */
  357                         if (uptodate) {
  358                                 break;
  359                         }
  360                         if (bhb == bhe) {
  361                                 break;
  362                         }
  363                 }
  364 
  365                 /* If the only block in the queue is bad then quit */
  366                 if (!(*bhe)) {
  367                         break;
  368                 }
  369 
  370                 /* Now request them all */
  371                 if (bhrequest) {
  372                         ll_rw_block(READ, bhrequest, bhreq);
  373                 }
  374 
  375                 do {  /* Finish off all I/O that has actually completed */
  376                         char *p;
  377 
  378                         wait_on_buffer(*bhe);
  379 
  380                         if (!buffer_uptodate(*bhe)) {
  381                                 /* read error? */
  382                                 brelse(*bhe);
  383                                 if (++bhe == &buflist[NBUF]) {
  384                                         bhe = buflist;
  385                                 }
  386                                 count = 0;
  387                                 break;
  388                         }
  389 
  390                         if (count < HFS_SECTOR_SIZE - offset) {
  391                                 chars = count;
  392                         } else {
  393                                 chars = HFS_SECTOR_SIZE - offset;
  394                         }
  395                         p = (*bhe)->b_data + offset;
  396                         if (convert) {
  397                                 xlate_to_user(buf, p, chars);
  398                         } else {
  399                                 chars -= copy_to_user(buf, p, chars);
  400                                 if (!chars) {
  401                                         brelse(*bhe);
  402                                         count = 0;
  403                                         if (!read)
  404                                                 read = -EFAULT;
  405                                         break;
  406                                 }
  407                         }
  408                         brelse(*bhe);
  409                         count -= chars;
  410                         buf += chars;
  411                         read += chars;
  412                         offset = 0;
  413                         if (++bhe == &buflist[NBUF]) {
  414                                 bhe = buflist;
  415                         }
  416                 } while (count && (bhe != bhb) && !buffer_locked(*bhe));
  417         } while (count);
  418 
  419         /* Release the read-ahead blocks */
  420         while (bhe != bhb) {
  421                 brelse(*bhe);
  422                 if (++bhe == &buflist[NBUF]) {
  423                         bhe = buflist;
  424                 }
  425         }
  426         if (!read) {
  427                 return -EIO;
  428         }
  429         return read;
  430 }
  431  
  432 /*
  433  * hfs_do_write()
  434  *
  435  * This function transfers actual data from user-space memory to disk,
  436  * returning the number of bytes successfully transferred.  'fork' tells
  437  * which file on the disk to write to.  'pos' gives the offset into
  438  * the Linux file at which to begin the transfer.  Note that this will
  439  * differ from 'filp->offset' in the case of an AppleDouble header file
  440  * due to the block of metadata at the beginning of the file, which has
  441  * no corresponding place in the HFS file.  'count' tells how many
  442  * bytes to transfer.  'buf' gives an address in user-space to transfer
  443  * the data from.
  444  * 
  445  * This is just a minor edit of Linus's minix_file_write().
  446  */
  447 hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
  448                      const char * buf, hfs_u32 count)
  449 {
  450         hfs_s32 written, c;
  451         struct buffer_head * bh;
  452         char * p;
  453         int convert = HFS_I(inode)->convert;
  454 
  455         written = 0;
  456         while (written < count) {
  457                 bh = hfs_getblk(fork, pos/HFS_SECTOR_SIZE, 1);
  458                 if (!bh) {
  459                         if (!written) {
  460                                 written = -ENOSPC;
  461                         }
  462                         break;
  463                 }
  464                 c = HFS_SECTOR_SIZE - (pos % HFS_SECTOR_SIZE);
  465                 if (c > count - written) {
  466                         c = count - written;
  467                 }
  468                 if (c != HFS_SECTOR_SIZE && !buffer_uptodate(bh)) {
  469                         ll_rw_block(READ, 1, &bh);
  470                         wait_on_buffer(bh);
  471                         if (!buffer_uptodate(bh)) {
  472                                 brelse(bh);
  473                                 if (!written) {
  474                                         written = -EIO;
  475                                 }
  476                                 break;
  477                         }
  478                 }
  479                 p = (pos % HFS_SECTOR_SIZE) + bh->b_data;
  480                 c -= convert ? xlate_from_user(p, buf, c) :
  481                         copy_from_user(p, buf, c);
  482                 if (!c) {
  483                         brelse(bh);
  484                         if (!written)
  485                                 written = -EFAULT;
  486                         break;
  487                 }
  488                 pos += c;
  489                 written += c;
  490                 buf += c;
  491                 mark_buffer_uptodate(bh, 1);
  492                 mark_buffer_dirty(bh);
  493                 brelse(bh);
  494         }
  495         if (written > 0) {
  496                 struct hfs_cat_entry *entry = fork->entry;
  497 
  498                 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  499                 if (pos > fork->lsize) {
  500                         fork->lsize = pos;
  501                 }
  502                 entry->modify_date = hfs_u_to_mtime(CURRENT_TIME);
  503                 hfs_cat_mark_dirty(entry);
  504         }
  505         return written;
  506 }
  507 
  508 /*
  509  * hfs_file_fix_mode()
  510  *
  511  * Fixes up the permissions on a file after changing the write-inhibit bit.
  512  */
  513 void hfs_file_fix_mode(struct hfs_cat_entry *entry)
  514 {
  515         struct dentry **de = entry->sys_entry;
  516         int i;
  517 
  518         if (entry->u.file.flags & HFS_FIL_LOCK) {
  519                 for (i = 0; i < 4; ++i) {
  520                         if (de[i]) {
  521                                 de[i]->d_inode->i_mode &= ~S_IWUGO;
  522                         }
  523                 }
  524         } else {
  525                 for (i = 0; i < 4; ++i) {
  526                         if (de[i]) {
  527                                 struct inode *inode = de[i]->d_inode;
  528                                 inode->i_mode |= S_IWUGO;
  529                                 inode->i_mode &= 
  530                                   ~HFS_SB(inode->i_sb)->s_umask;
  531                         }
  532                 }
  533         }
  534 }

Cache object: b0427f01867315832a0e224b98e13677


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