]> git.sesse.net Git - betaftpd/blobdiff - ftpd.c
Makefile now honours CPPFLAGS (C preprocessor flags).
[betaftpd] / ftpd.c
diff --git a/ftpd.c b/ftpd.c
index 0f497c9a2a60bc194db5c5bfe055546219d384b2..374db9691ba4900cda937a2c21fc84bf6547b5f9 100644 (file)
--- a/ftpd.c
+++ b/ftpd.c
@@ -2,7 +2,7 @@
     Copyright (C) 1999-2000 Steinar H. Gunderson
 
     This program is is free software; you can redistribute it and/or modify
     Copyright (C) 1999-2000 Steinar H. Gunderson
 
     This program is is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License, version 2 if the
+    it under the terms of the GNU General Public License, version 2 of the
     License as published by the Free Software Foundation.
 
     This program is distributed in the hope that it will be useful,
     License as published by the Free Software Foundation.
 
     This program is distributed in the hope that it will be useful,
 #include <config.h>
 #endif
 
 #include <config.h>
 #endif
 
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
 #if HAVE_ERRNO_H
 #include <errno.h>
 #endif
 #if HAVE_ERRNO_H
 #include <errno.h>
 #endif
 #include <stropts.h>
 #endif
 
 #include <stropts.h>
 #endif
 
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
 #if HAVE_SYS_CONF_H
 #include <sys/conf.h>
 #endif
 #if HAVE_SYS_CONF_H
 #include <sys/conf.h>
 #endif
 #include <unistd.h>
 #endif
 
 #include <unistd.h>
 #endif
 
+#if HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
+#endif
+
 #if HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
 
 #if HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
 
+#if HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
+
+#if HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
 #if HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
 #if HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
 #include <sys/stat.h>
 #endif
 
 #include <sys/stat.h>
 #endif
 
-#if HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
 #if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
 
 #if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
 
-#if HAVE_NETINET_IN_SYSTM_H
-#include <netinet/in_systm.h>
-#endif
-
-#if HAVE_NETINET_IP_H
-#include <netinet/ip.h>
-#endif
-
-#if HAVE_NETINET_TCP_H
-#include <netinet/tcp.h>
-#endif
-
 #if HAVE_LINUX_SOCKET_H
 #include <linux/socket.h>
 #endif
 #if HAVE_LINUX_SOCKET_H
 #include <linux/socket.h>
 #endif
@@ -206,7 +202,7 @@ fd_set master_fds, master_send_fds;
 FILE *xferlog = NULL;
 #endif
 
 FILE *xferlog = NULL;
 #endif
 
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
 int sendfile_supported = 1;
 #endif
 
 int sendfile_supported = 1;
 #endif
 
@@ -522,27 +518,6 @@ void destroy_ftran(struct ftran * const f)
        remove_from_linked_list((struct list_element *)f);
 }
 
        remove_from_linked_list((struct list_element *)f);
 }
 
-#if WANT_DCACHE
-/*
- * destroy_dcache():
- *             Destroy a directory listing cache entry, remove it from the
- *             linked list, and clean up after it.
- *
- *             If you free a cache entry that is in use (use_count > 0),
- *             BetaFTPD will most likely crash (later). The thing you're supposed
- *             to do when you're done with a dcache entry, is to decrement
- *             its use_count, and let the timeout functions do the destroying
- *             when it's time to do so.
- */
-void destroy_dcache(struct dcache * const d)
-{
-        if (d == NULL) return;
-
-       if (d->dir_data != NULL) free(d->dir_data);
-       remove_from_linked_list((struct list_element *)d);
-}
-#endif
-
 /*
  * process_all_clients():
  *             Processes all the _control_ connections in active_clients
 /*
  * process_all_clients():
  *             Processes all the _control_ connections in active_clients
@@ -613,6 +588,29 @@ int process_all_clients(const fd_set * const active_clients, const int num_ac)
        return checked_through;
 }
 
        return checked_through;
 }
 
+/*
+ * finish_transfer():
+ *             Send a message that the transfer is completed, write xferlog
+ *             entry (optional), and update the last_transfer record in the
+ *             file transfer object. Goes for both uploads and downloads.
+ */
+void finish_transfer(struct ftran * const f)
+{
+       numeric(f->owner, 226, "Transfer complete.");
+       time(&(f->owner->last_transfer));
+
+#if WANT_XFERLOG
+       if (!f->dir_listing) {
+               write_xferlog(f);
+       }
+#endif
+
+       destroy_ftran(f);
+#if WANT_FULLSCREEN
+       update_display(first_conn);
+#endif
+}
+
 /*
  * process_all_sendfiles():
  *             Sends data to all clients that are ready to receive it.
 /*
  * process_all_sendfiles():
  *             Sends data to all clients that are ready to receive it.
@@ -634,8 +632,15 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac)
                f = next;
                next = f->next_ftran;
 
                f = next;
                next = f->next_ftran;
 
+#if WANT_UPLOAD
+               if ((f->upload == 1) && (fds[f->sock].revents & POLLHUP)) {
+                       finish_transfer(f);
+                       continue;
+               }
+#endif
+
 #if HAVE_POLL
 #if HAVE_POLL
-               if (fds[f->sock].revents & (POLLHUP|POLLERR|POLLNVAL)) {
+               if (fds[f->sock].revents & (POLLERR|POLLNVAL|POLLHUP)) {
                        destroy_ftran(f);
                        continue;
                }
                        destroy_ftran(f);
                        continue;
                }
@@ -643,7 +648,7 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac)
 
                /* state = 2: incoming PASV, state >3: send file */
 #if HAVE_POLL
 
                /* state = 2: incoming PASV, state >3: send file */
 #if HAVE_POLL
-               if ((f->state < 2) || (f->state == 3) ||  (fds[f->sock].revents & (POLLIN|POLLOUT)) == 0) {
+               if ((f->state < 2) || (f->state == 3) || (fds[f->sock].revents & (POLLIN|POLLOUT)) == 0) {
 #else
                if ((f->state < 2) || (f->state == 3) || !FD_ISSET(f->sock, active_clients)) {
 #endif
 #else
                if ((f->state < 2) || (f->state == 3) || !FD_ISSET(f->sock, active_clients)) {
 #endif
@@ -693,16 +698,7 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac)
                        if (do_download(f)) continue;
 
                /* do_{upload,download} returned 0, the transfer is complete */
                        if (do_download(f)) continue;
 
                /* do_{upload,download} returned 0, the transfer is complete */
-                numeric(f->owner, 226, "Transfer complete.");
-                time(&(f->owner->last_transfer));
-
-#if WANT_XFERLOG
-                if (!f->dir_listing) {
-                       write_xferlog(f);
-               }
-#endif
-
-               destroy_ftran(f);
+               finish_transfer(f);
 #if WANT_FULLSCREEN
                 update_display(first_conn);
 #endif
 #if WANT_FULLSCREEN
                 update_display(first_conn);
 #endif
@@ -772,7 +768,7 @@ int do_download(struct ftran *f)
 #endif
        int size;
 
 #endif
        int size;
 
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
        /*
         * We handle the optimal case first, which is sendfile().
         * Here we use a rather simplified sending `algorithm',
        /*
         * We handle the optimal case first, which is sendfile().
         * Here we use a rather simplified sending `algorithm',
@@ -791,7 +787,7 @@ int do_download(struct ftran *f)
                }       
 #endif
 
                }       
 #endif
 
-                       err = sendfile(f->sock, f->local_file, &f->pos, size);
+                       err = mysendfile(f->sock, f->local_file, &f->pos, size);
                return (f->pos < f->size) && (err > -1);
        }
 #endif
                return (f->pos < f->size) && (err > -1);
        }
 #endif
@@ -851,11 +847,11 @@ void write_xferlog(struct ftran *f)
 
        if (xferlog == NULL) return;
 
 
        if (xferlog == NULL) return;
 
-       strftime(temp, 256, "%a %b %d %H:%M:%S %Y", t);
+       strftime(temp, 256, "%a  %b %d %H:%M:%S %Y", t);
 #if WANT_UPLOAD
 #if WANT_UPLOAD
-       fprintf(xferlog, "%s %u %s %lu %s b _ %c a %s ftp 0 * \n",
+       fprintf(xferlog, "%s %u %s %lu %s b _ %c %c %s ftp 0 *\n",
 #else
 #else
-       fprintf(xferlog, "%s %u %s %lu %s b _ o a %s ftp 0 *\n",
+       fprintf(xferlog, "%s %u %s %lu %s b _ o %c %s ftp 0 *\n",
 #endif
                temp, (int)(difftime(now, f->tran_start)),
                inet_ntoa(f->sin.sin_addr), f->size,
 #endif
                temp, (int)(difftime(now, f->tran_start)),
                inet_ntoa(f->sin.sin_addr), f->size,
@@ -863,7 +859,7 @@ void write_xferlog(struct ftran *f)
 #if WANT_UPLOAD
                (f->upload) ? 'i' : 'o',
 #endif
 #if WANT_UPLOAD
                (f->upload) ? 'i' : 'o',
 #endif
-               f->owner->username);
+               (f->owner->auth == 4) ? 'r' : 'a', f->owner->username);
                fflush(xferlog);
 
 #if 0
                fflush(xferlog);
 
 #if 0
@@ -956,8 +952,8 @@ int main(void)
 #warning No xferlog support for nonroot yet
 #else
        /* open xferlog */
 #warning No xferlog support for nonroot yet
 #else
        /* open xferlog */
-       xferlog = fopen("/var/log/xferlog", "r+");
-       if (xferlog == NULL) xferlog = fopen("/usr/adm/xferlog", "r+");
+       xferlog = fopen("/var/log/xferlog", "a");
+       if (xferlog == NULL) xferlog = fopen("/usr/adm/xferlog", "a");
 
        if (xferlog != NULL) {
                  fseek(xferlog, 0L, SEEK_END);
 
        if (xferlog != NULL) {
                  fseek(xferlog, 0L, SEEK_END);
@@ -985,7 +981,7 @@ int main(void)
        alarm(60);
        signal(SIGALRM, handle_alarm);
 
        alarm(60);
        signal(SIGALRM, handle_alarm);
 
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
        /* check that sendfile() is really implemented (same check as configure does) */
        {
                int out_fd = 1, in_fd = 0;
        /* check that sendfile() is really implemented (same check as configure does) */
        {
                int out_fd = 1, in_fd = 0;
@@ -993,7 +989,7 @@ int main(void)
                size_t size = 1024;
 
                errno = 0;
                size_t size = 1024;
 
                errno = 0;
-               sendfile(out_fd, in_fd, &offset, size);
+               mysendfile(out_fd, in_fd, &offset, size);
                if (errno == ENOSYS) sendfile_supported = 0;
        }
 #endif
                if (errno == ENOSYS) sendfile_supported = 0;
        }
 #endif
@@ -1350,7 +1346,7 @@ void init_file_transfer(struct ftran * const f)
         */
 #if HAVE_MMAP
        if (f->dir_listing == 0) {
         */
 #if HAVE_MMAP
        if (f->dir_listing == 0) {
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
                int do_mmap = (sendfile_supported) ? 0 : 1;
 #else
                int do_mmap = 1;
                int do_mmap = (sendfile_supported) ? 0 : 1;
 #else
                int do_mmap = 1;
@@ -1493,6 +1489,24 @@ void clear_bad_fds(int * const server_sock)
 }
 #endif
 
 }
 #endif
 
+#if HAVE_BSD_SENDFILE || HAVE_LINUX_SENDFILE
+int mysendfile(int sock, int fd, off_t *offset, size_t count)
+{
+#if HAVE_BSD_SENDFILE
+       int err;
+       off_t ssize = 0;
+       
+       err = sendfile(fd, sock, *offset, count, NULL, &ssize, 0);
+       if (ssize > 0) *offset += ssize;
+#else /* !HAVE_BSD_SENDFILE */
+#if HAVE_LINUX_SENDFILE
+       return sendfile(sock, fd, offset, count);
+#endif /* HAVE_LINUX_SENDFILE */
+#endif /* !HAVE_BSD_SENDFILE */
+}
+#endif /* HAVE_BSD_SENDFILE || HAVE_LINUX_SENDFILE */
+
+
 #if WANT_MESSAGE
 /*
  * dump_file(): Dumps a file on the control connection. Used for
 #if WANT_MESSAGE
 /*
  * dump_file(): Dumps a file on the control connection. Used for