xref: /freebsd/lib/libc/stdio/ftell.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Chris Torek.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "namespace.h"
36 #include <sys/types.h>
37 #include <errno.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include "un-namespace.h"
41 #include "local.h"
42 #include "libc_private.h"
43 
44 /*
45  * standard ftell function.
46  */
47 long
ftell(FILE * fp)48 ftell(FILE *fp)
49 {
50 	off_t rv;
51 
52 	rv = ftello(fp);
53 	if (rv > LONG_MAX) {
54 		errno = EOVERFLOW;
55 		return (-1);
56 	}
57 	return (rv);
58 }
59 
60 /*
61  * ftello: return current offset.
62  */
63 off_t
ftello(FILE * fp)64 ftello(FILE *fp)
65 {
66 	fpos_t rv;
67 	int ret;
68 
69 	FLOCKFILE(fp);
70 	ret = _ftello(fp, &rv);
71 	FUNLOCKFILE(fp);
72 	if (ret)
73 		return (-1);
74 	if (rv < 0) {   /* Unspecified value because of ungetc() at 0 */
75 		errno = ESPIPE;
76 		return (-1);
77 	}
78 	return (rv);
79 }
80 
81 int
_ftello(FILE * fp,fpos_t * offset)82 _ftello(FILE *fp, fpos_t *offset)
83 {
84 	fpos_t pos;
85 	size_t n;
86 
87 	if (fp->_seek == NULL) {
88 		errno = ESPIPE;			/* historic practice */
89 		return (1);
90 	}
91 
92 	/*
93 	 * Find offset of underlying I/O object, then
94 	 * adjust for buffered bytes.
95 	 */
96 	if (!(fp->_flags & __SRD) && (fp->_flags & __SWR) &&
97 	    fp->_p != NULL && fp->_p - fp->_bf._base > 0 &&
98 	    ((fp->_flags & __SAPP) || (fp->_flags2 & __S2OAP))) {
99 		pos = _sseek(fp, (fpos_t)0, SEEK_END);
100 		if (pos == -1)
101 			return (1);
102 	} else if (fp->_flags & __SOFF)
103 		pos = fp->_offset;
104 	else {
105 		pos = _sseek(fp, (fpos_t)0, SEEK_CUR);
106 		if (pos == -1)
107 			return (1);
108 	}
109 	if (fp->_flags & __SRD) {
110 		/*
111 		 * Reading.  Any unread characters (including
112 		 * those from ungetc) cause the position to be
113 		 * smaller than that in the underlying object.
114 		 */
115 		if ((pos -= (HASUB(fp) ? fp->_ur : fp->_r)) < 0) {
116 			fp->_flags |= __SERR;
117 			errno = EIO;
118 			return (1);
119 		}
120 		if (HASUB(fp))
121 			pos -= fp->_r;  /* Can be negative at this point. */
122 	} else if ((fp->_flags & __SWR) && fp->_p != NULL &&
123 	    (n = fp->_p - fp->_bf._base) > 0) {
124 		/*
125 		 * Writing.  Any buffered characters cause the
126 		 * position to be greater than that in the
127 		 * underlying object.
128 		 */
129 		if (pos > OFF_MAX - n) {
130 			errno = EOVERFLOW;
131 			return (1);
132 		}
133 		pos += n;
134 	}
135 	*offset = pos;
136 	return (0);
137 }
138