blob: ae4f11de925507def493fd62518ce73bf87d25f2 [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% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 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"
dirk007e9252015-01-15 21:02:57 +000049#include "MagickCore/image-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/list.h"
51#include "MagickCore/log.h"
cristy7832dc22011-09-05 01:21:53 +000052#include "MagickCore/magick-private.h"
cristy4c08aed2011-07-01 19:47:50 +000053#include "MagickCore/memory_.h"
cristy2c5fc272012-02-22 01:27:46 +000054#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000055#include "MagickCore/option.h"
56#include "MagickCore/policy.h"
cristy403ae7b2013-04-18 12:49:11 +000057#include "MagickCore/random_.h"
58#include "MagickCore/registry.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/resource_.h"
60#include "MagickCore/semaphore.h"
61#include "MagickCore/signature-private.h"
62#include "MagickCore/statistic.h"
63#include "MagickCore/string_.h"
cristy7832dc22011-09-05 01:21:53 +000064#include "MagickCore/string-private.h"
cristy4c08aed2011-07-01 19:47:50 +000065#include "MagickCore/token.h"
cristy7832dc22011-09-05 01:21:53 +000066#include "MagickCore/token-private.h"
cristy4c08aed2011-07-01 19:47:50 +000067#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000068#include "MagickCore/utility-private.h"
cristy98e91bd2010-01-12 01:11:42 +000069#if defined(MAGICKCORE_HAVE_PROCESS_H)
70#include <process.h>
71#endif
cristy3ed852e2009-09-05 21:47:34 +000072#if defined(MAGICKCORE_HAVE_MACH_O_DYLD_H)
73#include <mach-o/dyld.h>
74#endif
75
76/*
77 Static declarations.
78*/
79static const char
80 Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
81
82/*
83 Forward declaration.
84*/
85static int
86 IsPathDirectory(const char *);
87
88/*
89%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90% %
91% %
92% %
93% A c q u i r e U n i q u e F i l e n a m e %
94% %
95% %
96% %
97%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98%
99% AcquireUniqueFilename() replaces the contents of path by a unique path name.
100%
101% The format of the AcquireUniqueFilename method is:
102%
103% MagickBooleanType AcquireUniqueFilename(char *path)
104%
105% A description of each parameter follows.
106%
107% o path: Specifies a pointer to an array of characters. The unique path
108% name is returned in this array.
109%
110*/
111MagickExport MagickBooleanType AcquireUniqueFilename(char *path)
112{
113 int
114 file;
115
116 file=AcquireUniqueFileResource(path);
117 if (file == -1)
118 return(MagickFalse);
119 file=close(file)-1;
120 return(MagickTrue);
121}
122
123/*
124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125% %
126% %
127% %
128% A c q u i r e U n i q u e S ym b o l i c L i n k %
129% %
130% %
131% %
132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133%
134% AcquireUniqueSymbolicLink() creates a unique symbolic link to the specified
135% source path and returns MagickTrue on success otherwise MagickFalse. If the
136% symlink() method fails or is not available, a unique file name is generated
137% and the source file copied to it. When you are finished with the file, use
138% RelinquishUniqueFilename() to destroy it.
139%
140% The format of the AcquireUniqueSymbolicLink method is:
141%
142% MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
143% char destination)
144%
145% A description of each parameter follows.
146%
147% o source: the source path.
148%
149% o destination: the destination path.
150%
151*/
152
cristy3ed852e2009-09-05 21:47:34 +0000153MagickExport MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
154 char *destination)
155{
156 int
157 destination_file,
158 source_file;
159
160 size_t
161 length,
162 quantum;
163
164 ssize_t
165 count;
166
167 struct stat
168 attributes;
169
170 unsigned char
171 *buffer;
172
173 assert(source != (const char *) NULL);
174 assert(destination != (char *) NULL);
175#if defined(MAGICKCORE_HAVE_SYMLINK)
176 (void) AcquireUniqueFilename(destination);
177 (void) RelinquishUniqueFileResource(destination);
178 if (*source == *DirectorySeparator)
179 {
180 if (symlink(source,destination) == 0)
181 return(MagickTrue);
182 }
183 else
184 {
185 char
cristy151b66d2015-04-15 10:50:31 +0000186 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000187
188 *path='\0';
cristy151b66d2015-04-15 10:50:31 +0000189 if (getcwd(path,MagickPathExtent) == (char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000190 return(MagickFalse);
cristy151b66d2015-04-15 10:50:31 +0000191 (void) ConcatenateMagickString(path,DirectorySeparator,MagickPathExtent);
192 (void) ConcatenateMagickString(path,source,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000193 if (symlink(path,destination) == 0)
194 return(MagickTrue);
195 }
196#endif
197 destination_file=AcquireUniqueFileResource(destination);
198 if (destination_file == -1)
199 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +0000200 source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000201 if (source_file == -1)
202 {
203 (void) close(destination_file);
204 (void) RelinquishUniqueFileResource(destination);
205 return(MagickFalse);
206 }
207 quantum=(size_t) MagickMaxBufferExtent;
cristyf201ba62015-07-05 13:54:28 +0000208 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
209 quantum=(size_t) MagickMin(attributes.st_size,MagickMaxBufferExtent);
cristy3ed852e2009-09-05 21:47:34 +0000210 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
211 if (buffer == (unsigned char *) NULL)
212 {
213 (void) close(source_file);
214 (void) close(destination_file);
215 (void) RelinquishUniqueFileResource(destination);
216 return(MagickFalse);
217 }
218 for (length=0; ; )
219 {
220 count=(ssize_t) read(source_file,buffer,quantum);
221 if (count <= 0)
222 break;
223 length=(size_t) count;
224 count=(ssize_t) write(destination_file,buffer,length);
225 if ((size_t) count != length)
226 {
227 (void) close(destination_file);
228 (void) close(source_file);
229 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
230 (void) RelinquishUniqueFileResource(destination);
231 return(MagickFalse);
232 }
233 }
234 (void) close(destination_file);
235 (void) close(source_file);
236 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
237 return(MagickTrue);
238}
239
240/*
241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242% %
243% %
244% %
245% A p p e n d I m a g e F o r m a t %
246% %
247% %
248% %
249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250%
251% AppendImageFormat() appends the image format type to the filename. If an
252% extension to the file already exists, it is first removed.
253%
254% The format of the AppendImageFormat method is:
255%
256% void AppendImageFormat(const char *format,char *filename)
257%
258% A description of each parameter follows.
259%
260% o format: Specifies a pointer to an array of characters. This the
261% format of the image.
262%
263% o filename: Specifies a pointer to an array of characters. The unique
264% file name is returned in this array.
265%
266*/
267MagickExport void AppendImageFormat(const char *format,char *filename)
268{
269 char
cristy151b66d2015-04-15 10:50:31 +0000270 extension[MagickPathExtent],
271 root[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000272
273 assert(format != (char *) NULL);
274 assert(filename != (char *) NULL);
275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
276 if ((*format == '\0') || (*filename == '\0'))
277 return;
278 if (LocaleCompare(filename,"-") == 0)
279 {
280 char
cristy151b66d2015-04-15 10:50:31 +0000281 message[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000282
cristy58a33832015-04-15 22:36:16 +0000283 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",format,
284 filename);
cristy151b66d2015-04-15 10:50:31 +0000285 (void) CopyMagickString(filename,message,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000286 return;
287 }
cristy212e2622010-06-12 19:07:47 +0000288 GetPathComponent(filename,ExtensionPath,extension);
289 if ((LocaleCompare(extension,"Z") == 0) ||
290 (LocaleCompare(extension,"bz2") == 0) ||
291 (LocaleCompare(extension,"gz") == 0) ||
292 (LocaleCompare(extension,"wmz") == 0) ||
293 (LocaleCompare(extension,"svgz") == 0))
294 {
295 GetPathComponent(filename,RootPath,root);
cristy151b66d2015-04-15 10:50:31 +0000296 (void) CopyMagickString(filename,root,MagickPathExtent);
cristy212e2622010-06-12 19:07:47 +0000297 GetPathComponent(filename,RootPath,root);
cristy58a33832015-04-15 22:36:16 +0000298 (void) FormatLocaleString(filename,MagickPathExtent,"%s.%s.%s",root,
299 format,extension);
cristy212e2622010-06-12 19:07:47 +0000300 return;
301 }
cristy3ed852e2009-09-05 21:47:34 +0000302 GetPathComponent(filename,RootPath,root);
cristy151b66d2015-04-15 10:50:31 +0000303 (void) FormatLocaleString(filename,MagickPathExtent,"%s.%s",root,format);
cristy3ed852e2009-09-05 21:47:34 +0000304}
305
306/*
307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
308% %
309% %
310% %
311% B a s e 6 4 D e c o d e %
312% %
313% %
314% %
315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316%
317% Base64Decode() decodes Base64-encoded text and returns its binary
318% equivalent. NULL is returned if the text is not valid Base64 data, or a
319% memory allocation failure occurs.
320%
321% The format of the Base64Decode method is:
322%
323% unsigned char *Base64Decode(const char *source,length_t *length)
324%
325% A description of each parameter follows:
326%
327% o source: A pointer to a Base64-encoded string.
328%
329% o length: the number of bytes decoded.
330%
331*/
332MagickExport unsigned char *Base64Decode(const char *source,size_t *length)
333{
334 int
335 state;
336
337 register const char
338 *p,
339 *q;
340
341 register size_t
342 i;
343
344 unsigned char
345 *decode;
346
347 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
348 assert(source != (char *) NULL);
349 assert(length != (size_t *) NULL);
350 *length=0;
cristy2ceb4f82015-05-31 14:48:29 +0000351 decode=(unsigned char *) AcquireQuantumMemory((strlen(source)+3)/4,
cristy3ed852e2009-09-05 21:47:34 +0000352 3*sizeof(*decode));
353 if (decode == (unsigned char *) NULL)
354 return((unsigned char *) NULL);
355 i=0;
356 state=0;
357 for (p=source; *p != '\0'; p++)
358 {
359 if (isspace((int) ((unsigned char) *p)) != 0)
360 continue;
361 if (*p == '=')
362 break;
363 q=strchr(Base64,*p);
364 if (q == (char *) NULL)
365 {
366 decode=(unsigned char *) RelinquishMagickMemory(decode);
367 return((unsigned char *) NULL); /* non-Base64 character */
368 }
369 switch (state)
370 {
371 case 0:
372 {
373 decode[i]=(q-Base64) << 2;
374 state++;
375 break;
376 }
377 case 1:
378 {
379 decode[i++]|=(q-Base64) >> 4;
380 decode[i]=((q-Base64) & 0x0f) << 4;
381 state++;
382 break;
383 }
384 case 2:
385 {
386 decode[i++]|=(q-Base64) >> 2;
387 decode[i]=((q-Base64) & 0x03) << 6;
388 state++;
389 break;
390 }
391 case 3:
392 {
393 decode[i++]|=(q-Base64);
394 state=0;
395 break;
396 }
397 }
398 }
399 /*
400 Verify Base-64 string has proper terminal characters.
401 */
402 if (*p != '=')
403 {
404 if (state != 0)
405 {
406 decode=(unsigned char *) RelinquishMagickMemory(decode);
407 return((unsigned char *) NULL);
408 }
409 }
410 else
411 {
412 p++;
413 switch (state)
414 {
415 case 0:
416 case 1:
417 {
418 /*
419 Unrecognized '=' character.
420 */
421 decode=(unsigned char *) RelinquishMagickMemory(decode);
422 return((unsigned char *) NULL);
423 }
424 case 2:
425 {
426 for ( ; *p != '\0'; p++)
427 if (isspace((int) ((unsigned char) *p)) == 0)
428 break;
429 if (*p != '=')
430 {
431 decode=(unsigned char *) RelinquishMagickMemory(decode);
432 return((unsigned char *) NULL);
433 }
434 p++;
435 }
436 case 3:
437 {
438 for ( ; *p != '\0'; p++)
439 if (isspace((int) ((unsigned char) *p)) == 0)
440 {
441 decode=(unsigned char *) RelinquishMagickMemory(decode);
442 return((unsigned char *) NULL);
443 }
444 if ((int) decode[i] != 0)
445 {
446 decode=(unsigned char *) RelinquishMagickMemory(decode);
447 return((unsigned char *) NULL);
448 }
cristy6f008fd2014-05-25 23:27:26 +0000449 break;
cristy3ed852e2009-09-05 21:47:34 +0000450 }
451 }
452 }
453 *length=i;
454 return(decode);
455}
456
457/*
458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459% %
460% %
461% %
462% B a s e 6 4 E n c o d e %
463% %
464% %
465% %
466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467%
468% Base64Encode() encodes arbitrary binary data to Base64 encoded format as
469% described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and
470% returns the result as a null-terminated ASCII string. NULL is returned if
471% a memory allocation failure occurs.
472%
473% The format of the Base64Encode method is:
474%
475% char *Base64Encode(const unsigned char *blob,const size_t blob_length,
476% size_t *encode_length)
477%
478% A description of each parameter follows:
479%
480% o blob: A pointer to binary data to encode.
481%
482% o blob_length: the number of bytes to encode.
483%
484% o encode_length: The number of bytes encoded.
485%
486*/
487MagickExport char *Base64Encode(const unsigned char *blob,
488 const size_t blob_length,size_t *encode_length)
489{
490 char
491 *encode;
492
493 register const unsigned char
494 *p;
495
496 register size_t
497 i;
498
499 size_t
500 remainder;
501
502 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
503 assert(blob != (const unsigned char *) NULL);
504 assert(blob_length != 0);
505 assert(encode_length != (size_t *) NULL);
506 *encode_length=0;
507 encode=(char *) AcquireQuantumMemory(blob_length/3+4,4*sizeof(*encode));
508 if (encode == (char *) NULL)
509 return((char *) NULL);
510 i=0;
511 for (p=blob; p < (blob+blob_length-2); p+=3)
512 {
513 encode[i++]=Base64[(int) (*p >> 2)];
514 encode[i++]=Base64[(int) (((*p & 0x03) << 4)+(*(p+1) >> 4))];
515 encode[i++]=Base64[(int) (((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))];
516 encode[i++]=Base64[(int) (*(p+2) & 0x3f)];
517 }
518 remainder=blob_length % 3;
519 if (remainder != 0)
520 {
cristybb503372010-05-27 20:51:26 +0000521 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000522 j;
523
524 unsigned char
525 code[3];
526
527 code[0]='\0';
528 code[1]='\0';
529 code[2]='\0';
cristybb503372010-05-27 20:51:26 +0000530 for (j=0; j < (ssize_t) remainder; j++)
cristy3ed852e2009-09-05 21:47:34 +0000531 code[j]=(*p++);
532 encode[i++]=Base64[(int) (code[0] >> 2)];
533 encode[i++]=Base64[(int) (((code[0] & 0x03) << 4)+(code[1] >> 4))];
534 if (remainder == 1)
535 encode[i++]='=';
536 else
537 encode[i++]=Base64[(int) (((code[1] & 0x0f) << 2)+(code[2] >> 6))];
538 encode[i++]='=';
539 }
540 *encode_length=i;
541 encode[i++]='\0';
542 return(encode);
543}
544
545/*
546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547% %
548% %
549% %
550% C h o p P a t h C o m p o n e n t s %
551% %
552% %
553% %
554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
555%
556% ChopPathComponents() removes the number of specified file components from a
557% path.
558%
559% The format of the ChopPathComponents method is:
560%
cristybb503372010-05-27 20:51:26 +0000561% ChopPathComponents(char *path,size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000562%
563% A description of each parameter follows:
564%
565% o path: The path.
566%
567% o components: The number of components to chop.
568%
569*/
cristyd1dd6e42011-09-04 01:46:08 +0000570MagickPrivate void ChopPathComponents(char *path,const size_t components)
cristy3ed852e2009-09-05 21:47:34 +0000571{
cristybb503372010-05-27 20:51:26 +0000572 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000573 i;
574
cristybb503372010-05-27 20:51:26 +0000575 for (i=0; i < (ssize_t) components; i++)
cristy3ed852e2009-09-05 21:47:34 +0000576 GetPathComponent(path,HeadPath,path);
577}
578
579/*
580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
581% %
582% %
583% %
584% E x p a n d F i l e n a m e %
585% %
586% %
587% %
588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589%
590% ExpandFilename() expands '~' in a path.
591%
592% The format of the ExpandFilename function is:
593%
594% ExpandFilename(char *path)
595%
596% A description of each parameter follows:
597%
598% o path: Specifies a pointer to a character array that contains the
599% path.
600%
601*/
cristyd1dd6e42011-09-04 01:46:08 +0000602MagickPrivate void ExpandFilename(char *path)
cristy3ed852e2009-09-05 21:47:34 +0000603{
604 char
cristy151b66d2015-04-15 10:50:31 +0000605 expand_path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000606
607 if (path == (char *) NULL)
608 return;
609 if (*path != '~')
610 return;
cristy151b66d2015-04-15 10:50:31 +0000611 (void) CopyMagickString(expand_path,path,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000612 if ((*(path+1) == *DirectorySeparator) || (*(path+1) == '\0'))
613 {
614 char
615 *home;
616
617 /*
618 Substitute ~ with $HOME.
619 */
cristy151b66d2015-04-15 10:50:31 +0000620 (void) CopyMagickString(expand_path,".",MagickPathExtent);
621 (void) ConcatenateMagickString(expand_path,path+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000622 home=GetEnvironmentValue("HOME");
623 if (home == (char *) NULL)
624 home=GetEnvironmentValue("USERPROFILE");
625 if (home != (char *) NULL)
626 {
cristy151b66d2015-04-15 10:50:31 +0000627 (void) CopyMagickString(expand_path,home,MagickPathExtent);
628 (void) ConcatenateMagickString(expand_path,path+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000629 home=DestroyString(home);
630 }
631 }
632 else
633 {
634#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__)
635 char
cristy151b66d2015-04-15 10:50:31 +0000636 username[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000637
638 register char
639 *p;
640
641 struct passwd
642 *entry;
643
644 /*
645 Substitute ~ with home directory from password file.
646 */
cristy151b66d2015-04-15 10:50:31 +0000647 (void) CopyMagickString(username,path+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000648 p=strchr(username,'/');
649 if (p != (char *) NULL)
650 *p='\0';
651 entry=getpwnam(username);
652 if (entry == (struct passwd *) NULL)
653 return;
cristy151b66d2015-04-15 10:50:31 +0000654 (void) CopyMagickString(expand_path,entry->pw_dir,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000655 if (p != (char *) NULL)
656 {
cristy151b66d2015-04-15 10:50:31 +0000657 (void) ConcatenateMagickString(expand_path,"/",MagickPathExtent);
658 (void) ConcatenateMagickString(expand_path,p+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000659 }
660#endif
661 }
cristy151b66d2015-04-15 10:50:31 +0000662 (void) CopyMagickString(path,expand_path,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000663}
664
665/*
666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
667% %
668% %
669% %
670% E x p a n d F i l e n a m e s %
671% %
672% %
673% %
674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675%
anthonyde897b72012-04-27 00:16:17 +0000676% ExpandFilenames() checks each argument of the given argument array, and
677% expands it if they have a wildcard character.
678%
679% Any coder prefix (EG: 'coder:filename') or read modifier postfix (EG:
680% 'filename[...]') are ignored during the file the expansion, but will be
681% included in the final argument. If no filename matching the meta-character
682% 'glob' is found the original argument is returned.
683%
684% For example, an argument of '*.gif[20x20]' will be replaced by the list
685% 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
686% if such filenames exist, (in the current directory in this case).
687%
688% Meta-characters handled...
689% @ read a list of filenames (no further expansion performed)
690% ~ At start of filename expands to HOME environemtn variable
691% * matches any string including an empty string
692% ? matches by any single character
693%
694% WARNING: filenames starting with '.' (hidden files in a UNIX file system)
695% will never be expanded. Attempting to epand '.*' will produce no change.
696%
697% Expansion is ignored for coders "label:" "caption:" "pango:" and "vid:".
698% Which provide their own '@' meta-character handling.
699%
cristy8a5d7f42013-01-06 15:24:33 +0000700% You can see the results of the expansion using "Configure" log events.
anthony451f9092012-05-11 01:56:24 +0000701%
702% The returned list should be freed using DestroyStringList().
703%
704% However the strings in the original pointed to argv are not
705% freed (TO BE CHECKED). So a copy of the original pointer (and count)
706% should be kept separate if they need to be freed later.
707%
cristy3ed852e2009-09-05 21:47:34 +0000708% The format of the ExpandFilenames function is:
709%
710% status=ExpandFilenames(int *number_arguments,char ***arguments)
711%
712% A description of each parameter follows:
713%
714% o number_arguments: Specifies a pointer to an integer describing the
715% number of elements in the argument vector.
716%
717% o arguments: Specifies a pointer to a text array containing the command
718% line arguments.
719%
720*/
721MagickExport MagickBooleanType ExpandFilenames(int *number_arguments,
722 char ***arguments)
723{
724 char
cristy151b66d2015-04-15 10:50:31 +0000725 home_directory[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +0000726 **vector;
727
cristybb503372010-05-27 20:51:26 +0000728 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000729 i,
730 j;
731
cristybb503372010-05-27 20:51:26 +0000732 size_t
cristy3ed852e2009-09-05 21:47:34 +0000733 number_files;
734
cristy00976d82011-02-20 20:31:28 +0000735 ssize_t
736 count,
737 parameters;
738
cristy3ed852e2009-09-05 21:47:34 +0000739 /*
740 Allocate argument vector.
741 */
742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
743 assert(number_arguments != (int *) NULL);
744 assert(arguments != (char ***) NULL);
745 vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1),
746 sizeof(*vector));
747 if (vector == (char **) NULL)
748 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
749 /*
750 Expand any wildcard filenames.
751 */
752 *home_directory='\0';
cristy3ed852e2009-09-05 21:47:34 +0000753 count=0;
cristybb503372010-05-27 20:51:26 +0000754 for (i=0; i < (ssize_t) *number_arguments; i++)
cristy3ed852e2009-09-05 21:47:34 +0000755 {
756 char
757 **filelist,
cristy151b66d2015-04-15 10:50:31 +0000758 filename[MagickPathExtent],
759 magick[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +0000760 *option,
cristy151b66d2015-04-15 10:50:31 +0000761 path[MagickPathExtent],
762 subimage[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000763
764 MagickBooleanType
765 destroy;
766
767 option=(*arguments)[i];
768 *magick='\0';
769 *path='\0';
770 *filename='\0';
771 *subimage='\0';
cristy54ebd8d2014-01-14 01:14:23 +0000772 number_files=0;
cristy3ed852e2009-09-05 21:47:34 +0000773 vector[count++]=ConstantString(option);
774 destroy=MagickTrue;
cristy042ee782011-04-22 18:48:30 +0000775 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy3ed852e2009-09-05 21:47:34 +0000776 if (parameters > 0)
777 {
778 /*
779 Do not expand command option parameters.
780 */
781 for (j=0; j < parameters; j++)
782 {
783 i++;
cristybb503372010-05-27 20:51:26 +0000784 if (i == (ssize_t) *number_arguments)
cristy3ed852e2009-09-05 21:47:34 +0000785 break;
786 option=(*arguments)[i];
787 vector[count++]=ConstantString(option);
788 }
789 continue;
790 }
791 if ((*option == '"') || (*option == '\''))
792 continue;
cristy4b064822012-04-29 13:26:43 +0000793 GetPathComponent(option,TailPath,filename);
cristy3ed852e2009-09-05 21:47:34 +0000794 GetPathComponent(option,MagickPath,magick);
795 if ((LocaleCompare(magick,"CAPTION") == 0) ||
796 (LocaleCompare(magick,"LABEL") == 0) ||
cristyc0732c42012-03-20 19:28:35 +0000797 (LocaleCompare(magick,"PANGO") == 0) ||
cristy3ed852e2009-09-05 21:47:34 +0000798 (LocaleCompare(magick,"VID") == 0))
799 continue;
cristy127425f2012-04-29 13:38:05 +0000800 if ((IsGlob(filename) == MagickFalse) && (*option != '@'))
cristy3ed852e2009-09-05 21:47:34 +0000801 continue;
cristy127425f2012-04-29 13:38:05 +0000802 if (*option != '@')
cristy3ed852e2009-09-05 21:47:34 +0000803 {
804 /*
805 Generate file list from wildcard filename (e.g. *.jpg).
806 */
807 GetPathComponent(option,HeadPath,path);
808 GetPathComponent(option,SubimagePath,subimage);
809 ExpandFilename(path);
cristyf5ee5be2009-11-06 02:22:56 +0000810 if (*home_directory == '\0')
cristy151b66d2015-04-15 10:50:31 +0000811 getcwd_utf8(home_directory,MagickPathExtent-1);
cristy4b064822012-04-29 13:26:43 +0000812 filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
cristy3ed852e2009-09-05 21:47:34 +0000813 &number_files);
814 }
815 else
816 {
817 char
818 *files;
819
820 ExceptionInfo
821 *exception;
822
823 int
cristyf9218a72010-07-03 17:29:40 +0000824 length;
cristy3ed852e2009-09-05 21:47:34 +0000825
826 /*
827 Generate file list from file list (e.g. @filelist.txt).
828 */
829 exception=AcquireExceptionInfo();
cristy3a5987c2013-11-07 14:18:46 +0000830 files=FileToString(option+1,~0UL,exception);
cristy3ed852e2009-09-05 21:47:34 +0000831 exception=DestroyExceptionInfo(exception);
832 if (files == (char *) NULL)
833 continue;
cristyf9218a72010-07-03 17:29:40 +0000834 filelist=StringToArgv(files,&length);
835 if (filelist == (char **) NULL)
836 continue;
cristy3ed852e2009-09-05 21:47:34 +0000837 files=DestroyString(files);
cristyf9218a72010-07-03 17:29:40 +0000838 filelist[0]=DestroyString(filelist[0]);
839 for (j=0; j < (ssize_t) (length-1); j++)
840 filelist[j]=filelist[j+1];
841 number_files=(size_t) length-1;
cristy3ed852e2009-09-05 21:47:34 +0000842 }
843 if (filelist == (char **) NULL)
844 continue;
cristybb503372010-05-27 20:51:26 +0000845 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000846 if (IsPathDirectory(filelist[j]) <= 0)
847 break;
cristybb503372010-05-27 20:51:26 +0000848 if (j == (ssize_t) number_files)
cristy3ed852e2009-09-05 21:47:34 +0000849 {
cristybb503372010-05-27 20:51:26 +0000850 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000851 filelist[j]=DestroyString(filelist[j]);
852 filelist=(char **) RelinquishMagickMemory(filelist);
853 continue;
854 }
855 /*
856 Transfer file list to argument vector.
857 */
858 vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
859 count+number_files+1,sizeof(*vector));
860 if (vector == (char **) NULL)
dirk62813b52015-09-20 09:11:28 +0200861 {
862 for (j=0; j < (ssize_t) number_files; j++)
863 filelist[j]=DestroyString(filelist[j]);
864 filelist=(char **) RelinquishMagickMemory(filelist);
865 return(MagickFalse);
866 }
cristybb503372010-05-27 20:51:26 +0000867 for (j=0; j < (ssize_t) number_files; j++)
cristy3ed852e2009-09-05 21:47:34 +0000868 {
cristy0e526222010-05-06 14:07:32 +0000869 option=filelist[j];
cristy042ee782011-04-22 18:48:30 +0000870 parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
cristy0e526222010-05-06 14:07:32 +0000871 if (parameters > 0)
872 {
cristybb503372010-05-27 20:51:26 +0000873 ssize_t
cristy0e526222010-05-06 14:07:32 +0000874 k;
875
876 /*
877 Do not expand command option parameters.
878 */
879 vector[count++]=ConstantString(option);
880 for (k=0; k < parameters; k++)
881 {
882 j++;
cristybb503372010-05-27 20:51:26 +0000883 if (j == (ssize_t) number_files)
cristy0e526222010-05-06 14:07:32 +0000884 break;
885 option=filelist[j];
886 vector[count++]=ConstantString(option);
887 }
888 continue;
889 }
cristy151b66d2015-04-15 10:50:31 +0000890 (void) CopyMagickString(filename,path,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000891 if (*path != '\0')
892 (void) ConcatenateMagickString(filename,DirectorySeparator,
cristy151b66d2015-04-15 10:50:31 +0000893 MagickPathExtent);
cristyaa4db032014-01-14 15:07:39 +0000894 if (filelist[j] != (char *) NULL)
cristy151b66d2015-04-15 10:50:31 +0000895 (void) ConcatenateMagickString(filename,filelist[j],MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000896 filelist[j]=DestroyString(filelist[j]);
cristy151b66d2015-04-15 10:50:31 +0000897 if (strlen(filename) >= (MagickPathExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000898 ThrowFatalException(OptionFatalError,"FilenameTruncated");
cristy47dc34d2010-04-22 16:12:43 +0000899 if (IsPathDirectory(filename) <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000900 {
901 char
cristy151b66d2015-04-15 10:50:31 +0000902 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000903
904 *path='\0';
905 if (*magick != '\0')
906 {
cristy151b66d2015-04-15 10:50:31 +0000907 (void) ConcatenateMagickString(path,magick,MagickPathExtent);
908 (void) ConcatenateMagickString(path,":",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000909 }
cristy151b66d2015-04-15 10:50:31 +0000910 (void) ConcatenateMagickString(path,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000911 if (*subimage != '\0')
912 {
cristy151b66d2015-04-15 10:50:31 +0000913 (void) ConcatenateMagickString(path,"[",MagickPathExtent);
914 (void) ConcatenateMagickString(path,subimage,MagickPathExtent);
915 (void) ConcatenateMagickString(path,"]",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000916 }
cristy151b66d2015-04-15 10:50:31 +0000917 if (strlen(path) >= (MagickPathExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000918 ThrowFatalException(OptionFatalError,"FilenameTruncated");
919 if (destroy != MagickFalse)
920 {
921 count--;
922 vector[count]=DestroyString(vector[count]);
923 destroy=MagickFalse;
924 }
925 vector[count++]=ConstantString(path);
926 }
927 }
928 filelist=(char **) RelinquishMagickMemory(filelist);
929 }
930 vector[count]=(char *) NULL;
931 if (IsEventLogging() != MagickFalse)
932 {
933 char
934 *command_line;
935
936 command_line=AcquireString(vector[0]);
937 for (i=1; i < count; i++)
938 {
939 (void) ConcatenateString(&command_line," {");
940 (void) ConcatenateString(&command_line,vector[i]);
941 (void) ConcatenateString(&command_line,"}");
942 }
943 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
944 "Command line: %s",command_line);
945 command_line=DestroyString(command_line);
946 }
947 *number_arguments=(int) count;
948 *arguments=vector;
949 return(MagickTrue);
950}
951
952/*
953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954% %
955% %
956% %
957% G e t E x e c u t i o n P a t h %
958% %
959% %
960% %
961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962%
963% GetExecutionPath() returns the pathname of the executable that started
964% the process. On success MagickTrue is returned, otherwise MagickFalse.
965%
966% The format of the GetExecutionPath method is:
967%
968% MagickBooleanType GetExecutionPath(char *path,const size_t extent)
969%
970% A description of each parameter follows:
971%
972% o path: the pathname of the executable that started the process.
973%
974% o extent: the maximum extent of the path.
975%
976*/
cristyd1dd6e42011-09-04 01:46:08 +0000977MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +0000978{
cristyfbe485a2011-02-22 13:54:48 +0000979 char
980 *directory;
981
cristy3ed852e2009-09-05 21:47:34 +0000982 *path='\0';
cristyfbe485a2011-02-22 13:54:48 +0000983 directory=getcwd(path,(unsigned long) extent);
984 (void) directory;
cristyfa09d142009-10-15 01:02:25 +0000985#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
cristy3ed852e2009-09-05 21:47:34 +0000986 {
987 char
cristy58a33832015-04-15 22:36:16 +0000988 execution_path[PATH_MAX+1],
989 link_path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000990
991 ssize_t
992 count;
993
cristy151b66d2015-04-15 10:50:31 +0000994 (void) FormatLocaleString(link_path,MagickPathExtent,"/proc/%.20g/exe",
cristye8c25f92010-06-03 00:53:06 +0000995 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +0000996 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +0000997 if (count == -1)
998 {
cristy151b66d2015-04-15 10:50:31 +0000999 (void) FormatLocaleString(link_path,MagickPathExtent,"/proc/%.20g/file",
cristye8c25f92010-06-03 00:53:06 +00001000 (double) getpid());
cristyfa09d142009-10-15 01:02:25 +00001001 count=readlink(link_path,execution_path,PATH_MAX);
cristy3ed852e2009-09-05 21:47:34 +00001002 }
1003 if ((count > 0) && (count <= (ssize_t) PATH_MAX))
1004 {
cristyfa09d142009-10-15 01:02:25 +00001005 execution_path[count]='\0';
1006 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +00001007 }
1008 }
1009#endif
1010#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
1011 {
1012 char
1013 executable_path[PATH_MAX << 1],
cristyfa09d142009-10-15 01:02:25 +00001014 execution_path[PATH_MAX+1];
cristy3ed852e2009-09-05 21:47:34 +00001015
1016 uint32_t
1017 length;
1018
1019 length=sizeof(executable_path);
1020 if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
cristyfa09d142009-10-15 01:02:25 +00001021 (realpath(executable_path,execution_path) != (char *) NULL))
1022 (void) CopyMagickString(path,execution_path,extent);
cristy3ed852e2009-09-05 21:47:34 +00001023 }
1024#endif
1025#if defined(MAGICKCORE_HAVE_GETEXECNAME)
1026 {
1027 const char
1028 *execution_path;
1029
1030 execution_path=(const char *) getexecname();
1031 if (execution_path != (const char *) NULL)
1032 {
1033 if (*execution_path != *DirectorySeparator)
1034 (void) ConcatenateMagickString(path,DirectorySeparator,extent);
1035 (void) ConcatenateMagickString(path,execution_path,extent);
1036 }
1037 }
1038#endif
cristy0157aea2010-04-24 21:12:18 +00001039#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001040 NTGetExecutionPath(path,extent);
1041#endif
cristyfa09d142009-10-15 01:02:25 +00001042#if defined(__GNU__)
1043 {
1044 char
1045 *program_name,
1046 *execution_path;
1047
cristybb503372010-05-27 20:51:26 +00001048 ssize_t
cristyfa09d142009-10-15 01:02:25 +00001049 count;
1050
1051 count=0;
1052 execution_path=(char *) NULL;
1053 program_name=program_invocation_name;
1054 if (*program_invocation_name != '/')
1055 {
1056 size_t
1057 extent;
1058
cristyb29bea52011-05-26 17:54:31 +00001059 extent=strlen(directory)+strlen(program_name)+2;
cristyfa09d142009-10-15 01:02:25 +00001060 program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1061 if (program_name == (char *) NULL)
1062 program_name=program_invocation_name;
1063 else
cristyb29bea52011-05-26 17:54:31 +00001064 count=FormatLocaleString(program_name,extent,"%s/%s",directory,
cristyfa09d142009-10-15 01:02:25 +00001065 program_invocation_name);
1066 }
1067 if (count != -1)
1068 {
1069 execution_path=realpath(program_name,NULL);
1070 if (execution_path != (char *) NULL)
1071 (void) CopyMagickString(path,execution_path,extent);
1072 }
1073 if (program_name != program_invocation_name)
1074 program_name=(char *) RelinquishMagickMemory(program_name);
1075 execution_path=(char *) RelinquishMagickMemory(execution_path);
1076 }
1077#endif
cristy8a7ca3c2013-05-18 21:37:53 +00001078#if defined(__OpenBSD__)
1079 {
1080 extern char
1081 *__progname;
1082
1083 (void) CopyMagickString(path,__progname,extent);
1084 }
1085#endif
cristy3ed852e2009-09-05 21:47:34 +00001086 return(IsPathAccessible(path));
1087}
1088
1089/*
1090%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091% %
1092% %
1093% %
cristy688f07b2009-09-27 15:19:13 +00001094% G e t M a g i c k P a g e S i z e %
1095% %
1096% %
1097% %
1098%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099%
1100% GetMagickPageSize() returns the memory page size.
1101%
1102% The format of the GetMagickPageSize method is:
1103%
cristybb503372010-05-27 20:51:26 +00001104% ssize_t GetMagickPageSize()
cristy688f07b2009-09-27 15:19:13 +00001105%
1106*/
cristyd1dd6e42011-09-04 01:46:08 +00001107MagickPrivate ssize_t GetMagickPageSize(void)
cristy688f07b2009-09-27 15:19:13 +00001108{
cristybb503372010-05-27 20:51:26 +00001109 static ssize_t
cristy688f07b2009-09-27 15:19:13 +00001110 page_size = -1;
1111
1112 if (page_size > 0)
1113 return(page_size);
1114#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
cristyecd0ab52010-05-30 14:59:20 +00001115 page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
cristy09449f72010-01-23 03:08:36 +00001116#else
cristy688f07b2009-09-27 15:19:13 +00001117#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
cristyecd0ab52010-05-30 14:59:20 +00001118 page_size=(ssize_t) getpagesize();
cristy09449f72010-01-23 03:08:36 +00001119#endif
cristy688f07b2009-09-27 15:19:13 +00001120#endif
1121 if (page_size <= 0)
1122 page_size=16384;
1123 return(page_size);
1124}
1125
1126/*
1127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128% %
1129% %
1130% %
cristy3ed852e2009-09-05 21:47:34 +00001131% G e t P a t h A t t r i b u t e s %
1132% %
1133% %
1134% %
1135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136%
1137% GetPathAttributes() returns attributes (e.g. size of file) about a path.
1138%
1139% The path of the GetPathAttributes method is:
1140%
cristy21ef17b2015-02-09 22:59:26 +00001141% MagickBooleanType GetPathAttributes(const char *path,void *attributes)
cristy3ed852e2009-09-05 21:47:34 +00001142%
1143% A description of each parameter follows.
1144%
1145% o path: the file path.
1146%
1147% o attributes: the path attributes are returned here.
1148%
1149*/
cristy3ed852e2009-09-05 21:47:34 +00001150MagickExport MagickBooleanType GetPathAttributes(const char *path,
cristy21ef17b2015-02-09 22:59:26 +00001151 void *attributes)
cristy3ed852e2009-09-05 21:47:34 +00001152{
cristy21ef17b2015-02-09 22:59:26 +00001153 MagickBooleanType
1154 status;
1155
cristy3ed852e2009-09-05 21:47:34 +00001156 if (path == (const char *) NULL)
cristy21ef17b2015-02-09 22:59:26 +00001157 {
cristy3ed852e2009-09-05 21:47:34 +00001158 errno=EINVAL;
1159 return(MagickFalse);
1160 }
dirk9eecfbd2015-02-14 15:54:06 +00001161 (void) ResetMagickMemory(attributes,0,sizeof(struct stat));
cristy21ef17b2015-02-09 22:59:26 +00001162 status=stat_utf8(path,(struct stat *) attributes) == 0 ? MagickTrue :
1163 MagickFalse;
1164 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001165}
1166
1167/*
1168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169% %
1170% %
1171% %
1172% G e t P a t h C o m p o n e n t %
1173% %
1174% %
1175% %
1176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1177%
1178% GetPathComponent() returns the parent directory name, filename, basename, or
1179% extension of a file path.
1180%
cristy151b66d2015-04-15 10:50:31 +00001181% The component string pointed to must have at least MagickPathExtent space
anthony104f8932012-05-13 01:54:53 +00001182% for the results to be stored.
1183%
cristy3ed852e2009-09-05 21:47:34 +00001184% The format of the GetPathComponent function is:
1185%
1186% GetPathComponent(const char *path,PathType type,char *component)
1187%
1188% A description of each parameter follows:
1189%
1190% o path: Specifies a pointer to a character array that contains the
1191% file path.
1192%
1193% o type: Specififies which file path component to return.
1194%
1195% o component: the selected file path component is returned here.
1196%
1197*/
1198MagickExport void GetPathComponent(const char *path,PathType type,
1199 char *component)
1200{
1201 char
dirkf8aac352015-04-16 21:07:42 +00001202 *q;
cristy3ed852e2009-09-05 21:47:34 +00001203
1204 register char
1205 *p;
1206
dirkf8aac352015-04-16 21:07:42 +00001207 size_t
1208 magick_length,
1209 subimage_offset,
1210 subimage_length;
1211
cristy3ed852e2009-09-05 21:47:34 +00001212 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 }
cristy151b66d2015-04-15 10:50:31 +00001220 (void) CopyMagickString(component,path,MagickPathExtent);
dirkf8aac352015-04-16 21:07:42 +00001221 magick_length=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 */
dirkf8aac352015-04-16 21:07:42 +00001242 *p='\0';
1243 if (IsMagickConflict(component) != MagickFalse)
1244 *p=':';
cristy1224a992011-10-12 19:23:41 +00001245 else
dirkf8aac352015-04-16 21:07:42 +00001246 {
1247 magick_length=(size_t) (p-component+1);
1248 for (q=component; *(++p) != '\0'; q++)
1249 *q=*p;
1250 *q='\0';
1251 }
cristy1224a992011-10-12 19:23:41 +00001252 break;
1253 }
1254 }
dirkf8aac352015-04-16 21:07:42 +00001255 subimage_length=0;
1256 subimage_offset=0;
cristy86057c42011-08-03 18:12:58 +00001257 p=component;
1258 if (*p != '\0')
1259 p=component+strlen(component)-1;
1260 if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1261 (IsPathAccessible(path) == MagickFalse))
1262 {
1263 /*
1264 Look for scene specification (e.g. img0001.pcd[4]).
1265 */
1266 for (q=p-1; q > component; q--)
1267 if (*q == '[')
1268 break;
1269 if (*q == '[')
1270 {
dirkf8aac352015-04-16 21:07:42 +00001271 *p='\0';
1272 if ((IsSceneGeometry(q+1,MagickFalse) == MagickFalse) &&
1273 (IsGeometry(q+1) == MagickFalse))
1274 *p=']';
cristy1224a992011-10-12 19:23:41 +00001275 else
dirkf8aac352015-04-16 21:07:42 +00001276 {
1277 subimage_length=(size_t) (p-q);
1278 subimage_offset=magick_length+1+(size_t) (q-component);
1279 *q='\0';
1280 }
cristy86057c42011-08-03 18:12:58 +00001281 }
1282 }
cristy3ed852e2009-09-05 21:47:34 +00001283 p=component;
1284 if (*p != '\0')
1285 for (p=component+strlen(component)-1; p > component; p--)
1286 if (IsBasenameSeparator(*p) != MagickFalse)
1287 break;
1288 switch (type)
1289 {
1290 case MagickPath:
1291 {
dirkf8aac352015-04-16 21:07:42 +00001292 if (magick_length != 0)
1293 (void) CopyMagickString(component,path,magick_length);
1294 else
1295 *component = '\0';
cristy3ed852e2009-09-05 21:47:34 +00001296 break;
1297 }
1298 case RootPath:
1299 {
1300 for (p=component+(strlen(component)-1); p > component; p--)
1301 {
1302 if (IsBasenameSeparator(*p) != MagickFalse)
1303 break;
1304 if (*p == '.')
1305 break;
1306 }
1307 if (*p == '.')
1308 *p='\0';
1309 break;
1310 }
1311 case HeadPath:
1312 {
1313 *p='\0';
1314 break;
1315 }
1316 case TailPath:
1317 {
1318 if (IsBasenameSeparator(*p) != MagickFalse)
1319 (void) CopyMagickMemory((unsigned char *) component,
1320 (const unsigned char *) (p+1),strlen(p+1)+1);
1321 break;
1322 }
1323 case BasePath:
1324 {
1325 if (IsBasenameSeparator(*p) != MagickFalse)
cristy151b66d2015-04-15 10:50:31 +00001326 (void) CopyMagickString(component,p+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001327 for (p=component+(strlen(component)-1); p > component; p--)
1328 if (*p == '.')
1329 {
1330 *p='\0';
1331 break;
1332 }
1333 break;
1334 }
1335 case ExtensionPath:
1336 {
1337 if (IsBasenameSeparator(*p) != MagickFalse)
cristy151b66d2015-04-15 10:50:31 +00001338 (void) CopyMagickString(component,p+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001339 p=component;
1340 if (*p != '\0')
1341 for (p=component+strlen(component)-1; p > component; p--)
1342 if (*p == '.')
1343 break;
1344 *component='\0';
1345 if (*p == '.')
cristy151b66d2015-04-15 10:50:31 +00001346 (void) CopyMagickString(component,p+1,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001347 break;
1348 }
1349 case SubimagePath:
1350 {
dirkf8aac352015-04-16 21:07:42 +00001351 if (subimage_length != 0)
1352 (void) CopyMagickString(component,path+subimage_offset,subimage_length);
1353 else
1354 *component = '\0';
cristy3ed852e2009-09-05 21:47:34 +00001355 break;
1356 }
1357 case CanonicalPath:
1358 case UndefinedPath:
1359 break;
1360 }
1361}
1362
1363/*
1364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365% %
1366% %
1367% %
1368% G e t P a t h C o m p o n e n t s %
1369% %
1370% %
1371% %
1372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373%
1374% GetPathComponents() returns a list of path components.
1375%
1376% The format of the GetPathComponents method is:
1377%
1378% char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001379% size_t *number_componenets)
cristy3ed852e2009-09-05 21:47:34 +00001380%
1381% A description of each parameter follows:
1382%
1383% o path: Specifies the string to segment into a list.
1384%
1385% o number_components: return the number of components in the list
1386%
1387*/
cristyd1dd6e42011-09-04 01:46:08 +00001388MagickPrivate char **GetPathComponents(const char *path,
cristybb503372010-05-27 20:51:26 +00001389 size_t *number_components)
cristy3ed852e2009-09-05 21:47:34 +00001390{
1391 char
1392 **components;
1393
1394 register const char
1395 *p,
1396 *q;
1397
cristybb503372010-05-27 20:51:26 +00001398 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001399 i;
1400
1401 if (path == (char *) NULL)
1402 return((char **) NULL);
1403 *number_components=1;
1404 for (p=path; *p != '\0'; p++)
1405 if (IsBasenameSeparator(*p))
1406 (*number_components)++;
1407 components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1408 sizeof(*components));
1409 if (components == (char **) NULL)
1410 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1411 p=path;
cristybb503372010-05-27 20:51:26 +00001412 for (i=0; i < (ssize_t) *number_components; i++)
cristy3ed852e2009-09-05 21:47:34 +00001413 {
1414 for (q=p; *q != '\0'; q++)
1415 if (IsBasenameSeparator(*q))
1416 break;
cristy151b66d2015-04-15 10:50:31 +00001417 components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
cristyc92c1e12011-03-25 15:47:59 +00001418 sizeof(**components));
cristy3ed852e2009-09-05 21:47:34 +00001419 if (components[i] == (char *) NULL)
1420 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1421 (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1422 p=q+1;
1423 }
1424 components[i]=(char *) NULL;
1425 return(components);
1426}
1427
1428/*
1429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430% %
1431% %
1432% %
1433% I s P a t h A c c e s s i b l e %
1434% %
1435% %
1436% %
1437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1438%
1439% IsPathAccessible() returns MagickTrue if the file as defined by the path is
1440% accessible.
1441%
1442% The format of the IsPathAccessible method is:
1443%
cristy59864562013-04-18 11:47:41 +00001444% MagickBooleanType IsPathAccessible(const char *path)
cristy3ed852e2009-09-05 21:47:34 +00001445%
1446% A description of each parameter follows.
1447%
1448% o path: Specifies a path to a file.
1449%
1450*/
1451MagickExport MagickBooleanType IsPathAccessible(const char *path)
1452{
1453 MagickBooleanType
1454 status;
1455
1456 struct stat
1457 attributes;
1458
1459 if ((path == (const char *) NULL) || (*path == '\0'))
1460 return(MagickFalse);
1461 status=GetPathAttributes(path,&attributes);
1462 if (status == MagickFalse)
1463 return(status);
1464 if (S_ISREG(attributes.st_mode) == 0)
1465 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +00001466 if (access_utf8(path,F_OK) != 0)
cristy3ed852e2009-09-05 21:47:34 +00001467 return(MagickFalse);
1468 return(MagickTrue);
1469}
1470
1471/*
1472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1473% %
1474% %
1475% %
1476+ I s P a t h D i r e c t o r y %
1477% %
1478% %
1479% %
1480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481%
1482% IsPathDirectory() returns -1 if the directory does not exist, 1 is returned
1483% if the path represents a directory otherwise 0.
1484%
1485% The format of the IsPathDirectory method is:
1486%
1487% int IsPathDirectory(const char *path)
1488%
1489% A description of each parameter follows.
1490%
1491% o path: The directory path.
1492%
1493*/
1494static int IsPathDirectory(const char *path)
1495{
1496 MagickBooleanType
1497 status;
1498
1499 struct stat
1500 attributes;
1501
1502 if ((path == (const char *) NULL) || (*path == '\0'))
1503 return(MagickFalse);
1504 status=GetPathAttributes(path,&attributes);
1505 if (status == MagickFalse)
1506 return(-1);
1507 if (S_ISDIR(attributes.st_mode) == 0)
1508 return(0);
1509 return(1);
1510}
1511
1512/*
1513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1514% %
1515% %
1516% %
cristy3ed852e2009-09-05 21:47:34 +00001517% L i s t F i l e s %
1518% %
1519% %
1520% %
1521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522%
1523% ListFiles() reads the directory specified and returns a list of filenames
1524% contained in the directory sorted in ascending alphabetic order.
1525%
1526% The format of the ListFiles function is:
1527%
1528% char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001529% ssize_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001530%
1531% A description of each parameter follows:
1532%
1533% o filelist: Method ListFiles returns a list of filenames contained
1534% in the directory. If the directory specified cannot be read or it is
1535% a file a NULL list is returned.
1536%
1537% o directory: Specifies a pointer to a text string containing a directory
1538% name.
1539%
1540% o pattern: Specifies a pointer to a text string containing a pattern.
1541%
1542% o number_entries: This integer returns the number of filenames in the
1543% list.
1544%
1545*/
1546
1547#if defined(__cplusplus) || defined(c_plusplus)
1548extern "C" {
1549#endif
1550
1551static int FileCompare(const void *x,const void *y)
1552{
1553 register const char
1554 **p,
1555 **q;
1556
1557 p=(const char **) x;
1558 q=(const char **) y;
1559 return(LocaleCompare(*p,*q));
1560}
1561
1562#if defined(__cplusplus) || defined(c_plusplus)
1563}
1564#endif
1565
1566static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1567 struct dirent **result)
1568{
1569#if defined(MAGICKCORE_HAVE_READDIR_R)
1570 return(readdir_r(directory,entry,result));
1571#else
1572 (void) entry;
1573 errno=0;
1574 *result=readdir(directory);
1575 return(errno);
1576#endif
1577}
1578
cristyd1dd6e42011-09-04 01:46:08 +00001579MagickPrivate char **ListFiles(const char *directory,const char *pattern,
cristybb503372010-05-27 20:51:26 +00001580 size_t *number_entries)
cristy3ed852e2009-09-05 21:47:34 +00001581{
1582 char
1583 **filelist;
1584
1585 DIR
1586 *current_directory;
1587
1588 struct dirent
1589 *buffer,
1590 *entry;
1591
cristybb503372010-05-27 20:51:26 +00001592 size_t
cristy3ed852e2009-09-05 21:47:34 +00001593 max_entries;
1594
1595 /*
1596 Open directory.
1597 */
1598 assert(directory != (const char *) NULL);
1599 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1600 assert(pattern != (const char *) NULL);
cristybb503372010-05-27 20:51:26 +00001601 assert(number_entries != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001602 *number_entries=0;
1603 current_directory=opendir(directory);
1604 if (current_directory == (DIR *) NULL)
1605 return((char **) NULL);
1606 /*
1607 Allocate filelist.
1608 */
1609 max_entries=2048;
1610 filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1611 sizeof(*filelist));
1612 if (filelist == (char **) NULL)
1613 {
1614 (void) closedir(current_directory);
1615 return((char **) NULL);
1616 }
1617 /*
1618 Save the current and change to the new directory.
1619 */
cristy6e6c8222014-10-18 00:19:27 +00001620 buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+FILENAME_MAX+1);
cristy3ed852e2009-09-05 21:47:34 +00001621 if (buffer == (struct dirent *) NULL)
1622 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1623 while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
1624 (entry != (struct dirent *) NULL))
1625 {
1626 if (*entry->d_name == '.')
1627 continue;
1628 if ((IsPathDirectory(entry->d_name) > 0) ||
cristy0157aea2010-04-24 21:12:18 +00001629#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001630 (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
1631#else
1632 (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
1633#endif
1634 {
1635 if (*number_entries >= max_entries)
1636 {
1637 /*
1638 Extend the file list.
1639 */
1640 max_entries<<=1;
1641 filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
1642 max_entries,sizeof(*filelist));
1643 if (filelist == (char **) NULL)
1644 break;
1645 }
1646#if defined(vms)
1647 {
1648 register char
1649 *p;
1650
1651 p=strchr(entry->d_name,';');
1652 if (p)
1653 *p='\0';
1654 if (*number_entries > 0)
1655 if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
1656 continue;
1657 }
1658#endif
1659 filelist[*number_entries]=(char *) AcquireString(entry->d_name);
cristy3ed852e2009-09-05 21:47:34 +00001660 (*number_entries)++;
1661 }
1662 }
1663 buffer=(struct dirent *) RelinquishMagickMemory(buffer);
1664 (void) closedir(current_directory);
1665 if (filelist == (char **) NULL)
1666 return((char **) NULL);
1667 /*
1668 Sort filelist in ascending order.
1669 */
1670 qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
1671 FileCompare);
1672 return(filelist);
1673}
1674
1675/*
1676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677% %
1678% %
1679% %
cristya21afde2010-07-02 00:45:40 +00001680% M a g i c k D e l a y %
1681% %
1682% %
1683% %
1684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685%
1686% MagickDelay() suspends program execution for the number of milliseconds
1687% specified.
1688%
1689% The format of the Delay method is:
1690%
1691% void MagickDelay(const MagickSizeType milliseconds)
1692%
1693% A description of each parameter follows:
1694%
1695% o milliseconds: Specifies the number of milliseconds to delay before
1696% returning.
1697%
1698*/
cristyd1dd6e42011-09-04 01:46:08 +00001699MagickPrivate void MagickDelay(const MagickSizeType milliseconds)
cristya21afde2010-07-02 00:45:40 +00001700{
1701 if (milliseconds == 0)
1702 return;
1703#if defined(MAGICKCORE_HAVE_NANOSLEEP)
1704 {
1705 struct timespec
1706 timer;
1707
1708 timer.tv_sec=(time_t) (milliseconds/1000);
1709 timer.tv_nsec=(milliseconds % 1000)*1000*1000;
1710 (void) nanosleep(&timer,(struct timespec *) NULL);
1711 }
1712#elif defined(MAGICKCORE_HAVE_USLEEP)
1713 usleep(1000*milliseconds);
1714#elif defined(MAGICKCORE_HAVE_SELECT)
1715 {
1716 struct timeval
1717 timer;
1718
1719 timer.tv_sec=(long) milliseconds/1000;
1720 timer.tv_usec=(long) (milliseconds % 1000)*1000;
1721 (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
1722 }
1723#elif defined(MAGICKCORE_HAVE_POLL)
1724 (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
1725#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1726 Sleep((long) milliseconds);
1727#elif defined(vms)
1728 {
1729 float
1730 timer;
1731
1732 timer=milliseconds/1000.0;
1733 lib$wait(&timer);
1734 }
1735#elif defined(__BEOS__)
1736 snooze(1000*milliseconds);
1737#else
1738# error "Time delay method not defined."
1739#endif
1740}
1741
1742/*
1743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744% %
1745% %
1746% %
cristy3ed852e2009-09-05 21:47:34 +00001747% M u l t i l i n e C e n s u s %
1748% %
1749% %
1750% %
1751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1752%
1753% MultilineCensus() returns the number of lines within a label. A line is
1754% represented by a \n character.
1755%
1756% The format of the MultilineCenus method is:
1757%
cristybb503372010-05-27 20:51:26 +00001758% size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001759%
1760% A description of each parameter follows.
1761%
1762% o label: This character string is the label.
1763%
cristy3ed852e2009-09-05 21:47:34 +00001764*/
cristybb503372010-05-27 20:51:26 +00001765MagickExport size_t MultilineCensus(const char *label)
cristy3ed852e2009-09-05 21:47:34 +00001766{
cristybb503372010-05-27 20:51:26 +00001767 size_t
cristy3ed852e2009-09-05 21:47:34 +00001768 number_lines;
1769
1770 /*
1771 Determine the number of lines within this label.
1772 */
1773 if (label == (char *) NULL)
1774 return(0);
1775 for (number_lines=1; *label != '\0'; label++)
1776 if (*label == '\n')
1777 number_lines++;
1778 return(number_lines);
1779}
1780
1781/*
1782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783% %
1784% %
1785% %
dirk7fb986b2015-02-12 22:33:15 +00001786% S h r e d F i l e %
cristy59864562013-04-18 11:47:41 +00001787% %
1788% %
1789% %
1790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1791%
cristy403ae7b2013-04-18 12:49:11 +00001792% ShredFile() overwrites the specified file with zeros or random data and then
1793% removes it. The overwrite is optional and is only required to help keep
cristy3c91e2d2013-04-18 12:55:47 +00001794% the contents of the file private. On the first pass, the file is zeroed.
1795% For subsequent passes, random data is written.
cristy59864562013-04-18 11:47:41 +00001796%
1797% The format of the ShredFile method is:
1798%
1799% MagickBooleanType ShredFile(const char *path)
1800%
1801% A description of each parameter follows.
1802%
1803% o path: Specifies a path to a file.
1804%
1805*/
1806MagickPrivate MagickBooleanType ShredFile(const char *path)
1807{
cristy403ae7b2013-04-18 12:49:11 +00001808 char
cristy3c91e2d2013-04-18 12:55:47 +00001809 *passes;
cristy403ae7b2013-04-18 12:49:11 +00001810
cristy59864562013-04-18 11:47:41 +00001811 int
cristy403ae7b2013-04-18 12:49:11 +00001812 file,
cristy59864562013-04-18 11:47:41 +00001813 status;
1814
cristy403ae7b2013-04-18 12:49:11 +00001815 MagickSizeType
1816 length;
1817
1818 register ssize_t
1819 i;
1820
1821 size_t
1822 quantum;
1823
1824 struct stat
1825 file_stats;
1826
cristy59864562013-04-18 11:47:41 +00001827 if ((path == (const char *) NULL) || (*path == '\0'))
1828 return(MagickFalse);
cristy8a23f662014-03-26 20:58:19 +00001829 passes=GetEnvironmentValue("MAGICK_SHRED_PASSES");
cristy3c91e2d2013-04-18 12:55:47 +00001830 if (passes == (char *) NULL)
cristy403ae7b2013-04-18 12:49:11 +00001831 {
1832 /*
1833 Don't shred the file, just remove it.
1834 */
1835 status=remove_utf8(path);
1836 if (status == -1)
dirk7fb986b2015-02-12 22:33:15 +00001837 {
1838 (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
1839 "Failed to remove: %s",path);
1840 return(MagickFalse);
1841 }
cristy403ae7b2013-04-18 12:49:11 +00001842 return(MagickTrue);
1843 }
1844 file=open_utf8(path,O_WRONLY | O_EXCL | O_BINARY,S_MODE);
1845 if (file == -1)
cristyd2ce3602013-04-18 19:30:20 +00001846 {
1847 /*
1848 Don't shred the file, just remove it.
1849 */
1850 status=remove_utf8(path);
dirk7fb986b2015-02-12 22:33:15 +00001851 if (status == -1)
1852 (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
1853 "Failed to remove: %s",path);
cristyd2ce3602013-04-18 19:30:20 +00001854 return(MagickFalse);
1855 }
cristy403ae7b2013-04-18 12:49:11 +00001856 /*
1857 Shred the file.
1858 */
1859 quantum=(size_t) MagickMaxBufferExtent;
cristyf201ba62015-07-05 13:54:28 +00001860 if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1861 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
cristy403ae7b2013-04-18 12:49:11 +00001862 length=(MagickSizeType) file_stats.st_size;
cristy94cc10e2013-04-18 19:17:04 +00001863 for (i=0; i < (ssize_t) StringToInteger(passes); i++)
cristy403ae7b2013-04-18 12:49:11 +00001864 {
1865 RandomInfo
1866 *random_info;
1867
cristy6e31dc72013-04-18 19:22:03 +00001868 register MagickOffsetType
cristy403ae7b2013-04-18 12:49:11 +00001869 j;
1870
1871 ssize_t
1872 count;
1873
1874 if (lseek(file,0,SEEK_SET) < 0)
1875 break;
1876 random_info=AcquireRandomInfo();
cristy6e31dc72013-04-18 19:22:03 +00001877 for (j=0; j < (MagickOffsetType) length; j+=count)
cristy403ae7b2013-04-18 12:49:11 +00001878 {
1879 StringInfo
1880 *key;
1881
1882 key=GetRandomKey(random_info,quantum);
cristy689d9852013-04-18 19:19:01 +00001883 if (i == 0)
cristy403ae7b2013-04-18 12:49:11 +00001884 ResetStringInfo(key); /* zero on first pass */
1885 count=write(file,GetStringInfoDatum(key),(size_t)
1886 MagickMin(quantum,length-j));
1887 key=DestroyStringInfo(key);
1888 if (count <= 0)
1889 {
1890 count=0;
1891 if (errno != EINTR)
1892 break;
1893 }
1894 }
1895 random_info=DestroyRandomInfo(random_info);
cristy2a927fa2013-04-18 19:34:02 +00001896 if (j < (MagickOffsetType) length)
cristy403ae7b2013-04-18 12:49:11 +00001897 break;
1898 }
1899 status=close(file);
cristy59864562013-04-18 11:47:41 +00001900 status=remove_utf8(path);
1901 if (status == -1)
1902 return(MagickFalse);
cristyd2ce3602013-04-18 19:30:20 +00001903 return(i < (ssize_t) StringToInteger(passes) ? MagickFalse : MagickTrue);
cristy59864562013-04-18 11:47:41 +00001904}