1beacf11bSopenharmony_ci/****************************************************************************
2beacf11bSopenharmony_ci * fs/vfs/fs_pwrite.c
3beacf11bSopenharmony_ci *
4beacf11bSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
5beacf11bSopenharmony_ci * Based on NuttX originally from nuttx source (nuttx/fs/ and nuttx/drivers/)
6beacf11bSopenharmony_ci *
7beacf11bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8beacf11bSopenharmony_ci * you may not use this file except in compliance with the License.
9beacf11bSopenharmony_ci * You may obtain a copy of the License at
10beacf11bSopenharmony_ci *
11beacf11bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
12beacf11bSopenharmony_ci *
13beacf11bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14beacf11bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15beacf11bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16beacf11bSopenharmony_ci * See the License for the specific language governing permissions and
17beacf11bSopenharmony_ci * limitations under the License.
18beacf11bSopenharmony_ci *
19beacf11bSopenharmony_ci ****************************************************************************/
20beacf11bSopenharmony_ci
21beacf11bSopenharmony_ci/****************************************************************************
22beacf11bSopenharmony_ci * Included Files
23beacf11bSopenharmony_ci ****************************************************************************/
24beacf11bSopenharmony_ci
25beacf11bSopenharmony_ci#include "vfs_config.h"
26beacf11bSopenharmony_ci
27beacf11bSopenharmony_ci#include "sys/types.h"
28beacf11bSopenharmony_ci#include "unistd.h"
29beacf11bSopenharmony_ci#include "errno.h"
30beacf11bSopenharmony_ci
31beacf11bSopenharmony_ci#include "fs/file.h"
32beacf11bSopenharmony_ci
33beacf11bSopenharmony_ci/****************************************************************************
34beacf11bSopenharmony_ci * Public Functions
35beacf11bSopenharmony_ci ****************************************************************************/
36beacf11bSopenharmony_ci
37beacf11bSopenharmony_ci/****************************************************************************
38beacf11bSopenharmony_ci * Name: file_pwrite
39beacf11bSopenharmony_ci *
40beacf11bSopenharmony_ci * Description:
41beacf11bSopenharmony_ci *   Equivalent to the standard pwrite function except that is accepts a
42beacf11bSopenharmony_ci *   struct file instance instead of a file descriptor.  Currently used
43beacf11bSopenharmony_ci *   only by aio_write();
44beacf11bSopenharmony_ci *
45beacf11bSopenharmony_ci ****************************************************************************/
46beacf11bSopenharmony_ci
47beacf11bSopenharmony_cissize_t file_pwrite(struct file *filep, const void *buf,
48beacf11bSopenharmony_ci                    size_t nbytes, off_t offset)
49beacf11bSopenharmony_ci{
50beacf11bSopenharmony_ci  off_t savepos;
51beacf11bSopenharmony_ci  off_t pos;
52beacf11bSopenharmony_ci  ssize_t ret;
53beacf11bSopenharmony_ci  int errcode;
54beacf11bSopenharmony_ci
55beacf11bSopenharmony_ci  /* Perform the seek to the current position.  This will not move the
56beacf11bSopenharmony_ci   * file pointer, but will return its current setting
57beacf11bSopenharmony_ci   */
58beacf11bSopenharmony_ci
59beacf11bSopenharmony_ci  savepos = file_seek(filep, 0, SEEK_CUR);
60beacf11bSopenharmony_ci  if (savepos == (off_t)-1)
61beacf11bSopenharmony_ci    {
62beacf11bSopenharmony_ci      /* file_seek might fail if this if the media is not seekable */
63beacf11bSopenharmony_ci
64beacf11bSopenharmony_ci      return VFS_ERROR;
65beacf11bSopenharmony_ci    }
66beacf11bSopenharmony_ci
67beacf11bSopenharmony_ci  /* Then seek to the correct position in the file */
68beacf11bSopenharmony_ci
69beacf11bSopenharmony_ci  pos = file_seek(filep, offset, SEEK_SET);
70beacf11bSopenharmony_ci  if (pos == (off_t)-1)
71beacf11bSopenharmony_ci    {
72beacf11bSopenharmony_ci      /* This might fail is the offset is beyond the end of file */
73beacf11bSopenharmony_ci
74beacf11bSopenharmony_ci      return VFS_ERROR;
75beacf11bSopenharmony_ci    }
76beacf11bSopenharmony_ci
77beacf11bSopenharmony_ci  /* Then perform the write operation */
78beacf11bSopenharmony_ci
79beacf11bSopenharmony_ci  ret = file_write(filep, buf, nbytes);
80beacf11bSopenharmony_ci  errcode = get_errno();
81beacf11bSopenharmony_ci
82beacf11bSopenharmony_ci  /* Restore the file position */
83beacf11bSopenharmony_ci
84beacf11bSopenharmony_ci  pos = file_seek(filep, savepos, SEEK_SET);
85beacf11bSopenharmony_ci  if (pos == (off_t)-1 && ret >= 0)
86beacf11bSopenharmony_ci    {
87beacf11bSopenharmony_ci      /* This really should not fail */
88beacf11bSopenharmony_ci
89beacf11bSopenharmony_ci      return VFS_ERROR;
90beacf11bSopenharmony_ci    }
91beacf11bSopenharmony_ci
92beacf11bSopenharmony_ci  if (errcode != 0)
93beacf11bSopenharmony_ci    {
94beacf11bSopenharmony_ci      set_errno(errcode);
95beacf11bSopenharmony_ci    }
96beacf11bSopenharmony_ci  return ret;
97beacf11bSopenharmony_ci}
98beacf11bSopenharmony_ci
99beacf11bSopenharmony_ci/****************************************************************************
100beacf11bSopenharmony_ci * Name: pwrite
101beacf11bSopenharmony_ci *
102beacf11bSopenharmony_ci * Description:
103beacf11bSopenharmony_ci *   The pwrite() function performs the same action as write(), except that
104beacf11bSopenharmony_ci *   it writes into a given position without changing the file pointer. The
105beacf11bSopenharmony_ci *   first three arguments to pwrite() are the same as write() with the
106beacf11bSopenharmony_ci *   addition of a fourth argument offset for the desired position inside
107beacf11bSopenharmony_ci *   the file.
108beacf11bSopenharmony_ci *
109beacf11bSopenharmony_ci *   NOTE: This function could have been wholly implemented within libc but
110beacf11bSopenharmony_ci *   it is not.  Why?  Because if pwrite were implemented in libc, it would
111beacf11bSopenharmony_ci *   require four system calls.  If it is implemented within the kernel,
112beacf11bSopenharmony_ci *   only three.
113beacf11bSopenharmony_ci *
114beacf11bSopenharmony_ci * Input Parameters:
115beacf11bSopenharmony_ci *   fd       file descriptor (or socket descriptor) to write to
116beacf11bSopenharmony_ci *   buf      Data to write
117beacf11bSopenharmony_ci *   nbytes   Length of data to write
118beacf11bSopenharmony_ci *
119beacf11bSopenharmony_ci * Returned Value:
120beacf11bSopenharmony_ci *   The positive non-zero number of bytes read on success, 0 on if an
121beacf11bSopenharmony_ci *   end-of-file condition, or -1 on failure with errno set appropriately.
122beacf11bSopenharmony_ci *   See write() return values
123beacf11bSopenharmony_ci *
124beacf11bSopenharmony_ci * Assumptions/Limitations:
125beacf11bSopenharmony_ci *   POSIX requires that opening a file with the O_APPEND flag should have no
126beacf11bSopenharmony_ci *   effect on the location at which pwrite() writes data.  However, on NuttX
127beacf11bSopenharmony_ci *   like on Linux, if a file is opened with O_APPEND, pwrite() appends data
128beacf11bSopenharmony_ci *   to the end of the file, regardless of the value of offset.
129beacf11bSopenharmony_ci *
130beacf11bSopenharmony_ci ****************************************************************************/
131beacf11bSopenharmony_ci
132beacf11bSopenharmony_cissize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset)
133beacf11bSopenharmony_ci{
134beacf11bSopenharmony_ci  struct file *filep;
135beacf11bSopenharmony_ci
136beacf11bSopenharmony_ci  /* Get the file structure corresponding to the file descriptor. */
137beacf11bSopenharmony_ci
138beacf11bSopenharmony_ci  int ret = fs_getfilep(fd, &filep);
139beacf11bSopenharmony_ci  if (ret < 0)
140beacf11bSopenharmony_ci    {
141beacf11bSopenharmony_ci      /* The errno value has already been set */
142beacf11bSopenharmony_ci      set_errno(-ret);
143beacf11bSopenharmony_ci      return (ssize_t)VFS_ERROR;
144beacf11bSopenharmony_ci    }
145beacf11bSopenharmony_ci
146beacf11bSopenharmony_ci  if (filep->f_oflags & O_DIRECTORY)
147beacf11bSopenharmony_ci    {
148beacf11bSopenharmony_ci      set_errno(EBADF);
149beacf11bSopenharmony_ci      return (ssize_t)VFS_ERROR;
150beacf11bSopenharmony_ci    }
151beacf11bSopenharmony_ci
152beacf11bSopenharmony_ci  /* Let file_pread do the real work */
153beacf11bSopenharmony_ci
154beacf11bSopenharmony_ci  return file_pwrite(filep, buf, nbytes, offset);
155beacf11bSopenharmony_ci}
156