blob: 7f0a8560b4d67aa10f12c2afa1abe9092ea1d9ee [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 }
cristy6f008fd2014-05-25 23:27:26 +0000456 break;
cristy3ed852e2009-09-05 21:47:34 +0000457 }
458 }
459 }
460 *length=i;
461 return(decode);
462}
463
464/*
465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466% %
467% %
468% %
469% B a s e 6 4 E n c o d e %
470% %
471% %
472% %
473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474%
475% Base64Encode() encodes arbitrary binary data to Base64 encoded format as
476% described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and
477% returns the result as a null-terminated ASCII string. NULL is returned if
478% a memory allocation failure occurs.
479%
480% The format of the Base64Encode method is:
481%
482% char *Base64Encode(const unsigned char *blob,const size_t blob_length,
483% size_t *encode_length)
484%
485% A description of each parameter follows:
486%
487% o blob: A pointer to binary data to encode.
488%
489% o blob_length: the number of bytes to encode.
490%
491% o encode_length: The number of bytes encoded.
492%
493*/
494MagickExport char *Base64Encode(const unsigned char *blob,
495 const size_t blob_length,size_t *encode_length)
496{
497 char
498 *encode;
499
500 register const unsigned char
501 *p;
502
503 register size_t
504 i;
505
506 size_t
507 remainder;
508
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
510 assert(blob != (const unsigned char *) NULL);
511 assert(blob_length != 0);
512 assert(encode_length != (size_t *) NULL);
513 *encode_length=0;
514 encode=(char *) AcquireQuantumMemory(blob_length/3+4,4*sizeof(*encode));
515 if (encode == (char *) NULL)
516 return((char *) NULL);
517 i=0;
518 for (p=blob; p < (blob+blob_length-2); p+=3)
519 {
520 encode[i++]=Base64[(int) (*p >> 2)];
521 encode[i++]=Base64[(int) (((*p & 0x03) << 4)+(*(p+1) >> 4))];
522 encode[i++]=Base64[(int) (((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))];
523 encode[i++]=Base64[(int) (*(p+2) & 0x3f)];
524 }
525 remainder=blob_length % 3;
526 if (remainder != 0)
527 {
cristybb503372010-05-27 20:51:26 +0000528 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000529 j;
530
531 unsigned char
532 code[3];
533
534 code[0]='\0';
535 code[1]='\0';
536 code[2]='\0';
cristybb503372010-05-27 20:51:26 +0000537 for (j=0; j < (ssize_t) remainder; j++)
cristy3ed852e2009-09-05 21:47:34 +0000538 code[j]=(*p++);
539 encode[i++]=Base64[(int) (code[0] >> 2)];
540 encode[i++]=Base64[(int) (((code[0] & 0x03) << 4)+(code[1] >> 4))];
541 if (remainder == 1)
542 encode[i++]='=';
543 else
544 encode[i++]=Base64[(int) (((code[1] & 0x0f) << 2)+(code[2] >> 6))];
545 encode[i++]='=';
546 }
547 *encode_length=i;
548 encode[i++]='\0';
549 return(encode);
550}
551
552/*
553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554% %
555% %
556% %
557% C h o p P a t h C o m p o n e n t s %
558% %
559% %
560% %
561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562%
563% ChopPathComponents() removes the number of specified file components from a
564% path.
565%
566% The format of the ChopPathComponents method is:
567%
cristybb503372010-05-27 20:51:26 +0000568% ChopPathComponents(char *path,size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000569%
570% A description of each parameter follows:
571%
572% o path: The path.
573%
574% o components: The number of components to chop.
575%
576*/
cristyd1dd6e42011-09-04 01:46:08 +0000577MagickPrivate void ChopPathComponents(char *path,const size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000578{
cristybb503372010-05-27 20:51:26 +0000579 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000580 i;
581
cristybb503372010-05-27 20:51:26 +0000582 for (i=0; i < (ssize_t) components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000583 GetPathComponent(path,HeadPath,path);
584}
585
586/*
587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
588% %
589% %
590% %
591% E x p a n d F i l e n a m e %
592% %
593% %
594% %
595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
596%
597% ExpandFilename() expands '~' in a path.
598%
599% The format of the ExpandFilename function is:
600%
601% ExpandFilename(char *path)
602%
603% A description of each parameter follows:
604%
605% o path: Specifies a pointer to a character array that contains the
606% path.
607%
608*/
cristyd1dd6e42011-09-04 01:46:08 +0000609MagickPrivate void ExpandFilename(char *path)
cristy3ed852e2009-09-05 21:47:34 +0000610{
611 char
612 expand_path[MaxTextExtent];
613
614 if (path == (char *) NULL)
615 return;
616 if (*path != '~')
617 return;
618 (void) CopyMagickString(expand_path,path,MaxTextExtent);
619 if ((*(path+1) == *DirectorySeparator) || (*(path+1) == '\0'))
620 {
621 char
622 *home;
623
624 /*
625 Substitute ~ with $HOME.
626 */
627 (void) CopyMagickString(expand_path,".",MaxTextExtent);
628 (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
629 home=GetEnvironmentValue("HOME");
630 if (home == (char *) NULL)
631 home=GetEnvironmentValue("USERPROFILE");
632 if (home != (char *) NULL)
633 {
634 (void) CopyMagickString(expand_path,home,MaxTextExtent);
635 (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
636 home=DestroyString(home);
637 }
638 }
639 else
640 {
641#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__)
642 char
643 username[MaxTextExtent];
644
645 register char
646 *p;
647
648 struct passwd
649 *entry;
650
651 /*
652 Substitute ~ with home directory from password file.
653 */
654 (void) CopyMagickString(username,path+1,MaxTextExtent);
655 p=strchr(username,'/');
656 if (p != (char *) NULL)
657 *p='\0';
658 entry=getpwnam(username);
659 if (entry == (struct passwd *) NULL)
660 return;
661 (void) CopyMagickString(expand_path,entry->pw_dir,MaxTextExtent);
662 if (p != (char *) NULL)
663 {
664 (void) ConcatenateMagickString(expand_path,"/",MaxTextExtent);
665 (void) ConcatenateMagickString(expand_path,p+1,MaxTextExtent);
666 }
667#endif
668 }
669 (void) CopyMagickString(path,expand_path,MaxTextExtent);
670}
671
672/*
673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
674% %
675% %
676% %
677% E x p a n d F i l e n a m e s %
678% %
679% %
680% %
681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
682%
anthonyde897b72012-04-27 00:16:17 +0000683% ExpandFilenames() checks each argument of the given argument array, and
684% expands it if they have a wildcard character.
685%
686% Any coder prefix (EG: 'coder:filename') or read modifier postfix (EG:
687% 'filename[...]') are ignored during the file the expansion, but will be
688% included in the final argument. If no filename matching the meta-character
689% 'glob' is found the original argument is returned.
690%
691% For example, an argument of '*.gif[20x20]' will be replaced by the list
692% 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
693% if such filenames exist, (in the current directory in this case).
694%
695% Meta-characters handled...
696% @ read a list of filenames (no further expansion performed)
697% ~ At start of filename expands to HOME environemtn variable
698% * matches any string including an empty string
699% ? matches by any single character
700%
701% WARNING: filenames starting with '.' (hidden files in a UNIX file system)
702% will never be expanded. Attempting to epand '.*' will produce no change.
703%
704% Expansion is ignored for coders "label:" "caption:" "pango:" and "vid:".
705% Which provide their own '@' meta-character handling.
706%
cristy8a5d7f42013-01-06 15:24:33 +0000707% You can see the results of the expansion using "Configure" log events.
anthony451f9092012-05-11 01:56:24 +0000708%
709% The returned list should be freed using DestroyStringList().
710%
711% However the strings in the original pointed to argv are not
712% freed (TO BE CHECKED). So a copy of the original pointer (and count)
713% should be kept separate if they need to be freed later.
714%
cristy3ed852e2009-09-05 21:47:34 +0000715% The format of the ExpandFilenames function is:
716%
717% status=ExpandFilenames(int *number_arguments,char ***arguments)
718%
719% A description of each parameter follows:
720%
721% o number_arguments: Specifies a pointer to an integer describing the
722% number of elements in the argument vector.
723%
724% o arguments: Specifies a pointer to a text array containing the command
725% line arguments.
726%
727*/
728MagickExport MagickBooleanType ExpandFilenames(int *number_arguments,
729 char ***arguments)
730{
731 char
cristy00976d82011-02-20 20:31:28 +0000732 *directory,
cristy3ed852e2009-09-05 21:47:34 +0000733 home_directory[MaxTextExtent],
734 **vector;
735
cristybb503372010-05-27 20:51:26 +0000736 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000737 i,
738 j;
739
cristybb503372010-05-27 20:51:26 +0000740 size_t
cristy3ed852e2009-09-05 21:47:34 +0000741 number_files;
742
cristy00976d82011-02-20 20:31:28 +0000743 ssize_t
744 count,
745 parameters;
746
cristy3ed852e2009-09-05 21:47:34 +0000747 /*
748 Allocate argument vector.
749 */
750 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
751 assert(number_arguments != (int *) NULL);
752 assert(arguments != (char ***) NULL);
753 vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1),
754 sizeof(*vector));
755 if (vector == (char **) NULL)
756 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
757 /*
758 Expand any wildcard filenames.
759 */
760 *home_directory='\0';
cristy3ed852e2009-09-05 21:47:34 +0000761 count=0;
cristybb503372010-05-27 20:51:26 +0000762 for (i=0; i < (ssize_t) *number_arguments; i++)
cristy3ed852e2009-09-05 21:47:34 +0000763 {
764 char
765 **filelist,
766 filename[MaxTextExtent],
767 magick[MaxTextExtent],
768 *option,
769 path[MaxTextExtent],
770 subimage[MaxTextExtent];
771
772 MagickBooleanType
773 destroy;
774
775 option=(*arguments)[i];
776 *magick='\0';
777 *path='\0';
778 *filename='\0';
779 *subimage='\0';
cristy54ebd8d2014-01-14 01:14:23 +0000780 number_files=0;
cristy3ed852e2009-09-05 21:47:34 +0000781 vector[count++]=ConstantString(option);
782 destroy=MagickTrue;
cristy042ee782011-04-22 18:48:30 +0000783 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000784 if (parameters > 0)
785 {
786 /*
787 Do not expand command option parameters.
788 */
789 for (j=0; j < parameters; j++)
790 {
791 i++;
cristybb503372010-05-27 20:51:26 +0000792 if (i == (ssize_t) *number_arguments)
cristy3ed852e2009-09-05 21:47:34 +0000793 break;
794 option=(*arguments)[i];
795 vector[count++]=ConstantString(option);
796 }
797 continue;
798 }
799 if ((*option == '"') || (*option == '\''))
800 continue;
cristy4b064822012-04-29 13:26:43 +0000801 GetPathComponent(option,TailPath,filename);
cristy3ed852e2009-09-05 21:47:34 +0000802 GetPathComponent(option,MagickPath,magick);
803 if ((LocaleCompare(magick,"CAPTION") == 0) ||
804 (LocaleCompare(magick,"LABEL") == 0) ||
cristyc0732c42012-03-20 19:28:35 +0000805 (LocaleCompare(magick,"PANGO") == 0) ||
cristy3ed852e2009-09-05 21:47:34 +0000806 (LocaleCompare(magick,"VID") == 0))
807 continue;
cristy127425f2012-04-29 13:38:05 +0000808 if ((IsGlob(filename) == MagickFalse) && (*option != '@'))
cristy3ed852e2009-09-05 21:47:34 +0000809 continue;
cristy127425f2012-04-29 13:38:05 +0000810 if (*option != '@')
cristy3ed852e2009-09-05 21:47:34 +0000811 {
812 /*
813 Generate file list from wildcard filename (e.g. *.jpg).
814 */
815 GetPathComponent(option,HeadPath,path);
816 GetPathComponent(option,SubimagePath,subimage);
817 ExpandFilename(path);
cristyf5ee5be2009-11-06 02:22:56 +0000818 if (*home_directory == '\0')
cristy00976d82011-02-20 20:31:28 +0000819 directory=getcwd(home_directory,MaxTextExtent-1);
820 (void) directory;
cristy4b064822012-04-29 13:26:43 +0000821 filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
cristy3ed852e2009-09-05 21:47:34 +0000822 &number_files);
823 }
824 else
825 {
826 char
827 *files;
828
829 ExceptionInfo
830 *exception;
831
832 int
cristyf9218a72010-07-03 17:29:40 +0000833 length;
cristy3ed852e2009-09-05 21:47:34 +0000834
835 /*
836 Generate file list from file list (e.g. @filelist.txt).
837 */
838 exception=AcquireExceptionInfo();
cristy3a5987c2013-11-07 14:18:46 +0000839 files=FileToString(option+1,~0UL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000840 exception=DestroyExceptionInfo(exception);
841 if (files == (char *) NULL)
842 continue;
cristyf9218a72010-07-03 17:29:40 +0000843 filelist=StringToArgv(files,&length);
844 if (filelist == (char **) NULL)
845 continue;
cristy3ed852e2009-09-05 21:47:34 +0000846 files=DestroyString(files);
cristyf9218a72010-07-03 17:29:40 +0000847 filelist[0]=DestroyString(filelist[0]);
848 for (j=0; j < (ssize_t) (length-1); j++)
849 filelist[j]=filelist[j+1];
850 number_files=(size_t) length-1;
cristy3ed852e2009-09-05 21:47:34 +0000851 }
852 if (filelist == (char **) NULL)
853 continue;
cristybb503372010-05-27 20:51:26 +0000854 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000855 if (IsPathDirectory(filelist[j]) <= 0)
856 break;
cristybb503372010-05-27 20:51:26 +0000857 if (j == (ssize_t) number_files)
cristy3ed852e2009-09-05 21:47:34 +0000858 {
cristybb503372010-05-27 20:51:26 +0000859 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000860 filelist[j]=DestroyString(filelist[j]);
861 filelist=(char **) RelinquishMagickMemory(filelist);
862 continue;
863 }
864 /*
865 Transfer file list to argument vector.
866 */
867 vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
868 count+number_files+1,sizeof(*vector));
869 if (vector == (char **) NULL)
870 return(MagickFalse);
cristybb503372010-05-27 20:51:26 +0000871 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000872 {
cristy0e526222010-05-06 14:07:32 +0000873 option=filelist[j];
cristy042ee782011-04-22 18:48:30 +0000874 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy0e526222010-05-06 14:07:32 +0000875 if (parameters > 0)
876 {
cristybb503372010-05-27 20:51:26 +0000877 ssize_t
cristy0e526222010-05-06 14:07:32 +0000878 k;
879
880 /*
881 Do not expand command option parameters.
882 */
883 vector[count++]=ConstantString(option);
884 for (k=0; k < parameters; k++)
885 {
886 j++;
cristybb503372010-05-27 20:51:26 +0000887 if (j == (ssize_t) number_files)
cristy0e526222010-05-06 14:07:32 +0000888 break;
889 option=filelist[j];
890 vector[count++]=ConstantString(option);
891 }
892 continue;
893 }
cristy3ed852e2009-09-05 21:47:34 +0000894 (void) CopyMagickString(filename,path,MaxTextExtent);
895 if (*path != '\0')
896 (void) ConcatenateMagickString(filename,DirectorySeparator,
897 MaxTextExtent);
cristyaa4db032014-01-14 15:07:39 +0000898 if (filelist[j] != (char *) NULL)
899 (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +0000900 filelist[j]=DestroyString(filelist[j]);
cristycfef62c2010-05-05 01:21:43 +0000901 if (strlen(filename) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000902 ThrowFatalException(OptionFatalError,"FilenameTruncated");
cristy47dc34d2010-04-22 16:12:43 +0000903 if (IsPathDirectory(filename) <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000904 {
905 char
906 path[MaxTextExtent];
907
908 *path='\0';
909 if (*magick != '\0')
910 {
911 (void) ConcatenateMagickString(path,magick,MaxTextExtent);
912 (void) ConcatenateMagickString(path,":",MaxTextExtent);
913 }
914 (void) ConcatenateMagickString(path,filename,MaxTextExtent);
915 if (*subimage != '\0')
916 {
917 (void) ConcatenateMagickString(path,"[",MaxTextExtent);
918 (void) ConcatenateMagickString(path,subimage,MaxTextExtent);
919 (void) ConcatenateMagickString(path,"]",MaxTextExtent);
920 }
cristy37e0b382011-06-07 13:31:21 +0000921 if (strlen(path) >= (MaxTextExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000922 ThrowFatalException(OptionFatalError,"FilenameTruncated");
923 if (destroy != MagickFalse)
924 {
925 count--;
926 vector[count]=DestroyString(vector[count]);
927 destroy=MagickFalse;
928 }
929 vector[count++]=ConstantString(path);
930 }
931 }
932 filelist=(char **) RelinquishMagickMemory(filelist);
933 }
934 vector[count]=(char *) NULL;
935 if (IsEventLogging() != MagickFalse)
936 {
937 char
938 *command_line;
939
940 command_line=AcquireString(vector[0]);
941 for (i=1; i < count; i++)
942 {
943 (void) ConcatenateString(&command_line," {");
944 (void) ConcatenateString(&command_line,vector[i]);
945 (void) ConcatenateString(&command_line,"}");
946 }
947 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
948 "Command line: %s",command_line);
949 command_line=DestroyString(command_line);
950 }
951 *number_arguments=(int) count;
952 *arguments=vector;
953 return(MagickTrue);
954}
955
956/*
957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958% %
959% %
960% %
961% G e t E x e c u t i o n P a t h %
962% %
963% %
964% %
965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966%
967% GetExecutionPath() returns the pathname of the executable that started
968% the process. On success MagickTrue is returned, otherwise MagickFalse.
969%
970% The format of the GetExecutionPath method is:
971%
972% MagickBooleanType GetExecutionPath(char *path,const size_t extent)
973%
974% A description of each parameter follows:
975%
976% o path: the pathname of the executable that started the process.
977%
978% o extent: the maximum extent of the path.
979%
980*/
cristyd1dd6e42011-09-04 01:46:08 +0000981MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +0000982{
cristyfbe485a2011-02-22 13:54:48 +0000983 char
984 *directory;
985
cristy3ed852e2009-09-05 21:47:34 +0000986 *path='\0';
cristyfbe485a2011-02-22 13:54:48 +0000987 directory=getcwd(path,(unsigned long) extent);
988 (void) directory;
cristyfa09d142009-10-15 01:02:25 +0000989#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
cristy3ed852e2009-09-05 21:47:34 +0000990 {
991 char
992 link_path[MaxTextExtent],
cristyfa09d142009-10-15 01:02:25 +0000993 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +0000994
995 ssize_t
996 count;
997
cristyb51dff52011-05-19 16:55:47 +0000998 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/exe",
cristye8c25f92010-06-03 00:53:06 +0000999 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +00001000 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +00001001 if (count == -1)
1002 {
cristyb51dff52011-05-19 16:55:47 +00001003 (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/file",
cristye8c25f92010-06-03 00:53:06 +00001004 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +00001005 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +00001006 }
1007 if ((count > 0) && (count <= (ssize_t) PATH_MAX))
1008 {
cristyfa09d142009-10-15 01:02:25 +00001009 execution_path[count]='\0';
1010 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +00001011 }
1012 }
1013#endif
1014#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
1015 {
1016 char
1017 executable_path[PATH_MAX << 1],
cristyfa09d142009-10-15 01:02:25 +00001018 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +00001019
1020 uint32_t
1021 length;
1022
1023 length=sizeof(executable_path);
1024 if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
cristyfa09d142009-10-15 01:02:25 +00001025 (realpath(executable_path,execution_path) != (char *) NULL))
1026 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +00001027 }
1028#endif
1029#if defined(MAGICKCORE_HAVE_GETEXECNAME)
1030 {
1031 const char
1032 *execution_path;
1033
1034 execution_path=(const char *) getexecname();
1035 if (execution_path != (const char *) NULL)
1036 {
1037 if (*execution_path != *DirectorySeparator)
1038 (void) ConcatenateMagickString(path,DirectorySeparator,extent);
1039 (void) ConcatenateMagickString(path,execution_path,extent);
1040 }
1041 }
1042#endif
cristy0157aea2010-04-24 21:12:18 +00001043#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001044 NTGetExecutionPath(path,extent);
1045#endif
cristyfa09d142009-10-15 01:02:25 +00001046#if defined(__GNU__)
1047 {
1048 char
1049 *program_name,
1050 *execution_path;
1051
cristybb503372010-05-27 20:51:26 +00001052 ssize_t
cristyfa09d142009-10-15 01:02:25 +00001053 count;
1054
1055 count=0;
1056 execution_path=(char *) NULL;
1057 program_name=program_invocation_name;
1058 if (*program_invocation_name != '/')
1059 {
1060 size_t
1061 extent;
1062
cristyb29bea52011-05-26 17:54:31 +00001063 extent=strlen(directory)+strlen(program_name)+2;
cristyfa09d142009-10-15 01:02:25 +00001064 program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1065 if (program_name == (char *) NULL)
1066 program_name=program_invocation_name;
1067 else
cristyb29bea52011-05-26 17:54:31 +00001068 count=FormatLocaleString(program_name,extent,"%s/%s",directory,
cristyfa09d142009-10-15 01:02:25 +00001069 program_invocation_name);
1070 }
1071 if (count != -1)
1072 {
1073 execution_path=realpath(program_name,NULL);
1074 if (execution_path != (char *) NULL)
1075 (void) CopyMagickString(path,execution_path,extent);
1076 }
1077 if (program_name != program_invocation_name)
1078 program_name=(char *) RelinquishMagickMemory(program_name);
1079 execution_path=(char *) RelinquishMagickMemory(execution_path);
1080 }
1081#endif
cristy8a7ca3c2013-05-18 21:37:53 +00001082#if defined(__OpenBSD__)
1083 {
1084 extern char
1085 *__progname;
1086
1087 (void) CopyMagickString(path,__progname,extent);
1088 }
1089#endif
cristy3ed852e2009-09-05 21:47:34 +00001090 return(IsPathAccessible(path));
1091}
1092
1093/*
1094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1095% %
1096% %
1097% %
cristy688f07b2009-09-27 15:19:13 +00001098% G e t M a g i c k P a g e S i z e %
1099% %
1100% %
1101% %
1102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1103%
1104% GetMagickPageSize() returns the memory page size.
1105%
1106% The format of the GetMagickPageSize method is:
1107%
cristybb503372010-05-27 20:51:26 +00001108% ssize_t GetMagickPageSize()
cristy688f07b2009-09-27 15:19:13 +00001109%
1110*/
cristyd1dd6e42011-09-04 01:46:08 +00001111MagickPrivate ssize_t GetMagickPageSize(void)
cristy688f07b2009-09-27 15:19:13 +00001112{
cristybb503372010-05-27 20:51:26 +00001113 static ssize_t
cristy688f07b2009-09-27 15:19:13 +00001114 page_size = -1;
1115
1116 if (page_size > 0)
1117 return(page_size);
1118#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
cristyecd0ab52010-05-30 14:59:20 +00001119 page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
cristy09449f72010-01-23 03:08:36 +00001120#else
cristy688f07b2009-09-27 15:19:13 +00001121#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
cristyecd0ab52010-05-30 14:59:20 +00001122 page_size=(ssize_t) getpagesize();
cristy09449f72010-01-23 03:08:36 +00001123#endif
cristy688f07b2009-09-27 15:19:13 +00001124#endif
1125 if (page_size <= 0)
1126 page_size=16384;
1127 return(page_size);
1128}
1129
1130/*
1131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132% %
1133% %
1134% %
cristy3ed852e2009-09-05 21:47:34 +00001135% G e t P a t h A t t r i b u t e s %
1136% %
1137% %
1138% %
1139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1140%
1141% GetPathAttributes() returns attributes (e.g. size of file) about a path.
1142%
1143% The path of the GetPathAttributes method is:
1144%
1145% MagickBooleanType GetPathAttributes(const char *path,void *attributes)
1146%
1147% A description of each parameter follows.
1148%
1149% o path: the file path.
1150%
1151% o attributes: the path attributes are returned here.
1152%
1153*/
cristy3ed852e2009-09-05 21:47:34 +00001154MagickExport MagickBooleanType GetPathAttributes(const char *path,
1155 void *attributes)
1156{
1157 MagickBooleanType
1158 status;
1159
1160 if (path == (const char *) NULL)
1161 {
1162 errno=EINVAL;
1163 return(MagickFalse);
1164 }
cristy18c6c272011-09-23 14:40:37 +00001165 status=stat_utf8(path,(struct stat *) attributes) == 0 ? MagickTrue :
1166 MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001167 return(status);
1168}
1169
1170/*
1171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1172% %
1173% %
1174% %
1175% G e t P a t h C o m p o n e n t %
1176% %
1177% %
1178% %
1179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1180%
1181% GetPathComponent() returns the parent directory name, filename, basename, or
1182% extension of a file path.
1183%
anthony104f8932012-05-13 01:54:53 +00001184% The component string pointed to must have at least MaxTextExtent space
1185% for the results to be stored.
1186%
cristy3ed852e2009-09-05 21:47:34 +00001187% The format of the GetPathComponent function is:
1188%
1189% GetPathComponent(const char *path,PathType type,char *component)
1190%
1191% A description of each parameter follows:
1192%
1193% o path: Specifies a pointer to a character array that contains the
1194% file path.
1195%
1196% o type: Specififies which file path component to return.
1197%
1198% o component: the selected file path component is returned here.
1199%
1200*/
1201MagickExport void GetPathComponent(const char *path,PathType type,
1202 char *component)
1203{
1204 char
1205 magick[MaxTextExtent],
1206 *q,
1207 subimage[MaxTextExtent];
1208
1209 register char
1210 *p;
1211
1212 assert(path != (const char *) NULL);
1213 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
1214 assert(component != (char *) NULL);
1215 if (*path == '\0')
1216 {
1217 *component='\0';
1218 return;
1219 }
1220 (void) CopyMagickString(component,path,MaxTextExtent);
1221 *magick='\0';
cristy1224a992011-10-12 19:23:41 +00001222#if defined(__OS2__)
1223 if (path[1] != ":")
1224#endif
1225 for (p=component; *p != '\0'; p++)
1226 {
1227 if ((*p == '%') && (*(p+1) == '['))
1228 {
1229 /*
1230 Skip over %[...].
1231 */
1232 for (p++; (*p != ']') && (*p != '\0'); p++) ;
1233 if (*p == '\0')
1234 break;
1235 }
1236 if ((*p == ':') && (IsPathDirectory(path) < 0) &&
1237 (IsPathAccessible(path) == MagickFalse))
1238 {
1239 /*
1240 Look for image format specification (e.g. ps3:image).
1241 */
1242 (void) CopyMagickString(magick,component,(size_t) (p-component+1));
1243 if (IsMagickConflict(magick) != MagickFalse)
1244 *magick='\0';
1245 else
1246 for (q=component; *q != '\0'; q++)
1247 *q=(*++p);
1248 break;
1249 }
1250 }
cristy86057c42011-08-03 18:12:58 +00001251 *subimage='\0';
1252 p=component;
1253 if (*p != '\0')
1254 p=component+strlen(component)-1;
1255 if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1256 (IsPathAccessible(path) == MagickFalse))
1257 {
1258 /*
1259 Look for scene specification (e.g. img0001.pcd[4]).
1260 */
1261 for (q=p-1; q > component; q--)
1262 if (*q == '[')
1263 break;
1264 if (*q == '[')
1265 {
1266 (void) CopyMagickString(subimage,q+1,MaxTextExtent);
1267 subimage[p-q-1]='\0';
1268 if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) &&
1269 (IsGeometry(subimage) == MagickFalse))
1270 *subimage='\0';
cristy1224a992011-10-12 19:23:41 +00001271 else
1272 *q='\0';
cristy86057c42011-08-03 18:12:58 +00001273 }
1274 }
cristy3ed852e2009-09-05 21:47:34 +00001275 p=component;
1276 if (*p != '\0')
1277 for (p=component+strlen(component)-1; p > component; p--)
1278 if (IsBasenameSeparator(*p) != MagickFalse)
1279 break;
1280 switch (type)
1281 {
1282 case MagickPath:
1283 {
1284 (void) CopyMagickString(component,magick,MaxTextExtent);
1285 break;
1286 }
1287 case RootPath:
1288 {
1289 for (p=component+(strlen(component)-1); p > component; p--)
1290 {
1291 if (IsBasenameSeparator(*p) != MagickFalse)
1292 break;
1293 if (*p == '.')
1294 break;
1295 }
1296 if (*p == '.')
1297 *p='\0';
1298 break;
1299 }
1300 case HeadPath:
1301 {
1302 *p='\0';
1303 break;
1304 }
1305 case TailPath:
1306 {
1307 if (IsBasenameSeparator(*p) != MagickFalse)
1308 (void) CopyMagickMemory((unsigned char *) component,
1309 (const unsigned char *) (p+1),strlen(p+1)+1);
1310 break;
1311 }
1312 case BasePath:
1313 {
1314 if (IsBasenameSeparator(*p) != MagickFalse)
1315 (void) CopyMagickString(component,p+1,MaxTextExtent);
1316 for (p=component+(strlen(component)-1); p > component; p--)
1317 if (*p == '.')
1318 {
1319 *p='\0';
1320 break;
1321 }
1322 break;
1323 }
1324 case ExtensionPath:
1325 {
1326 if (IsBasenameSeparator(*p) != MagickFalse)
1327 (void) CopyMagickString(component,p+1,MaxTextExtent);
1328 p=component;
1329 if (*p != '\0')
1330 for (p=component+strlen(component)-1; p > component; p--)
1331 if (*p == '.')
1332 break;
1333 *component='\0';
1334 if (*p == '.')
1335 (void) CopyMagickString(component,p+1,MaxTextExtent);
1336 break;
1337 }
1338 case SubimagePath:
1339 {
1340 (void) CopyMagickString(component,subimage,MaxTextExtent);
1341 break;
1342 }
1343 case CanonicalPath:
1344 case UndefinedPath:
1345 break;
1346 }
1347}
1348
1349/*
1350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351% %
1352% %
1353% %
1354% G e t P a t h C o m p o n e n t s %
1355% %
1356% %
1357% %
1358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359%
1360% GetPathComponents() returns a list of path components.
1361%
1362% The format of the GetPathComponents method is:
1363%
1364% char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001365% size_t *number_componenets)
cristy3ed852e2009-09-05 21:47:34 +00001366%
1367% A description of each parameter follows:
1368%
1369% o path: Specifies the string to segment into a list.
1370%
1371% o number_components: return the number of components in the list
1372%
1373*/
cristyd1dd6e42011-09-04 01:46:08 +00001374MagickPrivate char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001375 size_t *number_components)
cristy3ed852e2009-09-05 21:47:34 +00001376{
1377 char
1378 **components;
1379
1380 register const char
1381 *p,
1382 *q;
1383
cristybb503372010-05-27 20:51:26 +00001384 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001385 i;
1386
1387 if (path == (char *) NULL)
1388 return((char **) NULL);
1389 *number_components=1;
1390 for (p=path; *p != '\0'; p++)
1391 if (IsBasenameSeparator(*p))
1392 (*number_components)++;
1393 components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1394 sizeof(*components));
1395 if (components == (char **) NULL)
1396 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1397 p=path;
cristybb503372010-05-27 20:51:26 +00001398 for (i=0; i < (ssize_t) *number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001399 {
1400 for (q=p; *q != '\0'; q++)
1401 if (IsBasenameSeparator(*q))
1402 break;
1403 components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
cristyc92c1e12011-03-25 15:47:59 +00001404 sizeof(**components));
cristy3ed852e2009-09-05 21:47:34 +00001405 if (components[i] == (char *) NULL)
1406 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1407 (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1408 p=q+1;
1409 }
1410 components[i]=(char *) NULL;
1411 return(components);
1412}
1413
1414/*
1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416% %
1417% %
1418% %
1419% I s P a t h A c c e s s i b l e %
1420% %
1421% %
1422% %
1423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424%
1425% IsPathAccessible() returns MagickTrue if the file as defined by the path is
1426% accessible.
1427%
1428% The format of the IsPathAccessible method is:
1429%
cristy59864562013-04-18 11:47:41 +00001430% MagickBooleanType IsPathAccessible(const char *path)
cristy3ed852e2009-09-05 21:47:34 +00001431%
1432% A description of each parameter follows.
1433%
1434% o path: Specifies a path to a file.
1435%
1436*/
1437MagickExport MagickBooleanType IsPathAccessible(const char *path)
1438{
1439 MagickBooleanType
1440 status;
1441
1442 struct stat
1443 attributes;
1444
1445 if ((path == (const char *) NULL) || (*path == '\0'))
1446 return(MagickFalse);
1447 status=GetPathAttributes(path,&attributes);
1448 if (status == MagickFalse)
1449 return(status);
1450 if (S_ISREG(attributes.st_mode) == 0)
1451 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +00001452 if (access_utf8(path,F_OK) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001453 return(MagickFalse);
1454 return(MagickTrue);
1455}
1456
1457/*
1458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459% %
1460% %
1461% %
1462+ I s P a t h D i r e c t o r y %
1463% %
1464% %
1465% %
1466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467%
1468% IsPathDirectory() returns -1 if the directory does not exist, 1 is returned
1469% if the path represents a directory otherwise 0.
1470%
1471% The format of the IsPathDirectory method is:
1472%
1473% int IsPathDirectory(const char *path)
1474%
1475% A description of each parameter follows.
1476%
1477% o path: The directory path.
1478%
1479*/
1480static int IsPathDirectory(const char *path)
1481{
1482 MagickBooleanType
1483 status;
1484
1485 struct stat
1486 attributes;
1487
1488 if ((path == (const char *) NULL) || (*path == '\0'))
1489 return(MagickFalse);
1490 status=GetPathAttributes(path,&attributes);
1491 if (status == MagickFalse)
1492 return(-1);
1493 if (S_ISDIR(attributes.st_mode) == 0)
1494 return(0);
1495 return(1);
1496}
1497
1498/*
1499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1500% %
1501% %
1502% %
cristy3ed852e2009-09-05 21:47:34 +00001503% L i s t F i l e s %
1504% %
1505% %
1506% %
1507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1508%
1509% ListFiles() reads the directory specified and returns a list of filenames
1510% contained in the directory sorted in ascending alphabetic order.
1511%
1512% The format of the ListFiles function is:
1513%
1514% char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001515% ssize_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001516%
1517% A description of each parameter follows:
1518%
1519% o filelist: Method ListFiles returns a list of filenames contained
1520% in the directory. If the directory specified cannot be read or it is
1521% a file a NULL list is returned.
1522%
1523% o directory: Specifies a pointer to a text string containing a directory
1524% name.
1525%
1526% o pattern: Specifies a pointer to a text string containing a pattern.
1527%
1528% o number_entries: This integer returns the number of filenames in the
1529% list.
1530%
1531*/
1532
1533#if defined(__cplusplus) || defined(c_plusplus)
1534extern "C" {
1535#endif
1536
1537static int FileCompare(const void *x,const void *y)
1538{
1539 register const char
1540 **p,
1541 **q;
1542
1543 p=(const char **) x;
1544 q=(const char **) y;
1545 return(LocaleCompare(*p,*q));
1546}
1547
1548#if defined(__cplusplus) || defined(c_plusplus)
1549}
1550#endif
1551
1552static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1553 struct dirent **result)
1554{
1555#if defined(MAGICKCORE_HAVE_READDIR_R)
1556 return(readdir_r(directory,entry,result));
1557#else
1558 (void) entry;
1559 errno=0;
1560 *result=readdir(directory);
1561 return(errno);
1562#endif
1563}
1564
cristyd1dd6e42011-09-04 01:46:08 +00001565MagickPrivate char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001566 size_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001567{
1568 char
1569 **filelist;
1570
1571 DIR
1572 *current_directory;
1573
1574 struct dirent
1575 *buffer,
1576 *entry;
1577
cristybb503372010-05-27 20:51:26 +00001578 size_t
cristy3ed852e2009-09-05 21:47:34 +00001579 max_entries;
1580
1581 /*
1582 Open directory.
1583 */
1584 assert(directory != (const char *) NULL);
1585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1586 assert(pattern != (const char *) NULL);
cristybb503372010-05-27 20:51:26 +00001587 assert(number_entries != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001588 *number_entries=0;
1589 current_directory=opendir(directory);
1590 if (current_directory == (DIR *) NULL)
1591 return((char **) NULL);
1592 /*
1593 Allocate filelist.
1594 */
1595 max_entries=2048;
1596 filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1597 sizeof(*filelist));
1598 if (filelist == (char **) NULL)
1599 {
1600 (void) closedir(current_directory);
1601 return((char **) NULL);
1602 }
1603 /*
1604 Save the current and change to the new directory.
1605 */
cristy6e6c8222014-10-18 00:19:27 +00001606 buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+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}