1/**************************************************************************** 2 * fs/vfs/fs_fcntl.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 "stdarg.h" 28#include "fcntl.h" 29#include "errno.h" 30#include "assert.h" 31#include "vnode.h" 32 33#if defined(LOSCFG_NET_LWIP_SACK) 34#include "lwip/sockets.h" 35#endif 36 37#define FAPPEND O_APPEND 38#define FFSYNC O_SYNC 39#define FNONBLOCK O_NONBLOCK 40#define FNDELAY O_NDELAY 41#define FFCNTL (FNONBLOCK | FNDELAY | FAPPEND | FFSYNC | FASYNC) 42 43/**************************************************************************** 44 * Public Functions 45 ****************************************************************************/ 46 47/**************************************************************************** 48 * Name: file_vfcntl 49 * 50 * Description: 51 * Similar to the standard vfcntl function except that is accepts a struct 52 * struct file instance instead of a file descriptor. 53 * 54 * Input Parameters: 55 * filep - Instance for struct file for the opened file. 56 * cmd - Indentifies the operation to be performed. 57 * ap - Variable argument following the command. 58 * 59 * Returned Value: 60 * The nature of the return value depends on the command. Non-negative 61 * values indicate success. Failures are reported as negated errno 62 * values. 63 * 64 ****************************************************************************/ 65 66#if CONFIG_NFILE_DESCRIPTORS > 0 67int file_vfcntl(struct file *filep, int cmd, va_list ap) 68{ 69 int err = 0; 70 int ret = OK; 71 72 /* Was this file opened ? */ 73 74 if (!filep || !filep->f_vnode) 75 { 76 err = EBADF; 77 goto errout; 78 } 79 80 switch (cmd) 81 { 82 case F_DUPFD: 83 /* Return a new file descriptor which shall be the lowest numbered 84 * available (that is, not already open) file descriptor greater than 85 * or equal to the third argument, arg, taken as an integer of type 86 * int. The new file descriptor shall refer to the same open file 87 * description as the original file descriptor, and shall share any 88 * locks. The FD_CLOEXEC flag associated with the new file descriptor 89 * shall be cleared to keep the file open across calls to one of the 90 * exec functions. 91 */ 92 93 { 94 /* Does not set the errno variable in the event of a failure */ 95 96 ret = file_dup(filep, va_arg(ap, int)); 97 } 98 break; 99 100 case F_GETFD: 101 /* Get the file descriptor flags defined in <fcntl.h> that are associated 102 * with the file descriptor fd. File descriptor flags are associated 103 * with a single file descriptor and do not affect other file descriptors 104 * that refer to the same file. 105 */ 106 107 { 108 ret = (filep->f_oflags & O_CLOEXEC) ? FD_CLOEXEC : 0; 109 } 110 break; 111 112 case F_SETFD: 113 /* Set the file descriptor flags defined in <fcntl.h>, that are associated 114 * with fd, to the third argument, arg, taken as type int. If the 115 * FD_CLOEXEC flag in the third argument is 0, the file shall remain open 116 * across the exec functions; otherwise, the file shall be closed upon 117 * successful execution of one of the exec functions. 118 */ 119 120 { 121 int oflags = va_arg(ap, int); 122 123 if (oflags & FD_CLOEXEC) 124 { 125 filep->f_oflags |= O_CLOEXEC; 126 } 127 else 128 { 129 err = EPERM; /* Not support */ 130 } 131 } 132 break; 133 134 case F_GETFL: 135 /* Get the file status flags and file access modes, defined in 136 * <fcntl.h>, for the file description associated with fd. The file 137 * access modes can be extracted from the return value using the 138 * mask O_ACCMODE, which is defined in <fcntl.h>. File status flags 139 * and file access modes are associated with the file description 140 * and do not affect other file descriptors that refer to the same 141 * file with different open file descriptions. 142 */ 143 144 { 145 ret = filep->f_oflags; 146 } 147 break; 148 149 case F_SETFL: 150 /* Set the file status flags, defined in <fcntl.h>, for the file 151 * description associated with fd from the corresponding bits in 152 * the third argument, arg, taken as type int. Bits corresponding 153 * to the file access mode and the file creation flags, as defined 154 * in <fcntl.h>, that are set in arg shall be ignored. If any bits 155 * in arg other than those mentioned here are changed by the 156 * application, the result is unspecified. 157 */ 158 159 { 160 int oflags = va_arg(ap, int); 161 162 oflags &= FFCNTL; 163 filep->f_oflags &= ~FFCNTL; 164 filep->f_oflags |= oflags; 165 } 166 break; 167 168 case F_GETOWN: 169 /* If fd refers to a socket, get the process or process group ID 170 * specified to receive SIGURG signals when out-of-band data is 171 * available. Positive values indicate a process ID; negative 172 * values, other than -1, indicate a process group ID. If fd does 173 * not refer to a socket, the results are unspecified. 174 */ 175 176 case F_SETOWN: 177 /* If fd refers to a socket, set the process or process group ID 178 * specified to receive SIGURG signals when out-of-band data is 179 * available, using the value of the third argument, arg, taken as 180 * type int. Positive values indicate a process ID; negative values, 181 * other than -1, indicate a process group ID. If fd does not refer 182 * to a socket, the results are unspecified. 183 */ 184 185 err = EBADF; /* Only valid on socket descriptors */ 186 break; 187 188 case F_GETLK: 189 /* Get the first lock which blocks the lock description pointed to 190 * by the third argument, arg, taken as a pointer to type struct 191 * flock, defined in <fcntl.h>. The information retrieved shall 192 * overwrite the information passed to fcntl() in the structure 193 * flock. If no lock is found that would prevent this lock from 194 * being created, then the structure shall be left unchanged except 195 * for the lock type which shall be set to F_UNLCK. 196 */ 197 198 case F_SETLK: 199 /* Set or clear a file segment lock according to the lock 200 * description pointed to by the third argument, arg, taken as a 201 * pointer to type struct flock, defined in <fcntl.h>. F_SETLK can 202 * establish shared (or read) locks (F_RDLCK) or exclusive (or 203 * write) locks (F_WRLCK), as well as to remove either type of lock 204 * (F_UNLCK). F_RDLCK, F_WRLCK, and F_UNLCK are defined in 205 * <fcntl.h>. If a shared or exclusive lock cannot be set, fcntl() 206 * shall return immediately with a return value of -1. 207 */ 208 209 case F_SETLKW: 210 /* This command shall be equivalent to F_SETLK except that if a 211 * shared or exclusive lock is blocked by other locks, the thread 212 * shall wait until the request can be satisfied. If a signal that 213 * is to be caught is received while fcntl() is waiting for a 214 * region, fcntl() shall be interrupted. Upon return from the signal 215 * handler, fcntl() shall return -1 with errno set to [EINTR], and 216 * the lock operation shall not be done. 217 */ 218 219 err = ENOSYS; /* Not implemented */ 220 break; 221 222 default: 223 err = EINVAL; 224 break; 225 } 226 227errout: 228 if (err != 0) 229 { 230 set_errno(err); 231 return VFS_ERROR; 232 } 233 234 return ret; 235} 236#endif /* CONFIG_NFILE_DESCRIPTORS > 0 */ 237 238/**************************************************************************** 239 * Name: fcntl 240 * 241 * Description: 242 * fcntl() will perform the operation specified by 'cmd' on an open file. 243 * 244 * Input Parameters: 245 * fd - File descriptor of the open file 246 * cmd - Identifies the operation to be performed. Command specific 247 * arguments may follow. 248 * 249 * Returned Value: 250 * The returned value depends on the nature of the command but for all 251 * commands the return value of -1 (ERROR) indicates that an error has 252 * occurred and, in this case, the errno variable will be set 253 * appropriately 254 * 255 ****************************************************************************/ 256 257int fcntl(int fd, int cmd, ...) 258{ 259 struct file *filep = NULL; 260 va_list ap; 261 int ret; 262 int val = 0; 263 264 /* Setup to access the variable argument list */ 265 266 va_start(ap, cmd); 267 268 /* Did we get a valid file descriptor? */ 269 270#if CONFIG_NFILE_DESCRIPTORS > 0 271 if ((unsigned int)fd < CONFIG_NFILE_DESCRIPTORS) 272 { 273 /* Get the file structure corresponding to the file descriptor. */ 274 275 ret = fs_getfilep(fd, &filep); 276 if (ret < 0) 277 { 278 /* The errno value has already been set */ 279 va_end(ap); 280 return VFS_ERROR; 281 } 282 283 /* Let file_vfcntl() do the real work. The errno is not set on 284 * failures. 285 */ 286 287 ret = file_vfcntl(filep, cmd, ap); 288 } 289 else 290#endif 291 { 292 /* No... check for operations on a socket descriptor */ 293 294#if defined(LOSCFG_NET_LWIP_SACK) 295 if ((unsigned int)fd < (unsigned int)(CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS)) 296 { 297 /* Yes.. defer socket descriptor operations to net_vfcntl() */ 298 299 val = va_arg(ap, int); 300 ret = lwip_fcntl(fd, cmd, val); 301 } 302 else 303#endif 304 { 305 /* No.. this descriptor number is out of range */ 306 307 (void)val; 308 ret = EBADF; 309 set_errno(ret); 310 va_end(ap); 311 return VFS_ERROR; 312 } 313 } 314 315 va_end(ap); 316 return ret; 317} 318 319int fcntl64(int fd, int cmd, ...) 320{ 321 struct file *filep = NULL; 322 va_list va_ap; 323 int reval; 324 int va_val = 0; 325 326 /* Setup to access the variable argument list */ 327 328 va_start(va_ap, cmd); 329 330 /* Did we get a valid file descriptor? */ 331 332#if CONFIG_NFILE_DESCRIPTORS > 0 333 if ((unsigned int)fd < CONFIG_NFILE_DESCRIPTORS) 334 { 335 /* Get the file structure corresponding to the file descriptor. */ 336 337 int ret = fs_getfilep(fd, &filep); 338 if (ret < 0) 339 { 340 /* The errno value has already been set */ 341 va_end(va_ap); 342 return VFS_ERROR; 343 } 344 345 /* Let file_vfcntl() do the real work */ 346 347 reval = file_vfcntl(filep, cmd, va_ap); 348 } 349 else 350#endif 351 { 352 /* No... check for operations on a socket descriptor */ 353 354#if defined(LOSCFG_NET_LWIP_SACK) 355 if ((unsigned int)fd < (unsigned int)(CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS)) 356 { 357 /* Yes.. defer socket descriptor operations to net_vfcntl() */ 358 359 va_val = va_arg(va_ap, int); 360 reval = lwip_fcntl(fd, cmd, va_val); 361 } 362 else 363#endif 364 { 365 /* No.. this descriptor number is out of range */ 366 367 (void)va_val; 368 reval = EBADF; 369 set_errno(reval); 370 va_end(va_ap); 371 return VFS_ERROR; 372 } 373 } 374 375 va_end(va_ap); 376 return reval; 377} 378