blob: d74f4b0215b39ee778bfea8658553b32a25d62d1 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% January 1993 %
18% %
19% %
cristyfe676ee2013-11-18 13:03:38 +000020% Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy7832dc22011-09-05 01:21:53 +000051#include "MagickCore/magick-private.h"
cristy4c08aed2011-07-01 19:47:50 +000052#include "MagickCore/memory_.h"
cristy2c5fc272012-02-22 01:27:46 +000053#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000054#include "MagickCore/option.h"
55#include "MagickCore/policy.h"
cristy403ae7b2013-04-18 12:49:11 +000056#include "MagickCore/random_.h"
57#include "MagickCore/registry.h"
cristy4c08aed2011-07-01 19:47:50 +000058#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"
cristy7832dc22011-09-05 01:21:53 +000063#include "MagickCore/string-private.h"
cristy4c08aed2011-07-01 19:47:50 +000064#include "MagickCore/token.h"
cristy7832dc22011-09-05 01:21:53 +000065#include "MagickCore/token-private.h"
cristy4c08aed2011-07-01 19:47:50 +000066#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000067#include "MagickCore/utility-private.h"
cristy98e91bd2010-01-12 01:11:42 +000068#if defined(MAGICKCORE_HAVE_PROCESS_H)
69#include <process.h>
70#endif
cristy3ed852e2009-09-05 21:47:34 +000071#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
cristy2a927fa2013-04-18 19:34:02 +0000152static inline MagickSizeType MagickMin(const MagickSizeType x,
153 const MagickSizeType y)
cristy3ed852e2009-09-05 21:47:34 +0000154{
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);
cristy18c6c272011-09-23 14:40:37 +0000207 source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000208 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))
cristy2a927fa2013-04-18 19:34:02 +0000216 quantum=(size_t) MagickMin((size_t) attributes.st_size,
217 MagickMaxBufferExtent);
cristy3ed852e2009-09-05 21:47:34 +0000218 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
cristy212e2622010-06-12 19:07:47 +0000278 extension[MaxTextExtent],
cristy3ed852e2009-09-05 21:47:34 +0000279 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
cristyb51dff52011-05-19 16:55:47 +0000291 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",format,filename);
cristy3ed852e2009-09-05 21:47:34 +0000292 (void) CopyMagickString(filename,message,MaxTextExtent);
293 return;
294 }
cristy212e2622010-06-12 19:07:47 +0000295 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);
cristyb51dff52011-05-19 16:55:47 +0000305 (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s.%s",root,format,
cristy212e2622010-06-12 19:07:47 +0000306 extension);
307 return;
308 }
cristy3ed852e2009-09-05 21:47:34 +0000309 GetPathComponent(filename,RootPath,root);
cristyb51dff52011-05-19 16:55:47 +0000310 (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s",root,format);
cristy3ed852e2009-09-05 21:47:34 +0000311}
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 {
cristybb503372010-05-27 20:51:26 +0000527 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000528 j;
529
530 unsigned char
531 code[3];
532
533 code[0]='\0';
534 code[1]='\0';
535 code[2]='\0';
cristybb503372010-05-27 20:51:26 +0000536 for (j=0; j < (ssize_t) remainder; j++)
cristy3ed852e2009-09-05 21:47:34 +0000537 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%
cristybb503372010-05-27 20:51:26 +0000567% ChopPathComponents(char *path,size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000568%
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*/
cristyd1dd6e42011-09-04 01:46:08 +0000576MagickPrivate void ChopPathComponents(char *path,const size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000577{
cristybb503372010-05-27 20:51:26 +0000578 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000579 i;
580
cristybb503372010-05-27 20:51:26 +0000581 for (i=0; i < (ssize_t) components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000582 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*/
cristyd1dd6e42011-09-04 01:46:08 +0000608MagickPrivate void ExpandFilename(char *path)
cristy3ed852e2009-09-05 21:47:34 +0000609{
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%
anthonyde897b72012-04-27 00:16:17 +0000682% 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%
cristy8a5d7f42013-01-06 15:24:33 +0000706% You can see the results of the expansion using "Configure" log events.
anthony451f9092012-05-11 01:56:24 +0000707%
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%
cristy3ed852e2009-09-05 21:47:34 +0000714% 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
cristy00976d82011-02-20 20:31:28 +0000731 *directory,
cristy3ed852e2009-09-05 21:47:34 +0000732 home_directory[MaxTextExtent],
733 **vector;
734
cristybb503372010-05-27 20:51:26 +0000735 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000736 i,
737 j;
738
cristybb503372010-05-27 20:51:26 +0000739 size_t
cristy3ed852e2009-09-05 21:47:34 +0000740 number_files;
741
cristy00976d82011-02-20 20:31:28 +0000742 ssize_t
743 count,
744 parameters;
745
cristy3ed852e2009-09-05 21:47:34 +0000746 /*
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';
cristy3ed852e2009-09-05 21:47:34 +0000760 count=0;
cristybb503372010-05-27 20:51:26 +0000761 for (i=0; i < (ssize_t) *number_arguments; i++)
cristy3ed852e2009-09-05 21:47:34 +0000762 {
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';
cristy54ebd8d2014-01-14 01:14:23 +0000779 number_files=0;
cristy3ed852e2009-09-05 21:47:34 +0000780 vector[count++]=ConstantString(option);
781 destroy=MagickTrue;
cristy042ee782011-04-22 18:48:30 +0000782 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000783 if (parameters > 0)
784 {
785 /*
786 Do not expand command option parameters.
787 */
788 for (j=0; j < parameters; j++)
789 {
790 i++;
cristybb503372010-05-27 20:51:26 +0000791 if (i == (ssize_t) *number_arguments)
cristy3ed852e2009-09-05 21:47:34 +0000792 break;
793 option=(*arguments)[i];
794 vector[count++]=ConstantString(option);
795 }
796 continue;
797 }
798 if ((*option == '"') || (*option == '\''))
799 continue;
cristy4b064822012-04-29 13:26:43 +0000800 GetPathComponent(option,TailPath,filename);
cristy3ed852e2009-09-05 21:47:34 +0000801 GetPathComponent(option,MagickPath,magick);
802 if ((LocaleCompare(magick,"CAPTION") == 0) ||
803 (LocaleCompare(magick,"LABEL") == 0) ||
cristyc0732c42012-03-20 19:28:35 +0000804 (LocaleCompare(magick,"PANGO") == 0) ||
cristy3ed852e2009-09-05 21:47:34 +0000805 (LocaleCompare(magick,"VID") == 0))
806 continue;
cristy127425f2012-04-29 13:38:05 +0000807 if ((IsGlob(filename) == MagickFalse) && (*option != '@'))
cristy3ed852e2009-09-05 21:47:34 +0000808 continue;
cristy127425f2012-04-29 13:38:05 +0000809 if (*option != '@')
cristy3ed852e2009-09-05 21:47:34 +0000810 {
811 /*
812 Generate file list from wildcard filename (e.g. *.jpg).
813 */
814 GetPathComponent(option,HeadPath,path);
815 GetPathComponent(option,SubimagePath,subimage);
816 ExpandFilename(path);
cristyf5ee5be2009-11-06 02:22:56 +0000817 if (*home_directory == '\0')
cristy00976d82011-02-20 20:31:28 +0000818 directory=getcwd(home_directory,MaxTextExtent-1);
819 (void) directory;
cristy4b064822012-04-29 13:26:43 +0000820 filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
cristy3ed852e2009-09-05 21:47:34 +0000821 &number_files);
822 }
823 else
824 {
825 char
826 *files;
827
828 ExceptionInfo
829 *exception;
830
831 int
cristyf9218a72010-07-03 17:29:40 +0000832 length;
cristy3ed852e2009-09-05 21:47:34 +0000833
834 /*
835 Generate file list from file list (e.g. @filelist.txt).
836 */
837 exception=AcquireExceptionInfo();
cristy3a5987c2013-11-07 14:18:46 +0000838 files=FileToString(option+1,~0UL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000839 exception=DestroyExceptionInfo(exception);
840 if (files == (char *) NULL)
841 continue;
cristyf9218a72010-07-03 17:29:40 +0000842 filelist=StringToArgv(files,&length);
843 if (filelist == (char **) NULL)
844 continue;
cristy3ed852e2009-09-05 21:47:34 +0000845 files=DestroyString(files);
cristyf9218a72010-07-03 17:29:40 +0000846 filelist[0]=DestroyString(filelist[0]);
847 for (j=0; j < (ssize_t) (length-1); j++)
848 filelist[j]=filelist[j+1];
849 number_files=(size_t) length-1;
cristy3ed852e2009-09-05 21:47:34 +0000850 }
851 if (filelist == (char **) NULL)
852 continue;
cristybb503372010-05-27 20:51:26 +0000853 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000854 if (IsPathDirectory(filelist[j]) <= 0)
855 break;
cristybb503372010-05-27 20:51:26 +0000856 if (j == (ssize_t) number_files)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
cristybb503372010-05-27 20:51:26 +0000858 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000859 filelist[j]=DestroyString(filelist[j]);
860 filelist=(char **) RelinquishMagickMemory(filelist);
861 continue;
862 }
863 /*
864 Transfer file list to argument vector.
865 */
866 vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
867 count+number_files+1,sizeof(*vector));
868 if (vector == (char **) NULL)
869 return(MagickFalse);
cristybb503372010-05-27 20:51:26 +0000870 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000871 {
cristy0e526222010-05-06 14:07:32 +0000872 option=filelist[j];
cristy042ee782011-04-22 18:48:30 +0000873 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy0e526222010-05-06 14:07:32 +0000874 if (parameters > 0)
875 {
cristybb503372010-05-27 20:51:26 +0000876 ssize_t
cristy0e526222010-05-06 14:07:32 +0000877 k;
878
879 /*
880 Do not expand command option parameters.
881 */
882 vector[count++]=ConstantString(option);
883 for (k=0; k < parameters; k++)
884 {
885 j++;
cristybb503372010-05-27 20:51:26 +0000886 if (j == (ssize_t) number_files)
cristy0e526222010-05-06 14:07:32 +0000887 break;
888 option=filelist[j];
889 vector[count++]=ConstantString(option);
890 }
891 continue;
892 }
cristy3ed852e2009-09-05 21:47:34 +0000893 (void) CopyMagickString(filename,path,MaxTextExtent);
894 if (*path != '\0')
895 (void) ConcatenateMagickString(filename,DirectorySeparator,
896 MaxTextExtent);
cristyaa4db032014-01-14 15:07:39 +0000897 if (filelist[j] != (char *) NULL)
898 (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +0000899 filelist[j]=DestroyString(filelist[j]);
cristycfef62c2010-05-05 01:21:43 +0000900 if (strlen(filename) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000901 ThrowFatalException(OptionFatalError,"FilenameTruncated");
cristy47dc34d2010-04-22 16:12:43 +0000902 if (IsPathDirectory(filename) <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 char
905 path[MaxTextExtent];
906
907 *path='\0';
908 if (*magick != '\0')
909 {
910 (void) ConcatenateMagickString(path,magick,MaxTextExtent);
911 (void) ConcatenateMagickString(path,":",MaxTextExtent);
912 }
913 (void) ConcatenateMagickString(path,filename,MaxTextExtent);
914 if (*subimage != '\0')
915 {
916 (void) ConcatenateMagickString(path,"[",MaxTextExtent);
917 (void) ConcatenateMagickString(path,subimage,MaxTextExtent);
918 (void) ConcatenateMagickString(path,"]",MaxTextExtent);
919 }
cristy37e0b382011-06-07 13:31:21 +0000920 if (strlen(path) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000921 ThrowFatalException(OptionFatalError,"FilenameTruncated");
922 if (destroy != MagickFalse)
923 {
924 count--;
925 vector[count]=DestroyString(vector[count]);
926 destroy=MagickFalse;
927 }
928 vector[count++]=ConstantString(path);
929 }
930 }
931 filelist=(char **) RelinquishMagickMemory(filelist);
932 }
933 vector[count]=(char *) NULL;
934 if (IsEventLogging() != MagickFalse)
935 {
936 char
937 *command_line;
938
939 command_line=AcquireString(vector[0]);
940 for (i=1; i < count; i++)
941 {
942 (void) ConcatenateString(&command_line," {");
943 (void) ConcatenateString(&command_line,vector[i]);
944 (void) ConcatenateString(&command_line,"}");
945 }
946 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
947 "Command line: %s",command_line);
948 command_line=DestroyString(command_line);
949 }
950 *number_arguments=(int) count;
951 *arguments=vector;
952 return(MagickTrue);
953}
954
955/*
956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957% %
958% %
959% %
960% G e t E x e c u t i o n P a t h %
961% %
962% %
963% %
964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965%
966% GetExecutionPath() returns the pathname of the executable that started
967% the process. On success MagickTrue is returned, otherwise MagickFalse.
968%
969% The format of the GetExecutionPath method is:
970%
971% MagickBooleanType GetExecutionPath(char *path,const size_t extent)
972%
973% A description of each parameter follows:
974%
975% o path: the pathname of the executable that started the process.
976%
977% o extent: the maximum extent of the path.
978%
979*/
cristyd1dd6e42011-09-04 01:46:08 +0000980MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +0000981{
cristyfbe485a2011-02-22 13:54:48 +0000982 char
983 *directory;
984
cristy3ed852e2009-09-05 21:47:34 +0000985 *path='\0';
cristyfbe485a2011-02-22 13:54:48 +0000986 directory=getcwd(path,(unsigned long) extent);
987 (void) directory;
cristyfa09d142009-10-15 01:02:25 +0000988#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
cristy3ed852e2009-09-05 21:47:34 +0000989 {
990 char
991 link_path[MaxTextExtent],
cristyfa09d142009-10-15 01:02:25 +0000992 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000993
994 ssize_t
995 count;
996
cristyb51dff52011-05-19 16:55:47 +0000997 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/exe",
cristye8c25f92010-06-03 00:53:06 +0000998 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000999 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +00001000 if (count == -1)
1001 {
cristyb51dff52011-05-19 16:55:47 +00001002 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/file",
cristye8c25f92010-06-03 00:53:06 +00001003 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +00001004 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +00001005 }
1006 if ((count > 0) && (count <= (ssize_t) PATH_MAX))
1007 {
cristyfa09d142009-10-15 01:02:25 +00001008 execution_path[count]='\0';
1009 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +00001010 }
1011 }
1012#endif
1013#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
1014 {
1015 char
1016 executable_path[PATH_MAX << 1],
cristyfa09d142009-10-15 01:02:25 +00001017 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +00001018
1019 uint32_t
1020 length;
1021
1022 length=sizeof(executable_path);
1023 if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
cristyfa09d142009-10-15 01:02:25 +00001024 (realpath(executable_path,execution_path) != (char *) NULL))
1025 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +00001026 }
1027#endif
1028#if defined(MAGICKCORE_HAVE_GETEXECNAME)
1029 {
1030 const char
1031 *execution_path;
1032
1033 execution_path=(const char *) getexecname();
1034 if (execution_path != (const char *) NULL)
1035 {
1036 if (*execution_path != *DirectorySeparator)
1037 (void) ConcatenateMagickString(path,DirectorySeparator,extent);
1038 (void) ConcatenateMagickString(path,execution_path,extent);
1039 }
1040 }
1041#endif
cristy0157aea2010-04-24 21:12:18 +00001042#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001043 NTGetExecutionPath(path,extent);
1044#endif
cristyfa09d142009-10-15 01:02:25 +00001045#if defined(__GNU__)
1046 {
1047 char
1048 *program_name,
1049 *execution_path;
1050
cristybb503372010-05-27 20:51:26 +00001051 ssize_t
cristyfa09d142009-10-15 01:02:25 +00001052 count;
1053
1054 count=0;
1055 execution_path=(char *) NULL;
1056 program_name=program_invocation_name;
1057 if (*program_invocation_name != '/')
1058 {
1059 size_t
1060 extent;
1061
cristyb29bea52011-05-26 17:54:31 +00001062 extent=strlen(directory)+strlen(program_name)+2;
cristyfa09d142009-10-15 01:02:25 +00001063 program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1064 if (program_name == (char *) NULL)
1065 program_name=program_invocation_name;
1066 else
cristyb29bea52011-05-26 17:54:31 +00001067 count=FormatLocaleString(program_name,extent,"%s/%s",directory,
cristyfa09d142009-10-15 01:02:25 +00001068 program_invocation_name);
1069 }
1070 if (count != -1)
1071 {
1072 execution_path=realpath(program_name,NULL);
1073 if (execution_path != (char *) NULL)
1074 (void) CopyMagickString(path,execution_path,extent);
1075 }
1076 if (program_name != program_invocation_name)
1077 program_name=(char *) RelinquishMagickMemory(program_name);
1078 execution_path=(char *) RelinquishMagickMemory(execution_path);
1079 }
1080#endif
cristy8a7ca3c2013-05-18 21:37:53 +00001081#if defined(__OpenBSD__)
1082 {
1083 extern char
1084 *__progname;
1085
1086 (void) CopyMagickString(path,__progname,extent);
1087 }
1088#endif
cristy3ed852e2009-09-05 21:47:34 +00001089 return(IsPathAccessible(path));
1090}
1091
1092/*
1093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094% %
1095% %
1096% %
cristy688f07b2009-09-27 15:19:13 +00001097% G e t M a g i c k P a g e S i z e %
1098% %
1099% %
1100% %
1101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102%
1103% GetMagickPageSize() returns the memory page size.
1104%
1105% The format of the GetMagickPageSize method is:
1106%
cristybb503372010-05-27 20:51:26 +00001107% ssize_t GetMagickPageSize()
cristy688f07b2009-09-27 15:19:13 +00001108%
1109*/
cristyd1dd6e42011-09-04 01:46:08 +00001110MagickPrivate ssize_t GetMagickPageSize(void)
cristy688f07b2009-09-27 15:19:13 +00001111{
cristybb503372010-05-27 20:51:26 +00001112 static ssize_t
cristy688f07b2009-09-27 15:19:13 +00001113 page_size = -1;
1114
1115 if (page_size > 0)
1116 return(page_size);
1117#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
cristyecd0ab52010-05-30 14:59:20 +00001118 page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
cristy09449f72010-01-23 03:08:36 +00001119#else
cristy688f07b2009-09-27 15:19:13 +00001120#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
cristyecd0ab52010-05-30 14:59:20 +00001121 page_size=(ssize_t) getpagesize();
cristy09449f72010-01-23 03:08:36 +00001122#endif
cristy688f07b2009-09-27 15:19:13 +00001123#endif
1124 if (page_size <= 0)
1125 page_size=16384;
1126 return(page_size);
1127}
1128
1129/*
1130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1131% %
1132% %
1133% %
cristy3ed852e2009-09-05 21:47:34 +00001134% G e t P a t h A t t r i b u t e s %
1135% %
1136% %
1137% %
1138%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1139%
1140% GetPathAttributes() returns attributes (e.g. size of file) about a path.
1141%
1142% The path of the GetPathAttributes method is:
1143%
1144% MagickBooleanType GetPathAttributes(const char *path,void *attributes)
1145%
1146% A description of each parameter follows.
1147%
1148% o path: the file path.
1149%
1150% o attributes: the path attributes are returned here.
1151%
1152*/
cristy3ed852e2009-09-05 21:47:34 +00001153MagickExport MagickBooleanType GetPathAttributes(const char *path,
1154 void *attributes)
1155{
1156 MagickBooleanType
1157 status;
1158
1159 if (path == (const char *) NULL)
1160 {
1161 errno=EINVAL;
1162 return(MagickFalse);
1163 }
cristy18c6c272011-09-23 14:40:37 +00001164 status=stat_utf8(path,(struct stat *) attributes) == 0 ? MagickTrue :
1165 MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001166 return(status);
1167}
1168
1169/*
1170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1171% %
1172% %
1173% %
1174% G e t P a t h C o m p o n e n t %
1175% %
1176% %
1177% %
1178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179%
1180% GetPathComponent() returns the parent directory name, filename, basename, or
1181% extension of a file path.
1182%
anthony104f8932012-05-13 01:54:53 +00001183% The component string pointed to must have at least MaxTextExtent space
1184% for the results to be stored.
1185%
cristy3ed852e2009-09-05 21:47:34 +00001186% The format of the GetPathComponent function is:
1187%
1188% GetPathComponent(const char *path,PathType type,char *component)
1189%
1190% A description of each parameter follows:
1191%
1192% o path: Specifies a pointer to a character array that contains the
1193% file path.
1194%
1195% o type: Specififies which file path component to return.
1196%
1197% o component: the selected file path component is returned here.
1198%
1199*/
1200MagickExport void GetPathComponent(const char *path,PathType type,
1201 char *component)
1202{
1203 char
1204 magick[MaxTextExtent],
1205 *q,
1206 subimage[MaxTextExtent];
1207
1208 register char
1209 *p;
1210
1211 assert(path != (const char *) NULL);
1212 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
1213 assert(component != (char *) NULL);
1214 if (*path == '\0')
1215 {
1216 *component='\0';
1217 return;
1218 }
1219 (void) CopyMagickString(component,path,MaxTextExtent);
1220 *magick='\0';
cristy1224a992011-10-12 19:23:41 +00001221#if defined(__OS2__)
1222 if (path[1] != ":")
1223#endif
1224 for (p=component; *p != '\0'; p++)
1225 {
1226 if ((*p == '%') && (*(p+1) == '['))
1227 {
1228 /*
1229 Skip over %[...].
1230 */
1231 for (p++; (*p != ']') && (*p != '\0'); p++) ;
1232 if (*p == '\0')
1233 break;
1234 }
1235 if ((*p == ':') && (IsPathDirectory(path) < 0) &&
1236 (IsPathAccessible(path) == MagickFalse))
1237 {
1238 /*
1239 Look for image format specification (e.g. ps3:image).
1240 */
1241 (void) CopyMagickString(magick,component,(size_t) (p-component+1));
1242 if (IsMagickConflict(magick) != MagickFalse)
1243 *magick='\0';
1244 else
1245 for (q=component; *q != '\0'; q++)
1246 *q=(*++p);
1247 break;
1248 }
1249 }
cristy86057c42011-08-03 18:12:58 +00001250 *subimage='\0';
1251 p=component;
1252 if (*p != '\0')
1253 p=component+strlen(component)-1;
1254 if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1255 (IsPathAccessible(path) == MagickFalse))
1256 {
1257 /*
1258 Look for scene specification (e.g. img0001.pcd[4]).
1259 */
1260 for (q=p-1; q > component; q--)
1261 if (*q == '[')
1262 break;
1263 if (*q == '[')
1264 {
1265 (void) CopyMagickString(subimage,q+1,MaxTextExtent);
1266 subimage[p-q-1]='\0';
1267 if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) &&
1268 (IsGeometry(subimage) == MagickFalse))
1269 *subimage='\0';
cristy1224a992011-10-12 19:23:41 +00001270 else
1271 *q='\0';
cristy86057c42011-08-03 18:12:58 +00001272 }
1273 }
cristy3ed852e2009-09-05 21:47:34 +00001274 p=component;
1275 if (*p != '\0')
1276 for (p=component+strlen(component)-1; p > component; p--)
1277 if (IsBasenameSeparator(*p) != MagickFalse)
1278 break;
1279 switch (type)
1280 {
1281 case MagickPath:
1282 {
1283 (void) CopyMagickString(component,magick,MaxTextExtent);
1284 break;
1285 }
1286 case RootPath:
1287 {
1288 for (p=component+(strlen(component)-1); p > component; p--)
1289 {
1290 if (IsBasenameSeparator(*p) != MagickFalse)
1291 break;
1292 if (*p == '.')
1293 break;
1294 }
1295 if (*p == '.')
1296 *p='\0';
1297 break;
1298 }
1299 case HeadPath:
1300 {
1301 *p='\0';
1302 break;
1303 }
1304 case TailPath:
1305 {
1306 if (IsBasenameSeparator(*p) != MagickFalse)
1307 (void) CopyMagickMemory((unsigned char *) component,
1308 (const unsigned char *) (p+1),strlen(p+1)+1);
1309 break;
1310 }
1311 case BasePath:
1312 {
1313 if (IsBasenameSeparator(*p) != MagickFalse)
1314 (void) CopyMagickString(component,p+1,MaxTextExtent);
1315 for (p=component+(strlen(component)-1); p > component; p--)
1316 if (*p == '.')
1317 {
1318 *p='\0';
1319 break;
1320 }
1321 break;
1322 }
1323 case ExtensionPath:
1324 {
1325 if (IsBasenameSeparator(*p) != MagickFalse)
1326 (void) CopyMagickString(component,p+1,MaxTextExtent);
1327 p=component;
1328 if (*p != '\0')
1329 for (p=component+strlen(component)-1; p > component; p--)
1330 if (*p == '.')
1331 break;
1332 *component='\0';
1333 if (*p == '.')
1334 (void) CopyMagickString(component,p+1,MaxTextExtent);
1335 break;
1336 }
1337 case SubimagePath:
1338 {
1339 (void) CopyMagickString(component,subimage,MaxTextExtent);
1340 break;
1341 }
1342 case CanonicalPath:
1343 case UndefinedPath:
1344 break;
1345 }
1346}
1347
1348/*
1349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1350% %
1351% %
1352% %
1353% G e t P a t h C o m p o n e n t s %
1354% %
1355% %
1356% %
1357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1358%
1359% GetPathComponents() returns a list of path components.
1360%
1361% The format of the GetPathComponents method is:
1362%
1363% char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001364% size_t *number_componenets)
cristy3ed852e2009-09-05 21:47:34 +00001365%
1366% A description of each parameter follows:
1367%
1368% o path: Specifies the string to segment into a list.
1369%
1370% o number_components: return the number of components in the list
1371%
1372*/
cristyd1dd6e42011-09-04 01:46:08 +00001373MagickPrivate char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001374 size_t *number_components)
cristy3ed852e2009-09-05 21:47:34 +00001375{
1376 char
1377 **components;
1378
1379 register const char
1380 *p,
1381 *q;
1382
cristybb503372010-05-27 20:51:26 +00001383 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001384 i;
1385
1386 if (path == (char *) NULL)
1387 return((char **) NULL);
1388 *number_components=1;
1389 for (p=path; *p != '\0'; p++)
1390 if (IsBasenameSeparator(*p))
1391 (*number_components)++;
1392 components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1393 sizeof(*components));
1394 if (components == (char **) NULL)
1395 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1396 p=path;
cristybb503372010-05-27 20:51:26 +00001397 for (i=0; i < (ssize_t) *number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001398 {
1399 for (q=p; *q != '\0'; q++)
1400 if (IsBasenameSeparator(*q))
1401 break;
1402 components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
cristyc92c1e12011-03-25 15:47:59 +00001403 sizeof(**components));
cristy3ed852e2009-09-05 21:47:34 +00001404 if (components[i] == (char *) NULL)
1405 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1406 (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1407 p=q+1;
1408 }
1409 components[i]=(char *) NULL;
1410 return(components);
1411}
1412
1413/*
1414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415% %
1416% %
1417% %
1418% I s P a t h A c c e s s i b l e %
1419% %
1420% %
1421% %
1422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423%
1424% IsPathAccessible() returns MagickTrue if the file as defined by the path is
1425% accessible.
1426%
1427% The format of the IsPathAccessible method is:
1428%
cristy59864562013-04-18 11:47:41 +00001429% MagickBooleanType IsPathAccessible(const char *path)
cristy3ed852e2009-09-05 21:47:34 +00001430%
1431% A description of each parameter follows.
1432%
1433% o path: Specifies a path to a file.
1434%
1435*/
1436MagickExport MagickBooleanType IsPathAccessible(const char *path)
1437{
1438 MagickBooleanType
1439 status;
1440
1441 struct stat
1442 attributes;
1443
1444 if ((path == (const char *) NULL) || (*path == '\0'))
1445 return(MagickFalse);
1446 status=GetPathAttributes(path,&attributes);
1447 if (status == MagickFalse)
1448 return(status);
1449 if (S_ISREG(attributes.st_mode) == 0)
1450 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +00001451 if (access_utf8(path,F_OK) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001452 return(MagickFalse);
1453 return(MagickTrue);
1454}
1455
1456/*
1457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458% %
1459% %
1460% %
1461+ I s P a t h D i r e c t o r y %
1462% %
1463% %
1464% %
1465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466%
1467% IsPathDirectory() returns -1 if the directory does not exist, 1 is returned
1468% if the path represents a directory otherwise 0.
1469%
1470% The format of the IsPathDirectory method is:
1471%
1472% int IsPathDirectory(const char *path)
1473%
1474% A description of each parameter follows.
1475%
1476% o path: The directory path.
1477%
1478*/
1479static int IsPathDirectory(const char *path)
1480{
1481 MagickBooleanType
1482 status;
1483
1484 struct stat
1485 attributes;
1486
1487 if ((path == (const char *) NULL) || (*path == '\0'))
1488 return(MagickFalse);
1489 status=GetPathAttributes(path,&attributes);
1490 if (status == MagickFalse)
1491 return(-1);
1492 if (S_ISDIR(attributes.st_mode) == 0)
1493 return(0);
1494 return(1);
1495}
1496
1497/*
1498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1499% %
1500% %
1501% %
cristy3ed852e2009-09-05 21:47:34 +00001502% L i s t F i l e s %
1503% %
1504% %
1505% %
1506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1507%
1508% ListFiles() reads the directory specified and returns a list of filenames
1509% contained in the directory sorted in ascending alphabetic order.
1510%
1511% The format of the ListFiles function is:
1512%
1513% char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001514% ssize_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001515%
1516% A description of each parameter follows:
1517%
1518% o filelist: Method ListFiles returns a list of filenames contained
1519% in the directory. If the directory specified cannot be read or it is
1520% a file a NULL list is returned.
1521%
1522% o directory: Specifies a pointer to a text string containing a directory
1523% name.
1524%
1525% o pattern: Specifies a pointer to a text string containing a pattern.
1526%
1527% o number_entries: This integer returns the number of filenames in the
1528% list.
1529%
1530*/
1531
1532#if defined(__cplusplus) || defined(c_plusplus)
1533extern "C" {
1534#endif
1535
1536static int FileCompare(const void *x,const void *y)
1537{
1538 register const char
1539 **p,
1540 **q;
1541
1542 p=(const char **) x;
1543 q=(const char **) y;
1544 return(LocaleCompare(*p,*q));
1545}
1546
1547#if defined(__cplusplus) || defined(c_plusplus)
1548}
1549#endif
1550
1551static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1552 struct dirent **result)
1553{
1554#if defined(MAGICKCORE_HAVE_READDIR_R)
1555 return(readdir_r(directory,entry,result));
1556#else
1557 (void) entry;
1558 errno=0;
1559 *result=readdir(directory);
1560 return(errno);
1561#endif
1562}
1563
cristyd1dd6e42011-09-04 01:46:08 +00001564MagickPrivate char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001565 size_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001566{
1567 char
1568 **filelist;
1569
1570 DIR
1571 *current_directory;
1572
1573 struct dirent
1574 *buffer,
1575 *entry;
1576
cristybb503372010-05-27 20:51:26 +00001577 size_t
cristy3ed852e2009-09-05 21:47:34 +00001578 max_entries;
1579
1580 /*
1581 Open directory.
1582 */
1583 assert(directory != (const char *) NULL);
1584 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1585 assert(pattern != (const char *) NULL);
cristybb503372010-05-27 20:51:26 +00001586 assert(number_entries != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001587 *number_entries=0;
1588 current_directory=opendir(directory);
1589 if (current_directory == (DIR *) NULL)
1590 return((char **) NULL);
1591 /*
1592 Allocate filelist.
1593 */
1594 max_entries=2048;
1595 filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1596 sizeof(*filelist));
1597 if (filelist == (char **) NULL)
1598 {
1599 (void) closedir(current_directory);
1600 return((char **) NULL);
1601 }
1602 /*
1603 Save the current and change to the new directory.
1604 */
cristy73bd4a52010-10-05 11:24:23 +00001605 buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+
cristy0be53ea2010-06-23 19:12:05 +00001606 FILENAME_MAX+1);
cristy3ed852e2009-09-05 21:47:34 +00001607 if (buffer == (struct dirent *) NULL)
1608 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1609 while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
1610 (entry != (struct dirent *) NULL))
1611 {
1612 if (*entry->d_name == '.')
1613 continue;
1614 if ((IsPathDirectory(entry->d_name) > 0) ||
cristy0157aea2010-04-24 21:12:18 +00001615#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001616 (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
1617#else
1618 (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
1619#endif
1620 {
1621 if (*number_entries >= max_entries)
1622 {
1623 /*
1624 Extend the file list.
1625 */
1626 max_entries<<=1;
1627 filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
1628 max_entries,sizeof(*filelist));
1629 if (filelist == (char **) NULL)
1630 break;
1631 }
1632#if defined(vms)
1633 {
1634 register char
1635 *p;
1636
1637 p=strchr(entry->d_name,';');
1638 if (p)
1639 *p='\0';
1640 if (*number_entries > 0)
1641 if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
1642 continue;
1643 }
1644#endif
1645 filelist[*number_entries]=(char *) AcquireString(entry->d_name);
cristy3ed852e2009-09-05 21:47:34 +00001646 (*number_entries)++;
1647 }
1648 }
1649 buffer=(struct dirent *) RelinquishMagickMemory(buffer);
1650 (void) closedir(current_directory);
1651 if (filelist == (char **) NULL)
1652 return((char **) NULL);
1653 /*
1654 Sort filelist in ascending order.
1655 */
1656 qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
1657 FileCompare);
1658 return(filelist);
1659}
1660
1661/*
1662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1663% %
1664% %
1665% %
cristya21afde2010-07-02 00:45:40 +00001666% M a g i c k D e l a y %
1667% %
1668% %
1669% %
1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671%
1672% MagickDelay() suspends program execution for the number of milliseconds
1673% specified.
1674%
1675% The format of the Delay method is:
1676%
1677% void MagickDelay(const MagickSizeType milliseconds)
1678%
1679% A description of each parameter follows:
1680%
1681% o milliseconds: Specifies the number of milliseconds to delay before
1682% returning.
1683%
1684*/
cristyd1dd6e42011-09-04 01:46:08 +00001685MagickPrivate void MagickDelay(const MagickSizeType milliseconds)
cristya21afde2010-07-02 00:45:40 +00001686{
1687 if (milliseconds == 0)
1688 return;
1689#if defined(MAGICKCORE_HAVE_NANOSLEEP)
1690 {
1691 struct timespec
1692 timer;
1693
1694 timer.tv_sec=(time_t) (milliseconds/1000);
1695 timer.tv_nsec=(milliseconds % 1000)*1000*1000;
1696 (void) nanosleep(&timer,(struct timespec *) NULL);
1697 }
1698#elif defined(MAGICKCORE_HAVE_USLEEP)
1699 usleep(1000*milliseconds);
1700#elif defined(MAGICKCORE_HAVE_SELECT)
1701 {
1702 struct timeval
1703 timer;
1704
1705 timer.tv_sec=(long) milliseconds/1000;
1706 timer.tv_usec=(long) (milliseconds % 1000)*1000;
1707 (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
1708 }
1709#elif defined(MAGICKCORE_HAVE_POLL)
1710 (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
1711#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1712 Sleep((long) milliseconds);
1713#elif defined(vms)
1714 {
1715 float
1716 timer;
1717
1718 timer=milliseconds/1000.0;
1719 lib$wait(&timer);
1720 }
1721#elif defined(__BEOS__)
1722 snooze(1000*milliseconds);
1723#else
1724# error "Time delay method not defined."
1725#endif
1726}
1727
1728/*
1729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1730% %
1731% %
1732% %
cristy3ed852e2009-09-05 21:47:34 +00001733% M u l t i l i n e C e n s u s %
1734% %
1735% %
1736% %
1737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1738%
1739% MultilineCensus() returns the number of lines within a label. A line is
1740% represented by a \n character.
1741%
1742% The format of the MultilineCenus method is:
1743%
cristybb503372010-05-27 20:51:26 +00001744% size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001745%
1746% A description of each parameter follows.
1747%
1748% o label: This character string is the label.
1749%
cristy3ed852e2009-09-05 21:47:34 +00001750*/
cristybb503372010-05-27 20:51:26 +00001751MagickExport size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001752{
cristybb503372010-05-27 20:51:26 +00001753 size_t
cristy3ed852e2009-09-05 21:47:34 +00001754 number_lines;
1755
1756 /*
1757 Determine the number of lines within this label.
1758 */
1759 if (label == (char *) NULL)
1760 return(0);
1761 for (number_lines=1; *label != '\0'; label++)
1762 if (*label == '\n')
1763 number_lines++;
1764 return(number_lines);
1765}
1766
1767/*
1768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769% %
1770% %
1771% %
cristy59864562013-04-18 11:47:41 +00001772% S h r e a d F i l e %
1773% %
1774% %
1775% %
1776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1777%
cristy403ae7b2013-04-18 12:49:11 +00001778% ShredFile() overwrites the specified file with zeros or random data and then
1779% removes it. The overwrite is optional and is only required to help keep
cristy3c91e2d2013-04-18 12:55:47 +00001780% the contents of the file private. On the first pass, the file is zeroed.
1781% For subsequent passes, random data is written.
cristy59864562013-04-18 11:47:41 +00001782%
1783% The format of the ShredFile method is:
1784%
1785% MagickBooleanType ShredFile(const char *path)
1786%
1787% A description of each parameter follows.
1788%
1789% o path: Specifies a path to a file.
1790%
1791*/
1792MagickPrivate MagickBooleanType ShredFile(const char *path)
1793{
cristy403ae7b2013-04-18 12:49:11 +00001794 char
cristy3c91e2d2013-04-18 12:55:47 +00001795 *passes;
cristy403ae7b2013-04-18 12:49:11 +00001796
cristy59864562013-04-18 11:47:41 +00001797 int
cristy403ae7b2013-04-18 12:49:11 +00001798 file,
cristy59864562013-04-18 11:47:41 +00001799 status;
1800
cristy403ae7b2013-04-18 12:49:11 +00001801 MagickSizeType
1802 length;
1803
1804 register ssize_t
1805 i;
1806
1807 size_t
1808 quantum;
1809
1810 struct stat
1811 file_stats;
1812
cristy59864562013-04-18 11:47:41 +00001813 if ((path == (const char *) NULL) || (*path == '\0'))
1814 return(MagickFalse);
cristy8a23f662014-03-26 20:58:19 +00001815 passes=GetEnvironmentValue("MAGICK_SHRED_PASSES");
cristy3c91e2d2013-04-18 12:55:47 +00001816 if (passes == (char *) NULL)
cristy403ae7b2013-04-18 12:49:11 +00001817 {
1818 /*
1819 Don't shred the file, just remove it.
1820 */
1821 status=remove_utf8(path);
1822 if (status == -1)
1823 return(MagickFalse);
1824 return(MagickTrue);
1825 }
1826 file=open_utf8(path,O_WRONLY | O_EXCL | O_BINARY,S_MODE);
1827 if (file == -1)
cristyd2ce3602013-04-18 19:30:20 +00001828 {
1829 /*
1830 Don't shred the file, just remove it.
1831 */
1832 status=remove_utf8(path);
1833 return(MagickFalse);
1834 }
cristy403ae7b2013-04-18 12:49:11 +00001835 /*
1836 Shred the file.
1837 */
1838 quantum=(size_t) MagickMaxBufferExtent;
1839 if ((fstat(file,&file_stats) == 0) && (file_stats.st_size != 0))
1840 quantum=(size_t) MagickMin((MagickSizeType) file_stats.st_size,
1841 MagickMaxBufferExtent);
1842 length=(MagickSizeType) file_stats.st_size;
cristy94cc10e2013-04-18 19:17:04 +00001843 for (i=0; i < (ssize_t) StringToInteger(passes); i++)
cristy403ae7b2013-04-18 12:49:11 +00001844 {
1845 RandomInfo
1846 *random_info;
1847
cristy6e31dc72013-04-18 19:22:03 +00001848 register MagickOffsetType
cristy403ae7b2013-04-18 12:49:11 +00001849 j;
1850
1851 ssize_t
1852 count;
1853
1854 if (lseek(file,0,SEEK_SET) < 0)
1855 break;
1856 random_info=AcquireRandomInfo();
cristy6e31dc72013-04-18 19:22:03 +00001857 for (j=0; j < (MagickOffsetType) length; j+=count)
cristy403ae7b2013-04-18 12:49:11 +00001858 {
1859 StringInfo
1860 *key;
1861
1862 key=GetRandomKey(random_info,quantum);
cristy689d9852013-04-18 19:19:01 +00001863 if (i == 0)
cristy403ae7b2013-04-18 12:49:11 +00001864 ResetStringInfo(key); /* zero on first pass */
1865 count=write(file,GetStringInfoDatum(key),(size_t)
1866 MagickMin(quantum,length-j));
1867 key=DestroyStringInfo(key);
1868 if (count <= 0)
1869 {
1870 count=0;
1871 if (errno != EINTR)
1872 break;
1873 }
1874 }
1875 random_info=DestroyRandomInfo(random_info);
cristy2a927fa2013-04-18 19:34:02 +00001876 if (j < (MagickOffsetType) length)
cristy403ae7b2013-04-18 12:49:11 +00001877 break;
1878 }
1879 status=close(file);
cristy59864562013-04-18 11:47:41 +00001880 status=remove_utf8(path);
1881 if (status == -1)
1882 return(MagickFalse);
cristyd2ce3602013-04-18 19:30:20 +00001883 return(i < (ssize_t) StringToInteger(passes) ? MagickFalse : MagickTrue);
cristy59864562013-04-18 11:47:41 +00001884}
1885
1886/*
1887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1888% %
1889% %
1890% %
cristy3ed852e2009-09-05 21:47:34 +00001891% S y s t e m C o m m a n d %
1892% %
1893% %
1894% %
1895%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1896%
1897% SystemCommand() executes the specified command and waits until it
1898% terminates. The returned value is the exit status of the command.
1899%
1900% The format of the SystemCommand method is:
1901%
cristy6de4bc22010-01-12 17:10:35 +00001902% int SystemCommand(const MagickBooleanType asynchronous,
1903% const MagickBooleanType verbose,const char *command,
cristyb32b90a2009-09-07 21:45:48 +00001904% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001905%
1906% A description of each parameter follows:
1907%
cristy6de4bc22010-01-12 17:10:35 +00001908% o asynchronous: a value other than 0 executes the parent program
1909% concurrently with the new child process.
1910%
cristyb32b90a2009-09-07 21:45:48 +00001911% o verbose: a value other than 0 prints the executed command before it is
cristy3ed852e2009-09-05 21:47:34 +00001912% invoked.
1913%
cristyb32b90a2009-09-07 21:45:48 +00001914% o command: this string is the command to execute.
1915%
1916% o exception: return any errors here.
cristy3ed852e2009-09-05 21:47:34 +00001917%
1918*/
cristy6de4bc22010-01-12 17:10:35 +00001919MagickExport int SystemCommand(const MagickBooleanType asynchronous,
1920 const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001921{
cristyb32b90a2009-09-07 21:45:48 +00001922 char
cristy6de4bc22010-01-12 17:10:35 +00001923 **arguments,
1924 *shell_command;
cristyb32b90a2009-09-07 21:45:48 +00001925
cristy3ed852e2009-09-05 21:47:34 +00001926 int
cristyb32b90a2009-09-07 21:45:48 +00001927 number_arguments,
cristy3ed852e2009-09-05 21:47:34 +00001928 status;
1929
cristyb32b90a2009-09-07 21:45:48 +00001930 PolicyDomain
1931 domain;
1932
1933 PolicyRights
1934 rights;
1935
cristybb503372010-05-27 20:51:26 +00001936 register ssize_t
cristyb32b90a2009-09-07 21:45:48 +00001937 i;
1938
1939 status=(-1);
1940 arguments=StringToArgv(command,&number_arguments);
1941 if (arguments == (char **) NULL)
1942 return(status);
cristy0217c562013-01-26 23:11:29 +00001943 if (*arguments[1] == '\0')
1944 {
1945 for (i=0; i < (ssize_t) number_arguments; i++)
1946 arguments[i]=DestroyString(arguments[i]);
1947 arguments=(char **) RelinquishMagickMemory(arguments);
1948 return(-1);
1949 }
cristyb32b90a2009-09-07 21:45:48 +00001950 rights=ExecutePolicyRights;
cristy6de4bc22010-01-12 17:10:35 +00001951 domain=DelegatePolicyDomain;
cristyb32b90a2009-09-07 21:45:48 +00001952 if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
1953 {
cristya9197f62010-01-12 02:23:34 +00001954 errno=EPERM;
cristyb32b90a2009-09-07 21:45:48 +00001955 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
cristyefe601c2013-01-05 17:51:12 +00001956 "NotAuthorized","`%s'",arguments[1]);
cristycee97112010-05-28 00:44:52 +00001957 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00001958 arguments[i]=DestroyString(arguments[i]);
1959 arguments=(char **) RelinquishMagickMemory(arguments);
1960 return(-1);
1961 }
cristy3ed852e2009-09-05 21:47:34 +00001962 if (verbose != MagickFalse)
1963 {
cristyb51dff52011-05-19 16:55:47 +00001964 (void) FormatLocaleFile(stderr,"%s\n",command);
cristy3ed852e2009-09-05 21:47:34 +00001965 (void) fflush(stderr);
1966 }
cristy6de4bc22010-01-12 17:10:35 +00001967 shell_command=(char *) command;
1968 if (asynchronous != MagickFalse)
1969 {
1970 shell_command=AcquireString(command);
1971 (void) ConcatenateMagickString(shell_command,"&",MaxTextExtent);
1972 }
cristy3ed852e2009-09-05 21:47:34 +00001973#if defined(MAGICKCORE_POSIX_SUPPORT)
cristya9197f62010-01-12 02:23:34 +00001974#if !defined(MAGICKCORE_HAVE_EXECVP)
cristy6de4bc22010-01-12 17:10:35 +00001975 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001976#else
cristye21dc962012-01-12 17:22:31 +00001977 if ((asynchronous != MagickFalse) ||
cristya4560912012-01-14 20:28:03 +00001978 (strpbrk(shell_command,"&;<>|") != (char *) NULL))
cristy6de4bc22010-01-12 17:10:35 +00001979 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00001980 else
1981 {
cristyb32b90a2009-09-07 21:45:48 +00001982 pid_t
1983 child_pid;
cristy3ed852e2009-09-05 21:47:34 +00001984
cristyb32b90a2009-09-07 21:45:48 +00001985 /*
1986 Call application directly rather than from a shell.
1987 */
cristye42f6582012-02-11 17:59:50 +00001988 child_pid=(pid_t) fork();
cristyb32b90a2009-09-07 21:45:48 +00001989 if (child_pid == (pid_t) -1)
cristy3ed852e2009-09-05 21:47:34 +00001990 status=system(command);
1991 else
cristyb32b90a2009-09-07 21:45:48 +00001992 if (child_pid == 0)
1993 {
1994 status=execvp(arguments[1],arguments+1);
1995 _exit(1);
1996 }
1997 else
1998 {
1999 int
2000 child_status;
cristy3ed852e2009-09-05 21:47:34 +00002001
cristyb32b90a2009-09-07 21:45:48 +00002002 pid_t
2003 pid;
cristy3ed852e2009-09-05 21:47:34 +00002004
cristyb32b90a2009-09-07 21:45:48 +00002005 child_status=0;
cristye42f6582012-02-11 17:59:50 +00002006 pid=(pid_t) waitpid(child_pid,&child_status,0);
cristyb32b90a2009-09-07 21:45:48 +00002007 if (pid == -1)
2008 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00002009 else
2010 {
cristyb32b90a2009-09-07 21:45:48 +00002011 if (WIFEXITED(child_status) != 0)
2012 status=WEXITSTATUS(child_status);
cristy3ed852e2009-09-05 21:47:34 +00002013 else
cristyb32b90a2009-09-07 21:45:48 +00002014 if (WIFSIGNALED(child_status))
2015 status=(-1);
cristy3ed852e2009-09-05 21:47:34 +00002016 }
cristyb32b90a2009-09-07 21:45:48 +00002017 }
cristy3ed852e2009-09-05 21:47:34 +00002018 }
2019#endif
cristy0157aea2010-04-24 21:12:18 +00002020#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
cristyea7bce92011-12-12 00:24:44 +00002021 status=NTSystemCommand(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00002022#elif defined(macintosh)
cristy6de4bc22010-01-12 17:10:35 +00002023 status=MACSystemCommand(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00002024#elif defined(vms)
cristy6de4bc22010-01-12 17:10:35 +00002025 status=system(shell_command);
cristy3ed852e2009-09-05 21:47:34 +00002026#else
2027# error No suitable system() method.
2028#endif
2029 if (status < 0)
cristy6de4bc22010-01-12 17:10:35 +00002030 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
anthonye5b39652012-04-21 05:37:29 +00002031 "'%s' (%d)",command,status);
cristy6de4bc22010-01-12 17:10:35 +00002032 if (shell_command != command)
2033 shell_command=DestroyString(shell_command);
cristycee97112010-05-28 00:44:52 +00002034 for (i=0; i < (ssize_t) number_arguments; i++)
cristyb32b90a2009-09-07 21:45:48 +00002035 arguments[i]=DestroyString(arguments[i]);
2036 arguments=(char **) RelinquishMagickMemory(arguments);
cristy3ed852e2009-09-05 21:47:34 +00002037 return(status);
2038}