rework the networking locking facility using the hashlist.
[citadel.git] / citadel / file_ops.c
index 96e00a0fd00d7cb44a2207b7722a9dfdad3c1fe1..9040c4c746b4d009ba5cad19ebc91644be48c1b3 100644 (file)
@@ -1,8 +1,5 @@
 /* 
- * $Id$
- *
  * Server functions which handle file transfers and room directories.
- *
  */
 
 #include "sysdep.h"
@@ -35,7 +32,6 @@
 #include "config.h"
 #include "file_ops.h"
 #include "sysdep_decls.h"
-#include "user_ops.h"
 #include "support.h"
 #include "room_ops.h"
 #include "msgbase.h"
 #endif
 
 #include "ctdl_module.h"
+#include "user_ops.h"
 
 /*
  * network_talking_to()  --  concurrency checker
  */
-int network_talking_to(char *nodename, int operation) {
+static HashList *nttlist = NULL;
+int network_talking_to(const char *nodename, long len, int operation) {
 
-       static char *nttlist = NULL;
-       char *ptr = NULL;
-       int i;
-       char buf[SIZ];
        int retval = 0;
+       HashPos *Pos = NULL;
+       void *vdata;
 
        begin_critical_section(S_NTTLIST);
 
        switch(operation) {
 
                case NTT_ADD:
-                       if (nttlist == NULL) nttlist = strdup("");
-                       if (nttlist == NULL) break;
-                       nttlist = (char *)realloc(nttlist,
-                               (strlen(nttlist) + strlen(nodename) + 3) );
-                       strcat(nttlist, "|");
-                       strcat(nttlist, nodename);
+                       if (nttlist == NULL) 
+                               nttlist = NewHash(1, NULL);
+                       Put(nttlist, nodename, len, NewStrBufPlain(nodename, len), HFreeStrBuf);
+                       syslog(LOG_DEBUG, "nttlist: added <%s>\n", nodename);
                        break;
-
                case NTT_REMOVE:
-                       if (nttlist == NULL) break;
-                       if (IsEmptyStr(nttlist)) break;
-                       ptr = malloc(strlen(nttlist));
-                       if (ptr == NULL) break;
-                       strcpy(ptr, "");
-                       for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
-                               extract_token(buf, nttlist, i, '|', sizeof buf);
-                               if ( (!IsEmptyStr(buf))
-                                    && (strcasecmp(buf, nodename)) ) {
-                                               strcat(ptr, buf);
-                                               strcat(ptr, "|");
-                               }
-                       }
-                       free(nttlist);
-                       nttlist = ptr;
+                       if ((nttlist == NULL) ||
+                           (GetCount(nttlist) == 0))
+                               break;
+                       Pos = GetNewHashPos(nttlist, 1);
+                       GetHashPosFromKey (nttlist, nodename, len, Pos);
+
+                       DeleteEntryFromHash(nttlist, Pos);
+                       DeleteHashPos(&Pos);
+                       syslog(LOG_DEBUG, "nttlist: removed <%s>\n", nodename);
+
                        break;
 
                case NTT_CHECK:
-                       if (nttlist == NULL) break;
-                       if (IsEmptyStr(nttlist)) break;
-                       for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
-                               extract_token(buf, nttlist, i, '|', sizeof buf);
-                               if (!strcasecmp(buf, nodename)) ++retval;
-                       }
+                       if ((nttlist == NULL) ||
+                           (GetCount(nttlist) == 0))
+                               break;
+                       if (!GetHash(nttlist, nodename, len, &vdata))
+                               retval ++;
+                       syslog(LOG_DEBUG, "nttlist: have [%d] <%s>\n", retval, nodename);
                        break;
        }
 
-       if (nttlist != NULL) CtdlLogPrintf(CTDL_DEBUG, "nttlist=<%s>\n", nttlist);
        end_critical_section(S_NTTLIST);
        return(retval);
 }
 
+void cleanup_nttlist(void)
+{
+        begin_critical_section(S_NTTLIST);
+       DeleteHash(&nttlist);
+        end_critical_section(S_NTTLIST);
+}
 
 
 
@@ -368,6 +361,12 @@ void cmd_oimg(char *cmdbuf)
                return;
        }
        rv = fread(&MimeTestBuf[0], 1, 32, CC->download_fp);
+       if (rv == -1) {
+               cprintf("%d Cannot access %s: %s\n",
+                       ERROR + FILE_NOT_FOUND, pathname, strerror(errno));
+               return;
+       }
+
        rewind (CC->download_fp);
        OpenCmdResult(pathname, GuessMimeType(&MimeTestBuf[0], 32));
 }
@@ -569,6 +568,7 @@ void cmd_ucls(char *cmd)
 {
        FILE *fp;
        char upload_notice[512];
+       static int seq = 0;
 
        if (CC->upload_fp == NULL) {
                cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
@@ -579,11 +579,31 @@ void cmd_ucls(char *cmd)
        CC->upload_fp = NULL;
 
        if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) {
-               CC->upload_type = UPL_FILE;
                cprintf("%d Upload completed.\n", CIT_OK);
 
-               /* FIXME ... here we need to trigger a network run */
+               if (CC->upload_type == UPL_NET) {
+                       char final_filename[PATH_MAX];
+                       snprintf(final_filename, sizeof final_filename,
+                               "%s/%s.%04lx.%04x",
+                               ctdl_netin_dir,
+                               CC->net_node,
+                               (long)getpid(),
+                               ++seq
+                       );
+
+                       if (link(CC->upl_path, final_filename) == 0) {
+                               unlink(CC->upl_path);
+                       }
+                       else {
+                               syslog(LOG_ALERT, "Cannot link %s to %s: %s\n",
+                                       CC->upl_path, final_filename, strerror(errno)
+                               );
+                       }
 
+                       /* FIXME ... here we need to trigger a network run */
+               }
+
+               CC->upload_type = UPL_FILE;
                return;
        }
 
@@ -615,7 +635,6 @@ void cmd_ucls(char *cmd)
 }
 
 
-
 /*
  * read from the download file
  */
@@ -623,9 +642,9 @@ void cmd_read(char *cmdbuf)
 {
        long start_pos;
        size_t bytes;
-       size_t actual_bytes;
-       char *buf = NULL;
+       char buf[SIZ];
 
+       /* The client will transmit its requested offset and byte count */
        start_pos = extract_long(cmdbuf, 0);
        bytes = extract_int(cmdbuf, 1);
 
@@ -635,26 +654,24 @@ void cmd_read(char *cmdbuf)
                return;
        }
 
-       buf = mmap(NULL, 
-                  CC->download_fp_total, 
-                  PROT_READ, 
-                  MAP_PRIVATE,
-                  fileno(CC->download_fp), 
-                  0);
-       
-       actual_bytes = CC->download_fp_total - start_pos;
-       if ((actual_bytes > 0) && (buf != NULL)) {
-               cprintf("%d %d\n", BINARY_FOLLOWS, (int)actual_bytes);
-               client_write(buf + start_pos, actual_bytes);
+       /* If necessary, reduce the byte count to the size of our buffer */
+       if (bytes > sizeof(buf)) {
+               bytes = sizeof(buf);
+       }
+
+       fseek(CC->download_fp, start_pos, 0);
+       bytes = fread(buf, 1, bytes, CC->download_fp);
+       if (bytes > 0) {
+               /* Tell the client the actual byte count and transmit it */
+               cprintf("%d %d\n", BINARY_FOLLOWS, (int)bytes);
+               client_write(bufbytes);
        }
        else {
                cprintf("%d %s\n", ERROR, strerror(errno));
        }
-       munmap(buf, CC->download_fp_total);
 }
 
 
-
 /*
  * write to the upload file
  */
@@ -683,6 +700,10 @@ void cmd_writ(char *cmdbuf)
        buf = malloc(bytes + 1);
        client_read(buf, bytes);
        rv = fwrite(buf, bytes, 1, CC->upload_fp);
+       if (rv == -1) {
+               syslog(LOG_EMERG, "Couldn't write: %s\n",
+                      strerror(errno));
+       }
        free(buf);
 }
 
@@ -761,7 +782,7 @@ void cmd_nuop(char *cmdbuf)
 
        snprintf(CC->upl_path, sizeof CC->upl_path,
                         "%s/%s.%04lx.%04x",
-                        ctdl_netin_dir,
+                        ctdl_nettmp_dir,
                         CC->net_node, 
                         (long)getpid(), 
                         ++seq);
@@ -794,19 +815,20 @@ void cmd_nuop(char *cmdbuf)
 CTDL_MODULE_INIT(file_ops)
 {
        if (!threading) {
-               CtdlRegisterProtoHook(cmd_delf, "DELF", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_movf, "MOVF", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_open, "OPEN", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_clos, "CLOS", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_uopn, "UOPN", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_ucls, "UCLS", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_read, "READ", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_writ, "WRIT", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_oimg, "OIMG", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_ndop, "NDOP", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_nuop, "NUOP", "Autoconverted. TODO: document me.");
-               CtdlRegisterProtoHook(cmd_uimg, "UIMG", "Autoconverted. TODO: document me.");
+               CtdlRegisterProtoHook(cmd_delf, "DELF", "Delete a file");
+               CtdlRegisterProtoHook(cmd_movf, "MOVF", "Move a file");
+               CtdlRegisterProtoHook(cmd_open, "OPEN", "Open a download file transfer");
+               CtdlRegisterProtoHook(cmd_clos, "CLOS", "Close a download file transfer");
+               CtdlRegisterProtoHook(cmd_uopn, "UOPN", "Open an upload file transfer");
+               CtdlRegisterProtoHook(cmd_ucls, "UCLS", "Close an upload file transfer");
+               CtdlRegisterProtoHook(cmd_read, "READ", "File transfer read operation");
+               CtdlRegisterProtoHook(cmd_writ, "WRIT", "File transfer write operation");
+               CtdlRegisterProtoHook(cmd_ndop, "NDOP", "Open a network spool file for download");
+               CtdlRegisterProtoHook(cmd_nuop, "NUOP", "Open a network spool file for upload");
+               CtdlRegisterProtoHook(cmd_oimg, "OIMG", "Open an image file for download");
+               CtdlRegisterProtoHook(cmd_uimg, "UIMG", "Upload an image file");
+               CtdlRegisterCleanupHook(cleanup_nttlist);
        }
         /* return our Subversion id for the Log */
-       return "$Id$";
+       return "file_ops";
 }