w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

gfile.cc
Go to the documentation of this file.
1 //========================================================================
2 //
3 // gfile.cc
4 //
5 // Miscellaneous file and directory name manipulation.
6 //
7 // Copyright 1996-2003 Glyph & Cog, LLC
8 //
9 //========================================================================
10 
11 //========================================================================
12 //
13 // Modified under the Poppler project - http://poppler.freedesktop.org
14 //
15 // All changes made under the Poppler project to this file are licensed
16 // under GPL version 2 or later
17 //
18 // Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
19 // Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
20 // Copyright (C) 2008 Adam Batkin <adam@batkin.net>
21 // Copyright (C) 2008, 2010, 2012, 2013 Hib Eris <hib@hiberis.nl>
22 // Copyright (C) 2009, 2012, 2014, 2017, 2018 Albert Astals Cid <aacid@kde.org>
23 // Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
24 // Copyright (C) 2013, 2018 Adam Reichold <adamreichold@myopera.com>
25 // Copyright (C) 2013, 2017 Adrian Johnson <ajohnson@redneon.com>
26 // Copyright (C) 2013 Peter Breitenlohner <peb@mppmu.mpg.de>
27 // Copyright (C) 2013, 2017 Thomas Freitag <Thomas.Freitag@alfa.de>
28 // Copyright (C) 2017 Christoph Cullmann <cullmann@kde.org>
29 // Copyright (C) 2018 Mojca Miklavec <mojca@macports.org>
30 // Copyright (C) 2019 Christian Persch <chpe@src.gnome.org>
31 //
32 // To see a description of the changes please see the Changelog file that
33 // came with your tarball or type make ChangeLog if you are building from git
34 //
35 //========================================================================
36 
37 #include <config.h>
38 
39 #ifndef _WIN32
40 # include <sys/types.h>
41 # include <sys/stat.h>
42 # include <fcntl.h>
43 # include <climits>
44 # include <cstring>
45 # include <pwd.h>
46 #endif // _WIN32
47 #include <cstdio>
48 #include <limits>
49 #include "GooString.h"
50 #include "gfile.h"
51 #include "gdir.h"
52 
53 // Some systems don't define this, so just make it something reasonably
54 // large.
55 #ifndef PATH_MAX
56 # define PATH_MAX 1024
57 #endif
58 
59 #ifndef _WIN32
60 
61 using namespace std::string_literals;
62 
63 namespace {
64 
65 template<typename...>
66 struct void_type
67 {
68  using type = void;
69 };
70 
71 template<typename... Args>
72 using void_t = typename void_type<Args...>::type;
73 
74 template<typename Stat, typename = void_t<>>
75 struct StatMtim
76 {
77  static const struct timespec &value(const Stat &stbuf) { return stbuf.st_mtim; }
78 };
79 
80 // Mac OS X uses a different field name than POSIX and this detects it.
81 template<typename Stat>
82 struct StatMtim<Stat, void_t<decltype(Stat::st_mtimespec)>>
83 {
84  static const struct timespec &value(const Stat &stbuf) { return stbuf.st_mtimespec; }
85 };
86 
87 inline const struct timespec &mtim(const struct stat &stbuf)
88 {
89  return StatMtim<struct stat>::value(stbuf);
90 }
91 
92 }
93 
94 #endif
95 
96 //------------------------------------------------------------------------
97 
99 {
100 #ifdef _WIN32
101  //---------- Win32 ----------
102  GooString *tmp;
103  char buf[256];
104  char *fp;
105 
106  tmp = new GooString(path);
107  tmp->append('/');
108  tmp->append(fileName);
109  GetFullPathNameA(tmp->c_str(), sizeof(buf), buf, &fp);
110  delete tmp;
111  path->clear();
112  path->append(buf);
113  return path;
114 
115 #else
116  //---------- Unix ----------
117  int i;
118 
119  // appending "." does nothing
120  if (!strcmp(fileName, "."))
121  return path;
122 
123  // appending ".." goes up one directory
124  if (!strcmp(fileName, "..")) {
125  for (i = path->getLength() - 2; i >= 0; --i) {
126  if (path->getChar(i) == '/')
127  break;
128  }
129  if (i <= 0) {
130  if (path->getChar(0) == '/') {
131  path->del(1, path->getLength() - 1);
132  } else {
133  path->clear();
134  path->append("..");
135  }
136  } else {
137  path->del(i, path->getLength() - i);
138  }
139  return path;
140  }
141 
142  // otherwise, append "/" and new path component
143  if (path->getLength() > 0 && path->getChar(path->getLength() - 1) != '/')
144  path->append('/');
145  path->append(fileName);
146  return path;
147 #endif
148 }
149 
150 static bool makeFileDescriptorCloexec(int fd)
151 {
152 #ifdef FD_CLOEXEC
153  int flags = fcntl(fd, F_GETFD);
154  if (flags >= 0 && !(flags & FD_CLOEXEC))
155  flags = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
156 
157  return flags >= 0;
158 #else
159  return true;
160 #endif
161 }
162 
163 #ifndef _WIN32
164 
165 int openFileDescriptor(const char *path, int flags)
166 {
167 # ifdef O_CLOEXEC
168  return open(path, flags | O_CLOEXEC);
169 # else
170  int fd = open(path, flags);
171  if (fd == -1)
172  return fd;
173 
174  if (!makeFileDescriptorCloexec(fd)) {
175  close(fd);
176  return -1;
177  }
178 
179  return fd;
180 # endif
181 }
182 
183 #endif
184 
185 FILE *openFile(const char *path, const char *mode)
186 {
187 #ifdef _WIN32
188  OSVERSIONINFO version;
189  wchar_t wPath[_MAX_PATH + 1];
190  char nPath[_MAX_PATH + 1];
191  wchar_t wMode[8];
192  const char *p;
193  size_t i;
194 
195  // NB: _wfopen is only available in NT
196  version.dwOSVersionInfoSize = sizeof(version);
197  GetVersionEx(&version);
198  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
199  for (p = path, i = 0; *p && i < _MAX_PATH; ++i) {
200  if ((p[0] & 0xe0) == 0xc0 && p[1] && (p[1] & 0xc0) == 0x80) {
201  wPath[i] = (wchar_t)(((p[0] & 0x1f) << 6) | (p[1] & 0x3f));
202  p += 2;
203  } else if ((p[0] & 0xf0) == 0xe0 && p[1] && (p[1] & 0xc0) == 0x80 && p[2] && (p[2] & 0xc0) == 0x80) {
204  wPath[i] = (wchar_t)(((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f));
205  p += 3;
206  } else {
207  wPath[i] = (wchar_t)(p[0] & 0xff);
208  p += 1;
209  }
210  }
211  wPath[i] = (wchar_t)0;
212  for (i = 0; (i < sizeof(mode) - 1) && mode[i]; ++i) {
213  wMode[i] = (wchar_t)(mode[i] & 0xff);
214  }
215  wMode[i] = (wchar_t)0;
216  return _wfopen(wPath, wMode);
217  } else {
218  for (p = path, i = 0; *p && i < _MAX_PATH; ++i) {
219  if ((p[0] & 0xe0) == 0xc0 && p[1] && (p[1] & 0xc0) == 0x80) {
220  nPath[i] = (char)(((p[0] & 0x1f) << 6) | (p[1] & 0x3f));
221  p += 2;
222  } else if ((p[0] & 0xf0) == 0xe0 && p[1] && (p[1] & 0xc0) == 0x80 && p[2] && (p[2] & 0xc0) == 0x80) {
223  nPath[i] = (char)(((p[1] & 0x3f) << 6) | (p[2] & 0x3f));
224  p += 3;
225  } else {
226  nPath[i] = p[0];
227  p += 1;
228  }
229  }
230  nPath[i] = '\0';
231  return fopen(nPath, mode);
232  }
233 #else
234  // First try to atomically open the file with CLOEXEC
235  const std::string modeStr = mode + "e"s;
236  FILE *file = fopen(path, modeStr.c_str());
237  if (file != nullptr)
238  return file;
239 
240  // Fall back to the provided mode and apply CLOEXEC afterwards
241  file = fopen(path, mode);
242  if (file == nullptr)
243  return nullptr;
244 
246  fclose(file);
247  return nullptr;
248  }
249 
250  return file;
251 #endif
252 }
253 
254 char *getLine(char *buf, int size, FILE *f)
255 {
256  int c, i;
257 
258  i = 0;
259  while (i < size - 1) {
260  if ((c = fgetc(f)) == EOF) {
261  break;
262  }
263  buf[i++] = (char)c;
264  if (c == '\x0a') {
265  break;
266  }
267  if (c == '\x0d') {
268  c = fgetc(f);
269  if (c == '\x0a' && i < size - 1) {
270  buf[i++] = (char)c;
271  } else if (c != EOF) {
272  ungetc(c, f);
273  }
274  break;
275  }
276  }
277  buf[i] = '\0';
278  if (i == 0) {
279  return nullptr;
280  }
281  return buf;
282 }
283 
284 int Gfseek(FILE *f, Goffset offset, int whence)
285 {
286 #if defined(HAVE_FSEEKO)
287  return fseeko(f, offset, whence);
288 #elif defined(HAVE_FSEEK64)
289  return fseek64(f, offset, whence);
290 #elif defined(__MINGW32__)
291  return fseeko64(f, offset, whence);
292 #elif defined(_WIN32)
293  return _fseeki64(f, offset, whence);
294 #else
295  return fseek(f, offset, whence);
296 #endif
297 }
298 
300 {
301 #if defined(HAVE_FSEEKO)
302  return ftello(f);
303 #elif defined(HAVE_FSEEK64)
304  return ftell64(f);
305 #elif defined(__MINGW32__)
306  return ftello64(f);
307 #elif defined(_WIN32)
308  return _ftelli64(f);
309 #else
310  return ftell(f);
311 #endif
312 }
313 
315 {
316 #if defined(HAVE_FSEEKO)
318 #elif defined(HAVE_FSEEK64) || defined(__MINGW32__)
320 #elif defined(_WIN32)
322 #else
324 #endif
325 }
326 
327 //------------------------------------------------------------------------
328 // GooFile
329 //------------------------------------------------------------------------
330 
331 #ifdef _WIN32
332 
333 GooFile::GooFile(HANDLE handleA) : handle(handleA)
334 {
335  GetFileTime(handleA, nullptr, nullptr, &modifiedTimeOnOpen);
336 }
337 
338 int GooFile::read(char *buf, int n, Goffset offset) const
339 {
340  DWORD m;
341 
342  LARGE_INTEGER largeInteger = {};
343  largeInteger.QuadPart = offset;
344 
345  OVERLAPPED overlapped = {};
346  overlapped.Offset = largeInteger.LowPart;
347  overlapped.OffsetHigh = largeInteger.HighPart;
348 
349  return FALSE == ReadFile(handle, buf, n, &m, &overlapped) ? -1 : m;
350 }
351 
352 Goffset GooFile::size() const
353 {
354  LARGE_INTEGER size = { (DWORD)-1, -1 };
355 
356  GetFileSizeEx(handle, &size);
357 
358  return size.QuadPart;
359 }
360 
362 {
363  HANDLE handle = CreateFileA(fileName->c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
364 
365  return handle == INVALID_HANDLE_VALUE ? nullptr : new GooFile(handle);
366 }
367 
368 GooFile *GooFile::open(const wchar_t *fileName)
369 {
370  HANDLE handle = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
371 
372  return handle == INVALID_HANDLE_VALUE ? nullptr : new GooFile(handle);
373 }
374 
376 {
377  struct _FILETIME lastModified;
378  GetFileTime(handle, nullptr, nullptr, &lastModified);
379 
380  return modifiedTimeOnOpen.dwHighDateTime != lastModified.dwHighDateTime || modifiedTimeOnOpen.dwLowDateTime != lastModified.dwLowDateTime;
381 }
382 
383 #else
384 
385 int GooFile::read(char *buf, int n, Goffset offset) const
386 {
387 # ifdef HAVE_PREAD64
388  return pread64(fd, buf, n, offset);
389 # else
390  return pread(fd, buf, n, offset);
391 # endif
392 }
393 
395 {
396 # ifdef HAVE_LSEEK64
397  return lseek64(fd, 0, SEEK_END);
398 # else
399  return lseek(fd, 0, SEEK_END);
400 # endif
401 }
402 
404 {
405  int fd = openFileDescriptor(fileName->c_str(), O_RDONLY);
406 
407  return fd < 0 ? nullptr : new GooFile(fd);
408 }
409 
410 GooFile::GooFile(int fdA) : fd(fdA)
411 {
412  struct stat statbuf;
413  fstat(fd, &statbuf);
414  modifiedTimeOnOpen = mtim(statbuf);
415 }
416 
418 {
419  struct stat statbuf;
420  fstat(fd, &statbuf);
421 
422  return modifiedTimeOnOpen.tv_sec != mtim(statbuf).tv_sec || modifiedTimeOnOpen.tv_nsec != mtim(statbuf).tv_nsec;
423 }
424 
425 #endif // _WIN32
426 
427 //------------------------------------------------------------------------
428 // GDir and GDirEntry
429 //------------------------------------------------------------------------
430 
431 GDirEntry::GDirEntry(const char *dirPath, const char *nameA, bool doStat)
432 {
433 #ifdef _WIN32
434  DWORD fa;
435 #else
436  struct stat st;
437 #endif
438 
439  name = new GooString(nameA);
440  dir = false;
441  fullPath = new GooString(dirPath);
442  appendToPath(fullPath, nameA);
443  if (doStat) {
444 #ifdef _WIN32
445  fa = GetFileAttributesA(fullPath->c_str());
446  dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
447 #else
448  if (stat(fullPath->c_str(), &st) == 0)
449  dir = S_ISDIR(st.st_mode);
450 #endif
451  }
452 }
453 
455 {
456  delete fullPath;
457  delete name;
458 }
459 
460 GDir::GDir(const char *name, bool doStatA)
461 {
462  path = new GooString(name);
463  doStat = doStatA;
464 #ifdef _WIN32
465  GooString *tmp;
466 
467  tmp = path->copy();
468  tmp->append("/*.*");
469  hnd = FindFirstFileA(tmp->c_str(), &ffd);
470  delete tmp;
471 #else
472  dir = opendir(name);
473 #endif
474 }
475 
477 {
478  delete path;
479 #ifdef _WIN32
480  if (hnd != INVALID_HANDLE_VALUE) {
481  FindClose(hnd);
482  hnd = INVALID_HANDLE_VALUE;
483  }
484 #else
485  if (dir)
486  closedir(dir);
487 #endif
488 }
489 
491 {
492  GDirEntry *e = nullptr;
493 
494 #ifdef _WIN32
495  if (hnd != INVALID_HANDLE_VALUE) {
496  e = new GDirEntry(path->c_str(), ffd.cFileName, doStat);
497  if (!FindNextFileA(hnd, &ffd)) {
498  FindClose(hnd);
499  hnd = INVALID_HANDLE_VALUE;
500  }
501  }
502 #else
503  struct dirent *ent;
504  if (dir) {
505  do {
506  ent = readdir(dir);
507  } while (ent && (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")));
508  if (ent) {
509  e = new GDirEntry(path->c_str(), ent->d_name, doStat);
510  }
511  }
512 #endif
513 
514  return e;
515 }
516 
518 {
519 #ifdef _WIN32
520  GooString *tmp;
521 
522  if (hnd != INVALID_HANDLE_VALUE)
523  FindClose(hnd);
524  tmp = path->copy();
525  tmp->append("/*.*");
526  hnd = FindFirstFileA(tmp->c_str(), &ffd);
527  delete tmp;
528 #else
529  if (dir)
530  rewinddir(dir);
531 #endif
532 }
#define type(a)
Definition: aptex-macros.h:171
#define name
#define mode
Definition: aptex-macros.h:510
Definition: gdir.h:47
~GDirEntry()
Definition: gfile.cc:454
GooString * name
Definition: gdir.h:60
bool dir
Definition: gdir.h:62
GooString * fullPath
Definition: gdir.h:61
GDirEntry(const char *dirPath, const char *nameA, bool doStat)
Definition: gfile.cc:431
GDir(const char *name, bool doStatA=true)
Definition: gfile.cc:460
~GDir()
Definition: gfile.cc:476
bool doStat
Definition: gdir.h:79
void rewind()
Definition: gfile.cc:517
DIR * dir
Definition: gdir.h:84
GDirEntry * getNextEntry()
Definition: gfile.cc:490
GooString * path
Definition: gdir.h:78
Definition: gfile.h:115
GooFile(const GooFile &)=delete
int read(char *buf, int n, Goffset offset) const
Definition: gfile.cc:385
int fd
Definition: gfile.h:144
Goffset size() const
Definition: gfile.cc:394
struct timespec modifiedTimeOnOpen
Definition: gfile.h:145
static GooFile * open(const GooString *fileName)
Definition: gfile.cc:403
bool modificationTimeChangedSinceOpen() const
Definition: gfile.cc:417
GooString * copy() const
Definition: GooString.h:101
GooString * append(char c)
Definition: GooString.h:161
#define n
Definition: t4ht.c:1290
@ FALSE
Definition: dd.h:101
#define fopen
Definition: xxstdio.h:21
#define fseek
Definition: xxstdio.h:30
#define fgetc
Definition: xxstdio.h:26
#define ftell
Definition: xxstdio.h:31
int strcmp()
Definition: coll.cpp:143
int fcntl(int fd, int action,...)
Definition: fcntl.c:202
#define FD_CLOEXEC
Definition: fcntl.in.h:191
#define F_GETFD
Definition: fcntl.in.h:210
#define O_CLOEXEC
Definition: fcntl.in.h:242
static void
Definition: fpif.c:118
mpz_t * f
Definition: gen-fib.c:34
#define s
Definition: afcover.h:80
#define c(n)
Definition: gpos-common.c:150
small capitals from c petite p
Definition: afcover.h:72
small capitals from c petite p scientific i
Definition: afcover.h:80
#define SEEK_END
Definition: ftzconf.h:251
#define EOF
Definition: afmparse.c:59
char * getLine(char *buf, int size, FILE *f)
Definition: gfile.cc:691
FILE * openFile(const char *path, const char *mode)
Definition: gfile.cc:612
GString * appendToPath(GString *path, const char *fileName)
Definition: gfile.cc:114
#define buf
#define fclose
Definition: debug.h:100
struct dirent * readdir(DIR *dirp)
Definition: dirent.c:138
int closedir(DIR *dirp)
Definition: dirent.c:123
DIR * opendir(char *fname)
Definition: dirent.c:60
#define fseeko
Definition: mingw32.h:52
#define ftello
Definition: mingw32.h:51
#define lseek
Definition: win32lib.h:83
#define fileno
Definition: win32lib.h:72
#define S_ISDIR(m)
Definition: win32lib.h:203
#define O_RDONLY
Definition: win32lib.h:176
#define open
Definition: win32lib.h:86
#define close
Definition: win32lib.h:63
#define fstat
Definition: win32lib.h:74
#define string
Definition: ctangleboot.c:111
int stat(const char *path, struct stat *sbuf)
unsigned int DWORD
Definition: mktexlib.h:49
typename voider< Ts... >::type void_t
Definition: variant.hpp:522
#define version
Definition: nup.c:10
union value value
Definition: obx.h:44
#define max(a, b)
Definition: pbmto4425.c:11
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst st
#define fp
static int size
Definition: ppmlabel.c:24
static int offset
Definition: ppmtogif.c:642
HANDLE hnd
Definition: pst2eps.c:6
#define flags
int Gfseek(FILE *f, Goffset offset, int whence)
Definition: gfile.cc:284
int openFileDescriptor(const char *path, int flags)
Definition: gfile.cc:165
Goffset GoffsetMax()
Definition: gfile.cc:314
Goffset Gftell(FILE *f)
Definition: gfile.cc:299
static bool makeFileDescriptorCloexec(int fd)
Definition: gfile.cc:150
long long Goffset
Definition: gfile.h:76
ShellFileEnvironment e
Definition: sh6.c:388
#define wchar_t
Definition: stddef.in.h:81
Definition: dirent.h:34
char d_name[260]
Definition: dirent.h:37
Definition: filedef.h:30
Definition: stemdb.c:56
pointer path
Definition: t1imager.h:36
#define FILE
Definition: t1stdio.h:34
#define ungetc(c, f)
Definition: t1stdio.h:106
char * file
Definition: t4ht.c:931
m
Definition: tex4ht.c:3990
const char * fileName
Definition: ugrep.cpp:52
#define rewinddir(dirp)
Definition: vmsdir.h:69
#define nullptr
Definition: xetex.h:75