summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libc/open.c
blob: 1203ca9688eeead28f045af5ac62656f51aac820 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
 *  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$
 */

#include "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->offset     = 0;
  iop->handlers   = loc.handlers;
  iop->file_info  = loc.node_access;
  iop->flags     |= rtems_libio_fcntl_flags( flags );
  iop->pathinfo   = loc;

  if ( !iop->handlers->open ) {
    rc = ENOTSUP;
    goto done; 
  }

  rc = (*iop->handlers->open)( 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