• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/vfs/fs_fcntl.c
3  *
4  *   Copyright (C) 2009, 2012-2014, 2016-2017 Gregory Nutt. All rights
5  *     reserved.
6  *   Author: Gregory Nutt <gnutt@nuttx.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  * 3. Neither the name NuttX nor the names of its contributors may be
19  *    used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  ****************************************************************************/
36 
37 /****************************************************************************
38  * Included Files
39  ****************************************************************************/
40 
41 #include "vfs_config.h"
42 
43 #include "stdarg.h"
44 #include "fcntl.h"
45 #include "errno.h"
46 #include "assert.h"
47 #include "vnode.h"
48 
49 #if defined(LOSCFG_NET_LWIP_SACK)
50 #include "lwip/sockets.h"
51 #endif
52 
53 #define FAPPEND     O_APPEND
54 #define FFSYNC      O_SYNC
55 #define FNONBLOCK   O_NONBLOCK
56 #define FNDELAY     O_NDELAY
57 #define FFCNTL      (FNONBLOCK | FNDELAY | FAPPEND | FFSYNC | FASYNC)
58 
59 /****************************************************************************
60  * Public Functions
61  ****************************************************************************/
62 
63 /****************************************************************************
64  * Name: file_vfcntl
65  *
66  * Description:
67  *   Similar to the standard vfcntl function except that is accepts a struct
68  *   struct file instance instead of a file descriptor.
69  *
70  * Input Parameters:
71  *   filep - Instance for struct file for the opened file.
72  *   cmd   - Indentifies the operation to be performed.
73  *   ap    - Variable argument following the command.
74  *
75  * Returned Value:
76  *   The nature of the return value depends on the command.  Non-negative
77  *   values indicate success.  Failures are reported as negated errno
78  *   values.
79  *
80  ****************************************************************************/
81 
82 #if CONFIG_NFILE_DESCRIPTORS > 0
file_vfcntl(struct file * filep,int cmd,va_list ap)83 int file_vfcntl(struct file *filep, int cmd, va_list ap)
84 {
85   int err = 0;
86   int ret = OK;
87 
88   /* Was this file opened ? */
89 
90   if (!filep || !filep->f_vnode)
91     {
92       err = EBADF;
93       goto errout;
94     }
95 
96   switch (cmd)
97     {
98       case F_DUPFD:
99         /* Return a new file descriptor which shall be the lowest numbered
100          * available (that is, not already open) file descriptor greater than
101          * or equal to the third argument, arg, taken as an integer of type
102          * int. The new file descriptor shall refer to the same open file
103          * description as the original file descriptor, and shall share any
104          * locks.  The FD_CLOEXEC flag associated  with the new file descriptor
105          * shall be cleared to keep the file open across calls to one of the
106          * exec functions.
107          */
108 
109         {
110           /* Does not set the errno variable in the event of a failure */
111 
112           ret = file_dup(filep, va_arg(ap, int));
113         }
114         break;
115 
116       case F_GETFD:
117         /* Get the file descriptor flags defined in <fcntl.h> that are associated
118          * with the file descriptor fd.  File descriptor flags are associated
119          * with a single file descriptor and do not affect other file descriptors
120          * that refer to the same file.
121          */
122 
123         {
124           ret = (filep->f_oflags & O_CLOEXEC) ? FD_CLOEXEC : 0;
125         }
126         break;
127 
128       case F_SETFD:
129         /* Set the file descriptor flags defined in <fcntl.h>, that are associated
130          * with fd, to the third argument, arg, taken as type int. If the
131          * FD_CLOEXEC flag in the third argument is 0, the file shall remain open
132          * across the exec functions; otherwise, the file shall be closed upon
133          * successful execution of one  of  the  exec  functions.
134          */
135 
136         {
137           int oflags = va_arg(ap, int);
138 
139           if (oflags & FD_CLOEXEC)
140             {
141               filep->f_oflags |= O_CLOEXEC;
142             }
143           else
144             {
145               err = EPERM; /* Not support */
146             }
147         }
148         break;
149 
150       case F_GETFL:
151         /* Get the file status flags and file access modes, defined in
152          * <fcntl.h>, for the file description associated with fd. The file
153          * access modes can be extracted from the return value using the
154          * mask O_ACCMODE, which is defined  in <fcntl.h>. File status flags
155          * and file access modes are associated with the file description
156          * and do not affect other file descriptors that refer to the same
157          * file with different open file descriptions.
158          */
159 
160         {
161           ret = filep->f_oflags;
162         }
163         break;
164 
165       case F_SETFL:
166         /* Set the file status flags, defined in <fcntl.h>, for the file
167          * description associated with fd from the corresponding  bits in
168          * the third argument, arg, taken as type int. Bits corresponding
169          * to the file access mode and the file creation flags, as defined
170          * in <fcntl.h>, that are set in arg shall be ignored. If any bits
171          * in arg other than those mentioned here are changed by the
172          * application, the result is unspecified.
173          */
174 
175         {
176           int oflags = va_arg(ap, int);
177 
178           oflags          &=  FFCNTL;
179           filep->f_oflags &= ~FFCNTL;
180           filep->f_oflags |= oflags;
181         }
182         break;
183 
184       case F_GETOWN:
185         /* If fd refers to a socket, get the process or process group ID
186          * specified to receive SIGURG signals when out-of-band data is
187          * available. Positive values indicate a process ID; negative
188          * values, other than -1, indicate a process group ID. If fd does
189          * not refer to a socket, the results are unspecified.
190          */
191 
192       case F_SETOWN:
193         /* If fd refers to a socket, set the process or process group ID
194          * specified to receive SIGURG signals when out-of-band data is
195          * available, using the value of the third argument, arg, taken as
196          * type int. Positive values indicate a process ID; negative values,
197          * other than -1, indicate a process group ID.  If fd does not refer
198          * to a socket, the results are unspecified.
199          */
200 
201         err = EBADF; /* Only valid on socket descriptors */
202         break;
203 
204       case F_GETLK:
205         /* Get the first lock which blocks the lock description pointed to
206          * by the third argument, arg, taken as a pointer to type struct
207          * flock, defined in <fcntl.h>.  The information retrieved shall
208          * overwrite the information passed to fcntl() in the structure
209          * flock. If no lock is found that would prevent this lock from
210          * being created, then the structure shall be left unchanged except
211          * for the lock type which shall be set to F_UNLCK.
212          */
213 
214       case F_SETLK:
215         /* Set or clear a file segment lock according to the lock
216          * description pointed to by the third argument, arg, taken as a
217          * pointer to type struct flock, defined in <fcntl.h>. F_SETLK can
218          * establish shared (or read) locks (F_RDLCK) or exclusive (or
219          * write) locks (F_WRLCK), as well  as to remove either type of lock
220          * (F_UNLCK).  F_RDLCK, F_WRLCK, and F_UNLCK are defined in
221          * <fcntl.h>. If a shared or exclusive lock cannot be set, fcntl()
222          * shall return immediately with a return value of -1.
223          */
224 
225       case F_SETLKW:
226         /* This command shall be equivalent to F_SETLK except that if a
227          * shared or exclusive lock is blocked by other locks, the thread
228          * shall wait until the request can be satisfied. If a signal that
229          * is to be caught is received while fcntl() is waiting for a
230          * region, fcntl() shall be interrupted. Upon return from the signal
231          * handler, fcntl() shall return -1 with errno set to [EINTR], and
232          * the lock operation shall not be done.
233          */
234 
235         err = ENOSYS; /* Not implemented */
236         break;
237 
238       default:
239         err = EINVAL;
240         break;
241     }
242 
243 errout:
244   if (err != 0)
245     {
246       set_errno(err);
247       return VFS_ERROR;
248     }
249 
250   return ret;
251 }
252 #endif /* CONFIG_NFILE_DESCRIPTORS > 0 */
253 
254 /****************************************************************************
255  * Name: fcntl
256  *
257  * Description:
258  *   fcntl() will perform the operation specified by 'cmd' on an open file.
259  *
260  * Input Parameters:
261  *   fd  - File descriptor of the open file
262  *   cmd - Identifies the operation to be performed.  Command specific
263  *         arguments may follow.
264  *
265  * Returned Value:
266  *   The returned value depends on the nature of the command but for all
267  *   commands the return value of -1 (ERROR) indicates that an error has
268  *   occurred and, in this case, the errno variable will be set
269  *   appropriately
270  *
271  ****************************************************************************/
272 
fcntl(int fd,int cmd,...)273 int fcntl(int fd, int cmd, ...)
274 {
275   struct file *filep = NULL;
276   va_list ap;
277   int ret;
278   int val = 0;
279 
280   /* Setup to access the variable argument list */
281 
282   va_start(ap, cmd);
283 
284   /* Did we get a valid file descriptor? */
285 
286 #if CONFIG_NFILE_DESCRIPTORS > 0
287   if ((unsigned int)fd < CONFIG_NFILE_DESCRIPTORS)
288     {
289       /* Get the file structure corresponding to the file descriptor. */
290 
291       ret = fs_getfilep(fd, &filep);
292       if (ret < 0)
293         {
294           /* The errno value has already been set */
295           va_end(ap);
296           return VFS_ERROR;
297         }
298 
299           /* Let file_vfcntl() do the real work.  The errno is not set on
300            * failures.
301            */
302 
303       ret = file_vfcntl(filep, cmd, ap);
304     }
305   else
306 #endif
307     {
308       /* No... check for operations on a socket descriptor */
309 
310 #if defined(LOSCFG_NET_LWIP_SACK)
311       if ((unsigned int)fd < (unsigned int)(CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS))
312         {
313           /* Yes.. defer socket descriptor operations to net_vfcntl() */
314 
315           val = va_arg(ap, int);
316           ret = lwip_fcntl(fd, cmd, val);
317         }
318       else
319 #endif
320         {
321           /* No.. this descriptor number is out of range */
322 
323           (void)val;
324           ret = EBADF;
325           set_errno(ret);
326           va_end(ap);
327           return VFS_ERROR;
328         }
329     }
330 
331   va_end(ap);
332   return ret;
333 }
334 
fcntl64(int fd,int cmd,...)335 int fcntl64(int fd, int cmd, ...)
336 {
337   struct file *filep = NULL;
338   va_list va_ap;
339   int reval;
340   int va_val = 0;
341 
342   /* Setup to access the variable argument list */
343 
344   va_start(va_ap, cmd);
345 
346   /* Did we get a valid file descriptor? */
347 
348 #if CONFIG_NFILE_DESCRIPTORS > 0
349   if ((unsigned int)fd < CONFIG_NFILE_DESCRIPTORS)
350     {
351       /* Get the file structure corresponding to the file descriptor. */
352 
353       int ret = fs_getfilep(fd, &filep);
354       if (ret < 0)
355         {
356           /* The errno value has already been set */
357           va_end(va_ap);
358           return VFS_ERROR;
359         }
360 
361       /* Let file_vfcntl() do the real work */
362 
363       reval = file_vfcntl(filep, cmd, va_ap);
364     }
365   else
366 #endif
367     {
368       /* No... check for operations on a socket descriptor */
369 
370 #if defined(LOSCFG_NET_LWIP_SACK)
371       if ((unsigned int)fd < (unsigned int)(CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS))
372         {
373           /* Yes.. defer socket descriptor operations to net_vfcntl() */
374 
375           va_val = va_arg(va_ap, int);
376           reval = lwip_fcntl(fd, cmd, va_val);
377         }
378       else
379 #endif
380         {
381           /* No.. this descriptor number is out of range */
382 
383           (void)va_val;
384           reval = EBADF;
385           set_errno(reval);
386           va_end(va_ap);
387           return VFS_ERROR;
388         }
389     }
390 
391   va_end(va_ap);
392   return reval;
393 }
394