]> git.sesse.net Git - betaftpd/blobdiff - ftpd.c
If the xferlog file doesn't exist, BetaFTPD will now try to create one. Thanks to...
[betaftpd] / ftpd.c
diff --git a/ftpd.c b/ftpd.c
index 3982a74e2d4812a1f42ccafd345995f55a1ceb1a..2a01996e9004b167393baf4b9d121580018ddc4f 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
-    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,
 #include <config.h>
 #endif
 
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
 #if HAVE_ERRNO_H
 #include <errno.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
 #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_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
 #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_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_TCP_H
+#include <linux/tcp.h>
+#endif
+
 #if HAVE_MMAP
 #include <sys/mman.h>
 #endif
 #include <ascii.h>
 #endif
 
+#if WANT_DCACHE
+#include <dcache.h>
+#endif
+
 #ifndef MAP_FAILED
 #define MAP_FAILED -1
 #endif
@@ -198,7 +202,7 @@ fd_set master_fds, master_send_fds;
 FILE *xferlog = NULL;
 #endif
 
-#if HAVE_LINUX_SENDFILE
+#if HAVE_LINUX_SENDFILE || HAVE_BSD_SENDFILE
 int sendfile_supported = 1;
 #endif
 
@@ -443,30 +447,6 @@ struct ftran *alloc_new_ftran(const int sock, const struct conn * const c)
        return f;
 }
 
-#if WANT_DCACHE
-/*
- * alloc_new_dcache():
- *             Allocates a new directory cache entry (type `struct dcache'),
- *             and adds it to the linked list.
- */
-struct dcache *alloc_new_dcache()
-{
-       struct dcache *d = (struct dcache *)(malloc(sizeof(struct dcache)));
-
-       if (d == NULL) return d;
-
-       d->use_count = 0;
-       d->last_used = 0;
-       strcpy(d->dir_name, "");
-       d->dir_data = NULL;
-
-       add_to_linked_list((struct list_element *)first_dcache,
-                          (struct list_element *)d);
-
-       return d;
-}
-#endif
-
 /*
  * destroy_conn():
  *             Destroy a control connection, remove it from the linked
@@ -538,27 +518,6 @@ void destroy_ftran(struct ftran * const 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
@@ -629,6 +588,29 @@ int process_all_clients(const fd_set * const active_clients, const int num_ac)
        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.
@@ -650,8 +632,15 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac)
                f = next;
                next = f->next_ftran;
 
+#if HAVE_UPLOAD
+               if (f->upload == 1 && fds[f->sock].revents & POLLHUP) {
+                       finish_transfer(f);
+                       continue;
+               }
+#endif
+
 #if HAVE_POLL
-               if (fds[f->sock].revents & (POLLHUP|POLLERR|POLLNVAL)) {
+               if (fds[f->sock].revents & (POLLERR|POLLNVAL|POLLHUP)) {
                        destroy_ftran(f);
                        continue;
                }
@@ -659,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
-               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
@@ -709,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 */
-                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
@@ -788,7 +768,7 @@ int do_download(struct ftran *f)
 #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',
@@ -807,7 +787,7 @@ int do_download(struct ftran *f)
                }       
 #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
@@ -972,8 +952,8 @@ int main(void)
 #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);
@@ -1001,7 +981,7 @@ int main(void)
        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;
@@ -1009,7 +989,7 @@ int main(void)
                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
@@ -1191,29 +1171,6 @@ void time_out_sockets()
        }
 }
 
-#if WANT_DCACHE
-/*
- * time_out_dcache():
- *             Time out expired directory listing cache entries.
- *             Uses much of the same code as time_out_sockets().
- */
-void time_out_dcache()
-{
-       struct dcache *d = NULL, *next = first_dcache->next_dcache;
-       time_t now = time(NULL);        
-
-       /* run through the linked list */
-       while (next != NULL) {
-               d = next;
-               next = d->next_dcache;
-
-               if (d->use_count == 0 && (now - d->last_used > 900)) {
-                       destroy_dcache(d);
-               }
-       }
-}
-#endif
-
 /*
  * remove_bytes():
  *             Remove some bytes from the incoming buffer. This gives
@@ -1389,7 +1346,7 @@ void init_file_transfer(struct ftran * const f)
         */
 #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;
@@ -1532,6 +1489,24 @@ void clear_bad_fds(int * const server_sock)
 }
 #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