1 //  This may look like C code, but it is really -*- C++ -*-
2 
3 //  ------------------------------------------------------------------
4 //  The Goldware Library
5 //  Copyright (C) 1990-1999 Odinn Sorensen
6 //  Copyright (C) 1999-2000 Alexander S. Aganichev
7 //  ------------------------------------------------------------------
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Library General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Library General Public License for more details.
17 //
18 //  You should have received a copy of the GNU Library General Public
19 //  License along with this program; if not, write to the Free
20 //  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 //  MA 02111-1307, USA
22 //  ------------------------------------------------------------------
23 //  $Id: gfilutl1.cpp,v 1.29 2011/02/17 22:59:54 stas_degteff Exp $
24 //  ------------------------------------------------------------------
25 //  File utility functions
26 //  ------------------------------------------------------------------
27 
28 #include <gtimall.h>
29 #include <gstrall.h>
30 #include <gfilutil.h>
31 #include <gfile.h>
32 #include <stdlib.h>
33 
34 #if defined(__MINGW32__) || defined(_MSC_VER)
35 #include <sys/utime.h>
36 #else
37 #include <utime.h>
38 #endif
39 
40 #if defined(__OS2__)
41 #define INCL_BASE
42 #include <os2.h>
43 #endif
44 
45 #if defined(__WIN32__)
46 #include <windows.h>
47 #endif
48 
49 #if defined(__MSDOS__)
50 #include <dos.h>
51 #endif
52 
53 #if defined(__UNIX__)
54 #include <pwd.h>
55 #include <sys/types.h>
56 #endif
57 
58 //  ------------------------------------------------------------------
59 //  Adds the directory-delimiter character into end of string ('\\' in DOS-based, '/' in unix-based OS)
60 // Replace wrong directory-delimiter character with good.
61 
AddBackslash(char * p)62 char* AddBackslash(char* p) {
63 
64   if(p != NULL) {
65    if(*p) {
66     strchg(p, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
67     if(p[strlen(p)-1] != GOLD_SLASH_CHR)
68       strcat(p, GOLD_SLASH_STR);
69    }
70    else
71     strcpy(p, GOLD_SLASH_STR);
72   }
73 
74   return p;
75 }
76 
77 
78 //  ------------------------------------------------------------------
79 //  Remove one trailing directory-delimiter character ('\\' in DOS-based, '/' in unix-based OS)
80 
StripBackslash(char * p)81 char* StripBackslash(char* p) {
82 
83   if(p == NULL) return p;
84 
85   int x = strlen(p) - 1;
86 
87   if(*p and isslash(p[x]))
88     p[x] = NUL;
89 
90   return p;
91 }
92 
93 
94 //  ------------------------------------------------------------------
95 //  Get size of file
96 
GetFilesize(const char * file)97 long GetFilesize(const char* file) {
98 
99   if(file == NULL) return 0;
100 
101   struct stat info;
102   if(stat(file, &info) == 0)
103     return info.st_size;
104   return -1;
105 }
106 
107 
108 //  ------------------------------------------------------------------
109 //  Convert time returned with stat to FFTime
110 
gfixstattime(time32_t st_time)111 time32_t gfixstattime(time32_t st_time)
112 {
113   #if (defined(__MINGW32__) && !defined(__MSVCRT__)) || defined(__CYGWIN__)
114   struct tm f; ggmtime(&f, &st_time);
115   #else
116   struct tm f; glocaltime(&f, &st_time);
117   #endif
118   FFTime t;
119   t.ft_year  = f.tm_year - 80;
120   t.ft_month = f.tm_mon + 1;
121   t.ft_day   = f.tm_mday;
122   t.ft_hour  = f.tm_hour;
123   t.ft_min   = f.tm_min;
124   t.ft_tsec  = f.tm_sec / 2;
125   #if (defined(__MINGW32__) && !defined(__MSVCRT__)) || defined(__CYGWIN__)
126   union {
127     DWORD t;
128     struct {
129       WORD wFatTime;
130       WORD wFatDate;
131     } d;
132   } ft;
133   ft.t = (DWORD)t.number();
134   FILETIME FileTime, LocalFileTime;
135   DosDateTimeToFileTime(ft.d.wFatDate, ft.d.wFatTime, &FileTime);
136   FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
137   SYSTEMTIME SystemTime;
138   FileTimeToSystemTime(&LocalFileTime, &SystemTime);
139   t.ft_year = SystemTime.wYear - 1980;
140   t.ft_month = SystemTime.wMonth;
141   t.ft_day = SystemTime.wDay;
142   t.ft_hour = SystemTime.wHour;
143   t.ft_min = SystemTime.wMinute;
144   t.ft_tsec = SystemTime.wSecond / 2;
145   #endif
146   return t.number();
147 }
148 
149 
150 //  ------------------------------------------------------------------
151 //  Get timestamp of file
152 
GetFiletime(const char * file)153 time32_t GetFiletime(const char* file) {
154 
155   struct stat st;
156 
157   if(file == NULL) return 0;
158 
159   if(stat(file, &st) == 0) {
160     #if defined(__MINGW32__)
161     if(st.st_mode & S_IFDIR)
162       return 0;
163     #endif
164     return gfixstattime(st.st_mtime);
165   }
166   return 0;
167 }
168 
169 
170 //  ------------------------------------------------------------------
171 //  Get size of open file
172 
fsize(FILE * fp)173 long fsize(FILE* fp) {
174   if(fp == NULL) return 0;
175   return filelength(fileno(fp));
176 }
177 
178 
179 //  ------------------------------------------------------------------
180 //  Check if a pathname is a directory
181 
is_dir(const TCHAR * path)182 bool is_dir(const TCHAR *path)
183 {
184   if(path == NULL) return false;
185 
186   // Check if it's a root path (X:\ оr /)
187   #if defined(__HAVE_DRIVES__)
188   if(g_isalpha(path[0]) and (path[1] == ':') and isslash(path[2]) and (path[3] == NUL))
189     return true;  // The root is a directory
190   # else
191   if( isslash(path[0]) and (path[1] == NUL))
192     return true;  // The root is a directory
193   #endif
194 
195   Path tmp;
196   strxcpy(tmp, path, sizeof(Path));
197   StripBackslash(tmp);
198 
199   struct stat st;
200   if(stat(tmp, &st) == 0)
201     return make_bool(st.st_mode & S_IFDIR);
202   return false;
203 }
204 
205 
206 //  ------------------------------------------------------------------
207 //  Add path to filename if no path is present
208 
209 static Path __addpath;
210 
AddPath(const char * path,const char * file)211 const char* AddPath(const char* path, const char* file) {
212 
213   if( (path == NULL) or (file == NULL) ) return file;
214 
215   if(strpbrk(file, "/\\")) {
216     // Don't add path if the filename already contains one
217     return file;
218   }
219   else if(*path and ((*file == '.') or isslash(path[strlen(path)-1]))) {
220     // Build path+filename if path ends with a slash or backslash
221     strxmerge(__addpath, sizeof(Path), path, file, NULL);
222     return __addpath;
223   }
224   else {
225     // Use filename in path or file
226     return *path ? path : file;
227   }
228 }
229 
230 
231 //  ------------------------------------------------------------------
232 //  Add path to filename, if no path is set
233 
MakePathname(char * pathname,const char * path,const char * name)234 void MakePathname(char* pathname, const char* path, const char* name) {
235 
236   Path tmpname;
237 
238   if( (pathname == NULL) or (path == NULL) or (name == NULL) ) return;
239 
240   strxcpy(tmpname, name, sizeof(tmpname));
241   strschg_environ(tmpname, sizeof(tmpname));
242 
243   if(strblank(tmpname)) {
244     *pathname = NUL;
245     return;
246   }
247 
248   bool have_path = false;
249 
250   if(isslash(tmpname[0]))
251     have_path = true;
252   #if defined(__HAVE_DRIVES__)
253   // Check if it's a root path (X:\)
254   else if(g_isalpha(tmpname[0]) and (tmpname[1] == ':') and isslash(tmpname[2]))
255     have_path = true;  // The root is a directory
256   #endif
257 
258   strchg(tmpname, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
259   if(have_path) {
260     strxcpy(pathname, tmpname, sizeof(Path));
261   }
262   else {
263     Path tmppath;
264 
265     strcpy(tmppath, path);
266     strbtrim(tmppath);
267     strchg(tmppath, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
268     if(*tmppath)
269       AddBackslash(tmppath);
270     strxmerge(pathname, sizeof(Path), tmppath, tmpname, NULL);
271   }
272   strschg_environ(pathname);
273 }
274 
275 
276 //  ------------------------------------------------------------------
277 //  Shareable fopen() for compilers that need it
278 
fsopen(const char * path,const char * type,int shflag)279 FILE *fsopen(const char *path, const char *type, int shflag) {
280 
281   FILE* fp=NULL;
282   int fh=-1, acc=0, mode=S_STDRD, c, n;
283 
284   if( (path == NULL) or (type == NULL) ) return NULL;
285 
286   switch(type[0]) {
287     case 'r':
288       acc |= O_RDONLY;
289       break;
290     case 'w':
291       acc |= (O_TRUNC|O_CREAT|O_WRONLY);
292       mode |= S_STDRW;
293       break;
294     case 'a':
295       acc |= (O_APPEND|O_CREAT|O_WRONLY);
296       mode |= S_STDRW;
297       break;
298     default:
299       return NULL;
300   }
301   n=0;
302   do {
303     c = type[++n];
304     switch(c) {
305       case '+':
306         acc &= (~O_RDONLY);
307         acc &= (~O_WRONLY);
308         acc |= O_RDWR;
309         break;
310       case 'b':
311         acc |= O_BINARY;
312         break;
313       case 't':
314         acc |= O_TEXT;
315         break;
316       default:
317         break;
318     }
319   } while((n < 3) and (c));
320 
321   fh = sopen(path, acc, shflag, mode);
322   if(fh != -1)
323     fp = fdopen(fh, (char*)type);
324 
325   return fp;
326 }
327 
328 
329 //  ------------------------------------------------------------------
330 //  Update time of modification for the file 'filename'
331 
TouchFile(const TCHAR * filename)332 void TouchFile(const TCHAR *filename)
333 {
334   if(filename == NULL) return;
335 
336   if (not fexist(filename))
337   {
338     gfile fh(filename, O_WRONLY|O_CREAT|O_TRUNC);
339   }
340   else
341   {
342     struct utimbuf ut;
343     ut.actime = ut.modtime = time(NULL);
344     utime(filename, &ut);
345   }
346 }
347 
348 
349 //  ------------------------------------------------------------------
350 //  Copy pathname with enviroment variables substitution and adds directory delimiter char.
351 //  Copy not more sizeof(Path) characters (__dst should be type "Path" or equvalence, size is GMAXPATH)
352 
PathCopy(char * __dst,const char * __src)353 char* PathCopy(char* __dst, const char* __src) {
354   if( (__dst == NULL) or (__src == NULL) ) return __dst;
355   strschg_environ(strxcpy(__dst, __src, sizeof(Path)), sizeof(Path));
356   return AddBackslash(__dst);
357 }
358 
359 //  ------------------------------------------------------------------
360 //  Test filesystem for file locks feature
361 
TestLockPath(const char * __path)362 int TestLockPath(const char* __path) {
363 
364   int _canlock = false;
365 
366   Path _file;
367 
368   if(__path == NULL) return NO;
369 
370   strxmerge(_file, sizeof(Path), __path, "GDXXXXXX", NULL);
371   mktemp(_file);
372 
373   int _fh = sopen(_file, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, SH_DENYNO, S_STDRW);
374   if(_fh != -1) {
375     if(lock(_fh, 0L, 1L) == -1)
376       _canlock = NO;
377     else {
378       _canlock = YES;
379       unlock(_fh, 0L, 1L);
380     }
381     close(_fh);
382     remove(_file);
383   }
384 
385   return _canlock;
386 }
387 
388 
389 //  ------------------------------------------------------------------
390 //  Return filename without path. (Return pointer to filename part of filepath.)
391 
CleanFilename(const char * __file)392 const char* CleanFilename(const char* __file) {
393 
394   static const char* invalidfilename = "<invalid>";
395   if((__file == NULL) or (__file == (char*)0xFFFFFFFFL) or (__file == (char*)0xEEEEEEEEL))
396     return invalidfilename;
397 
398   const char *tmp, *tmp2;
399   tmp = tmp2 = __file;
400   while(*tmp)
401     if(isslash(*tmp++))
402       tmp2 = tmp;
403   return *tmp2 ? tmp2 : invalidfilename;
404 }
405 
406 
407 //  ------------------------------------------------------------------
408 //  Fill file with garbage (random byte values).
409 
WipeFile(const char * file,int options)410 void WipeFile(const char* file, int options) {
411 
412   uint n;
413   byte buf[512];
414 
415   (void)options;
416 
417   if(file == NULL) return;
418 
419   for(n=0; n<512; n++)
420     buf[n] = (byte)(rand() % 256);
421 
422   int fh = sopen(file, O_RDWR|O_BINARY, SH_DENYRW, S_STDRW);
423   if(fh != -1) {
424     uint blocks = (uint)(filelength(fh) / 512L) + 1;
425     for(n=0; n<blocks; n++)
426       write(fh, buf, 512);
427     chsize(fh, 0);
428     close(fh);
429     remove(file);
430   }
431 }
432 
433 
434 //  ------------------------------------------------------------------
435 //  DOS-style enviroment variables substitution in string.
436 
strschg_environ(char * s)437 int strschg_environ(char* s) {
438 
439   if(s == NULL) return 0;
440   if(*s == NUL)
441     return 0;
442 
443   std::string __s = s;
444   int rv = strschg_environ(__s); // Look in gfilutl2.cpp
445   if(rv)
446     strcpy(s, __s.c_str());
447   return rv;
448 }
449 
strschg_environ(char * s,size_t s_size)450 int strschg_environ(char* s, size_t s_size) {
451 
452   if(s == NULL) return 0;
453   if(*s == NUL)
454     return 0;
455 
456   std::string __s = s;
457   int rv = strschg_environ(__s); // Look in gfilutl2.cpp
458   if(rv)
459     strxcpy(s, __s.c_str(), s_size);
460   return rv;
461 }
462 
463 
464 //  ------------------------------------------------------------------
465 //  OS-independent change directory
466 
gchdir(const char * dir)467 int gchdir(const char* dir) {
468 
469   if(dir == NULL) return 0;
470   #if defined(__WIN32__)
471   return not SetCurrentDirectory(dir);
472   #else
473   #if defined(__HAVE_DRIVES__)
474   if(dir[1] == ':') {
475     #if defined(__EMX__)
476     _chdrive(*dir);
477     #else
478     uint drives;
479     _dos_setdrive(g_toupper(*dir)-'@', &drives);
480     #endif
481   }
482   #endif
483   int e = chdir(dir);
484   if(e) {
485     Path p;
486     strcpy(p, dir);
487     StripBackslash(p);
488     e = chdir(p);
489   }
490   return e;
491   #endif
492 }
493 
494 
495 //  ------------------------------------------------------------------
496 //  Replace file suffix with specified in 'ext'
497 
replaceextension(char * destpath,const char * srcpath,const char * ext)498 void replaceextension(char *destpath, const char *srcpath, const char *ext) {
499 
500   const char *ptr;
501   char *ptr2, *slash, *dot;
502 
503   if( (destpath == NULL) or (srcpath == NULL) or (ext == NULL) ) return;
504 
505   ptr2 = slash = dot = destpath;
506   ptr = srcpath;
507   while(*ptr) {
508     if(isslash(*ptr))
509       slash = ptr2;
510     else if(*ptr == '.')
511       dot = ptr2;
512     *ptr2++ = *ptr++;
513   }
514   if(dot-slash > 0)
515     ptr2 = dot;
516   strcpy(ptr2, ext);
517 }
518 
519 
520 //  ------------------------------------------------------------------
521 //  Write to 'dir' dirname of the 'path'
522 
extractdirname(char * dir,const char * path)523 void extractdirname(char *dir, const char *path) {
524 
525   const char *p1 = path;
526   char *p2, *p3;
527 
528   if( (dir == NULL) or (path == NULL) ) return;
529 
530   p3 = p2 = dir;
531   *p3 = NUL;
532   while(*p1) {
533     if(isslash(*p1))
534       p2 = p3;
535     *p3++ = *p1++;
536   }
537   if(isslash(*p2))
538     ++p2;
539   *p2 = NUL;
540 }
541 
542 
543 //  ------------------------------------------------------------------
544