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