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