MagickCore  6.9.13-26
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/timer-private.h"
66 #include "magick/token.h"
67 #include "magick/timer-private.h"
68 #include "magick/utility.h"
69 #include "magick/utility-private.h"
70 
71 /*
72  Define declarations.
73 */
74 #define MagickPathTemplate "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" /* min 6 X's */
75 #define NumberOfResourceTypes \
76  (sizeof(resource_semaphore)/sizeof(*resource_semaphore))
77 
78 /*
79  Typedef declarations.
80 */
81 typedef struct _ResourceInfo
82 {
83  MagickOffsetType
84  width,
85  height,
86  list_length,
87  area,
88  memory,
89  map,
90  disk,
91  file,
92  thread,
93  throttle,
94  time;
95 
96  MagickSizeType
97  width_limit,
98  height_limit,
99  list_length_limit,
100  area_limit,
101  memory_limit,
102  map_limit,
103  disk_limit,
104  file_limit,
105  thread_limit,
106  throttle_limit,
107  time_limit;
108 } ResourceInfo;
109 
110 /*
111  Global declarations.
112 */
113 static RandomInfo
114  *random_info = (RandomInfo *) NULL;
115 
116 static ResourceInfo
117  resource_info =
118  {
119  MagickULLConstant(0), /* initial width */
120  MagickULLConstant(0), /* initial height */
121  MagickULLConstant(0), /* initial list length */
122  MagickULLConstant(0), /* initial area */
123  MagickULLConstant(0), /* initial memory */
124  MagickULLConstant(0), /* initial map */
125  MagickULLConstant(0), /* initial disk */
126  MagickULLConstant(0), /* initial file */
127  MagickULLConstant(0), /* initial thread */
128  MagickULLConstant(0), /* initial throttle */
129  MagickULLConstant(0), /* initial time */
130  (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(PixelPacket)/5), /* width limit */
131  (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(PixelPacket)/5), /* height limit */
132  MagickResourceInfinity, /* list length limit */
133  MagickULLConstant(3072)*1024*1024, /* area limit */
134  MagickULLConstant(1536)*1024*1024, /* memory limit */
135  MagickULLConstant(3072)*1024*1024, /* map limit */
136  MagickResourceInfinity, /* disk limit */
137  MagickULLConstant(768), /* file limit */
138  MagickULLConstant(1), /* thread limit */
139  MagickULLConstant(0), /* throttle limit */
140  MagickResourceInfinity, /* time limit */
141  };
142 
143 static SemaphoreInfo
144  *resource_semaphore[] = {
145  (SemaphoreInfo *) NULL,
146  (SemaphoreInfo *) NULL,
147  (SemaphoreInfo *) NULL,
148  (SemaphoreInfo *) NULL,
149  (SemaphoreInfo *) NULL,
150  (SemaphoreInfo *) NULL,
151  (SemaphoreInfo *) NULL,
152  (SemaphoreInfo *) NULL,
153  (SemaphoreInfo *) NULL,
154  (SemaphoreInfo *) NULL,
155  (SemaphoreInfo *) NULL,
156  (SemaphoreInfo *) NULL
157  };
158 
159 static SplayTreeInfo
160  *temporary_resources = (SplayTreeInfo *) NULL;
161 
162 /*
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 % %
165 % %
166 % %
167 % A c q u i r e M a g i c k R e s o u r c e %
168 % %
169 % %
170 % %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 %
173 % AcquireMagickResource() acquires resources of the specified type.
174 % MagickFalse is returned if the specified resource is exhausted otherwise
175 % MagickTrue.
176 %
177 % The format of the AcquireMagickResource() method is:
178 %
179 % MagickBooleanType AcquireMagickResource(const ResourceType type,
180 % const MagickSizeType size)
181 %
182 % A description of each parameter follows:
183 %
184 % o type: the type of resource.
185 %
186 % o size: the number of bytes needed from for this resource.
187 %
188 */
189 MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
190  const MagickSizeType size)
191 {
192  char
193  resource_current[MaxTextExtent] = "",
194  resource_limit[MaxTextExtent] = "",
195  resource_request[MaxTextExtent] = "";
196 
197  MagickBooleanType
198  logging,
199  status;
200 
201  MagickOffsetType
202  request;
203 
204  MagickSizeType
205  limit;
206 
207  request=(MagickOffsetType) size;
208  if (request < 0)
209  return(MagickFalse);
210  status=MagickFalse;
211  logging=(GetLogEventMask() & ResourceEvent) != 0 ? MagickTrue : MagickFalse;
212  switch (type)
213  {
214  case DiskResource:
215  case FileResource:
216  case MapResource:
217  case MemoryResource:
218  case TimeResource:
219  {
220  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
221  ActivateSemaphoreInfo(&resource_semaphore[type]);
222  LockSemaphoreInfo(resource_semaphore[type]);
223  break;
224  }
225  default: ;
226  }
227  switch (type)
228  {
229  case AreaResource:
230  {
231  resource_info.area=(MagickOffsetType) size;
232  limit=resource_info.area_limit;
233  if ((limit == MagickResourceInfinity) || (size < limit))
234  status=MagickTrue;
235  if (logging != MagickFalse)
236  {
237  (void) FormatMagickSize(size,MagickFalse,resource_request);
238  (void) FormatMagickSize(size,MagickFalse,resource_current);
239  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
240  }
241  break;
242  }
243  case DiskResource:
244  {
245  limit=resource_info.disk_limit;
246  if (((MagickSizeType) resource_info.disk+request) >
247  (MagickSizeType) resource_info.disk)
248  {
249  resource_info.disk+=request;
250  if ((limit == MagickResourceInfinity) ||
251  (resource_info.disk < (MagickOffsetType) limit))
252  status=MagickTrue;
253  else
254  resource_info.disk-=request;
255  }
256  if (logging != MagickFalse)
257  {
258  (void) FormatMagickSize(size,MagickTrue,resource_request);
259  (void) FormatMagickSize((MagickSizeType) resource_info.disk,
260  MagickTrue,resource_current);
261  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
262  }
263  break;
264  }
265  case FileResource:
266  {
267  limit=resource_info.file_limit;
268  if (((MagickSizeType) resource_info.file+request) >
269  (MagickSizeType) resource_info.file)
270  {
271  resource_info.file+=request;
272  if ((limit == MagickResourceInfinity) ||
273  (resource_info.file < (MagickOffsetType) limit))
274  status=MagickTrue;
275  }
276  if (logging != MagickFalse)
277  {
278  (void) FormatMagickSize(size,MagickFalse,resource_request);
279  (void) FormatMagickSize((MagickSizeType) resource_info.file,
280  MagickFalse,resource_current);
281  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
282  }
283  break;
284  }
285  case HeightResource:
286  {
287  resource_info.height=(MagickOffsetType) size;
288  limit=resource_info.height_limit;
289  if ((limit == MagickResourceInfinity) || (size < limit))
290  status=MagickTrue;
291  if (logging != MagickFalse)
292  {
293  (void) FormatMagickSize(size,MagickFalse,resource_request);
294  (void) FormatMagickSize(size,MagickFalse,resource_current);
295  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
296  }
297  break;
298  }
299  case ListLengthResource:
300  {
301  resource_info.list_length=(MagickOffsetType) size;
302  limit=resource_info.list_length_limit;
303  if ((limit == MagickResourceInfinity) || (size < limit))
304  status=MagickTrue;
305  if (logging != MagickFalse)
306  {
307  (void) FormatMagickSize(size,MagickFalse,resource_request);
308  (void) FormatMagickSize(size,MagickFalse,resource_current);
309  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
310  }
311  break;
312  }
313  case MapResource:
314  {
315  limit=resource_info.map_limit;
316  if (((MagickSizeType) resource_info.map+request) >
317  (MagickSizeType) resource_info.map)
318  {
319  resource_info.map+=request;
320  if ((limit == MagickResourceInfinity) ||
321  (resource_info.map < (MagickOffsetType) limit))
322  status=MagickTrue;
323  else
324  resource_info.map-=request;
325  }
326  if (logging != MagickFalse)
327  {
328  (void) FormatMagickSize(size,MagickTrue,resource_request);
329  (void) FormatMagickSize((MagickSizeType) resource_info.map,
330  MagickTrue,resource_current);
331  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
332  }
333  break;
334  }
335  case MemoryResource:
336  {
337  limit=resource_info.memory_limit;
338  if (((MagickSizeType) resource_info.memory+request) >
339  (MagickSizeType) resource_info.memory)
340  {
341  resource_info.memory+=request;
342  if ((limit == MagickResourceInfinity) ||
343  (resource_info.memory < (MagickOffsetType) limit))
344  status=MagickTrue;
345  else
346  resource_info.memory-=request;
347  }
348  if (logging != MagickFalse)
349  {
350  (void) FormatMagickSize(size,MagickTrue,resource_request);
351  (void) FormatMagickSize((MagickSizeType) resource_info.memory,
352  MagickTrue,resource_current);
353  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
354  }
355  break;
356  }
357  case ThreadResource:
358  {
359  limit=resource_info.thread_limit;
360  if ((limit == MagickResourceInfinity) ||
361  (resource_info.thread < (MagickOffsetType) limit))
362  status=MagickTrue;
363  if (logging != MagickFalse)
364  {
365  (void) FormatMagickSize(size,MagickFalse,resource_request);
366  (void) FormatMagickSize((MagickSizeType) resource_info.thread,
367  MagickFalse,resource_current);
368  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
369  }
370  break;
371  }
372  case ThrottleResource:
373  {
374  limit=resource_info.throttle_limit;
375  if ((limit == MagickResourceInfinity) ||
376  (resource_info.throttle < (MagickOffsetType) limit))
377  status=MagickTrue;
378  if (logging != MagickFalse)
379  {
380  (void) FormatMagickSize(size,MagickFalse,resource_request);
381  (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
382  MagickFalse,resource_current);
383  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
384  }
385  break;
386  }
387  case TimeResource:
388  {
389  limit=resource_info.time_limit;
390  if (((MagickSizeType) resource_info.time+request) > (MagickSizeType) resource_info.time)
391  {
392  resource_info.time+=request;
393  if ((limit == MagickResourceInfinity) ||
394  (resource_info.time < (MagickOffsetType) 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(MagickFalse);
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  count,
958  i,
959  j;
960 
961  static const char
962  *bi_units[] =
963  {
964  "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi", "Ri", "Qi", (char *) NULL
965  },
966  *traditional_units[] =
967  {
968  "", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q", (char *) NULL
969  };
970 
971  bytes=1000.0;
972  units=traditional_units;
973  if (bi != MagickFalse)
974  {
975  bytes=1024.0;
976  units=bi_units;
977  }
978 #if defined(_MSC_VER) && (_MSC_VER == 1200)
979  length=(double) ((MagickOffsetType) size);
980 #else
981  length=(double) size;
982 #endif
983  for (i=0; (length >= bytes) && (units[i+1] != (const char *) NULL); i++)
984  length/=bytes;
985  count=0;
986  for (j=2; j < 12; j++)
987  {
988  count=FormatLocaleString(format,MaxTextExtent,"%.*g%sP",(int) (i+j),length,
989  units[i]);
990  if (strchr(format,'+') == (char *) NULL)
991  break;
992  }
993  return(count);
994 }
995 
996 static void FormatTimeToLive(const MagickSizeType ttl,char *timeString)
997 {
998  MagickSizeType
999  days,
1000  hours,
1001  minutes,
1002  months,
1003  seconds,
1004  weeks,
1005  years;
1006 
1007  years=ttl/31536000;
1008  seconds=ttl % 31536000;
1009  if (seconds == 0)
1010  {
1011  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld years",years);
1012  return;
1013  }
1014  months=ttl/2628000;
1015  seconds=ttl % 2628000;
1016  if (seconds == 0)
1017  {
1018  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld months",
1019  months);
1020  return;
1021  }
1022  weeks=ttl/604800;
1023  seconds=ttl % 604800;
1024  if (seconds == 0)
1025  {
1026  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld weeks",weeks);
1027  return;
1028  }
1029  days=ttl/86400;
1030  seconds=ttl % 86400;
1031  if (seconds == 0)
1032  {
1033  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld days",days);
1034  return;
1035  }
1036  hours=ttl/3600;
1037  seconds=ttl % 3600;
1038  if (seconds == 0)
1039  {
1040  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld hours",hours);
1041  return;
1042  }
1043  minutes=ttl/60;
1044  seconds=ttl % 60;
1045  if (seconds == 0)
1046  {
1047  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld minutes",
1048  minutes);
1049  return;
1050  }
1051  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld seconds",ttl);
1052 }
1053 
1054 MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
1055  ExceptionInfo *magick_unused(exception))
1056 {
1057  char
1058  area_limit[MaxTextExtent],
1059  disk_limit[MaxTextExtent],
1060  height_limit[MaxTextExtent],
1061  list_length_limit[MaxTextExtent],
1062  map_limit[MaxTextExtent],
1063  memory_limit[MaxTextExtent],
1064  time_limit[MaxTextExtent],
1065  width_limit[MaxTextExtent];
1066 
1067  magick_unreferenced(exception);
1068 
1069  if (file == (const FILE *) NULL)
1070  file=stdout;
1071  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1072  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1073  LockSemaphoreInfo(resource_semaphore[FileResource]);
1074  (void) FormatPixelSize(resource_info.width_limit,MagickFalse,width_limit);
1075  (void) FormatPixelSize(resource_info.height_limit,MagickFalse,height_limit);
1076  (void) FormatPixelSize(resource_info.area_limit,MagickFalse,area_limit);
1077  (void) CopyMagickString(list_length_limit,"unlimited",MaxTextExtent);
1078  if (resource_info.list_length_limit != MagickResourceInfinity)
1079  (void) FormatMagickSize(resource_info.list_length_limit,MagickTrue,
1080  list_length_limit);
1081  (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,memory_limit);
1082  (void) FormatMagickSize(resource_info.map_limit,MagickTrue,map_limit);
1083  (void) CopyMagickString(disk_limit,"unlimited",MaxTextExtent);
1084  if (resource_info.disk_limit != MagickResourceInfinity)
1085  (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,disk_limit);
1086  (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
1087  if (resource_info.time_limit != MagickResourceInfinity)
1088  FormatTimeToLive(resource_info.time_limit,time_limit);
1089  (void) FormatLocaleFile(file,"Resource limits:\n");
1090  (void) FormatLocaleFile(file," Width: %s\n",width_limit);
1091  (void) FormatLocaleFile(file," Height: %s\n",height_limit);
1092  (void) FormatLocaleFile(file," List length: %s\n",list_length_limit);
1093  (void) FormatLocaleFile(file," Area: %s\n",area_limit);
1094  (void) FormatLocaleFile(file," Memory: %s\n",memory_limit);
1095  (void) FormatLocaleFile(file," Map: %s\n",map_limit);
1096  (void) FormatLocaleFile(file," Disk: %s\n",disk_limit);
1097  (void) FormatLocaleFile(file," File: %.20g\n",(double) ((MagickOffsetType)
1098  resource_info.file_limit));
1099  (void) FormatLocaleFile(file," Thread: %.20g\n",(double) ((MagickOffsetType)
1100  resource_info.thread_limit));
1101  (void) FormatLocaleFile(file," Throttle: %.20g\n",(double)
1102  ((MagickOffsetType) resource_info.throttle_limit));
1103  (void) FormatLocaleFile(file," Time: %s\n",time_limit);
1104  (void) fflush(file);
1105  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1106  return(MagickTrue);
1107 }
1108 
1109 /*
1110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1111 % %
1112 % %
1113 % %
1114 % R e l i n q u i s h M a g i c k R e s o u r c e %
1115 % %
1116 % %
1117 % %
1118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 %
1120 % RelinquishMagickResource() relinquishes resources of the specified type.
1121 %
1122 % The format of the RelinquishMagickResource() method is:
1123 %
1124 % void RelinquishMagickResource(const ResourceType type,
1125 % const MagickSizeType size)
1126 %
1127 % A description of each parameter follows:
1128 %
1129 % o type: the type of resource.
1130 %
1131 % o size: the size of the resource.
1132 %
1133 */
1134 MagickExport void RelinquishMagickResource(const ResourceType type,
1135  const MagickSizeType size)
1136 {
1137  char
1138  resource_current[MaxTextExtent],
1139  resource_limit[MaxTextExtent],
1140  resource_request[MaxTextExtent];
1141 
1142  MagickBooleanType
1143  logging;
1144 
1145  logging=(GetLogEventMask() & ResourceEvent) != 0 ? MagickTrue : MagickFalse;
1146  if (logging != MagickFalse)
1147  (void) FormatMagickSize(size,MagickFalse,resource_request);
1148  switch (type)
1149  {
1150  case DiskResource:
1151  case FileResource:
1152  case MapResource:
1153  case MemoryResource:
1154  case TimeResource:
1155  {
1156  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1157  ActivateSemaphoreInfo(&resource_semaphore[type]);
1158  LockSemaphoreInfo(resource_semaphore[type]);
1159  break;
1160  }
1161  default: ;
1162  }
1163  switch (type)
1164  {
1165  case AreaResource:
1166  {
1167  resource_info.area=(MagickOffsetType) size;
1168  if (logging != MagickFalse)
1169  {
1170  (void) FormatMagickSize((MagickSizeType) resource_info.area,
1171  MagickFalse,resource_current);
1172  (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
1173  resource_limit);
1174  }
1175  break;
1176  }
1177  case DiskResource:
1178  {
1179  resource_info.disk-=size;
1180  assert(resource_info.disk >= 0);
1181  if (logging != MagickFalse)
1182  {
1183  (void) FormatMagickSize((MagickSizeType) resource_info.disk,
1184  MagickTrue,resource_current);
1185  (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,
1186  resource_limit);
1187  }
1188  break;
1189  }
1190  case FileResource:
1191  {
1192  resource_info.file-=size;
1193  assert(resource_info.file >= 0);
1194  if (logging != MagickFalse)
1195  {
1196  (void) FormatMagickSize((MagickSizeType) resource_info.file,
1197  MagickFalse,resource_current);
1198  (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
1199  MagickFalse,resource_limit);
1200  }
1201  break;
1202  }
1203  case HeightResource:
1204  {
1205  resource_info.height=(MagickOffsetType) size;
1206  if (logging != MagickFalse)
1207  {
1208  (void) FormatMagickSize((MagickSizeType) resource_info.height,
1209  MagickFalse,resource_current);
1210  (void) FormatMagickSize(resource_info.height_limit,MagickFalse,
1211  resource_limit);
1212  }
1213  break;
1214  }
1215  case ListLengthResource:
1216  {
1217  resource_info.list_length=(MagickOffsetType) size;
1218  if (logging != MagickFalse)
1219  {
1220  (void) FormatMagickSize((MagickSizeType) resource_info.list_length,
1221  MagickFalse,resource_current);
1222  (void) FormatMagickSize(resource_info.list_length_limit,MagickFalse,
1223  resource_limit);
1224  }
1225  break;
1226  }
1227  case MapResource:
1228  {
1229  resource_info.map-=size;
1230  assert(resource_info.map >= 0);
1231  if (logging != MagickFalse)
1232  {
1233  (void) FormatMagickSize((MagickSizeType) resource_info.map,
1234  MagickTrue,resource_current);
1235  (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
1236  resource_limit);
1237  }
1238  break;
1239  }
1240  case MemoryResource:
1241  {
1242  resource_info.memory-=size;
1243  assert(resource_info.memory >= 0);
1244  if (logging != MagickFalse)
1245  {
1246  (void) FormatMagickSize((MagickSizeType) resource_info.memory,
1247  MagickTrue,resource_current);
1248  (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
1249  resource_limit);
1250  }
1251  break;
1252  }
1253  case ThreadResource:
1254  {
1255  if (logging != MagickFalse)
1256  {
1257  (void) FormatMagickSize((MagickSizeType) resource_info.thread,
1258  MagickFalse,resource_current);
1259  (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
1260  MagickFalse,resource_limit);
1261  }
1262  break;
1263  }
1264  case ThrottleResource:
1265  {
1266  if (logging != MagickFalse)
1267  {
1268  (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
1269  MagickFalse,resource_current);
1270  (void) FormatMagickSize((MagickSizeType) resource_info.throttle_limit,
1271  MagickFalse,resource_limit);
1272  }
1273  break;
1274  }
1275  case TimeResource:
1276  {
1277  resource_info.time-=size;
1278  assert(resource_info.time >= 0);
1279  if (logging != MagickFalse)
1280  {
1281  (void) FormatMagickSize((MagickSizeType) resource_info.time,
1282  MagickFalse,resource_current);
1283  (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
1284  MagickFalse,resource_limit);
1285  }
1286  break;
1287  }
1288  case WidthResource:
1289  {
1290  resource_info.width=(MagickOffsetType) size;
1291  if (logging != MagickFalse)
1292  {
1293  (void) FormatMagickSize((MagickSizeType) resource_info.width,
1294  MagickFalse,resource_current);
1295  (void) FormatMagickSize(resource_info.width_limit,MagickFalse,
1296  resource_limit);
1297  }
1298  break;
1299  }
1300  default:
1301  break;
1302  }
1303  switch (type)
1304  {
1305  case DiskResource:
1306  case FileResource:
1307  case MapResource:
1308  case MemoryResource:
1309  case TimeResource:
1310  {
1311  UnlockSemaphoreInfo(resource_semaphore[type]);
1312  break;
1313  }
1314  default: ;
1315  }
1316  if (logging != MagickFalse)
1317  {
1318  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
1319  CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
1320  resource_request,resource_current,resource_limit);
1321  }
1322 }
1323 
1324 /*
1325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1326 % %
1327 % %
1328 % %
1329 % 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 %
1330 % %
1331 % %
1332 % %
1333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334 %
1335 % RelinquishUniqueFileResource() relinquishes a unique file resource.
1336 %
1337 % The format of the RelinquishUniqueFileResource() method is:
1338 %
1339 % MagickBooleanType RelinquishUniqueFileResource(const char *path)
1340 %
1341 % A description of each parameter follows:
1342 %
1343 % o name: the name of the temporary resource.
1344 %
1345 */
1346 MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
1347 {
1348  char
1349  cache_path[MaxTextExtent];
1350 
1351  MagickStatusType
1352  status;
1353 
1354  assert(path != (const char *) NULL);
1355  status=MagickFalse;
1356  if ((GetLogEventMask() & ResourceEvent) != 0)
1357  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"Relinquish %s",path);
1358  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1359  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1360  LockSemaphoreInfo(resource_semaphore[FileResource]);
1361  if (temporary_resources != (SplayTreeInfo *) NULL)
1362  status=DeleteNodeFromSplayTree(temporary_resources, (const void *) path);
1363  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1364  (void) CopyMagickString(cache_path,path,MaxTextExtent);
1365  AppendImageFormat("cache",cache_path);
1366  if (access_utf8(cache_path,F_OK) == 0)
1367  {
1368  status=ShredFile(cache_path);
1369  status|=remove_utf8(cache_path);
1370  }
1371  if (status == MagickFalse)
1372  {
1373  status=ShredFile(path);
1374  status|=remove_utf8(path);
1375  }
1376  return(status == 0 ? MagickFalse : MagickTrue);
1377 }
1378 
1379 /*
1380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % %
1382 % %
1383 % %
1384 + R e s o u r c e C o m p o n e n t G e n e s i s %
1385 % %
1386 % %
1387 % %
1388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1389 %
1390 % ResourceComponentGenesis() instantiates the resource component.
1391 %
1392 % The format of the ResourceComponentGenesis method is:
1393 %
1394 % MagickBooleanType ResourceComponentGenesis(void)
1395 %
1396 */
1397 MagickExport MagickBooleanType ResourceComponentGenesis(void)
1398 {
1399  char
1400  *limit;
1401 
1402  MagickSizeType
1403  memory;
1404 
1405  ssize_t
1406  files,
1407  i,
1408  number_threads,
1409  pages,
1410  pagesize;
1411 
1412  /*
1413  Set Magick resource limits.
1414  */
1415  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1416  if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1417  ActivateSemaphoreInfo(&resource_semaphore[i]);
1418  (void) SetMagickResourceLimit(WidthResource,resource_info.width_limit);
1419  limit=GetEnvironmentValue("MAGICK_WIDTH_LIMIT");
1420  if (limit != (char *) NULL)
1421  {
1422  (void) SetMagickResourceLimit(WidthResource,StringToSizeType(limit,
1423  100.0));
1424  limit=DestroyString(limit);
1425  }
1426  (void) SetMagickResourceLimit(HeightResource,resource_info.height_limit);
1427  limit=GetEnvironmentValue("MAGICK_HEIGHT_LIMIT");
1428  if (limit != (char *) NULL)
1429  {
1430  (void) SetMagickResourceLimit(HeightResource,StringToSizeType(limit,
1431  100.0));
1432  limit=DestroyString(limit);
1433  }
1434  pagesize=GetMagickPageSize();
1435  pages=(-1);
1436 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
1437  pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
1438 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1439  pages=pages/2;
1440 #endif
1441 #endif
1442  memory=(MagickSizeType) pages*pagesize;
1443  if ((pagesize <= 0) || (pages <= 0))
1444  memory=2048UL*1024UL*1024UL;
1445 #if defined(MAGICKCORE_PixelCacheThreshold)
1446  memory=StringToMagickSizeType(MAGICKCORE_PixelCacheThreshold,100.0);
1447 #endif
1448  (void) SetMagickResourceLimit(AreaResource,4*memory);
1449  limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
1450  if (limit != (char *) NULL)
1451  {
1452  (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
1453  limit=DestroyString(limit);
1454  }
1455  (void) SetMagickResourceLimit(MemoryResource,memory);
1456  limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
1457  if (limit != (char *) NULL)
1458  {
1459  (void) SetMagickResourceLimit(MemoryResource,
1460  StringToSizeType(limit,100.0));
1461  limit=DestroyString(limit);
1462  }
1463  (void) SetMagickResourceLimit(MapResource,2*memory);
1464  limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
1465  if (limit != (char *) NULL)
1466  {
1467  (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
1468  limit=DestroyString(limit);
1469  }
1470  (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity);
1471  limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
1472  if (limit != (char *) NULL)
1473  {
1474  (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
1475  limit=DestroyString(limit);
1476  }
1477  files=(-1);
1478 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1479  files=(ssize_t) sysconf(_SC_OPEN_MAX);
1480 #endif
1481 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1482  if (files < 0)
1483  {
1484  struct rlimit
1485  resources;
1486 
1487  if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
1488  files=(ssize_t) resources.rlim_cur;
1489  }
1490 #endif
1491 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
1492  if (files < 0)
1493  files=(ssize_t) getdtablesize();
1494 #endif
1495  if (files < 0)
1496  files=64;
1497  (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
1498  (3*files/4),64));
1499  limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
1500  if (limit != (char *) NULL)
1501  {
1502  (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,100.0));
1503  limit=DestroyString(limit);
1504  }
1505  number_threads=(ssize_t) GetOpenMPMaximumThreads();
1506  if (number_threads > 1)
1507  number_threads--; /* reserve core for OS */
1508  (void) SetMagickResourceLimit(ThreadResource,(size_t) number_threads);
1509  limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1510  if (limit != (char *) NULL)
1511  {
1512  (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
1513  100.0));
1514  limit=DestroyString(limit);
1515  }
1516  (void) SetMagickResourceLimit(ThrottleResource,0);
1517  limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT");
1518  if (limit != (char *) NULL)
1519  {
1520  (void) SetMagickResourceLimit(ThrottleResource,StringToSizeType(limit,
1521  100.0));
1522  limit=DestroyString(limit);
1523  }
1524  (void) SetMagickResourceLimit(TimeResource,MagickResourceInfinity);
1525  limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1526  if (limit != (char *) NULL)
1527  {
1528  (void) SetMagickResourceLimit(TimeResource,(MagickSizeType)
1529  ParseMagickTimeToLive(limit));
1530  limit=DestroyString(limit);
1531  }
1532  (void) SetMagickResourceLimit(ListLengthResource,MagickResourceInfinity);
1533  limit=GetEnvironmentValue("MAGICK_LIST_LENGTH_LIMIT");
1534  if (limit != (char *) NULL)
1535  {
1536  (void) SetMagickResourceLimit(ListLengthResource,
1537  StringToSizeType(limit,100.0));
1538  limit=DestroyString(limit);
1539  }
1540  return(MagickTrue);
1541 }
1542 
1543 /*
1544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545 % %
1546 % %
1547 % %
1548 + R e s o u r c e C o m p o n e n t T e r m i n u s %
1549 % %
1550 % %
1551 % %
1552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553 %
1554 % ResourceComponentTerminus() destroys the resource component.
1555 %
1556 % The format of the ResourceComponentTerminus() method is:
1557 %
1558 % ResourceComponentTerminus(void)
1559 %
1560 */
1561 MagickExport void ResourceComponentTerminus(void)
1562 {
1563  ssize_t
1564  i;
1565 
1566  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1567  if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1568  ActivateSemaphoreInfo(&resource_semaphore[i]);
1569  LockSemaphoreInfo(resource_semaphore[FileResource]);
1570  if (temporary_resources != (SplayTreeInfo *) NULL)
1571  temporary_resources=DestroySplayTree(temporary_resources);
1572  if (random_info != (RandomInfo *) NULL)
1573  random_info=DestroyRandomInfo(random_info);
1574  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1575  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1576  DestroySemaphoreInfo(&resource_semaphore[i]);
1577 }
1578 
1579 /*
1580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581 % %
1582 % %
1583 % %
1584 % S e t M a g i c k R e s o u r c e L i m i t %
1585 % %
1586 % %
1587 % %
1588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 %
1590 % SetMagickResourceLimit() sets the limit for a particular resource.
1591 %
1592 % The format of the SetMagickResourceLimit() method is:
1593 %
1594 % MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1595 % const MagickSizeType limit)
1596 %
1597 % A description of each parameter follows:
1598 %
1599 % o type: the type of resource.
1600 %
1601 % o limit: the maximum limit for the resource.
1602 %
1603 */
1604 
1605 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1606  const MagickSizeType limit)
1607 {
1608  char
1609  *value;
1610 
1611  MagickBooleanType
1612  status;
1613 
1614  status=MagickTrue;
1615  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1616  ActivateSemaphoreInfo(&resource_semaphore[type]);
1617  LockSemaphoreInfo(resource_semaphore[type]);
1618  value=(char *) NULL;
1619  switch (type)
1620  {
1621  case AreaResource:
1622  {
1623  value=GetPolicyValue("resource:area");
1624  if (value == (char *) NULL)
1625  resource_info.area_limit=limit;
1626  else
1627  resource_info.area_limit=MagickMin(limit,StringToSizeType(value,100.0));
1628  break;
1629  }
1630  case DiskResource:
1631  {
1632  value=GetPolicyValue("resource:disk");
1633  if (value == (char *) NULL)
1634  resource_info.disk_limit=limit;
1635  else
1636  resource_info.disk_limit=MagickMin(limit,StringToSizeType(value,100.0));
1637  break;
1638  }
1639  case FileResource:
1640  {
1641  value=GetPolicyValue("resource:file");
1642  if (value == (char *) NULL)
1643  resource_info.file_limit=limit;
1644  else
1645  resource_info.file_limit=MagickMin(limit,StringToSizeType(value,100.0));
1646  break;
1647  }
1648  case HeightResource:
1649  {
1650  value=GetPolicyValue("resource:height");
1651  if (value == (char *) NULL)
1652  resource_info.height_limit=limit;
1653  else
1654  resource_info.height_limit=MagickMin(limit,StringToSizeType(value,
1655  100.0));
1656  resource_info.height_limit=MagickMin(resource_info.height_limit,
1657  (MagickSizeType) MAGICK_SSIZE_MAX);
1658  break;
1659  }
1660  case ListLengthResource:
1661  {
1662  value=GetPolicyValue("resource:list-length");
1663  if (value == (char *) NULL)
1664  resource_info.list_length_limit=limit;
1665  else
1666  resource_info.list_length_limit=MagickMin(limit,
1667  StringToSizeType(value,100.0));
1668  break;
1669  }
1670  case MapResource:
1671  {
1672  value=GetPolicyValue("resource:map");
1673  if (value == (char *) NULL)
1674  resource_info.map_limit=limit;
1675  else
1676  resource_info.map_limit=MagickMin(limit,StringToSizeType(value,100.0));
1677  break;
1678  }
1679  case MemoryResource:
1680  {
1681  value=GetPolicyValue("resource:memory");
1682  if (value == (char *) NULL)
1683  resource_info.memory_limit=limit;
1684  else
1685  resource_info.memory_limit=MagickMin(limit,StringToSizeType(value,
1686  100.0));
1687  break;
1688  }
1689  case ThreadResource:
1690  {
1691  value=GetPolicyValue("resource:thread");
1692  if (value == (char *) NULL)
1693  resource_info.thread_limit=limit;
1694  else
1695  resource_info.thread_limit=MagickMin(limit,StringToSizeType(value,
1696  100.0));
1697  if (resource_info.thread_limit > GetOpenMPMaximumThreads())
1698  resource_info.thread_limit=GetOpenMPMaximumThreads();
1699  else
1700  if (resource_info.thread_limit == 0)
1701  resource_info.thread_limit=1;
1702  break;
1703  }
1704  case ThrottleResource:
1705  {
1706  value=GetPolicyValue("resource:throttle");
1707  if (value == (char *) NULL)
1708  resource_info.throttle_limit=limit;
1709  else
1710  resource_info.throttle_limit=MagickMax(limit,StringToSizeType(value,
1711  100.0));
1712  break;
1713  }
1714  case TimeResource:
1715  {
1716  value=GetPolicyValue("resource:time");
1717  if (value == (char *) NULL)
1718  resource_info.time_limit=limit;
1719  else
1720  resource_info.time_limit=MagickMin(limit,(MagickSizeType)
1721  ParseMagickTimeToLive(value));
1722  break;
1723  }
1724  case WidthResource:
1725  {
1726  value=GetPolicyValue("resource:width");
1727  if (value == (char *) NULL)
1728  resource_info.width_limit=limit;
1729  else
1730  resource_info.width_limit=MagickMin(limit,StringToSizeType(value,
1731  100.0));
1732  resource_info.width_limit=MagickMin(resource_info.width_limit,
1733  (MagickSizeType) MAGICK_SSIZE_MAX);
1734  break;
1735  }
1736  default:
1737  {
1738  status=MagickFalse;
1739  break;
1740  }
1741  }
1742  if (value != (char *) NULL)
1743  value=DestroyString(value);
1744  UnlockSemaphoreInfo(resource_semaphore[type]);
1745  return(status);
1746 }