1 /*****************************************************************************/
2 /* */
3 /* (C) Copyright 1995-1997 Alberto Pasquale */
4 /* Portions (C) Copyright 1999 Per Lundberg */
5 /* */
6 /* A L L R I G H T S R E S E R V E D */
7 /* */
8 /*****************************************************************************/
9 /* */
10 /* How to contact the author: Alberto Pasquale of 2:332/504@fidonet */
11 /* Viale Verdi 106 */
12 /* 41100 Modena */
13 /* Italy */
14 /* */
15 /*****************************************************************************/
16
17 #include "apgenlib.hpp"
18 #include <ctype.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <time.h>
26 #include <sys/types.h>
27 #include <utime.h>
28 #include <stdio.h>
29
Exist(const char * path,_ExistStat * st)30 int Exist (const char *path, _ExistStat *st)
31 {
32 int plen = strlen (path);
33 if (plen == 0)
34 return 0;
35
36 char mypath[PATH_MAX];
37 BOOL DirReq = FALSE,
38 RootReq = FALSE;
39
40 if (path[plen-1] == '/') { // Dir Required
41 DirReq = TRUE;
42 RootReq = TRUE;
43 if (plen > 1)
44 if (path[plen-2] != ':') { // remove trailing backslash
45 RootReq = FALSE;
46 strcpy (mypath, path);
47 mypath[plen-1] = '\0';
48 path = mypath;
49 }
50 }
51
52 struct stat buf;
53
54 if (stat (path, &buf))
55 return 0;
56
57 if (S_ISCHR (buf.st_mode))
58 return _ExDEVICE_;
59
60 int ret = ((S_ISDIR (buf.st_mode) | RootReq) ? _ExDIR_ : _ExFILE_) |
61 ((buf.st_mode & S_IWUSR) ? _ExWRITE_ : 0);
62
63 if (DirReq && !(ret & _ExDIR_))
64 return 0;
65
66 if (st) {
67 st->ctime = 0;
68 st->atime = 0;
69 st->mtime = buf.st_mtime;
70 st->size = buf.st_size;
71 }
72
73 return ret;
74 }
75
76
getftime(int handle,time_t * mtime,time_t * ctime,time_t * atime)77 BOOL getftime (int handle, time_t *mtime, time_t *ctime, time_t *atime)
78 {
79 struct stat buf;
80
81 if (fstat (handle, &buf))
82 return FALSE;
83 if (mtime)
84 *mtime = buf.st_mtime;
85 if (ctime)
86 *ctime = buf.st_ctime;
87 if (atime)
88 *atime = buf.st_atime;
89 return TRUE;
90 }
91
92
getftime(const char * filename,time_t * mtime,time_t * ctime,time_t * atime)93 BOOL getftime (const char *filename, time_t *mtime, time_t *ctime, time_t *atime)
94 {
95 struct stat buf;
96
97 if (stat (filename, &buf))
98 return FALSE;
99 if (mtime)
100 *mtime = buf.st_mtime;
101 if (ctime)
102 *ctime = buf.st_ctime;
103 if (atime)
104 *atime = buf.st_atime;
105
106 return TRUE;
107 }
108
109 // BOOL touchf (int handle, time_t mtime, time_t ctime, time_t *nowp)
my_touchf(const char * fname,time_t mtime,time_t ctime,time_t * nowp)110 BOOL my_touchf (const char *fname, time_t mtime, time_t ctime, time_t *nowp)
111 {
112 time_t now = time (NULL);
113 struct utimbuf tvp;
114
115 if (nowp)
116 *nowp = now;
117
118 BOOL FTouch = FALSE; // must touch mtime when ctime not valid
119
120 if (mtime == _TF_Auto) {
121 mtime = 0;
122 FTouch = TRUE;
123 }
124
125 if (ctime == FL_TIME_MAX) {
126 ctime = now;
127 FTouch = TRUE;
128 }
129
130 if (mtime == FL_TIME_MAX)
131 mtime = now;
132
133 if (FTouch)
134 mtime = ctime;
135 if (mtime) {
136 tvp.actime = ctime;
137 tvp.modtime = mtime;
138 if (utime (fname, &tvp))
139 return FALSE;
140 }
141
142 return TRUE;
143 }
144
145
touchf(pcsz filename,time_t mtime,time_t ctime,time_t * nowp)146 BOOL touchf (pcsz filename, time_t mtime, time_t ctime, time_t *nowp)
147 {
148 if (!my_touchf (filename, mtime, ctime, nowp))
149 return FALSE;
150 return TRUE;
151 }
152
153 /*
154 BOOL touchf (int handle, byte touchflag, time_t *nowp)
155 {
156 return touchf (handle, (touchflag & _CF_mtouch_) ? FL_TIME_MAX : 0,
157 (touchflag & _CF_ctouch_) ? FL_TIME_MAX : 0, nowp);
158 }
159 */
160
touchf(pcsz filename,byte touchflag,time_t * nowp)161 BOOL touchf (pcsz filename, byte touchflag, time_t *nowp)
162 {
163 return touchf (filename, (touchflag & _CF_mtouch_) ? FL_TIME_MAX : 0,
164 (touchflag & _CF_ctouch_) ? FL_TIME_MAX : 0, nowp);
165 }
166
167
168 #define COPYBUFSIZE 0x8000
169
170
171 // Just copies the file (no EAs), handles Modification date only
172 // returns 0 on success
173
174 // Used under DOS and with OS/2 when destination is NFS with no EAs.
175
176
CopyFile(pcsz sourcefile,pcsz destfile,byte flags)177 static int CopyFile (pcsz sourcefile, pcsz destfile, byte flags)
178 {
179 int source, destination;
180 int bread;
181
182 byte *bufp = new byte[COPYBUFSIZE];
183
184 if ((source = open (sourcefile, O_RDONLY | O_BINARY)) == -1) {
185 delete[] bufp;
186 return -1;
187 }
188
189 if ((destination = open (destfile,
190 ((flags & _CF_ExistFail_) ? O_EXCL : O_TRUNC) |
191 O_WRONLY | O_CREAT | O_BINARY)) == -1) {
192 delete[] bufp;
193 close (source);
194 return -1;
195 }
196
197 // _dos_getftime (source, &srcfdate, &srcftime);
198
199 while ((bread = read (source, bufp, COPYBUFSIZE)) > 0) {
200 if (bread == -1)
201 break;
202 if (write (destination, bufp, bread) != bread) {
203 delete[] bufp;
204 close (source);
205 close (destination);
206 unlink (destfile);
207 return -1;
208 }
209 }
210
211 if (bread != 0) {
212 delete[] bufp;
213 close (source);
214 close (destination);
215 unlink (destfile);
216 return -1;
217 }
218
219 // _dos_setftime (destination, srcfdate, srcftime);
220
221 delete[] bufp;
222 close (source);
223 if (close (destination))
224 return -1;
225
226 return 0;
227 }
228
229
copyfile(pcsz sourcefile,pcsz destfile,byte flags)230 int copyfile (pcsz sourcefile, pcsz destfile, byte flags)
231 {
232 if (!(Exist (sourcefile) & _ExFILE_))
233 return _CF_NOSRC_;
234
235 if (eqpath (sourcefile, destfile)) {
236 if (flags & _CF_touchflags_)
237 touchf (destfile, flags);
238 return _CF_SRCEQDEST_;
239 }
240
241 bool copyerr;
242
243 copyerr = (CopyFile (sourcefile, destfile, flags) != 0);
244
245 if (copyerr) {
246
247 if (flags & _CF_ExistFail_) {
248 if (Exist (destfile) & _ExFILE_)
249 return _CF_DESTEXISTS_;
250 }
251
252 return _CF_ERROR_;
253 }
254
255 if (flags & _CF_touchflags_)
256 if (!touchf (destfile, flags))
257 return _CF_TOUCHERR_;
258
259 return _CF_OK_;
260 }
261
262
movefile(pcsz sourcefile,pcsz destfile,byte flags)263 int movefile (pcsz sourcefile, pcsz destfile, byte flags)
264 {
265 if (!(Exist (sourcefile) & _ExFILE_))
266 return _CF_NOSRC_;
267
268 if (eqpath (sourcefile, destfile)) {
269 if (flags & _CF_touchflags_)
270 touchf (destfile, flags);
271 return _CF_SRCEQDEST_;
272 }
273
274 if (Exist (destfile) & _ExFILE_)
275 if (flags & _CF_ExistFail_)
276 return _CF_DESTEXISTS_;
277 else
278 unlink (destfile);
279
280 if (rename (sourcefile, destfile) == 0) { // try rename
281 if (flags & _CF_touchflags_)
282 if (!touchf (destfile, flags))
283 return 1;
284 return _CF_OK_;
285 }
286
287 int err = copyfile (sourcefile, destfile, flags); // otherwise copy
288 if ((err != _CF_OK_) && (err != _CF_TOUCHERR_))
289 return err;
290
291 if (unlink (sourcefile)) // erase source
292 return _CF_SRCNOTDELETED_;
293
294 return err;
295 }
296
297
pathnobs(char * path)298 char *pathnobs (char *path) // remove trailing backslash
299 {
300 int len = strlen (path);
301 if (len < 2) // at least 2 chars needed e.g. "A\"
302 return path;
303 if ((path[1] == ':') && (len < 4)) // at least 4 chars e.g. "c:a\"
304 return path;
305 if (path[len-1] == '/')
306 path[len-1] = '\0'; // remove trailing backslash
307 return path;
308 }
309
310
pathwbs(char * path)311 char *pathwbs (char *path) // append trailing backslash
312 {
313 int len = strlen (path);
314 if (len < 1) // at leat 1 char needed e.g. "A" -> "A\"
315 return path;
316 if ((path[1] == ':') && (len < 3)) // at least 3 chars e.g. "c:a"
317 return path;
318 if (path[len-1] != '/') {
319 path[len] = '/';
320 path[len+1] = '\0';
321 }
322 return path;
323 }
324
325 #ifdef UNIX
326
fullpath(char * buffer,const char * path,size_t size,int * len)327 char *fullpath(char *buffer, const char *path, size_t size, int *len)
328 {
329 if (!buffer)
330 buffer = (char *)malloc(PATH_MAX);
331
332 realpath(path, buffer);
333 return buffer;
334 }
335
336 #else
fullpath(char * buffer,const char * path,size_t size,int * len)337 char *fullpath (char *buffer, const char *path, size_t size, int *len)
338 {
339 char work[PATH_MAX];
340 int wlen;
341
342 if (!path) {
343 getcwd (work, PATH_MAX);
344 wlen = strlen (work);
345 goto fpret;
346 }
347 if (*path == '\0') {
348 getcwd (work, PATH_MAX);
349 wlen = strlen (work);
350 goto fpret;
351 }
352
353 if ((path[0] == '\\') && (path[1] == '\\')) { // UNC names
354 strcpy (work, path);
355 wlen = strlen (work);
356 goto fpret;
357 }
358
359 {
360 const char *p = path;
361 char *w = work;
362 BOOL cwdgot = FALSE;
363
364 if (p[1] == ':') { // drive specified
365 work[0] = p[0];
366 work[1] = ':';
367 w += 2;
368 p += 2;
369 } else {
370 getcwd (work, PATH_MAX);
371 cwdgot = TRUE;
372 w += 2;
373 }
374
375 if (*p == '\\') { // root specified
376 *(w++) = '\\';
377 p ++;
378 } else { // root not specified
379 if (!cwdgot) {
380 unsigned curdrv;
381 _dos_getdrive (&curdrv);
382 unsigned wrkdrv = (toupper (work[0]) - 'A') + 1;
383 if (curdrv != wrkdrv) {
384 unsigned actdrv, total;
385 _dos_setdrive (wrkdrv, &total);
386 _dos_getdrive (&actdrv);
387 if (actdrv != wrkdrv) {
388 errno = ENOENT;
389 return NULL;
390 }
391 getcwd (work, PATH_MAX);
392 _dos_setdrive (curdrv, &total);
393 } else {
394 getcwd (work, PATH_MAX);
395 }
396 }
397 w = strchr (w, '\0'); // skip dir
398 }
399
400 while (*p) {
401 if (*p == '\\') {
402 errno = ENOENT;
403 return NULL;
404 }
405
406 if (*p == '.') { // special token
407 p ++;
408 while (*p && (*p != '\\')) {
409 if (*p != '.') { // check all '.'
410 errno = ENOENT;
411 return NULL;
412 }
413 w --; // points to last char
414 if (*w == '\\') { // root: too many '.'
415 errno = ENOENT;
416 return NULL;
417 }
418 while (*w != '\\') // remove last token
419 w --;
420 if (*(w-1) == ':')
421 w ++;
422 p ++;
423 }
424 } else { // normal token: copy
425 if (*(w-1) != '\\')
426 *(w++) = '\\';
427 while (*p && (*p != '\\'))
428 *(w++) = *(p++);
429 }
430
431 if (*p == '\\')
432 p ++;
433 }
434
435 if (*(w-1) != '\\') { // if path is '\' terminated, terminate fullpath
436 if (*(p-1) == '\\')
437 *(w++) = '\\';
438 }
439
440 *w = '\0';
441
442 wlen = w - work;
443 }
444
445 fpret:
446 if (!buffer) {
447 size = PATH_MAX;
448 buffer = (char *) malloc (size);
449 if (!buffer) {
450 errno = ENOMEM;
451 return NULL;
452 }
453 }
454 if (size < PATH_MAX) {
455 if (size <= wlen) {
456 errno = ERANGE;
457 return NULL;
458 }
459 }
460 strcpy (buffer, work);
461 if (len)
462 *len = wlen;
463 return buffer;
464 }
465 #endif
466
eqpath(const char * p1,const char * p2)467 BOOL eqpath (const char *p1, const char *p2)
468 {
469 if (!p1 || !p2)
470 return FALSE;
471
472 char p1f[PATH_MAX], p2f[PATH_MAX];
473 int len1, len2;
474
475 if (!fullpath (p1f, p1, PATH_MAX, &len1))
476 return FALSE;
477 if (!fullpath (p2f, p2, PATH_MAX, &len2))
478 return FALSE;
479
480 if (len1 > 4) {
481 if (p1f[len1-1] == DIRSEP) {
482 p1f[len1-1] = '\0'; // remove trailing backslash if present
483 len1 --;
484 }
485 }
486
487 if (len2 > 4) {
488 if (p2f[len2-1] == DIRSEP) {
489 p2f[len2-1] = '\0'; // remove trailing backslash if present
490 len2 --;
491 }
492 }
493
494 return (stricmp (p1f, p2f) == 0);
495 }
496
497
fnamecmp(const char * fname,const char * wildname)498 int fnamecmp (const char *fname, const char *wildname)
499 {
500 const char *f, *w;
501
502 f = fname;
503 w = wildname;
504
505 while (*w && *f) {
506 if (*w == '?') {
507 f++;
508 w++;
509 continue;
510 }
511 if (*w == '*') {
512 while (((*w == '?') || (*w == '*')) && (*f)) {
513 if (*w == '?')
514 f++;
515 w++;
516 }
517 while ((toupper (*f) != toupper (*w)) && (*f))
518 f++;
519 continue;
520 }
521
522 if (toupper (*f) != toupper (*w))
523 return 1;
524 f++;
525 w++;
526 }
527
528 if (*w == '.') // skip trailing ".*" if ok till now
529 w++;
530
531 while ((*w == '?') || (*w == '*')) // skip trailing ? if ok till now
532 w++;
533
534 if (*w || *f)
535 return 1;
536
537 return 0;
538 }
539
540
hasext(pcsz filename)541 char *hasext (pcsz filename)
542 {
543 pcsz p = strrchr (filename, '.');
544 if (!p)
545 return NULL;
546 if (strchr (p+1, DIRSEP))
547 return NULL;
548 return (char *)p;
549 }
550
551
remext(char * filename)552 void remext (char *filename)
553 {
554 char *p = hasext (filename);
555 if (p)
556 *p = '\0';
557 }
558
559
setext(char * filename,pcsz newext)560 void setext (char *filename, pcsz newext)
561 {
562 remext (filename);
563 strcat (filename, newext);
564 }
565
566
addext(char * filename,pcsz ext)567 void addext (char *filename, pcsz ext)
568 {
569 if (!hasext (filename))
570 strcat (filename, ext);
571 }
572
573
filefrompath(const char * path)574 char *filefrompath (const char *path)
575 {
576 #ifndef __QNXNTO__
577 char *bs = strrchr (path, DIRSEP);
578 #else
579 char *bs = strrchr ((char *)path, DIRSEP);
580 #endif // __QNXNTO__
581
582 #ifndef __QNXNTO__
583 if (!bs)
584 bs = strchr (path, ':');
585 #else
586 if (!bs)
587 bs = strchr ((char *)path, ':');
588 #endif // __QNXNTO__
589
590 if (!bs)
591 return (psz) path;
592
593 return (bs + 1);
594 }
595
596
fullname2path(const char * fullname,char * path,const char ** fname)597 char *fullname2path (const char *fullname, char *path, const char **fname)
598 {
599 const char *name = filefrompath (fullname);
600 int pathlen = int (name - fullname);
601 if (pathlen)
602 strncpy (path, fullname, pathlen);
603 path[pathlen] = '\0';
604 if (fname)
605 *fname = name;
606 return path;
607 }
608
DosFileTime(const char * filename)609 time_t DosFileTime (const char *filename)
610 {
611 time_t mtime;
612
613 if (!getftime (filename, &mtime))
614 return 0;
615 return mtime;
616 }
617
DosFileTime(int handle)618 time_t DosFileTime (int handle)
619 {
620 time_t mtime;
621
622 if (!getftime (handle, &mtime))
623 return 0;
624 return mtime;
625 }
626
myunlink(const char * path,int flags)627 static int myunlink (const char *path, int flags)
628 {
629 return unlink (path);
630 }
631
tunlink(const char * path,int timeout,int flags)632 int tunlink (const char *path, int timeout, int flags)
633 {
634 if (!(Exist (path) & _ExFILE_))
635 return _TUNLINK_NOTFILE_;
636
637 /* if (!(flags & _TUNLINK_ANY_)) {
638 unsigned attribs;
639 if (_dos_getfileattr (path, &attribs))
640 return _TUNLINK_ERROR_;
641 if (attribs & (_A_HIDDEN|_A_SYSTEM|_A_RDONLY))
642 return _TUNLINK_UNDELETABLE_;
643 }*/
644
645 int i = 0;
646 int ret = myunlink (path, flags);
647 while ((ret != 0) && (i < timeout)) {
648 sleep (1);
649 i++;
650 ret = myunlink (path, flags);
651 }
652
653 if (ret)
654 return _TUNLINK_TIMEOUT_;
655
656 return _TUNLINK_OK_;
657 }
658