1 /****************************************************************************
2 * fs/vfs/fs_pread.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 "errno.h"
30
31 #include "fs/file.h"
32
33 /****************************************************************************
34 * Public Functions
35 ****************************************************************************/
36
37 /****************************************************************************
38 * Name: file_pread
39 *
40 * Description:
41 * Equivalent to the standard pread function except that is accepts a
42 * struct file instance instead of a file descriptor. Currently used
43 * only by aio_read();
44 *
45 ****************************************************************************/
46
file_pread(struct file * filep,void * buf,size_t nbytes,off_t offset)47 ssize_t file_pread(struct file *filep, void *buf, size_t nbytes,
48 off_t offset)
49 {
50 off_t savepos;
51 off_t pos;
52 ssize_t ret;
53 int errcode;
54
55 /* Perform the seek to the current position. This will not move the
56 * file pointer, but will return its current setting
57 */
58
59 savepos = file_seek(filep, 0, SEEK_CUR);
60 if (savepos == (off_t)-1)
61 {
62 /* file_seek might fail if this if the media is not seekable */
63
64 return VFS_ERROR;
65 }
66
67 /* Then seek to the correct position in the file */
68
69 pos = file_seek(filep, offset, SEEK_SET);
70 if (pos == (off_t)-1)
71 {
72 /* This might fail is the offset is beyond the end of file */
73
74 return VFS_ERROR;
75 }
76
77 /* Then perform the read operation */
78
79 ret = file_read(filep, buf, nbytes);
80 errcode = get_errno();
81
82 /* Restore the file position */
83
84 pos = file_seek(filep, savepos, SEEK_SET);
85 if (pos == (off_t)-1 && ret >= 0)
86 {
87 /* This really should not fail */
88
89 return VFS_ERROR;
90 }
91
92 if (errcode != 0)
93 {
94 set_errno(errcode);
95 }
96 return ret;
97 }
98
99 /****************************************************************************
100 * Name: pread
101 *
102 * Description:
103 * The pread() function performs the same action as read(), except that it
104 * reads from a given position in the file without changing the file
105 * pointer. The first three arguments to pread() are the same as read()
106 * with the addition of a fourth argument offset for the desired position
107 * inside the file. An attempt to perform a pread() on a file that is
108 * incapable of seeking results in an error.
109 *
110 * NOTE: This function could have been wholly implemented within libc but
111 * it is not. Why? Because if pread were implemented in libc, it would
112 * require four system calls. If it is implemented within the kernel,
113 * only three.
114 *
115 * Input Parameters:
116 * file File structure instance
117 * buf User-provided to save the data
118 * nbytes The maximum size of the user-provided buffer
119 * offset The file offset
120 *
121 * Returned Value:
122 * The positive non-zero number of bytes read on success, 0 on if an
123 * end-of-file condition, or -1 on failure with errno set appropriately.
124 * See read() return values
125 *
126 ****************************************************************************/
127
pread(int fd,void * buf,size_t nbytes,off_t offset)128 ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset)
129 {
130 struct file *filep;
131
132 /* Get the file structure corresponding to the file descriptor. */
133
134 int ret = fs_getfilep(fd, &filep);
135 if (ret < 0)
136 {
137 /* The errno value has already been set */
138 set_errno(-ret);
139 return (ssize_t)VFS_ERROR;
140 }
141
142 if (filep->f_oflags & O_DIRECTORY)
143 {
144 set_errno(EBADF);
145 return (ssize_t)VFS_ERROR;
146 }
147
148 /* Let file_pread do the real work */
149
150 return file_pread(filep, buf, nbytes, offset);
151 }
152