FDIO: check for double freeing of an FDIO resource to fix possible double close ...
[citadel.git] / libcitadel / lib / stringbuf.c
index 3e81aac65efa992a96496250c6668201e848e391..9bc1c8eb04aa9015ab7f5d62abdd50fe5b2d0175 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1987-2011 by the citadel.org team
+ * Copyright (c) 1987-2013 by the citadel.org team
  *
  * This program is open source software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,8 +40,8 @@
 #include <execinfo.h>
 #endif
 
-#ifdef LINUX_SENDFILE
-#include <sys/sendfile.h>
+#ifdef UNDEF_MEMCPY
+#undef memcpy
 #endif
 
 #ifdef HAVE_ZLIB
@@ -50,6 +50,7 @@ int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen,
                           const Bytef * source, uLong sourceLen, int level);
 #endif
 int BaseStrBufSize = 64;
+int EnableSplice = 0;
 
 const char *StrBufNOTNULL = ((char*) NULL) - 1;
 
@@ -361,7 +362,12 @@ long StrBufShrinkToFit(StrBuf *Buf, int Force)
        if (Force || 
            (Buf->BufUsed + (Buf->BufUsed / 3) > Buf->BufSize))
        {
-               char *TmpBuf = (char*) malloc(Buf->BufUsed + 1);
+               char *TmpBuf;
+
+               TmpBuf = (char*) malloc(Buf->BufUsed + 1);
+               if (TmpBuf == NULL)
+                       return -1;
+
                memcpy (TmpBuf, Buf->buf, Buf->BufUsed + 1);
                Buf->BufSize = Buf->BufUsed + 1;
                free(Buf->buf);
@@ -380,7 +386,15 @@ StrBuf* NewStrBuf(void)
        StrBuf *NewBuf;
 
        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+       if (NewBuf == NULL)
+               return NULL;
+
        NewBuf->buf = (char*) malloc(BaseStrBufSize);
+       if (NewBuf->buf == NULL)
+       {
+               free(NewBuf);
+               return NULL;
+       }
        NewBuf->buf[0] = '\0';
        NewBuf->BufSize = BaseStrBufSize;
        NewBuf->BufUsed = 0;
@@ -405,7 +419,16 @@ StrBuf* NewStrBufDup(const StrBuf *CopyMe)
                return NewStrBuf();
 
        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+       if (NewBuf == NULL)
+               return NULL;
+
        NewBuf->buf = (char*) malloc(CopyMe->BufSize);
+       if (NewBuf->buf == NULL)
+       {
+               free(NewBuf);
+               return NULL;
+       }
+
        memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
        NewBuf->BufUsed = CopyMe->BufUsed;
        NewBuf->BufSize = CopyMe->BufSize;
@@ -501,6 +524,9 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars)
        size_t CopySize;
 
        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+       if (NewBuf == NULL)
+               return NULL;
+
        if (nChars < 0)
                CopySize = strlen((ptr != NULL)?ptr:"");
        else
@@ -594,6 +620,8 @@ StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
        StrBuf *NewBuf;
 
        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+       if (NewBuf == NULL)
+               return NULL;
        NewBuf->buf = (char*) StringConstant;
        NewBuf->BufSize = SizeOfStrConstant;
        NewBuf->BufUsed = SizeOfStrConstant;
@@ -1022,16 +1050,18 @@ int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t n
        }
        if (Offset + nChars < Source->BufUsed)
        {
-               if (nChars >= dest->BufSize)
-                       IncreaseBuf(dest, 0, nChars + 1);
+               if ((nChars >= dest->BufSize) && 
+                   (IncreaseBuf(dest, 0, nChars + 1) == -1))
+                       return 0;
                memcpy(dest->buf, Source->buf + Offset, nChars);
                dest->BufUsed = nChars;
                dest->buf[dest->BufUsed] = '\0';
                return nChars;
        }
        NCharsRemain = Source->BufUsed - Offset;
-       if (NCharsRemain  >= dest->BufSize)
-               IncreaseBuf(dest, 0, NCharsRemain + 1);
+       if ((NCharsRemain  >= dest->BufSize) && 
+           (IncreaseBuf(dest, 0, NCharsRemain + 1) == -1))
+               return 0;
        memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
        dest->BufUsed = NCharsRemain;
        dest->buf[dest->BufUsed] = '\0';
@@ -1143,29 +1173,31 @@ void StrBufSpaceToBlank(StrBuf *Buf)
 
 void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
 {
-       const char *pBuff;
        const char *pLeft;
        const char *pRight;
 
-       if ((Buf == NULL) || (Buf->buf == NULL))
+       if ((Buf == NULL) || (Buf->buf == NULL)) {
+               StrBufCutAt(Buf, 0, Buf->buf);
                return;
-       pLeft = pBuff = Buf->buf;
-       while (pBuff != NULL) {
-               pLeft = pBuff;
-               pBuff = strchr(pBuff, leftboundary);
-               if (pBuff != NULL)
-                       pBuff++;
        }
-               
-       if (pLeft != NULL)
-               pBuff = pLeft;
-       else
-               pBuff = Buf->buf;
-       pRight = strchr(pBuff, rightboundary);
-       if (pRight != NULL)
+
+       pRight = strchr(Buf->buf, rightboundary);
+       if (pRight != NULL) {
                StrBufCutAt(Buf, 0, pRight);
-       if (pLeft != NULL)
-               StrBufCutLeft(Buf, pLeft - Buf->buf);
+       }
+       else {
+               StrBufCutAt(Buf, 0, Buf->buf);
+               return;
+       }
+
+       pLeft = strrchr(ChrPtr(Buf), leftboundary);
+       if (pLeft != NULL) {
+               StrBufCutLeft(Buf, pLeft - Buf->buf + 1);
+       }
+       else {
+               StrBufCutAt(Buf, 0, Buf->buf);
+               return;
+       }
 }
 
 
@@ -2510,6 +2542,23 @@ long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *Plai
        return Target->BufUsed;
 }
 
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief replace all non-Ascii characters by another
+ * @param Buf buffer to inspect
+ * @param repl charater to stamp over non ascii chars
+ */
+void StrBufAsciify(StrBuf *Buf, const char repl)
+{
+       long offset;
+
+       for (offset = 0; offset < Buf->BufUsed; offset ++)
+               if (!isascii(Buf->buf[offset]))
+                       Buf->buf[offset] = repl;
+       
+}
+
 /**
  * @ingroup StrBuf_DeEnCoder
  * @brief unhide special chars hidden to the HTML escaper
@@ -2603,9 +2652,14 @@ int StrBufDecodeBase64(StrBuf *Buf)
 {
        char *xferbuf;
        size_t siz;
-       if (Buf == NULL) return -1;
+
+       if (Buf == NULL)
+               return -1;
 
        xferbuf = (char*) malloc(Buf->BufSize);
+       if (xferbuf == NULL)
+               return -1;
+
        *xferbuf = '\0';
        siz = CtdlDecodeBase64(xferbuf,
                               Buf->buf,
@@ -3886,24 +3940,32 @@ void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize)
        FDB->ChunkSize = 
                FDB->TotalSendSize = TotalSendSize;
        FDB->IOB = IO;
-#ifndef LINUX_SPLICE
-       FDB->ChunkBuffer = NewStrBufPlain(NULL, TotalSendSize + 1);
-#else
-       pipe(FDB->SplicePipe);
+#ifdef LINUX_SPLICE
+       if (EnableSplice)
+               pipe(FDB->SplicePipe);
+       else
 #endif
+               FDB->ChunkBuffer = NewStrBufPlain(NULL, TotalSendSize + 1);
+
        FDB->OtherFD = FD;
 }
 
 void FDIOBufferDelete(FDIOBuffer *FDB)
 {
-#ifndef LINUX_SPLICE
-       FreeStrBuf(&FDB->ChunkBuffer);
-#else
-       close(FDB->SplicePipe[0]);
-       close(FDB->SplicePipe[1]);
-       
+#ifdef LINUX_SPLICE
+       if (EnableSplice)
+       {
+               if (FDB->SplicePipe[0] > 0)
+                       close(FDB->SplicePipe[0]);
+               if (FDB->SplicePipe[1] > 0)
+                       close(FDB->SplicePipe[1]);
+       }
+       else
 #endif
-       close(FDB->OtherFD);
+               FreeStrBuf(&FDB->ChunkBuffer);
+       
+       if (FDB->OtherFD > 0)
+               close(FDB->OtherFD);
        memset(FDB, 0, sizeof(FDIOBuffer));     
 }
 
@@ -3911,65 +3973,69 @@ int FileSendChunked(FDIOBuffer *FDB, const char **Err)
 {
        ssize_t sent, pipesize;
 #ifdef LINUX_SPLICE
-       if (FDB->PipeSize == 0)
+       if (EnableSplice)
        {
-               pipesize = splice(FDB->OtherFD,
-                                 &FDB->TotalSentAlready, 
-                                 FDB->SplicePipe[1],
-                                 NULL, 
-                                 FDB->ChunkSendRemain, 
-                                 SPLICE_F_MOVE);
+               if (FDB->PipeSize == 0)
+               {
+                       pipesize = splice(FDB->OtherFD,
+                                         &FDB->TotalSentAlready, 
+                                         FDB->SplicePipe[1],
+                                         NULL, 
+                                         FDB->ChunkSendRemain, 
+                                         SPLICE_F_MOVE);
        
-               if (pipesize == -1)
+                       if (pipesize == -1)
+                       {
+                               *Err = strerror(errno);
+                               return pipesize;
+                       }
+                       FDB->PipeSize = pipesize;
+               }
+               sent =  splice(FDB->SplicePipe[0],
+                              NULL, 
+                              FDB->IOB->fd,
+                              NULL, 
+                              FDB->PipeSize,
+                              SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
+               if (sent == -1)
                {
                        *Err = strerror(errno);
-                       return pipesize;
+                       return sent;
                }
-               FDB->PipeSize = pipesize;
-       }
-       sent =  splice(FDB->SplicePipe[0],
-                      NULL, 
-                      FDB->IOB->fd,
-                      NULL, 
-                      FDB->PipeSize,
-                      SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
-       if (sent == -1)
-       {
-               *Err = strerror(errno);
+               FDB->PipeSize -= sent;
+               FDB->ChunkSendRemain -= sent;
                return sent;
        }
-       FDB->PipeSize -= sent;
-       FDB->ChunkSendRemain -= sent;
-       return sent;
-#else
-
-       char *pRead;
-       long nRead = 0;
-
-       pRead = FDB->ChunkBuffer->buf;
-       while ((FDB->ChunkBuffer->BufUsed < FDB->TotalSendSize) && (nRead >= 0))
+       else
+#endif
        {
-               nRead = read(FDB->OtherFD, pRead, FDB->TotalSendSize - FDB->ChunkBuffer->BufUsed);
-               if (nRead > 0) {
-                       FDB->ChunkBuffer->BufUsed += nRead;
-                       FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0';
-               }
-               else if (nRead == 0) {}
-               else return nRead;
+               char *pRead;
+               long nRead = 0;
+
+               pRead = FDB->ChunkBuffer->buf;
+               while ((FDB->ChunkBuffer->BufUsed < FDB->TotalSendSize) && (nRead >= 0))
+               {
+                       nRead = read(FDB->OtherFD, pRead, FDB->TotalSendSize - FDB->ChunkBuffer->BufUsed);
+                       if (nRead > 0) {
+                               FDB->ChunkBuffer->BufUsed += nRead;
+                               FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0';
+                       }
+                       else if (nRead == 0) {}
+                       else return nRead;
                
-       }
+               }
 
-       nRead = write(FDB->IOB->fd, FDB->ChunkBuffer->buf + FDB->TotalSentAlready, FDB->ChunkSendRemain);
+               nRead = write(FDB->IOB->fd, FDB->ChunkBuffer->buf + FDB->TotalSentAlready, FDB->ChunkSendRemain);
 
-       if (nRead >= 0) {
-               FDB->TotalSentAlready += nRead;
-               FDB->ChunkSendRemain -= nRead;
-               return FDB->ChunkSendRemain;
-       }
-       else {
-               return nRead;
+               if (nRead >= 0) {
+                       FDB->TotalSentAlready += nRead;
+                       FDB->ChunkSendRemain -= nRead;
+                       return FDB->ChunkSendRemain;
+               }
+               else {
+                       return nRead;
+               }
        }
-#endif
 }
 
 int FileRecvChunked(FDIOBuffer *FDB, const char **Err)
@@ -3977,68 +4043,71 @@ int FileRecvChunked(FDIOBuffer *FDB, const char **Err)
        ssize_t sent, pipesize;
 
 #ifdef LINUX_SPLICE
-       if (FDB->PipeSize == 0)
+       if (EnableSplice)
        {
-               pipesize = splice(FDB->IOB->fd,
-                                 NULL, 
-                                 FDB->SplicePipe[1],
-                                 NULL, 
-                                 FDB->ChunkSendRemain, 
-                                 SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
-
-               if (pipesize == -1)
+               if (FDB->PipeSize == 0)
                {
-                       *Err = strerror(errno);
-                       return pipesize;
+                       pipesize = splice(FDB->IOB->fd,
+                                         NULL, 
+                                         FDB->SplicePipe[1],
+                                         NULL, 
+                                         FDB->ChunkSendRemain, 
+                                         SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
+
+                       if (pipesize == -1)
+                       {
+                               *Err = strerror(errno);
+                               return pipesize;
+                       }
+                       FDB->PipeSize = pipesize;
                }
-               FDB->PipeSize = pipesize;
-       }
        
-       sent = splice(FDB->SplicePipe[0],
-                     NULL, 
-                     FDB->OtherFD,
-                     &FDB->TotalSentAlready, 
-                     FDB->PipeSize,
-                     SPLICE_F_MORE | SPLICE_F_MOVE);
-
-       if (sent == -1)
-       {
-               *Err = strerror(errno);
+               sent = splice(FDB->SplicePipe[0],
+                             NULL, 
+                             FDB->OtherFD,
+                             &FDB->TotalSentAlready, 
+                             FDB->PipeSize,
+                             SPLICE_F_MORE | SPLICE_F_MOVE);
+
+               if (sent == -1)
+               {
+                       *Err = strerror(errno);
+                       return sent;
+               }
+               FDB->PipeSize -= sent;
+               FDB->ChunkSendRemain -= sent;
                return sent;
        }
-       FDB->PipeSize -= sent;
-       FDB->ChunkSendRemain -= sent;
-       return sent;
-#else
-       
-       sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
-       if (sent > 0) {
-               int nWritten = 0;
-               int rc; 
+       else
+#endif
+       {
+               sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
+               if (sent > 0) {
+                       int nWritten = 0;
+                       int rc; 
                
-               FDB->ChunkBuffer->BufUsed = sent;
+                       FDB->ChunkBuffer->BufUsed = sent;
 
-               while (nWritten < FDB->ChunkBuffer->BufUsed) {
-                       rc =  write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
-                       if (rc < 0) {
-                               *Err = strerror(errno);
-                               return rc;
-                       }
-                       nWritten += rc;
+                       while (nWritten < FDB->ChunkBuffer->BufUsed) {
+                               rc =  write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
+                               if (rc < 0) {
+                                       *Err = strerror(errno);
+                                       return rc;
+                               }
+                               nWritten += rc;
 
+                       }
+                       FDB->ChunkBuffer->BufUsed = 0;
+                       FDB->TotalSentAlready += sent;
+                       FDB->ChunkSendRemain -= sent;
+                       return FDB->ChunkSendRemain;
                }
-               FDB->ChunkBuffer->BufUsed = 0;
-               FDB->TotalSentAlready += sent;
-               FDB->ChunkSendRemain -= sent;
-               return FDB->ChunkSendRemain;
-       }
-       else if (sent < 0) {
-               *Err = strerror(errno);
-               return sent;
+               else if (sent < 0) {
+                       *Err = strerror(errno);
+                       return sent;
+               }
+               return 0;
        }
-
-#endif
-       return 0;
 }
 
 int FileMoveChunked(FDIOBuffer *FDB, const char **Err)
@@ -4046,68 +4115,71 @@ int FileMoveChunked(FDIOBuffer *FDB, const char **Err)
        ssize_t sent, pipesize;
 
 #ifdef LINUX_SPLICE
-       if (FDB->PipeSize == 0)
+       if (EnableSplice)
        {
-               pipesize = splice(FDB->IOB->fd,
-                                 &FDB->TotalReadAlready, 
-                                 FDB->SplicePipe[1],
-                                 NULL, 
-                                 FDB->ChunkSendRemain, 
-                                 SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
-
-               if (pipesize == -1)
+               if (FDB->PipeSize == 0)
+               {
+                       pipesize = splice(FDB->IOB->fd,
+                                         &FDB->TotalReadAlready, 
+                                         FDB->SplicePipe[1],
+                                         NULL, 
+                                         FDB->ChunkSendRemain, 
+                                         SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
+                       
+                       if (pipesize == -1)
+                       {
+                               *Err = strerror(errno);
+                               return pipesize;
+                       }
+                       FDB->PipeSize = pipesize;
+               }
+               
+               sent = splice(FDB->SplicePipe[0],
+                             NULL, 
+                             FDB->OtherFD,
+                             &FDB->TotalSentAlready, 
+                             FDB->PipeSize,
+                             SPLICE_F_MORE | SPLICE_F_MOVE);
+               
+               if (sent == -1)
                {
                        *Err = strerror(errno);
-                       return pipesize;
+                       return sent;
                }
-               FDB->PipeSize = pipesize;
-       }
-       
-       sent = splice(FDB->SplicePipe[0],
-                     NULL, 
-                     FDB->OtherFD,
-                     &FDB->TotalSentAlready, 
-                     FDB->PipeSize,
-                     SPLICE_F_MORE | SPLICE_F_MOVE);
-
-       if (sent == -1)
-       {
-               *Err = strerror(errno);
+               FDB->PipeSize -= sent;
+               FDB->ChunkSendRemain -= sent;
                return sent;
        }
-       FDB->PipeSize -= sent;
-       FDB->ChunkSendRemain -= sent;
-       return sent;
-#else
-       
-       sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
-       if (sent > 0) {
-               int nWritten = 0;
-               int rc; 
+       else
+#endif 
+       {
+               sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
+               if (sent > 0) {
+                       int nWritten = 0;
+                       int rc; 
                
-               FDB->ChunkBuffer->BufUsed = sent;
+                       FDB->ChunkBuffer->BufUsed = sent;
 
-               while (nWritten < FDB->ChunkBuffer->BufUsed) {
-                       rc =  write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
-                       if (rc < 0) {
-                               *Err = strerror(errno);
-                               return rc;
-                       }
-                       nWritten += rc;
+                       while (nWritten < FDB->ChunkBuffer->BufUsed) {
+                               rc =  write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
+                               if (rc < 0) {
+                                       *Err = strerror(errno);
+                                       return rc;
+                               }
+                               nWritten += rc;
 
+                       }
+                       FDB->ChunkBuffer->BufUsed = 0;
+                       FDB->TotalSentAlready += sent;
+                       FDB->ChunkSendRemain -= sent;
+                       return FDB->ChunkSendRemain;
                }
-               FDB->ChunkBuffer->BufUsed = 0;
-               FDB->TotalSentAlready += sent;
-               FDB->ChunkSendRemain -= sent;
-               return FDB->ChunkSendRemain;
-       }
-       else if (sent < 0) {
-               *Err = strerror(errno);
-               return sent;
+               else if (sent < 0) {
+                       *Err = strerror(errno);
+                       return sent;
+               }
+               return 0;
        }
-
-#endif
-       return 0;
 }
 
 eReadState WriteIOBAlreadyRead(FDIOBuffer *FDB, const char **Error)
@@ -4300,10 +4372,11 @@ int StrBufTCP_read_buffered_line(StrBuf *Line,
                        nSuccessLess = 0;
                        buf->BufUsed += rlen;
                        buf->buf[buf->BufUsed] = '\0';
-                       if (buf->BufUsed + 10 > buf->BufSize) {
-                               IncreaseBuf(buf, 1, -1);
-                       }
                        pch = strchr(buf->buf, '\n');
+                       if ((pch == NULL) &&
+                           (buf->BufUsed + 10 > buf->BufSize) &&
+                           (IncreaseBuf(buf, 1, -1) == -1))
+                               return -1;
                        continue;
                }
                
@@ -4493,6 +4566,10 @@ int StrBufTCP_read_buffered_line_fast(StrBuf *Line,
 
                        continue;
                }
+               else
+               {
+                       nSuccessLess++;
+               }
        }
        *Pos = NULL;
        if (pLF != NULL) {
@@ -4629,9 +4706,12 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
        int nSuccessLess = 0;
        int MaxTries;
 
-       if ((Blob == NULL) || (*fd == -1) || (IOBuf == NULL) || (Pos == NULL))
+       if ((Blob == NULL)  ||
+           (*fd == -1)     ||
+           (IOBuf == NULL) ||
+           (Pos == NULL))
        {
-               if (*Pos != NULL)
+               if (Pos != NULL)
                        *Pos = NULL;
                *Error = ErrRBB_BLOBFPreConditionFailed;
                return -1;