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