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