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