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/servers/fs/open.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 /* This file contains the procedures for creating, opening, closing, and
    2  * seeking on files.
    3  *
    4  * The entry points into this file are
    5  *   do_creat:  perform the CREAT system call
    6  *   do_open:   perform the OPEN system call
    7  *   do_mknod:  perform the MKNOD system call
    8  *   do_mkdir:  perform the MKDIR system call
    9  *   do_close:  perform the CLOSE system call
   10  *   do_lseek:  perform the LSEEK system call
   11  */
   12 
   13 #include "fs.h"
   14 #include <sys/stat.h>
   15 #include <fcntl.h>
   16 #include <minix/callnr.h>
   17 #include <minix/com.h>
   18 #include "buf.h"
   19 #include "file.h"
   20 #include "fproc.h"
   21 #include "inode.h"
   22 #include "lock.h"
   23 #include "param.h"
   24 #include "super.h"
   25 
   26 #define offset m2_l1
   27 
   28 PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
   29 
   30 FORWARD _PROTOTYPE( int common_open, (int oflags, mode_t omode)         );
   31 FORWARD _PROTOTYPE( int pipe_open, (struct inode *rip,mode_t bits,int oflags));
   32 FORWARD _PROTOTYPE( struct inode *new_node, (char *path, mode_t bits,
   33                                                         zone_t z0)      );
   34 
   35 /*===========================================================================*
   36  *                              do_creat                                     *
   37  *===========================================================================*/
   38 PUBLIC int do_creat()
   39 {
   40 /* Perform the creat(name, mode) system call. */
   41   int r;
   42 
   43   if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
   44   r = common_open(O_WRONLY | O_CREAT | O_TRUNC, (mode_t) m_in.mode);
   45   return(r);
   46 }
   47 
   48 /*===========================================================================*
   49  *                              do_open                                      *
   50  *===========================================================================*/
   51 PUBLIC int do_open()
   52 {
   53 /* Perform the open(name, flags,...) system call. */
   54 
   55   int create_mode = 0;          /* is really mode_t but this gives problems */
   56   int r;
   57 
   58   /* If O_CREAT is set, open has three parameters, otherwise two. */
   59   if (m_in.mode & O_CREAT) {
   60         create_mode = m_in.c_mode;      
   61         r = fetch_name(m_in.c_name, m_in.name1_length, M1);
   62   } else {
   63         r = fetch_name(m_in.name, m_in.name_length, M3);
   64   }
   65 
   66   if (r != OK) return(err_code); /* name was bad */
   67   r = common_open(m_in.mode, create_mode);
   68   return(r);
   69 }
   70 
   71 /*===========================================================================*
   72  *                              common_open                                  *
   73  *===========================================================================*/
   74 PRIVATE int common_open(register int oflags, mode_t omode)
   75 {
   76 /* Common code from do_creat and do_open. */
   77 
   78   register struct inode *rip;
   79   int r, b, exist = TRUE;
   80   dev_t dev;
   81   mode_t bits;
   82   off_t pos;
   83   struct filp *fil_ptr, *filp2;
   84 
   85   /* Remap the bottom two bits of oflags. */
   86   bits = (mode_t) mode_map[oflags & O_ACCMODE];
   87 
   88   /* See if file descriptor and filp slots are available. */
   89   if ( (r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r);
   90 
   91   /* If O_CREATE is set, try to make the file. */ 
   92   if (oflags & O_CREAT) {
   93         /* Create a new inode by calling new_node(). */
   94         omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask);
   95         rip = new_node(user_path, omode, NO_ZONE);
   96         r = err_code;
   97         if (r == OK) exist = FALSE;      /* we just created the file */
   98         else if (r != EEXIST) return(r); /* other error */
   99         else exist = !(oflags & O_EXCL); /* file exists, if the O_EXCL 
  100                                             flag is set this is an error */
  101   } else {
  102          /* Scan path name. */
  103         if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  104   }
  105 
  106   /* Claim the file descriptor and filp slot and fill them in. */
  107   fp->fp_filp[m_in.fd] = fil_ptr;
  108   fil_ptr->filp_count = 1;
  109   fil_ptr->filp_ino = rip;
  110   fil_ptr->filp_flags = oflags;
  111 
  112   /* Only do the normal open code if we didn't just create the file. */
  113   if (exist) {
  114         /* Check protections. */
  115         if ((r = forbidden(rip, bits)) == OK) {
  116                 /* Opening reg. files directories and special files differ. */
  117                 switch (rip->i_mode & I_TYPE) {
  118                    case I_REGULAR: 
  119                         /* Truncate regular file if O_TRUNC. */
  120                         if (oflags & O_TRUNC) {
  121                                 if ((r = forbidden(rip, W_BIT)) !=OK) break;
  122                                 truncate(rip);
  123                                 wipe_inode(rip);
  124                                 /* Send the inode from the inode cache to the
  125                                  * block cache, so it gets written on the next
  126                                  * cache flush.
  127                                  */
  128                                 rw_inode(rip, WRITING);
  129                         }
  130                         break;
  131  
  132                    case I_DIRECTORY: 
  133                         /* Directories may be read but not written. */
  134                         r = (bits & W_BIT ? EISDIR : OK);
  135                         break;
  136 
  137                    case I_CHAR_SPECIAL:
  138                    case I_BLOCK_SPECIAL:
  139                         /* Invoke the driver for special processing. */
  140                         dev = (dev_t) rip->i_zone[0];
  141                         r = dev_open(dev, who, bits | (oflags & ~O_ACCMODE));
  142                         break;
  143 
  144                    case I_NAMED_PIPE:
  145                         oflags |= O_APPEND;     /* force append mode */
  146                         fil_ptr->filp_flags = oflags;
  147                         r = pipe_open(rip, bits, oflags);
  148                         if (r != ENXIO) {
  149                                 /* See if someone else is doing a rd or wt on
  150                                  * the FIFO.  If so, use its filp entry so the
  151                                  * file position will be automatically shared.
  152                                  */
  153                                 b = (bits & R_BIT ? R_BIT : W_BIT);
  154                                 fil_ptr->filp_count = 0; /* don't find self */
  155                                 if ((filp2 = find_filp(rip, b)) != NIL_FILP) {
  156                                         /* Co-reader or writer found. Use it.*/
  157                                         fp->fp_filp[m_in.fd] = filp2;
  158                                         filp2->filp_count++;
  159                                         filp2->filp_ino = rip;
  160                                         filp2->filp_flags = oflags;
  161 
  162                                         /* i_count was incremented incorrectly
  163                                          * by eatpath above, not knowing that
  164                                          * we were going to use an existing
  165                                          * filp entry.  Correct this error.
  166                                          */
  167                                         rip->i_count--;
  168                                 } else {
  169                                         /* Nobody else found.  Restore filp. */
  170                                         fil_ptr->filp_count = 1;
  171                                         if (b == R_BIT)
  172                                              pos = rip->i_zone[V2_NR_DZONES+0];
  173                                         else
  174                                              pos = rip->i_zone[V2_NR_DZONES+1];
  175                                         fil_ptr->filp_pos = pos;
  176                                 }
  177                         }
  178                         break;
  179                 }
  180         }
  181   }
  182 
  183   /* If error, release inode. */
  184   if (r != OK) {
  185         if (r == SUSPEND) return(r);            /* Oops, just suspended */
  186         fp->fp_filp[m_in.fd] = NIL_FILP;
  187         fil_ptr->filp_count= 0;
  188         put_inode(rip);
  189         return(r);
  190   }
  191   
  192   return(m_in.fd);
  193 }
  194 
  195 /*===========================================================================*
  196  *                              new_node                                     *
  197  *===========================================================================*/
  198 PRIVATE struct inode *new_node(char *path, mode_t bits, zone_t z0)
  199 {
  200 /* New_node() is called by common_open(), do_mknod(), and do_mkdir().  
  201  * In all cases it allocates a new inode, makes a directory entry for it on 
  202  * the path 'path', and initializes it.  It returns a pointer to the inode if 
  203  * it can do this; otherwise it returns NIL_INODE.  It always sets 'err_code'
  204  * to an appropriate value (OK or an error code).
  205  */
  206 
  207   register struct inode *rlast_dir_ptr, *rip;
  208   register int r;
  209   char string[NAME_MAX];
  210 
  211   /* See if the path can be opened down to the last directory. */
  212   if ((rlast_dir_ptr = last_dir(path, string)) == NIL_INODE) return(NIL_INODE);
  213 
  214   /* The final directory is accessible. Get final component of the path. */
  215   rip = advance(rlast_dir_ptr, string);
  216   if ( rip == NIL_INODE && err_code == ENOENT) {
  217         /* Last path component does not exist.  Make new directory entry. */
  218         if ( (rip = alloc_inode(rlast_dir_ptr->i_dev, bits)) == NIL_INODE) {
  219                 /* Can't creat new inode: out of inodes. */
  220                 put_inode(rlast_dir_ptr);
  221                 return(NIL_INODE);
  222         }
  223 
  224         /* Force inode to the disk before making directory entry to make
  225          * the system more robust in the face of a crash: an inode with
  226          * no directory entry is much better than the opposite.
  227          */
  228         rip->i_nlinks++;
  229         rip->i_zone[0] = z0;            /* major/minor device numbers */
  230         rw_inode(rip, WRITING);         /* force inode to disk now */
  231 
  232         /* New inode acquired.  Try to make directory entry. */
  233         if ((r = search_dir(rlast_dir_ptr, string, &rip->i_num,ENTER)) != OK) {
  234                 put_inode(rlast_dir_ptr);
  235                 rip->i_nlinks--;        /* pity, have to free disk inode */
  236                 rip->i_dirt = DIRTY;    /* dirty inodes are written out */
  237                 put_inode(rip); /* this call frees the inode */
  238                 err_code = r;
  239                 return(NIL_INODE);
  240         }
  241 
  242   } else {
  243         /* Either last component exists, or there is some problem. */
  244         if (rip != NIL_INODE)
  245                 r = EEXIST;
  246         else
  247                 r = err_code;
  248   }
  249 
  250   /* Return the directory inode and exit. */
  251   put_inode(rlast_dir_ptr);
  252   err_code = r;
  253   return(rip);
  254 }
  255 
  256 /*===========================================================================*
  257  *                              pipe_open                                    *
  258  *===========================================================================*/
  259 PRIVATE int pipe_open(register struct inode *rip, register mode_t bits,
  260         register int oflags)
  261 {
  262 /*  This function is called from common_open. It checks if
  263  *  there is at least one reader/writer pair for the pipe, if not
  264  *  it suspends the caller, otherwise it revives all other blocked
  265  *  processes hanging on the pipe.
  266  */
  267 
  268   rip->i_pipe = I_PIPE; 
  269   if (find_filp(rip, bits & W_BIT ? R_BIT : W_BIT) == NIL_FILP) { 
  270         if (oflags & O_NONBLOCK) {
  271                 if (bits & W_BIT) return(ENXIO);
  272         } else {
  273                 suspend(XPOPEN);        /* suspend caller */
  274                 return(SUSPEND);
  275         }
  276   } else if (susp_count > 0) {/* revive blocked processes */
  277         release(rip, OPEN, susp_count);
  278         release(rip, CREAT, susp_count);
  279   }
  280   return(OK);
  281 }
  282 
  283 /*===========================================================================*
  284  *                              do_mknod                                     *
  285  *===========================================================================*/
  286 PUBLIC int do_mknod()
  287 {
  288 /* Perform the mknod(name, mode, addr) system call. */
  289 
  290   register mode_t bits, mode_bits;
  291   struct inode *ip;
  292 
  293   /* Only the super_user may make nodes other than fifos. */
  294   mode_bits = (mode_t) m_in.mk_mode;            /* mode of the inode */
  295   if (!super_user && ((mode_bits & I_TYPE) != I_NAMED_PIPE)) return(EPERM);
  296   if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
  297   bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask);
  298   ip = new_node(user_path, bits, (zone_t) m_in.mk_z0);
  299   put_inode(ip);
  300   return(err_code);
  301 }
  302 
  303 /*===========================================================================*
  304  *                              do_mkdir                                     *
  305  *===========================================================================*/
  306 PUBLIC int do_mkdir()
  307 {
  308 /* Perform the mkdir(name, mode) system call. */
  309 
  310   int r1, r2;                   /* status codes */
  311   ino_t dot, dotdot;            /* inode numbers for . and .. */
  312   mode_t bits;                  /* mode bits for the new inode */
  313   char string[NAME_MAX];        /* last component of the new dir's path name */
  314   register struct inode *rip, *ldirp;
  315 
  316   /* Check to see if it is possible to make another link in the parent dir. */
  317   if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
  318   ldirp = last_dir(user_path, string);  /* pointer to new dir's parent */
  319   if (ldirp == NIL_INODE) return(err_code);
  320   if (ldirp->i_nlinks >= (ldirp->i_sp->s_version == V1 ?
  321          CHAR_MAX : SHRT_MAX)) {
  322         put_inode(ldirp);       /* return parent */
  323         return(EMLINK);
  324   }
  325 
  326   /* Next make the inode. If that fails, return error code. */
  327   bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask);
  328   rip = new_node(user_path, bits, (zone_t) 0);
  329   if (rip == NIL_INODE || err_code == EEXIST) {
  330         put_inode(rip);         /* can't make dir: it already exists */
  331         put_inode(ldirp);       /* return parent too */
  332         return(err_code);
  333   }
  334 
  335   /* Get the inode numbers for . and .. to enter in the directory. */
  336   dotdot = ldirp->i_num;        /* parent's inode number */
  337   dot = rip->i_num;             /* inode number of the new dir itself */
  338 
  339   /* Now make dir entries for . and .. unless the disk is completely full. */
  340   /* Use dot1 and dot2, so the mode of the directory isn't important. */
  341   rip->i_mode = bits;   /* set mode */
  342   r1 = search_dir(rip, dot1, &dot, ENTER);      /* enter . in the new dir */
  343   r2 = search_dir(rip, dot2, &dotdot, ENTER);   /* enter .. in the new dir */
  344 
  345   /* If both . and .. were successfully entered, increment the link counts. */
  346   if (r1 == OK && r2 == OK) {
  347         /* Normal case.  It was possible to enter . and .. in the new dir. */
  348         rip->i_nlinks++;        /* this accounts for . */
  349         ldirp->i_nlinks++;      /* this accounts for .. */
  350         ldirp->i_dirt = DIRTY;  /* mark parent's inode as dirty */
  351   } else {
  352         /* It was not possible to enter . or .. probably disk was full. */
  353         (void) search_dir(ldirp, string, (ino_t *) 0, DELETE);
  354         rip->i_nlinks--;        /* undo the increment done in new_node() */
  355   }
  356   rip->i_dirt = DIRTY;          /* either way, i_nlinks has changed */
  357 
  358   put_inode(ldirp);             /* return the inode of the parent dir */
  359   put_inode(rip);               /* return the inode of the newly made dir */
  360   return(err_code);             /* new_node() always sets 'err_code' */
  361 }
  362 
  363 /*===========================================================================*
  364  *                              do_close                                     *
  365  *===========================================================================*/
  366 PUBLIC int do_close()
  367 {
  368 /* Perform the close(fd) system call. */
  369 
  370   register struct filp *rfilp;
  371   register struct inode *rip;
  372   struct file_lock *flp;
  373   int rw, mode_word, lock_count;
  374   dev_t dev;
  375 
  376   /* First locate the inode that belongs to the file descriptor. */
  377   if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
  378   rip = rfilp->filp_ino;        /* 'rip' points to the inode */
  379 
  380   if (rfilp->filp_count - 1 == 0 && rfilp->filp_mode != FILP_CLOSED) {
  381         /* Check to see if the file is special. */
  382         mode_word = rip->i_mode & I_TYPE;
  383         if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) {
  384                 dev = (dev_t) rip->i_zone[0];
  385                 if (mode_word == I_BLOCK_SPECIAL)  {
  386                         /* Invalidate cache entries unless special is mounted
  387                          * or ROOT
  388                          */
  389                         if (!mounted(rip)) {
  390                                 (void) do_sync();       /* purge cache */
  391                                 invalidate(dev);
  392                         }    
  393                 }
  394                 /* Do any special processing on device close. */
  395                 dev_close(dev);
  396         }
  397   }
  398 
  399   /* If the inode being closed is a pipe, release everyone hanging on it. */
  400   if (rip->i_pipe == I_PIPE) {
  401         rw = (rfilp->filp_mode & R_BIT ? WRITE : READ);
  402         release(rip, rw, NR_PROCS);
  403   }
  404 
  405   /* If a write has been done, the inode is already marked as DIRTY. */
  406   if (--rfilp->filp_count == 0) {
  407         if (rip->i_pipe == I_PIPE && rip->i_count > 1) {
  408                 /* Save the file position in the i-node in case needed later.
  409                  * The read and write positions are saved separately.  The
  410                  * last 3 zones in the i-node are not used for (named) pipes.
  411                  */
  412                 if (rfilp->filp_mode == R_BIT)
  413                         rip->i_zone[V2_NR_DZONES+0] = (zone_t) rfilp->filp_pos;
  414                 else
  415                         rip->i_zone[V2_NR_DZONES+1] = (zone_t) rfilp->filp_pos;
  416         }
  417         put_inode(rip);
  418   }
  419 
  420   fp->fp_cloexec &= ~(1L << m_in.fd);   /* turn off close-on-exec bit */
  421   fp->fp_filp[m_in.fd] = NIL_FILP;
  422 
  423   /* Check to see if the file is locked.  If so, release all locks. */
  424   if (nr_locks == 0) return(OK);
  425   lock_count = nr_locks;        /* save count of locks */
  426   for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
  427         if (flp->lock_type == 0) continue;      /* slot not in use */
  428         if (flp->lock_inode == rip && flp->lock_pid == fp->fp_pid) {
  429                 flp->lock_type = 0;
  430                 nr_locks--;
  431         }
  432   }
  433   if (nr_locks < lock_count) lock_revive();     /* lock released */
  434   return(OK);
  435 }
  436 
  437 /*===========================================================================*
  438  *                              do_lseek                                     *
  439  *===========================================================================*/
  440 PUBLIC int do_lseek()
  441 {
  442 /* Perform the lseek(ls_fd, offset, whence) system call. */
  443 
  444   register struct filp *rfilp;
  445   register off_t pos;
  446 
  447   /* Check to see if the file descriptor is valid. */
  448   if ( (rfilp = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code);
  449 
  450   /* No lseek on pipes. */
  451   if (rfilp->filp_ino->i_pipe == I_PIPE) return(ESPIPE);
  452 
  453   /* The value of 'whence' determines the start position to use. */
  454   switch(m_in.whence) {
  455         case 0: pos = 0;        break;
  456         case 1: pos = rfilp->filp_pos;  break;
  457         case 2: pos = rfilp->filp_ino->i_size;  break;
  458         default: return(EINVAL);
  459   }
  460 
  461   /* Check for overflow. */
  462   if (((long)m_in.offset > 0) && ((long)(pos + m_in.offset) < (long)pos)) 
  463         return(EINVAL);
  464   if (((long)m_in.offset < 0) && ((long)(pos + m_in.offset) > (long)pos)) 
  465         return(EINVAL);
  466   pos = pos + m_in.offset;
  467 
  468   if (pos != rfilp->filp_pos)
  469         rfilp->filp_ino->i_seek = ISEEK;        /* inhibit read ahead */
  470   rfilp->filp_pos = pos;
  471   m_out.reply_l1 = pos;         /* insert the long into the output message */
  472   return(OK);
  473 }

Cache object: 3d1920acc38c81acae136240ff806ee3


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