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