Commit 20dcf6d0a for imagemagick.org

commit 20dcf6d0aae2ca1d8a263f5855808d6ff7f0b1e3
Author: Cristy <urban-warrior@imagemagick.org>
Date:   Sat Jul 18 12:06:01 2026 -0400

    safe read/write

diff --git a/MagickCore/blob.c b/MagickCore/blob.c
index f8b340738..346f4b0f2 100644
--- a/MagickCore/blob.c
+++ b/MagickCore/blob.c
@@ -395,14 +395,10 @@ MagickExport MagickBooleanType BlobToFile(char *filename,const void *blob,
     }
   for (i=0; i < length; i+=(size_t) count)
   {
-    count=write(file,(const char *) blob+i,MagickMin(length-i,(size_t)
+    count=MagickWrite(file,(const char *) blob+i,MagickMin(length-i,(size_t)
       MagickMaxBufferExtent));
     if (count <= 0)
-      {
-        count=0;
-        if (errno != EINTR)
-          break;
-      }
+      break;
   }
   file=close_utf8(file);
   if ((file == -1) || (i < length))
@@ -1502,13 +1498,9 @@ MagickExport void *FileToBlob(const char *filename,const size_t extent,
       blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
       for (i=0; blob != (unsigned char *) NULL; i+=(size_t) count)
       {
-        count=read(file,blob+i,quantum);
+        count=MagickRead(file,blob+i,quantum);
         if (count <= 0)
-          {
-            count=0;
-            if (errno != EINTR)
-              break;
-          }
+          break;
         if (~i < ((size_t) count+quantum+1))
           {
             blob=(unsigned char *) RelinquishMagickMemory(blob);
@@ -1561,14 +1553,10 @@ MagickExport void *FileToBlob(const char *filename,const size_t extent,
       (void) lseek(file,0,SEEK_SET);
       for (i=0; i < *length; i+=(size_t) count)
       {
-        count=read(file,blob+i,(size_t) MagickMin(*length-i,(size_t)
+        count=MagickRead(file,blob+i,(size_t) MagickMin(*length-i,(size_t)
           MagickMaxBufferExtent));
         if (count <= 0)
-          {
-            count=0;
-            if (errno != EINTR)
-              break;
-          }
+          break;
       }
       if (i < *length)
         {
@@ -1707,13 +1695,9 @@ MagickExport MagickBooleanType FileToImage(Image *image,const char *filename,
     }
   for ( ; ; )
   {
-    count=read(file,blob,quantum);
+    count=MagickRead(file,blob,quantum);
     if (count <= 0)
-      {
-        count=0;
-        if (errno != EINTR)
-          break;
-      }
+      break;
     length=(size_t) count;
     count=WriteBlobStream(image,length,blob);
     if (count != (ssize_t) length)
@@ -2401,13 +2385,9 @@ MagickExport MagickBooleanType ImageToFile(Image *image,char *filename,
     length=(size_t) count;
     for (i=0; i < length; i+=(size_t) count)
     {
-      count=write(file,p+i,(size_t) (length-i));
+      count=MagickWrite(file,p+i,(size_t) (length-i));
       if (count <= 0)
-        {
-          count=0;
-          if (errno != EINTR)
-            break;
-        }
+        break;
     }
     if (i < length)
       break;
diff --git a/MagickCore/cache.c b/MagickCore/cache.c
index 8bb81d542..81f280d17 100644
--- a/MagickCore/cache.c
+++ b/MagickCore/cache.c
@@ -668,10 +668,7 @@ static MagickBooleanType ClonePixelCacheOnDisk(

     length=(size_t) MagickMin((MagickSizeType) quantum,cache_info->length-
       extent);
-    do
-    {
-      count=read(cache_info->file,buffer,length);
-    } while ((count < 0) && (errno == EINTR));
+    count=MagickRead(cache_info->file,buffer,length);
     if (count <= 0)
       {
         buffer=(unsigned char *) RelinquishMagickMemory(buffer);
@@ -684,11 +681,8 @@ static MagickBooleanType ClonePixelCacheOnDisk(

       while (offset < count)
       {
-        do
-        {
-          number_bytes=write(clone_info->file,buffer+offset,(size_t) (count-
-            offset));
-        } while ((number_bytes < 0) && (errno == EINTR));
+        number_bytes=MagickWrite(clone_info->file,buffer+offset,(size_t) (count-
+          offset));
         if (number_bytes <= 0)
           {
             buffer=(unsigned char *) RelinquishMagickMemory(buffer);
@@ -3685,25 +3679,14 @@ static inline MagickOffsetType WritePixelCacheRegion(
   ssize_t
     count = 0;

-#if !defined(MAGICKCORE_HAVE_PWRITE)
   if (lseek(cache_info->file,offset,SEEK_SET) < 0)
     return((MagickOffsetType) -1);
-#endif
   for (i=0; i < (MagickOffsetType) length; i+=count)
   {
-#if !defined(MAGICKCORE_HAVE_PWRITE)
-    count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-
+    count=MagickWrite(cache_info->file,buffer+i,(size_t) MagickMin(length-
       (MagickSizeType) i,MagickMaxBufferExtent));
-#else
-    count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-
-      (MagickSizeType) i,MagickMaxBufferExtent),offset+i);
-#endif
     if (count <= 0)
-      {
-        count=0;
-        if (errno != EINTR)
-          break;
-      }
+      break;
   }
   return(i);
 }
@@ -4560,25 +4543,14 @@ static inline MagickOffsetType ReadPixelCacheRegion(
   ssize_t
     count = 0;

-#if !defined(MAGICKCORE_HAVE_PREAD)
   if (lseek(cache_info->file,offset,SEEK_SET) < 0)
     return((MagickOffsetType) -1);
-#endif
   for (i=0; i < (MagickOffsetType) length; i+=count)
   {
-#if !defined(MAGICKCORE_HAVE_PREAD)
-    count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-
+    count=MagickRead(cache_info->file,buffer+i,(size_t) MagickMin(length-
       (MagickSizeType) i,(size_t) MagickMaxBufferExtent));
-#else
-    count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-
-      (MagickSizeType) i,(size_t) MagickMaxBufferExtent),offset+i);
-#endif
     if (count <= 0)
-      {
-        count=0;
-        if (errno != EINTR)
-          break;
-      }
+      break;
   }
   return(i);
 }
diff --git a/MagickCore/distribute-cache.c b/MagickCore/distribute-cache.c
index a12b7e5f2..a7c981688 100644
--- a/MagickCore/distribute-cache.c
+++ b/MagickCore/distribute-cache.c
@@ -158,25 +158,24 @@ static inline MagickOffsetType dpc_read(SOCKET_TYPE magick_unused(file),
 static inline MagickOffsetType dpc_read(SOCKET_TYPE file,
   const MagickSizeType length,unsigned char *magick_restrict message)
 {
-  MagickOffsetType
-    i;
-
-  ssize_t
-    count;
-
-  count=0;
-  for (i=0; i < (MagickOffsetType) length; i+=count)
+  MagickOffsetType offset = 0;
+  while (offset < (MagickOffsetType) length)
   {
-    count=recv(file,(char *) message+i,(LENGTH_TYPE) MagickMin(length-
-      (MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),0);
-    if (count <= 0)
-      {
-        count=0;
-        if (errno != EINTR)
-          break;
-      }
+    MagickSizeType remaining = length-(MagickSizeType) offset;
+    ssize_t count = recv(file,(char *) message+offset,(LENGTH_TYPE)
+      MagickMin(remaining,(MagickSizeType) MagickMaxBufferExtent),0);
+    if (count > 0)
+      offset+=(MagickOffsetType) count;
+    else
+      if (count == 0)
+        break;
+      else
+        {
+          if (errno != EINTR)
+            continue;
+        }
   }
-  return(i);
+  return(offset);
 }
 #endif

diff --git a/MagickCore/matrix.c b/MagickCore/matrix.c
index c4a5f589a..077ff0f2d 100644
--- a/MagickCore/matrix.c
+++ b/MagickCore/matrix.c
@@ -142,34 +142,21 @@ static inline MagickOffsetType WriteMatrixElements(
   ssize_t
     count;

-#if !defined(MAGICKCORE_HAVE_PWRITE)
   LockSemaphoreInfo(matrix_info->semaphore);
   if (lseek(matrix_info->file,offset,SEEK_SET) < 0)
     {
       UnlockSemaphoreInfo(matrix_info->semaphore);
       return((MagickOffsetType) -1);
     }
-#endif
   count=0;
   for (i=0; i < (MagickOffsetType) length; i+=count)
   {
-#if !defined(MAGICKCORE_HAVE_PWRITE)
-    count=write(matrix_info->file,buffer+i,(size_t) MagickMin(length-
+    count=MagickWrite(matrix_info->file,buffer+i,(size_t) MagickMin(length-
       (MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent));
-#else
-    count=pwrite(matrix_info->file,buffer+i,(size_t) MagickMin(length-
-      (MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),offset+i);
-#endif
     if (count <= 0)
-      {
-        count=0;
-        if (errno != EINTR)
-          break;
-      }
+      break;
   }
-#if !defined(MAGICKCORE_HAVE_PWRITE)
   UnlockSemaphoreInfo(matrix_info->semaphore);
-#endif
   return(i);
 }

@@ -499,34 +486,21 @@ static inline MagickOffsetType ReadMatrixElements(
   ssize_t
     count;

-#if !defined(MAGICKCORE_HAVE_PREAD)
   LockSemaphoreInfo(matrix_info->semaphore);
   if (lseek(matrix_info->file,offset,SEEK_SET) < 0)
     {
       UnlockSemaphoreInfo(matrix_info->semaphore);
       return((MagickOffsetType) -1);
     }
-#endif
   count=0;
   for (i=0; i < (MagickOffsetType) length; i+=count)
   {
-#if !defined(MAGICKCORE_HAVE_PREAD)
-    count=read(matrix_info->file,buffer+i,(size_t) MagickMin(length-i,
+    count=MagickRead(matrix_info->file,buffer+i,(size_t) MagickMin(length-i,
       (MagickSizeType) MagickMaxBufferExtent));
-#else
-    count=pread(matrix_info->file,buffer+i,(size_t) MagickMin(length-
-      (MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),offset+i);
-#endif
     if (count <= 0)
-      {
-        count=0;
-        if (errno != EINTR)
-          break;
-      }
+      break;
   }
-#if !defined(MAGICKCORE_HAVE_PREAD)
   UnlockSemaphoreInfo(matrix_info->semaphore);
-#endif
   return(i);
 }

@@ -1064,7 +1038,7 @@ MagickExport MagickBooleanType NullMatrix(MatrixInfo *matrix_info)
   {
     for (x=0; x < (ssize_t) matrix_info->length; x++)
     {
-      count=write(matrix_info->file,&value,sizeof(value));
+      count=MagickWrite(matrix_info->file,&value,sizeof(value));
       if (count != (ssize_t) sizeof(value))
         break;
     }
diff --git a/MagickCore/memory.c b/MagickCore/memory.c
index 799541263..dfc8ee707 100644
--- a/MagickCore/memory.c
+++ b/MagickCore/memory.c
@@ -623,7 +623,7 @@ MagickExport void *AcquireCriticalMemory(const size_t size)
   memory=AcquireMagickMemory(size);
   if (memory != (void *) NULL)
     return(memory);
-  status=write(STDERR_FILENO,fatal_message,sizeof(fatal_message)-1);
+  status=MagickWrite(STDERR_FILENO,fatal_message,sizeof(fatal_message)-1);
   (void) status;
   MagickCoreTerminus();
   _exit(EXIT_FAILURE);
diff --git a/MagickCore/string.c b/MagickCore/string.c
index 85c303b54..5147d62e0 100644
--- a/MagickCore/string.c
+++ b/MagickCore/string.c
@@ -625,14 +625,10 @@ MagickExport StringInfo *ConfigureFileToStringInfo(const char *filename)
       (void) lseek(file,0,SEEK_SET);
       for (i=0; i < length; i+=(size_t) count)
       {
-        count=read(file,string+i,(size_t) MagickMin(length-i,(size_t)
+        count=MagickRead(file,string+i,(size_t) MagickMin(length-i,(size_t)
           MagickMaxBufferExtent));
         if (count <= 0)
-          {
-            count=0;
-            if (errno != EINTR)
-              break;
-          }
+          break;
       }
       if (i < length)
         {
diff --git a/MagickCore/utility-private.h b/MagickCore/utility-private.h
index 8242e5f1e..74e867353 100644
--- a/MagickCore/utility-private.h
+++ b/MagickCore/utility-private.h
@@ -49,15 +49,6 @@ extern MagickPrivate void
   ChopPathComponents(char *,const size_t),
   ExpandFilename(char *);

-static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
-  struct dirent **result)
-{
-  (void) entry;
-  errno=0;
-  *result=readdir(directory);
-  return(errno);
-}
-
 static inline int access_utf8(const char *path,int mode)
 {
   if (path == (const char *) NULL)
@@ -102,6 +93,55 @@ static inline MagickBooleanType is_symlink_utf8(const char *path)
 #endif
 }

+static inline ssize_t MagickRead(int fd,void *buffer,size_t extent)
+{
+  unsigned char *p = (unsigned char *) buffer;
+  size_t offset = 0;
+  while (offset < extent)
+  {
+    ssize_t count = read(fd,p+offset,extent-offset);
+    if (count < 0)
+      {
+        if (errno == EINTR)
+          continue;
+        return(-1);
+      }
+    if (count == 0)
+      break;
+    offset+=(size_t) count;
+  }
+  return((ssize_t) offset);
+}
+
+static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
+  struct dirent **result)
+{
+  (void) entry;
+  errno=0;
+  *result=readdir(directory);
+  return(errno);
+}
+
+static inline ssize_t MagickWrite(int fd,const void *buffer,size_t extent)
+{
+  const unsigned char *p = (const unsigned char *) buffer;
+  size_t offset = 0;
+  while (offset < extent)
+  {
+    ssize_t count = write(fd,p+offset,extent-offset);
+    if (count < 0) {
+      if (errno == EINTR)
+        continue;
+      return(-1);
+    }
+    if (count == 0)
+      break;
+    offset+=(size_t) count;
+  }
+  return((ssize_t) offset);
+}
+
+
 static inline int open_utf8(const char *path,int flags,mode_t mode)
 {
 #if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
diff --git a/MagickCore/utility.c b/MagickCore/utility.c
index cb3252256..7a84c0c74 100644
--- a/MagickCore/utility.c
+++ b/MagickCore/utility.c
@@ -2078,14 +2078,10 @@ MagickPrivate MagickBooleanType ShredFile(const char *path)
     {
       if (i != 0)
         SetRandomKey(random_info,quantum,GetStringInfoDatum(key));
-      count=write(file,GetStringInfoDatum(key),(size_t)
+      count=MagickWrite(file,GetStringInfoDatum(key),(size_t)
         MagickMin((MagickOffsetType) quantum,(MagickOffsetType) length-j));
       if (count <= 0)
-        {
-          count=0;
-          if (errno != EINTR)
-            break;
-        }
+        break;
     }
     if (j < (MagickOffsetType) length)
       break;
diff --git a/MagickCore/xml-tree.c b/MagickCore/xml-tree.c
index 4736545ad..23e45272b 100644
--- a/MagickCore/xml-tree.c
+++ b/MagickCore/xml-tree.c
@@ -580,13 +580,9 @@ MagickPrivate char *FileToXML(const char *filename,const size_t extent)
       xml=(char *) AcquireQuantumMemory(quantum,sizeof(*xml));
       for (i=0; xml != (char *) NULL; i+=(size_t) count)
       {
-        count=read(file,xml+i,quantum);
+        count=MagickRead(file,xml+i,quantum);
         if (count <= 0)
-          {
-            count=0;
-            if (errno != EINTR)
-              break;
-          }
+          break;
         if (~((size_t) i) < (quantum+1))
           {
             xml=(char *) RelinquishMagickMemory(xml);
@@ -629,14 +625,10 @@ MagickPrivate char *FileToXML(const char *filename,const size_t extent)
       (void) lseek(file,0,SEEK_SET);
       for (i=0; i < length; i+=(size_t) count)
       {
-        count=read(file,xml+i,(size_t) MagickMin(length-i,(size_t)
+        count=MagickRead(file,xml+i,(size_t) MagickMin(length-i,(size_t)
           MagickMaxBufferExtent));
         if (count <= 0)
-          {
-            count=0;
-            if (errno != EINTR)
-              break;
-          }
+          break;
       }
       if (i < length)
         {
diff --git a/coders/ps.c b/coders/ps.c
index 0a0cc5e46..94befbc4e 100644
--- a/coders/ps.c
+++ b/coders/ps.c
@@ -745,7 +745,7 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
   (void) CopyMagickString(command,"/setpagedevice {pop} bind 1 index where {"
     "dup wcheck {3 1 roll put} {pop def} ifelse} {def} ifelse\n",
     MagickPathExtent);
-  count=write(file,command,(unsigned int) strlen(command));
+  count=MagickWrite(file,command,(unsigned int) strlen(command));
   if (image_info->page == (char *) NULL)
     {
       char
@@ -753,7 +753,7 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)

       (void) FormatLocaleString(translate_geometry,MagickPathExtent,
         "%g %g translate\n",-info.bounds.x1,-info.bounds.y1);
-      count=write(file,translate_geometry,(unsigned int)
+      count=MagickWrite(file,translate_geometry,(unsigned int)
         strlen(translate_geometry));
     }
   (void) count;