1 /****************************************************************************
2 * fs/vfs/fs_pwrite.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) 2014, 2016-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 "errno.h"
48
49 #include "fs/file.h"
50
51 /****************************************************************************
52 * Public Functions
53 ****************************************************************************/
54
55 /****************************************************************************
56 * Name: file_pwrite
57 *
58 * Description:
59 * Equivalent to the standard pwrite function except that is accepts a
60 * struct file instance instead of a file descriptor. Currently used
61 * only by aio_write();
62 *
63 ****************************************************************************/
64
file_pwrite64(struct file * filep,const void * buf,size_t nbytes,off64_t offset)65 static ssize_t file_pwrite64(struct file *filep, const void *buf,
66 size_t nbytes, off64_t offset)
67 {
68 off64_t savepos;
69 off64_t pos;
70 ssize_t ret;
71 int errcode;
72
73 /* Perform the seek to the current position. This will not move the
74 * file pointer, but will return its current setting
75 */
76
77 savepos = file_seek64(filep, 0, SEEK_CUR);
78 if (savepos == (off64_t)-1)
79 {
80 /* file_seek64 might fail if this if the media is not seekable */
81
82 return VFS_ERROR;
83 }
84
85 /* Then seek to the correct position in the file */
86
87 pos = file_seek64(filep, offset, SEEK_SET);
88 if (pos == (off64_t)-1)
89 {
90 /* This might fail is the offset is beyond the end of file */
91
92 return VFS_ERROR;
93 }
94
95 /* Then perform the write operation */
96
97 ret = file_write(filep, buf, nbytes);
98 errcode = get_errno();
99
100 /* Restore the file position */
101
102 pos = file_seek64(filep, savepos, SEEK_SET);
103 if (pos == (off64_t)-1 && ret >= 0)
104 {
105 /* This really should not fail */
106
107 return VFS_ERROR;
108 }
109
110 if (errcode != 0)
111 {
112 set_errno(errcode);
113 }
114 return ret;
115 }
116
117 /****************************************************************************
118 * Name: pwrite64
119 *
120 * Description:
121 * The pwrite64() function performs the same action as write(), except that
122 * it writes into a given position without changing the file pointer. The
123 * first three arguments to pwrite() are the same as write() with the
124 * addition of a fourth argument offset for the desired position inside
125 * the file.
126 *
127 * NOTE: This function could have been wholly implemented within libc but
128 * it is not. Why? Because if pwrite were implemented in libc, it would
129 * require four system calls. If it is implemented within the kernel,
130 * only three.
131 *
132 * Input Parameters:
133 * fd file descriptor (or socket descriptor) to write to
134 * buf Data to write
135 * nbytes Length of data to write
136 *
137 * Returned Value:
138 * The positive non-zero number of bytes read on success, 0 on if an
139 * end-of-file condition, or -1 on failure with errno set appropriately.
140 * See write() return values
141 *
142 * Assumptions/Limitations:
143 * POSIX requires that opening a file with the O_APPEND flag should have no
144 * effect on the location at which pwrite() writes data. However, on NuttX
145 * like on Linux, if a file is opened with O_APPEND, pwrite() appends data
146 * to the end of the file, regardless of the value of offset.
147 *
148 ****************************************************************************/
149
pwrite64(int fd,const void * buf,size_t nbytes,off64_t offset)150 ssize_t pwrite64(int fd, const void *buf, size_t nbytes, off64_t offset)
151 {
152 struct file *filep;
153
154 /* Get the file structure corresponding to the file descriptor. */
155
156 int ret = fs_getfilep(fd, &filep);
157 if (ret < 0)
158 {
159 /* The errno value has already been set */
160 return (ssize_t)VFS_ERROR;
161 }
162
163 if (filep->f_oflags & O_DIRECTORY)
164 {
165 set_errno(EBADF);
166 return VFS_ERROR;
167 }
168
169 /* Let file_pread do the real work */
170
171 return file_pwrite64(filep, buf, nbytes, offset);
172 }
173