1 /****************************************************************************
2 * fs/vfs/fs_pwrite.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_pwrite
39 *
40 * Description:
41 * Equivalent to the standard pwrite function except that is accepts a
42 * struct file instance instead of a file descriptor. Currently used
43 * only by aio_write();
44 *
45 ****************************************************************************/
46
file_pwrite(struct file * filep,const void * buf,size_t nbytes,off_t offset)47 ssize_t file_pwrite(struct file *filep, const void *buf,
48 size_t nbytes, 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 write operation */
78
79 ret = file_write(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: pwrite
101 *
102 * Description:
103 * The pwrite() function performs the same action as write(), except that
104 * it writes into a given position without changing the file pointer. The
105 * first three arguments to pwrite() are the same as write() with the
106 * addition of a fourth argument offset for the desired position inside
107 * the file.
108 *
109 * NOTE: This function could have been wholly implemented within libc but
110 * it is not. Why? Because if pwrite were implemented in libc, it would
111 * require four system calls. If it is implemented within the kernel,
112 * only three.
113 *
114 * Input Parameters:
115 * fd file descriptor (or socket descriptor) to write to
116 * buf Data to write
117 * nbytes Length of data to write
118 *
119 * Returned Value:
120 * The positive non-zero number of bytes read on success, 0 on if an
121 * end-of-file condition, or -1 on failure with errno set appropriately.
122 * See write() return values
123 *
124 * Assumptions/Limitations:
125 * POSIX requires that opening a file with the O_APPEND flag should have no
126 * effect on the location at which pwrite() writes data. However, on NuttX
127 * like on Linux, if a file is opened with O_APPEND, pwrite() appends data
128 * to the end of the file, regardless of the value of offset.
129 *
130 ****************************************************************************/
131
pwrite(int fd,const void * buf,size_t nbytes,off_t offset)132 ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset)
133 {
134 struct file *filep;
135
136 /* Get the file structure corresponding to the file descriptor. */
137
138 int ret = fs_getfilep(fd, &filep);
139 if (ret < 0)
140 {
141 /* The errno value has already been set */
142 set_errno(-ret);
143 return (ssize_t)VFS_ERROR;
144 }
145
146 if (filep->f_oflags & O_DIRECTORY)
147 {
148 set_errno(EBADF);
149 return (ssize_t)VFS_ERROR;
150 }
151
152 /* Let file_pread do the real work */
153
154 return file_pwrite(filep, buf, nbytes, offset);
155 }
156