MagickCore  7.1.2-29
Convert, Edit, Or Compose Bitmap Images
resource.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % RRRR EEEEE SSSSS OOO U U RRRR CCCC EEEEE %
7 % R R E SS O O U U R R C E %
8 % RRRR EEE SSS O O U U RRRR C EEE %
9 % R R E SS O O U U R R C E %
10 % R R EEEEE SSSSS OOO UUU R R CCCC EEEEE %
11 % %
12 % %
13 % Get/Set MagickCore Resources %
14 % %
15 % Software Design %
16 % Cristy %
17 % September 2002 %
18 % %
19 % %
20 % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/license/ %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 ␌
39 /*
40  Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/cache.h"
44 #include "MagickCore/configure.h"
45 #include "MagickCore/exception.h"
46 #include "MagickCore/exception-private.h"
47 #include "MagickCore/linked-list.h"
48 #include "MagickCore/log.h"
49 #include "MagickCore/image.h"
50 #include "MagickCore/image-private.h"
51 #include "MagickCore/memory_.h"
52 #include "MagickCore/nt-base-private.h"
53 #include "MagickCore/option.h"
54 #include "MagickCore/policy.h"
55 #include "MagickCore/random_.h"
56 #include "MagickCore/registry.h"
57 #include "MagickCore/resource_.h"
58 #include "MagickCore/resource-private.h"
59 #include "MagickCore/semaphore.h"
60 #include "MagickCore/signature-private.h"
61 #include "MagickCore/string_.h"
62 #include "MagickCore/string-private.h"
63 #include "MagickCore/splay-tree.h"
64 #include "MagickCore/thread-private.h"
65 #include "MagickCore/timer-private.h"
66 #include "MagickCore/token.h"
67 #include "MagickCore/utility.h"
68 #include "MagickCore/utility-private.h"
69 ␌
70 /*
71  Define declarations.
72 */
73 #define NumberOfResourceTypes \
74  (sizeof(resource_semaphore)/sizeof(*resource_semaphore))
75 ␌
76 /*
77  Typedef declarations.
78 */
79 typedef struct _ResourceInfo
80 {
81  MagickOffsetType
82  width,
83  height,
84  list_length,
85  area,
86  memory,
87  map,
88  disk,
89  file,
90  thread,
91  throttle,
92  time;
93 
94  MagickSizeType
95  width_limit,
96  height_limit,
97  list_length_limit,
98  area_limit,
99  memory_limit,
100  map_limit,
101  disk_limit,
102  file_limit,
103  thread_limit,
104  throttle_limit,
105  time_limit;
106 } ResourceInfo;
107 ␌
108 /*
109  Global declarations.
110 */
111 static RandomInfo
112  *random_info = (RandomInfo *) NULL;
113 
114 static ResourceInfo
115  resource_info =
116  {
117  MagickULLConstant(0), /* initial width */
118  MagickULLConstant(0), /* initial height */
119  MagickULLConstant(0), /* initial list length */
120  MagickULLConstant(0), /* initial area */
121  MagickULLConstant(0), /* initial memory */
122  MagickULLConstant(0), /* initial map */
123  MagickULLConstant(0), /* initial disk */
124  MagickULLConstant(0), /* initial file */
125  MagickULLConstant(0), /* initial thread */
126  MagickULLConstant(0), /* initial throttle */
127  MagickULLConstant(0), /* initial time */
128  (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(Quantum)/MaxPixelChannels), /* width limit */
129  (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(Quantum)/MaxPixelChannels), /* height limit */
130  MagickResourceInfinity, /* list length limit */
131  MagickULLConstant(3072)*1024*1024, /* area limit */
132  MagickULLConstant(1536)*1024*1024, /* memory limit */
133  MagickULLConstant(3072)*1024*1024, /* map limit */
134  MagickResourceInfinity, /* disk limit */
135  MagickULLConstant(768), /* file limit */
136  MagickULLConstant(1), /* thread limit */
137  MagickULLConstant(0), /* throttle limit */
138  MagickResourceInfinity, /* time limit */
139  };
140 
141 static SemaphoreInfo
142  *resource_semaphore[] = {
143  (SemaphoreInfo *) NULL,
144  (SemaphoreInfo *) NULL,
145  (SemaphoreInfo *) NULL,
146  (SemaphoreInfo *) NULL,
147  (SemaphoreInfo *) NULL,
148  (SemaphoreInfo *) NULL,
149  (SemaphoreInfo *) NULL,
150  (SemaphoreInfo *) NULL,
151  (SemaphoreInfo *) NULL,
152  (SemaphoreInfo *) NULL,
153  (SemaphoreInfo *) NULL,
154  (SemaphoreInfo *) NULL
155  };
156 
157 static SplayTreeInfo
158  *temporary_resources = (SplayTreeInfo *) NULL;
159 ␌
160 /*
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162 % %
163 % %
164 % %
165 % A c q u i r e M a g i c k R e s o u r c e %
166 % %
167 % %
168 % %
169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 %
171 % AcquireMagickResource() acquires resources of the specified type.
172 % MagickFalse is returned if the specified resource is exhausted otherwise
173 % MagickTrue.
174 %
175 % The format of the AcquireMagickResource() method is:
176 %
177 % MagickBooleanType AcquireMagickResource(const ResourceType type,
178 % const MagickSizeType size)
179 %
180 % A description of each parameter follows:
181 %
182 % o type: the type of resource.
183 %
184 % o size: the number of bytes needed from for this resource.
185 %
186 */
187 MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
188  const MagickSizeType size)
189 {
190  MagickBooleanType
191  bi,
192  status;
193 
194  MagickOffsetType
195  current,
196  request;
197 
198  MagickSizeType
199  limit;
200 
201  request=(MagickOffsetType) size;
202  if (request < 0)
203  return(MagickFalse);
204  limit=0;
205  current=0;
206  bi=MagickFalse;
207  status=MagickFalse;
208  switch (type)
209  {
210  case DiskResource:
211  case FileResource:
212  case MapResource:
213  case MemoryResource:
214  case TimeResource:
215  {
216  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
217  ActivateSemaphoreInfo(&resource_semaphore[type]);
218  LockSemaphoreInfo(resource_semaphore[type]);
219  break;
220  }
221  default: ;
222  }
223  switch (type)
224  {
225  case AreaResource:
226  {
227  bi=MagickTrue;
228  resource_info.area=request;
229  limit=resource_info.area_limit;
230  if ((limit == MagickResourceInfinity) || (size < limit))
231  status=MagickTrue;
232  break;
233  }
234  case DiskResource:
235  {
236  bi=MagickTrue;
237  limit=resource_info.disk_limit;
238  if (resource_info.disk <= (MagickOffsetMax-request))
239  {
240  resource_info.disk+=request;
241  if ((limit == MagickResourceInfinity) ||
242  (resource_info.disk < (MagickOffsetType) limit))
243  status=MagickTrue;
244  else
245  resource_info.disk-=request;
246  }
247  current=resource_info.disk;
248  break;
249  }
250  case FileResource:
251  {
252  limit=resource_info.file_limit;
253  if (resource_info.file <= (MagickOffsetMax-request))
254  {
255  resource_info.file+=request;
256  if ((limit == MagickResourceInfinity) ||
257  (resource_info.file < (MagickOffsetType) limit))
258  status=MagickTrue;
259  }
260  current=resource_info.file;
261  break;
262  }
263  case HeightResource:
264  {
265  bi=MagickTrue;
266  resource_info.height=request;
267  limit=resource_info.height_limit;
268  if ((limit == MagickResourceInfinity) || (size < limit))
269  status=MagickTrue;
270  break;
271  }
272  case ListLengthResource:
273  {
274  resource_info.list_length=request;
275  limit=resource_info.list_length_limit;
276  if ((limit == MagickResourceInfinity) || (size < limit))
277  status=MagickTrue;
278  break;
279  }
280  case MapResource:
281  {
282  bi=MagickTrue;
283  limit=resource_info.map_limit;
284  if (resource_info.map <= (MagickOffsetMax-request))
285  {
286  resource_info.map+=request;
287  if ((limit == MagickResourceInfinity) ||
288  (resource_info.map < (MagickOffsetType) limit))
289  status=MagickTrue;
290  else
291  resource_info.map-=request;
292  }
293  current=resource_info.map;
294  break;
295  }
296  case MemoryResource:
297  {
298  bi=MagickTrue;
299  limit=resource_info.memory_limit;
300  if (resource_info.memory <= (MagickOffsetMax-request))
301  {
302  resource_info.memory+=request;
303  if ((limit == MagickResourceInfinity) ||
304  (resource_info.memory < (MagickOffsetType) limit))
305  status=MagickTrue;
306  else
307  resource_info.memory-=request;
308  }
309  current=resource_info.memory;
310  break;
311  }
312  case ThreadResource:
313  {
314  limit=resource_info.thread_limit;
315  if ((limit == MagickResourceInfinity) ||
316  (resource_info.thread < (MagickOffsetType) limit))
317  status=MagickTrue;
318  break;
319  }
320  case ThrottleResource:
321  {
322  limit=resource_info.throttle_limit;
323  if ((limit == MagickResourceInfinity) ||
324  (resource_info.throttle < (MagickOffsetType) limit))
325  status=MagickTrue;
326  break;
327  }
328  case TimeResource:
329  {
330  limit=resource_info.time_limit;
331  if (resource_info.time <= (MagickOffsetMax-request))
332  {
333  resource_info.time+=request;
334  if ((limit == MagickResourceInfinity) ||
335  (resource_info.time < (MagickOffsetType) limit))
336  status=MagickTrue;
337  else
338  resource_info.time-=request;
339  }
340  current=resource_info.time;
341  break;
342  }
343  case WidthResource:
344  {
345  bi=MagickTrue;
346  resource_info.width=request;
347  limit=resource_info.width_limit;
348  if ((limit == MagickResourceInfinity) || (size < limit))
349  status=MagickTrue;
350  break;
351  }
352  default:
353  {
354  current=0;
355  break;
356  }
357  }
358  switch (type)
359  {
360  case DiskResource:
361  case FileResource:
362  case MapResource:
363  case MemoryResource:
364  case TimeResource:
365  {
366  UnlockSemaphoreInfo(resource_semaphore[type]);
367  break;
368  }
369  default: ;
370  }
371  if ((GetLogEventMask() & ResourceEvent) != 0)
372  {
373  char
374  resource_current[MagickFormatExtent],
375  resource_limit[MagickFormatExtent],
376  resource_request[MagickFormatExtent];
377 
378  (void) FormatMagickSize(size,bi,(bi != MagickFalse) ? "B" :
379  (const char *) NULL,MagickFormatExtent,resource_request);
380  (void) FormatMagickSize((MagickSizeType) current,bi,(bi != MagickFalse) ?
381  "B" : (const char *) NULL,MagickFormatExtent,resource_current);
382  (void) FormatMagickSize(limit,bi,(bi != MagickFalse) ? "B" :
383  (const char *) NULL,MagickFormatExtent,resource_limit);
384  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
385  CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
386  resource_request,resource_current,resource_limit);
387  }
388  return(status);
389 }
390 ␌
391 /*
392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
393 % %
394 % %
395 % %
396 + A s y n c h r o n o u s R e s o u r c e C o m p o n e n t T e r m i n u s %
397 % %
398 % %
399 % %
400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
401 %
402 % AsynchronousResourceComponentTerminus() destroys the resource environment.
403 % It differs from ResourceComponentTerminus() in that it can be called from a
404 % asynchronous signal handler.
405 %
406 % The format of the ResourceComponentTerminus() method is:
407 %
408 % ResourceComponentTerminus(void)
409 %
410 */
411 MagickExport void AsynchronousResourceComponentTerminus(void)
412 {
413  const char
414  *path;
415 
416  if (temporary_resources == (SplayTreeInfo *) NULL)
417  return;
418  /*
419  Remove any lingering temporary files.
420  */
421  ResetSplayTreeIterator(temporary_resources);
422  path=(const char *) GetNextKeyInSplayTree(temporary_resources);
423  while (path != (const char *) NULL)
424  {
425  (void) ShredFile(path);
426  (void) remove_utf8(path);
427  path=(const char *) GetNextKeyInSplayTree(temporary_resources);
428  }
429 }
430 ␌
431 /*
432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
433 % %
434 % %
435 % %
436 % A c q u i r e U n i q u e F i l e R e s o u r c e %
437 % %
438 % %
439 % %
440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441 %
442 % AcquireUniqueFileResource() returns a unique file name, and returns a file
443 % descriptor for the file open for reading and writing.
444 %
445 % The format of the AcquireUniqueFileResource() method is:
446 %
447 % int AcquireUniqueFileResource(char *path)
448 %
449 % A description of each parameter follows:
450 %
451 % o path: Specifies a pointer to an array of characters. The unique path
452 % name is returned in this array.
453 %
454 */
455 
456 static void *DestroyTemporaryResources(void *temporary_resource)
457 {
458  (void) ShredFile((char *) temporary_resource);
459  (void) remove_utf8((char *) temporary_resource);
460  temporary_resource=DestroyString((char *) temporary_resource);
461  return((void *) NULL);
462 }
463 
464 MagickExport int AcquireUniqueFileResource(char *path)
465 {
466 #if !defined(O_NOFOLLOW)
467 #define O_NOFOLLOW 0
468 #endif
469 #if !defined(TMP_MAX)
470 # define TMP_MAX 238328
471 #endif
472 
473  int
474  c,
475  file;
476 
477  char
478  *p;
479 
480  MagickBooleanType
481  status;
482 
483  ssize_t
484  i;
485 
486  static const char
487  portable_filename[65] =
488  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
489 
490  StringInfo
491  *key;
492 
493  struct stat
494  *attributes;
495 
496  unsigned char
497  *datum;
498 
499  assert(path != (char *) NULL);
500  if ((GetLogEventMask() & ResourceEvent) != 0)
501  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"...");
502  if (random_info == (RandomInfo *) NULL)
503  {
504  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
505  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
506  LockSemaphoreInfo(resource_semaphore[FileResource]);
507  if (random_info == (RandomInfo *) NULL)
508  random_info=AcquireRandomInfo();
509  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
510  }
511  file=(-1);
512  for (i=0; i < (ssize_t) TMP_MAX; i++)
513  {
514  ssize_t
515  j;
516 
517  /*
518  Get temporary pathname.
519  */
520  (void) GetPathTemplate(path);
521  key=GetRandomKey(random_info,strlen(MagickPathTemplate)-6);
522  p=path+strlen(path)-strlen(MagickPathTemplate);
523  datum=GetStringInfoDatum(key);
524  for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
525  {
526  c=(int) (datum[j] & 0x3f);
527  *p++=portable_filename[c];
528  }
529  key=DestroyStringInfo(key);
530 #if defined(MAGICKCORE_HAVE_MKSTEMP)
531  file=mkstemp(path);
532  if (file != -1)
533  {
534 #if defined(MAGICKCORE_HAVE_FCHMOD)
535  (void) fchmod(file,0600);
536 #endif
537 #if defined(__OS2__)
538  setmode(file,O_BINARY);
539 #endif
540  break;
541  }
542 #endif
543  key=GetRandomKey(random_info,strlen(MagickPathTemplate));
544  p=path+strlen(path)-strlen(MagickPathTemplate);
545  datum=GetStringInfoDatum(key);
546  for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
547  {
548  c=(int) (datum[j] & 0x3f);
549  *p++=portable_filename[c];
550  }
551  key=DestroyStringInfo(key);
552  file=open_utf8(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,
553  S_MODE);
554  if ((file >= 0) || (errno != EEXIST))
555  break;
556  }
557  if ((GetLogEventMask() & ResourceEvent) != 0)
558  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
559  if (file == -1)
560  return(file);
561  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
562  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
563  LockSemaphoreInfo(resource_semaphore[FileResource]);
564  if (temporary_resources == (SplayTreeInfo *) NULL)
565  temporary_resources=NewSplayTree(CompareSplayTreeString,
566  DestroyTemporaryResources,RelinquishMagickMemory);
567  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
568  attributes=(struct stat *) AcquireCriticalMemory(sizeof(struct stat));
569  status=GetPathAttributes(path,attributes);
570  if (status == MagickFalse)
571  attributes=(struct stat *) RelinquishMagickMemory(attributes);
572  else
573  status=AddValueToSplayTree(temporary_resources,ConstantString(path),
574  attributes);
575  if (status == MagickFalse)
576  file=close_utf8(file)-1;
577  return(file);
578 }
579 ␌
580 /*
581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
582 % %
583 % %
584 % %
585 % G e t M a g i c k R e s o u r c e %
586 % %
587 % %
588 % %
589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590 %
591 % GetMagickResource() returns the specified resource.
592 %
593 % The format of the GetMagickResource() method is:
594 %
595 % MagickSizeType GetMagickResource(const ResourceType type)
596 %
597 % A description of each parameter follows:
598 %
599 % o type: the type of resource.
600 %
601 */
602 MagickExport MagickSizeType GetMagickResource(const ResourceType type)
603 {
604  MagickSizeType
605  resource;
606 
607  resource=0;
608  switch (type)
609  {
610  case DiskResource:
611  case FileResource:
612  case MapResource:
613  case MemoryResource:
614  case TimeResource:
615  {
616  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
617  ActivateSemaphoreInfo(&resource_semaphore[type]);
618  LockSemaphoreInfo(resource_semaphore[type]);
619  break;
620  }
621  default: ;
622  }
623  switch (type)
624  {
625  case AreaResource:
626  {
627  resource=(MagickSizeType) resource_info.area;
628  break;
629  }
630  case DiskResource:
631  {
632  resource=(MagickSizeType) resource_info.disk;
633  break;
634  }
635  case FileResource:
636  {
637  resource=(MagickSizeType) resource_info.file;
638  break;
639  }
640  case HeightResource:
641  {
642  resource=(MagickSizeType) resource_info.height;
643  break;
644  }
645  case ListLengthResource:
646  {
647  resource=(MagickSizeType) resource_info.list_length;
648  break;
649  }
650  case MapResource:
651  {
652  resource=(MagickSizeType) resource_info.map;
653  break;
654  }
655  case MemoryResource:
656  {
657  resource=(MagickSizeType) resource_info.memory;
658  break;
659  }
660  case TimeResource:
661  {
662  resource=(MagickSizeType) resource_info.time;
663  break;
664  }
665  case ThreadResource:
666  {
667  resource=(MagickSizeType) resource_info.thread;
668  break;
669  }
670  case ThrottleResource:
671  {
672  resource=(MagickSizeType) resource_info.throttle;
673  break;
674  }
675  case WidthResource:
676  {
677  resource=(MagickSizeType) resource_info.width;
678  break;
679  }
680  default:
681  break;
682  }
683  switch (type)
684  {
685  case DiskResource:
686  case FileResource:
687  case MapResource:
688  case MemoryResource:
689  case TimeResource:
690  {
691  UnlockSemaphoreInfo(resource_semaphore[type]);
692  break;
693  }
694  default: ;
695  }
696  return(resource);
697 }
698 ␌
699 /*
700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
701 % %
702 % %
703 % %
704 % I s F i l e R e s o u r c e I d e n t i t y V a l i d %
705 % %
706 % %
707 % %
708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
709 %
710 % IsFileResourceIdentityValid() returns MagickTrue if the file resource
711 % identity is valid.
712 %
713 % The format of the IsFileResourceIdentityValid() method is:
714 %
715 % MagickBooleanType IsFileResourceIdentityValid(const char *path)
716 %
717 % A description of each parameter follows:
718 %
719 % o path: the file resource path.
720 %
721 */
722 MagickExport MagickBooleanType IsFileResourceIdentityValid(const char *path)
723 {
724  const struct stat
725  *temporary_attributes;
726 
727  MagickBooleanType
728  status = MagickTrue;
729 
730  struct stat
731  attributes;
732 
733  if (temporary_resources == (SplayTreeInfo *) NULL)
734  return(MagickTrue);
735  LockSemaphoreInfo(resource_semaphore[FileResource]);
736  temporary_attributes=(const struct stat *) GetValueFromSplayTree(
737  temporary_resources,(const void *) path);
738  if (temporary_attributes != (const struct stat *) NULL)
739  {
740  status=GetPathAttributes(path,&attributes);
741  if (status != MagickFalse)
742  if ((attributes.st_dev != temporary_attributes->st_dev) ||
743  (attributes.st_ino != temporary_attributes->st_ino) ||
744  (attributes.st_mode != temporary_attributes->st_mode))
745  status=MagickFalse;
746  }
747  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
748  return(status);
749 }
750 ␌
751 /*
752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753 % %
754 % %
755 % %
756 % G e t M a g i c k R e s o u r c e L i m i t %
757 % %
758 % %
759 % %
760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761 %
762 % GetMagickResourceLimit() returns the specified resource limit.
763 %
764 % The format of the GetMagickResourceLimit() method is:
765 %
766 % MagickSizeType GetMagickResourceLimit(const ResourceType type)
767 %
768 % A description of each parameter follows:
769 %
770 % o type: the type of resource.
771 %
772 */
773 MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
774 {
775  MagickSizeType
776  resource;
777 
778  switch (type)
779  {
780  case AreaResource:
781  return(resource_info.area_limit);
782  case HeightResource:
783  return(resource_info.height_limit);
784  case ListLengthResource:
785  return(resource_info.list_length_limit);
786  case ThreadResource:
787  return(resource_info.thread_limit);
788  case ThrottleResource:
789  return(resource_info.throttle_limit);
790  case WidthResource:
791  return(resource_info.width_limit);
792  default: ;
793  }
794  resource=0;
795  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
796  ActivateSemaphoreInfo(&resource_semaphore[type]);
797  LockSemaphoreInfo(resource_semaphore[type]);
798  switch (type)
799  {
800  case DiskResource:
801  {
802  resource=resource_info.disk_limit;
803  break;
804  }
805  case FileResource:
806  {
807  resource=resource_info.file_limit;
808  break;
809  }
810  case MapResource:
811  {
812  resource=resource_info.map_limit;
813  break;
814  }
815  case MemoryResource:
816  {
817  resource=resource_info.memory_limit;
818  break;
819  }
820  case TimeResource:
821  {
822  resource=resource_info.time_limit;
823  break;
824  }
825  default:
826  break;
827  }
828  UnlockSemaphoreInfo(resource_semaphore[type]);
829  return(resource);
830 }
831 ␌
832 /*
833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
834 % %
835 % %
836 % %
837 % L i s t M a g i c k R e s o u r c e I n f o %
838 % %
839 % %
840 % %
841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
842 %
843 % ListMagickResourceInfo() lists the resource info to a file.
844 %
845 % The format of the ListMagickResourceInfo method is:
846 %
847 % MagickBooleanType ListMagickResourceInfo(FILE *file,
848 % ExceptionInfo *exception)
849 %
850 % A description of each parameter follows.
851 %
852 % o file: An pointer to a FILE.
853 %
854 % o exception: return any errors or warnings in this structure.
855 %
856 */
857 
858 static void FormatTimeToLive(const MagickSizeType ttl,char *timeString)
859 {
860  MagickSizeType
861  days,
862  hours,
863  minutes,
864  months,
865  seconds,
866  weeks,
867  years;
868 
869  years=ttl/31536000;
870  seconds=ttl % 31536000;
871  if (seconds == 0)
872  {
873  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld years",years);
874  return;
875  }
876  months=ttl/2628000;
877  seconds=ttl % 2628000;
878  if (seconds == 0)
879  {
880  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld months",
881  months);
882  return;
883  }
884  weeks=ttl/604800;
885  seconds=ttl % 604800;
886  if (seconds == 0)
887  {
888  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld weeks",weeks);
889  return;
890  }
891  days=ttl/86400;
892  seconds=ttl % 86400;
893  if (seconds == 0)
894  {
895  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld days",days);
896  return;
897  }
898  hours=ttl/3600;
899  seconds=ttl % 3600;
900  if (seconds == 0)
901  {
902  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld hours",hours);
903  return;
904  }
905  minutes=ttl/60;
906  seconds=ttl % 60;
907  if (seconds == 0)
908  {
909  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld minutes",
910  minutes);
911  return;
912  }
913  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld seconds",ttl);
914 }
915 
916 MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
917  ExceptionInfo *magick_unused(exception))
918 {
919  char
920  area_limit[MagickFormatExtent],
921  disk_limit[MagickFormatExtent],
922  height_limit[MagickFormatExtent],
923  list_length_limit[MagickFormatExtent],
924  map_limit[MagickFormatExtent],
925  memory_limit[MagickFormatExtent],
926  time_limit[MagickFormatExtent],
927  width_limit[MagickFormatExtent];
928 
929  magick_unreferenced(exception);
930 
931  if (file == (const FILE *) NULL)
932  file=stdout;
933  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
934  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
935  LockSemaphoreInfo(resource_semaphore[FileResource]);
936  (void) FormatMagickSize(resource_info.width_limit,MagickFalse,"P",
937  MagickFormatExtent,width_limit);
938  (void) FormatMagickSize(resource_info.height_limit,MagickFalse,"P",
939  MagickFormatExtent,height_limit);
940  (void) FormatMagickSize(resource_info.area_limit,MagickFalse,"P",
941  MagickFormatExtent,area_limit);
942  (void) CopyMagickString(list_length_limit,"unlimited",MagickFormatExtent);
943  if (resource_info.list_length_limit != MagickResourceInfinity)
944  (void) FormatMagickSize(resource_info.list_length_limit,MagickTrue,"B",
945  MagickFormatExtent,list_length_limit);
946  (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,"B",
947  MagickFormatExtent,memory_limit);
948  (void) FormatMagickSize(resource_info.map_limit,MagickTrue,"B",
949  MagickFormatExtent,map_limit);
950  (void) CopyMagickString(disk_limit,"unlimited",MagickFormatExtent);
951  if (resource_info.disk_limit != MagickResourceInfinity)
952  (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,"B",
953  MagickFormatExtent,disk_limit);
954  (void) CopyMagickString(time_limit,"unlimited",MagickFormatExtent);
955  if (resource_info.time_limit != MagickResourceInfinity)
956  FormatTimeToLive(resource_info.time_limit,time_limit);
957  (void) FormatLocaleFile(file,"Resource limits:\n");
958  (void) FormatLocaleFile(file," Width: %s\n",width_limit);
959  (void) FormatLocaleFile(file," Height: %s\n",height_limit);
960  (void) FormatLocaleFile(file," Area: %s\n",area_limit);
961  (void) FormatLocaleFile(file," List length: %s\n",list_length_limit);
962  (void) FormatLocaleFile(file," Memory: %s\n",memory_limit);
963  (void) FormatLocaleFile(file," Map: %s\n",map_limit);
964  (void) FormatLocaleFile(file," Disk: %s\n",disk_limit);
965  (void) FormatLocaleFile(file," File: %.17g\n",(double) ((MagickOffsetType)
966  resource_info.file_limit));
967  (void) FormatLocaleFile(file," Thread: %.17g\n",(double) ((MagickOffsetType)
968  resource_info.thread_limit));
969  (void) FormatLocaleFile(file," Throttle: %.17g\n",(double)
970  ((MagickOffsetType) resource_info.throttle_limit));
971  (void) FormatLocaleFile(file," Time: %s\n",time_limit);
972  (void) fflush(file);
973  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
974  return(MagickTrue);
975 }
976 ␌
977 /*
978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
979 % %
980 % %
981 % %
982 % R e l i n q u i s h M a g i c k R e s o u r c e %
983 % %
984 % %
985 % %
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 %
988 % RelinquishMagickResource() relinquishes resources of the specified type.
989 %
990 % The format of the RelinquishMagickResource() method is:
991 %
992 % void RelinquishMagickResource(const ResourceType type,
993 % const MagickSizeType size)
994 %
995 % A description of each parameter follows:
996 %
997 % o type: the type of resource.
998 %
999 % o size: the size of the resource.
1000 %
1001 */
1002 MagickExport void RelinquishMagickResource(const ResourceType type,
1003  const MagickSizeType size)
1004 {
1005  MagickBooleanType
1006  bi;
1007 
1008  MagickSizeType
1009  current,
1010  limit;
1011 
1012  bi=MagickFalse;
1013  limit=0;
1014  current=0;
1015  switch (type)
1016  {
1017  case DiskResource:
1018  case FileResource:
1019  case MapResource:
1020  case MemoryResource:
1021  case TimeResource:
1022  {
1023  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1024  ActivateSemaphoreInfo(&resource_semaphore[type]);
1025  LockSemaphoreInfo(resource_semaphore[type]);
1026  break;
1027  }
1028  default: ;
1029  }
1030  switch (type)
1031  {
1032  case DiskResource:
1033  {
1034  bi=MagickTrue;
1035  resource_info.disk-=(MagickOffsetType) size;
1036  current=(MagickSizeType) resource_info.disk;
1037  limit=resource_info.disk_limit;
1038  assert(resource_info.disk >= 0);
1039  break;
1040  }
1041  case FileResource:
1042  {
1043  resource_info.file-=(MagickOffsetType) size;
1044  current=(MagickSizeType) resource_info.file;
1045  limit=resource_info.file_limit;
1046  assert(resource_info.file >= 0);
1047  break;
1048  }
1049  case MapResource:
1050  {
1051  bi=MagickTrue;
1052  resource_info.map-=(MagickOffsetType) size;
1053  current=(MagickSizeType) resource_info.map;
1054  limit=resource_info.map_limit;
1055  assert(resource_info.map >= 0);
1056  break;
1057  }
1058  case MemoryResource:
1059  {
1060  bi=MagickTrue;
1061  resource_info.memory-=(MagickOffsetType) size;
1062  current=(MagickSizeType) resource_info.memory;
1063  limit=resource_info.memory_limit;
1064  assert(resource_info.memory >= 0);
1065  break;
1066  }
1067  case TimeResource:
1068  {
1069  bi=MagickTrue;
1070  resource_info.time-=(MagickOffsetType) size;
1071  current=(MagickSizeType) resource_info.time;
1072  limit=resource_info.time_limit;
1073  assert(resource_info.time >= 0);
1074  break;
1075  }
1076  default:
1077  {
1078  current=0;
1079  break;
1080  }
1081  }
1082  switch (type)
1083  {
1084  case DiskResource:
1085  case FileResource:
1086  case MapResource:
1087  case MemoryResource:
1088  case TimeResource:
1089  {
1090  UnlockSemaphoreInfo(resource_semaphore[type]);
1091  break;
1092  }
1093  default: ;
1094  }
1095  if ((GetLogEventMask() & ResourceEvent) != 0)
1096  {
1097  char
1098  resource_current[MagickFormatExtent],
1099  resource_limit[MagickFormatExtent],
1100  resource_request[MagickFormatExtent];
1101 
1102  (void) FormatMagickSize(size,bi,(bi != MagickFalse) ? "B" :
1103  (const char *) NULL,MagickFormatExtent,resource_request);
1104  (void) FormatMagickSize(current,bi,(bi != MagickFalse) ? "B" :
1105  (const char *) NULL,MagickFormatExtent,resource_current);
1106  (void) FormatMagickSize(limit,bi,(bi != MagickFalse) ? "B" :
1107  (const char *) NULL,MagickFormatExtent,resource_limit);
1108  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
1109  CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
1110  resource_request,resource_current,resource_limit);
1111  }
1112 }
1113 ␌
1114 /*
1115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 % %
1117 % %
1118 % %
1119 % R e l i n q u i s h U n i q u e F i l e R e s o u r c e %
1120 % %
1121 % %
1122 % %
1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1124 %
1125 % RelinquishUniqueFileResource() relinquishes a unique file resource.
1126 %
1127 % The format of the RelinquishUniqueFileResource() method is:
1128 %
1129 % MagickBooleanType RelinquishUniqueFileResource(const char *path)
1130 %
1131 % A description of each parameter follows:
1132 %
1133 % o name: the name of the temporary resource.
1134 %
1135 */
1136 MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
1137 {
1138  char
1139  cache_path[MagickPathExtent];
1140 
1141  MagickStatusType
1142  status;
1143 
1144  assert(path != (const char *) NULL);
1145  status=MagickFalse;
1146  if ((GetLogEventMask() & ResourceEvent) != 0)
1147  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
1148  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1149  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1150  LockSemaphoreInfo(resource_semaphore[FileResource]);
1151  if (temporary_resources != (SplayTreeInfo *) NULL)
1152  status=DeleteNodeFromSplayTree(temporary_resources,(const void *) path);
1153  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1154  (void) CopyMagickString(cache_path,path,MagickPathExtent);
1155  AppendImageFormat("cache",cache_path);
1156  if (access_utf8(cache_path,F_OK) == 0)
1157  {
1158  status=ShredFile(cache_path);
1159  status|=(MagickStatusType) remove_utf8(cache_path);
1160  }
1161  if (status == MagickFalse)
1162  {
1163  status=ShredFile(path);
1164  status|=(MagickStatusType) remove_utf8(path);
1165  }
1166  return(status == 0 ? MagickFalse : MagickTrue);
1167 }
1168 ␌
1169 /*
1170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1171 % %
1172 % %
1173 % %
1174 + R e s o u r c e C o m p o n e n t G e n e s i s %
1175 % %
1176 % %
1177 % %
1178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179 %
1180 % ResourceComponentGenesis() instantiates the resource component.
1181 %
1182 % The format of the ResourceComponentGenesis method is:
1183 %
1184 % MagickBooleanType ResourceComponentGenesis(void)
1185 %
1186 */
1187 
1188 MagickPrivate MagickBooleanType ResourceComponentGenesis(void)
1189 {
1190  char
1191  *limit;
1192 
1193  MagickSizeType
1194  memory;
1195 
1196  ssize_t
1197  files,
1198  i,
1199  number_threads,
1200  pages,
1201  pagesize;
1202 
1203  /*
1204  Set Magick resource limits.
1205  */
1206  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1207  if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1208  resource_semaphore[i]=AcquireSemaphoreInfo();
1209  (void) SetMagickResourceLimit(WidthResource,resource_info.width_limit);
1210  limit=GetEnvironmentValue("MAGICK_WIDTH_LIMIT");
1211  if (limit != (char *) NULL)
1212  {
1213  (void) SetMagickResourceLimit(WidthResource,StringToMagickSizeType(limit,
1214  100.0));
1215  limit=DestroyString(limit);
1216  }
1217  (void) SetMagickResourceLimit(HeightResource,resource_info.height_limit);
1218  limit=GetEnvironmentValue("MAGICK_HEIGHT_LIMIT");
1219  if (limit != (char *) NULL)
1220  {
1221  (void) SetMagickResourceLimit(HeightResource,StringToMagickSizeType(
1222  limit,100.0));
1223  limit=DestroyString(limit);
1224  }
1225  pagesize=GetMagickPageSize();
1226  pages=(-1);
1227 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
1228  pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
1229 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1230  pages=pages/2;
1231 #endif
1232 #endif
1233  memory=(MagickSizeType) ((MagickOffsetType) pages*pagesize);
1234  if ((pagesize <= 0) || (pages <= 0))
1235  memory=2048UL*1024UL*1024UL;
1236 #if defined(MAGICKCORE_PixelCacheThreshold)
1237  memory=StringToMagickSizeType(MAGICKCORE_PixelCacheThreshold,100.0);
1238 #endif
1239  (void) SetMagickResourceLimit(AreaResource,4*memory);
1240  limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
1241  if (limit != (char *) NULL)
1242  {
1243  (void) SetMagickResourceLimit(AreaResource,StringToMagickSizeType(limit,
1244  100.0));
1245  limit=DestroyString(limit);
1246  }
1247  (void) SetMagickResourceLimit(MemoryResource,memory);
1248  limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
1249  if (limit != (char *) NULL)
1250  {
1251  (void) SetMagickResourceLimit(MemoryResource,StringToMagickSizeType(
1252  limit,100.0));
1253  limit=DestroyString(limit);
1254  }
1255  (void) SetMagickResourceLimit(MapResource,2*memory);
1256  limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
1257  if (limit != (char *) NULL)
1258  {
1259  (void) SetMagickResourceLimit(MapResource,StringToMagickSizeType(limit,
1260  100.0));
1261  limit=DestroyString(limit);
1262  }
1263  (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity);
1264  limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
1265  if (limit != (char *) NULL)
1266  {
1267  (void) SetMagickResourceLimit(DiskResource,StringToMagickSizeType(limit,
1268  100.0));
1269  limit=DestroyString(limit);
1270  }
1271  files=(-1);
1272 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1273  files=(ssize_t) sysconf(_SC_OPEN_MAX);
1274 #endif
1275 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1276  if (files < 0)
1277  {
1278  struct rlimit
1279  resources;
1280 
1281  if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
1282  files=(ssize_t) resources.rlim_cur;
1283  }
1284 #endif
1285 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
1286  if (files < 0)
1287  files=(ssize_t) getdtablesize();
1288 #endif
1289  if (files < 0)
1290  files=64;
1291  (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
1292  (3*files/4),64));
1293  limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
1294  if (limit != (char *) NULL)
1295  {
1296  (void) SetMagickResourceLimit(FileResource,StringToMagickSizeType(limit,
1297  100.0));
1298  limit=DestroyString(limit);
1299  }
1300  number_threads=(ssize_t) GetOpenMPMaximumThreads();
1301  if (number_threads > 1)
1302  number_threads--; /* reserve core for OS */
1303  (void) SetMagickResourceLimit(ThreadResource,(size_t) number_threads);
1304  limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1305  if (limit != (char *) NULL)
1306  {
1307  (void) SetMagickResourceLimit(ThreadResource,StringToMagickSizeType(
1308  limit,100.0));
1309  limit=DestroyString(limit);
1310  }
1311  (void) SetMagickResourceLimit(ThrottleResource,0);
1312  limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT");
1313  if (limit != (char *) NULL)
1314  {
1315  (void) SetMagickResourceLimit(ThrottleResource,StringToMagickSizeType(
1316  limit,100.0));
1317  limit=DestroyString(limit);
1318  }
1319  (void) SetMagickResourceLimit(TimeResource,MagickResourceInfinity);
1320  limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1321  if (limit != (char *) NULL)
1322  {
1323  (void) SetMagickResourceLimit(TimeResource,(MagickSizeType)
1324  ParseMagickTimeToLive(limit));
1325  limit=DestroyString(limit);
1326  }
1327  (void) SetMagickResourceLimit(ListLengthResource,MagickResourceInfinity);
1328  limit=GetEnvironmentValue("MAGICK_LIST_LENGTH_LIMIT");
1329  if (limit != (char *) NULL)
1330  {
1331  (void) SetMagickResourceLimit(ListLengthResource,
1332  StringToMagickSizeType(limit,100.0));
1333  limit=DestroyString(limit);
1334  }
1335  return(MagickTrue);
1336 }
1337 ␌
1338 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1339 /*
1340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341 % %
1342 % %
1343 % %
1344 % R e s e t M a g i c k R e s o u r c e C o u n t e r s %
1345 % %
1346 % %
1347 % %
1348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1349 %
1350 % ResetMagickResourceCounters() resets the current resource usage counters
1351 % to zero. This is useful for fuzzing to ensure deterministic behavior
1352 % between iterations.
1353 %
1354 % The format of the ResetMagickResourceCounters() method is:
1355 %
1356 % void ResetMagickResourceCounters(void)
1357 %
1358 */
1359 MagickExport void ResetMagickResourceCounters(void)
1360 {
1361  resource_info.width=0;
1362  resource_info.height=0;
1363  resource_info.list_length=0;
1364  resource_info.area=0;
1365  resource_info.memory=0;
1366  resource_info.map=0;
1367  resource_info.disk=0;
1368  resource_info.file=0;
1369  resource_info.thread=0;
1370  resource_info.throttle=0;
1371  resource_info.time=0;
1372 }
1373 #endif
1374 ␌
1375 /*
1376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 % %
1378 % %
1379 % %
1380 + R e s o u r c e C o m p o n e n t T e r m i n u s %
1381 % %
1382 % %
1383 % %
1384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385 %
1386 % ResourceComponentTerminus() destroys the resource component.
1387 %
1388 % The format of the ResourceComponentTerminus() method is:
1389 %
1390 % ResourceComponentTerminus(void)
1391 %
1392 */
1393 MagickPrivate void ResourceComponentTerminus(void)
1394 {
1395  ssize_t
1396  i;
1397 
1398  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1399  if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1400  resource_semaphore[i]=AcquireSemaphoreInfo();
1401  LockSemaphoreInfo(resource_semaphore[FileResource]);
1402  if (temporary_resources != (SplayTreeInfo *) NULL)
1403  temporary_resources=DestroySplayTree(temporary_resources);
1404  if (random_info != (RandomInfo *) NULL)
1405  random_info=DestroyRandomInfo(random_info);
1406  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1407  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1408  RelinquishSemaphoreInfo(&resource_semaphore[i]);
1409 }
1410 ␌
1411 /*
1412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413 % %
1414 % %
1415 % %
1416 % S e t M a g i c k R e s o u r c e L i m i t %
1417 % %
1418 % %
1419 % %
1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 %
1422 % SetMagickResourceLimit() sets the limit for a particular resource.
1423 %
1424 % The format of the SetMagickResourceLimit() method is:
1425 %
1426 % MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1427 % const MagickSizeType limit)
1428 %
1429 % A description of each parameter follows:
1430 %
1431 % o type: the type of resource.
1432 %
1433 % o limit: the maximum limit for the resource.
1434 %
1435 */
1436 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1437  const MagickSizeType limit)
1438 {
1439  char
1440  *value;
1441 
1442  MagickBooleanType
1443  status;
1444 
1445  status=MagickTrue;
1446  value=(char *) NULL;
1447  switch (type)
1448  {
1449  case DiskResource:
1450  case FileResource:
1451  case MapResource:
1452  case MemoryResource:
1453  case TimeResource:
1454  {
1455  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1456  ActivateSemaphoreInfo(&resource_semaphore[type]);
1457  LockSemaphoreInfo(resource_semaphore[type]);
1458  break;
1459  }
1460  default: ;
1461  }
1462  switch (type)
1463  {
1464  case AreaResource:
1465  {
1466  value=GetPolicyValue("resource:area");
1467  if (value == (char *) NULL)
1468  resource_info.area_limit=limit;
1469  else
1470  resource_info.area_limit=MagickMin(limit,StringToMagickSizeType(value,
1471  100.0));
1472  break;
1473  }
1474  case DiskResource:
1475  {
1476  value=GetPolicyValue("resource:disk");
1477  if (value == (char *) NULL)
1478  resource_info.disk_limit=limit;
1479  else
1480  resource_info.disk_limit=MagickMin(limit,StringToMagickSizeType(value,
1481  100.0));
1482  break;
1483  }
1484  case FileResource:
1485  {
1486  value=GetPolicyValue("resource:file");
1487  if (value == (char *) NULL)
1488  resource_info.file_limit=limit;
1489  else
1490  resource_info.file_limit=MagickMin(limit,StringToMagickSizeType(value,
1491  100.0));
1492  break;
1493  }
1494  case HeightResource:
1495  {
1496  value=GetPolicyValue("resource:height");
1497  if (value == (char *) NULL)
1498  resource_info.height_limit=limit;
1499  else
1500  resource_info.height_limit=MagickMin(limit,StringToMagickSizeType(
1501  value,100.0));
1502  resource_info.height_limit=MagickMin(resource_info.height_limit,
1503  (MagickSizeType) MAGICK_SSIZE_MAX);
1504  break;
1505  }
1506  case ListLengthResource:
1507  {
1508  value=GetPolicyValue("resource:list-length");
1509  if (value == (char *) NULL)
1510  resource_info.list_length_limit=limit;
1511  else
1512  resource_info.list_length_limit=MagickMin(limit,
1513  StringToMagickSizeType(value,100.0));
1514  break;
1515  }
1516  case MapResource:
1517  {
1518  value=GetPolicyValue("resource:map");
1519  if (value == (char *) NULL)
1520  resource_info.map_limit=limit;
1521  else
1522  resource_info.map_limit=MagickMin(limit,StringToMagickSizeType(
1523  value,100.0));
1524  break;
1525  }
1526  case MemoryResource:
1527  {
1528  value=GetPolicyValue("resource:memory");
1529  if (value == (char *) NULL)
1530  resource_info.memory_limit=limit;
1531  else
1532  resource_info.memory_limit=MagickMin(limit,StringToMagickSizeType(
1533  value,100.0));
1534  break;
1535  }
1536  case ThreadResource:
1537  {
1538  value=GetPolicyValue("resource:thread");
1539  if (value == (char *) NULL)
1540  resource_info.thread_limit=limit;
1541  else
1542  resource_info.thread_limit=MagickMin(limit,StringToMagickSizeType(
1543  value,100.0));
1544  if (resource_info.thread_limit > GetOpenMPMaximumThreads())
1545  resource_info.thread_limit=GetOpenMPMaximumThreads();
1546  else
1547  if (resource_info.thread_limit == 0)
1548  resource_info.thread_limit=1;
1549  break;
1550  }
1551  case ThrottleResource:
1552  {
1553  value=GetPolicyValue("resource:throttle");
1554  if (value == (char *) NULL)
1555  resource_info.throttle_limit=limit;
1556  else
1557  resource_info.throttle_limit=MagickMax(limit,StringToMagickSizeType(
1558  value,100.0));
1559  break;
1560  }
1561  case TimeResource:
1562  {
1563  value=GetPolicyValue("resource:time");
1564  if (value == (char *) NULL)
1565  resource_info.time_limit=limit;
1566  else
1567  resource_info.time_limit=MagickMin(limit,(MagickSizeType)
1568  ParseMagickTimeToLive(value));
1569  break;
1570  }
1571  case WidthResource:
1572  {
1573  value=GetPolicyValue("resource:width");
1574  if (value == (char *) NULL)
1575  resource_info.width_limit=limit;
1576  else
1577  resource_info.width_limit=MagickMin(limit,StringToMagickSizeType(value,
1578  100.0));
1579  resource_info.width_limit=MagickMin(resource_info.width_limit,
1580  (MagickSizeType) MAGICK_SSIZE_MAX);
1581  break;
1582  }
1583  default:
1584  {
1585  status=MagickFalse;
1586  break;
1587  }
1588  }
1589  switch (type)
1590  {
1591  case DiskResource:
1592  case FileResource:
1593  case MapResource:
1594  case MemoryResource:
1595  case TimeResource:
1596  {
1597  UnlockSemaphoreInfo(resource_semaphore[type]);
1598  break;
1599  }
1600  default: ;
1601  }
1602  if (value != (char *) NULL)
1603  value=DestroyString(value);
1604  return(status);
1605 }