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/common/syscall/lseek.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  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or http://www.opensolaris.org/os/licensing.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 /*
   22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
   23  * Use is subject to license terms.
   24  */
   25 
   26 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
   27 /*        All Rights Reserved   */
   28 
   29 /*
   30  * Portions of this source code were derived from Berkeley 4.3 BSD
   31  * under license from the Regents of the University of California.
   32  */
   33 
   34 #pragma ident   "%Z%%M% %I%     %E% SMI"
   35 
   36 #include <sys/param.h>
   37 #include <sys/isa_defs.h>
   38 #include <sys/types.h>
   39 #include <sys/sysmacros.h>
   40 #include <sys/cred.h>
   41 #include <sys/systm.h>
   42 #include <sys/errno.h>
   43 #include <sys/vnode.h>
   44 #include <sys/file.h>
   45 #include <sys/debug.h>
   46 #include <sys/cmn_err.h>
   47 #include <sys/filio.h>
   48 
   49 /*
   50  * These are defined in unistd.h - but we can't include that
   51  */
   52 #define SEEK_SET        0       /* Set file pointer to "offset" */
   53 #define SEEK_CUR        1       /* Set file pointer to current plus "offset" */
   54 #define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
   55 #define SEEK_DATA       3       /* Set file pointer to next data past offset */
   56 #define SEEK_HOLE       4       /* Set file pointer to next hole past offset */
   57 
   58 /*
   59  * Seek on a file
   60  */
   61 
   62 #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
   63 /*
   64  * Workhorse for the 32-bit seek variants: lseek32 and llseek32
   65  *
   66  * 'max' represents the maximum possible representation of offset
   67  * in the data type corresponding to lseek and llseek. It is
   68  * MAXOFF32_T for off32_t and MAXOFFSET_T for off64_t.
   69  * We return EOVERFLOW if we cannot represent the resulting offset
   70  * in the data type.
   71  * We provide support for character devices to be seeked beyond MAXOFF32_T
   72  * by lseek. To maintain compatibility in such cases lseek passes
   73  * the arguments carefully to lseek_common when file is not regular.
   74  * (/dev/kmem is a good example of a > 2Gbyte seek!)
   75  */
   76 static int
   77 lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
   78     offset_t *retoff)
   79 {
   80         vnode_t *vp;
   81         struct vattr vattr;
   82         int error;
   83         u_offset_t noff;
   84         offset_t curoff, newoff;
   85         int reg;
   86 
   87         vp = fp->f_vnode;
   88         reg = (vp->v_type == VREG);
   89 
   90         curoff = fp->f_offset;
   91 
   92         switch (stype) {
   93         case SEEK_SET:
   94                 noff = (u_offset_t)off;
   95                 if (reg && noff > max) {
   96                         error = EINVAL;
   97                         goto out;
   98                 }
   99                 break;
  100 
  101         case SEEK_CUR:
  102                 if (reg && off > (max - curoff)) {
  103                         error = EOVERFLOW;
  104                         goto out;
  105                 }
  106                 noff = (u_offset_t)(off + curoff);
  107                 if (reg && noff > max) {
  108                         error = EINVAL;
  109                         goto out;
  110                 }
  111                 break;
  112 
  113         case SEEK_END:
  114                 vattr.va_mask = AT_SIZE;
  115                 if (error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL)) {
  116                         goto out;
  117                 }
  118                 if (reg && (off  > (max - (offset_t)vattr.va_size))) {
  119                         error = EOVERFLOW;
  120                         goto out;
  121                 }
  122                 noff = (u_offset_t)(off + (offset_t)vattr.va_size);
  123                 if (reg && noff > max) {
  124                         error = EINVAL;
  125                         goto out;
  126                 }
  127                 break;
  128 
  129         case SEEK_DATA:
  130                 /*
  131                  * Get and set the file pointer to the offset of the next
  132                  * data past "off"
  133                  */
  134                 noff = (u_offset_t)off;
  135                 error = VOP_IOCTL(vp, _FIO_SEEK_DATA, (intptr_t)(&noff),
  136                     FKIOCTL, kcred, NULL, NULL);
  137                 if (error) {
  138                         if (error != ENOTTY)
  139                                 return (error);
  140                         /*
  141                          * The ioctl is not supported, check the supplied
  142                          * "off" is not past the end of file
  143                          */
  144                         vattr.va_mask = AT_SIZE;
  145                         error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
  146                         if (error)
  147                                 return (error);
  148                         if (noff >= (u_offset_t)vattr.va_size)
  149                                 return (ENXIO);
  150                 }
  151                 if (reg && (noff > max))
  152                         return (EOVERFLOW);
  153 
  154                 fp->f_offset = (offset_t)noff;
  155                 (*retoff) = (offset_t)noff;
  156                 return (0);
  157 
  158         case SEEK_HOLE:
  159                 /*
  160                  * Get and set the file pointer to the offset of the next
  161                  * hole past "off"
  162                  */
  163                 noff = (u_offset_t)off;
  164                 error = VOP_IOCTL(vp, _FIO_SEEK_HOLE, (intptr_t)(&noff),
  165                     FKIOCTL, kcred, NULL, NULL);
  166                 if (error) {
  167                         if (error != ENOTTY)
  168                                 return (error);
  169                         /*
  170                          * ioctl is not supported, if the off is valid return
  171                          * the "virtual hole" at the end of the file.
  172                          */
  173                         vattr.va_mask = AT_SIZE;
  174                         error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
  175                         if (error)
  176                                 return (error);
  177                         if (off < (offset_t)vattr.va_size)
  178                                 noff = (u_offset_t)vattr.va_size;
  179                         else
  180                                 return (ENXIO);
  181                 }
  182                 if (reg && (noff > max))
  183                         return (EOVERFLOW);
  184 
  185                 fp->f_offset = (offset_t)noff;
  186                 (*retoff) = (offset_t)noff;
  187                 return (0);
  188 
  189         default:
  190                 error = EINVAL;
  191                 goto out;
  192         }
  193 
  194         ASSERT((reg && noff <= max) || !reg);
  195         newoff = (offset_t)noff;
  196         if ((error = VOP_SEEK(vp, curoff, &newoff, NULL)) == 0) {
  197                 fp->f_offset = newoff;
  198                 (*retoff) = newoff;
  199                 return (0);
  200         }
  201 out:
  202         return (error);
  203 }
  204 
  205 off32_t
  206 lseek32(int32_t fdes, off32_t off, int32_t stype)
  207 {
  208         file_t *fp;
  209         int error;
  210         offset_t retoff;
  211 
  212         if ((fp = getf(fdes)) == NULL)
  213                 return ((off32_t)set_errno(EBADF));
  214 
  215         /*
  216          * lseek32 returns EOVERFLOW if we cannot represent the resulting
  217          * offset from seek in a 32-bit off_t.
  218          * The following routines are sensitive to sign extensions and
  219          * calculations and if ever you change this make sure it works for
  220          * special files.
  221          *
  222          * When VREG is not set we do the check for stype != SEEK_SET
  223          * to send the unsigned value to lseek_common and not the sign
  224          * extended value. (The maximum representable value is not
  225          * checked by lseek_common for special files.)
  226          */
  227         if (fp->f_vnode->v_type == VREG || stype != SEEK_SET)
  228                 error = lseek32_common(fp, stype, (offset_t)off,
  229                     (offset_t)MAXOFF32_T, &retoff);
  230         else if (stype == SEEK_SET)
  231                 error = lseek32_common(fp, stype, (offset_t)(uint_t)off,
  232                     (offset_t)(uint_t)UINT_MAX, &retoff);
  233 
  234         releasef(fdes);
  235         if (!error)
  236                 return ((off32_t)retoff);
  237         return ((off32_t)set_errno(error));
  238 }
  239 
  240 /*
  241  * 64-bit seeks from 32-bit applications
  242  */
  243 offset_t
  244 llseek32(int32_t fdes, uint32_t off1, uint32_t off2, int stype)
  245 {
  246         file_t *fp;
  247         int error;
  248         offset_t retoff;
  249 #if defined(_LITTLE_ENDIAN)
  250         offset_t off = ((u_offset_t)off2 << 32) | (u_offset_t)off1;
  251 #else
  252         offset_t off = ((u_offset_t)off1 << 32) | (u_offset_t)off2;
  253 #endif
  254 
  255         if ((fp = getf(fdes)) == NULL)
  256                 error = EBADF;
  257         else {
  258                 error = lseek32_common(fp, stype, off, MAXOFFSET_T, &retoff);
  259                 releasef(fdes);
  260         }
  261 
  262         return (error ? (offset_t)set_errno(error) : retoff);
  263 }
  264 #endif  /* _SYSCALL32_IMPL || _ILP32 */
  265 
  266 #ifdef _LP64
  267 /*
  268  * Seek on a file.
  269  *
  270  * Life is almost simple again (at least until we do 128-bit files ;-)
  271  * This is both 'lseek' and 'llseek' to a 64-bit application.
  272  */
  273 off_t
  274 lseek64(int fdes, off_t off, int stype)
  275 {
  276         file_t *fp;
  277         vnode_t *vp;
  278         struct vattr vattr;
  279         int error;
  280         off_t old_off;
  281         offset_t new_off;
  282 
  283         if ((fp = getf(fdes)) == NULL)
  284                 return ((off_t)set_errno(EBADF));
  285 
  286         vp = fp->f_vnode;
  287         new_off = off;
  288 
  289         switch (stype) {
  290         case SEEK_CUR:
  291                 new_off += fp->f_offset;
  292                 break;
  293 
  294         case SEEK_END:
  295                 vattr.va_mask = AT_SIZE;
  296                 if ((error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL)) != 0)
  297                         goto lseek64error;
  298                 new_off += vattr.va_size;
  299                 break;
  300 
  301         case SEEK_SET:
  302                 break;
  303 
  304         case SEEK_DATA:
  305                 /*
  306                  * Get and set the file pointer to the offset of the next
  307                  * data past "off"
  308                  */
  309                 new_off = (offset_t)off;
  310                 error = VOP_IOCTL(vp, _FIO_SEEK_DATA, (intptr_t)(&new_off),
  311                     FKIOCTL, kcred, NULL, NULL);
  312                 if (error) {
  313                         if (error != ENOTTY) {
  314                                 goto lseek64error;
  315                         }
  316                         /*
  317                          * The ioctl is not supported, check the supplied off
  318                          * is not past end of file
  319                          */
  320                         vattr.va_mask = AT_SIZE;
  321                         error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
  322                         if (error)
  323                                 goto lseek64error;
  324                         if (new_off >= (offset_t)vattr.va_size) {
  325                                 error = ENXIO;
  326                                 goto lseek64error;
  327                         }
  328                 }
  329                 fp->f_offset = new_off;
  330                 releasef(fdes);
  331                 return (new_off);
  332 
  333         case SEEK_HOLE:
  334                 /*
  335                  * Get and set the file pointer to the offset of the next
  336                  * hole past "off"
  337                  */
  338                 new_off = off;
  339                 error = VOP_IOCTL(vp, _FIO_SEEK_HOLE, (intptr_t)(&new_off),
  340                     FKIOCTL, kcred, NULL, NULL);
  341                 if (error) {
  342                         if (error != ENOTTY)
  343                                 goto lseek64error;
  344                         /*
  345                          * ioctl is not supported, if the off is valid return
  346                          * the "virtual hole" at the end of the file.
  347                          */
  348                         vattr.va_mask = AT_SIZE;
  349                         error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
  350                         if (error)
  351                                 goto lseek64error;
  352                         if (off < (offset_t)vattr.va_size) {
  353                                 new_off = (offset_t)vattr.va_size;
  354                         } else {
  355                                 error = ENXIO;
  356                                 goto lseek64error;
  357                         }
  358                 }
  359                 fp->f_offset = new_off;
  360                 releasef(fdes);
  361                 return (new_off);
  362 
  363         default:
  364                 error = EINVAL;
  365                 goto lseek64error;
  366         }
  367 
  368         old_off = fp->f_offset;
  369         if ((error = VOP_SEEK(vp, old_off, &new_off, NULL)) == 0) {
  370                 fp->f_offset = new_off;
  371                 releasef(fdes);
  372                 return (new_off);
  373         }
  374 
  375 lseek64error:
  376         releasef(fdes);
  377         return ((off_t)set_errno(error));
  378 }
  379 #endif  /* _LP64 */

Cache object: cb9222973b91394a8dc8c1ed4474c893


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