1 /****************************************************************************
2 * fs/vfs/fs_lseek.c
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership. The
7 * ASF licenses this file to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance with the
9 * License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 * License for the specific language governing permissions and limitations
17 * under the License.
18 *
19 ****************************************************************************/
20
21 /****************************************************************************
22 * Included Files
23 ****************************************************************************/
24
25 #include <vfs_config.h>
26
27 #include "sys/types.h"
28 #include "unistd.h"
29 #include "sched.h"
30 #include "assert.h"
31 #include "errno.h"
32 #include "vnode.h"
33
34 #if CONFIG_NFILE_DESCRIPTORS > 0
35
36 /****************************************************************************
37 * Public Functions
38 ****************************************************************************/
39
40 /****************************************************************************
41 * Name: file_seek
42 *
43 * Description:
44 * This is the internal implementation of lseek. See the comments in
45 * lseek() for further information.
46 *
47 * Input Parameters:
48 * file File structure instance
49 * offset Defines the offset to position to
50 * whence Defines how to use offset
51 *
52 * Returned Value:
53 * The resulting offset on success. A negated errno value is returned on
54 * any failure (see lseek comments).
55 *
56 ****************************************************************************/
57
file_seek(struct file * filep,off_t offset,int whence)58 off_t file_seek(struct file *filep, off_t offset, int whence)
59 {
60 struct Vnode *vnode;
61 int err = OK;
62 off_t pos;
63
64 vnode = filep->f_vnode;
65
66 if (!vnode)
67 {
68 err = -EBADF;
69 goto errout;
70 }
71
72 /* Invoke the file seek method if available */
73
74 if (filep->ops != NULL && filep->ops->seek != NULL)
75 {
76 pos = filep->ops->seek(filep, offset, whence);
77 if (pos < 0)
78 {
79 err = pos;
80 goto errout;
81 }
82 else
83 {
84 filep->f_pos = pos;
85 }
86 }
87 else
88 { /* No... Just set the common file position value */
89 switch (whence)
90 {
91 case SEEK_CUR:
92 offset += (off_t)filep->f_pos;
93
94 /* FALLTHROUGH */
95
96 case SEEK_SET:
97 if (offset >= 0)
98 {
99 filep->f_pos = (loff_t)offset; /* Might be beyond the end-of-file */
100 }
101 else
102 {
103 err = -EINVAL;
104 goto errout;
105 }
106 break;
107 case SEEK_END:
108 err = -ENOSYS;
109 goto errout;
110
111 default:
112 err = -EINVAL;
113 goto errout;
114 }
115 }
116
117 return (off_t)filep->f_pos;
118
119 errout:
120 set_errno(-err);
121 return (off_t)VFS_ERROR;
122 }
123
124 /****************************************************************************
125 * Name: lseek
126 *
127 * Description:
128 * The lseek() function repositions the offset of the open file associated
129 * with the file descriptor fd to the argument 'offset' according to the
130 * directive 'whence' as follows:
131 *
132 * SEEK_SET
133 * The offset is set to offset bytes.
134 * SEEK_CUR
135 * The offset is set to its current location plus offset bytes.
136 * SEEK_END
137 * The offset is set to the size of the file plus offset bytes.
138 *
139 * The lseek() function allows the file offset to be set beyond the end of the
140 * file (but this does not change the size of the file). If data is later written
141 * at this point, subsequent reads of the data in the gap (a "hole") return null
142 * bytes ('\0') until data is actually written into the gap.
143 *
144 * Input Parameters:
145 * fd File descriptor of device
146 * offset Defines the offset to position to
147 * whence Defines how to use offset
148 *
149 * Returned Value:
150 * The resulting offset on success. -1 on failure withi errno set properly:
151 *
152 * EBADF fd is not an open file descriptor.
153 * EINVAL whence is not one of SEEK_SET, SEEK_CUR, SEEK_END; or the
154 * resulting file offset would be negative, or beyond the end of a
155 * seekable device.
156 * EOVERFLOW The resulting file offset cannot be represented in an off_t.
157 * ESPIPE fd is associated with a pipe, socket, or FIFO.
158 *
159 ****************************************************************************/
160
lseek(int fd,off_t offset,int whence)161 off_t lseek(int fd, off_t offset, int whence)
162 {
163 struct file *filep;
164
165 /* Get the file structure corresponding to the file descriptor. */
166
167 int ret = fs_getfilep(fd, &filep);
168 if (ret < 0)
169 {
170 /* The errno value has already been set */
171 return (off_t)VFS_ERROR;
172 }
173
174 /* Then let file_seek do the real work */
175
176 return file_seek(filep, offset, whence);
177 }
178 #endif
179