17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*da6c28aaSamw * Common Development and Distribution License (the "License"). 6*da6c28aaSamw * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*da6c28aaSamw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 317c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <sys/param.h> 377c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 407c478bd9Sstevel@tonic-gate #include <sys/cred.h> 417c478bd9Sstevel@tonic-gate #include <sys/systm.h> 427c478bd9Sstevel@tonic-gate #include <sys/errno.h> 437c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 447c478bd9Sstevel@tonic-gate #include <sys/file.h> 457c478bd9Sstevel@tonic-gate #include <sys/debug.h> 467c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 477c478bd9Sstevel@tonic-gate #include <sys/filio.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * These are defined in unistd.h - but we can't include that 517c478bd9Sstevel@tonic-gate */ 527c478bd9Sstevel@tonic-gate #define SEEK_SET 0 /* Set file pointer to "offset" */ 537c478bd9Sstevel@tonic-gate #define SEEK_CUR 1 /* Set file pointer to current plus "offset" */ 547c478bd9Sstevel@tonic-gate #define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ 557c478bd9Sstevel@tonic-gate #define SEEK_DATA 3 /* Set file pointer to next data past offset */ 567c478bd9Sstevel@tonic-gate #define SEEK_HOLE 4 /* Set file pointer to next hole past offset */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * Seek on a file 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32) 637c478bd9Sstevel@tonic-gate /* 647c478bd9Sstevel@tonic-gate * Workhorse for the 32-bit seek variants: lseek32 and llseek32 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * 'max' represents the maximum possible representation of offset 677c478bd9Sstevel@tonic-gate * in the data type corresponding to lseek and llseek. It is 687c478bd9Sstevel@tonic-gate * MAXOFF32_T for off32_t and MAXOFFSET_T for off64_t. 697c478bd9Sstevel@tonic-gate * We return EOVERFLOW if we cannot represent the resulting offset 707c478bd9Sstevel@tonic-gate * in the data type. 717c478bd9Sstevel@tonic-gate * We provide support for character devices to be seeked beyond MAXOFF32_T 727c478bd9Sstevel@tonic-gate * by lseek. To maintain compatibility in such cases lseek passes 737c478bd9Sstevel@tonic-gate * the arguments carefully to lseek_common when file is not regular. 747c478bd9Sstevel@tonic-gate * (/dev/kmem is a good example of a > 2Gbyte seek!) 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate static int 777c478bd9Sstevel@tonic-gate lseek32_common(file_t *fp, int stype, offset_t off, offset_t max, 787c478bd9Sstevel@tonic-gate offset_t *retoff) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate vnode_t *vp; 817c478bd9Sstevel@tonic-gate struct vattr vattr; 827c478bd9Sstevel@tonic-gate int error; 837c478bd9Sstevel@tonic-gate u_offset_t noff; 847c478bd9Sstevel@tonic-gate offset_t curoff, newoff; 857c478bd9Sstevel@tonic-gate int reg; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 887c478bd9Sstevel@tonic-gate reg = (vp->v_type == VREG); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate curoff = fp->f_offset; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate switch (stype) { 937c478bd9Sstevel@tonic-gate case SEEK_SET: 947c478bd9Sstevel@tonic-gate noff = (u_offset_t)off; 957c478bd9Sstevel@tonic-gate if (reg && noff > max) { 967c478bd9Sstevel@tonic-gate error = EINVAL; 977c478bd9Sstevel@tonic-gate goto out; 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate break; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate case SEEK_CUR: 1027c478bd9Sstevel@tonic-gate if (reg && off > (max - curoff)) { 1037c478bd9Sstevel@tonic-gate error = EOVERFLOW; 1047c478bd9Sstevel@tonic-gate goto out; 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate noff = (u_offset_t)(off + curoff); 1077c478bd9Sstevel@tonic-gate if (reg && noff > max) { 1087c478bd9Sstevel@tonic-gate error = EINVAL; 1097c478bd9Sstevel@tonic-gate goto out; 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate break; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate case SEEK_END: 1147c478bd9Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 115*da6c28aaSamw if (error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL)) { 1167c478bd9Sstevel@tonic-gate goto out; 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate if (reg && (off > (max - (offset_t)vattr.va_size))) { 1197c478bd9Sstevel@tonic-gate error = EOVERFLOW; 1207c478bd9Sstevel@tonic-gate goto out; 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate noff = (u_offset_t)(off + (offset_t)vattr.va_size); 1237c478bd9Sstevel@tonic-gate if (reg && noff > max) { 1247c478bd9Sstevel@tonic-gate error = EINVAL; 1257c478bd9Sstevel@tonic-gate goto out; 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate break; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate case SEEK_DATA: 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * Get and set the file pointer to the offset of the next 1327c478bd9Sstevel@tonic-gate * data past "off" 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate noff = (u_offset_t)off; 1357c478bd9Sstevel@tonic-gate error = VOP_IOCTL(vp, _FIO_SEEK_DATA, (intptr_t)(&noff), 136*da6c28aaSamw FKIOCTL, kcred, NULL, NULL); 1377c478bd9Sstevel@tonic-gate if (error) { 1387c478bd9Sstevel@tonic-gate if (error != ENOTTY) 1397c478bd9Sstevel@tonic-gate return (error); 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * The ioctl is not supported, check the supplied 1427c478bd9Sstevel@tonic-gate * "off" is not past the end of file 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 145*da6c28aaSamw error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL); 1467c478bd9Sstevel@tonic-gate if (error) 1477c478bd9Sstevel@tonic-gate return (error); 1487c478bd9Sstevel@tonic-gate if (noff >= (u_offset_t)vattr.va_size) 1497c478bd9Sstevel@tonic-gate return (ENXIO); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate if (reg && (noff > max)) 1527c478bd9Sstevel@tonic-gate return (EOVERFLOW); 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate fp->f_offset = (offset_t)noff; 1557c478bd9Sstevel@tonic-gate (*retoff) = (offset_t)noff; 1567c478bd9Sstevel@tonic-gate return (0); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate case SEEK_HOLE: 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * Get and set the file pointer to the offset of the next 1617c478bd9Sstevel@tonic-gate * hole past "off" 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate noff = (u_offset_t)off; 1647c478bd9Sstevel@tonic-gate error = VOP_IOCTL(vp, _FIO_SEEK_HOLE, (intptr_t)(&noff), 165*da6c28aaSamw FKIOCTL, kcred, NULL, NULL); 1667c478bd9Sstevel@tonic-gate if (error) { 1677c478bd9Sstevel@tonic-gate if (error != ENOTTY) 1687c478bd9Sstevel@tonic-gate return (error); 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * ioctl is not supported, if the off is valid return 1717c478bd9Sstevel@tonic-gate * the "virtual hole" at the end of the file. 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 174*da6c28aaSamw error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL); 1757c478bd9Sstevel@tonic-gate if (error) 1767c478bd9Sstevel@tonic-gate return (error); 1777c478bd9Sstevel@tonic-gate if (off < (offset_t)vattr.va_size) 1787c478bd9Sstevel@tonic-gate noff = (u_offset_t)vattr.va_size; 1797c478bd9Sstevel@tonic-gate else 1807c478bd9Sstevel@tonic-gate return (ENXIO); 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate if (reg && (noff > max)) 1837c478bd9Sstevel@tonic-gate return (EOVERFLOW); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate fp->f_offset = (offset_t)noff; 1867c478bd9Sstevel@tonic-gate (*retoff) = (offset_t)noff; 1877c478bd9Sstevel@tonic-gate return (0); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate default: 1907c478bd9Sstevel@tonic-gate error = EINVAL; 1917c478bd9Sstevel@tonic-gate goto out; 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate ASSERT((reg && noff <= max) || !reg); 1957c478bd9Sstevel@tonic-gate newoff = (offset_t)noff; 196*da6c28aaSamw if ((error = VOP_SEEK(vp, curoff, &newoff, NULL)) == 0) { 1977c478bd9Sstevel@tonic-gate fp->f_offset = newoff; 1987c478bd9Sstevel@tonic-gate (*retoff) = newoff; 1997c478bd9Sstevel@tonic-gate return (0); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate out: 2027c478bd9Sstevel@tonic-gate return (error); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate off32_t 2067c478bd9Sstevel@tonic-gate lseek32(int32_t fdes, off32_t off, int32_t stype) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate file_t *fp; 2097c478bd9Sstevel@tonic-gate int error; 2107c478bd9Sstevel@tonic-gate offset_t retoff; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 2137c478bd9Sstevel@tonic-gate return ((off32_t)set_errno(EBADF)); 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * lseek32 returns EOVERFLOW if we cannot represent the resulting 2177c478bd9Sstevel@tonic-gate * offset from seek in a 32-bit off_t. 2187c478bd9Sstevel@tonic-gate * The following routines are sensitive to sign extensions and 2197c478bd9Sstevel@tonic-gate * calculations and if ever you change this make sure it works for 2207c478bd9Sstevel@tonic-gate * special files. 2217c478bd9Sstevel@tonic-gate * 2227c478bd9Sstevel@tonic-gate * When VREG is not set we do the check for stype != SEEK_SET 2237c478bd9Sstevel@tonic-gate * to send the unsigned value to lseek_common and not the sign 2247c478bd9Sstevel@tonic-gate * extended value. (The maximum representable value is not 2257c478bd9Sstevel@tonic-gate * checked by lseek_common for special files.) 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate if (fp->f_vnode->v_type == VREG || stype != SEEK_SET) 2287c478bd9Sstevel@tonic-gate error = lseek32_common(fp, stype, (offset_t)off, 2297c478bd9Sstevel@tonic-gate (offset_t)MAXOFF32_T, &retoff); 2307c478bd9Sstevel@tonic-gate else if (stype == SEEK_SET) 2317c478bd9Sstevel@tonic-gate error = lseek32_common(fp, stype, (offset_t)(uint_t)off, 2327c478bd9Sstevel@tonic-gate (offset_t)(uint_t)UINT_MAX, &retoff); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate releasef(fdes); 2357c478bd9Sstevel@tonic-gate if (!error) 2367c478bd9Sstevel@tonic-gate return ((off32_t)retoff); 2377c478bd9Sstevel@tonic-gate return ((off32_t)set_errno(error)); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* 2417c478bd9Sstevel@tonic-gate * 64-bit seeks from 32-bit applications 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate offset_t 2447c478bd9Sstevel@tonic-gate llseek32(int32_t fdes, uint32_t off1, uint32_t off2, int stype) 2457c478bd9Sstevel@tonic-gate { 2467c478bd9Sstevel@tonic-gate file_t *fp; 2477c478bd9Sstevel@tonic-gate int error; 2487c478bd9Sstevel@tonic-gate offset_t retoff; 2497c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN) 2507c478bd9Sstevel@tonic-gate offset_t off = ((u_offset_t)off2 << 32) | (u_offset_t)off1; 2517c478bd9Sstevel@tonic-gate #else 2527c478bd9Sstevel@tonic-gate offset_t off = ((u_offset_t)off1 << 32) | (u_offset_t)off2; 2537c478bd9Sstevel@tonic-gate #endif 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 2567c478bd9Sstevel@tonic-gate error = EBADF; 2577c478bd9Sstevel@tonic-gate else { 2587c478bd9Sstevel@tonic-gate error = lseek32_common(fp, stype, off, MAXOFFSET_T, &retoff); 2597c478bd9Sstevel@tonic-gate releasef(fdes); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate return (error ? (offset_t)set_errno(error) : retoff); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL || _ILP32 */ 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate #ifdef _LP64 2677c478bd9Sstevel@tonic-gate /* 2687c478bd9Sstevel@tonic-gate * Seek on a file. 2697c478bd9Sstevel@tonic-gate * 2707c478bd9Sstevel@tonic-gate * Life is almost simple again (at least until we do 128-bit files ;-) 2717c478bd9Sstevel@tonic-gate * This is both 'lseek' and 'llseek' to a 64-bit application. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate off_t 2747c478bd9Sstevel@tonic-gate lseek64(int fdes, off_t off, int stype) 2757c478bd9Sstevel@tonic-gate { 2767c478bd9Sstevel@tonic-gate file_t *fp; 2777c478bd9Sstevel@tonic-gate vnode_t *vp; 2787c478bd9Sstevel@tonic-gate struct vattr vattr; 2797c478bd9Sstevel@tonic-gate int error; 2807c478bd9Sstevel@tonic-gate off_t old_off; 2817c478bd9Sstevel@tonic-gate offset_t new_off; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 2847c478bd9Sstevel@tonic-gate return ((off_t)set_errno(EBADF)); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 2877c478bd9Sstevel@tonic-gate new_off = off; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate switch (stype) { 2907c478bd9Sstevel@tonic-gate case SEEK_CUR: 2917c478bd9Sstevel@tonic-gate new_off += fp->f_offset; 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate case SEEK_END: 2957c478bd9Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 296*da6c28aaSamw if ((error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL)) != 0) 2977c478bd9Sstevel@tonic-gate goto lseek64error; 2987c478bd9Sstevel@tonic-gate new_off += vattr.va_size; 2997c478bd9Sstevel@tonic-gate break; 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate case SEEK_SET: 3027c478bd9Sstevel@tonic-gate break; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate case SEEK_DATA: 3057c478bd9Sstevel@tonic-gate /* 3067c478bd9Sstevel@tonic-gate * Get and set the file pointer to the offset of the next 3077c478bd9Sstevel@tonic-gate * data past "off" 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate new_off = (offset_t)off; 3107c478bd9Sstevel@tonic-gate error = VOP_IOCTL(vp, _FIO_SEEK_DATA, (intptr_t)(&new_off), 311*da6c28aaSamw FKIOCTL, kcred, NULL, NULL); 3127c478bd9Sstevel@tonic-gate if (error) { 3137c478bd9Sstevel@tonic-gate if (error != ENOTTY) { 3147c478bd9Sstevel@tonic-gate goto lseek64error; 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * The ioctl is not supported, check the supplied off 3187c478bd9Sstevel@tonic-gate * is not past end of file 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 321*da6c28aaSamw error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL); 3227c478bd9Sstevel@tonic-gate if (error) 3237c478bd9Sstevel@tonic-gate goto lseek64error; 3247c478bd9Sstevel@tonic-gate if (new_off >= (offset_t)vattr.va_size) { 3257c478bd9Sstevel@tonic-gate error = ENXIO; 3267c478bd9Sstevel@tonic-gate goto lseek64error; 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate fp->f_offset = new_off; 3307c478bd9Sstevel@tonic-gate releasef(fdes); 3317c478bd9Sstevel@tonic-gate return (new_off); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate case SEEK_HOLE: 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * Get and set the file pointer to the offset of the next 3367c478bd9Sstevel@tonic-gate * hole past "off" 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate new_off = off; 3397c478bd9Sstevel@tonic-gate error = VOP_IOCTL(vp, _FIO_SEEK_HOLE, (intptr_t)(&new_off), 340*da6c28aaSamw FKIOCTL, kcred, NULL, NULL); 3417c478bd9Sstevel@tonic-gate if (error) { 3427c478bd9Sstevel@tonic-gate if (error != ENOTTY) 3437c478bd9Sstevel@tonic-gate goto lseek64error; 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * ioctl is not supported, if the off is valid return 3467c478bd9Sstevel@tonic-gate * the "virtual hole" at the end of the file. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 349*da6c28aaSamw error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL); 3507c478bd9Sstevel@tonic-gate if (error) 3517c478bd9Sstevel@tonic-gate goto lseek64error; 3527c478bd9Sstevel@tonic-gate if (off < (offset_t)vattr.va_size) { 3537c478bd9Sstevel@tonic-gate new_off = (offset_t)vattr.va_size; 3547c478bd9Sstevel@tonic-gate } else { 3557c478bd9Sstevel@tonic-gate error = ENXIO; 3567c478bd9Sstevel@tonic-gate goto lseek64error; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate fp->f_offset = new_off; 3607c478bd9Sstevel@tonic-gate releasef(fdes); 3617c478bd9Sstevel@tonic-gate return (new_off); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate default: 3647c478bd9Sstevel@tonic-gate error = EINVAL; 3657c478bd9Sstevel@tonic-gate goto lseek64error; 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate old_off = fp->f_offset; 369*da6c28aaSamw if ((error = VOP_SEEK(vp, old_off, &new_off, NULL)) == 0) { 3707c478bd9Sstevel@tonic-gate fp->f_offset = new_off; 3717c478bd9Sstevel@tonic-gate releasef(fdes); 3727c478bd9Sstevel@tonic-gate return (new_off); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate lseek64error: 3767c478bd9Sstevel@tonic-gate releasef(fdes); 3777c478bd9Sstevel@tonic-gate return ((off_t)set_errno(error)); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate #endif /* _LP64 */ 380