/*
* Copyright (c) 2003 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*/
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/time.h>
#ifdef __APPLE__
#include <sys/paths.h>
#include <sys/attr.h>
#endif /* __APPLE__ */
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#ifdef HAVE_ZLIB
#include <zlib.h>
#endif /* HAVE_ZLIB */
#include <snet.h>
#include "applefile.h"
#include "connect.h"
#include "cksum.h"
#include "base64.h"
#include "code.h"
#include "largefile.h"
#include "progress.h"
extern struct timeval timeout;
extern struct as_header as_header;
extern int verbose;
extern int quiet;
extern int dodots;
extern int cksum;
extern int linenum;
extern int force;
extern int showprogress;
extern off_t lsize, total;
extern void (*logger)( char * );
extern SSL_CTX *ctx;
int
stor_response( SNET *sn, int *respcount, struct timeval *tv )
{
fd_set fds;
char *line;
struct timeval to;
for ( ; *respcount > 0; (*respcount)-- ) {
if ( ! snet_hasdata( sn )) {
FD_ZERO( &fds );
FD_SET( snet_fd( sn ), &fds );
if ( select( snet_fd( sn ) + 1, &fds, NULL, NULL, tv ) < 0 ) {
return( -1 );
}
if ( ! FD_ISSET( snet_fd( sn ), &fds )) {
break;
}
}
to = timeout;
if (( line = snet_getline_multi( sn, logger, &to )) == NULL ) {
if ( snet_eof( sn )) {
fprintf( stderr, "store failed: Connection closed\n" );
} else {
fprintf( stderr, "store failed: %s\n", strerror( errno ));
}
return( -1 );
}
if ( (*respcount) % 2 ) {
if ( *line != '2' ) {
/* Error from server - transaction aborted */
fprintf( stderr, "%s\n", line );
return( -1 );
}
} else {
if ( *line != '3' ) {
/* Error from server - transaction aborted */
fprintf( stderr, "%s\n", line );
return( -1 );
}
}
}
return( 0 );
}
int
n_stor_file( SNET *sn, char *pathdesc, char *path )
{
/* tell server what it is getting */
if ( snet_writef( sn, "%s\r\n", pathdesc ) < 0 ) {
fprintf( stderr, "n_store_file %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
if ( verbose ) printf( ">>> %s\n", pathdesc );
/* tell server how much data to expect and send '.' */
if ( snet_writef( sn, "0\r\n.\r\n" ) < 0 ) {
fprintf( stderr, "n_store_file %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
if ( verbose ) fputs( ">>> 0\n>>> .\n", stdout );
if ( !quiet && !showprogress ) {
printf( "%s: stored as zero length file\n", path );
}
return( 0 );
}
int
stor_file( SNET *sn, char *pathdesc, char *path, off_t transize,
char *trancksum )
{
int fd;
char buf[ 8192 ];
struct stat st;
struct timeval tv;
ssize_t rr, size = 0;
unsigned int md_len;
extern EVP_MD *md;
EVP_MD_CTX mdctx;
unsigned char md_value[ EVP_MAX_MD_SIZE ];
char cksum_b64[ SZ_BASE64_E( EVP_MAX_MD_SIZE ) ];
/* Check for checksum in transcript */
if ( cksum ) {
if ( strcmp( trancksum, "-" ) == 0 ) {
fprintf( stderr, "line %d: No checksum listed\n", linenum );
exit( 2 );
}
EVP_DigestInit( &mdctx, md );
}
/* Open and stat file */
if (( fd = open( path, O_RDONLY, 0 )) < 0 ) {
perror( path );
exit( 2 );
}
if ( fstat( fd, &st ) < 0 ) {
perror( path );
close( fd );
exit( 2 );
}
/* Check size listed in transcript */
if ( st.st_size != transize ) {
if ( force ) {
fprintf( stderr, "warning: " );
}
fprintf( stderr,
"line %d: size in transcript does not match size of file\n",
linenum );
if ( ! force ) {
close( fd );
exit( 2 );
}
}
size = st.st_size;
/* tell server what it is getting */
if ( snet_writef( sn, "%s\r\n", pathdesc ) < 0 ) {
fprintf( stderr, "stor_file %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
if ( verbose ) printf( ">>> %s\n", pathdesc );
/* tell server how much data to expect */
if ( snet_writef( sn, "%" PRIofft "d\r\n", st.st_size ) < 0 ) {
fprintf( stderr, "stor_file %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
if ( verbose ) printf( ">>> %" PRIofft "d\n", st.st_size );
/* write file to server */
while (( rr = read( fd, buf, sizeof( buf ))) > 0 ) {
tv = timeout;
if ( snet_write( sn, buf, rr, &tv ) != rr ) {
fprintf( stderr, "stor_file %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= rr;
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
if ( cksum ) {
EVP_DigestUpdate( &mdctx, buf, (unsigned int)rr );
}
if ( showprogress ) {
progressupdate( rr, path );
}
}
if ( rr < 0 ) {
perror( path );
exit( 2 );
}
/* Check number of bytes sent to server */
if ( size != 0 ) {
fprintf( stderr,
"stor_file %s failed: Sent wrong number of bytes to server\n",
pathdesc );
exit( 2 );
}
/* End transaction with server */
if ( snet_writef( sn, ".\r\n" ) < 0 ) {
fprintf( stderr, "stor_file %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
if ( verbose ) fputs( "\n>>> .\n", stdout );
if ( close( fd ) < 0 ) {
perror( path );
exit( 2 );
}
/* cksum data sent */
if ( cksum ) {
EVP_DigestFinal( &mdctx, md_value, &md_len );
base64_e( md_value, md_len, cksum_b64 );
if ( strcmp( trancksum, cksum_b64 ) != 0 ) {
fprintf( stderr,
"line %d: checksum listed in transcript wrong\n", linenum );
if ( ! force ) exit( 2 );
}
}
if ( !quiet && !showprogress ) printf( "%s: stored\n", path );
return( 0 );
}
#ifdef __APPLE__
int
stor_applefile( SNET *sn, char *pathdesc, char *path, off_t transize,
char *trancksum, struct applefileinfo *afinfo )
{
int rc = 0, dfd = 0, rfd = 0;
off_t size;
char buf[ 8192 ], rsrc_path[ MAXPATHLEN ];
struct timeval tv;
unsigned int md_len;
unsigned int rsrc_len;
extern EVP_MD *md;
EVP_MD_CTX mdctx;
unsigned char md_value[ EVP_MAX_MD_SIZE ];
char cksum_b64[ EVP_MAX_MD_SIZE ];
/* Check for checksum in transcript */
if ( cksum ) {
if ( strcmp( trancksum, "-" ) == 0 ) {
fprintf( stderr, "line %d: No checksum listed\n", linenum );
exit( 2 );
}
EVP_DigestInit( &mdctx, md );
}
/* Check size listed in transcript */
if ( afinfo->as_size != transize ) {
if ( force ) {
fprintf( stderr, "warning: " );
}
fprintf( stderr,
"%s: size in transcript does not match size of file\n", path );
if ( ! force ) {
exit( 2 );
}
}
size = afinfo->as_size;
/* endian handling, swap header entries if necessary */
rsrc_len = afinfo->as_ents[ AS_RFE ].ae_length;
as_entry_netswap( &afinfo->as_ents[ AS_FIE ] );
as_entry_netswap( &afinfo->as_ents[ AS_RFE ] );
as_entry_netswap( &afinfo->as_ents[ AS_DFE ] );
/* open data and rsrc fork */
if (( dfd = open( path, O_RDONLY )) < 0 ) {
perror( path );
exit( 2 );
}
if ( rsrc_len > 0 ) {
if ( snprintf( rsrc_path, MAXPATHLEN, "%s%s",
path, _PATH_RSRCFORKSPEC ) >= MAXPATHLEN ) {
errno = ENAMETOOLONG;
return( -1 );
}
if (( rfd = open( rsrc_path, O_RDONLY )) < 0 ) {
perror( rsrc_path );
close( dfd );
exit( 2 );
}
}
if ( snet_writef( sn, "%s\r\n", pathdesc ) < 0 ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
if ( verbose ) {
printf( ">>> %s\n", pathdesc );
}
/* tell server how much data to expect */
tv = timeout;
if ( snet_writef( sn, "%" PRIofft "d\r\n", afinfo->as_size ) < 0 ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
if ( verbose ) printf( ">>> %" PRIofft "d\n", afinfo->as_size );
/* write applesingle header to server */
tv = timeout;
if ( snet_write( sn, ( char * )&as_header, AS_HEADERLEN, &tv ) !=
AS_HEADERLEN ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= AS_HEADERLEN;
if ( cksum ) {
EVP_DigestUpdate( &mdctx, (char *)&as_header, AS_HEADERLEN );
}
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
if ( showprogress ) {
progressupdate( AS_HEADERLEN, path );
}
/* write header entries to server */
tv = timeout;
if ( snet_write( sn, ( char * )&afinfo->as_ents,
( 3 * sizeof( struct as_entry )), &tv )
!= ( 3 * sizeof( struct as_entry ))) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= ( 3 * sizeof( struct as_entry ));
if ( cksum ) {
EVP_DigestUpdate( &mdctx, (char *)&afinfo->as_ents,
(unsigned int)( 3 * sizeof( struct as_entry )));
}
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
if ( showprogress ) {
progressupdate(( 3 * sizeof( struct as_entry )), path );
}
/* write finder info data to server */
tv = timeout;
if ( snet_write( sn, (char *)afinfo->ai.ai_data, FINFOLEN,
&tv ) != FINFOLEN ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= FINFOLEN;
if ( cksum ) {
EVP_DigestUpdate( &mdctx, afinfo->ai.ai_data, FINFOLEN );
}
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
if ( showprogress ) {
progressupdate( FINFOLEN, path );
}
/* write rsrc fork data to server */
if ( rsrc_len > 0 ) {
while (( rc = read( rfd, buf, sizeof( buf ))) > 0 ) {
tv = timeout;
if ( snet_write( sn, buf, rc, &tv ) != rc ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= rc;
if ( cksum ) {
EVP_DigestUpdate( &mdctx, buf, (unsigned int)rc );
}
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
if ( showprogress ) {
progressupdate( rc, path );
}
}
if ( rc < 0 ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
}
/* write data fork to server */
while (( rc = read( dfd, buf, sizeof( buf ))) > 0 ) {
tv = timeout;
if ( snet_write( sn, buf, rc, &tv ) != rc ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= rc;
if ( cksum ) {
EVP_DigestUpdate( &mdctx, buf, (unsigned int)rc );
}
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
if ( showprogress ) {
progressupdate( rc, path );
}
}
if ( rc < 0 ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
/* Check number of bytes sent to server */
if ( size != 0 ) {
fprintf( stderr,
"stor_applefile %s failed: Sent wrong number of bytes to server\n",
pathdesc );
exit( 2 );
}
/* End transaction with server */
if ( snet_writef( sn, ".\r\n" ) < 0 ) {
fprintf( stderr, "stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
if ( verbose ) fputs( "\n>>> .\n", stdout );
/* Close file descriptors */
if ( close( dfd ) < 0 ) {
perror( path );
if ( afinfo->as_ents[ AS_RFE ].ae_length > 0 ) {
close( rfd );
}
exit( 2 );
}
if ( afinfo->as_ents[ AS_RFE ].ae_length > 0 ) {
if ( close( rfd ) < 0 ) {
perror( rsrc_path );
exit( 2 );
}
}
/* cksum data sent */
if ( cksum ) {
EVP_DigestFinal( &mdctx, md_value, &md_len );
base64_e( ( char*)&md_value, md_len, cksum_b64 );
if ( strcmp( trancksum, cksum_b64 ) != 0 ) {
fprintf( stderr,
"line %d: checksum listed in transcript wrong\n", linenum );
if ( ! force ) exit( 2 );
}
}
if ( !quiet && !showprogress ) printf( "%s: stored\n", path );
return( 0 );
}
int
n_stor_applefile( SNET *sn, char *pathdesc, char *path )
{
struct timeval tv;
struct applefileinfo afinfo;
off_t size;
/* Setup fake apple file info */
/* Finder Info */
memset( &afinfo, 0, sizeof( afinfo ));
sprintf( (char *)(afinfo.ai.ai_data + FI_CREATOR_OFFSET), "%s", "RDMD" );
afinfo.as_ents[AS_FIE].ae_id = ASEID_FINFO;
afinfo.as_ents[AS_FIE].ae_offset = AS_HEADERLEN +
( 3 * sizeof( struct as_entry )); /* 62 */
afinfo.as_ents[AS_FIE].ae_length = FINFOLEN;
/* Resource Fork */
afinfo.as_ents[AS_RFE].ae_id = ASEID_RFORK;
afinfo.as_ents[AS_RFE].ae_offset = /* 94 */
( afinfo.as_ents[ AS_FIE ].ae_offset
+ afinfo.as_ents[ AS_FIE ].ae_length );
afinfo.as_ents[ AS_RFE ].ae_length = 0;
/* Data Fork */
afinfo.as_ents[AS_DFE].ae_id = ASEID_DFORK;
afinfo.as_ents[ AS_DFE ].ae_offset =
( afinfo.as_ents[ AS_RFE ].ae_offset
+ afinfo.as_ents[ AS_RFE ].ae_length );
afinfo.as_ents[ AS_DFE ].ae_length = 0;
afinfo.as_size = afinfo.as_ents[ AS_DFE ].ae_offset
+ afinfo.as_ents[ AS_DFE ].ae_length;
size = afinfo.as_size;
/* tell server what it is getting */
if ( snet_writef( sn, "%s\r\n", pathdesc ) < 0 ) {
fprintf( stderr, "n_stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
if ( verbose ) printf( ">>> %s\n", pathdesc );
/* tell server how much data to expect and send '.' */
if ( snet_writef( sn, "%" PRIofft "d\r\n", afinfo.as_size ) < 0 ) {
fprintf( stderr, "n_stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
exit( 2 );
}
if ( verbose ) printf( ">>> %" PRIofft "d\n", afinfo.as_size );
/* write applesingle header to server */
tv = timeout;
if ( snet_write( sn, (char *)&as_header, AS_HEADERLEN, &tv )
!= AS_HEADERLEN ) {
fprintf( stderr, "n_stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= AS_HEADERLEN;
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
/* endian handling, convert to valid AppleSingle format, if necessary */
as_entry_netswap( &afinfo.as_ents[ AS_FIE ] );
as_entry_netswap( &afinfo.as_ents[ AS_RFE ] );
as_entry_netswap( &afinfo.as_ents[ AS_DFE ] );
/* write header entries to server */
tv = timeout;
if ( snet_write( sn, ( char * )&afinfo.as_ents,
( 3 * sizeof( struct as_entry )), &tv )
!= ( 3 * sizeof( struct as_entry ))) {
fprintf( stderr, "n_stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= ( 3 * sizeof( struct as_entry ));
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
/* write finder info data to server */
tv = timeout;
if ( snet_write( sn, (char *)afinfo.ai.ai_data, FINFOLEN,
&tv ) != FINFOLEN ) {
fprintf( stderr, "n_stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
size -= FINFOLEN;
if ( dodots ) { putc( '.', stdout ); fflush( stdout ); }
/* Check number of bytes sent to server */
if ( size != 0 ) {
fprintf( stderr, "n_stor_applefile %s failed:"
" Sent wrong number of bytes to server\n",
pathdesc );
exit( 2 );
}
/* End transaction with server */
if ( snet_writef( sn, ".\r\n" ) < 0 ) {
fprintf( stderr, "n_stor_applefile %s failed: %s\n", pathdesc,
strerror( errno ));
return( -1 );
}
if ( verbose ) fputs( "\n>>> .\n", stdout );
if ( !quiet && !showprogress ) {
printf( "%s: stored as zero length applefile\n", path );
}
return( 0 );
}
#else /* __APPLE__ */
int
stor_applefile( SNET *sn, char *pathdesc, char *path, off_t transize,
char *trancksum, struct applefileinfo *afinfo )
{
fprintf( stderr, "stor_applefile %s invalid\n", pathdesc );
exit( 2 );
}
int
n_stor_applefile( SNET *sn, char *pathdesc, char *path )
{
fprintf( stderr, "n_stor_applefile %s invalid\n", pathdesc );
exit( 2 );
}
#endif /* __APPLE__ */
syntax highlighted by Code2HTML, v. 0.9.1