]> git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/gfile.cxx
Merge changes from 1.1.x into 1.2 devel.
[thirdparty/cups.git] / pdftops / gfile.cxx
1 //========================================================================
2 //
3 // gfile.cc
4 //
5 // Miscellaneous file and directory name manipulation.
6 //
7 // Copyright 1996 Derek B. Noonburg
8 //
9 //========================================================================
10
11 #ifdef WIN32
12 extern "C" {
13 # ifndef _MSC_VER
14 # include <kpathsea/win32lib.h>
15 # endif
16 }
17 #else // !WIN32
18 # if defined(MACOS)
19 # include <sys/stat.h>
20 # elif !defined(ACORN)
21 # include <sys/types.h>
22 # include <sys/stat.h>
23 # include <fcntl.h>
24 # endif
25 # include <limits.h>
26 # include <string.h>
27 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
28 # include <pwd.h>
29 # endif
30 # if defined(VMS) && (__DECCXX_VER < 50200000)
31 # include <unixlib.h>
32 # endif
33 #endif // WIN32
34 #include "GString.h"
35 #include "gfile.h"
36
37 #ifdef HAVE_LIBCUPS
38 # include <cups/cups.h>
39 #endif // HAVE_LIBCUPS
40
41 #ifdef __sun
42 // Solaris doesn't define mkstemp()...
43 extern "C" {
44 extern int mkstemp(char *);
45 }
46 #endif // __sun
47
48 // Some systems don't define this, so just make it something reasonably
49 // large.
50 #ifndef PATH_MAX
51 #define PATH_MAX 1024
52 #endif
53
54 //------------------------------------------------------------------------
55
56 GString *getHomeDir() {
57 #ifdef VMS
58 //---------- VMS ----------
59 return new GString("SYS$LOGIN:");
60
61 #elif defined(__EMX__) || defined(WIN32)
62 //---------- OS/2+EMX and Win32 ----------
63 char *s;
64 GString *ret;
65
66 if ((s = getenv("HOME")))
67 ret = new GString(s);
68 else
69 ret = new GString(".");
70 return ret;
71
72 #elif defined(ACORN)
73 //---------- RISCOS ----------
74 return new GString("@");
75
76 #elif defined(MACOS)
77 //---------- MacOS ----------
78 return new GString(":");
79
80 #else
81 //---------- Unix ----------
82 char *s;
83 struct passwd *pw;
84 GString *ret;
85
86 if ((s = getenv("HOME"))) {
87 ret = new GString(s);
88 # ifdef HAVE_LIBCUPS
89 } else if ((s = getenv("CUPS_SERVERROOT"))) {
90 ret = new GString(s);
91 # endif // HAVE_LIBCUPS
92 } else {
93 if ((s = getenv("USER")))
94 pw = getpwnam(s);
95 else
96 pw = getpwuid(getuid());
97 if (pw)
98 ret = new GString(pw->pw_dir);
99 else
100 ret = new GString(".");
101 }
102 return ret;
103 #endif
104 }
105
106 GString *getCurrentDir() {
107 char buf[PATH_MAX+1];
108
109 #if defined(__EMX__)
110 if (_getcwd2(buf, sizeof(buf)))
111 #elif defined(WIN32)
112 if (GetCurrentDirectory(sizeof(buf), buf))
113 #elif defined(ACORN)
114 if (strcpy(buf, "@"))
115 #elif defined(MACOS)
116 if (strcpy(buf, ":"))
117 #else
118 if (getcwd(buf, sizeof(buf)))
119 #endif
120 return new GString(buf);
121 return new GString();
122 }
123
124 GString *appendToPath(GString *path, const char *fileName) {
125 #if defined(VMS)
126 //---------- VMS ----------
127 //~ this should handle everything necessary for file
128 //~ requesters, but it's certainly not complete
129 char *p0, *p1, *p2;
130 char *q1;
131
132 p0 = path->getCString();
133 p1 = p0 + path->getLength() - 1;
134 if (!strcmp(fileName, "-")) {
135 if (*p1 == ']') {
136 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
137 if (*p2 == '[')
138 ++p2;
139 path->del(p2 - p0, p1 - p2);
140 } else if (*p1 == ':') {
141 path->append("[-]");
142 } else {
143 path->clear();
144 path->append("[-]");
145 }
146 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
147 if (*p1 == ']') {
148 path->insert(p1 - p0, '.');
149 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
150 } else if (*p1 == ':') {
151 path->append('[');
152 path->append(']');
153 path->append(fileName, q1 - fileName);
154 } else {
155 path->clear();
156 path->append(fileName, q1 - fileName);
157 }
158 } else {
159 if (*p1 != ']' && *p1 != ':')
160 path->clear();
161 path->append(fileName);
162 }
163 return path;
164
165 #elif defined(WIN32)
166 //---------- Win32 ----------
167 GString *tmp;
168 char buf[256];
169 char *fp;
170
171 tmp = new GString(path);
172 tmp->append('/');
173 tmp->append(fileName);
174 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
175 delete tmp;
176 path->clear();
177 path->append(buf);
178 return path;
179
180 #elif defined(ACORN)
181 //---------- RISCOS ----------
182 char *p;
183 int i;
184
185 path->append(".");
186 i = path->getLength();
187 path->append(fileName);
188 for (p = path->getCString() + i; *p; ++p) {
189 if (*p == '/') {
190 *p = '.';
191 } else if (*p == '.') {
192 *p = '/';
193 }
194 }
195 return path;
196
197 #elif defined(MACOS)
198 //---------- MacOS ----------
199 char *p;
200 int i;
201
202 path->append(":");
203 i = path->getLength();
204 path->append(fileName);
205 for (p = path->getCString() + i; *p; ++p) {
206 if (*p == '/') {
207 *p = ':';
208 } else if (*p == '.') {
209 *p = ':';
210 }
211 }
212 return path;
213
214 #elif defined(__EMX__)
215 //---------- OS/2+EMX ----------
216 int i;
217
218 // appending "." does nothing
219 if (!strcmp(fileName, "."))
220 return path;
221
222 // appending ".." goes up one directory
223 if (!strcmp(fileName, "..")) {
224 for (i = path->getLength() - 2; i >= 0; --i) {
225 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
226 path->getChar(i) == ':')
227 break;
228 }
229 if (i <= 0) {
230 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
231 path->del(1, path->getLength() - 1);
232 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
233 path->del(2, path->getLength() - 2);
234 } else {
235 path->clear();
236 path->append("..");
237 }
238 } else {
239 if (path->getChar(i-1) == ':')
240 ++i;
241 path->del(i, path->getLength() - i);
242 }
243 return path;
244 }
245
246 // otherwise, append "/" and new path component
247 if (path->getLength() > 0 &&
248 path->getChar(path->getLength() - 1) != '/' &&
249 path->getChar(path->getLength() - 1) != '\\')
250 path->append('/');
251 path->append(fileName);
252 return path;
253
254 #else
255 //---------- Unix ----------
256 int i;
257
258 // appending "." does nothing
259 if (!strcmp(fileName, "."))
260 return path;
261
262 // appending ".." goes up one directory
263 if (!strcmp(fileName, "..")) {
264 for (i = path->getLength() - 2; i >= 0; --i) {
265 if (path->getChar(i) == '/')
266 break;
267 }
268 if (i <= 0) {
269 if (path->getChar(0) == '/') {
270 path->del(1, path->getLength() - 1);
271 } else {
272 path->clear();
273 path->append("..");
274 }
275 } else {
276 path->del(i, path->getLength() - i);
277 }
278 return path;
279 }
280
281 // otherwise, append "/" and new path component
282 if (path->getLength() > 0 &&
283 path->getChar(path->getLength() - 1) != '/')
284 path->append('/');
285 path->append(fileName);
286 return path;
287 #endif
288 }
289
290 GString *grabPath(const char *fileName) {
291 #ifdef VMS
292 //---------- VMS ----------
293 const char *p;
294
295 if ((p = strrchr(fileName, ']')))
296 return new GString(fileName, p + 1 - fileName);
297 if ((p = strrchr(fileName, ':')))
298 return new GString(fileName, p + 1 - fileName);
299 return new GString();
300
301 #elif defined(__EMX__) || defined(WIN32)
302 //---------- OS/2+EMX and Win32 ----------
303 const char *p;
304
305 if ((p = strrchr(fileName, '/')))
306 return new GString(fileName, p - fileName);
307 if ((p = strrchr(fileName, '\\')))
308 return new GString(fileName, p - fileName);
309 if ((p = strrchr(fileName, ':')))
310 return new GString(fileName, p + 1 - fileName);
311 return new GString();
312
313 #elif defined(ACORN)
314 //---------- RISCOS ----------
315 const char *p;
316
317 if ((p = strrchr(fileName, '.')))
318 return new GString(fileName, p - fileName);
319 return new GString();
320
321 #elif defined(MACOS)
322 //---------- MacOS ----------
323 const char *p;
324
325 if ((p = strrchr(fileName, ':')))
326 return new GString(fileName, p - fileName);
327 return new GString();
328
329 #else
330 //---------- Unix ----------
331 const char *p;
332
333 if ((p = strrchr(fileName, '/')))
334 return new GString(fileName, p - fileName);
335 return new GString();
336 #endif
337 }
338
339 GBool isAbsolutePath(const char *path) {
340 #ifdef VMS
341 //---------- VMS ----------
342 return strchr(path, ':') ||
343 (path[0] == '[' && path[1] != '.' && path[1] != '-');
344
345 #elif defined(__EMX__) || defined(WIN32)
346 //---------- OS/2+EMX and Win32 ----------
347 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
348
349 #elif defined(ACORN)
350 //---------- RISCOS ----------
351 return path[0] == '$';
352
353 #elif defined(MACOS)
354 //---------- MacOS ----------
355 return path[0] != ':';
356
357 #else
358 //---------- Unix ----------
359 return path[0] == '/';
360 #endif
361 }
362
363 GString *makePathAbsolute(GString *path) {
364 #ifdef VMS
365 //---------- VMS ----------
366 char buf[PATH_MAX+1];
367
368 if (!isAbsolutePath(path->getCString())) {
369 if (getcwd(buf, sizeof(buf))) {
370 path->insert(0, buf);
371 }
372 }
373 return path;
374
375 #elif defined(WIN32)
376 //---------- Win32 ----------
377 char buf[_MAX_PATH];
378 char *fp;
379
380 buf[0] = '\0';
381 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
382 path->clear();
383 return path;
384 }
385 path->clear();
386 path->append(buf);
387 return path;
388
389 #elif defined(ACORN)
390 //---------- RISCOS ----------
391 path->insert(0, '@');
392 return path;
393
394 #elif defined(MACOS)
395 //---------- MacOS ----------
396 path->del(0, 1);
397 return path;
398
399 #else
400 //---------- Unix and OS/2+EMX ----------
401 struct passwd *pw;
402 char buf[PATH_MAX+1];
403 GString *s;
404 char *p1, *p2;
405 int n;
406
407 if (path->getChar(0) == '~') {
408 if (path->getChar(1) == '/' ||
409 #ifdef __EMX__
410 path->getChar(1) == '\\' ||
411 #endif
412 path->getLength() == 1) {
413 path->del(0, 1);
414 s = getHomeDir();
415 path->insert(0, s);
416 delete s;
417 } else {
418 p1 = path->getCString() + 1;
419 #ifdef __EMX__
420 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
421 #else
422 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
423 #endif
424 if ((n = p2 - p1) > PATH_MAX)
425 n = PATH_MAX;
426 strncpy(buf, p1, n);
427 buf[n] = '\0';
428 if ((pw = getpwnam(buf))) {
429 path->del(0, p2 - p1 + 1);
430 path->insert(0, pw->pw_dir);
431 }
432 }
433 } else if (!isAbsolutePath(path->getCString())) {
434 if (getcwd(buf, sizeof(buf))) {
435 #ifndef __EMX__
436 path->insert(0, '/');
437 #endif
438 path->insert(0, buf);
439 }
440 }
441 return path;
442 #endif
443 }
444
445 time_t getModTime(const char *fileName) {
446 #ifdef WIN32
447 //~ should implement this, but it's (currently) only used in xpdf
448 return 0;
449 #else
450 struct stat statBuf;
451
452 if (stat(fileName, &statBuf)) {
453 return 0;
454 }
455 return statBuf.st_mtime;
456 #endif
457 }
458
459 GBool openTempFile(GString **name, FILE **f, const char *mode, const char *ext) {
460 #if defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
461 //---------- non-Unix ----------
462 char *s;
463
464 // There is a security hole here: an attacker can create a symlink
465 // with this file name after the tmpnam call and before the fopen
466 // call. I will happily accept fixes to this function for non-Unix
467 // OSs.
468 if (!(s = tmpnam(NULL))) {
469 return gFalse;
470 }
471 *name = new GString(s);
472 if (ext) {
473 (*name)->append(ext);
474 }
475 if (!(*f = fopen((*name)->getCString(), mode))) {
476 delete (*name);
477 return gFalse;
478 }
479 return gTrue;
480 #else
481 //---------- Unix ----------
482 char *s;
483 int fd;
484
485 // MRS: Currently there is no standard function for creating a temporary
486 // file with an extension; this is required when uncompressing
487 // LZW data using the uncompress program on some UNIX, which is
488 // looking for a ".Z" extension on the temporary filename. Sooo,
489 // when you print an *OLD* PDF file that uses LZW compression,
490 // the tmpnam() function is usually the one that is called to
491 // create the temporary file. Under *BSD, the safer mkstemps()
492 // function is used instead.
493 //
494 // That said, all CUPS filters are run with TMPDIR pointing to
495 // a private temporary directory, which by default is only
496 // accessible to the 'lp' user. Also, most files use Flate
497 // compression now and will be able to use the (safer)
498 // mkstemp() function for any temporary files...
499
500 if (ext) {
501 # if HAVE_MKSTEMPS
502 if ((s = getenv("TMPDIR"))) {
503 *name = new GString(s);
504 } else {
505 *name = new GString("/tmp");
506 }
507 (*name)->append("/XXXXXX");
508 (*name)->append(ext);
509 fd = mkstemps((*name)->getCString(), strlen(ext));
510 # else // HAVE_MKSTEMPS
511 char *p;
512 if (!(s = tmpnam(NULL))) {
513 return gFalse;
514 }
515 *name = new GString(s);
516 s = (*name)->getCString();
517 if ((p = strrchr(s, '.'))) {
518 (*name)->del(p - s, (*name)->getLength() - (p - s));
519 }
520 (*name)->append(ext);
521 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
522 # endif // HAVE_MKSTEMPS
523 } else {
524 # if HAVE_MKSTEMP
525 if ((s = getenv("TMPDIR"))) {
526 *name = new GString(s);
527 } else {
528 *name = new GString("/tmp");
529 }
530 (*name)->append("/XXXXXX");
531 fd = mkstemp((*name)->getCString());
532 # else // HAVE_MKSTEMP
533 if (!(s = tmpnam(NULL))) {
534 return gFalse;
535 }
536 *name = new GString(s);
537 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
538 # endif // HAVE_MKSTEMP
539 }
540 if (fd < 0 || !(*f = fdopen(fd, mode))) {
541 delete *name;
542 return gFalse;
543 }
544 return gTrue;
545 #endif
546 }
547
548 //------------------------------------------------------------------------
549 // GDir and GDirEntry
550 //------------------------------------------------------------------------
551
552 GDirEntry::GDirEntry(const char *dirPath, const char *name1, GBool doStat) {
553 #ifdef VMS
554 char *p;
555 #elif defined(WIN32)
556 int fa;
557 GString *s;
558 #elif defined(ACORN)
559 #else
560 struct stat st;
561 GString *s;
562 #endif
563
564 name = new GString(name1);
565 dir = gFalse;
566 if (doStat) {
567 #ifdef VMS
568 if (!strcmp(name1, "-") ||
569 ((p = strrchr(name1, '.')) && !strncmp(p, ".DIR;", 5)))
570 dir = gTrue;
571 #elif defined(ACORN)
572 #else
573 s = new GString(dirPath);
574 appendToPath(s, name1);
575 #ifdef WIN32
576 fa = GetFileAttributes(s->getCString());
577 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
578 #else
579 if (stat(s->getCString(), &st) == 0)
580 dir = S_ISDIR(st.st_mode);
581 #endif
582 delete s;
583 #endif
584 }
585 }
586
587 GDirEntry::~GDirEntry() {
588 delete name;
589 }
590
591 GDir::GDir(const char *name, GBool doStat1) {
592 path = new GString(name);
593 doStat = doStat1;
594 #if defined(WIN32)
595 GString *tmp;
596
597 tmp = path->copy();
598 tmp->append("/*.*");
599 hnd = FindFirstFile(tmp->getCString(), &ffd);
600 delete tmp;
601 #elif defined(ACORN)
602 #elif defined(MACOS)
603 #else
604 dir = opendir(name);
605 #ifdef VMS
606 needParent = strchr(name, '[') != NULL;
607 #endif
608 #endif
609 }
610
611 GDir::~GDir() {
612 delete path;
613 #if defined(WIN32)
614 if (hnd) {
615 FindClose(hnd);
616 hnd = NULL;
617 }
618 #elif defined(ACORN)
619 #elif defined(MACOS)
620 #else
621 if (dir)
622 closedir(dir);
623 #endif
624 }
625
626 GDirEntry *GDir::getNextEntry() {
627 struct dirent *ent;
628 GDirEntry *e;
629
630 e = NULL;
631 #if defined(WIN32)
632 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
633 if (hnd && !FindNextFile(hnd, &ffd)) {
634 FindClose(hnd);
635 hnd = NULL;
636 }
637 #elif defined(ACORN)
638 #elif defined(MACOS)
639 #else
640 if (dir) {
641 #ifdef VMS
642 if (needParent) {
643 e = new GDirEntry(path->getCString(), "-", doStat);
644 needParent = gFalse;
645 return e;
646 }
647 #endif
648 ent = readdir(dir);
649 #ifndef VMS
650 if (ent && !strcmp(ent->d_name, "."))
651 ent = readdir(dir);
652 #endif
653 if (ent)
654 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
655 }
656 #endif
657 return e;
658 }
659
660 void GDir::rewind() {
661 #ifdef WIN32
662 GString *tmp;
663
664 if (hnd)
665 FindClose(hnd);
666 tmp = path->copy();
667 tmp->append("/*.*");
668 hnd = FindFirstFile(tmp->getCString(), &ffd);
669 #elif defined(ACORN)
670 #elif defined(MACOS)
671 #else
672 if (dir)
673 rewinddir(dir);
674 #ifdef VMS
675 needParent = strchr(path->getCString(), '[') != NULL;
676 #endif
677 #endif
678 }