Hello community, here is the log from the commit of package uftpd for openSUSE:Factory checked in at 2019-08-27 10:27:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/uftpd (Old) and /work/SRC/openSUSE:Factory/.uftpd.new.7948 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "uftpd" Tue Aug 27 10:27:44 2019 rev:7 rq:726274 version:2.10 Changes: -------- --- /work/SRC/openSUSE:Factory/uftpd/uftpd.changes 2019-07-30 12:39:25.914933313 +0200 +++ /work/SRC/openSUSE:Factory/.uftpd.new.7948/uftpd.changes 2019-08-27 10:27:48.227912562 +0200 @@ -1,0 +2,10 @@ +Mon Aug 26 20:56:41 UTC 2019 - Martin Hauke <[email protected]> + +- Update to version 2.10 + * Add support for TFTP WRQ, i.e. for clients sending files to + server + * Fix invalid TFTP error codes, now uses custom error string to + code 0 + * Slightly improved debug messages + +------------------------------------------------------------------- Old: ---- uftpd-2.9.tar.gz New: ---- uftpd-2.10.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ uftpd.spec ++++++ --- /var/tmp/diff_new_pack.13v7ay/_old 2019-08-27 10:27:48.687912528 +0200 +++ /var/tmp/diff_new_pack.13v7ay/_new 2019-08-27 10:27:48.691912528 +0200 @@ -18,7 +18,7 @@ Name: uftpd -Version: 2.9 +Version: 2.10 Release: 0 Summary: A combined TFTP/FTP server License: ISC ++++++ uftpd-2.9.tar.gz -> uftpd-2.10.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/ChangeLog.md new/uftpd-2.10/ChangeLog.md --- old/uftpd-2.9/ChangeLog.md 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/ChangeLog.md 2019-08-15 09:20:03.000000000 +0200 @@ -4,6 +4,18 @@ All notable changes to the project are documented in this file. +[v2.10][] - 2019-08-15 +---------------------- + +### Changes +- Issue #25: Add support for TFTP write support (WRQ) +- Slightly improved debug messages. + +### Fixes +- Minor fix to TFTP error codes, only use standardized codes, and + code 0 + custom error message for everything else + + [v2.9][] - 2019-07-29 --------------------- @@ -16,7 +28,7 @@ - Fixes failing `dpkg -P uftpd` due to bug in postrm script ### Fixes -- Issue #21: Check for `pkg-config` before lookging for deps. +- Issue #21: Check for `pkg-config` before looking for deps. - Issue #22: Check FTP root security *after* having dropped privs. This means no longer having to run with `-o writable` by default - Issue #23: FTP command `CWD /` does not work, affects all clients. @@ -44,7 +56,7 @@ - Require libuEv v2.2, or later ### Fixes -- Issue #17: Issues with relative FTP root when running unpriviliged +- Issue #17: Issues with relative FTP root when running unprivileged [v2.6][] - 2018-07-03 @@ -90,7 +102,7 @@ ### Changes - Handle non-chrooted use-cases better, ensure CWD starts with / -- Increased default inactivty timer: 20 sec --> 180 sec +- Increased default inactivity timer: 20 sec --> 180 sec - Ensure FTP `PASV` and `PORT` sockets are set non-blocking to prevent blocking the event loop - [README.md][] updates, add usage section and improve build + install @@ -175,7 +187,7 @@ [v2.0][] - 2016-01-22 --------------------- -Sleak, smart, simple ... UNIX +Sleek, smart, simple ... UNIX ### Changes - Greatly simplified command line syntax @@ -220,7 +232,7 @@ - Major refactor of both FTP and TFTP servers to use libuEv better. - Move to use [libite][] v1.0.0 for `strlcpy()`, `strlcat()`, `pidfile()` and more. -- Add proper session timout to TFTP, like what FTP already has. +- Add proper session timeout to TFTP, like what FTP already has. - Add support for `NLST` FTP command, needed for multiple get operations. This fixes issue #2, thanks to @oz123 on GitHub for pointing this out! - Add support for `FEAT` and `HELP` FTP commands used by some clients. @@ -301,7 +313,7 @@ ### Fixes - Fix nasty invalid `sizeof()` argument to `recv()` causing uftpd to only read 4/8 bytes (32/64 bit arch) at a time from the FTP socket. - This should greatly reduce CPU utilisation and improve xfer speeds. + This should greatly reduce CPU utilization and improve xfer speeds. Found by [Coverity Scan][]. - Fix minor resource leak in `ftp_session()` when `getsockname()` or `getpeername()` fail. Minor fix because the session exits and the OS @@ -349,7 +361,7 @@ - Incompatible changes to the command line arguments, compared to v1.2! - Add libuEv as a GIT submodule, handles signals, timers, and all I/O. - Refactor all signal handling, timers, and socket `poll()` calls to - use libuEv instead. Much cleaner and maintaiable code as a result. + use libuEv instead. Much cleaner and maintainable code as a result. - Clarify copyright claims, not much remains of the original [FtpServer][] code, by [Xu Wang][]. @@ -424,7 +436,8 @@ Lines must end in the old `\r\n` format, rather than UNIX `\n`. -[UNRELEASED]: https://github.com/troglobit/uftpd/compare/v2.9...HEAD +[UNRELEASED]: https://github.com/troglobit/uftpd/compare/v2.10...HEAD +[v2.10]: https://github.com/troglobit/uftpd/compare/v2.9...v2.10 [v2.9]: https://github.com/troglobit/uftpd/compare/v2.8...v2.9 [v2.8]: https://github.com/troglobit/uftpd/compare/v2.7...v2.8 [v2.7]: https://github.com/troglobit/uftpd/compare/v2.6...v2.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/configure.ac new/uftpd-2.10/configure.ac --- old/uftpd-2.9/configure.ac 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/configure.ac 2019-08-15 09:20:03.000000000 +0200 @@ -1,4 +1,5 @@ -AC_INIT([uftpd], [2.9], [https://github.com/troglobit/uftpd/issues],, [http://troglobit.com/uftpd.html]) +AC_INIT([uftpd], [2.10], [https://github.com/troglobit/uftpd/issues],, + [https://troglobit.com/projects/uftpd/]) AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) AM_SILENT_RULES([yes]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/debian/changelog new/uftpd-2.10/debian/changelog --- old/uftpd-2.9/debian/changelog 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/debian/changelog 2019-08-15 09:20:03.000000000 +0200 @@ -1,3 +1,11 @@ +uftpd (2.10) unstable; urgency=medium + + * Add support for TFTP WRQ, i.e. for clients sending files to server + * Fix invalid TFTP error codes, now uses custom error string to code 0 + * Slightly improved debug messages + + -- Joachim Nilsson <[email protected]> Thu, 15 Aug 2019 08:59:35 +0200 + uftpd (2.9) unstable; urgency=medium * Check FTP root security after dropping privileges, issue #22 @@ -22,7 +30,7 @@ uftpd (2.7) unstable; urgency=medium * Bug fix release - * Fix running uftpd as unpriviliged user using a relative FTP root + * Fix running uftpd as unprivileged user using a relative FTP root -- Joachim Nilsson <[email protected]> Sun, 03 Mar 2019 11:39:03 +0100 @@ -73,7 +81,7 @@ A user must now be member of the users group to share files over TFTP/FTP. Simply add a user to 'users' and they can upload their - files to /srv/ftp. The TFT/FTP server itself has no rights to + files to /srv/ftp. The TFTP/FTP server itself has no rights to write there. Add an uploads/ sub-directory with write perms for the 'ftp' user if you want to enable anonymous uploads via FTP. @@ -134,7 +142,7 @@ * New upstream release: - Fix insecure chroot(), reported by Coverity Scan, CID #54523 - - Minor updates to README and a new CHANGLOG file + - Minor updates to README and a new CHANGELOG file -- Joachim Nilsson <[email protected]> Sun, 2 Feb 2015 06:45:06 +0100 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/debian/config new/uftpd-2.10/debian/config --- old/uftpd-2.9/debian/config 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/debian/config 2019-08-15 09:20:03.000000000 +0200 @@ -1,4 +1,6 @@ -#!/bin/sh -e +#!/bin/sh + +set -e . /usr/share/debconf/confmodule db_title uftpd diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/debian/control new/uftpd-2.10/debian/control --- old/uftpd-2.9/debian/control 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/debian/control 2019-08-15 09:20:03.000000000 +0200 @@ -4,7 +4,7 @@ Maintainer: Joachim Nilsson <[email protected]> Build-Depends: debhelper (>= 10) Standards-Version: 4.3.0 -Homepage: https://troglobit.com/uftpd.html +Homepage: https://troglobit.com/projects/uftpd/ Package: uftpd Architecture: any @@ -13,12 +13,14 @@ Provides: ftp-server Conflicts: ftp-server, tftpd, tftpd-hpa Description: No nonsense TFTP/FTP server - uftpd is a very simple TFTP and FTP server intended for small and local - LANs. It works on the Internet, although it is not recommended, and is - set up in a read-only configuration by default. It has no users, no - configuration file, and is started on-demand by the UNIX inetd super - server, neatly tcpwrapped for your safety. + uftpd is a small and simple TFTP and FTP server intended for LANs. Its + author runs it on the Internet, although this is not recommended. + . + uftpd is set up in a read-only configuration by default. It has no + users, except for anonymous, no configuration file, and is started + on-demand by the UNIX inetd super server, neatly tcpwrapped for your + safety. . Hardcore Internet users and anyone concerned about security should probably consider a separate TFTP server and for FTP look at one of: - vsftpd, proftpd or pure-ftpd. + vsftpd, proftpd, or pure-ftpd. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/debian/postinst new/uftpd-2.10/debian/postinst --- old/uftpd-2.9/debian/postinst 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/debian/postinst 2019-08-15 09:20:03.000000000 +0200 @@ -1,4 +1,6 @@ -#!/bin/sh -e +#!/bin/sh + +set -e [ "$1" = "configure" ] || exit 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/debian/postrm new/uftpd-2.10/debian/postrm --- old/uftpd-2.9/debian/postrm 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/debian/postrm 2019-08-15 09:20:03.000000000 +0200 @@ -1,4 +1,5 @@ -#!/bin/sh -e +#!/bin/sh +set -e if [ "$1" = "purge" ]; then if command -v update-inetd >/dev/null 2>&1; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/debian/prerm new/uftpd-2.10/debian/prerm --- old/uftpd-2.9/debian/prerm 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/debian/prerm 2019-08-15 09:20:03.000000000 +0200 @@ -1,4 +1,6 @@ -#!/bin/sh -e +#!/bin/sh + +set -e update-inetd --pattern 'in.ftpd' --multi --disable ftp update-inetd --pattern 'in.tftpd' --multi --disable tftp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/man/uftpd.8 new/uftpd-2.10/man/uftpd.8 --- old/uftpd-2.9/man/uftpd.8 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/man/uftpd.8 2019-08-15 09:20:03.000000000 +0200 @@ -13,9 +13,9 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd Jul 29, 2019 +.Dd Aug 12, 2019 .Dt UFTPD 8 -.Os "uftpd (2.9)" +.Os "uftpd (2.10)" .Sh NAME .Nm uftpd .Nd @@ -23,7 +23,7 @@ .Sh SYNOPSIS .Nm .Op Fl hnsv -.Op Fl l Ar LVL +.Op Fl l Ar LOG .Op Fl o Ar ftp=PORT,tftp=PORT,writable .Op Ar PATH .Sh DESCRIPTION @@ -50,7 +50,7 @@ .Bl -tag -width Ds .It Fl h Show built-in help text -.It Fl l Ar LVL +.It Fl l Ar LOG Set log level: none, err, info, .Ar notice , debug @@ -130,7 +130,7 @@ The FTP server currently supports the following requests. The case of the requests is ignored. .Bl -column "Request" -offset indent -.It Request Ta "Description" +.It Sy Request Ta Sy "Description" .It ABOR Ta "abort current transfer" .It CDUP Ta "shorthand for CD .. command" .It CWD Ta "change working directory" @@ -174,15 +174,18 @@ .Pp The TFTP server currently supports the following requests. .Bl -column "Request" -offset indent -.It RRQ -.It ERROR -.It ACK +.It Sy Request Ta Sy Description +.It RRQ Ta Read Request for file, may have options +.It WRQ Ta Write Request for file, may have options +.It DATA Ta File data, preceeded by block n:o +.It ERROR Ta Error, end of session +.It ACK Ta ACKnowledge DATA or WRQ without options +.It OACK Ta Option acknowleged, sent as response to RRQ/WRQ .El .Pp .Nm supports TFTP blocksize negotiation, according to RFC2348, so full sized -Ethernet frames can be used, which greatly speeds up transfers. Support -for WRQ is not yet implemented, patches welcome! +Ethernet frames can be used, which greatly speeds up transfers. .Pp .Sh FILES .Bl -tag -width /etc/ftpwelcome -compact diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/src/ftpcmd.c new/uftpd-2.10/src/ftpcmd.c --- old/uftpd-2.9/src/ftpcmd.c 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/src/ftpcmd.c 2019-08-15 09:20:03.000000000 +0200 @@ -127,7 +127,7 @@ *cmd = msg; *argument = NULL; - DBG("Recv: [%s], %d bytes", msg, bytes); + DBG("Recv: [%s], %zd bytes", msg, bytes); return 0; } @@ -1023,7 +1023,7 @@ gettimeofday(&tv, NULL); if (tv.tv_sec - ctrl->tv.tv_sec > 3) { - DBG("Sending %d bytes of %s to %s ...", num, ctrl->file, ctrl->clientaddr); + DBG("Sending %zd bytes of %s to %s ...", num, ctrl->file, ctrl->clientaddr); ctrl->tv.tv_sec = tv.tv_sec; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/src/tftpcmd.c new/uftpd-2.10/src/tftpcmd.c --- old/uftpd-2.9/src/tftpcmd.c 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/src/tftpcmd.c 2019-08-15 09:20:03.000000000 +0200 @@ -19,6 +19,28 @@ #include <poll.h> #include <arpa/tftp.h> +/* + * Theory of operation, from RFC1350: + * + * Client gets file, RRQ: + * + * client server + * |----------- RRQ ---------->| + * |<--------- DATA -----------| + * |----------- ACK ---------->| + * | | + * + * Client puts file, WRQ: + * + * client server + * |----------- WRQ ---------->| + * |<---------- ACK -----------| + * |---------- DATA ---------->| + * |<---------- ACK -----------| + * | | + * + */ + /* Send @len bytes data in @ctrl->buf */ static int do_send(ctrl_t *ctrl, size_t len) { @@ -32,7 +54,7 @@ if (ctrl->th->th_opcode == OACK) hdrsz = ctrl->th->th_stuff - ctrl->buf; - DBG("tftp sending %zd + %zd bytes ...", hdrsz, len); + DBG("SND %c: header size: %zd, data len: %zd ...", ctrl->th->th_code, hdrsz, len); result = sendto(ctrl->sd, ctrl->buf, hdrsz + len, 0, (struct sockaddr *)&ctrl->client_sa, salen); if (-1 == result) return 1; @@ -67,21 +89,22 @@ return do_send(ctrl, len); } -#if 0 /* TODO, for client op */ -static int send_ACK(ctrl_t *ctrl) +static int send_ACK(ctrl_t *ctrl, int block) { - return 0; + memset(ctrl->buf, 0, ctrl->bufsz); + + ctrl->th->th_opcode = htons(ACK); + ctrl->th->th_block = htons(block); + DBG("ACK block %d", block); + + return do_send(ctrl, 4); } -#endif /* Acknowledge options sent by client */ static int send_OACK(ctrl_t *ctrl) { char *ptr; - if (!ctrl->tftp_options) - return 0; - memset(ctrl->buf, 0, ctrl->bufsz); /* Create message */ @@ -99,10 +122,13 @@ return do_send(ctrl, ptr - ctrl->buf); } -static int send_ERROR(ctrl_t *ctrl, int code) +static int send_ERROR(ctrl_t *ctrl, int code, char *str) { - char *str = strerror(code); - size_t len = strlen(str); + size_t len; + + if (!str) + str = strerror(code); + len = strlen(str); memset(ctrl->buf, 0, ctrl->segsize); @@ -110,6 +136,7 @@ ctrl->th->th_opcode = htons(ERROR); ctrl->th->th_code = htons(code); strlcpy(ctrl->th->th_msg, str, len); + DBG("ERR %d: %s", code, str); /* Error is ASCIIZ string, hence +1 */ return do_send(ctrl, len + 1); @@ -138,15 +165,15 @@ return 0; } -/* Parse TFTP payload in RRQ to get filename and optional blksize & timeout */ -static int parse_RRQ(ctrl_t *ctrl, char *buf, size_t len) +/* Parse TFTP payload in WRQ/RRQ for filename and optional blksize+timeout */ +static int parse_RWRQ(ctrl_t *ctrl, char *buf, size_t len) { size_t opt_len = strlen(buf) + 1; /* First opt is always filename */ ctrl->file = strdup(buf); if (!ctrl->file) - return send_ERROR(ctrl, ENOMEM); + return send_ERROR(ctrl, EUNDEF, NULL); do { /* Prepare to read options */ @@ -167,13 +194,17 @@ if (alloc_buf(ctrl, sz)) { ERR(errno, "Failed reallocating TFTP buffer memory"); - return send_ERROR(ctrl, ENOMEM); + return send_ERROR(ctrl, EUNDEF, NULL); } + DBG("Negotiated blksize %zd", sz); setbit(&ctrl->tftp_options, 1); } } while (len); + if (!ctrl->tftp_options) + return 0; + return send_OACK(ctrl); } @@ -184,18 +215,67 @@ path = compose_path(ctrl, ctrl->file); if (!path) { ERR(errno, "%s: Invalid path to file %s", ctrl->clientaddr, ctrl->file); - return send_ERROR(ctrl, ENOTFOUND); + return send_ERROR(ctrl, ENOTFOUND, NULL); } ctrl->fp = fopen(path, "r"); if (!ctrl->fp) { ERR(errno, "%s: Failed opening %s", ctrl->clientaddr, path); - return send_ERROR(ctrl, ENOTFOUND); + return send_ERROR(ctrl, ENOTFOUND, NULL); } return !send_DATA(ctrl, 0); } +static int handle_WRQ(ctrl_t *ctrl) +{ + char *path; + + path = compose_path(ctrl, ctrl->file); + if (!path) { + ERR(errno, "%s: Invalid path to file %s", ctrl->clientaddr, ctrl->file); + return send_ERROR(ctrl, ENOTFOUND, NULL); + } + + ctrl->offset = 1; /* First expected block */ + ctrl->fp = fopen(path, "w"); + if (!ctrl->fp) { + ERR(errno, "%s: Failed opening %s", ctrl->clientaddr, path); + return send_ERROR(ctrl, ENOTFOUND, NULL); + } + + if (ctrl->tftp_options) + return 0; + + return send_ACK(ctrl, 0); +} + +static int handle_DATA(ctrl_t *ctrl, size_t len) +{ + char errmsg[80]; + int block; + + block = ntohs(ctrl->th->th_block); + if (block != ctrl->offset) { + snprintf(errmsg, sizeof(errmsg), "Expected block %ld, " + "got DATA for block %d", ctrl->offset, block); + return !send_ERROR(ctrl, EUNDEF, errmsg); + } + + DBG("tftp block %d writing %zd bytes ...", ctrl->th->th_block, len); + if (len != fwrite(ctrl->th->th_data, sizeof(char), len, ctrl->fp)) { + snprintf(errmsg, sizeof(errmsg), "Failed writing file: %s", + strerror(errno)); + return !send_ERROR(ctrl, ENOSPACE, errmsg); + } + + ctrl->offset++; + if (send_ACK(ctrl, block) || len < ctrl->segsize) + return 0; + + return 1; +} + /* TODO: Add support for ACK timeout and resend */ static int handle_ACK(ctrl_t *ctrl, int block) { @@ -243,7 +323,7 @@ switch (op) { case RRQ: len -= ctrl->th->th_stuff - ctrl->buf; - if (parse_RRQ(ctrl, ctrl->th->th_stuff, len)) { + if (parse_RWRQ(ctrl, ctrl->th->th_stuff, len)) { ERR(errno, "Failed parsing TFTP RRQ"); active = 0; break; @@ -253,12 +333,30 @@ free(ctrl->file); break; + case WRQ: + len -= ctrl->th->th_stuff - ctrl->buf; + if (parse_RWRQ(ctrl, ctrl->th->th_stuff, len)) { + ERR(errno, "Failed parsing TFTP WRQ"); + active = 0; + break; + } + DBG("tftp WRQ %s from %s:%d", ctrl->file, ctrl->clientaddr, port); + handle_WRQ(ctrl); + free(ctrl->file); + break; + + case DATA: /* Received data after WRQ */ + DBG("tftp DATA %s from %s:%d", ctrl->file, ctrl->clientaddr, port); + len -= ctrl->th->th_data - ctrl->buf; + active = handle_DATA(ctrl, len); + break; + case ERROR: DBG("tftp ERROR: %hd", ntohs(ctrl->th->th_code)); active = 0; break; - case ACK: + case ACK: /* Sent for each DATA we send in a RRQ */ DBG("tftp ACK, block # %hu", block); active = handle_ACK(ctrl, block); break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/uftpd-2.9/src/uftpd.h new/uftpd-2.10/src/uftpd.h --- old/uftpd-2.9/src/uftpd.h 2019-07-29 10:53:23.000000000 +0200 +++ new/uftpd-2.10/src/uftpd.h 2019-08-15 09:20:03.000000000 +0200 @@ -126,7 +126,7 @@ char pending; /* Pending op: LIST, RETR, STOR */ char list_mode; /* Current LIST mode */ char *file; /* Current file name to fetch */ - off_t offset; /* Offset in current file, for REST */ + off_t offset; /* Offset/block in current file, for REST/WRQ */ FILE *fp; /* Current file in operation */ int i; /* i of d_num in 'd' */ int d_num; /* Number of entries in 'd' */
