MagickCore 7.1.2-28
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
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*/
79typedef 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*/
111static RandomInfo
112 *random_info = (RandomInfo *) NULL;
113
114static 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
141static 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
157static 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*/
187MagickExport 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*/
411MagickExport 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
456static 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
464MagickExport 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*/
602MagickExport 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*/
722MagickExport 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*/
773MagickExport 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
858static 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
916MagickExport 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: %.20g\n",(double) ((MagickOffsetType)
966 resource_info.file_limit));
967 (void) FormatLocaleFile(file," Thread: %.20g\n",(double) ((MagickOffsetType)
968 resource_info.thread_limit));
969 (void) FormatLocaleFile(file," Throttle: %.20g\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*/
1002MagickExport 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*/
1136MagickExport 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
1188MagickPrivate 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*/
1359MagickExport 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*/
1393MagickPrivate 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*/
1436MagickExport 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}