|  | @@ -60,12 +60,6 @@ struct posix_file {
 | 
		
	
		
			
			| 60 | 60 |  /** List of open files */
 | 
		
	
		
			
			| 61 | 61 |  static LIST_HEAD ( posix_files );
 | 
		
	
		
			
			| 62 | 62 |  
 | 
		
	
		
			
			| 63 |  | -/** Minimum file descriptor that will ever be allocated */
 | 
		
	
		
			
			| 64 |  | -#define POSIX_FD_MIN ( 1 )
 | 
		
	
		
			
			| 65 |  | -
 | 
		
	
		
			
			| 66 |  | -/** Maximum file descriptor that will ever be allocated */
 | 
		
	
		
			
			| 67 |  | -#define POSIX_FD_MAX ( 255 )
 | 
		
	
		
			
			| 68 |  | -
 | 
		
	
		
			
			| 69 | 63 |  /**
 | 
		
	
		
			
			| 70 | 64 |   * Free open file
 | 
		
	
		
			
			| 71 | 65 |   *
 | 
		
	
	
		
			
			|  | @@ -251,6 +245,38 @@ int open ( const char *uri_string ) {
 | 
		
	
		
			
			| 251 | 245 |  	return rc;
 | 
		
	
		
			
			| 252 | 246 |  }
 | 
		
	
		
			
			| 253 | 247 |  
 | 
		
	
		
			
			|  | 248 | +/**
 | 
		
	
		
			
			|  | 249 | + * Check file descriptors for readiness
 | 
		
	
		
			
			|  | 250 | + *
 | 
		
	
		
			
			|  | 251 | + * @v readfds		File descriptors to check
 | 
		
	
		
			
			|  | 252 | + * @v wait		Wait until data is ready
 | 
		
	
		
			
			|  | 253 | + * @ret nready		Number of ready file descriptors
 | 
		
	
		
			
			|  | 254 | + */
 | 
		
	
		
			
			|  | 255 | +int select ( fd_set *readfds, int wait ) {
 | 
		
	
		
			
			|  | 256 | +	struct posix_file *file;
 | 
		
	
		
			
			|  | 257 | +	int fd;
 | 
		
	
		
			
			|  | 258 | +
 | 
		
	
		
			
			|  | 259 | +	do {
 | 
		
	
		
			
			|  | 260 | +		for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) {
 | 
		
	
		
			
			|  | 261 | +			if ( ! FD_ISSET ( fd, readfds ) )
 | 
		
	
		
			
			|  | 262 | +				continue;
 | 
		
	
		
			
			|  | 263 | +			file = posix_fd_to_file ( fd );
 | 
		
	
		
			
			|  | 264 | +			if ( ! file )
 | 
		
	
		
			
			|  | 265 | +				return -EBADF;
 | 
		
	
		
			
			|  | 266 | +			if ( ( list_empty ( &file->data ) ) &&
 | 
		
	
		
			
			|  | 267 | +			     ( file->rc != -EINPROGRESS ) )
 | 
		
	
		
			
			|  | 268 | +				continue;
 | 
		
	
		
			
			|  | 269 | +			/* Data is available or status has changed */
 | 
		
	
		
			
			|  | 270 | +			FD_ZERO ( readfds );
 | 
		
	
		
			
			|  | 271 | +			FD_SET ( fd, readfds );
 | 
		
	
		
			
			|  | 272 | +			return 1;
 | 
		
	
		
			
			|  | 273 | +		}
 | 
		
	
		
			
			|  | 274 | +		step();
 | 
		
	
		
			
			|  | 275 | +	} while ( wait );
 | 
		
	
		
			
			|  | 276 | +
 | 
		
	
		
			
			|  | 277 | +	return 0;
 | 
		
	
		
			
			|  | 278 | +}
 | 
		
	
		
			
			|  | 279 | +
 | 
		
	
		
			
			| 254 | 280 |  /**
 | 
		
	
		
			
			| 255 | 281 |   * Read data from file
 | 
		
	
		
			
			| 256 | 282 |   *
 | 
		
	
	
		
			
			|  | @@ -258,47 +284,45 @@ int open ( const char *uri_string ) {
 | 
		
	
		
			
			| 258 | 284 |   * @v offset		Starting offset within data buffer
 | 
		
	
		
			
			| 259 | 285 |   * @v len		Maximum length to read
 | 
		
	
		
			
			| 260 | 286 |   * @ret len		Actual length read, or negative error number
 | 
		
	
		
			
			|  | 287 | + *
 | 
		
	
		
			
			|  | 288 | + * This call is non-blocking; if no data is available to read then
 | 
		
	
		
			
			|  | 289 | + * -EWOULDBLOCK will be returned.
 | 
		
	
		
			
			| 261 | 290 |   */
 | 
		
	
		
			
			| 262 | 291 |  ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
 | 
		
	
		
			
			| 263 | 292 |  	struct posix_file *file;
 | 
		
	
		
			
			| 264 | 293 |  	struct io_buffer *iobuf;
 | 
		
	
		
			
			| 265 |  | -	size_t frag_len;
 | 
		
	
		
			
			| 266 |  | -	ssize_t len = 0;
 | 
		
	
		
			
			|  | 294 | +	size_t len;
 | 
		
	
		
			
			| 267 | 295 |  
 | 
		
	
		
			
			| 268 | 296 |  	/* Identify file */
 | 
		
	
		
			
			| 269 | 297 |  	file = posix_fd_to_file ( fd );
 | 
		
	
		
			
			| 270 | 298 |  	if ( ! file )
 | 
		
	
		
			
			| 271 | 299 |  		return -EBADF;
 | 
		
	
		
			
			| 272 | 300 |  
 | 
		
	
		
			
			| 273 |  | -	while ( 1 ) {
 | 
		
	
		
			
			| 274 |  | -		/* Try to fetch more data if none available */
 | 
		
	
		
			
			| 275 |  | -		if ( list_empty ( &file->data ) )
 | 
		
	
		
			
			| 276 |  | -			step();
 | 
		
	
		
			
			| 277 |  | -		/* Dequeue at most one received I/O buffer into user buffer */
 | 
		
	
		
			
			| 278 |  | -		list_for_each_entry ( iobuf, &file->data, list ) {
 | 
		
	
		
			
			| 279 |  | -			frag_len = iob_len ( iobuf );
 | 
		
	
		
			
			| 280 |  | -			if ( frag_len > max_len )
 | 
		
	
		
			
			| 281 |  | -				frag_len = max_len;
 | 
		
	
		
			
			| 282 |  | -			copy_to_user ( buffer, offset, iobuf->data,
 | 
		
	
		
			
			| 283 |  | -				       frag_len );
 | 
		
	
		
			
			| 284 |  | -			iob_pull ( iobuf, frag_len );
 | 
		
	
		
			
			| 285 |  | -			if ( ! iob_len ( iobuf ) ) {
 | 
		
	
		
			
			| 286 |  | -				list_del ( &iobuf-> list );
 | 
		
	
		
			
			| 287 |  | -				free_iob ( iobuf );
 | 
		
	
		
			
			| 288 |  | -			}
 | 
		
	
		
			
			| 289 |  | -			file->pos += frag_len;
 | 
		
	
		
			
			| 290 |  | -			len += frag_len;
 | 
		
	
		
			
			| 291 |  | -			offset += frag_len;
 | 
		
	
		
			
			| 292 |  | -			max_len -= frag_len;
 | 
		
	
		
			
			| 293 |  | -			break;
 | 
		
	
		
			
			|  | 301 | +	/* Try to fetch more data if none available */
 | 
		
	
		
			
			|  | 302 | +	if ( list_empty ( &file->data ) )
 | 
		
	
		
			
			|  | 303 | +		step();
 | 
		
	
		
			
			|  | 304 | +
 | 
		
	
		
			
			|  | 305 | +	/* Dequeue at most one received I/O buffer into user buffer */
 | 
		
	
		
			
			|  | 306 | +	list_for_each_entry ( iobuf, &file->data, list ) {
 | 
		
	
		
			
			|  | 307 | +		len = iob_len ( iobuf );
 | 
		
	
		
			
			|  | 308 | +		if ( len > max_len )
 | 
		
	
		
			
			|  | 309 | +			len = max_len;
 | 
		
	
		
			
			|  | 310 | +		copy_to_user ( buffer, offset, iobuf->data, len );
 | 
		
	
		
			
			|  | 311 | +		iob_pull ( iobuf, len );
 | 
		
	
		
			
			|  | 312 | +		if ( ! iob_len ( iobuf ) ) {
 | 
		
	
		
			
			|  | 313 | +			list_del ( &iobuf->list );
 | 
		
	
		
			
			|  | 314 | +			free_iob ( iobuf );
 | 
		
	
		
			
			| 294 | 315 |  		}
 | 
		
	
		
			
			| 295 |  | -		/* If buffer is full, return */
 | 
		
	
		
			
			| 296 |  | -		if ( ! max_len )
 | 
		
	
		
			
			| 297 |  | -			return len;
 | 
		
	
		
			
			| 298 |  | -		/* If file has completed, return */
 | 
		
	
		
			
			| 299 |  | -		if ( file->rc != -EINPROGRESS )
 | 
		
	
		
			
			| 300 |  | -			return ( file->rc ? file->rc : len );
 | 
		
	
		
			
			|  | 316 | +		file->pos += len;
 | 
		
	
		
			
			|  | 317 | +		return len;
 | 
		
	
		
			
			| 301 | 318 |  	}
 | 
		
	
		
			
			|  | 319 | +
 | 
		
	
		
			
			|  | 320 | +	/* If file has completed, return (after returning all data) */
 | 
		
	
		
			
			|  | 321 | +	if ( file->rc != -EINPROGRESS )
 | 
		
	
		
			
			|  | 322 | +		return file->rc;
 | 
		
	
		
			
			|  | 323 | +
 | 
		
	
		
			
			|  | 324 | +	/* No data ready and file still in progress; return -WOULDBLOCK */
 | 
		
	
		
			
			|  | 325 | +	return -EWOULDBLOCK;
 | 
		
	
		
			
			| 302 | 326 |  }
 | 
		
	
		
			
			| 303 | 327 |  
 | 
		
	
		
			
			| 304 | 328 |  /**
 |