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