xref: /third_party/NuttX/fs/vfs/fs_pwrite64.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 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
65static 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
150ssize_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