posix_io.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <errno.h>
00024 #include <gpxe/list.h>
00025 #include <gpxe/xfer.h>
00026 #include <gpxe/open.h>
00027 #include <gpxe/process.h>
00028 #include <gpxe/posix_io.h>
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 struct posix_file {
00041
00042 struct refcnt refcnt;
00043
00044 struct list_head list;
00045
00046 int fd;
00047
00048
00049
00050
00051 int rc;
00052
00053 struct xfer_interface xfer;
00054
00055 size_t pos;
00056
00057 size_t filesize;
00058
00059 struct list_head data;
00060 };
00061
00062
00063 static LIST_HEAD ( posix_files );
00064
00065
00066
00067
00068
00069
00070 static void posix_file_free ( struct refcnt *refcnt ) {
00071 struct posix_file *file =
00072 container_of ( refcnt, struct posix_file, refcnt );
00073 struct io_buffer *iobuf;
00074 struct io_buffer *tmp;
00075
00076 list_for_each_entry_safe ( iobuf, tmp, &file->data, list ) {
00077 list_del ( &iobuf->list );
00078 free_iob ( iobuf );
00079 }
00080 free ( file );
00081 }
00082
00083
00084
00085
00086
00087
00088
00089 static void posix_file_finished ( struct posix_file *file, int rc ) {
00090 xfer_nullify ( &file->xfer );
00091 xfer_close ( &file->xfer, rc );
00092 file->rc = rc;
00093 }
00094
00095
00096
00097
00098
00099
00100
00101 static void posix_file_xfer_close ( struct xfer_interface *xfer, int rc ) {
00102 struct posix_file *file =
00103 container_of ( xfer, struct posix_file, xfer );
00104
00105 posix_file_finished ( file, rc );
00106 }
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 static int
00117 posix_file_xfer_deliver_iob ( struct xfer_interface *xfer,
00118 struct io_buffer *iobuf,
00119 struct xfer_metadata *meta ) {
00120 struct posix_file *file =
00121 container_of ( xfer, struct posix_file, xfer );
00122
00123
00124 if ( meta->whence != SEEK_CUR )
00125 file->pos = 0;
00126 file->pos += meta->offset;
00127 if ( file->filesize < file->pos )
00128 file->filesize = file->pos;
00129
00130 if ( iob_len ( iobuf ) ) {
00131 list_add_tail ( &iobuf->list, &file->data );
00132 } else {
00133 free_iob ( iobuf );
00134 }
00135
00136 return 0;
00137 }
00138
00139
00140 static struct xfer_interface_operations posix_file_xfer_operations = {
00141 .close = posix_file_xfer_close,
00142 .vredirect = xfer_vreopen,
00143 .window = unlimited_xfer_window,
00144 .alloc_iob = default_xfer_alloc_iob,
00145 .deliver_iob = posix_file_xfer_deliver_iob,
00146 .deliver_raw = xfer_deliver_as_iob,
00147 };
00148
00149
00150
00151
00152
00153
00154
00155 static struct posix_file * posix_fd_to_file ( int fd ) {
00156 struct posix_file *file;
00157
00158 list_for_each_entry ( file, &posix_files, list ) {
00159 if ( file->fd == fd )
00160 return file;
00161 }
00162 return NULL;
00163 }
00164
00165
00166
00167
00168
00169
00170 static int posix_find_free_fd ( void ) {
00171 int fd;
00172
00173 for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) {
00174 if ( ! posix_fd_to_file ( fd ) )
00175 return fd;
00176 }
00177 DBG ( "POSIX could not find free file descriptor\n" );
00178 return -ENFILE;
00179 }
00180
00181
00182
00183
00184
00185
00186
00187 int open ( const char *uri_string ) {
00188 struct posix_file *file;
00189 int fd;
00190 int rc;
00191
00192
00193 fd = posix_find_free_fd();
00194 if ( fd < 0 )
00195 return fd;
00196
00197
00198 file = zalloc ( sizeof ( *file ) );
00199 if ( ! file )
00200 return -ENOMEM;
00201 file->refcnt.free = posix_file_free;
00202 file->fd = fd;
00203 file->rc = -EINPROGRESS;
00204 xfer_init ( &file->xfer, &posix_file_xfer_operations,
00205 &file->refcnt );
00206 INIT_LIST_HEAD ( &file->data );
00207
00208
00209 if ( ( rc = xfer_open_uri_string ( &file->xfer, uri_string ) ) != 0 )
00210 goto err;
00211
00212
00213 while ( list_empty ( &file->data ) ) {
00214 step();
00215 if ( file->rc == 0 )
00216 break;
00217 if ( file->rc != -EINPROGRESS ) {
00218 rc = file->rc;
00219 goto err;
00220 }
00221 }
00222
00223
00224 list_add ( &file->list, &posix_files );
00225 DBG ( "POSIX opened %s as file %d\n", uri_string, fd );
00226 return fd;
00227
00228 err:
00229 posix_file_finished ( file, rc );
00230 ref_put ( &file->refcnt );
00231 return rc;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241 int select ( fd_set *readfds, int wait ) {
00242 struct posix_file *file;
00243 int fd;
00244
00245 do {
00246 for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) {
00247 if ( ! FD_ISSET ( fd, readfds ) )
00248 continue;
00249 file = posix_fd_to_file ( fd );
00250 if ( ! file )
00251 return -EBADF;
00252 if ( ( list_empty ( &file->data ) ) &&
00253 ( file->rc == -EINPROGRESS ) )
00254 continue;
00255
00256 FD_ZERO ( readfds );
00257 FD_SET ( fd, readfds );
00258 return 1;
00259 }
00260 step();
00261 } while ( wait );
00262
00263 return 0;
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
00278 struct posix_file *file;
00279 struct io_buffer *iobuf;
00280 size_t len;
00281
00282
00283 file = posix_fd_to_file ( fd );
00284 if ( ! file )
00285 return -EBADF;
00286
00287
00288 if ( list_empty ( &file->data ) )
00289 step();
00290
00291
00292 list_for_each_entry ( iobuf, &file->data, list ) {
00293 len = iob_len ( iobuf );
00294 if ( len > max_len )
00295 len = max_len;
00296 copy_to_user ( buffer, offset, iobuf->data, len );
00297 iob_pull ( iobuf, len );
00298 if ( ! iob_len ( iobuf ) ) {
00299 list_del ( &iobuf->list );
00300 free_iob ( iobuf );
00301 }
00302 file->pos += len;
00303 assert ( len != 0 );
00304 return len;
00305 }
00306
00307
00308 if ( file->rc != -EINPROGRESS ) {
00309 assert ( list_empty ( &file->data ) );
00310 return file->rc;
00311 }
00312
00313
00314 return -EWOULDBLOCK;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323 ssize_t fsize ( int fd ) {
00324 struct posix_file *file;
00325
00326
00327 file = posix_fd_to_file ( fd );
00328 if ( ! file )
00329 return -EBADF;
00330
00331 return file->filesize;
00332 }
00333
00334
00335
00336
00337
00338
00339
00340 int close ( int fd ) {
00341 struct posix_file *file;
00342
00343
00344 file = posix_fd_to_file ( fd );
00345 if ( ! file )
00346 return -EBADF;
00347
00348
00349 posix_file_finished ( file, 0 );
00350
00351
00352 list_del ( &file->list );
00353 ref_put ( &file->refcnt );
00354 return 0;
00355 }