Logo Search packages:      
Sourcecode: fdclone version File versions  Download package

ftp.c

/*
 *    ftp.c
 *
 *    FTP accesing in RFC959
 */

#include "headers.h"
#include "depend.h"
#include "printf.h"
#include "kctype.h"
#include "string.h"
#include "malloc.h"
#include "time.h"
#include "sysemu.h"
#include "pathname.h"
#include "termio.h"
#include "parse.h"
#include "lsparse.h"
#include "socket.h"
#include "auth.h"
#include "urldisk.h"

#if   !MSDOS
#include <arpa/ftp.h>
#endif

#define     FTP_QUIT          0
#define     FTP_USER          1
#define     FTP_PASS          2
#define     FTP_CWD                 3
#define     FTP_PWD                 4
#define     FTP_TYPE          5
#define     FTP_LIST          6
#define     FTP_NLST          7
#define     FTP_PORT          8
#define     FTP_PASV          9
#define     FTP_MDTM          10
#define     FTP_CHMOD         11
#define     FTP_DELE          12
#define     FTP_RNFR          13
#define     FTP_RNTO          14
#define     FTP_RETR          15
#define     FTP_STOR          16
#define     FTP_MKD                 17
#define     FTP_RMD                 18
#define     FTP_FEAT          19
#define     FTP_ABOR          20
#define     FTP_ASCII         "A"
#define     FTP_IMAGE         "I"

#ifndef     PRELIM
#define     PRELIM                  1
#endif
#ifndef     COMPLETE
#define     COMPLETE          2
#endif
#ifndef     CONTINUE
#define     CONTINUE          3
#endif
#ifndef     TRANSIENT
#define     TRANSIENT         4
#endif
#ifndef     ERROR
#define     ERROR             5
#endif

typedef struct _ftpcmd_t {
      int id;
      CONST char *cmd[2];
      int argc;
      int flags;
} ftpcmd_t;

#define     FFL_INT                 0001
#define     FFL_COMMA         0002
#define     FFL_LIST          0004

#ifdef      DEP_FTPPATH

static VOID NEAR vftplog __P_((CONST char *, va_list));
static VOID NEAR ftplog __P_((CONST char *, ...));
static char *NEAR ftprecv __P_((XFILE *));
static int NEAR vftpsend __P_((XFILE *, int, CONST char *, va_list));
static int NEAR ftppasv __P_((int));
static int NEAR ftpdata __P_((int));
static int NEAR sendrequest __P_((int, int, CONST char *));
static int NEAR ftpopenport __P_((int, int, CONST char *, CONST char *));
static char *ftpfgets __P_((VOID_P));
static int NEAR _ftprecvlist __P_((int, CONST char *, namelist **));
static int NEAR recvpwd __P_((int, char *, ALLOC_T));
static int NEAR ftpfeat __P_((int));
static int NEAR ftpmdtm __P_((int, CONST char *, namelist *, int, int));

char *ftpaddress = NULL;
char *ftpproxy = NULL;
char *ftplogfile = NULL;

static char *form_ftp[] = {
      "%a %l %u %g %s %m %d %{yt} %*f",
      "%a %l %u %g %B, %b %m %d %{yt} %*f",
      "%a %l %u %s %m %d %{yt} %*f",
      "%a %l %u %B, %b %m %d %{yt} %*f",
      "%m-%d-%y %t %{s/<DIR>/} %*f",
      "%s %/DIR/ %m-%d-%y %t %*f",
      "%s %m-%d-%y %t %*f",
      NULL
};
static char *ign_ftp[] = {
      "total *",
      NULL
};
static CONST lsparse_t ftpformat = {
      NULL, NULL, form_ftp, ign_ftp, NULL, 0, 0, LF_NOTRAVERSE
};
static CONST ftpcmd_t ftpcmdlist[] = {
      {FTP_QUIT, {"QUIT", NULL}, 0, 0},
      {FTP_USER, {"USER", NULL}, 1, 0},
      {FTP_PASS, {"PASS", NULL}, 1, 0},
      {FTP_CWD, {"CWD", "XCWD"}, 1, 0},
      {FTP_PWD, {"PWD", "XPWD"}, 0, 0},
      {FTP_TYPE, {"TYPE", NULL}, 1, 0},
      {FTP_LIST, {"LIST -la", "LIST"}, 1, FFL_LIST},
      {FTP_NLST, {"NLST -la", "NLST"}, 1, FFL_LIST},
      {FTP_PORT, {"PORT", NULL}, 6, FFL_INT | FFL_COMMA},
      {FTP_PASV, {"PASV", NULL}, 0, 0},
      {FTP_MDTM, {"MDTM", NULL}, 1, 0},
      {FTP_CHMOD, {"SITE CHMOD", NULL}, 2, 0},
      {FTP_DELE, {"DELE", NULL}, 1, 0},
      {FTP_RNFR, {"RNFR", NULL}, 1, 0},
      {FTP_RNTO, {"RNTO", NULL}, 1, 0},
      {FTP_RETR, {"RETR", NULL}, 1, 0},
      {FTP_STOR, {"STOR", NULL}, 1, 0},
      {FTP_MKD, {"MKD", "XMKD"}, 1, 0},
      {FTP_RMD, {"RMD", "XRMD"}, 1, 0},
      {FTP_FEAT, {"FEAT", NULL}, 0, 0},
      {FTP_ABOR, {"ABOR", NULL}, 0, 0},
};
#define     FTPCMDLISTSIZ           arraysize(ftpcmdlist)


static VOID NEAR vftplog(fmt, args)
CONST char *fmt;
va_list args;
{
      XFILE *fp;

      if (!ftplogfile || !isrootdir(ftplogfile)) return;
      if (!(fp = Xfopen(ftplogfile, "a"))) return;
      if (logheader) {
            Xfputs(logheader, fp);
            free2(logheader);
            logheader = NULL;
      }
      VOID_C vfprintf2(fp, fmt, args);
      Xfclose(fp);
}

#ifdef      USESTDARGH
/*VARARGS1*/
static VOID NEAR ftplog(CONST char *fmt, ...)
#else
/*VARARGS1*/
static VOID NEAR ftplog(fmt, va_alist)
CONST char *fmt;
va_dcl
#endif
{
      va_list args;

      VA_START(args, fmt);
      vftplog(fmt, args);
      va_end(args);
}

static char *NEAR ftprecv(fp)
XFILE *fp;
{
      char *buf;

      buf = Xfgets(fp);
      if (!buf) return(NULL);
      ftplog("<-- \"%s\"\n", buf);

      return(buf);
}

static int NEAR vftpsend(fp, cmd, fmt, args)
XFILE *fp;
int cmd;
CONST char *fmt;
va_list args;
{
      u_char oob[3];
      char buf[URLMAXCMDLINE + 1];
      int n;

      n = snprintf2(buf, sizeof(buf), "--> \"%s\"\n", fmt);
      if (n < 0) /*EMPTY*/;
      else if (cmd == FTP_PASS) ftplog(buf, "????");
      else vftplog(buf, args);

      if (cmd == FTP_ABOR) {
            oob[0] = TELNET_IAC;
            oob[1] = TELNET_IP;
            oob[2] = TELNET_IAC;
            n = socksendoob(Xfileno(fp), oob, sizeof(oob));
            if (n >= 0) VOID_C Xfputc(TELNET_DM, fp);
      }

      n = vfprintf2(fp, fmt, args);
      if (n >= 0) n = fputnl(fp);

      return(n);
}

int ftpgetreply(fp, sp)
XFILE *fp;
char **sp;
{
      char *cp, *buf;
      ALLOC_T len, size;
      int i, n, code;

      if (!(buf = ftprecv(fp))) return(-1);
      for (i = n = 0; i < 3; i++) {
            if (!isdigit2(buf[i])) break;
            n *= 10;
            n += buf[i] - '0';
      }
      code = n;

      if (i < 3) {
            free2(buf);
            return(seterrno(EINVAL));
      }
      if (buf[3] == '-') {
            size = strlen(buf);
            for (;;) {
                  if (!(cp = ftprecv(fp))) {
                        free2(buf);
                        return(-1);
                  }
                  for (i = n = 0; i < 3; i++) {
                        if (!isdigit2(cp[i])) break;
                        n *= 10;
                        n += cp[i] - '0';
                  }
                  if (i < 3 || cp[3] != ' ') n = -1;

                  len = strlen(cp);
                  buf = realloc2(buf, size + 1 + len + 1);
                  buf[size++] = '\n';
                  memcpy(&(buf[size]), cp, len + 1);
                  size += len;
                  free2(cp);
                  if (n == code) break;
            }
      }
      if (sp) *sp = buf;
      else free2(buf);

      return(code);
}

int ftpseterrno(n)
int n;
{
      if (n < 0) return(-1);
      if (n / 100 != COMPLETE) return(seterrno(EACCES));

      return(0);
}

int vftpcommand(uh, sp, cmd, args)
int uh;
char **sp;
int cmd;
va_list args;
{
      char *cp, buf[URLMAXCMDLINE + 1];
      ALLOC_T size;
      int i, j, n, c, delim;

      if (sp) *sp = NULL;
      if (cmd < 0 || cmd >= FTPCMDLISTSIZ) return(seterrno(EINVAL));

      n = 0;
      for (i = 0; i < 2; i++) {
            if (!(ftpcmdlist[cmd].cmd[i])) break;
            if (i || !(ftpcmdlist[cmd].flags & FFL_LIST)) /*EMPTY*/;
            else if (urlhostlist[uh].options & UOP_NOLISTOPT) continue;

            /* Some FTP proxy cannot allow option arguments */
            if (urlhostlist[uh].flags & UFL_PROXIED) {
                  cp = strchr2(ftpcmdlist[cmd].cmd[i], ' ');
                  if (cp && *skipspace(++cp) == '-') continue;
            }

            cp = buf;
            size = sizeof(buf);
            n = snprintf2(cp, size, "%s", ftpcmdlist[cmd].cmd[i]);
            if (n < 0) break;

            delim = ' ';
            c = (ftpcmdlist[cmd].flags & FFL_INT) ? 'd' : 's';
            for (j = 0; j < ftpcmdlist[cmd].argc; j++) {
                  cp += n;
                  size -= n;
                  n = snprintf2(cp, size, "%c%%%c", delim, c);
                  if (n < 0) break;
                  if (ftpcmdlist[cmd].flags & FFL_COMMA) delim = ',';
            }
            if (n < 0) break;
            n = vftpsend(urlhostlist[uh].fp, cmd, buf, args);
            if (n < 0) break;

            if (cmd == FTP_QUIT)
                  Xsettimeout(urlhostlist[uh].fp, URLENDTIMEOUT);
            n = urlgetreply(uh, sp);
            Xsettimeout(urlhostlist[uh].fp, urltimeout);
            if (n == 500) continue;
            if (n != 421 || cmd == FTP_USER || cmd == FTP_PASS) break;

            if (urlreconnect(uh) < 0) break;
            if (ftplogin(uh) < 0) {
                  safefclose(urlhostlist[uh].fp);
                  urlhostlist[uh].fp = NULL;
                  break;
            }
            i--;
      }

      return(n);
}

int ftpquit(uh)
int uh;
{
      if (urlhostlist[uh].flags & UFL_LOCKED) return(0);

      return(urlcommand(uh, NULL, FTP_QUIT));
}

int ftpabort(uh)
int uh;
{
      return(urlcommand(uh, NULL, FTP_ABOR));
}

int ftplogin(uh)
int uh;
{
      CONST char *pass;
      char buf[URLMAXCMDLINE + 1];
      int n, anon, flags;

      flags = (UGP_USER | UGP_ANON);
      if (urlhostlist[uh].flags & UFL_PROXIED) {
            flags |= UGP_HOST;
            urlhostlist[uh].options |= UOP_NOFEAT;
      }
      if (urlgenpath(uh, buf, sizeof(buf), flags) < 0) return(-1);

      n = urlcommand(uh, NULL, FTP_USER, buf);
      if (n / 100 == CONTINUE) {
            anon = 0;
            if ((pass = urlhostlist[uh].host.pass)) /*EMPTY*/;
            else if (urlhostlist[uh].host.user) pass = nullstr;
            else {
                  anon++;
                  pass = (ftpaddress && *ftpaddress)
                        ? ftpaddress : FTPANONPASS;
            }

            n = urlcommand(uh, NULL, FTP_PASS, pass);
            if (n == 530) {
                  if (anon) fprintf2(Xstderr,
                        "%s: Invalid address.\r\n", pass);
                  else fprintf2(Xstderr,
                        "%s: Login incorrect.\r\n", buf);
                  free2(urlhostlist[uh].host.pass);
                  urlhostlist[uh].host.pass = NULL;
            }
      }
      if (ftpseterrno(n) < 0) return(-1);
      authentry(&(urlhostlist[uh].host), urlhostlist[uh].type);
      VOID_C ftpfeat(uh);

      return(0);
}

static int NEAR ftppasv(uh)
int uh;
{
      u_char addr[4], port[2];
      char *cp, *buf, host[4 * 4];
      int n;

      n = urlcommand(uh, &buf, FTP_PASV);
      if (ftpseterrno(n) < 0) {
            free2(buf);
            return(-1);
      }
      if ((cp = strchr2(buf, '(')))
            cp = sscanf2(cp, "(%Cu,%Cu,%Cu,%Cu,%Cu,%Cu)",
                  &(addr[0]), &(addr[1]), &(addr[2]), &(addr[3]),
                  &(port[0]), &(port[1]));
      free2(buf);
      if (!cp) return(seterrno(EINVAL));
      n = snprintf2(host, sizeof(host),
            "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
      if (n < 0) return(seterrno(EINVAL));
      n = (port[0] << 8 | port[1]);

      return(sockconnect(host, n, urltimeout, SCK_THROUGHPUT));
}

static int NEAR ftpdata(uh)
int uh;
{
      u_char addr[4];
      char *cp, host[SCK_ADDRSIZE + 1];
      int n, s, port, opt;

      if (!(urlhostlist[uh].options & UOP_NOPASV)) return(ftppasv(uh));

      s = Xfileno(urlhostlist[uh].fp);
      if (getsockinfo(s, host, sizeof(host), &port, 0) < 0) return(-1);
      if (urlhostlist[uh].options & UOP_NOPORT)
            opt = (SCK_LOWDELAY | SCK_REUSEADDR);
      else {
            opt = SCK_LOWDELAY;
            port = 0;
      }
      if ((s = sockbind(host, port, opt)) < 0) return(-1);
      if (urlhostlist[uh].options & UOP_NOPORT) return(s);

      if (getsockinfo(s, host, sizeof(host), &port, 0) < 0) {
            safeclose(s);
            return(-1);
      }
      cp = sscanf2(host, "%Cu.%Cu.%Cu.%Cu%$",
            &(addr[0]), &(addr[1]), &(addr[2]), &(addr[3]));
      if (!cp) return(seterrno(EINVAL));

      n = urlcommand(uh, NULL, FTP_PORT,
            addr[0], addr[1], addr[2], addr[3],
            (port >> 8) & 0xff, port & 0xff);
      if (ftpseterrno(n) < 0) {
            safeclose(s);
            return(-1);
      }

      return(s);
}

static int NEAR sendrequest(uh, cmd, path)
int uh, cmd;
CONST char *path;
{
      int n;

      if ((n = urlcommand(uh, NULL, cmd, path)) < 0) return(-1);
      if (n / 100 == PRELIM) return(1);
      if (n != 425) return(seterrno(EINVAL));
      if ((urlhostlist[uh].flags & UFL_RETRYPORT)
      && (urlhostlist[uh].flags & UFL_RETRYPASV))
            return(seterrno(EINVAL));

      if (!(urlhostlist[uh].options & UOP_NOPASV)
      || (urlhostlist[uh].flags & UFL_RETRYPORT)) {
            urlhostlist[uh].flags |= UFL_RETRYPASV;
            urlhostlist[uh].options ^= UOP_NOPASV;
      }
      else {
            urlhostlist[uh].flags |= UFL_RETRYPORT;
            urlhostlist[uh].options ^= UOP_NOPORT;
      }

      return(0);
}

static int NEAR ftpopenport(uh, cmd, path, type)
int uh, cmd;
CONST char *path, *type;
{
      int n, fd;

      n = urlcommand(uh, NULL, FTP_TYPE, type);
      if (ftpseterrno(n) < 0) return(-1);

      for (;;) {
            if ((fd = ftpdata(uh)) < 0) return(-1);
            if ((n = sendrequest(uh, cmd, path)) > 0) break;
            if (n < 0) {
                  safeclose(fd);
                  return(-1);
            }
      }

      if (urlhostlist[uh].options & UOP_NOPASV)
            fd = sockaccept(fd, SCK_THROUGHPUT);

      return(fd);
}

static char *ftpfgets(vp)
VOID_P vp;
{
      char *buf;

      buf = Xfgets((XFILE *)vp);
      if (!buf) return(NULL);
      ftplog("    \"%s\"\n", buf);

      return(buf);
}

static int NEAR _ftprecvlist(uh, path, listp)
int uh;
CONST char *path;
namelist **listp;
{
      XFILE *fp;
      int n, fd, cmd, max;

      cmd = (urlhostlist[uh].options & UOP_USENLST) ? FTP_NLST : FTP_LIST;
      if ((fd = ftpopenport(uh, cmd, path, FTP_ASCII)) < 0) return(-1);
      if (!(fp = Xfdopen(fd, "r"))) {
            safeclose(fd);
            return(-1);
      }
      Xsettimeout(fp, urltimeout);
      Xsetflags(fp, XF_CRNL | XF_NONBLOCK);

      *listp = NULL;
      ftplog("<-- (data)\n");
      max = lsparse(fp, &ftpformat, listp, ftpfgets);
      safefclose(fp);
      if (max < 0) return(-1);

      n = urlgetreply(uh, NULL);
      if (ftpseterrno(n) < 0) {
            freelist(*listp, max);
            return(-1);
      }

      return(max);
}

int ftprecvlist(uh, path, listp)
int uh;
CONST char *path;
namelist **listp;
{
      int n;

      n = _ftprecvlist(uh, path, listp);
      if (n < 0 || (urlhostlist[uh].flags & UFL_FIXLISTOPT)) return(n);
      if (n > 1) {
            urlhostlist[uh].flags |= UFL_FIXLISTOPT;
            return(n);
      }
      urlhostlist[uh].options ^= UOP_NOLISTOPT;
      n = _ftprecvlist(uh, path, listp);
      urlhostlist[uh].options ^= UOP_NOLISTOPT;
      if (n > 1) {
            urlhostlist[uh].options ^= UOP_NOLISTOPT;
            urlhostlist[uh].flags |= UFL_FIXLISTOPT;
      }

      return(n);
}

static int NEAR recvpwd(uh, path, size)
int uh;
char *path;
ALLOC_T size;
{
      char *buf;
      int i, j, n, quote;

      if ((n = urlcommand(uh, &buf, FTP_PWD)) < 0) return(-1);
      if (n != 257) {
            free2(buf);
            return(seterrno(EACCES));
      }

      for (i = 4; isblank2(buf[i]); i++) /*EMPTY*/;
      quote = '\0';
      for (j = 0; buf[i]; i++) {
            if (buf[i] == quote) {
                  if (buf[i + 1] != quote) {
                        quote = '\0';
                        continue;
                  }
                  i++;
            }
            else if (quote) /*EMPTY*/;
            else if (isblank2(buf[i])) break;
            else if (buf[i] == '"') {
                  quote = buf[i];
                  continue;
            }

            if (j >= size - 1) break;
            path[j++] = buf[i];
      }
      path[j] = '\0';
      free2(buf);

      return(0);
}

static int NEAR ftpfeat(uh)
int uh;
{
      char *cp, *next, *buf;
      int n, mdtm;

      if (urlhostlist[uh].options & UOP_NOFEAT) return(0);

      n = urlcommand(uh, &buf, FTP_FEAT);
      if (ftpseterrno(n) < 0) {
            if (n == 500 || n == 502)
                  urlhostlist[uh].options |= UOP_NOFEAT;
            free2(buf);
            return(-1);
      }

      next = NULL;
      mdtm = 0;
      for (cp = buf; cp && *cp; cp = next) {
            while (isblank2(*cp)) cp++;
            if (!(next = strchr2(cp, '\n'))) n = strlen(cp);
            else {
                  n = next - cp;
                  *(next++) = '\0';
            }
            if (!strcasecmp2(cp, "MDTM")) mdtm++;
      }
      if (!mdtm) urlhostlist[uh].options |= UOP_NOMDTM;
      free2(buf);

      return(0);
}

static int NEAR ftpmdtm(uh, path, namep, st, ent)
int uh;
CONST char *path;
namelist *namep;
int st, ent;
{
      namelist *tmp;
      struct tm tm;
      char *cp, *buf;
      time_t t;
      int n, year, mon, day, hour, min, sec;

      if (urlhostlist[uh].options & UOP_NOMDTM) return(0);
      if (ismark(namep)) return(0);
      tmp = NULL;
      if (st >= 0 && st < maxurlstat
      && ent >= 0 && ent < urlstatlist[st].max)
            tmp = &(urlstatlist[st].list[ent]);

      n = urlcommand(uh, &buf, FTP_MDTM, path);
      if (n >= 0 && tmp) tmp -> tmpflags |= F_ISMRK;
      if (ftpseterrno(n) < 0) {
            if (n == 500 || n == 502)
                  urlhostlist[uh].options |= UOP_NOMDTM;
            free2(buf);
            return(-1);
      }
      if ((cp = strchr2(buf, ' '))) {
            cp = skipspace(&(cp[1]));
            cp = sscanf2(cp, "%04u%02u%02u%02u%02u%02u",
                  &year, &mon, &day, &hour, &min, &sec);
      }
      free2(buf);
      if (!cp) return(seterrno(EINVAL));
      tm.tm_year = year - 1900;
      tm.tm_mon = mon - 1;
      tm.tm_mday = day;
      tm.tm_hour = hour;
      tm.tm_min = min;
      tm.tm_sec = sec;

      t = timegm2(&tm);
      if (t == (time_t)-1) return(seterrno(EINVAL));
      namep -> st_mtim = t;
      if (tmp) tmp -> st_mtim = t;

      return(0);
}

int ftprecvstatus(uh, path, namep, n, ent)
int uh;
CONST char *path;
namelist *namep;
int n, ent;
{
      return(ftpmdtm(uh, path, namep, n, ent));
}

int ftpchdir(uh, path)
int uh;
CONST char *path;
{
      return(ftpseterrno(urlcommand(uh, NULL, FTP_CWD, path)));
}

char *ftpgetcwd(uh, path, size)
int uh;
char *path;
ALLOC_T size;
{
      char *cp;
      int n;

      cp = path;
      n = urlgenpath(uh, cp, size, UGP_SCHEME | UGP_USER | UGP_HOST);
      if (n < 0) return(NULL);
      cp += n;
      size -= n;
      if (recvpwd(uh, cp, size) < 0) return(NULL);

      return(path);
}

int ftpchmod(uh, path, mode)
int uh;
CONST char *path;
int mode;
{
      char buf[MAXLONGWIDTH + 1];
      int n;

      mode &= 0777;
      if (snprintf2(buf, sizeof(buf), "%03o", mode) < 0) return(-1);
      n = urlcommand(uh, NULL, FTP_CHMOD, buf, path);

      return(ftpseterrno(n));
}

int ftpunlink(uh, path)
int uh;
CONST char *path;
{
      return(ftpseterrno(urlcommand(uh, NULL, FTP_DELE, path)));
}

int ftprename(uh, from, to)
int uh;
CONST char *from, *to;
{
      int n;

      n = urlcommand(uh, NULL, FTP_RNFR, from);
      if (n / 100 != CONTINUE) {
            if (n >= 0) errno = ENOENT;
            return(-1);
      }

      return(ftpseterrno(urlcommand(uh, NULL, FTP_RNTO, to)));
}

int ftpopen(uh, path, flags)
int uh;
CONST char *path;
int flags;
{
      int cmd;

      switch (flags & O_ACCMODE) {
            case O_RDONLY:
                  cmd = FTP_RETR;
                  break;
            case O_WRONLY:
                  cmd = FTP_STOR;
                  break;
            default:
                  return(seterrno(EACCES));
/*NOTREACHED*/
                  break;
      }

      return(ftpopenport(uh, cmd, path, FTP_IMAGE));
}

/*ARGSUSED*/
int ftpclose(uh, fd)
int uh, fd;
{
      return(ftpseterrno(urlgetreply(uh, NULL)));
}

/*ARGSUSED*/
int ftpfstat(uh, stp)
int uh;
struct stat *stp;
{
      return(seterrno(ENOENT));
}

/*ARGSUSED*/
int ftpread(uh, fd, buf, nbytes)
int uh, fd;
char *buf;
int nbytes;
{
      return(read(fd, buf, nbytes));
}

/*ARGSUSED*/
int ftpwrite(uh, fd, buf, nbytes)
int uh, fd;
CONST char *buf;
int nbytes;
{
      return(write(fd, buf, nbytes));
}

int ftpmkdir(uh, path)
int uh;
CONST char *path;
{
      return(ftpseterrno(urlcommand(uh, NULL, FTP_MKD, path)));
}

int ftprmdir(uh, path)
int uh;
CONST char *path;
{
      return(ftpseterrno(urlcommand(uh, NULL, FTP_RMD, path)));
}
#endif      /* DEP_FTPPATH */

Generated by  Doxygen 1.6.0   Back to index