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