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