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