This is upload.c in view mode; [Download] [Up]
/*
* A client for term. Hacked about by Jeff Grills, bashed a little here and
* there by me. Mostly formatting changes + a few error condition
* changes.
* [-u] (unlink) by Darren Drake (drd@gnu.ai.mit.edu)
*/
#define I_IOCTL
#define I_SYS
#define I_STRING
#define DEBUG
#include "includes.h"
#include "client.h"
#include <sys/stat.h>
#include <time.h>
int debug = 0;
int force = 0;
int verbose = 1;
int unlinkmode = 0;
int literal_filename = 0;
struct stat st;
/*---------------------------------------------------------------------------*/
int local_options ( char opt, char *optarg )
{
switch(opt)
{
case 'f' :
force = 1;
break;
case 'q' :
verbose = 0;
break;
case 'u':
unlinkmode = 1;
break;
case 'v' :
verbose++;
break;
case 'l':
literal_filename = 1;
break;
default:
return -1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
void main(int argc, char *argv[])
{
/* From client.c */
extern int lcompression, rcompression;
/* locals for upload. */
struct Buffer buffer;
char *cutpath, *file, *remote, path[255], filename[255];
int term, fd, first, remote_size, stdin_used, type, perms, i, perc;
int ret, bytesent, total_bytesent, filesent;
double cps;
time_t total_starttime, total_stoptime, starttime, stoptime, etime;
term = -1;
fd = -1;
first = -1;
stdin_used = 0;
priority = -2;
bytesent = 0;
starttime = 0;
total_bytesent = 0;
total_starttime = time(NULL);
filesent = 0;
path[0] = '\0';
lcompression = rcompression = 0;
buffer.start = buffer.end = buffer.size = buffer.alloced = 0;
buffer.data = NULL;
/* Handle the options. We use the standard client argument handling */
/* to do this. Options peculiar to upload are 'f' for force, q for */
/* quiet, and v for verbose, u for unlink */
if ( ((first = client_options(argc,argv,"fquvl",local_options)) == -1)
|| (first >= argc) ) {
fprintf(stderr,
"Usage: upload [-f] [-q] [-u] [-v] [-r] [-c] [-p <num>] <file>"
" [... <file>] [remote dir]\n");
exit(1);
}
/* Make sure the buffer is non-zero in */
/* size. */
add_to_buffer(&buffer, 0);
get_from_buffer(&buffer);
term = connect_server(term_server);
/* check the last arg to see if it's a dir, and if so, */
/* that's the path we send to. */
if ((first < argc) && (send_command(term, C_STAT, 0, "%s",
argv[argc-1]) >= 0)) {
sscanf(command_result, "%d %d %d", &remote_size, &type, &perms );
/* check if it's a dir, and writable. */
if (type == 1) {
strcpy(path, argv[--argc]);
if ( ! (i = strlen(path))) {
fprintf(stderr, "\tFatal. Zero length path passed.\n");
exit(1);
}
if ( path[i - 1] != '/' ) {
path[i] = '/';
path[i+1] = '\0';
}
}
}
/* should check here for a file to send. enforce command line. */
/* or, maybe no args should mean take from stdin. */
/* but then, what's the output file name? -q */
while ( first < argc ) {
/* close the input file if it was left open */
if (fd > 0) {
close(fd);
fd = -1;
}
/* get the a filename to send.*/
file = argv[first++];
if ( (first+1 < argc) && (strcmp(argv[first],"-as") == 0) ) {
remote = argv[first+1];
first += 2;
}
else {
/* leave the filename alone */
remote = file;
/* remove the pathname for the outgoing file */
if (!literal_filename) {
for ( cutpath = remote; *cutpath; cutpath++ )
if ( ( *cutpath == '/' ) && ( *(cutpath+1) ) )
remote = cutpath + 1;
}
}
/* prepend the specified path, if there is one. */
if ( *path ) {
strcpy(filename, path);
strcat(filename, remote);
remote = filename;
}
if ( verbose > 0 )
if ( file == remote )
fprintf(stderr, "sending %s\n",file);
else
fprintf(stderr, "sending %s as %s\n", file, remote );
/* open input file, or use stdin. The stdin is a bit of a kludge */
/* but it can be useful. */
fd = -1;
if ( strcmp(file, "-") )
fd = open(file, O_RDONLY);
else
/* try to use stdin's file descriptor */
if ( stdin_used++ ) {
fprintf(stderr, "\tskipped : can only take input from stdin once\n");
continue;
}
else
fd = 0;
if (fd < 0) {
fprintf(stderr, "\tskipped : can't open local file\n");
continue;
}
/* get some info on the local file. We need to know the file */
/* size at the very least. */
if (fd)
stat(file, &st);
/* see if the file exists to be resumed. Done by asking term to */
/* stat the file on the remote end. */
remote_size = 0;
if (send_command(term, C_STAT, 0, "%s", remote) >= 0) {
if (force)
fprintf(stderr,"\twarning, overwriting file on remote host\n");
else
if (!fd) {
fprintf(stderr,"\tcannot resume from stdin\n");
continue;
}
else {
/* Ok. The remote file exists. lets check a few things here.. */
remote_size = atoi(command_result);
/* remote file is same size. Skip it. */
if ( remote_size == st.st_size ) {
fprintf(stderr,"\tskipping, remote file is same size as local\n");
continue;
}
/* remote file is larger than current file. Skip this as well.*/
if ( remote_size > st.st_size ) {
fprintf(stderr,"\tskipping, remote file is larger than local\n");
continue;
}
fprintf(stderr, "\tattempting to restarting upload from %d\n",
remote_size);
/* i'd really like a checksum of the file done here to make sure */
/* it's the same file -q */
}
}
if (remote_size) {
/* open file on the remote end. We use C_OPEN instead of */
/* C_UPLOAD as we don't want to truncate the file. */
if (send_command(term, C_OPEN, 0, "%s", remote) < 0) {
fprintf(stderr,"\tskipped : Couldn't open remote file, %s\n",
command_result);
continue;
}
/* do the remote file seek. */
if (send_command(term, C_SEEK, 0, "%d", remote_size) < 0) {
fprintf(stderr, "\tskipped, remote seek failed, %s\n",
command_result);
continue;
}
/* do the local file seek */
if (lseek(fd, remote_size, 0)<0) {
fprintf(stderr, "\tskipped, local seek failed, ");
perror("Reason given");
continue;
}
}
else {
/* it's a new file. Use C_UPLOAD to open, and possiblely creat, */
/* or truncate it. */
if (send_command(term, C_UPLOAD, 0, "%s", remote) < 0) {
fprintf(stderr,"\tskipped : Couldn't open remote file, %s\n",
command_result);
continue;
}
}
/* dump the file over the socket. We handle this by using C_DUMP */
/* commands to escape the data. */
if (verbose > 1)
starttime = time(NULL);
bytesent = 0;
filesent++;
do {
if (!buffer.size) {
ret = read_into_buff(fd, &buffer, 0);
if (ret <=0 && term_errno) break;
if (!buffer.size) continue;
if (send_command(term, C_DUMP, 1, "%d", buffer.size) < 0) {
fprintf(stderr, "\taborted, couldn't turn off command"
" processing, %s\n", command_result );
continue;
}
}
else {
ret = write_from_buff(term, &buffer, 0);
if (ret <=0 && term_errno) {
fprintf(stderr, "\terror writing to term server. Exiting..\n");
exit(1);
}
bytesent += ret;
total_bytesent += ret;
remote_size += ret;
if ( (verbose > 2)) {
stoptime = time(NULL);
if (stoptime - starttime)
cps = (float)(bytesent - buffer.alloced) / (float)(stoptime - starttime);
else
cps = (float)0;
if ( fd && (st.st_size) ) {
perc = (remote_size*100) / st.st_size;
fprintf(stderr, "\r\t%d of %d (%d%%) at %.2f CPS. TR: %.1f TT: %.1f ", remote_size,
st.st_size, perc, cps, (cps)?(st.st_size/cps)-(remote_size/cps):0,
(cps)?(st.st_size/cps):0 );
}
else
if (!fd)
fprintf(stderr, "\r\t%d at %.2f CPS. ", remote_size, cps );
fflush(stderr);
}
}
} while (1);
/* Close the file */
send_command(term , C_CLCLOSE, 0, 0);
/* check the remote file after send */
send_command(term, C_STAT, 0, "%s", remote);
if ((send_command(term, C_STAT, 0, "%s", remote)) >= 0) {
if (( fd && (atoi(command_result) != st.st_size) ) ||
( (!fd) && (atoi(command_result) != bytesent) ))
fprintf(stderr, "\tremote file is a different size from local after"
" upload!\n");
else
/* unlink files if we wanna remove them after *sucessful* send */
if(fd && unlinkmode) {
if((unlink(file))&&(verbose>1))
fprintf(stderr,"\tunable to remove sent file\n");
else
fprintf(stderr,"\tsent file removed.\n");
}
}
else
fprintf(stderr,"\tcouldn't stat remote file after upload. Please"
" check it.\n");
/* give them cps ratings */
if (verbose > 1) {
stoptime = time(NULL);
if ( (etime = (stoptime - starttime)) )
cps = (double)bytesent / (double)etime;
else
cps = (double)bytesent;
if ( verbose > 2)
fprintf(stderr, "\r");
fprintf(stderr, "\t%d bytes sent in %ld seconds, cps = %.2f\n",
bytesent, etime, cps );
}
}
/* be very nice, and close the file if it was left open */
if (fd > 0) {
close(fd);
fd = -1;
}
close(term);
/* give them global cps rating */
if ( (verbose > 1) && (filesent > 1) ) {
total_stoptime = time(NULL);
if ( (etime = ( total_stoptime - total_starttime )) )
cps = (double)total_bytesent / (double)etime;
else
cps = (double)total_bytesent;
fprintf(stderr, "%d total bytes sent in %ld seconds, cps ="
" %.2f\n", total_bytesent, etime, cps );
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.