1 /****************************************************************************
2 * fs/vfs/fs_lseek.c
3 *
4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
5 * Based on NuttX originally written by Gregory Nutt
6 *
7 * Copyright (C) 2008, 2017 Gregory Nutt. All rights reserved.
8 * Author: Gregory Nutt <gnutt@nuttx.org>
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 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 * 3. Neither the name NuttX nor the names of its contributors may be
21 * used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
31 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ****************************************************************************/
38
39 /****************************************************************************
40 * Included Files
41 ****************************************************************************/
42
43 #include <vfs_config.h>
44
45 #include "sys/types.h"
46 #include "unistd.h"
47 #include "sched.h"
48 #include "assert.h"
49 #include "errno.h"
50 #include "vnode.h"
51
52 #if CONFIG_NFILE_DESCRIPTORS > 0
53
54 /****************************************************************************
55 * Public Functions
56 ****************************************************************************/
57
58 /****************************************************************************
59 * Name: file_seek64
60 *
61 * Description:
62 * This is the internal implementation of lseek. See the comments in
63 * lseek() for further information.
64 *
65 * Input Parameters:
66 * file File structure instance
67 * offset Defines the offset to position to
68 * whence Defines how to use offset
69 *
70 * Returned Value:
71 * The resulting offset on success. A negated errno value is returned on
72 * any failure (see lseek comments).
73 *
74 ****************************************************************************/
75
file_seek64(struct file * filep,off64_t offset,int whence)76 off64_t file_seek64(struct file *filep, off64_t offset, int whence)
77 {
78 struct Vnode *vnode = NULL;
79 int err = OK;
80 off64_t pos;
81
82 DEBUGASSERT(filep);
83 vnode = filep->f_vnode;
84
85 if (vnode == NULL)
86 {
87 err = -EBADF;
88 goto errout;
89 }
90
91 /* Invoke the file seek method if available */
92
93 if (filep->ops != NULL && filep->ops->seek != NULL)
94 {
95 pos = filep->ops->seek(filep, offset, whence);
96 if (pos < 0)
97 {
98 err = pos;
99 goto errout;
100 }
101 else
102 {
103 filep->f_pos = pos;
104 }
105 }
106 else
107 { /* No... Just set the common file position value */
108 switch (whence)
109 {
110 case SEEK_CUR:
111 offset += filep->f_pos;
112
113 /* FALLTHROUGH */
114
115 case SEEK_SET:
116 if (offset >= 0)
117 {
118 filep->f_pos = offset; /* Might be beyond the end-of-file */
119 }
120 else
121 {
122 err = -EINVAL;
123 goto errout;
124 }
125 break;
126
127 case SEEK_END:
128 err = -ENOSYS;
129 goto errout;
130
131 default:
132 err = -EINVAL;
133 goto errout;
134 }
135 }
136
137 return filep->f_pos;
138
139 errout:
140 set_errno(-err);
141 return (off64_t)VFS_ERROR;
142 }
143
144 /****************************************************************************
145 * Name: lseek64
146 *
147 * Description:
148 * The lseek64() function repositions the offset of the open file associated
149 * with the file descriptor fd to the argument 'offset' according to the
150 * directive 'whence' as follows:
151 *
152 * SEEK_SET
153 * The offset is set to offset bytes.
154 * SEEK_CUR
155 * The offset is set to its current location plus offset bytes.
156 * SEEK_END
157 * The offset is set to the size of the file plus offset bytes.
158 *
159 * The lseek64() function allows the file offset to be set beyond the end of the
160 * file (but this does not change the size of the file). If data is later written
161 * at this point, subsequent reads of the data in the gap (a "hole") return null
162 * bytes ('\0') until data is actually written into the gap.
163 *
164 * Input Parameters:
165 * fd File descriptor of device
166 * offset Defines the offset to position to
167 * whence Defines how to use offset
168 *
169 * Returned Value:
170 * The resulting offset on success. -1 on failure withi errno set properly:
171 *
172 * EBADF fd is not an open file descriptor.
173 * EINVAL whence is not one of SEEK_SET, SEEK_CUR, SEEK_END; or the
174 * resulting file offset would be negative, or beyond the end of a
175 * seekable device.
176 * EOVERFLOW The resulting file offset cannot be represented in an off_t.
177 * ESPIPE fd is associated with a pipe, socket, or FIFO.
178 *
179 ****************************************************************************/
180
lseek64(int fd,off64_t offset,int whence)181 off64_t lseek64(int fd, off64_t offset, int whence)
182 {
183 struct file *filep;
184
185 /* Get the file structure corresponding to the file descriptor. */
186
187 int ret = fs_getfilep(fd, &filep);
188 if (ret < 0)
189 {
190 /* The errno value has already been set */
191 return (off64_t)VFS_ERROR;
192 }
193
194 /* Then let file_seek do the real work */
195
196 return file_seek64(filep, offset, whence);
197 }
198 #endif
199