diff options
Diffstat (limited to 'cpukit/libcsupport/src/open.c')
-rw-r--r-- | cpukit/libcsupport/src/open.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/cpukit/libcsupport/src/open.c b/cpukit/libcsupport/src/open.c new file mode 100644 index 0000000000..a49ebfec0d --- /dev/null +++ b/cpukit/libcsupport/src/open.c @@ -0,0 +1,215 @@ +/* + * open() - POSIX 1003.1 5.3.1 - Open a File + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdarg.h> +#include <fcntl.h> +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +#include <unistd.h> + +/* + * Returns file descriptor on success or -1 and errno set to one of the + * following: + * + * EACCESS - Seach permission is denied on a component of the path prefix, + * or the file exists and the permissions specified by the + * flags are denied, or the file does not exist and write + * permission is denied for the parent directory of the file + * to be created, or O_TRUNC is specified and write permission + * is denied. + * EEXIST - O_CREAT and O_EXCL are set and the named file exists. + * EINTR - The open( operation was interrupted by a signal. + * EINVAL - This implementation does not support synchronized IO for this + * file. + * EISDIR - The named file is a directory and the flags argument + * specified write or read/write access. + * EMFILE - Too many file descriptors are in used by this process. + * ENAMETOOLONG - + * The length of the path exceeds PATH_MAX or a pathname + * component is longer than NAME_MAX while POSIX_NO_TRUNC + * is in effect. + * ENFILE - Too many files are open in the system. + * ENOENT - O_CREAT is not set and and the anmed file does not exist, + * or O_CREAT is set and either the path prefix does not exist + * or the path argument points to an empty string. + * ENOSPC - The directory or file system that would contain the new file + * cannot be extended. + * ENOTDIR - A component of the path prefix is not a directory. + * ENXIO - O_NONBLOCK is set, the named file is a FIFO, O_WRONLY is + * set, and no process has the file open for reading. + * EROFS - The named file resides on a read-only file system and either + * O_WRONLY, O_RDWR, O_CREAT (if the file does not exist), or + * O_TRUNC is set in the flags argument. + */ + +int open( + const char *pathname, + int flags, + ... +) +{ + va_list ap; + int mode; + int rc; + rtems_libio_t *iop = 0; + int status; + rtems_filesystem_location_info_t loc; + rtems_filesystem_location_info_t *loc_to_free = NULL; + int eval_flags; + + /* + * Set the Evaluation flags + */ + eval_flags = 0; + status = flags + 1; + if ( ( status & _FREAD ) == _FREAD ) + eval_flags |= RTEMS_LIBIO_PERMS_READ; + if ( ( status & _FWRITE ) == _FWRITE ) + eval_flags |= RTEMS_LIBIO_PERMS_WRITE; + + va_start(ap, flags); + + mode = va_arg( ap, int ); + + /* + * NOTE: This comment is OBSOLETE. The proper way to do this now + * would be to support a magic mounted file system. + * + * Additional external I/O handlers would be supported by adding + * code to pick apart the pathname appropriately. The networking + * code does not require changes here since network file + * descriptors are obtained using socket(), not open(). + */ + + /* allocate a file control block */ + iop = rtems_libio_allocate(); + if ( iop == 0 ) { + rc = ENFILE; + goto done; + } + + /* + * See if the file exists. + */ + status = rtems_filesystem_evaluate_path( + pathname, strlen( pathname ), eval_flags, &loc, true ); + + if ( status == -1 ) { + if ( errno != ENOENT ) { + rc = errno; + goto done; + } + + /* If the file does not exist and we are not trying to create it--> error */ + if ( !(flags & O_CREAT) ) { + rc = ENOENT; + goto done; + } + + /* Create the node for the new regular file */ + rc = mknod( pathname, S_IFREG | mode, 0LL ); + if ( rc ) { + rc = errno; + goto done; + } + + /* + * After we do the mknod(), we have to evaluate the path to get the + * "loc" structure needed to actually have the file itself open. + * So we created it, and then we need to have "look it up." + */ + status = rtems_filesystem_evaluate_path( + pathname, strlen( pathname ), 0x0, &loc, true ); + if ( status != 0 ) { /* The file did not exist */ + rc = EACCES; + goto done; + } + + } else if ((flags & (O_EXCL|O_CREAT)) == (O_EXCL|O_CREAT)) { + /* We were trying to create a file that already exists */ + rc = EEXIST; + loc_to_free = &loc; + goto done; + } + + loc_to_free = &loc; + + /* + * Fill in the file control block based on the loc structure + * returned by successful path evaluation. + */ + iop->flags |= rtems_libio_fcntl_flags( flags ); + iop->pathinfo = loc; + + rc = (*iop->pathinfo.handlers->open_h)( iop, pathname, flags, mode ); + if ( rc ) { + rc = errno; + goto done; + } + + /* + * Optionally truncate the file. + */ + if ( (flags & O_TRUNC) == O_TRUNC ) { + rc = ftruncate( iop - rtems_libio_iops, 0 ); + if ( rc ) { + if(errno) rc = errno; + close( iop - rtems_libio_iops ); + /* those are released by close(): */ + iop = 0; + loc_to_free = NULL; + } + } + + /* + * Single exit and clean up path. + */ +done: + va_end(ap); + + if ( rc ) { + if ( iop ) + rtems_libio_free( iop ); + if ( loc_to_free ) + rtems_filesystem_freenode( loc_to_free ); + rtems_set_errno_and_return_minus_one( rc ); + } + + return iop - rtems_libio_iops; +} + +/* + * _open_r + * + * This is the Newlib dependent reentrant version of open(). + */ + +#if defined(RTEMS_NEWLIB) && !defined(HAVE__OPEN_R) + +#include <reent.h> + +int _open_r( + struct _reent *ptr __attribute__((unused)), + const char *buf, + int flags, + int mode +) +{ + return open( buf, flags, mode ); +} +#endif |