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