/*
* open() - POSIX 1003.1 5.3.1 - Open a File
*
* COPYRIGHT (c) 1989-1999.
* 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.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/libio_.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 eitehr 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;
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, 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;
}
/* Sanity check to see if the file name exists after the mknod() */
status = rtems_filesystem_evaluate_path( 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;
goto done;
}
/*
* Fill in the file control block based on the loc structure
* returned by successful path evaluation.
*/
iop->handlers = loc.handlers;
iop->file_info = loc.node_access;
iop->flags |= rtems_libio_fcntl_flags( flags );
iop->pathinfo = loc;
if ( !iop->handlers->open_h ) {
rc = ENOTSUP;
goto done;
}
rc = (*iop->handlers->open_h)( iop, pathname, flags, mode );
if ( rc )
goto done;
/*
* Optionally truncate the file.
*/
if ( (flags & O_TRUNC) == O_TRUNC ) {
rc = ftruncate( iop - rtems_libio_iops, 0 );
}
/*
* Single exit and clean up path.
*/
done:
va_end(ap);
if ( rc ) {
if ( iop )
rtems_libio_free( iop );
set_errno_and_return_minus_one( rc );
}
rtems_filesystem_freenode( &loc );
return iop - rtems_libio_iops;
}
/*
* _open_r
*
* This is the Newlib dependent reentrant version of open().
*/
#if defined(RTEMS_NEWLIB)
#include <reent.h>
int _open_r(
struct _reent *ptr,
const char *buf,
int flags,
int mode
)
{
return open( buf, flags, mode );
}
#endif