utility.c revision 6f008fdcea6389206e36baf0f05c8999c7366f7b
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% U U TTTTT IIIII L IIIII TTTTT Y Y % 7% U U T I L I T Y Y % 8% U U T I L I T Y % 9% U U T I L I T Y % 10% UUU T IIIII LLLLL IIIII T Y % 11% % 12% % 13% MagickCore Utility Methods % 14% % 15% Software Design % 16% Cristy % 17% January 1993 % 18% % 19% % 20% Copyright 1999-2014 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% http://www.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/property.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/color.h" 46#include "MagickCore/exception.h" 47#include "MagickCore/exception-private.h" 48#include "MagickCore/geometry.h" 49#include "MagickCore/list.h" 50#include "MagickCore/log.h" 51#include "MagickCore/magick-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/semaphore.h" 60#include "MagickCore/signature-private.h" 61#include "MagickCore/statistic.h" 62#include "MagickCore/string_.h" 63#include "MagickCore/string-private.h" 64#include "MagickCore/token.h" 65#include "MagickCore/token-private.h" 66#include "MagickCore/utility.h" 67#include "MagickCore/utility-private.h" 68#if defined(MAGICKCORE_HAVE_PROCESS_H) 69#include <process.h> 70#endif 71#if defined(MAGICKCORE_HAVE_MACH_O_DYLD_H) 72#include <mach-o/dyld.h> 73#endif 74 75/* 76 Static declarations. 77*/ 78static const char 79 Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 80 81/* 82 Forward declaration. 83*/ 84static int 85 IsPathDirectory(const char *); 86 87/* 88%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 89% % 90% % 91% % 92% A c q u i r e U n i q u e F i l e n a m e % 93% % 94% % 95% % 96%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 97% 98% AcquireUniqueFilename() replaces the contents of path by a unique path name. 99% 100% The format of the AcquireUniqueFilename method is: 101% 102% MagickBooleanType AcquireUniqueFilename(char *path) 103% 104% A description of each parameter follows. 105% 106% o path: Specifies a pointer to an array of characters. The unique path 107% name is returned in this array. 108% 109*/ 110MagickExport MagickBooleanType AcquireUniqueFilename(char *path) 111{ 112 int 113 file; 114 115 file=AcquireUniqueFileResource(path); 116 if (file == -1) 117 return(MagickFalse); 118 file=close(file)-1; 119 return(MagickTrue); 120} 121 122/* 123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 124% % 125% % 126% % 127% A c q u i r e U n i q u e S ym b o l i c L i n k % 128% % 129% % 130% % 131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 132% 133% AcquireUniqueSymbolicLink() creates a unique symbolic link to the specified 134% source path and returns MagickTrue on success otherwise MagickFalse. If the 135% symlink() method fails or is not available, a unique file name is generated 136% and the source file copied to it. When you are finished with the file, use 137% RelinquishUniqueFilename() to destroy it. 138% 139% The format of the AcquireUniqueSymbolicLink method is: 140% 141% MagickBooleanType AcquireUniqueSymbolicLink(const char *source, 142% char destination) 143% 144% A description of each parameter follows. 145% 146% o source: the source path. 147% 148% o destination: the destination path. 149% 150*/ 151 152static inline MagickSizeType MagickMin(const MagickSizeType x, 153 const MagickSizeType y) 154{ 155 if (x < y) 156 return(x); 157 return(y); 158} 159 160MagickExport MagickBooleanType AcquireUniqueSymbolicLink(const char *source, 161 char *destination) 162{ 163 int 164 destination_file, 165 source_file; 166 167 size_t 168 length, 169 quantum; 170 171 ssize_t 172 count; 173 174 struct stat 175 attributes; 176 177 unsigned char 178 *buffer; 179 180 assert(source != (const char *) NULL); 181 assert(destination != (char *) NULL); 182#if defined(MAGICKCORE_HAVE_SYMLINK) 183 (void) AcquireUniqueFilename(destination); 184 (void) RelinquishUniqueFileResource(destination); 185 if (*source == *DirectorySeparator) 186 { 187 if (symlink(source,destination) == 0) 188 return(MagickTrue); 189 } 190 else 191 { 192 char 193 path[MaxTextExtent]; 194 195 *path='\0'; 196 if (getcwd(path,MaxTextExtent) == (char *) NULL) 197 return(MagickFalse); 198 (void) ConcatenateMagickString(path,DirectorySeparator,MaxTextExtent); 199 (void) ConcatenateMagickString(path,source,MaxTextExtent); 200 if (symlink(path,destination) == 0) 201 return(MagickTrue); 202 } 203#endif 204 destination_file=AcquireUniqueFileResource(destination); 205 if (destination_file == -1) 206 return(MagickFalse); 207 source_file=open_utf8(source,O_RDONLY | O_BINARY,0); 208 if (source_file == -1) 209 { 210 (void) close(destination_file); 211 (void) RelinquishUniqueFileResource(destination); 212 return(MagickFalse); 213 } 214 quantum=(size_t) MagickMaxBufferExtent; 215 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0)) 216 quantum=(size_t) MagickMin((size_t) attributes.st_size, 217 MagickMaxBufferExtent); 218 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer)); 219 if (buffer == (unsigned char *) NULL) 220 { 221 (void) close(source_file); 222 (void) close(destination_file); 223 (void) RelinquishUniqueFileResource(destination); 224 return(MagickFalse); 225 } 226 for (length=0; ; ) 227 { 228 count=(ssize_t) read(source_file,buffer,quantum); 229 if (count <= 0) 230 break; 231 length=(size_t) count; 232 count=(ssize_t) write(destination_file,buffer,length); 233 if ((size_t) count != length) 234 { 235 (void) close(destination_file); 236 (void) close(source_file); 237 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 238 (void) RelinquishUniqueFileResource(destination); 239 return(MagickFalse); 240 } 241 } 242 (void) close(destination_file); 243 (void) close(source_file); 244 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 245 return(MagickTrue); 246} 247 248/* 249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 250% % 251% % 252% % 253% A p p e n d I m a g e F o r m a t % 254% % 255% % 256% % 257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 258% 259% AppendImageFormat() appends the image format type to the filename. If an 260% extension to the file already exists, it is first removed. 261% 262% The format of the AppendImageFormat method is: 263% 264% void AppendImageFormat(const char *format,char *filename) 265% 266% A description of each parameter follows. 267% 268% o format: Specifies a pointer to an array of characters. This the 269% format of the image. 270% 271% o filename: Specifies a pointer to an array of characters. The unique 272% file name is returned in this array. 273% 274*/ 275MagickExport void AppendImageFormat(const char *format,char *filename) 276{ 277 char 278 extension[MaxTextExtent], 279 root[MaxTextExtent]; 280 281 assert(format != (char *) NULL); 282 assert(filename != (char *) NULL); 283 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 284 if ((*format == '\0') || (*filename == '\0')) 285 return; 286 if (LocaleCompare(filename,"-") == 0) 287 { 288 char 289 message[MaxTextExtent]; 290 291 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",format,filename); 292 (void) CopyMagickString(filename,message,MaxTextExtent); 293 return; 294 } 295 GetPathComponent(filename,ExtensionPath,extension); 296 if ((LocaleCompare(extension,"Z") == 0) || 297 (LocaleCompare(extension,"bz2") == 0) || 298 (LocaleCompare(extension,"gz") == 0) || 299 (LocaleCompare(extension,"wmz") == 0) || 300 (LocaleCompare(extension,"svgz") == 0)) 301 { 302 GetPathComponent(filename,RootPath,root); 303 (void) CopyMagickString(filename,root,MaxTextExtent); 304 GetPathComponent(filename,RootPath,root); 305 (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s.%s",root,format, 306 extension); 307 return; 308 } 309 GetPathComponent(filename,RootPath,root); 310 (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s",root,format); 311} 312 313/* 314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 315% % 316% % 317% % 318% B a s e 6 4 D e c o d e % 319% % 320% % 321% % 322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 323% 324% Base64Decode() decodes Base64-encoded text and returns its binary 325% equivalent. NULL is returned if the text is not valid Base64 data, or a 326% memory allocation failure occurs. 327% 328% The format of the Base64Decode method is: 329% 330% unsigned char *Base64Decode(const char *source,length_t *length) 331% 332% A description of each parameter follows: 333% 334% o source: A pointer to a Base64-encoded string. 335% 336% o length: the number of bytes decoded. 337% 338*/ 339MagickExport unsigned char *Base64Decode(const char *source,size_t *length) 340{ 341 int 342 state; 343 344 register const char 345 *p, 346 *q; 347 348 register size_t 349 i; 350 351 unsigned char 352 *decode; 353 354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 355 assert(source != (char *) NULL); 356 assert(length != (size_t *) NULL); 357 *length=0; 358 decode=(unsigned char *) AcquireQuantumMemory(strlen(source)/4+4, 359 3*sizeof(*decode)); 360 if (decode == (unsigned char *) NULL) 361 return((unsigned char *) NULL); 362 i=0; 363 state=0; 364 for (p=source; *p != '\0'; p++) 365 { 366 if (isspace((int) ((unsigned char) *p)) != 0) 367 continue; 368 if (*p == '=') 369 break; 370 q=strchr(Base64,*p); 371 if (q == (char *) NULL) 372 { 373 decode=(unsigned char *) RelinquishMagickMemory(decode); 374 return((unsigned char *) NULL); /* non-Base64 character */ 375 } 376 switch (state) 377 { 378 case 0: 379 { 380 decode[i]=(q-Base64) << 2; 381 state++; 382 break; 383 } 384 case 1: 385 { 386 decode[i++]|=(q-Base64) >> 4; 387 decode[i]=((q-Base64) & 0x0f) << 4; 388 state++; 389 break; 390 } 391 case 2: 392 { 393 decode[i++]|=(q-Base64) >> 2; 394 decode[i]=((q-Base64) & 0x03) << 6; 395 state++; 396 break; 397 } 398 case 3: 399 { 400 decode[i++]|=(q-Base64); 401 state=0; 402 break; 403 } 404 } 405 } 406 /* 407 Verify Base-64 string has proper terminal characters. 408 */ 409 if (*p != '=') 410 { 411 if (state != 0) 412 { 413 decode=(unsigned char *) RelinquishMagickMemory(decode); 414 return((unsigned char *) NULL); 415 } 416 } 417 else 418 { 419 p++; 420 switch (state) 421 { 422 case 0: 423 case 1: 424 { 425 /* 426 Unrecognized '=' character. 427 */ 428 decode=(unsigned char *) RelinquishMagickMemory(decode); 429 return((unsigned char *) NULL); 430 } 431 case 2: 432 { 433 for ( ; *p != '\0'; p++) 434 if (isspace((int) ((unsigned char) *p)) == 0) 435 break; 436 if (*p != '=') 437 { 438 decode=(unsigned char *) RelinquishMagickMemory(decode); 439 return((unsigned char *) NULL); 440 } 441 p++; 442 } 443 case 3: 444 { 445 for ( ; *p != '\0'; p++) 446 if (isspace((int) ((unsigned char) *p)) == 0) 447 { 448 decode=(unsigned char *) RelinquishMagickMemory(decode); 449 return((unsigned char *) NULL); 450 } 451 if ((int) decode[i] != 0) 452 { 453 decode=(unsigned char *) RelinquishMagickMemory(decode); 454 return((unsigned char *) NULL); 455 } 456 break; 457 } 458 } 459 } 460 *length=i; 461 return(decode); 462} 463 464/* 465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 466% % 467% % 468% % 469% B a s e 6 4 E n c o d e % 470% % 471% % 472% % 473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 474% 475% Base64Encode() encodes arbitrary binary data to Base64 encoded format as 476% described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and 477% returns the result as a null-terminated ASCII string. NULL is returned if 478% a memory allocation failure occurs. 479% 480% The format of the Base64Encode method is: 481% 482% char *Base64Encode(const unsigned char *blob,const size_t blob_length, 483% size_t *encode_length) 484% 485% A description of each parameter follows: 486% 487% o blob: A pointer to binary data to encode. 488% 489% o blob_length: the number of bytes to encode. 490% 491% o encode_length: The number of bytes encoded. 492% 493*/ 494MagickExport char *Base64Encode(const unsigned char *blob, 495 const size_t blob_length,size_t *encode_length) 496{ 497 char 498 *encode; 499 500 register const unsigned char 501 *p; 502 503 register size_t 504 i; 505 506 size_t 507 remainder; 508 509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 510 assert(blob != (const unsigned char *) NULL); 511 assert(blob_length != 0); 512 assert(encode_length != (size_t *) NULL); 513 *encode_length=0; 514 encode=(char *) AcquireQuantumMemory(blob_length/3+4,4*sizeof(*encode)); 515 if (encode == (char *) NULL) 516 return((char *) NULL); 517 i=0; 518 for (p=blob; p < (blob+blob_length-2); p+=3) 519 { 520 encode[i++]=Base64[(int) (*p >> 2)]; 521 encode[i++]=Base64[(int) (((*p & 0x03) << 4)+(*(p+1) >> 4))]; 522 encode[i++]=Base64[(int) (((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))]; 523 encode[i++]=Base64[(int) (*(p+2) & 0x3f)]; 524 } 525 remainder=blob_length % 3; 526 if (remainder != 0) 527 { 528 ssize_t 529 j; 530 531 unsigned char 532 code[3]; 533 534 code[0]='\0'; 535 code[1]='\0'; 536 code[2]='\0'; 537 for (j=0; j < (ssize_t) remainder; j++) 538 code[j]=(*p++); 539 encode[i++]=Base64[(int) (code[0] >> 2)]; 540 encode[i++]=Base64[(int) (((code[0] & 0x03) << 4)+(code[1] >> 4))]; 541 if (remainder == 1) 542 encode[i++]='='; 543 else 544 encode[i++]=Base64[(int) (((code[1] & 0x0f) << 2)+(code[2] >> 6))]; 545 encode[i++]='='; 546 } 547 *encode_length=i; 548 encode[i++]='\0'; 549 return(encode); 550} 551 552/* 553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 554% % 555% % 556% % 557% C h o p P a t h C o m p o n e n t s % 558% % 559% % 560% % 561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 562% 563% ChopPathComponents() removes the number of specified file components from a 564% path. 565% 566% The format of the ChopPathComponents method is: 567% 568% ChopPathComponents(char *path,size_t components) 569% 570% A description of each parameter follows: 571% 572% o path: The path. 573% 574% o components: The number of components to chop. 575% 576*/ 577MagickPrivate void ChopPathComponents(char *path,const size_t components) 578{ 579 register ssize_t 580 i; 581 582 for (i=0; i < (ssize_t) components; i++) 583 GetPathComponent(path,HeadPath,path); 584} 585 586/* 587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 588% % 589% % 590% % 591% E x p a n d F i l e n a m e % 592% % 593% % 594% % 595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 596% 597% ExpandFilename() expands '~' in a path. 598% 599% The format of the ExpandFilename function is: 600% 601% ExpandFilename(char *path) 602% 603% A description of each parameter follows: 604% 605% o path: Specifies a pointer to a character array that contains the 606% path. 607% 608*/ 609MagickPrivate void ExpandFilename(char *path) 610{ 611 char 612 expand_path[MaxTextExtent]; 613 614 if (path == (char *) NULL) 615 return; 616 if (*path != '~') 617 return; 618 (void) CopyMagickString(expand_path,path,MaxTextExtent); 619 if ((*(path+1) == *DirectorySeparator) || (*(path+1) == '\0')) 620 { 621 char 622 *home; 623 624 /* 625 Substitute ~ with $HOME. 626 */ 627 (void) CopyMagickString(expand_path,".",MaxTextExtent); 628 (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent); 629 home=GetEnvironmentValue("HOME"); 630 if (home == (char *) NULL) 631 home=GetEnvironmentValue("USERPROFILE"); 632 if (home != (char *) NULL) 633 { 634 (void) CopyMagickString(expand_path,home,MaxTextExtent); 635 (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent); 636 home=DestroyString(home); 637 } 638 } 639 else 640 { 641#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__) 642 char 643 username[MaxTextExtent]; 644 645 register char 646 *p; 647 648 struct passwd 649 *entry; 650 651 /* 652 Substitute ~ with home directory from password file. 653 */ 654 (void) CopyMagickString(username,path+1,MaxTextExtent); 655 p=strchr(username,'/'); 656 if (p != (char *) NULL) 657 *p='\0'; 658 entry=getpwnam(username); 659 if (entry == (struct passwd *) NULL) 660 return; 661 (void) CopyMagickString(expand_path,entry->pw_dir,MaxTextExtent); 662 if (p != (char *) NULL) 663 { 664 (void) ConcatenateMagickString(expand_path,"/",MaxTextExtent); 665 (void) ConcatenateMagickString(expand_path,p+1,MaxTextExtent); 666 } 667#endif 668 } 669 (void) CopyMagickString(path,expand_path,MaxTextExtent); 670} 671 672/* 673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 674% % 675% % 676% % 677% E x p a n d F i l e n a m e s % 678% % 679% % 680% % 681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 682% 683% ExpandFilenames() checks each argument of the given argument array, and 684% expands it if they have a wildcard character. 685% 686% Any coder prefix (EG: 'coder:filename') or read modifier postfix (EG: 687% 'filename[...]') are ignored during the file the expansion, but will be 688% included in the final argument. If no filename matching the meta-character 689% 'glob' is found the original argument is returned. 690% 691% For example, an argument of '*.gif[20x20]' will be replaced by the list 692% 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]' 693% if such filenames exist, (in the current directory in this case). 694% 695% Meta-characters handled... 696% @ read a list of filenames (no further expansion performed) 697% ~ At start of filename expands to HOME environemtn variable 698% * matches any string including an empty string 699% ? matches by any single character 700% 701% WARNING: filenames starting with '.' (hidden files in a UNIX file system) 702% will never be expanded. Attempting to epand '.*' will produce no change. 703% 704% Expansion is ignored for coders "label:" "caption:" "pango:" and "vid:". 705% Which provide their own '@' meta-character handling. 706% 707% You can see the results of the expansion using "Configure" log events. 708% 709% The returned list should be freed using DestroyStringList(). 710% 711% However the strings in the original pointed to argv are not 712% freed (TO BE CHECKED). So a copy of the original pointer (and count) 713% should be kept separate if they need to be freed later. 714% 715% The format of the ExpandFilenames function is: 716% 717% status=ExpandFilenames(int *number_arguments,char ***arguments) 718% 719% A description of each parameter follows: 720% 721% o number_arguments: Specifies a pointer to an integer describing the 722% number of elements in the argument vector. 723% 724% o arguments: Specifies a pointer to a text array containing the command 725% line arguments. 726% 727*/ 728MagickExport MagickBooleanType ExpandFilenames(int *number_arguments, 729 char ***arguments) 730{ 731 char 732 *directory, 733 home_directory[MaxTextExtent], 734 **vector; 735 736 register ssize_t 737 i, 738 j; 739 740 size_t 741 number_files; 742 743 ssize_t 744 count, 745 parameters; 746 747 /* 748 Allocate argument vector. 749 */ 750 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 751 assert(number_arguments != (int *) NULL); 752 assert(arguments != (char ***) NULL); 753 vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1), 754 sizeof(*vector)); 755 if (vector == (char **) NULL) 756 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 757 /* 758 Expand any wildcard filenames. 759 */ 760 *home_directory='\0'; 761 count=0; 762 for (i=0; i < (ssize_t) *number_arguments; i++) 763 { 764 char 765 **filelist, 766 filename[MaxTextExtent], 767 magick[MaxTextExtent], 768 *option, 769 path[MaxTextExtent], 770 subimage[MaxTextExtent]; 771 772 MagickBooleanType 773 destroy; 774 775 option=(*arguments)[i]; 776 *magick='\0'; 777 *path='\0'; 778 *filename='\0'; 779 *subimage='\0'; 780 number_files=0; 781 vector[count++]=ConstantString(option); 782 destroy=MagickTrue; 783 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option); 784 if (parameters > 0) 785 { 786 /* 787 Do not expand command option parameters. 788 */ 789 for (j=0; j < parameters; j++) 790 { 791 i++; 792 if (i == (ssize_t) *number_arguments) 793 break; 794 option=(*arguments)[i]; 795 vector[count++]=ConstantString(option); 796 } 797 continue; 798 } 799 if ((*option == '"') || (*option == '\'')) 800 continue; 801 GetPathComponent(option,TailPath,filename); 802 GetPathComponent(option,MagickPath,magick); 803 if ((LocaleCompare(magick,"CAPTION") == 0) || 804 (LocaleCompare(magick,"LABEL") == 0) || 805 (LocaleCompare(magick,"PANGO") == 0) || 806 (LocaleCompare(magick,"VID") == 0)) 807 continue; 808 if ((IsGlob(filename) == MagickFalse) && (*option != '@')) 809 continue; 810 if (*option != '@') 811 { 812 /* 813 Generate file list from wildcard filename (e.g. *.jpg). 814 */ 815 GetPathComponent(option,HeadPath,path); 816 GetPathComponent(option,SubimagePath,subimage); 817 ExpandFilename(path); 818 if (*home_directory == '\0') 819 directory=getcwd(home_directory,MaxTextExtent-1); 820 (void) directory; 821 filelist=ListFiles(*path == '\0' ? home_directory : path,filename, 822 &number_files); 823 } 824 else 825 { 826 char 827 *files; 828 829 ExceptionInfo 830 *exception; 831 832 int 833 length; 834 835 /* 836 Generate file list from file list (e.g. @filelist.txt). 837 */ 838 exception=AcquireExceptionInfo(); 839 files=FileToString(option+1,~0UL,exception); 840 exception=DestroyExceptionInfo(exception); 841 if (files == (char *) NULL) 842 continue; 843 filelist=StringToArgv(files,&length); 844 if (filelist == (char **) NULL) 845 continue; 846 files=DestroyString(files); 847 filelist[0]=DestroyString(filelist[0]); 848 for (j=0; j < (ssize_t) (length-1); j++) 849 filelist[j]=filelist[j+1]; 850 number_files=(size_t) length-1; 851 } 852 if (filelist == (char **) NULL) 853 continue; 854 for (j=0; j < (ssize_t) number_files; j++) 855 if (IsPathDirectory(filelist[j]) <= 0) 856 break; 857 if (j == (ssize_t) number_files) 858 { 859 for (j=0; j < (ssize_t) number_files; j++) 860 filelist[j]=DestroyString(filelist[j]); 861 filelist=(char **) RelinquishMagickMemory(filelist); 862 continue; 863 } 864 /* 865 Transfer file list to argument vector. 866 */ 867 vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+ 868 count+number_files+1,sizeof(*vector)); 869 if (vector == (char **) NULL) 870 return(MagickFalse); 871 for (j=0; j < (ssize_t) number_files; j++) 872 { 873 option=filelist[j]; 874 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option); 875 if (parameters > 0) 876 { 877 ssize_t 878 k; 879 880 /* 881 Do not expand command option parameters. 882 */ 883 vector[count++]=ConstantString(option); 884 for (k=0; k < parameters; k++) 885 { 886 j++; 887 if (j == (ssize_t) number_files) 888 break; 889 option=filelist[j]; 890 vector[count++]=ConstantString(option); 891 } 892 continue; 893 } 894 (void) CopyMagickString(filename,path,MaxTextExtent); 895 if (*path != '\0') 896 (void) ConcatenateMagickString(filename,DirectorySeparator, 897 MaxTextExtent); 898 if (filelist[j] != (char *) NULL) 899 (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent); 900 filelist[j]=DestroyString(filelist[j]); 901 if (strlen(filename) >= (MaxTextExtent-1)) 902 ThrowFatalException(OptionFatalError,"FilenameTruncated"); 903 if (IsPathDirectory(filename) <= 0) 904 { 905 char 906 path[MaxTextExtent]; 907 908 *path='\0'; 909 if (*magick != '\0') 910 { 911 (void) ConcatenateMagickString(path,magick,MaxTextExtent); 912 (void) ConcatenateMagickString(path,":",MaxTextExtent); 913 } 914 (void) ConcatenateMagickString(path,filename,MaxTextExtent); 915 if (*subimage != '\0') 916 { 917 (void) ConcatenateMagickString(path,"[",MaxTextExtent); 918 (void) ConcatenateMagickString(path,subimage,MaxTextExtent); 919 (void) ConcatenateMagickString(path,"]",MaxTextExtent); 920 } 921 if (strlen(path) >= (MaxTextExtent-1)) 922 ThrowFatalException(OptionFatalError,"FilenameTruncated"); 923 if (destroy != MagickFalse) 924 { 925 count--; 926 vector[count]=DestroyString(vector[count]); 927 destroy=MagickFalse; 928 } 929 vector[count++]=ConstantString(path); 930 } 931 } 932 filelist=(char **) RelinquishMagickMemory(filelist); 933 } 934 vector[count]=(char *) NULL; 935 if (IsEventLogging() != MagickFalse) 936 { 937 char 938 *command_line; 939 940 command_line=AcquireString(vector[0]); 941 for (i=1; i < count; i++) 942 { 943 (void) ConcatenateString(&command_line," {"); 944 (void) ConcatenateString(&command_line,vector[i]); 945 (void) ConcatenateString(&command_line,"}"); 946 } 947 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), 948 "Command line: %s",command_line); 949 command_line=DestroyString(command_line); 950 } 951 *number_arguments=(int) count; 952 *arguments=vector; 953 return(MagickTrue); 954} 955 956/* 957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 958% % 959% % 960% % 961% G e t E x e c u t i o n P a t h % 962% % 963% % 964% % 965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 966% 967% GetExecutionPath() returns the pathname of the executable that started 968% the process. On success MagickTrue is returned, otherwise MagickFalse. 969% 970% The format of the GetExecutionPath method is: 971% 972% MagickBooleanType GetExecutionPath(char *path,const size_t extent) 973% 974% A description of each parameter follows: 975% 976% o path: the pathname of the executable that started the process. 977% 978% o extent: the maximum extent of the path. 979% 980*/ 981MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent) 982{ 983 char 984 *directory; 985 986 *path='\0'; 987 directory=getcwd(path,(unsigned long) extent); 988 (void) directory; 989#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX) 990 { 991 char 992 link_path[MaxTextExtent], 993 execution_path[PATH_MAX+1]; 994 995 ssize_t 996 count; 997 998 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/exe", 999 (double) getpid()); 1000 count=readlink(link_path,execution_path,PATH_MAX); 1001 if (count == -1) 1002 { 1003 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/file", 1004 (double) getpid()); 1005 count=readlink(link_path,execution_path,PATH_MAX); 1006 } 1007 if ((count > 0) && (count <= (ssize_t) PATH_MAX)) 1008 { 1009 execution_path[count]='\0'; 1010 (void) CopyMagickString(path,execution_path,extent); 1011 } 1012 } 1013#endif 1014#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH) 1015 { 1016 char 1017 executable_path[PATH_MAX << 1], 1018 execution_path[PATH_MAX+1]; 1019 1020 uint32_t 1021 length; 1022 1023 length=sizeof(executable_path); 1024 if ((_NSGetExecutablePath(executable_path,&length) == 0) && 1025 (realpath(executable_path,execution_path) != (char *) NULL)) 1026 (void) CopyMagickString(path,execution_path,extent); 1027 } 1028#endif 1029#if defined(MAGICKCORE_HAVE_GETEXECNAME) 1030 { 1031 const char 1032 *execution_path; 1033 1034 execution_path=(const char *) getexecname(); 1035 if (execution_path != (const char *) NULL) 1036 { 1037 if (*execution_path != *DirectorySeparator) 1038 (void) ConcatenateMagickString(path,DirectorySeparator,extent); 1039 (void) ConcatenateMagickString(path,execution_path,extent); 1040 } 1041 } 1042#endif 1043#if defined(MAGICKCORE_WINDOWS_SUPPORT) 1044 NTGetExecutionPath(path,extent); 1045#endif 1046#if defined(__GNU__) 1047 { 1048 char 1049 *program_name, 1050 *execution_path; 1051 1052 ssize_t 1053 count; 1054 1055 count=0; 1056 execution_path=(char *) NULL; 1057 program_name=program_invocation_name; 1058 if (*program_invocation_name != '/') 1059 { 1060 size_t 1061 extent; 1062 1063 extent=strlen(directory)+strlen(program_name)+2; 1064 program_name=AcquireQuantumMemory(extent,sizeof(*program_name)); 1065 if (program_name == (char *) NULL) 1066 program_name=program_invocation_name; 1067 else 1068 count=FormatLocaleString(program_name,extent,"%s/%s",directory, 1069 program_invocation_name); 1070 } 1071 if (count != -1) 1072 { 1073 execution_path=realpath(program_name,NULL); 1074 if (execution_path != (char *) NULL) 1075 (void) CopyMagickString(path,execution_path,extent); 1076 } 1077 if (program_name != program_invocation_name) 1078 program_name=(char *) RelinquishMagickMemory(program_name); 1079 execution_path=(char *) RelinquishMagickMemory(execution_path); 1080 } 1081#endif 1082#if defined(__OpenBSD__) 1083 { 1084 extern char 1085 *__progname; 1086 1087 (void) CopyMagickString(path,__progname,extent); 1088 } 1089#endif 1090 return(IsPathAccessible(path)); 1091} 1092 1093/* 1094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1095% % 1096% % 1097% % 1098% G e t M a g i c k P a g e S i z e % 1099% % 1100% % 1101% % 1102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1103% 1104% GetMagickPageSize() returns the memory page size. 1105% 1106% The format of the GetMagickPageSize method is: 1107% 1108% ssize_t GetMagickPageSize() 1109% 1110*/ 1111MagickPrivate ssize_t GetMagickPageSize(void) 1112{ 1113 static ssize_t 1114 page_size = -1; 1115 1116 if (page_size > 0) 1117 return(page_size); 1118#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) 1119 page_size=(ssize_t) sysconf(_SC_PAGE_SIZE); 1120#else 1121#if defined(MAGICKCORE_HAVE_GETPAGESIZE) 1122 page_size=(ssize_t) getpagesize(); 1123#endif 1124#endif 1125 if (page_size <= 0) 1126 page_size=16384; 1127 return(page_size); 1128} 1129 1130/* 1131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1132% % 1133% % 1134% % 1135% G e t P a t h A t t r i b u t e s % 1136% % 1137% % 1138% % 1139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1140% 1141% GetPathAttributes() returns attributes (e.g. size of file) about a path. 1142% 1143% The path of the GetPathAttributes method is: 1144% 1145% MagickBooleanType GetPathAttributes(const char *path,void *attributes) 1146% 1147% A description of each parameter follows. 1148% 1149% o path: the file path. 1150% 1151% o attributes: the path attributes are returned here. 1152% 1153*/ 1154MagickExport MagickBooleanType GetPathAttributes(const char *path, 1155 void *attributes) 1156{ 1157 MagickBooleanType 1158 status; 1159 1160 if (path == (const char *) NULL) 1161 { 1162 errno=EINVAL; 1163 return(MagickFalse); 1164 } 1165 status=stat_utf8(path,(struct stat *) attributes) == 0 ? MagickTrue : 1166 MagickFalse; 1167 return(status); 1168} 1169 1170/* 1171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1172% % 1173% % 1174% % 1175% G e t P a t h C o m p o n e n t % 1176% % 1177% % 1178% % 1179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1180% 1181% GetPathComponent() returns the parent directory name, filename, basename, or 1182% extension of a file path. 1183% 1184% The component string pointed to must have at least MaxTextExtent space 1185% for the results to be stored. 1186% 1187% The format of the GetPathComponent function is: 1188% 1189% GetPathComponent(const char *path,PathType type,char *component) 1190% 1191% A description of each parameter follows: 1192% 1193% o path: Specifies a pointer to a character array that contains the 1194% file path. 1195% 1196% o type: Specififies which file path component to return. 1197% 1198% o component: the selected file path component is returned here. 1199% 1200*/ 1201MagickExport void GetPathComponent(const char *path,PathType type, 1202 char *component) 1203{ 1204 char 1205 magick[MaxTextExtent], 1206 *q, 1207 subimage[MaxTextExtent]; 1208 1209 register char 1210 *p; 1211 1212 assert(path != (const char *) NULL); 1213 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path); 1214 assert(component != (char *) NULL); 1215 if (*path == '\0') 1216 { 1217 *component='\0'; 1218 return; 1219 } 1220 (void) CopyMagickString(component,path,MaxTextExtent); 1221 *magick='\0'; 1222#if defined(__OS2__) 1223 if (path[1] != ":") 1224#endif 1225 for (p=component; *p != '\0'; p++) 1226 { 1227 if ((*p == '%') && (*(p+1) == '[')) 1228 { 1229 /* 1230 Skip over %[...]. 1231 */ 1232 for (p++; (*p != ']') && (*p != '\0'); p++) ; 1233 if (*p == '\0') 1234 break; 1235 } 1236 if ((*p == ':') && (IsPathDirectory(path) < 0) && 1237 (IsPathAccessible(path) == MagickFalse)) 1238 { 1239 /* 1240 Look for image format specification (e.g. ps3:image). 1241 */ 1242 (void) CopyMagickString(magick,component,(size_t) (p-component+1)); 1243 if (IsMagickConflict(magick) != MagickFalse) 1244 *magick='\0'; 1245 else 1246 for (q=component; *q != '\0'; q++) 1247 *q=(*++p); 1248 break; 1249 } 1250 } 1251 *subimage='\0'; 1252 p=component; 1253 if (*p != '\0') 1254 p=component+strlen(component)-1; 1255 if ((*p == ']') && (strchr(component,'[') != (char *) NULL) && 1256 (IsPathAccessible(path) == MagickFalse)) 1257 { 1258 /* 1259 Look for scene specification (e.g. img0001.pcd[4]). 1260 */ 1261 for (q=p-1; q > component; q--) 1262 if (*q == '[') 1263 break; 1264 if (*q == '[') 1265 { 1266 (void) CopyMagickString(subimage,q+1,MaxTextExtent); 1267 subimage[p-q-1]='\0'; 1268 if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) && 1269 (IsGeometry(subimage) == MagickFalse)) 1270 *subimage='\0'; 1271 else 1272 *q='\0'; 1273 } 1274 } 1275 p=component; 1276 if (*p != '\0') 1277 for (p=component+strlen(component)-1; p > component; p--) 1278 if (IsBasenameSeparator(*p) != MagickFalse) 1279 break; 1280 switch (type) 1281 { 1282 case MagickPath: 1283 { 1284 (void) CopyMagickString(component,magick,MaxTextExtent); 1285 break; 1286 } 1287 case RootPath: 1288 { 1289 for (p=component+(strlen(component)-1); p > component; p--) 1290 { 1291 if (IsBasenameSeparator(*p) != MagickFalse) 1292 break; 1293 if (*p == '.') 1294 break; 1295 } 1296 if (*p == '.') 1297 *p='\0'; 1298 break; 1299 } 1300 case HeadPath: 1301 { 1302 *p='\0'; 1303 break; 1304 } 1305 case TailPath: 1306 { 1307 if (IsBasenameSeparator(*p) != MagickFalse) 1308 (void) CopyMagickMemory((unsigned char *) component, 1309 (const unsigned char *) (p+1),strlen(p+1)+1); 1310 break; 1311 } 1312 case BasePath: 1313 { 1314 if (IsBasenameSeparator(*p) != MagickFalse) 1315 (void) CopyMagickString(component,p+1,MaxTextExtent); 1316 for (p=component+(strlen(component)-1); p > component; p--) 1317 if (*p == '.') 1318 { 1319 *p='\0'; 1320 break; 1321 } 1322 break; 1323 } 1324 case ExtensionPath: 1325 { 1326 if (IsBasenameSeparator(*p) != MagickFalse) 1327 (void) CopyMagickString(component,p+1,MaxTextExtent); 1328 p=component; 1329 if (*p != '\0') 1330 for (p=component+strlen(component)-1; p > component; p--) 1331 if (*p == '.') 1332 break; 1333 *component='\0'; 1334 if (*p == '.') 1335 (void) CopyMagickString(component,p+1,MaxTextExtent); 1336 break; 1337 } 1338 case SubimagePath: 1339 { 1340 (void) CopyMagickString(component,subimage,MaxTextExtent); 1341 break; 1342 } 1343 case CanonicalPath: 1344 case UndefinedPath: 1345 break; 1346 } 1347} 1348 1349/* 1350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1351% % 1352% % 1353% % 1354% G e t P a t h C o m p o n e n t s % 1355% % 1356% % 1357% % 1358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1359% 1360% GetPathComponents() returns a list of path components. 1361% 1362% The format of the GetPathComponents method is: 1363% 1364% char **GetPathComponents(const char *path, 1365% size_t *number_componenets) 1366% 1367% A description of each parameter follows: 1368% 1369% o path: Specifies the string to segment into a list. 1370% 1371% o number_components: return the number of components in the list 1372% 1373*/ 1374MagickPrivate char **GetPathComponents(const char *path, 1375 size_t *number_components) 1376{ 1377 char 1378 **components; 1379 1380 register const char 1381 *p, 1382 *q; 1383 1384 register ssize_t 1385 i; 1386 1387 if (path == (char *) NULL) 1388 return((char **) NULL); 1389 *number_components=1; 1390 for (p=path; *p != '\0'; p++) 1391 if (IsBasenameSeparator(*p)) 1392 (*number_components)++; 1393 components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL, 1394 sizeof(*components)); 1395 if (components == (char **) NULL) 1396 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1397 p=path; 1398 for (i=0; i < (ssize_t) *number_components; i++) 1399 { 1400 for (q=p; *q != '\0'; q++) 1401 if (IsBasenameSeparator(*q)) 1402 break; 1403 components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent, 1404 sizeof(**components)); 1405 if (components[i] == (char *) NULL) 1406 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1407 (void) CopyMagickString(components[i],p,(size_t) (q-p+1)); 1408 p=q+1; 1409 } 1410 components[i]=(char *) NULL; 1411 return(components); 1412} 1413 1414/* 1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1416% % 1417% % 1418% % 1419% I s P a t h A c c e s s i b l e % 1420% % 1421% % 1422% % 1423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1424% 1425% IsPathAccessible() returns MagickTrue if the file as defined by the path is 1426% accessible. 1427% 1428% The format of the IsPathAccessible method is: 1429% 1430% MagickBooleanType IsPathAccessible(const char *path) 1431% 1432% A description of each parameter follows. 1433% 1434% o path: Specifies a path to a file. 1435% 1436*/ 1437MagickExport MagickBooleanType IsPathAccessible(const char *path) 1438{ 1439 MagickBooleanType 1440 status; 1441 1442 struct stat 1443 attributes; 1444 1445 if ((path == (const char *) NULL) || (*path == '\0')) 1446 return(MagickFalse); 1447 status=GetPathAttributes(path,&attributes); 1448 if (status == MagickFalse) 1449 return(status); 1450 if (S_ISREG(attributes.st_mode) == 0) 1451 return(MagickFalse); 1452 if (access_utf8(path,F_OK) != 0) 1453 return(MagickFalse); 1454 return(MagickTrue); 1455} 1456 1457/* 1458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1459% % 1460% % 1461% % 1462+ I s P a t h D i r e c t o r y % 1463% % 1464% % 1465% % 1466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1467% 1468% IsPathDirectory() returns -1 if the directory does not exist, 1 is returned 1469% if the path represents a directory otherwise 0. 1470% 1471% The format of the IsPathDirectory method is: 1472% 1473% int IsPathDirectory(const char *path) 1474% 1475% A description of each parameter follows. 1476% 1477% o path: The directory path. 1478% 1479*/ 1480static int IsPathDirectory(const char *path) 1481{ 1482 MagickBooleanType 1483 status; 1484 1485 struct stat 1486 attributes; 1487 1488 if ((path == (const char *) NULL) || (*path == '\0')) 1489 return(MagickFalse); 1490 status=GetPathAttributes(path,&attributes); 1491 if (status == MagickFalse) 1492 return(-1); 1493 if (S_ISDIR(attributes.st_mode) == 0) 1494 return(0); 1495 return(1); 1496} 1497 1498/* 1499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1500% % 1501% % 1502% % 1503% L i s t F i l e s % 1504% % 1505% % 1506% % 1507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1508% 1509% ListFiles() reads the directory specified and returns a list of filenames 1510% contained in the directory sorted in ascending alphabetic order. 1511% 1512% The format of the ListFiles function is: 1513% 1514% char **ListFiles(const char *directory,const char *pattern, 1515% ssize_t *number_entries) 1516% 1517% A description of each parameter follows: 1518% 1519% o filelist: Method ListFiles returns a list of filenames contained 1520% in the directory. If the directory specified cannot be read or it is 1521% a file a NULL list is returned. 1522% 1523% o directory: Specifies a pointer to a text string containing a directory 1524% name. 1525% 1526% o pattern: Specifies a pointer to a text string containing a pattern. 1527% 1528% o number_entries: This integer returns the number of filenames in the 1529% list. 1530% 1531*/ 1532 1533#if defined(__cplusplus) || defined(c_plusplus) 1534extern "C" { 1535#endif 1536 1537static int FileCompare(const void *x,const void *y) 1538{ 1539 register const char 1540 **p, 1541 **q; 1542 1543 p=(const char **) x; 1544 q=(const char **) y; 1545 return(LocaleCompare(*p,*q)); 1546} 1547 1548#if defined(__cplusplus) || defined(c_plusplus) 1549} 1550#endif 1551 1552static inline int MagickReadDirectory(DIR *directory,struct dirent *entry, 1553 struct dirent **result) 1554{ 1555#if defined(MAGICKCORE_HAVE_READDIR_R) 1556 return(readdir_r(directory,entry,result)); 1557#else 1558 (void) entry; 1559 errno=0; 1560 *result=readdir(directory); 1561 return(errno); 1562#endif 1563} 1564 1565MagickPrivate char **ListFiles(const char *directory,const char *pattern, 1566 size_t *number_entries) 1567{ 1568 char 1569 **filelist; 1570 1571 DIR 1572 *current_directory; 1573 1574 struct dirent 1575 *buffer, 1576 *entry; 1577 1578 size_t 1579 max_entries; 1580 1581 /* 1582 Open directory. 1583 */ 1584 assert(directory != (const char *) NULL); 1585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory); 1586 assert(pattern != (const char *) NULL); 1587 assert(number_entries != (size_t *) NULL); 1588 *number_entries=0; 1589 current_directory=opendir(directory); 1590 if (current_directory == (DIR *) NULL) 1591 return((char **) NULL); 1592 /* 1593 Allocate filelist. 1594 */ 1595 max_entries=2048; 1596 filelist=(char **) AcquireQuantumMemory((size_t) max_entries, 1597 sizeof(*filelist)); 1598 if (filelist == (char **) NULL) 1599 { 1600 (void) closedir(current_directory); 1601 return((char **) NULL); 1602 } 1603 /* 1604 Save the current and change to the new directory. 1605 */ 1606 buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+ 1607 FILENAME_MAX+1); 1608 if (buffer == (struct dirent *) NULL) 1609 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1610 while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) && 1611 (entry != (struct dirent *) NULL)) 1612 { 1613 if (*entry->d_name == '.') 1614 continue; 1615 if ((IsPathDirectory(entry->d_name) > 0) || 1616#if defined(MAGICKCORE_WINDOWS_SUPPORT) 1617 (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse)) 1618#else 1619 (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse)) 1620#endif 1621 { 1622 if (*number_entries >= max_entries) 1623 { 1624 /* 1625 Extend the file list. 1626 */ 1627 max_entries<<=1; 1628 filelist=(char **) ResizeQuantumMemory(filelist,(size_t) 1629 max_entries,sizeof(*filelist)); 1630 if (filelist == (char **) NULL) 1631 break; 1632 } 1633#if defined(vms) 1634 { 1635 register char 1636 *p; 1637 1638 p=strchr(entry->d_name,';'); 1639 if (p) 1640 *p='\0'; 1641 if (*number_entries > 0) 1642 if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0) 1643 continue; 1644 } 1645#endif 1646 filelist[*number_entries]=(char *) AcquireString(entry->d_name); 1647 (*number_entries)++; 1648 } 1649 } 1650 buffer=(struct dirent *) RelinquishMagickMemory(buffer); 1651 (void) closedir(current_directory); 1652 if (filelist == (char **) NULL) 1653 return((char **) NULL); 1654 /* 1655 Sort filelist in ascending order. 1656 */ 1657 qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist), 1658 FileCompare); 1659 return(filelist); 1660} 1661 1662/* 1663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1664% % 1665% % 1666% % 1667% M a g i c k D e l a y % 1668% % 1669% % 1670% % 1671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1672% 1673% MagickDelay() suspends program execution for the number of milliseconds 1674% specified. 1675% 1676% The format of the Delay method is: 1677% 1678% void MagickDelay(const MagickSizeType milliseconds) 1679% 1680% A description of each parameter follows: 1681% 1682% o milliseconds: Specifies the number of milliseconds to delay before 1683% returning. 1684% 1685*/ 1686MagickPrivate void MagickDelay(const MagickSizeType milliseconds) 1687{ 1688 if (milliseconds == 0) 1689 return; 1690#if defined(MAGICKCORE_HAVE_NANOSLEEP) 1691 { 1692 struct timespec 1693 timer; 1694 1695 timer.tv_sec=(time_t) (milliseconds/1000); 1696 timer.tv_nsec=(milliseconds % 1000)*1000*1000; 1697 (void) nanosleep(&timer,(struct timespec *) NULL); 1698 } 1699#elif defined(MAGICKCORE_HAVE_USLEEP) 1700 usleep(1000*milliseconds); 1701#elif defined(MAGICKCORE_HAVE_SELECT) 1702 { 1703 struct timeval 1704 timer; 1705 1706 timer.tv_sec=(long) milliseconds/1000; 1707 timer.tv_usec=(long) (milliseconds % 1000)*1000; 1708 (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer); 1709 } 1710#elif defined(MAGICKCORE_HAVE_POLL) 1711 (void) poll((struct pollfd *) NULL,0,(int) milliseconds); 1712#elif defined(MAGICKCORE_WINDOWS_SUPPORT) 1713 Sleep((long) milliseconds); 1714#elif defined(vms) 1715 { 1716 float 1717 timer; 1718 1719 timer=milliseconds/1000.0; 1720 lib$wait(&timer); 1721 } 1722#elif defined(__BEOS__) 1723 snooze(1000*milliseconds); 1724#else 1725# error "Time delay method not defined." 1726#endif 1727} 1728 1729/* 1730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1731% % 1732% % 1733% % 1734% M u l t i l i n e C e n s u s % 1735% % 1736% % 1737% % 1738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1739% 1740% MultilineCensus() returns the number of lines within a label. A line is 1741% represented by a \n character. 1742% 1743% The format of the MultilineCenus method is: 1744% 1745% size_t MultilineCensus(const char *label) 1746% 1747% A description of each parameter follows. 1748% 1749% o label: This character string is the label. 1750% 1751*/ 1752MagickExport size_t MultilineCensus(const char *label) 1753{ 1754 size_t 1755 number_lines; 1756 1757 /* 1758 Determine the number of lines within this label. 1759 */ 1760 if (label == (char *) NULL) 1761 return(0); 1762 for (number_lines=1; *label != '\0'; label++) 1763 if (*label == '\n') 1764 number_lines++; 1765 return(number_lines); 1766} 1767 1768/* 1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1770% % 1771% % 1772% % 1773% S h r e a d F i l e % 1774% % 1775% % 1776% % 1777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1778% 1779% ShredFile() overwrites the specified file with zeros or random data and then 1780% removes it. The overwrite is optional and is only required to help keep 1781% the contents of the file private. On the first pass, the file is zeroed. 1782% For subsequent passes, random data is written. 1783% 1784% The format of the ShredFile method is: 1785% 1786% MagickBooleanType ShredFile(const char *path) 1787% 1788% A description of each parameter follows. 1789% 1790% o path: Specifies a path to a file. 1791% 1792*/ 1793MagickPrivate MagickBooleanType ShredFile(const char *path) 1794{ 1795 char 1796 *passes; 1797 1798 int 1799 file, 1800 status; 1801 1802 MagickSizeType 1803 length; 1804 1805 register ssize_t 1806 i; 1807 1808 size_t 1809 quantum; 1810 1811 struct stat 1812 file_stats; 1813 1814 if ((path == (const char *) NULL) || (*path == '\0')) 1815 return(MagickFalse); 1816 passes=GetEnvironmentValue("MAGICK_SHRED_PASSES"); 1817 if (passes == (char *) NULL) 1818 { 1819 /* 1820 Don't shred the file, just remove it. 1821 */ 1822 status=remove_utf8(path); 1823 if (status == -1) 1824 return(MagickFalse); 1825 return(MagickTrue); 1826 } 1827 file=open_utf8(path,O_WRONLY | O_EXCL | O_BINARY,S_MODE); 1828 if (file == -1) 1829 { 1830 /* 1831 Don't shred the file, just remove it. 1832 */ 1833 status=remove_utf8(path); 1834 return(MagickFalse); 1835 } 1836 /* 1837 Shred the file. 1838 */ 1839 quantum=(size_t) MagickMaxBufferExtent; 1840 if ((fstat(file,&file_stats) == 0) && (file_stats.st_size != 0)) 1841 quantum=(size_t) MagickMin((MagickSizeType) file_stats.st_size, 1842 MagickMaxBufferExtent); 1843 length=(MagickSizeType) file_stats.st_size; 1844 for (i=0; i < (ssize_t) StringToInteger(passes); i++) 1845 { 1846 RandomInfo 1847 *random_info; 1848 1849 register MagickOffsetType 1850 j; 1851 1852 ssize_t 1853 count; 1854 1855 if (lseek(file,0,SEEK_SET) < 0) 1856 break; 1857 random_info=AcquireRandomInfo(); 1858 for (j=0; j < (MagickOffsetType) length; j+=count) 1859 { 1860 StringInfo 1861 *key; 1862 1863 key=GetRandomKey(random_info,quantum); 1864 if (i == 0) 1865 ResetStringInfo(key); /* zero on first pass */ 1866 count=write(file,GetStringInfoDatum(key),(size_t) 1867 MagickMin(quantum,length-j)); 1868 key=DestroyStringInfo(key); 1869 if (count <= 0) 1870 { 1871 count=0; 1872 if (errno != EINTR) 1873 break; 1874 } 1875 } 1876 random_info=DestroyRandomInfo(random_info); 1877 if (j < (MagickOffsetType) length) 1878 break; 1879 } 1880 status=close(file); 1881 status=remove_utf8(path); 1882 if (status == -1) 1883 return(MagickFalse); 1884 return(i < (ssize_t) StringToInteger(passes) ? MagickFalse : MagickTrue); 1885} 1886 1887/* 1888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1889% % 1890% % 1891% % 1892% S y s t e m C o m m a n d % 1893% % 1894% % 1895% % 1896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1897% 1898% SystemCommand() executes the specified command and waits until it 1899% terminates. The returned value is the exit status of the command. 1900% 1901% The format of the SystemCommand method is: 1902% 1903% int SystemCommand(const MagickBooleanType asynchronous, 1904% const MagickBooleanType verbose,const char *command, 1905% ExceptionInfo *exception) 1906% 1907% A description of each parameter follows: 1908% 1909% o asynchronous: a value other than 0 executes the parent program 1910% concurrently with the new child process. 1911% 1912% o verbose: a value other than 0 prints the executed command before it is 1913% invoked. 1914% 1915% o command: this string is the command to execute. 1916% 1917% o exception: return any errors here. 1918% 1919*/ 1920 1921static char *SanitizeSystemCommand(const char *command) 1922{ 1923 char 1924 *sanitize_command; 1925 1926 const char 1927 *q; 1928 1929 register char 1930 *p; 1931 1932 static char 1933 whitelist[] = 1934 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_- " 1935 ".@&;<>|/\\\'\":%"; 1936 1937 sanitize_command=AcquireString(command); 1938 p=sanitize_command; 1939 q=sanitize_command+strlen(sanitize_command); 1940 for (p+=strspn(p,whitelist); p != q; p+=strspn(p,whitelist)) 1941 *p='_'; 1942 return(sanitize_command); 1943} 1944 1945MagickExport int SystemCommand(const MagickBooleanType asynchronous, 1946 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception) 1947{ 1948 char 1949 **arguments, 1950 *sanitize_command; 1951 1952 int 1953 number_arguments, 1954 status; 1955 1956 PolicyDomain 1957 domain; 1958 1959 PolicyRights 1960 rights; 1961 1962 register ssize_t 1963 i; 1964 1965 status=(-1); 1966 arguments=StringToArgv(command,&number_arguments); 1967 if (arguments == (char **) NULL) 1968 return(status); 1969 if (*arguments[1] == '\0') 1970 { 1971 for (i=0; i < (ssize_t) number_arguments; i++) 1972 arguments[i]=DestroyString(arguments[i]); 1973 arguments=(char **) RelinquishMagickMemory(arguments); 1974 return(-1); 1975 } 1976 rights=ExecutePolicyRights; 1977 domain=DelegatePolicyDomain; 1978 if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse) 1979 { 1980 errno=EPERM; 1981 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError, 1982 "NotAuthorized","`%s'",arguments[1]); 1983 for (i=0; i < (ssize_t) number_arguments; i++) 1984 arguments[i]=DestroyString(arguments[i]); 1985 arguments=(char **) RelinquishMagickMemory(arguments); 1986 return(-1); 1987 } 1988 if (verbose != MagickFalse) 1989 { 1990 (void) FormatLocaleFile(stderr,"%s\n",command); 1991 (void) fflush(stderr); 1992 } 1993 sanitize_command=SanitizeSystemCommand(command); 1994 if (asynchronous != MagickFalse) 1995 (void) ConcatenateMagickString(sanitize_command,"&",MaxTextExtent); 1996#if defined(MAGICKCORE_POSIX_SUPPORT) 1997#if !defined(MAGICKCORE_HAVE_EXECVP) 1998 status=system(sanitize_command); 1999#else 2000 if ((asynchronous != MagickFalse) || 2001 (strpbrk(sanitize_command,"&;<>|") != (char *) NULL)) 2002 status=system(sanitize_command); 2003 else 2004 { 2005 pid_t 2006 child_pid; 2007 2008 /* 2009 Call application directly rather than from a shell. 2010 */ 2011 child_pid=(pid_t) fork(); 2012 if (child_pid == (pid_t) -1) 2013 status=system(sanitize_command); 2014 else 2015 if (child_pid == 0) 2016 { 2017 status=execvp(arguments[1],arguments+1); 2018 _exit(1); 2019 } 2020 else 2021 { 2022 int 2023 child_status; 2024 2025 pid_t 2026 pid; 2027 2028 child_status=0; 2029 pid=(pid_t) waitpid(child_pid,&child_status,0); 2030 if (pid == -1) 2031 status=(-1); 2032 else 2033 { 2034 if (WIFEXITED(child_status) != 0) 2035 status=WEXITSTATUS(child_status); 2036 else 2037 if (WIFSIGNALED(child_status)) 2038 status=(-1); 2039 } 2040 } 2041 } 2042#endif 2043#elif defined(MAGICKCORE_WINDOWS_SUPPORT) 2044 status=NTSystemCommand(sanitize_command); 2045#elif defined(macintosh) 2046 status=MACSystemCommand(sanitize_command); 2047#elif defined(vms) 2048 status=system(sanitize_command); 2049#else 2050# error No suitable system() method. 2051#endif 2052 if (status < 0) 2053 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, 2054 "FailedToExecuteCommand","`%s' (%d)",command,status); 2055 sanitize_command=DestroyString(sanitize_command); 2056 for (i=0; i < (ssize_t) number_arguments; i++) 2057 arguments[i]=DestroyString(arguments[i]); 2058 arguments=(char **) RelinquishMagickMemory(arguments); 2059 return(status); 2060} 2061