mirror of
https://git.FreeBSD.org/src.git
synced 2025-02-09 02:26:27 +00:00
Bring in a new library `libftpio', so named to avoid clashes with older
packages and also sort of give the (correct) impression that this basically sits on top of stdio and deals with stream pointers (FILE*).
This commit is contained in:
parent
baebc39ab5
commit
31caf7f20f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/FREEBSD/; revision=16420
10
lib/libftpio/Makefile
Normal file
10
lib/libftpio/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
LIB= ftpio
|
||||
CFLAGS+= -I${.CURDIR}
|
||||
SRCS= ftpio.c
|
||||
MAN3= ftpio.3
|
||||
|
||||
beforeinstall:
|
||||
cd ${.CURDIR}; cmp -s ftpio.h ${DESTDIR}/usr/include/ftpio.h || \
|
||||
${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ftpio.h ${DESTDIR}/usr/include
|
||||
|
||||
.include <bsd.lib.mk>
|
257
lib/libftpio/ftp_pkg.c
Normal file
257
lib/libftpio/ftp_pkg.c
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c)1995, 1996 Jordan Hubbard
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code may be used, modified, copied, distributed, and
|
||||
* sold, in both source and binary form provided that the above
|
||||
* copyright and these terms are retained, verbatim, as the first
|
||||
* lines of this file. Under no circumstances is the author
|
||||
* responsible for the proper functioning of the software nor does
|
||||
* the author assume any responsibility for damages incurred with
|
||||
* its use.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* TCL Interface code for functions provided by the ftp library.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ftpio.h>
|
||||
#include "ftp_pkg.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (1)
|
||||
#define FALSE (0)
|
||||
#endif
|
||||
|
||||
#define CHECK_ARGS(cnt, myname, str) \
|
||||
if (argc <= (cnt)) { sprintf(interp->result, "usage: %s %s", myname, str); return TCL_ERROR; }
|
||||
|
||||
#define USAGE(myname, msg) \
|
||||
{ fprintf(stderr, "%s: %s\n", myname, msg); return TCL_ERROR; }
|
||||
|
||||
|
||||
/* Registration function */
|
||||
int
|
||||
Ftp_Init(Tcl_Interp *interp)
|
||||
{
|
||||
Tcl_CreateCommand (interp, "ftp_login", Ftp_login, NULL, NULL);
|
||||
Tcl_CreateCommand (interp, "ftp_chdir", Ftp_chdir, NULL, NULL);
|
||||
Tcl_CreateCommand (interp, "ftp_getsize", Ftp_getsize, NULL, NULL);
|
||||
Tcl_CreateCommand (interp, "ftp_get", Ftp_get, NULL, NULL);
|
||||
Tcl_CreateCommand (interp, "ftp_put", Ftp_put, NULL, NULL);
|
||||
Tcl_CreateCommand (interp, "ftp_binary", Ftp_binary, NULL, NULL);
|
||||
Tcl_CreateCommand (interp, "ftp_passive", Ftp_passive, NULL, NULL);
|
||||
Tcl_CreateCommand (interp, "ftp_get_url", Ftp_get_url, NULL, NULL);
|
||||
Tcl_CreateCommand (interp, "ftp_put_url", Ftp_put_url, NULL, NULL);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_login host user passwd port
|
||||
* -- returns new fileId
|
||||
*
|
||||
*/
|
||||
int
|
||||
Ftp_login(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
char *user, *pass;
|
||||
int port;
|
||||
|
||||
CHECK_ARGS(1, argv[0], "host [user] [passwd] [port]");
|
||||
|
||||
user = (argc > 2) ? argv[2] : "ftp";
|
||||
pass = (argc > 3) ? argv[3] : "setup@";
|
||||
port = (argc > 4) ? atoi(argv[4]) : 21;
|
||||
/* Debug("ftp_pkg: attempt login to host %s using %s/%s (port %d)", argv[1], user, pass, port); */
|
||||
fp = ftpLogin(argv[1], user, pass, port);
|
||||
if (fp) {
|
||||
/* Debug("ftp_pkg: logged successfully into host %s", argv[1]); */
|
||||
Tcl_EnterFile(interp, fp, TCL_FILE_READABLE | TCL_FILE_WRITABLE);
|
||||
return TCL_OK;
|
||||
}
|
||||
/* Debug("ftp_pkg: login operation failed for host %s", argv[1]); */
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_chdir file-handle newdir
|
||||
* -- returns status
|
||||
*/
|
||||
int
|
||||
Ftp_chdir(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
CHECK_ARGS(2, argv[0], "fileId directory");
|
||||
if (Tcl_GetOpenFile(interp, argv[1], TRUE, TRUE, &fp) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
/* Debug("ftp_pkg: attempt chdir to dir %s", argv[2]); */
|
||||
if (!ftpChdir(fp, argv[2])) {
|
||||
/* Debug("ftp_pkg: chdir successful"); */
|
||||
return TCL_OK;
|
||||
}
|
||||
/* Debug("ftp_pkg: chdir failed"); */
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_getsize file-handle filename
|
||||
* -- returns size
|
||||
*/
|
||||
int
|
||||
Ftp_getsize(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
int sz;
|
||||
|
||||
CHECK_ARGS(2, argv[0], "fileId filename");
|
||||
if (Tcl_GetOpenFile(interp, argv[1], TRUE, TRUE, &fp) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
/* Debug("ftp_pkg: attempt to get size of %s", argv[2]); */
|
||||
if ((sz = ftpGetSize(fp, argv[2])) >= 0) {
|
||||
/* Debug("ftp_pkg: getsize successful (%d)", sz); */
|
||||
sprintf(interp->result, "%d", sz);
|
||||
return TCL_OK;
|
||||
}
|
||||
/* Debug("ftp_pkg: chdir failed"); */
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_get fileId filename
|
||||
* -- returns new fileId for filename
|
||||
*
|
||||
*/
|
||||
int
|
||||
Ftp_get(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp, *fp2;
|
||||
|
||||
CHECK_ARGS(2, argv[0], "fileId filename");
|
||||
if (Tcl_GetOpenFile(interp, argv[1], TRUE, TRUE, &fp) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
/* Debug("ftp_pkg: attempt to get file %s", argv[2]); */
|
||||
fp2 = ftpGet(fp, argv[2]);
|
||||
if (fp2) {
|
||||
/* Debug("ftp_pkg: get operation successful for: %s", argv[2]); */
|
||||
Tcl_EnterFile(interp, fp2, TCL_FILE_READABLE);
|
||||
return TCL_OK;
|
||||
}
|
||||
/* Debug("ftp_pkg: get operation failed for file %s", argv[2]); */
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_put fileId filename
|
||||
* -- returns new fileId for filename
|
||||
*
|
||||
*/
|
||||
int
|
||||
Ftp_put(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp, *fp2;
|
||||
|
||||
CHECK_ARGS(2, argv[0], "fileId filename");
|
||||
if (Tcl_GetOpenFile(interp, argv[1], TRUE, TRUE, &fp) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
/* Debug("ftp_pkg: attempt to put file %s", argv[2]); */
|
||||
fp2 = ftpPut(fp, argv[2]);
|
||||
if (fp2) {
|
||||
/* Debug("ftp_pkg: put operation successful for: %s", argv[2]); */
|
||||
Tcl_EnterFile(interp, fp2, TCL_FILE_READABLE);
|
||||
return TCL_OK;
|
||||
}
|
||||
/* Debug("ftp_pkg: put operation failed for file %s", argv[2]); */
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_binary fileId value
|
||||
* -- Set binary mode to truth value for FTP session represented by fileId
|
||||
*
|
||||
*/
|
||||
int
|
||||
Ftp_binary(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
CHECK_ARGS(2, argv[0], "fileId bool");
|
||||
if (Tcl_GetOpenFile(interp, argv[1], TRUE, TRUE, &fp) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
/* Debug("ftp_pkg: set binary mode to %d", atoi(argv[2])); */
|
||||
ftpBinary(fp, atoi(argv[2]));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_passive fileId value
|
||||
* -- Set passive mode to truth value for FTP session represented by fileId
|
||||
*
|
||||
*/
|
||||
int
|
||||
Ftp_passive(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
CHECK_ARGS(2, argv[0], "fileId bool");
|
||||
if (Tcl_GetOpenFile(interp, argv[1], TRUE, TRUE, &fp) != TCL_OK)
|
||||
return TCL_ERROR;
|
||||
/* Debug("ftp_pkg: set passive mode to %d", atoi(argv[2])); */
|
||||
ftpPassive(fp, atoi(argv[2]));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_get_url URL user pass
|
||||
* -- Return new fileId for open URL (using user and pass to log in)
|
||||
*
|
||||
*/
|
||||
int
|
||||
Ftp_get_url(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
char *user, *pass;
|
||||
|
||||
CHECK_ARGS(1, argv[0], "URL [username] [password]");
|
||||
user = (argc > 2) ? argv[2] : "ftp";
|
||||
pass = (argc > 3) ? argv[3] : "setup@";
|
||||
/* Debug("ftp_pkg: attempt to get URL %s as %s/%s", argv[1], user, pass); */
|
||||
fp = ftpGetURL(argv[1], user, pass);
|
||||
if (fp) {
|
||||
/* Debug("ftp_pkg: get URL successful"); */
|
||||
Tcl_EnterFile(interp, fp, TCL_FILE_READABLE);
|
||||
return TCL_OK;
|
||||
}
|
||||
/* Debug("ftp_pkg: get URL failed"); */
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* ftp_put_url URL user pass
|
||||
* -- Return new fileId for open url (using user and pass to log in)
|
||||
*
|
||||
*/
|
||||
int
|
||||
Ftp_put_url(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
char *user, *pass;
|
||||
|
||||
CHECK_ARGS(1, argv[0], "URL [username] [password]");
|
||||
user = (argc > 2) ? argv[2] : "ftp";
|
||||
pass = (argc > 3) ? argv[3] : "setup@";
|
||||
/* Debug("ftp_pkg: attempt to put URL %s as %s/%s", argv[1], user, pass); */
|
||||
fp = ftpPutURL(argv[1], user, pass);
|
||||
if (fp) {
|
||||
/* Debug("ftp_pkg: put URL successful"); */
|
||||
Tcl_EnterFile(interp, fp, TCL_FILE_READABLE);
|
||||
return TCL_OK;
|
||||
}
|
||||
/* Debug("ftp_pkg: put URL failed"); */
|
||||
return TCL_ERROR;
|
||||
}
|
35
lib/libftpio/ftp_pkg.h
Normal file
35
lib/libftpio/ftp_pkg.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef _FTP_PKG_H
|
||||
#define _FTP_PKG_H
|
||||
|
||||
/*
|
||||
* Copyright (c)1995, 1996 Jordan Hubbard
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code may be used, modified, copied, distributed, and
|
||||
* sold, in both source and binary form provided that the above
|
||||
* copyright and these terms are retained, verbatim, as the first
|
||||
* lines of this file. Under no circumstances is the author
|
||||
* responsible for the proper functioning of the software nor does
|
||||
* the author assume any responsibility for damages incurred with
|
||||
* its use.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* TCL Interface code for functions provided by the ftp library.
|
||||
*/
|
||||
|
||||
#include <tcl.h>
|
||||
#include <ftpio.h>
|
||||
|
||||
extern int Ftp_login (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
extern int Ftp_chdir (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
extern int Ftp_getsize (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
extern int Ftp_get (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
extern int Ftp_put (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
extern int Ftp_binary (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
extern int Ftp_passive (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
extern int Ftp_get_url (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
extern int Ftp_put_url (ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
|
||||
|
||||
#endif /* _FTP_PKG_H */
|
185
lib/libftpio/ftpio.3
Normal file
185
lib/libftpio/ftpio.3
Normal file
@ -0,0 +1,185 @@
|
||||
.\" Copyright (c) 1996 Jordan Hubbard (jkh@FreeBSD.org)
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\"
|
||||
.Dd June 17, 1996
|
||||
.Dt ftpio 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ftpLogin ,
|
||||
.Nm ftpChdir ,
|
||||
.Nm ftpErrno ,
|
||||
.Nm ftpGetModtime ,
|
||||
.Nm ftpGetSize ,
|
||||
.Nm ftpGet ,
|
||||
.Nm ftpPut ,
|
||||
.Nm ftpBinary ,
|
||||
.Nm ftpPassive ,
|
||||
.Nm ftpRestart ,
|
||||
.Nm ftpGetURL ,
|
||||
.Nm ftpPutURL ,
|
||||
.Nd FTPIO User library
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <ftpio.h>
|
||||
.Ft FILE *
|
||||
.Fn ftpLogin "char *host, char *user, char *passwd, int ftp_port"
|
||||
.Ft int
|
||||
.Fn ftpChdir "FILE *fp, char *dirname"
|
||||
.Ft int
|
||||
.Fn ftpErrno "FILE *fp"
|
||||
.Ft time_t
|
||||
.Fn ftpGetModtime "FILE *fp, char *file"
|
||||
.Ft size_t
|
||||
.Fn ftpGetSize "FILE *fp, char *file"
|
||||
.Ft FILE *
|
||||
.Fn ftpGet "FILE *fp, char *file"
|
||||
.Ft FILE *
|
||||
.Fn ftpPut "FILE *fp, char *file"
|
||||
.Ft int
|
||||
.Fn ftpBinary "FILE *fp, int status"
|
||||
.Ft int
|
||||
.Fn ftpPassive "FILE *fp, int status"
|
||||
.Ft int
|
||||
.Fn ftpRestart "FILE *fp, int where"
|
||||
.Ft FILE *
|
||||
.Fn ftpGetURL "char *url, char *user, char *passwd"
|
||||
.Ft FILE *
|
||||
.Fn ftpPutURL "char *url, char *user, char *passwd"
|
||||
|
||||
.Sh DESCRIPTION
|
||||
These functions implement a high-level library for managing FTP connections.
|
||||
.Pp
|
||||
.Fn ftpLogin
|
||||
attempts to log in using the supplied
|
||||
.Fa user ,
|
||||
.Fa passwd
|
||||
and
|
||||
.Fa ftp_port
|
||||
fields (if passed as 0,
|
||||
.Fa ftp_port
|
||||
defaults to the standard ftp port of 21). If it is successful, a
|
||||
standard
|
||||
.Fa stream
|
||||
descriptor is returned which should be passed to subsequent FTP
|
||||
operations. On failure, NULL is returned and
|
||||
.Fn ftpErrno
|
||||
will return the error code returned by the foreign server.
|
||||
.Pp
|
||||
.Fn ftpChdir
|
||||
attempts to issue a server CD command to the the directory named in
|
||||
.Fa dir.
|
||||
On success, zero is returned. On failure, -1.
|
||||
.Pp
|
||||
.Fn ftpErrno
|
||||
returns the server failure code for the last operation (useful for seeing
|
||||
more about what happened if you're familiar with FTP error codes).
|
||||
.Pp
|
||||
.Fn ftpGet
|
||||
attempts to retreive the file named by the
|
||||
.Fa file
|
||||
argument (which is assumed to be relative to the FTP server's current directory,
|
||||
see
|
||||
.Fn ftpChdir )
|
||||
and returns a new
|
||||
.Fa stream
|
||||
pointer for the file or NULL on failure.
|
||||
.Pp
|
||||
.Fn ftpGetModtime
|
||||
returns the last modification time of the file named by the
|
||||
.Fa file
|
||||
argument. If the file could not be opened or stat'd, 0 is returned.
|
||||
.Pp
|
||||
.Fn ftpGetSize
|
||||
returns the size in bytes of the file named by the
|
||||
.Fa file
|
||||
argument. If the file could not be opened or stat'd, -1 is returned.
|
||||
.Pp
|
||||
.Fn ftpPut
|
||||
attempts to create a new file named by the
|
||||
.Fa file
|
||||
argument (which is assumed to be relative to the FTP server's current directory,
|
||||
see
|
||||
.Fn ftpChdir )
|
||||
and returns a new
|
||||
.Fa stream
|
||||
pointer for the file or NULL on failure.
|
||||
.Pp
|
||||
.Fn ftpBinary
|
||||
sets binary mode for the current server connection named by
|
||||
.Fa stream
|
||||
to boolean value
|
||||
.Fa status .
|
||||
.Pp
|
||||
.Fn ftpPassive
|
||||
sets passive mode (for firewalls) for the current server connection named by
|
||||
.Fa stream
|
||||
to boolean value
|
||||
.Fa status .
|
||||
.Pp
|
||||
.Fn ftpRestart
|
||||
requests that if the remote server supports restart operations, the offset
|
||||
in bytes specified in
|
||||
.Fa where
|
||||
should be used in the next file get operation to resume transferring from
|
||||
that location. This is handy for restarting long get operations which have
|
||||
aborted in the middle without re-transferring wasted bytes. Returns the
|
||||
old seek value, if any.
|
||||
.Pp
|
||||
.Fn ftpGetURL
|
||||
attempts to retreive the file named by the supplied
|
||||
.Fa URL
|
||||
and can be considered equivalent to the combined
|
||||
.Fn ftpLogin ,
|
||||
.Fn ftpChdir
|
||||
and
|
||||
.Fn ftpGet
|
||||
operations except that no server
|
||||
.Fa stream
|
||||
is ever returned - the connection to the server closes when
|
||||
the file has been completely read. Use the lower-level routines
|
||||
if multiple gets are required as it will be far more efficient.
|
||||
.Pp
|
||||
.Fn ftpPutURL
|
||||
attempts to create the file named by the supplied
|
||||
.Fa URL
|
||||
and can be considered equivalent to the combined
|
||||
.Fn ftpLogin ,
|
||||
.Fn ftpChdir
|
||||
and
|
||||
.Fn ftpPut
|
||||
operations except that no server
|
||||
.Fa stream
|
||||
is ever returned - the connection to the server closes when
|
||||
the file has been completely written. Use the lower-level routines
|
||||
if multiple puts are required as it will be far more efficient.
|
||||
.Sh BUGS
|
||||
I'm sure you can get this thing's internal state machine confused if
|
||||
you really work at it, but so far it's proven itself pretty robust in
|
||||
all my tests.
|
||||
.Sh HISTORY
|
||||
Started life as Poul-Henning Kamp's ftp driver for the system installation
|
||||
utility, later significantly mutated into a more general form as an
|
||||
extension of stdio and given a TCL interface (not enabled by default)
|
||||
by Jordan Hubbard. Also incorporates some ideas and extensions from
|
||||
Jean-Marc Zucconi.
|
686
lib/libftpio/ftpio.c
Normal file
686
lib/libftpio/ftpio.c
Normal file
@ -0,0 +1,686 @@
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Major Changelog:
|
||||
*
|
||||
* Jordan K. Hubbard
|
||||
* 17 Jan 1996
|
||||
*
|
||||
* Turned inside out. Now returns xfers as new file ids, not as a special
|
||||
* `state' of FTP_t
|
||||
*
|
||||
* $Id: ftp.c,v 1.14 1995/06/11 19:29:55 rgrimes Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ftpio.h>
|
||||
|
||||
#define SUCCESS 0
|
||||
#define FAILURE -1
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (1)
|
||||
#define FALSE (0)
|
||||
#endif
|
||||
|
||||
/* How to see by a given code whether or not the connection has timed out */
|
||||
#define FTP_TIMEOUT(code) (code == 421)
|
||||
|
||||
/* Internal routines - deal only with internal FTP_t type */
|
||||
static FTP_t ftp_new(void);
|
||||
static int ftp_read_method(void *n, char *buf, int nbytes);
|
||||
static int ftp_write_method(void *n, const char *buf, int nbytes);
|
||||
static int ftp_close_method(void *n);
|
||||
static int writes(int fd, char *s);
|
||||
static __inline char *get_a_line(FTP_t ftp);
|
||||
static int get_a_number(FTP_t ftp, char **q);
|
||||
static int botch(char *func, char *botch_state);
|
||||
static int cmd(FTP_t ftp, const char *fmt, ...);
|
||||
static int ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port);
|
||||
static int ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode);
|
||||
static int ftp_close(FTP_t ftp);
|
||||
static int get_url_info(char *url_in, char *host_ret, int *port_ret, char *name_ret);
|
||||
|
||||
/* Global status variable - ick */
|
||||
int FtpTimedOut;
|
||||
|
||||
/* FTP status codes */
|
||||
#define FTP_BINARY_HAPPY 200
|
||||
#define FTP_PORT_HAPPY 200
|
||||
#define FTP_QUIT_HAPPY 221
|
||||
#define FTP_TRANSFER_HAPPY 226
|
||||
#define FTP_PASSIVE_HAPPY 227
|
||||
#define FTP_CHDIR_HAPPY 250
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* gross! evil! bad! We really need an access primitive for cookie in stdio itself.
|
||||
* it's too convenient a hook to bury and it's already exported through funopen as it is, so...
|
||||
* XXX
|
||||
*/
|
||||
#define fcookie(fp) ((fp)->_cookie)
|
||||
|
||||
/* Placeholder in case we want to do any pre-init stuff at some point */
|
||||
int
|
||||
networkInit()
|
||||
{
|
||||
return SUCCESS; /* XXX dummy function for now XXX */
|
||||
}
|
||||
|
||||
/* Check a return code with some lenience for back-dated garbage that might be in the buffer */
|
||||
static int
|
||||
check_code(FTP_t ftp, int var, int preferred)
|
||||
{
|
||||
ftp->errno = 0;
|
||||
while (1) {
|
||||
if (var == preferred)
|
||||
return 0;
|
||||
else if (var == 226) /* last operation succeeded */
|
||||
var = get_a_number(ftp, NULL);
|
||||
else if (var == 220) /* chit-chat */
|
||||
var = get_a_number(ftp, NULL);
|
||||
else if (var == 200) /* success codes */
|
||||
var = get_a_number(ftp, NULL);
|
||||
else {
|
||||
ftp->errno = var;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns a standard FILE pointer type representing an open control connection */
|
||||
FILE *
|
||||
ftpLogin(char *host, char *user, char *passwd, int port)
|
||||
{
|
||||
FTP_t n;
|
||||
FILE *fp;
|
||||
|
||||
if (networkInit() != SUCCESS)
|
||||
return NULL;
|
||||
|
||||
n = ftp_new();
|
||||
fp = NULL;
|
||||
if (n && ftp_login_session(n, host, user, passwd, port) == SUCCESS) {
|
||||
fp = funopen(n, ftp_read_method, ftp_write_method, NULL, ftp_close_method); /* BSD 4.4 function! */
|
||||
/* Yuck, but can't use fdopen() because that also allocates an fp. Sigh! */
|
||||
fp->_file = n->fd_ctrl;
|
||||
}
|
||||
if (n && !fp)
|
||||
free(n);
|
||||
return fp;
|
||||
}
|
||||
|
||||
int
|
||||
ftpChdir(FILE *fp, char *dir)
|
||||
{
|
||||
int i;
|
||||
FTP_t ftp = fcookie(fp);
|
||||
|
||||
i = cmd(ftp, "CWD %s", dir);
|
||||
if (i < 0 || check_code(ftp, i, FTP_CHDIR_HAPPY))
|
||||
return -1;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
ftpErrno(FILE *fp)
|
||||
{
|
||||
FTP_t ftp = fcookie(fp);
|
||||
return ftp->errno;
|
||||
}
|
||||
|
||||
int
|
||||
ftpRestart(FILE *fp, int where)
|
||||
{
|
||||
FTP_t ftp = fcookie(fp);
|
||||
int old = ftp->seek;
|
||||
|
||||
ftp->seek = where;
|
||||
return old;
|
||||
}
|
||||
|
||||
size_t
|
||||
ftpGetSize(FILE *fp, char *name)
|
||||
{
|
||||
int i;
|
||||
char p[BUFSIZ], *cp;
|
||||
FTP_t ftp = fcookie(fp);
|
||||
|
||||
sprintf(p, "SIZE %s\r\n", name);
|
||||
i = writes(ftp->fd_ctrl, p);
|
||||
if (i)
|
||||
return (size_t)-1;
|
||||
i = get_a_number(ftp, &cp);
|
||||
if (check_code(ftp, i, 213))
|
||||
return (size_t)-1;
|
||||
return (size_t)atoi(cp);
|
||||
}
|
||||
|
||||
time_t
|
||||
ftpGetModtime(FILE *fp, char *name)
|
||||
{
|
||||
char p[BUFSIZ], *cp;
|
||||
struct tm t;
|
||||
time_t t0 = time (0);
|
||||
FTP_t ftp = fcookie(fp);
|
||||
int i;
|
||||
|
||||
sprintf(p, "MDTM %s\r\n", name);
|
||||
i = writes(ftp->fd_ctrl, p);
|
||||
if (i)
|
||||
return (time_t)0;
|
||||
i = get_a_number(ftp, &cp);
|
||||
if (check_code(ftp, i, 213))
|
||||
return (time_t)0;
|
||||
while (*cp && !isdigit(*cp))
|
||||
cp++;
|
||||
if (!*cp)
|
||||
return (time_t)0;
|
||||
t0 = localtime (&t0)->tm_gmtoff;
|
||||
sscanf(cp, "%04d%02d%02d%02d%02d%02d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec);
|
||||
t.tm_mon--;
|
||||
t.tm_year -= 1900;
|
||||
t.tm_isdst=-1;
|
||||
t.tm_gmtoff = 0;
|
||||
t0 += mktime (&t);
|
||||
return t0;
|
||||
}
|
||||
|
||||
FILE *
|
||||
ftpGet(FILE *fp, char *file)
|
||||
{
|
||||
FILE *fp2;
|
||||
FTP_t ftp = fcookie(fp);
|
||||
|
||||
if (ftp_file_op(ftp, "RETR", file, &fp2, "r") == SUCCESS)
|
||||
return fp2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FILE *
|
||||
ftpPut(FILE *fp, char *file)
|
||||
{
|
||||
FILE *fp2;
|
||||
FTP_t ftp = fcookie(fp);
|
||||
|
||||
if (ftp_file_op(ftp, "STOR", file, &fp2, "w") == SUCCESS)
|
||||
return fp2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
ftpBinary(FILE *fp, int st)
|
||||
{
|
||||
FTP_t ftp = fcookie(fp);
|
||||
|
||||
ftp->binary = st;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
ftpPassive(FILE *fp, int st)
|
||||
{
|
||||
FTP_t ftp = fcookie(fp);
|
||||
|
||||
ftp->passive = st;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
FILE *
|
||||
ftpGetURL(char *url, char *user, char *passwd)
|
||||
{
|
||||
char host[255], name[255];
|
||||
int port;
|
||||
FILE *fp, *fp2;
|
||||
|
||||
if (get_url_info(url, host, &port, name) == SUCCESS) {
|
||||
fp = ftpLogin(host, user, passwd, port);
|
||||
if (fp) {
|
||||
fp2 = ftpGet(fp, name);
|
||||
fclose(fp);
|
||||
return fp2;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FILE *
|
||||
ftpPutURL(char *url, char *user, char *passwd)
|
||||
{
|
||||
char host[255], name[255];
|
||||
int port;
|
||||
FILE *fp, *fp2;
|
||||
|
||||
if (get_url_info(url, host, &port, name) == SUCCESS) {
|
||||
fp = ftpLogin(host, user, passwd, port);
|
||||
if (fp) {
|
||||
fp2 = ftpPut(fp, name);
|
||||
fclose(fp);
|
||||
return fp2;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Internal workhorse function for dissecting URLs. Takes a URL as the first argument and returns the
|
||||
result of such disection in the host, user, passwd, port and name variables. */
|
||||
static int
|
||||
get_url_info(char *url_in, char *host_ret, int *port_ret, char *name_ret)
|
||||
{
|
||||
char *name, *host, *cp, url[BUFSIZ];
|
||||
int port;
|
||||
|
||||
name = host = NULL;
|
||||
/* XXX add http:// here or somewhere reasonable at some point XXX */
|
||||
if (strncmp("ftp://", url_in, 6) != NULL)
|
||||
return FAILURE;
|
||||
/* We like to stomp a lot on the URL string in dissecting it, so copy it first */
|
||||
strncpy(url, url_in, BUFSIZ);
|
||||
host = url + 6;
|
||||
if ((cp = index(host, ':')) != NULL) {
|
||||
*(cp++) = '\0';
|
||||
port = strtol(cp, 0, 0);
|
||||
}
|
||||
else
|
||||
port = 0; /* use default */
|
||||
if (port_ret)
|
||||
*port_ret = port;
|
||||
|
||||
if ((name = index(cp ? cp : host, '/')) != NULL)
|
||||
*(name++) = '\0';
|
||||
if (host_ret)
|
||||
strcpy(host_ret, host);
|
||||
if (name && name_ret)
|
||||
strcpy(name_ret, name);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static FTP_t
|
||||
ftp_new(void)
|
||||
{
|
||||
FTP_t ftp;
|
||||
|
||||
ftp = (FTP_t)malloc(sizeof *ftp);
|
||||
if (!ftp)
|
||||
return NULL;
|
||||
memset(ftp, 0, sizeof *ftp);
|
||||
ftp->fd_ctrl = -1;
|
||||
ftp->con_state = init;
|
||||
ftp->errno = 0;
|
||||
ftp->seek = 0;
|
||||
return ftp;
|
||||
}
|
||||
|
||||
static int
|
||||
ftp_read_method(void *vp, char *buf, int nbytes)
|
||||
{
|
||||
int i, fd;
|
||||
FTP_t n = (FTP_t)vp;
|
||||
|
||||
fd = n->fd_ctrl;
|
||||
i = (fd >= 0) ? read(fd, buf, nbytes) : EOF;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
ftp_write_method(void *vp, const char *buf, int nbytes)
|
||||
{
|
||||
int i, fd;
|
||||
FTP_t n = (FTP_t)vp;
|
||||
|
||||
fd = n->fd_ctrl;
|
||||
i = (fd >= 0) ? write(fd, buf, nbytes) : EOF;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
ftp_close_method(void *n)
|
||||
{
|
||||
return ftp_close((FTP_t)n);
|
||||
}
|
||||
|
||||
static void
|
||||
ftp_timeout()
|
||||
{
|
||||
FtpTimedOut = TRUE;
|
||||
/* Debug("ftp_pkg: ftp_timeout called - operation timed out"); */
|
||||
}
|
||||
|
||||
static int
|
||||
writes(int fd, char *s)
|
||||
{
|
||||
int n, i = strlen(s);
|
||||
|
||||
/* Set the timer */
|
||||
FtpTimedOut = FALSE;
|
||||
signal(SIGALRM, ftp_timeout);
|
||||
alarm(120);
|
||||
/* Debug("ftp_pkg: writing \"%s\" to ftp connection %d", s, fd); */
|
||||
n = write(fd, s, i);
|
||||
alarm(0);
|
||||
if (i != n)
|
||||
return FAILURE;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static __inline char *
|
||||
get_a_line(FTP_t ftp)
|
||||
{
|
||||
static char buf[BUFSIZ];
|
||||
int i,j;
|
||||
|
||||
/* Set the timer */
|
||||
FtpTimedOut = FALSE;
|
||||
signal(SIGALRM, ftp_timeout);
|
||||
|
||||
/* Debug("ftp_pkg: trying to read a line from %d", ftp->fd_ctrl); */
|
||||
for(i = 0; i < BUFSIZ;) {
|
||||
alarm(120);
|
||||
j = read(ftp->fd_ctrl, buf + i, 1);
|
||||
alarm(0);
|
||||
if (j != 1)
|
||||
return NULL;
|
||||
if (buf[i] == '\r' || buf[i] == '\n') {
|
||||
if (!i)
|
||||
continue;
|
||||
buf[i] = '\0';
|
||||
return buf;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
/* Debug("ftp_pkg: read string \"%s\" from %d", buf, ftp->fd_ctrl); */
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int
|
||||
get_a_number(FTP_t ftp, char **q)
|
||||
{
|
||||
char *p;
|
||||
int i = -1, j;
|
||||
|
||||
while(1) {
|
||||
p = get_a_line(ftp);
|
||||
if (!p)
|
||||
return FAILURE;
|
||||
if (!(isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2])))
|
||||
continue;
|
||||
if (i == -1 && p[3] == '-') {
|
||||
i = strtol(p, 0, 0);
|
||||
continue;
|
||||
}
|
||||
if (p[3] != ' ' && p[3] != '\t')
|
||||
continue;
|
||||
j = strtol(p, 0, 0);
|
||||
if (i == -1) {
|
||||
if (q) *q = p+4;
|
||||
/* Debug("ftp_pkg: read reply %d from server (%s)", j, p); */
|
||||
return j;
|
||||
} else if (j == i) {
|
||||
if (q) *q = p+4;
|
||||
/* Debug("ftp_pkg: read reply %d from server (%s)", j, p); */
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ftp_close(FTP_t ftp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ftp->con_state == isopen) {
|
||||
/* Debug("ftp_pkg: in ftp_close(), sending QUIT"); */
|
||||
i = cmd(ftp, "QUIT");
|
||||
close(ftp->fd_ctrl);
|
||||
ftp->fd_ctrl = -1;
|
||||
ftp->con_state = init;
|
||||
if (check_code(ftp, i, FTP_QUIT_HAPPY)) {
|
||||
ftp->errno = i;
|
||||
return FAILURE;
|
||||
}
|
||||
/* Debug("ftp_pkg: ftp_close() - proper shutdown"); */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* Debug("ftp_pkg: ftp_close() - improper shutdown"); */
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
botch(char *func, char *botch_state)
|
||||
{
|
||||
/* Debug("ftp_pkg: botch: %s(%s)", func, botch_state); */
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd(FTP_t ftp, const char *fmt, ...)
|
||||
{
|
||||
char p[BUFSIZ];
|
||||
int i;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
(void)vsnprintf(p, sizeof p, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (ftp->con_state != isopen)
|
||||
return botch("cmd", "open");
|
||||
|
||||
strcat(p, "\r\n");
|
||||
i = writes(ftp->fd_ctrl, p);
|
||||
if (i)
|
||||
return FAILURE;
|
||||
while ((i = get_a_number(ftp, NULL)) == 220);
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port)
|
||||
{
|
||||
struct hostent *he = NULL;
|
||||
struct sockaddr_in sin;
|
||||
int s;
|
||||
unsigned long temp;
|
||||
int i;
|
||||
|
||||
if (networkInit() != SUCCESS)
|
||||
return FAILURE;
|
||||
|
||||
if (ftp->con_state != init)
|
||||
ftp_close(ftp);
|
||||
|
||||
if (!user)
|
||||
user = "ftp";
|
||||
|
||||
if (!passwd)
|
||||
passwd = "setup@";
|
||||
|
||||
if (!port)
|
||||
port = 21;
|
||||
|
||||
temp = inet_addr(host);
|
||||
if (temp != INADDR_NONE) {
|
||||
ftp->addrtype = sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = temp;
|
||||
}
|
||||
else {
|
||||
he = gethostbyname(host);
|
||||
if (!he)
|
||||
return FAILURE;
|
||||
ftp->addrtype = sin.sin_family = he->h_addrtype;
|
||||
bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
|
||||
}
|
||||
|
||||
sin.sin_port = htons(port);
|
||||
|
||||
if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0)
|
||||
return FAILURE;
|
||||
|
||||
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
||||
(void)close(s);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
ftp->fd_ctrl = s;
|
||||
ftp->con_state = isopen;
|
||||
|
||||
i = cmd(ftp, "USER %s", user);
|
||||
if (i >= 300 && i < 400)
|
||||
i = cmd(ftp, "PASS %s", passwd);
|
||||
if (i >= 299 || i < 0) {
|
||||
ftp_close(ftp);
|
||||
return FAILURE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode)
|
||||
{
|
||||
int i,s;
|
||||
char *q;
|
||||
unsigned char addr[64];
|
||||
struct sockaddr_in sin;
|
||||
u_long a;
|
||||
|
||||
if (!fp)
|
||||
return FAILURE;
|
||||
*fp = NULL;
|
||||
|
||||
if (ftp->con_state != isopen)
|
||||
return botch("ftp_file_op", "open");
|
||||
|
||||
if (ftp->binary) {
|
||||
i = cmd(ftp, "TYPE I");
|
||||
if (check_code(ftp, i, FTP_BINARY_HAPPY)) {
|
||||
ftp_close(ftp);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0)
|
||||
return FAILURE;
|
||||
|
||||
if (ftp->passive) {
|
||||
if (writes(ftp->fd_ctrl, "PASV\r\n")) {
|
||||
ftp_close(ftp);
|
||||
return FAILURE;
|
||||
}
|
||||
i = get_a_number(ftp, &q);
|
||||
if (check_code(ftp, i, FTP_PASSIVE_HAPPY))
|
||||
return i;
|
||||
while (*q && !isdigit(*q))
|
||||
q++;
|
||||
if (!*q) {
|
||||
ftp_close(ftp);
|
||||
return FAILURE;
|
||||
}
|
||||
q--;
|
||||
for (i = 0; i < 6; i++) {
|
||||
q++;
|
||||
addr[i] = strtol(q, &q, 10);
|
||||
}
|
||||
|
||||
sin.sin_family = ftp->addrtype;
|
||||
bcopy(addr, (char *)&sin.sin_addr, 4);
|
||||
bcopy(addr + 4, (char *)&sin.sin_port, 2);
|
||||
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
||||
(void)close(s);
|
||||
return FAILURE;
|
||||
}
|
||||
if (!strcmp(operation, "RETR") && ftp->seek) {
|
||||
i = cmd(ftp, "RETR %d", ftp->seek);
|
||||
if (i < 0 || FTP_TIMEOUT(i)) {
|
||||
close(s);
|
||||
ftp->errno = i;
|
||||
return i;
|
||||
}
|
||||
else if (i != 350)
|
||||
ftp->seek = 0;
|
||||
}
|
||||
i = cmd(ftp, "%s %s", operation, file);
|
||||
if (i < 0 || i > 299) {
|
||||
close(s);
|
||||
ftp->errno = i;
|
||||
return i;
|
||||
}
|
||||
*fp = fdopen(s, mode);
|
||||
}
|
||||
else {
|
||||
int fd;
|
||||
|
||||
i = sizeof sin;
|
||||
getsockname(ftp->fd_ctrl, (struct sockaddr *)&sin, &i);
|
||||
sin.sin_port = 0;
|
||||
i = sizeof sin;
|
||||
if (bind(s, (struct sockaddr *)&sin, i) < 0) {
|
||||
close (s);
|
||||
return FAILURE;
|
||||
}
|
||||
getsockname(s,(struct sockaddr *)&sin,&i);
|
||||
if (listen(s, 1) < 0) {
|
||||
close(s);
|
||||
return FAILURE;
|
||||
}
|
||||
a = ntohl(sin.sin_addr.s_addr);
|
||||
i = cmd(ftp, "PORT %d,%d,%d,%d,%d,%d",
|
||||
(a >> 24) & 0xff,
|
||||
(a >> 16) & 0xff,
|
||||
(a >> 8) & 0xff,
|
||||
a & 0xff,
|
||||
(ntohs(sin.sin_port) >> 8) & 0xff,
|
||||
ntohs(sin.sin_port) & 0xff);
|
||||
if (check_code(ftp, i, FTP_PORT_HAPPY)) {
|
||||
close(s);
|
||||
return i;
|
||||
}
|
||||
if (!strcmp(operation, "RETR") && ftp->seek) {
|
||||
i = cmd(ftp, "RETR %d", ftp->seek);
|
||||
if (i < 0 || FTP_TIMEOUT(i)) {
|
||||
close(s);
|
||||
ftp->errno = i;
|
||||
return i;
|
||||
}
|
||||
else if (i != 350)
|
||||
ftp->seek = 0;
|
||||
}
|
||||
i = cmd(ftp, "%s %s", operation, file);
|
||||
if (i < 0 || i > 299) {
|
||||
close(s);
|
||||
ftp->errno = i;
|
||||
return FAILURE;
|
||||
}
|
||||
fd = accept(s, 0, 0);
|
||||
if (fd < 0) {
|
||||
close(s);
|
||||
ftp->errno = 401;
|
||||
return FAILURE;
|
||||
}
|
||||
close(s);
|
||||
*fp = fdopen(fd, mode);
|
||||
}
|
||||
if (*fp)
|
||||
return SUCCESS;
|
||||
else
|
||||
return FAILURE;
|
||||
}
|
53
lib/libftpio/ftpio.h
Normal file
53
lib/libftpio/ftpio.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef _FTP_H_INCLUDE
|
||||
#define _FTP_H_INCLUDE
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Major Changelog:
|
||||
*
|
||||
* Jordan K. Hubbard
|
||||
* 17 Jan 1996
|
||||
*
|
||||
* Turned inside out. Now returns xfers as new file ids, not as a special
|
||||
* `state' of FTP_t
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* Internal housekeeping data structure for FTP sessions */
|
||||
typedef struct {
|
||||
enum { init, isopen } con_state;
|
||||
int fd_ctrl;
|
||||
int binary;
|
||||
int passive;
|
||||
int addrtype;
|
||||
char *host;
|
||||
char *file;
|
||||
int errno;
|
||||
int seek;
|
||||
} *FTP_t;
|
||||
|
||||
/* Exported routines - deal only with FILE* type */
|
||||
extern FILE *ftpLogin(char *host, char *user, char *passwd, int port);
|
||||
extern int ftpChdir(FILE *fp, char *dir);
|
||||
extern int ftpErrno(FILE *fp);
|
||||
extern size_t ftpGetSize(FILE *fp, char *file);
|
||||
extern FILE *ftpGet(FILE *fp, char *file);
|
||||
extern FILE *ftpPut(FILE *fp, char *file);
|
||||
extern int ftpBinary(FILE *fp, int status);
|
||||
extern int ftpPassive(FILE *fp, int status);
|
||||
extern int ftpRestart(FILE *fp, int where);
|
||||
extern FILE *ftpGetURL(char *url, char *user, char *passwd);
|
||||
extern FILE *ftpPutURL(char *url, char *user, char *passwd);
|
||||
extern time_t ftpModtime(FILE *fp, char *s);
|
||||
|
||||
#endif /* _FTP_H_INCLUDE */
|
Loading…
x
Reference in New Issue
Block a user