xref: /third_party/NuttX/fs/vfs/fs_pwrite.c (revision beacf11b)
1/****************************************************************************
2 * fs/vfs/fs_pwrite.c
3 *
4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
5 * Based on NuttX originally from nuttx source (nuttx/fs/ and nuttx/drivers/)
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * 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,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations 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
47ssize_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
132ssize_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