* cmd_snet: make shure the target FS has enough space for the new config
authorWilfried Goesgens <dothebart@citadel.org>
Sat, 30 Oct 2010 16:44:15 +0000 (18:44 +0200)
committerWilfried Goesgens <dothebart@citadel.org>
Mon, 1 Nov 2010 09:55:48 +0000 (10:55 +0100)
 - Create our own filename insteaf of using mk*tmp*; CC->cs_pid should be uniq.; we use  O_CREAT|O_EXCL so we're shure its ours or fails.
 - Create that filename in the same directory as the filal config filename; by that we can be shure its in the same filesystem, and if thats full, we will fail
 - Stat the original file for sise (if not there assume 80) and write twice as much into that file so we're next to shure the content from the client will fit in
 - the citadel protocol is a little st00pit here, we don't know the size in advance, and we can't return an error _after_ accepting the file
 - instead of moving the content of the tempfile into the final file, we use rename() which is supposed to be atomic.

citadel/modules/network/serv_network.c

index e89f26eec7b78c03e21d0efe98a82a877a0fffd1..7b8224dd8b1f8ae3116aa0426d51a9d61d355981 100644 (file)
@@ -405,8 +405,11 @@ void cmd_gnet(char *argbuf) {
 void cmd_snet(char *argbuf) {
        char tempfilename[PATH_MAX];
        char filename[PATH_MAX];
-       char buf[SIZ];
-       FILE *fp, *newfp;
+       int TmpFD;
+       StrBuf *Line;
+       struct stat StatBuf;
+       long len;
+       int rc;
 
        unbuffer_output();
 
@@ -415,40 +418,66 @@ void cmd_snet(char *argbuf) {
        }
        else if (CtdlAccessCheck(ac_room_aide)) return;
 
-       CtdlMakeTempFileName(tempfilename, sizeof tempfilename);
-       assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
+       len = assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
+       memcpy(tempfilename, filename, len + 1);
 
-       fp = fopen(tempfilename, "w");
-       if (fp == NULL) {
-               cprintf("%d Cannot open %s: %s\n",
+       memset(&StatBuf, 0, sizeof(struct stat));
+       if (stat(filename, &StatBuf)  == -1)
+               StatBuf.st_size = 80; /* Not there? guess 80 chars line. */
+
+       sprintf(tempfilename + len, ".%d", CC->cs_pid);
+
+       TmpFD = open(tempfilename, O_CREAT|O_EXCL);
+
+       if (TmpFD > 0)
+       {
+               char *tmp = malloc(StatBuf.st_size * 2);
+               memset(tmp, 0, StatBuf.st_size * 2);
+               rc = write(TmpFD, tmp, StatBuf.st_size * 2);
+               free(tmp);
+               if (rc <= 0)
+               {
+                       close(TmpFD);
+                       cprintf("%d Unable to allocate the space required for %s: %s\n",
+                               ERROR + INTERNAL_ERROR,
+                               tempfilename,
+                               strerror(errno));
+                       return;
+               }       
+               lseek(TmpFD, SEEK_SET, 0);
+       }
+       else {
+               cprintf("%d Unable to allocate the space required for %s: %s\n",
                        ERROR + INTERNAL_ERROR,
                        tempfilename,
                        strerror(errno));
+
+
        }
+       Line = NewStrBuf();
 
        cprintf("%d %s\n", SEND_LISTING, tempfilename);
-       while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
-               fprintf(fp, "%s\n", buf);
+
+       len = 0;
+       while (rc = CtdlClientGetLine(Line), 
+              (rc >= 0))
+       {
+               if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0))
+                       break;
+               StrBufAppendBufPlain(Line, HKEY("\n"), 0);
+               write(TmpFD, ChrPtr(Line), StrLength(Line));
+               len += StrLength(Line);
        }
-       fclose(fp);
+       FreeStrBuf(&Line);
+       ftruncate(TmpFD, len + 1);
+       close(TmpFD);
 
        /* Now copy the temp file to its permanent location.
         * (We copy instead of link because they may be on different filesystems)
         */
        begin_critical_section(S_NETCONFIGS);
-       fp = fopen(tempfilename, "r");
-       if (fp != NULL) {
-               newfp = fopen(filename, "w");
-               if (newfp != NULL) {
-                       while (fgets(buf, sizeof buf, fp) != NULL) {
-                               fprintf(newfp, "%s", buf);
-                       }
-                       fclose(newfp);
-               }
-               fclose(fp);
-       }
+       rename(filename, tempfilename);
        end_critical_section(S_NETCONFIGS);
-       unlink(tempfilename);
 }