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