mirror of
https://github.com/ipxe/ipxe
synced 2026-04-16 03:00:10 +03:00
Merge branch 'master' into mcb-tcp-xfer
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
/**
|
||||
* Write a formatted string to newly allocated memory.
|
||||
*
|
||||
* @v strp Pointer to hold allocated string
|
||||
* @v fmt Format string
|
||||
* @v args Arguments corresponding to the format string
|
||||
* @ret len Length of formatted string
|
||||
*/
|
||||
int vasprintf ( char **strp, const char *fmt, va_list args ) {
|
||||
size_t len;
|
||||
va_list args_tmp;
|
||||
|
||||
/* Calculate length needed for string */
|
||||
va_copy ( args_tmp, args );
|
||||
len = ( vsnprintf ( NULL, 0, fmt, args_tmp ) + 1 );
|
||||
va_end ( args_tmp );
|
||||
|
||||
/* Allocate and fill string */
|
||||
*strp = malloc ( len );
|
||||
if ( ! *strp )
|
||||
return -ENOMEM;
|
||||
return vsnprintf ( *strp, len, fmt, args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a formatted string to newly allocated memory.
|
||||
*
|
||||
* @v strp Pointer to hold allocated string
|
||||
* @v fmt Format string
|
||||
* @v ... Arguments corresponding to the format string
|
||||
* @ret len Length of formatted string
|
||||
*/
|
||||
int asprintf ( char **strp, const char *fmt, ... ) {
|
||||
va_list args;
|
||||
int len;
|
||||
|
||||
va_start ( args, fmt );
|
||||
len = vasprintf ( strp, fmt, args );
|
||||
va_end ( args );
|
||||
return len;
|
||||
}
|
||||
@@ -38,3 +38,25 @@ char * basename ( char *path ) {
|
||||
basename = strrchr ( path, '/' );
|
||||
return ( basename ? ( basename + 1 ) : path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return directory name from path
|
||||
*
|
||||
* @v path Full path
|
||||
* @ret dirname Directory name
|
||||
*
|
||||
* Note that this function may modify its argument.
|
||||
*/
|
||||
char * dirname ( char *path ) {
|
||||
char *separator;
|
||||
|
||||
separator = strrchr ( path, '/' );
|
||||
if ( separator == path ) {
|
||||
return "/";
|
||||
} else if ( separator ) {
|
||||
*separator = 0;
|
||||
return path;
|
||||
} else {
|
||||
return ".";
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -121,7 +121,7 @@ int start_download ( const char *uri_string, struct async *parent,
|
||||
err:
|
||||
async_uninit ( &download->async );
|
||||
ufree ( download->buffer.addr );
|
||||
free_uri ( download->uri );
|
||||
uri_put ( download->uri );
|
||||
free ( download );
|
||||
return rc;
|
||||
}
|
||||
@@ -150,7 +150,7 @@ static void download_sigchld ( struct async *async,
|
||||
/* Discard the buffer */
|
||||
ufree ( download->buffer.addr );
|
||||
}
|
||||
free_uri ( download->uri );
|
||||
uri_put ( download->uri );
|
||||
download->uri = NULL;
|
||||
|
||||
/* Terminate ourselves */
|
||||
|
||||
+1
-14
@@ -114,19 +114,6 @@ static int downloader_ensure_size ( struct downloader *downloader,
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handle start() event received via job control interface
|
||||
*
|
||||
* @v job Downloader job control interface
|
||||
*/
|
||||
static void downloader_job_start ( struct job_interface *job ) {
|
||||
struct downloader *downloader =
|
||||
container_of ( job, struct downloader, job );
|
||||
|
||||
/* Start data transfer */
|
||||
xfer_request_all ( &downloader->xfer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle kill() event received via job control interface
|
||||
*
|
||||
@@ -142,7 +129,7 @@ static void downloader_job_kill ( struct job_interface *job ) {
|
||||
|
||||
/** Downloader job control interface operations */
|
||||
static struct job_interface_operations downloader_job_operations = {
|
||||
.start = downloader_job_start,
|
||||
.start = ignore_job_start,
|
||||
.done = ignore_job_done,
|
||||
.kill = downloader_job_kill,
|
||||
.progress = ignore_job_progress,
|
||||
|
||||
+15
-12
@@ -3,6 +3,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <gpxe/refcnt.h>
|
||||
#include <gpxe/process.h>
|
||||
#include <gpxe/xfer.h>
|
||||
#include <gpxe/open.h>
|
||||
|
||||
@@ -15,6 +16,7 @@
|
||||
struct hw {
|
||||
struct refcnt refcnt;
|
||||
struct xfer_interface xfer;
|
||||
struct process process;
|
||||
};
|
||||
|
||||
static const char hw_msg[] = "Hello world!\n";
|
||||
@@ -22,6 +24,7 @@ static const char hw_msg[] = "Hello world!\n";
|
||||
static void hw_finished ( struct hw *hw, int rc ) {
|
||||
xfer_nullify ( &hw->xfer );
|
||||
xfer_close ( &hw->xfer, rc );
|
||||
process_del ( &hw->process );
|
||||
}
|
||||
|
||||
static void hw_xfer_close ( struct xfer_interface *xfer, int rc ) {
|
||||
@@ -30,26 +33,25 @@ static void hw_xfer_close ( struct xfer_interface *xfer, int rc ) {
|
||||
hw_finished ( hw, rc );
|
||||
}
|
||||
|
||||
static int hw_xfer_request ( struct xfer_interface *xfer,
|
||||
off_t start __unused, int whence __unused,
|
||||
size_t len __unused ) {
|
||||
struct hw *hw = container_of ( xfer, struct hw, xfer );
|
||||
int rc;
|
||||
|
||||
rc = xfer_deliver_raw ( xfer, hw_msg, sizeof ( hw_msg ) );
|
||||
hw_finished ( hw, rc );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct xfer_interface_operations hw_xfer_operations = {
|
||||
.close = hw_xfer_close,
|
||||
.vredirect = ignore_xfer_vredirect,
|
||||
.request = hw_xfer_request,
|
||||
.request = ignore_xfer_request,
|
||||
.seek = ignore_xfer_seek,
|
||||
.deliver_iob = xfer_deliver_as_raw,
|
||||
.deliver_raw = ignore_xfer_deliver_raw,
|
||||
};
|
||||
|
||||
static void hw_step ( struct process *process ) {
|
||||
struct hw *hw = container_of ( process, struct hw, process );
|
||||
int rc;
|
||||
|
||||
if ( xfer_ready ( &hw->xfer ) == 0 ) {
|
||||
rc = xfer_deliver_raw ( &hw->xfer, hw_msg, sizeof ( hw_msg ) );
|
||||
hw_finished ( hw, rc );
|
||||
}
|
||||
}
|
||||
|
||||
static int hw_open ( struct xfer_interface *xfer, struct uri *uri __unused ) {
|
||||
struct hw *hw;
|
||||
|
||||
@@ -59,6 +61,7 @@ static int hw_open ( struct xfer_interface *xfer, struct uri *uri __unused ) {
|
||||
return -ENOMEM;
|
||||
memset ( hw, 0, sizeof ( *hw ) );
|
||||
xfer_init ( &hw->xfer, &hw_xfer_operations, &hw->refcnt );
|
||||
process_init ( &hw->process, hw_step, &hw->refcnt );
|
||||
|
||||
/* Attach parent interface, mortalise self, and return */
|
||||
xfer_plug_plug ( &hw->xfer, xfer );
|
||||
|
||||
+17
-16
@@ -52,6 +52,7 @@ static struct socket_opener socket_openers_end[0]
|
||||
int xfer_open_uri ( struct xfer_interface *xfer, const char *uri_string ) {
|
||||
struct uri *uri;
|
||||
struct uri_opener *opener;
|
||||
int rc = -ENOTSUP;
|
||||
|
||||
DBGC ( xfer, "XFER %p opening URI %s\n", xfer, uri_string );
|
||||
|
||||
@@ -61,44 +62,45 @@ int xfer_open_uri ( struct xfer_interface *xfer, const char *uri_string ) {
|
||||
|
||||
for ( opener = uri_openers ; opener < uri_openers_end ; opener++ ) {
|
||||
if ( strcmp ( uri->scheme, opener->scheme ) == 0 ) {
|
||||
return opener->open ( xfer, uri );
|
||||
rc = opener->open ( xfer, uri );
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
DBGC ( xfer, "XFER %p attempted to open unsupported URI scheme "
|
||||
"\"%s\"\n", xfer, uri->scheme );
|
||||
free_uri ( uri );
|
||||
return -ENOTSUP;
|
||||
done:
|
||||
uri_put ( uri );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open socket
|
||||
*
|
||||
* @v xfer Data transfer interface
|
||||
* @v domain Communication domain (e.g. PF_INET)
|
||||
* @v type Communication semantics (e.g. SOCK_STREAM)
|
||||
* @v semantics Communication semantics (e.g. SOCK_STREAM)
|
||||
* @v peer Peer socket address
|
||||
* @v local Local socket address, or NULL
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int xfer_open_socket ( struct xfer_interface *xfer,
|
||||
int domain, int type, struct sockaddr *peer,
|
||||
struct sockaddr *local ) {
|
||||
int xfer_open_socket ( struct xfer_interface *xfer, int semantics,
|
||||
struct sockaddr *peer, struct sockaddr *local ) {
|
||||
struct socket_opener *opener;
|
||||
|
||||
DBGC ( xfer, "XFER %p opening (%s,%s) socket\n", xfer,
|
||||
socket_domain_name ( domain ), socket_type_name ( type ) );
|
||||
socket_semantics_name ( semantics ),
|
||||
socket_family_name ( peer->sa_family ) );
|
||||
|
||||
for ( opener = socket_openers; opener < socket_openers_end; opener++ ){
|
||||
if ( ( opener->domain == domain ) &&
|
||||
( opener->type == type ) ) {
|
||||
if ( ( opener->semantics == semantics ) &&
|
||||
( opener->family == peer->sa_family ) ) {
|
||||
return opener->open ( xfer, peer, local );
|
||||
}
|
||||
}
|
||||
|
||||
DBGC ( xfer, "XFER %p attempted to open unsupported socket type "
|
||||
"(%s,%s)\n", xfer, socket_domain_name ( domain ),
|
||||
socket_type_name ( type ) );
|
||||
"(%s,%s)\n", xfer, socket_semantics_name ( semantics ),
|
||||
socket_family_name ( peer->sa_family ) );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -117,12 +119,11 @@ int xfer_vopen ( struct xfer_interface *xfer, int type, va_list args ) {
|
||||
|
||||
return xfer_open_uri ( xfer, uri_string ); }
|
||||
case LOCATION_SOCKET: {
|
||||
int domain = va_arg ( args, int );
|
||||
int type = va_arg ( args, int );
|
||||
int semantics = va_arg ( args, int );
|
||||
struct sockaddr *peer = va_arg ( args, struct sockaddr * );
|
||||
struct sockaddr *local = va_arg ( args, struct sockaddr * );
|
||||
|
||||
return xfer_open_socket ( xfer, domain, type, peer, local ); }
|
||||
return xfer_open_socket ( xfer, semantics, peer, local ); }
|
||||
default:
|
||||
DBGC ( xfer, "XFER %p attempted to open unsupported location "
|
||||
"type %d\n", xfer, type );
|
||||
|
||||
+8
-5
@@ -78,6 +78,7 @@ static void posix_file_free ( struct refcnt *refcnt ) {
|
||||
struct io_buffer *tmp;
|
||||
|
||||
list_for_each_entry_safe ( iobuf, tmp, &file->data, list ) {
|
||||
list_del ( &iobuf->list );
|
||||
free_iob ( iobuf );
|
||||
}
|
||||
free ( file );
|
||||
@@ -190,6 +191,7 @@ static int posix_find_free_fd ( void ) {
|
||||
if ( ! posix_fd_to_file ( fd ) )
|
||||
return fd;
|
||||
}
|
||||
DBG ( "POSIX could not find free file descriptor\n" );
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
@@ -225,13 +227,11 @@ int open ( const char *uri_string ) {
|
||||
if ( ( rc = xfer_open_uri ( &file->xfer, uri_string ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
/* Request data */
|
||||
if ( ( rc = xfer_request_all ( &file->xfer ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
/* Wait for open to succeed or fail */
|
||||
while ( list_empty ( &file->data ) ) {
|
||||
step();
|
||||
if ( file->rc == 0 )
|
||||
break;
|
||||
if ( file->rc != -EINPROGRESS ) {
|
||||
rc = file->rc;
|
||||
goto err;
|
||||
@@ -240,6 +240,7 @@ int open ( const char *uri_string ) {
|
||||
|
||||
/* Add to list of open files. List takes reference ownership. */
|
||||
list_add ( &file->list, &posix_files );
|
||||
DBG ( "POSIX opened %s as file %d\n", uri_string, fd );
|
||||
return fd;
|
||||
|
||||
err:
|
||||
@@ -279,8 +280,10 @@ ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
|
||||
copy_to_user ( buffer, offset, iobuf->data,
|
||||
frag_len );
|
||||
iob_pull ( iobuf, frag_len );
|
||||
if ( ! iob_len ( iobuf ) )
|
||||
if ( ! iob_len ( iobuf ) ) {
|
||||
list_del ( &iobuf-> list );
|
||||
free_iob ( iobuf );
|
||||
}
|
||||
file->pos += frag_len;
|
||||
len += frag_len;
|
||||
offset += frag_len;
|
||||
|
||||
+22
-4
@@ -31,25 +31,43 @@
|
||||
static LIST_HEAD ( run_queue );
|
||||
|
||||
/**
|
||||
* Add process to run queue
|
||||
* Add process to process list
|
||||
*
|
||||
* @v process Process
|
||||
*/
|
||||
void schedule ( struct process *process ) {
|
||||
void process_add ( struct process *process ) {
|
||||
ref_get ( process->refcnt );
|
||||
list_add_tail ( &process->list, &run_queue );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove process from process list
|
||||
*
|
||||
* @v process Process
|
||||
*
|
||||
* It is safe to call process_del() multiple times; further calls will
|
||||
* have no effect.
|
||||
*/
|
||||
void process_del ( struct process *process ) {
|
||||
if ( ! list_empty ( &process->list ) ) {
|
||||
list_del ( &process->list );
|
||||
INIT_LIST_HEAD ( &process->list );
|
||||
ref_put ( process->refcnt );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single-step a single process
|
||||
*
|
||||
* This removes the first process from the run queue and executes a
|
||||
* single step of that process.
|
||||
* This executes a single step of the first process in the run queue,
|
||||
* and moves the process to the end of the run queue.
|
||||
*/
|
||||
void step ( void ) {
|
||||
struct process *process;
|
||||
|
||||
list_for_each_entry ( process, &run_queue, list ) {
|
||||
list_del ( &process->list );
|
||||
list_add_tail ( &process->list, &run_queue );
|
||||
process->step ( process );
|
||||
break;
|
||||
}
|
||||
|
||||
+4
-4
@@ -39,8 +39,8 @@ void ref_get ( struct refcnt *refcnt ) {
|
||||
|
||||
refcnt->refcnt++;
|
||||
|
||||
DBGC ( refcnt, "REFCNT %p incremented to %d\n",
|
||||
refcnt, refcnt->refcnt );
|
||||
DBGC2 ( refcnt, "REFCNT %p incremented to %d\n",
|
||||
refcnt, refcnt->refcnt );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,8 +59,8 @@ void ref_put ( struct refcnt *refcnt ) {
|
||||
return;
|
||||
|
||||
refcnt->refcnt--;
|
||||
DBGC ( refcnt, "REFCNT %p decremented to %d\n",
|
||||
refcnt, refcnt->refcnt );
|
||||
DBGC2 ( refcnt, "REFCNT %p decremented to %d\n",
|
||||
refcnt, refcnt->refcnt );
|
||||
|
||||
if ( refcnt->refcnt >= 0 )
|
||||
return;
|
||||
|
||||
+221
-20
@@ -25,8 +25,36 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <gpxe/vsprintf.h>
|
||||
#include <gpxe/uri.h>
|
||||
|
||||
/**
|
||||
* Dump URI for debugging
|
||||
*
|
||||
* @v uri URI
|
||||
*/
|
||||
static void dump_uri ( struct uri *uri ) {
|
||||
if ( uri->scheme )
|
||||
DBG ( " scheme \"%s\"", uri->scheme );
|
||||
if ( uri->opaque )
|
||||
DBG ( " opaque \"%s\"", uri->opaque );
|
||||
if ( uri->user )
|
||||
DBG ( " user \"%s\"", uri->user );
|
||||
if ( uri->password )
|
||||
DBG ( " password \"%s\"", uri->password );
|
||||
if ( uri->host )
|
||||
DBG ( " host \"%s\"", uri->host );
|
||||
if ( uri->port )
|
||||
DBG ( " port \"%s\"", uri->port );
|
||||
if ( uri->path )
|
||||
DBG ( " path \"%s\"", uri->path );
|
||||
if ( uri->query )
|
||||
DBG ( " query \"%s\"", uri->query );
|
||||
if ( uri->fragment )
|
||||
DBG ( " fragment \"%s\"", uri->fragment );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse URI
|
||||
*
|
||||
@@ -35,7 +63,7 @@
|
||||
*
|
||||
* Splits a URI into its component parts. The return URI structure is
|
||||
* dynamically allocated and must eventually be freed by calling
|
||||
* free_uri().
|
||||
* uri_put().
|
||||
*/
|
||||
struct uri * parse_uri ( const char *uri_string ) {
|
||||
struct uri *uri;
|
||||
@@ -136,25 +164,8 @@ struct uri * parse_uri ( const char *uri_string ) {
|
||||
}
|
||||
|
||||
done:
|
||||
DBG ( "URI \"%s\" split into", raw );
|
||||
if ( uri->scheme )
|
||||
DBG ( " scheme \"%s\"", uri->scheme );
|
||||
if ( uri->opaque )
|
||||
DBG ( " opaque \"%s\"", uri->opaque );
|
||||
if ( uri->user )
|
||||
DBG ( " user \"%s\"", uri->user );
|
||||
if ( uri->password )
|
||||
DBG ( " password \"%s\"", uri->password );
|
||||
if ( uri->host )
|
||||
DBG ( " host \"%s\"", uri->host );
|
||||
if ( uri->port )
|
||||
DBG ( " port \"%s\"", uri->port );
|
||||
if ( uri->path )
|
||||
DBG ( " path \"%s\"", uri->path );
|
||||
if ( uri->query )
|
||||
DBG ( " query \"%s\"", uri->query );
|
||||
if ( uri->fragment )
|
||||
DBG ( " fragment \"%s\"", uri->fragment );
|
||||
DBG ( "URI \"%s\" split into", uri_string );
|
||||
dump_uri ( uri );
|
||||
DBG ( "\n" );
|
||||
|
||||
return uri;
|
||||
@@ -170,3 +181,193 @@ struct uri * parse_uri ( const char *uri_string ) {
|
||||
unsigned int uri_port ( struct uri *uri, unsigned int default_port ) {
|
||||
return ( uri->port ? strtoul ( uri->port, NULL, 0 ) : default_port );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unparse URI
|
||||
*
|
||||
* @v buf Buffer to fill with URI string
|
||||
* @v size Size of buffer
|
||||
* @v uri URI to write into buffer
|
||||
* @ret len Length of URI string
|
||||
*/
|
||||
int unparse_uri ( char *buf, size_t size, struct uri *uri ) {
|
||||
int used = 0;
|
||||
|
||||
DBG ( "URI unparsing" );
|
||||
dump_uri ( uri );
|
||||
DBG ( "\n" );
|
||||
|
||||
/* Special-case opaque URIs */
|
||||
if ( uri->opaque ) {
|
||||
return ssnprintf ( ( buf + used ), ( size - used ),
|
||||
"%s:%s", uri->scheme, uri->opaque );
|
||||
}
|
||||
|
||||
/* scheme:// */
|
||||
if ( uri->scheme ) {
|
||||
used += ssnprintf ( ( buf + used ), ( size - used ),
|
||||
"%s://", uri->scheme );
|
||||
}
|
||||
|
||||
/* [user[:password]@]host[:port] */
|
||||
if ( uri->host ) {
|
||||
if ( uri->user ) {
|
||||
used += ssnprintf ( ( buf + used ), ( size - used ),
|
||||
"%s", uri->user );
|
||||
if ( uri->password ) {
|
||||
used += ssnprintf ( ( buf + used ),
|
||||
( size - used ),
|
||||
":%s", uri->password );
|
||||
}
|
||||
used += ssnprintf ( ( buf + used ), ( size - used ),
|
||||
"@" );
|
||||
}
|
||||
used += ssnprintf ( ( buf + used ), ( size - used ), "%s",
|
||||
uri->host );
|
||||
if ( uri->port ) {
|
||||
used += ssnprintf ( ( buf + used ), ( size - used ),
|
||||
":%s", uri->port );
|
||||
}
|
||||
}
|
||||
|
||||
/* /path */
|
||||
if ( uri->path ) {
|
||||
used += ssnprintf ( ( buf + used ), ( size - used ),
|
||||
"%s", uri->path );
|
||||
}
|
||||
|
||||
/* ?query */
|
||||
if ( uri->query ) {
|
||||
used += ssnprintf ( ( buf + used ), ( size - used ),
|
||||
"?%s", uri->query );
|
||||
}
|
||||
|
||||
/* #fragment */
|
||||
if ( uri->fragment ) {
|
||||
used += ssnprintf ( ( buf + used ), ( size - used ),
|
||||
"#%s", uri->fragment );
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate URI
|
||||
*
|
||||
* @v uri URI
|
||||
* @ret uri Duplicate URI
|
||||
*
|
||||
* Creates a modifiable copy of a URI.
|
||||
*/
|
||||
struct uri * uri_dup ( struct uri *uri ) {
|
||||
size_t len = ( unparse_uri ( NULL, 0, uri ) + 1 );
|
||||
char buf[len];
|
||||
|
||||
unparse_uri ( buf, len, uri );
|
||||
return parse_uri ( buf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve base+relative path
|
||||
*
|
||||
* @v base_uri Base path
|
||||
* @v relative_uri Relative path
|
||||
* @ret resolved_uri Resolved path
|
||||
*
|
||||
* Takes a base path (e.g. "/var/lib/tftpboot/vmlinuz" and a relative
|
||||
* path (e.g. "initrd.gz") and produces a new path
|
||||
* (e.g. "/var/lib/tftpboot/initrd.gz"). Note that any non-directory
|
||||
* portion of the base path will automatically be stripped; this
|
||||
* matches the semantics used when resolving the path component of
|
||||
* URIs.
|
||||
*/
|
||||
char * resolve_path ( const char *base_path,
|
||||
const char *relative_path ) {
|
||||
size_t base_len = ( strlen ( base_path ) + 1 );
|
||||
char base_path_copy[base_len];
|
||||
char *base_tmp = base_path_copy;
|
||||
char *resolved;
|
||||
|
||||
/* If relative path is absolute, just re-use it */
|
||||
if ( relative_path[0] == '/' )
|
||||
return strdup ( relative_path );
|
||||
|
||||
/* Create modifiable copy of path for dirname() */
|
||||
memcpy ( base_tmp, base_path, base_len );
|
||||
base_tmp = dirname ( base_tmp );
|
||||
|
||||
/* Process "./" and "../" elements */
|
||||
while ( *relative_path == '.' ) {
|
||||
relative_path++;
|
||||
if ( *relative_path == 0 ) {
|
||||
/* Do nothing */
|
||||
} else if ( *relative_path == '/' ) {
|
||||
relative_path++;
|
||||
} else if ( *relative_path == '.' ) {
|
||||
relative_path++;
|
||||
if ( *relative_path == 0 ) {
|
||||
base_tmp = dirname ( base_tmp );
|
||||
} else if ( *relative_path == '/' ) {
|
||||
base_tmp = dirname ( base_tmp );
|
||||
relative_path++;
|
||||
} else {
|
||||
relative_path -= 2;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
relative_path--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create and return new path */
|
||||
if ( asprintf ( &resolved, "%s%s%s", base_tmp,
|
||||
( ( base_tmp[ strlen ( base_tmp ) - 1 ] == '/' ) ?
|
||||
"" : "/" ), relative_path ) < 0 )
|
||||
return NULL;
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve base+relative URI
|
||||
*
|
||||
* @v base_uri Base URI
|
||||
* @v relative_uri Relative URI
|
||||
* @ret resolved_uri Resolved URI
|
||||
*
|
||||
* Takes a base URI (e.g. "http://etherboot.org/kernels/vmlinuz" and a
|
||||
* relative URI (e.g. "../initrds/initrd.gz") and produces a new URI
|
||||
* (e.g. "http://etherboot.org/initrds/initrd.gz").
|
||||
*/
|
||||
struct uri * resolve_uri ( struct uri *base_uri,
|
||||
struct uri *relative_uri ) {
|
||||
struct uri tmp_uri;
|
||||
char *tmp_path = NULL;
|
||||
struct uri *new_uri;
|
||||
|
||||
/* If relative URI is absolute, just re-use it */
|
||||
if ( uri_is_absolute ( relative_uri ) )
|
||||
return uri_get ( relative_uri );
|
||||
|
||||
/* Mangle URI */
|
||||
memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
|
||||
if ( relative_uri->path ) {
|
||||
tmp_path = resolve_path ( ( base_uri->path ?
|
||||
base_uri->path : "/" ),
|
||||
relative_uri->path );
|
||||
tmp_uri.path = tmp_path;
|
||||
tmp_uri.query = relative_uri->query;
|
||||
tmp_uri.fragment = relative_uri->fragment;
|
||||
} else if ( relative_uri->query ) {
|
||||
tmp_uri.query = relative_uri->query;
|
||||
tmp_uri.fragment = relative_uri->fragment;
|
||||
} else if ( relative_uri->fragment ) {
|
||||
tmp_uri.fragment = relative_uri->fragment;
|
||||
}
|
||||
|
||||
/* Create demangled URI */
|
||||
new_uri = uri_dup ( &tmp_uri );
|
||||
free ( tmp_path );
|
||||
return new_uri;
|
||||
}
|
||||
|
||||
@@ -338,6 +338,45 @@ int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of vsnprintf() that accepts a signed buffer size
|
||||
*
|
||||
* @v buf Buffer into which to write the string
|
||||
* @v size Size of buffer
|
||||
* @v fmt Format string
|
||||
* @v args Arguments corresponding to the format string
|
||||
* @ret len Length of formatted string
|
||||
*/
|
||||
int vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) {
|
||||
|
||||
/* Treat negative buffer size as zero buffer size */
|
||||
if ( ssize < 0 )
|
||||
ssize = 0;
|
||||
|
||||
/* Hand off to vsnprintf */
|
||||
return vsnprintf ( buf, ssize, fmt, args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of vsnprintf() that accepts a signed buffer size
|
||||
*
|
||||
* @v buf Buffer into which to write the string
|
||||
* @v size Size of buffer
|
||||
* @v fmt Format string
|
||||
* @v ... Arguments corresponding to the format string
|
||||
* @ret len Length of formatted string
|
||||
*/
|
||||
int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
|
||||
va_list args;
|
||||
int len;
|
||||
|
||||
/* Hand off to vssnprintf */
|
||||
va_start ( args, fmt );
|
||||
len = vssnprintf ( buf, ssize, fmt, args );
|
||||
va_end ( args );
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write character to console
|
||||
*
|
||||
|
||||
+103
-10
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <gpxe/xfer.h>
|
||||
|
||||
@@ -35,6 +36,8 @@
|
||||
void xfer_close ( struct xfer_interface *xfer, int rc ) {
|
||||
struct xfer_interface *dest = xfer_get_dest ( xfer );
|
||||
|
||||
DBGC ( xfer, "XFER %p->%p close\n", xfer, dest );
|
||||
|
||||
dest->op->close ( dest, rc );
|
||||
xfer_unplug ( xfer );
|
||||
xfer_put ( dest );
|
||||
@@ -52,7 +55,14 @@ int xfer_vredirect ( struct xfer_interface *xfer, int type, va_list args ) {
|
||||
struct xfer_interface *dest = xfer_get_dest ( xfer );
|
||||
int rc;
|
||||
|
||||
DBGC ( xfer, "XFER %p->%p redirect\n", xfer, dest );
|
||||
|
||||
rc = dest->op->vredirect ( dest, type, args );
|
||||
|
||||
if ( rc != 0 ) {
|
||||
DBGC ( xfer, "XFER %p<-%p redirect: %s\n", xfer, dest,
|
||||
strerror ( rc ) );
|
||||
}
|
||||
xfer_put ( dest );
|
||||
return rc;
|
||||
}
|
||||
@@ -89,21 +99,19 @@ int xfer_request ( struct xfer_interface *xfer, off_t offset, int whence,
|
||||
struct xfer_interface *dest = xfer_get_dest ( xfer );
|
||||
int rc;
|
||||
|
||||
DBGC ( xfer, "XFER %p->%p request %s+%ld %zd\n", xfer, dest,
|
||||
whence_text ( whence ), offset, len );
|
||||
|
||||
rc = dest->op->request ( dest, offset, whence, len );
|
||||
|
||||
if ( rc != 0 ) {
|
||||
DBGC ( xfer, "XFER %p<-%p request: %s\n", xfer, dest,
|
||||
strerror ( rc ) );
|
||||
}
|
||||
xfer_put ( dest );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request all data
|
||||
*
|
||||
* @v xfer Data transfer interface
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int xfer_request_all ( struct xfer_interface *xfer ) {
|
||||
return xfer_request ( xfer, 0, SEEK_SET, ~( ( size_t ) 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek to position
|
||||
*
|
||||
@@ -116,11 +124,33 @@ int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ) {
|
||||
struct xfer_interface *dest = xfer_get_dest ( xfer );
|
||||
int rc;
|
||||
|
||||
DBGC ( xfer, "XFER %p->%p seek %s+%ld\n", xfer, dest,
|
||||
whence_text ( whence ), offset );
|
||||
|
||||
rc = dest->op->seek ( dest, offset, whence );
|
||||
|
||||
if ( rc != 0 ) {
|
||||
DBGC ( xfer, "XFER %p<-%p seek: %s\n", xfer, dest,
|
||||
strerror ( rc ) );
|
||||
}
|
||||
xfer_put ( dest );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if interface is ready to accept data
|
||||
*
|
||||
* @v xfer Data transfer interface
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This test is optional; the data transfer interface may wish that it
|
||||
* does not yet wish to accept data, but cannot prevent attempts to
|
||||
* deliver data to it.
|
||||
*/
|
||||
int xfer_ready ( struct xfer_interface *xfer ) {
|
||||
return xfer_seek ( xfer, 0, SEEK_CUR );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate I/O buffer
|
||||
*
|
||||
@@ -132,7 +162,13 @@ struct io_buffer * xfer_alloc_iob ( struct xfer_interface *xfer, size_t len ) {
|
||||
struct xfer_interface *dest = xfer_get_dest ( xfer );
|
||||
struct io_buffer *iobuf;
|
||||
|
||||
DBGC ( xfer, "XFER %p->%p alloc_iob %zd\n", xfer, dest, len );
|
||||
|
||||
iobuf = dest->op->alloc_iob ( dest, len );
|
||||
|
||||
if ( ! iobuf ) {
|
||||
DBGC ( xfer, "XFER %p<-%p alloc_iob failed\n", xfer, dest );
|
||||
}
|
||||
xfer_put ( dest );
|
||||
return iobuf;
|
||||
}
|
||||
@@ -148,7 +184,15 @@ int xfer_deliver_iob ( struct xfer_interface *xfer, struct io_buffer *iobuf ) {
|
||||
struct xfer_interface *dest = xfer_get_dest ( xfer );
|
||||
int rc;
|
||||
|
||||
DBGC ( xfer, "XFER %p->%p deliver_iob %zd\n", xfer, dest,
|
||||
iob_len ( iobuf ) );
|
||||
|
||||
rc = dest->op->deliver_iob ( dest, iobuf );
|
||||
|
||||
if ( rc != 0 ) {
|
||||
DBGC ( xfer, "XFER %p<-%p deliver_iob: %s\n", xfer, dest,
|
||||
strerror ( rc ) );
|
||||
}
|
||||
xfer_put ( dest );
|
||||
return rc;
|
||||
}
|
||||
@@ -165,11 +209,60 @@ int xfer_deliver_raw ( struct xfer_interface *xfer,
|
||||
struct xfer_interface *dest = xfer_get_dest ( xfer );
|
||||
int rc;
|
||||
|
||||
DBGC ( xfer, "XFER %p->%p deliver_raw %p+%zd\n", xfer, dest,
|
||||
data, len );
|
||||
|
||||
rc = dest->op->deliver_raw ( dest, data, len );
|
||||
|
||||
if ( rc != 0 ) {
|
||||
DBGC ( xfer, "XFER %p<-%p deliver_raw: %s\n", xfer, dest,
|
||||
strerror ( rc ) );
|
||||
}
|
||||
xfer_put ( dest );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver formatted string
|
||||
*
|
||||
* @v xfer Data transfer interface
|
||||
* @v format Format string
|
||||
* @v args Arguments corresponding to the format string
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int xfer_vprintf ( struct xfer_interface *xfer, const char *format,
|
||||
va_list args ) {
|
||||
size_t len;
|
||||
va_list args_tmp;
|
||||
|
||||
va_copy ( args_tmp, args );
|
||||
len = vsnprintf ( NULL, 0, format, args );
|
||||
{
|
||||
char buf[len + 1];
|
||||
vsnprintf ( buf, sizeof ( buf ), format, args_tmp );
|
||||
va_end ( args_tmp );
|
||||
return xfer_deliver_raw ( xfer, buf, len );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver formatted string
|
||||
*
|
||||
* @v xfer Data transfer interface
|
||||
* @v format Format string
|
||||
* @v ... Arguments corresponding to the format string
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int xfer_printf ( struct xfer_interface *xfer, const char *format, ... ) {
|
||||
va_list args;
|
||||
int rc;
|
||||
|
||||
va_start ( args, format );
|
||||
rc = xfer_vprintf ( xfer, format, args );
|
||||
va_end ( args );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Helper methods
|
||||
|
||||
Reference in New Issue
Block a user