1 /*
2  * $Id: environ.c,v 1.23 2004/06/18 16:19:37 andrew_belov Exp $
3  * ---------------------------------------------------------------------------
4  * This module contains  platform-specific routines along with a  set of hacks
5  * to implement the common functions of Borland compilers and their behavior.
6  *
7  */
8 
9 #include "arj.h"
10 
11 #if TARGET!=UNIX
12 #include <conio.h>
13 #include <io.h>
14 #include <process.h>
15 #endif
16 
17 #include <fcntl.h>
18 
19 #if COMPILER==BCC
20  #include <dir.h>
21 #elif COMPILER==MSC||COMPILER==MSVC||COMPILER==ICC
22  #include <direct.h>
23 #endif
24 
25 #if TARGET!=UNIX
26  #include <share.h>
27 #endif
28 
29 #if COMPILER==MSC||COMPILER==MSVC||COMPILER==ICC||COMPILER==HIGHC||defined(__EMX__)||(TARGET==OS2&&defined(LIBC))
30  #include <sys/types.h>
31  #include <sys/stat.h>
32  #if COMPILER==HIGHC&&!defined(LIBC)
33   #define SH_DENYRW _SH_DENYRW
34   #define SH_DENYWR _SH_DENYWR
35   #define SH_DENYNO _SH_DENYNO
36  #endif
37 #elif TARGET!=UNIX
38  #include <share.h>
39 #endif
40 #if COMPILER==BCC&&TARGET==DOS
41  #include <sys/stat.h>                  /* S_* only */
42 #endif
43 #if TARGET==UNIX
44  #ifdef SUNOS
45   #include <sys/statvfs.h>
46   #include <termio.h>
47  #endif
48  #ifdef __sco__
49   #include <sys/statvfs.h>
50  #endif
51  #include <unistd.h>
52  #include <fnmatch.h>
53  #include <signal.h>                    /* fork()+spawnvp() control */
54  #include <utime.h>
55  #include <sys/time.h>                  /* LIBC high-resolution timing */
56  #include <sys/resource.h>              /* Priority control */
57  #if defined(linux)
58   #include <sys/ioctl.h>
59   #include <sys/statfs.h>
60   #include <sys/statvfs.h>
61  #elif defined(__FreeBSD__)||defined(__NetBSD__)
62   #include <sys/param.h>
63   #include <sys/mount.h>
64  #elif defined(__QNXNTO__)
65   #include <sys/statvfs.h>
66  #else
67   #include <sys/statfs.h>
68  #endif
69 #endif
70 #ifdef TILED
71  #include <dos.h>
72 #endif
73 
74 #if TARGET==DOS
75  #include "win95dos.h"
76 #endif
77 
78 #if TARGET==WIN32&&!defined(F_OK)
79  #define F_OK                      0    /* For MSVCRT */
80 #endif
81 
82 /* IBM toolkit -> EMX wrapper */
83 
84 #ifdef __EMX__
85  #define DosCaseMap     DosMapCase
86  #define DosQCurDisk    DosQueryCurrentDisk
87  #define DosQFileInfo   DosQueryFileInfo
88  #define DosQFSInfo     DosQueryFSInfo
89  #define DosSelectDisk  DosSetDefaultDisk
90  #define DosSetPrty     DosSetPriority
91 #endif
92 
93 DEBUGHDR(__FILE__)                      /* Debug information block */
94 
95 /*
96  * DOS legacy
97  */
98 
99 #if TARGET==DOS
100 
101 /* INT 24h */
102 
103 #define INT24                   0x24
104 #define INT24_IGNORE               0
105 #define INT24_RETRY                1
106 #define INT24_ABORT                2
107 #define INT24_FAIL                 3
108 #define INT24_DPF_WRITING     0x0100    /* Device processing flag in AX */
109 #define INT24_IO_ERROR        0x8000
110 
111 /* Character device IOCTL statements */
112 
113 #define CHDI_STDOUT           0x0001
114 #define CHDI_STDIN            0x0002
115 #define CHDI_NUL              0x0004
116 #define CHDI_CLOCK            0x0008
117 #define CHDI_SPECIAL          0x0010
118 #define CHDI_BINARY           0x0020
119 #define CHDI_EOF_ON_INPUT     0x0040
120 #define CHDI_SET              0x0080
121 #define CHDI_OPENCLOSE        0x0800
122 #define CHDI_OUTPUT_TILL_BUSY 0x2000
123 #define CHDI_CAN_IOCTL        0x4000
124 
125 /* File IOCTL statements */
126 
127 #define CHDF_NOT_WRITTEN      0x0040
128 #define CHDF_NOT_FILE         0x0080
129 #define CHDF_EXT_INT24        0x0100    /* DOS 4.x only */
130 #define CHDF_NOT_REMOVABLE    0x0800
131 #define CHDF_NO_TIMESTAMPING  0x4000
132 #define CHDF_IS_REMOTE        0x8000
133 
134 /* This macro checks if DOS version is less than 3.10 */
135 
136 #define is_dos_31                  (_osmajor<3||_osmajor==3&&_osminor<10)
137 
138 /* For MS C, a macro to query the current time */
139 
140 #if COMPILER==MSC
141  #define g_timer(t) t=*(long FAR *)0x0000046CL
142 #endif
143 
144 #endif /* TARGET==DOS */
145 
146 /* An OS/2 & Win32 macro to join timestamps */
147 
148 #if TARGET==OS2||TARGET==WIN32
149  #define make_ftime(fd, ft) ((unsigned long)*(USHORT *)&fd<<16)+(unsigned long)*(USHORT *)&ft
150 #endif
151 
152 /* Allowable DOS file attributes (HSRA) */
153 
154 #if TARGET!=UNIX
155  #define STD_FILE_ATTR             (FATTR_ARCH|FATTR_SYSTEM|FATTR_HIDDEN|FATTR_RDONLY)
156 #endif
157 
158 /* Attribute comparison for UNIX */
159 
160 #if TARGET==UNIX
161  #define match_unix_attrs(attr, pattern) (((pattern)==0)||(((attr)&(pattern))==(pattern)))
162 #endif
163 
164 /* Command-line input limit */
165 
166 #if TARGET==DOS
167  #define INPUT_LIMIT             127
168 #endif
169 
170 /* UNIX file time requests */
171 
172 #if TARGET==UNIX
173  #define UFTREQ_FTIME              0
174  #define UFTREQ_ATIME              1
175  #define UFTREQ_CTIME              2
176 #endif
177 
178 /*
179  * Exported variables
180  */
181 
182 /* Line feed string */
183 
184 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
185  char simple_lf[]="\n";
186 #endif
187 
188 /* Carriage return */
189 
190 #if SFX_LEVEL>=ARJ||TARGET==DOS&&(SFX_LEVEL>=ARJSFX||defined(REARJ))
191  char simple_cr[]="\r";
192 #endif
193 
194 /* The following systems are considered equal to host OS under which ARJ is
195    run. The contents of this list greatly depend upon the host OS itself... */
196 
197 #if SFX_LEVEL>=ARJSFX
198  #if TARGET==DOS
199   int friendly_systems[]={OS_DOS, OS_WIN95, OS_WINNT, -1};
200  #elif TARGET==OS2
201   int friendly_systems[]={OS_DOS, OS_OS2, OS_WIN95, OS_WINNT, -1};
202  #elif TARGET==WIN32
203   int friendly_systems[]={OS_DOS, OS_WIN95, OS_WINNT, -1};
204  #elif TARGET==UNIX
205   int friendly_systems[]={OS_UNIX, OS_NEXT, -1};
206  #endif
207 #endif
208 
209 /* Standard devices */
210 
211 #if SFX_LEVEL>=ARJSFX
212  #if TARGET==UNIX
213   char dev_null[]="/dev/null";          /* NULL device */
214   char dev_con[]="/dev/tty";            /* Console device */
215  #else
216   char dev_null[]="NUL";                /* NULL device */
217   char dev_con[]="CON";                 /* Console device */
218  #endif
219 #endif
220 
221 /* Wildcard used to select all files */
222 
223 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
224  #if TARGET==DOS
225   char all_wildcard[]="*.*";
226  #else
227   char all_wildcard[]="*";
228  #endif
229 #endif
230 
231 /* Win32 can't use setftime_on_stream - this is required for ARJSFXJR: */
232 
233 #if SFX_LEVEL==ARJSFXJR&&TARGET==WIN32
234  #define NEED_SETFTIME_HACK
235 #endif
236 
237 /*
238  * Internal variables
239  */
240 
241 /* Attribute format */
242 
243 #if SFX_LEVEL>=ARJSFX
244  static char attrib_buf[]="---W";       /* ASHR if all set */
245 #endif
246 
247 /* Arbitrary disk drive for LFN testing */
248 
249 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
250  static char drive_c[]="C:";            /* Although it's incorrect... */
251 #endif
252 
253 /* Directory specifiers for file search */
254 
255 #if SFX_LEVEL>=ARJ||defined(REARJ)
256  /* Subdirectory/root search wildcard */
257  #if TARGET==DOS
258   char root_wildcard[]="\\*.*";
259  #elif TARGET==OS2||TARGET==WIN32
260   char root_wildcard[]="\\*";
261  #elif TARGET==UNIX
262   char root_wildcard[]="/*";
263  #endif
264  char up_dir_spec[]="..";               /* Parent directory specifier */
265  char pathsep_str[]={PATHSEP_DEFAULT, '\0'};
266 #endif
267 #if SFX_LEVEL>=ARJ||defined(REARJ)||(SFX_LEVEL>=ARJSFXV&&TARGET==UNIX)
268  char cur_dir_spec[]=".";               /* Current directory specifier */
269 #endif
270 
271 /* FCB mask (used to fill in FCBs) */
272 
273 #if SFX_LEVEL>=ARJSFXV&&TARGET==DOS
274  static char fcb_mask[]="???????????";
275 #endif
276 
277 /* Queues for detecting child session shutdown */
278 
279 #if TARGET==OS2&&defined(REARJ)
280  static char rearj_q_fmt[]="\\QUEUES\\REARJ#%u";
281 #endif
282 
283 /* Name of file that is currently being opened */
284 
285 #if COMPILER==MSC&&TARGET==DOS
286  static char *f_file_ptr=NULL;
287 #endif
288 
289 /* For the case if the environment doesn't allow to query EXE name, we'll store
290    our own ones. */
291 
292 #if TARGET==DOS
293  #if SFX_LEVEL>=ARJ
294   static char default_exe[]="arj" EXE_EXTENSION;
295  #elif SFX_LEVEL>=ARJSFXJR
296   static char default_exe[]="arjsfx" EXE_EXTENSION;
297  #elif defined(REARJ)
298   static char default_exe[]="rearj" EXE_EXTENSION;
299  #endif
300 #endif
301 
302 /*
303  * Frequently used Borland routines
304  */
305 
306 /* Returns 0 for A:, 1 for B:, etc. */
307 
308 #if defined(HAVE_DRIVES)&&((SFX_LEVEL>=ARJSFX||defined(REARJ))&&COMPILER!=BCC)
getdisk()309 int getdisk()
310 {
311  #if TARGET==DOS
312   int rc;
313 
314   _dos_getdrive((unsigned int *)&rc);
315   return(rc-1);
316  #elif TARGET==OS2
317   #ifndef __32BIT__
318    USHORT rc;
319    ULONG total;
320 
321    DosQCurDisk(&rc, &total);
322    return(rc-1);
323   #else
324    ULONG rc, total;
325 
326    DosQCurDisk(&rc, &total);
327    return(rc-1);
328   #endif
329  #elif TARGET==WIN32
330   char cur_dir[CCHMAXPATH];
331 
332   if(GetCurrentDirectory(sizeof(cur_dir), cur_dir)&&cur_dir[1]==':')
333    return(cur_dir[0]-'A');
334   else
335    return(-1);
336  #endif
337 }
338 #endif
339 
340 /* Performs heap checking if required */
341 
342 #if SFX_LEVEL>=ARJ
verify_heap()343 int verify_heap()
344 {
345  #if COMPILER==BCC
346   return(heapcheck()==_HEAPCORRUPT);
347  #elif COMPILER==MSC||COMPILER==MSVC
348   int rc;
349 
350   rc=_heapchk();
351   return(rc!=_HEAPOK&&rc!=_HEAPEMPTY);
352  #elif COMPILER==ICC&&defined(DEBUG)
353   _heap_check();
354   return(0);
355  #else
356   return(0);                            /* Not implemented otherwise */
357  #endif
358 }
359 #endif
360 
361 /* Performs far heap verification (if there is any) */
362 
363 #if SFX_LEVEL>=ARJ
verify_far_heap()364 int verify_far_heap()
365 {
366  #if COMPILER==BCC
367   return(farheapcheck());
368  #elif COMPILER==MSC
369   return(_fheapchk());
370  #elif !defined(TILED)
371   return(verify_heap());
372  #else
373   return(0);                            /* Don't even bother of it */
374  #endif
375 }
376 #endif
377 
378 /* Returns the available stack space */
379 
380 #if SFX_LEVEL>=ARJ
get_stack_space()381 static unsigned int get_stack_space()
382 {
383  #if defined(__BORLANDC__)
384   return(stackavail());
385  #elif defined(__TURBOC__)
386   return(_stklen+_SP);
387  #elif COMPILER==MSC
388   return(stackavail());
389  #else
390   return(32767);
391  #endif
392 }
393 #endif
394 
395 /* Changes the current drive to 0=A:, 1=B:, and so on... */
396 
397 #if defined(HAVE_DRIVES)&&(defined(REARJ)&&COMPILER!=BCC)
setdisk(int drive)398 int setdisk(int drive)
399 {
400  #if TARGET==DOS
401   int numdrives;
402 
403   _dos_setdrive(drive+1, &numdrives);
404   return(numdrives);
405  #elif TARGET==OS2
406   #ifdef __32BIT__
407    ULONG rc;
408   #else
409    USHORT rc;
410   #endif
411   ULONG total;
412 
413   rc=DosSelectDisk(drive+1);
414   if(rc)
415    return(0);
416   DosQCurDisk(&rc, &total);
417   return(total);
418  #elif TARGET==WIN32
419   char t[4];
420 
421   t[0]=drive+'A';
422   t[1]=':';
423   t[2]='\0';
424   SetCurrentDirectory(t);
425   return(25);                           /* Dummy value */
426  #endif
427 }
428 #endif
429 
430 /* Returns the number of bytes available in the far heap (quite slow). This is
431    an advisory function for legacy parts of ARJ. Avoid it by all means. */
432 
433 #if SFX_LEVEL>=ARJSFXV&&COMPILER!=BCC
farcoreleft()434 long farcoreleft()
435 {
436  #if TARGET==DOS
437   void _huge *hp;
438   static long rc=736L;
439   long s_rc;
440 
441   s_rc=rc;
442   rc+=2L;
443   do
444    hp=halloc(rc-=2L, 1024);
445   while(hp==NULL&&rc>0L);
446   if(hp!=NULL)
447    hfree(hp);
448   if(rc<s_rc)
449    return(rc*1024L);
450   do
451   {
452    hp=halloc(rc+=16L, 1024);
453    if(hp!=NULL)
454     hfree(hp);
455   } while(hp!=NULL);
456   return((rc-16L)*1024L);
457  #elif TARGET==OS2
458   #ifdef __32BIT__
459    ULONG rc;
460 
461    DosQuerySysInfo(QSV_MAXPRMEM, QSV_MAXPRMEM, (PVOID)&rc, sizeof(rc));
462    return(rc);
463   #else
464    ULONG rc;
465 
466    DosMemAvail(&rc);
467    return(rc);
468   #endif
469  #elif TARGET==WIN32
470   MEMORYSTATUS memstat;
471 
472   memstat.dwLength=sizeof(memstat);
473   GlobalMemoryStatus(&memstat);
474   return(max(0x7FFFFFFFUL, memstat.dwAvailVirtual));
475  #else
476   return(0x7FFFFFFF);
477  #endif
478 }
479 #endif
480 
481 /* Returns the current time of day */
482 
483 #if (SFX_LEVEL>=ARJSFXV||defined(REARJ)||defined(REGISTER))&&COMPILER!=BCC
arj_gettime(struct time * ts)484 void arj_gettime(struct time *ts)
485 {
486  #if TARGET==DOS
487   struct dostime_t dts;
488 
489   _dos_gettime(&dts);
490   ts->ti_hour=dts.hour;
491   ts->ti_min=dts.minute;
492   ts->ti_sec=dts.second;
493   ts->ti_hund=dts.hsecond;
494  #elif TARGET==OS2
495   DATETIME dts;
496 
497   DosGetDateTime(&dts);
498   ts->ti_hour=dts.hours;
499   ts->ti_min=dts.minutes;
500   ts->ti_sec=dts.seconds;
501   ts->ti_hund=dts.hundredths;
502  #elif TARGET==WIN32
503   SYSTEMTIME st;
504 
505   GetLocalTime(&st);
506   ts->ti_hour=st.wHour;
507   ts->ti_min=st.wMinute;
508   ts->ti_sec=st.wSecond;
509   ts->ti_hund=st.wMilliseconds/10;
510  #else
511   time_t t;
512   struct timeval v;
513   struct tm *tms;
514 
515   do
516   {
517    t=time(NULL);
518    gettimeofday(&v, NULL);
519   } while(time(NULL)!=t);
520   tms=localtime(&t);
521   ts->ti_hour=tms->tm_hour;
522   ts->ti_min=tms->tm_min;
523   ts->ti_sec=tms->tm_sec;
524   ts->ti_hund=v.tv_usec/10000;
525  #endif
526 }
527 #endif
528 
529 /* Returns the current date */
530 
531 #if defined(REARJ)&&COMPILER!=BCC
arj_getdate(struct date * ds)532 void arj_getdate(struct date *ds)
533 {
534  #if TARGET==DOS
535   struct dosdate_t dds;
536 
537   _dos_getdate(&dds);
538   ds->da_year=1980+dds.year;
539   ds->da_day=dds.day;
540   ds->da_mon=dds.month;
541  #elif TARGET==OS2
542   DATETIME dts;
543 
544   DosGetDateTime(&dts);
545   ds->da_year=dts.year;
546   ds->da_day=dts.day;
547   ds->da_mon=dts.month;
548  #elif TARGET==WIN32
549   SYSTEMTIME st;
550 
551   GetLocalTime(&st);
552   ds->da_year=st.wYear;
553   ds->da_day=st.wDay;
554   ds->da_mon=st.wMonth;
555  #else
556   time_t t;
557   struct tm *tms;
558 
559   t=time(NULL);
560   tms=localtime(&t);
561   ds->da_year=tms->tm_year+1900;
562   ds->da_day=tms->tm_mday;
563   ds->da_mon=tms->tm_mon+1;
564  #endif
565 }
566 #endif
567 
568 /* Gets address of DOS DTA */
569 
570 #if SFX_LEVEL>=ARJSFXV&&COMPILER!=BCC&&TARGET==DOS
getdta()571 static char FAR *getdta()
572 {
573  union REGS regs;
574  struct SREGS sregs;
575 
576  regs.h.ah=0x2F;
577  intdosx(&regs, &regs, &sregs);
578  return(MK_FP(sregs.es, regs.x.bx));
579 }
580 #endif
581 
582 /* Sets address of DOS DTA */
583 
584 #if SFX_LEVEL>=ARJSFXV&&COMPILER!=BCC&&TARGET==DOS
setdta(char FAR * dta)585 static void setdta(char FAR *dta)
586 {
587  union REGS regs;
588  struct SREGS sregs;
589 
590  regs.h.ah=0x1A;
591  sregs.ds=FP_SEG(dta); regs.x.dx=FP_OFF(dta);
592  intdosx(&regs, &regs, &sregs);
593 }
594 #endif
595 
596 /*
597  * OS/2 farcalloc()/farfree() routines
598  */
599 
600 #if TARGET==OS2&&defined(TILED)
601 
602 /* farcalloc() for 0-based segments */
603 
604 #if SFX_LEVEL>=ARJ&&defined(ASM8086)
farcalloc_based(unsigned long num,unsigned long size)605 void FAR *farcalloc_based(unsigned long num, unsigned long size)
606 {
607  USHORT total;
608  SEL selector;
609  void FAR *rc;
610 
611  total=(USHORT)num*size;
612  if(DosAllocSeg(total, &selector, SEG_NONSHARED))
613   return(NULL);
614  rc=(void FAR *)MAKEP(selector, 0);
615  far_memset(rc, 0, total);
616  return(rc);
617 }
618 #endif
619 
620 /* farfree() for 0-based segments */
621 
622 #if SFX_LEVEL>=ARJ&&defined(ASM8086)
farfree_based(void FAR * ptr)623 void farfree_based(void FAR *ptr)
624 {
625  DosFreeSeg(SELECTOROF(ptr));
626 }
627 #endif
628 
629 #endif
630 
631 /* Sets the process priority. */
632 
633 #if TARGET!=DOS&&SFX_LEVEL>=ARJ
set_priority(struct priority * priority)634 void set_priority(struct priority *priority)
635 {
636  #if TARGET==OS2
637   DosSetPrty(PRTYS_THREAD, priority->class, priority->delta, 0);
638  #elif TARGET==WIN32
639   static HANDLE ph=0, th=0;
640   static DWORD w32_classes[4]={IDLE_PRIORITY_CLASS,
641                                NORMAL_PRIORITY_CLASS,
642                                HIGH_PRIORITY_CLASS,
643                                REALTIME_PRIORITY_CLASS};
644 
645   if(!ph)
646    ph=GetCurrentProcess();
647   if(!th)
648    th=GetCurrentThread();
649   if(priority->class<=4)
650   SetPriorityClass(ph, w32_classes[priority->class-1]);
651   SetThreadPriority(th, priority->delta);
652  #else
653   #if defined(HAVE_SETPRIORITY)
654    setpriority(PRIO_PROCESS, 0, 21-priority->class);
655   #else
656    #error Priority functions missing
657   #endif
658  #endif
659 }
660 #endif
661 
662 /*
663  * This section is specific to Windows 95 LFN API.
664  */
665 
666 /* Just a customized interrupt call procedure */
667 
668 #if (SFX_LEVEL>=ARJSFX||defined(REARJ))&&TARGET==DOS
call_dos_int(unsigned int funcnum,union REGS * regs,struct SREGS * sregs)669 static int call_dos_int(unsigned int funcnum, union REGS *regs, struct SREGS *sregs)
670 {
671  regs->x.ax=funcnum;
672  #ifdef ASM8086
673   asm{
674    pushf
675    pop   ax
676    or    ax, 1
677    push  ax
678    popf
679   };
680  #else
681   /* Provoke the carry flag */
682   regs->x.cflag=(regs->x.ax&0x7FFF)+0x8000;
683  #endif
684  intdosx(regs, regs, sregs);
685  _doserrno=(regs->x.cflag!=0)?(regs->x.ax):0;
686  return(regs->x.cflag);
687 }
688 #endif
689 
690 /* Test the specified volume for long filename support */
691 
692 #if (SFX_LEVEL>=ARJSFX||defined(REARJ))&&TARGET==DOS
w95_test_for_lfn(char * drive)693 static int w95_test_for_lfn(char *drive)
694 {
695  union REGS regs;
696  struct SREGS sregs;
697  char filesystem[40];                   /* Ralf Brown says 32 */
698  char FAR *fsptr, FAR *dptr;
699 
700  fsptr=(char FAR *)filesystem;
701  dptr=(char FAR *)drive;
702  memset(&sregs, 0, sizeof(sregs));
703  sregs.es=FP_SEG(fsptr); regs.x.di=FP_OFF(fsptr);
704  regs.x.cx=sizeof(filesystem);
705  sregs.ds=FP_SEG(dptr); regs.x.dx=FP_OFF(dptr);
706  return(call_dos_int(W95_GET_VOLUME_INFO, &regs, &sregs)==0&&regs.x.bx&0x4000);
707 }
708 #endif
709 
710 /* Return equivalent canonical short filename for a long filename */
711 
712 #if (SFX_LEVEL>=ARJSFX||defined(REARJ))&&TARGET==DOS
w95_get_shortname(char * longname,char * shortname,int cb_shortname)713 static int w95_get_shortname(char *longname, char *shortname, int cb_shortname)
714 {
715  union REGS regs;
716  struct SREGS sregs;
717  char FAR *lnptr, FAR *snptr;
718 
719  memset(&sregs, 0, sizeof(sregs));
720  if(cb_shortname>=CCHMAXPATH_DOS)
721  {
722   lnptr=(char FAR *)longname;
723   snptr=(char FAR *)shortname;
724   shortname[0]='\0';
725   sregs.ds=FP_SEG(lnptr); regs.x.si=FP_OFF(lnptr);
726   sregs.es=FP_SEG(snptr); regs.x.di=FP_OFF(snptr);
727   regs.x.cx=W95_GET_SHORTNAME;          /* No SUBST expansion, subfunc #1 */
728   if(!call_dos_int(W95_TRUENAME, &regs, &sregs))
729    return(strlen(shortname));
730   else
731    return(0);
732  }
733  else
734   return(0);
735 }
736 #endif
737 
738 /* Changes directory under Windows 95 */
739 
740 #if defined(REARJ)&&TARGET==DOS
w95_chdir(char * longname)741 static int w95_chdir(char *longname)
742 {
743  union REGS regs;
744  struct SREGS sregs;
745  char FAR *lnptr;
746 
747  memset(&sregs, 0, sizeof(sregs));
748  lnptr=(char FAR *)longname;
749  sregs.ds=FP_SEG(lnptr); regs.x.dx=FP_OFF(lnptr);
750  return(call_dos_int(W95_CHDIR, &regs, &sregs)?-1:0);
751 }
752 #endif
753 
754 /* Return equivalent canonical long filename for a short filename */
755 
756 #if (SFX_LEVEL>=ARJ)&&TARGET==DOS
w95_get_longname(char * shortname,char * longname,int cb_longname)757 static int w95_get_longname(char *shortname, char *longname, int cb_longname)
758 {
759  union REGS regs;
760  struct SREGS sregs;
761  char FAR *lnptr, FAR *snptr;
762 
763  memset(&sregs, 0, sizeof(sregs));
764  if(cb_longname>=CCHMAXPATH_W95)
765  {
766   longname[0]='\0';
767   lnptr=(char FAR *)longname;
768   snptr=(char FAR *)shortname;
769   sregs.ds=FP_SEG(snptr); regs.x.si=FP_OFF(snptr);
770   sregs.es=FP_SEG(lnptr); regs.x.di=FP_OFF(lnptr);
771   regs.x.cx=W95_GET_LONGNAME;           /* No SUBST expansion, subfunc #2 */
772   if(!call_dos_int(W95_TRUENAME, &regs, &sregs))
773    return(strlen(longname));
774   else
775    return(0);
776  }
777  else
778   return(0);
779 }
780 #endif
781 
782 /* Returns 1 if the current OS is Windows NT, 0 if Windows 95 */
783 
784 #if SFX_LEVEL>=ARJ&&TARGET==DOS
test_for_winnt()785 int test_for_winnt()
786 {
787  return(0);                     	/* Implemented in ARJ32 */
788 }
789 #endif
790 
791 /* Returns the name of current directory */
792 
793 #if defined(REARJ)&&TARGET==DOS
w95_cwd(char * dest)794 static char *w95_cwd(char *dest)
795 {
796  union REGS regs;
797  struct SREGS sregs;
798  char FAR *dptr;
799 
800  dptr=(char FAR *)dest;
801  memset(&sregs, 0, sizeof(sregs));
802  dest[0]=getdisk()+'A';
803  dest[1]=':';
804  dest[2]=PATHSEP_DEFAULT;
805  regs.h.dl=0;
806  sregs.ds=FP_SEG(dptr); regs.x.si=FP_OFF(dptr)+3;
807  return(call_dos_int(W95_CWD, &regs, &sregs)?NULL:dest);
808 }
809 #endif
810 
811 /* Create a directory with longname. Return -1 if failed. */
812 
813 #if (SFX_LEVEL>=ARJSFX||defined(REARJ))&&TARGET==DOS
w95_mkdir(char * longname)814 static int w95_mkdir(char *longname)
815 {
816  union REGS regs;
817  struct SREGS sregs;
818  char FAR *lnptr;
819 
820  lnptr=(char FAR *)longname;
821  memset(&sregs, 0, sizeof(sregs));      /* BUG?! No register cleanup in ARJ */
822  sregs.ds=FP_SEG(lnptr); regs.x.dx=FP_OFF(lnptr);
823  return(call_dos_int(W95_MKDIR, &regs, &sregs)?-1:0);
824 }
825 #endif
826 
827 /* Remove a directory with longname. Return -1 if failed. */
828 
829 #if (SFX_LEVEL>=ARJ||defined(REARJ))&&TARGET==DOS
w95_rmdir(char * longname)830 static int w95_rmdir(char *longname)
831 {
832  union REGS regs;
833  struct SREGS sregs;
834  char FAR *lnptr;
835 
836  lnptr=(char FAR *)longname;
837  memset(&sregs, 0, sizeof(sregs));
838  sregs.ds=FP_SEG(lnptr); regs.x.dx=FP_OFF(lnptr);
839  return(call_dos_int(W95_RMDIR, &regs, &sregs)?-1:0);
840 }
841 #endif
842 
843 /* Delete a file */
844 
845 #if (SFX_LEVEL>=ARJSFX||defined(REARJ))&&TARGET==DOS
w95_unlink(char * longname)846 static int w95_unlink(char *longname)
847 {
848  union REGS regs;
849  struct SREGS sregs;
850  char FAR *lnptr;
851 
852  lnptr=(char FAR *)longname;
853  memset(&sregs, 0, sizeof(sregs));
854  sregs.ds=FP_SEG(lnptr); regs.x.dx=FP_OFF(lnptr);
855  #ifndef REARJ
856   regs.x.cx=FATTR_ARCH|FATTR_SYSTEM|FATTR_RDONLY;
857  #else
858   regs.x.cx=0;
859  #endif
860  regs.x.si=W95_WILDCARDS_DISABLED;      /* Forbid wildcard usage */
861  return(call_dos_int(W95_UNLINK, &regs, &sregs)?-1:0);
862 }
863 #endif
864 
865 /* Rename a file */
866 
867 #if (SFX_LEVEL>=ARJ||defined(REARJ))&&TARGET==DOS
w95_rename(char * longname1,char * longname2)868 static int w95_rename(char *longname1, char *longname2)
869 {
870  union REGS regs;
871  struct SREGS sregs;
872  char FAR *lnptr1, FAR *lnptr2;
873 
874  lnptr1=(char FAR *)longname1;
875  lnptr2=(char FAR *)longname2;
876  memset(&sregs, 0, sizeof(sregs));
877  sregs.ds=FP_SEG(lnptr1); regs.x.dx=FP_OFF(lnptr1);
878  sregs.es=FP_SEG(lnptr2); regs.x.di=FP_OFF(lnptr2);
879  return(call_dos_int(W95_RENAME, &regs, &sregs)?-1:0);
880 }
881 #endif
882 
883 /* Query or change attributes */
884 
885 #if (SFX_LEVEL>=ARJSFX||defined(REARJ))&&TARGET==DOS
w95_chmod(char * longname,int action,int pmode)886 static int w95_chmod(char *longname, int action, int pmode)
887 {
888  union REGS regs;
889  struct SREGS sregs;
890  char FAR *lnptr;
891 
892  lnptr=(char FAR *)longname;
893  memset(&sregs, 0, sizeof(sregs));
894  regs.x.bx=action;
895  regs.x.cx=pmode;
896  sregs.ds=FP_SEG(lnptr); regs.x.dx=FP_OFF(lnptr);
897  return(call_dos_int(W95_CHMOD, &regs, &sregs)?-1:regs.x.cx);
898 }
899 #endif
900 
901 /* access() function for LFNs - test if the file has the given access mode */
902 
903 #if (SFX_LEVEL>=ARJSFX||defined(REARJ))&&TARGET==DOS
w95_access(char * longname,int mode)904 static int w95_access(char *longname, int mode)
905 {
906  if((w95_chmod(longname, W95_GETATTR, 0))==-1)
907   return(-1);
908  else
909  {
910   if((!(mode&2))||!(mode&FATTR_RDONLY))
911    return(0);
912   else
913   {
914    errno=EACCES;
915    return(-1);
916   }
917  }
918 }
919 #endif
920 
921 /* findfirst() function as implemented in Borland Turbo C++ */
922 
923 #if (SFX_LEVEL>=ARJSFXV||defined(REARJ))&&TARGET==DOS
w95_findfirst(char * path,struct new_ffblk * new_ffblk,int attrib)924 static int w95_findfirst(char *path, struct new_ffblk *new_ffblk, int attrib)
925 {
926  union REGS regs;
927  struct SREGS sregs;
928  struct W95_FFBLK w95_ffblk, FAR *fb_ptr;
929  char FAR *p_ptr;
930 
931  memset(&sregs, 0, sizeof(sregs));
932  fb_ptr=(struct W95_FFBLK FAR *)&w95_ffblk;
933  p_ptr=(char FAR *)path;
934  sregs.ds=FP_SEG(p_ptr); regs.x.dx=FP_OFF(p_ptr);
935  sregs.es=FP_SEG(fb_ptr); regs.x.di=FP_OFF(fb_ptr);
936  regs.x.cx=attrib;
937  regs.x.si=W95_DT_DOS;                  /* Use DOS date/time format */
938  if(!call_dos_int(W95_FINDFIRST, &regs, &sregs))
939  {
940   #if SFX_LEVEL>=ARJ||defined(REARJ)
941    new_ffblk->ff_handle=regs.x.ax;      /* Preserve handle for findclose */
942    strcpy(new_ffblk->ff_name, w95_ffblk.ff_longname);
943    new_ffblk->ff_atime=w95_ffblk.ff_atime;
944    new_ffblk->ff_ctime=w95_ffblk.ff_ctime;
945   #endif
946   new_ffblk->ff_attrib=(char)w95_ffblk.ff_attrib;
947   new_ffblk->ff_ftime=w95_ffblk.ff_ftime;
948   new_ffblk->ff_fsize=w95_ffblk.ff_fsize;
949   #if SFX_LEVEL==ARJSFXV
950    memset(&sregs, 0, sizeof(sregs));
951    regs.x.bx=regs.x.ax;                 /* Transfer FF handle */
952    call_dos_int(W95_FINDCLOSE, &regs, &sregs);
953   #endif
954   return(0);
955  }
956  else
957   return(-1);
958 }
959 #endif
960 
961 /* findnext() function as implemented in Borland Turbo C++ */
962 
963 #if (SFX_LEVEL>=ARJ||defined(REARJ))&&TARGET==DOS
w95_findnext(struct new_ffblk * new_ffblk)964 static int w95_findnext(struct new_ffblk *new_ffblk)
965 {
966  union REGS regs;
967  struct SREGS sregs;
968  struct W95_FFBLK w95_ffblk, FAR *fb_ptr;
969 
970  memset(&sregs, 0, sizeof(sregs));
971  fb_ptr=(struct W95_FFBLK FAR *)&w95_ffblk;
972  sregs.es=FP_SEG(fb_ptr);
973  regs.x.di=FP_OFF(fb_ptr);
974  regs.x.bx=new_ffblk->ff_handle;
975  regs.x.si=W95_DT_DOS;                  /* Not present in original ARJ! */
976  if(!call_dos_int(W95_FINDNEXT, &regs, &sregs))
977  {
978   new_ffblk->ff_attrib=(char)w95_ffblk.ff_attrib;
979   strcpy(new_ffblk->ff_name, w95_ffblk.ff_longname);
980   new_ffblk->ff_ftime=w95_ffblk.ff_ftime;
981   new_ffblk->ff_atime=w95_ffblk.ff_atime;
982   new_ffblk->ff_ctime=w95_ffblk.ff_ctime;
983   new_ffblk->ff_fsize=w95_ffblk.ff_fsize;
984   return(0);
985  }
986  else
987   return(-1);
988 }
989 #endif
990 
991 /* Close search (specific to Windows 95) */
992 
993 #if (SFX_LEVEL>=ARJSFXV||defined(REARJ))&&TARGET==DOS
w95_findclose(struct new_ffblk * new_ffblk)994 static void w95_findclose(struct new_ffblk *new_ffblk)
995 {
996  union REGS regs;
997  struct SREGS sregs;
998 
999  memset(&sregs, 0, sizeof(sregs));
1000  regs.x.bx=new_ffblk->ff_handle;
1001  call_dos_int(W95_FINDCLOSE, &regs, &sregs);
1002 }
1003 #endif
1004 
1005 /* Create a file with the same options as given for _open, return handle */
1006 
1007 #if (SFX_LEVEL>=ARJSFX||defined(REARJ))&&TARGET==DOS
w95_creat(char * longname,int access)1008 static int w95_creat(char *longname, int access)
1009 {
1010  union REGS regs;
1011  struct SREGS sregs;
1012  char FAR *lnptr;
1013 
1014  lnptr=(char FAR *)longname;
1015  memset(&sregs, 0, sizeof(sregs));
1016  sregs.ds=FP_SEG(lnptr); regs.x.si=FP_OFF(lnptr);
1017  regs.x.bx=access&(O_RDONLY|O_WRONLY);
1018  regs.x.cx=32;
1019  regs.x.dx=0;
1020  regs.x.di=1;
1021  /* Translate FCNTL actions into Win95 actions */
1022  if(access&O_CREAT) regs.x.dx|=W95_A_CREAT;
1023  if(access&O_TRUNC) regs.x.dx|=W95_A_TRUNC;
1024  if(access&O_EXCL) regs.x.dx|=W95_A_EXCL;
1025  return(call_dos_int(W95_OPEN, &regs, &sregs)?-1:regs.x.ax);
1026 }
1027 #endif
1028 
1029 /* Stamp date/time of last access on handle. Note that Win95 does not support
1030    time of last access. */
1031 
1032 #if (SFX_LEVEL>=ARJSFXV)&&TARGET==DOS
w95_set_dta(int handle,unsigned long ftime)1033 static int w95_set_dta(int handle, unsigned long ftime)
1034 {
1035  union REGS regs;
1036  struct SREGS sregs;
1037 
1038  memset(&sregs, 0, sizeof(sregs));
1039  regs.x.bx=handle;
1040  regs.x.cx=0;
1041  regs.x.dx=(unsigned short)ftime>>16;
1042  return(call_dos_int(W95_SET_DTA, &regs, &sregs)?-1:0);
1043 }
1044 #endif
1045 
1046 /* Stamp date/time of last access on handle. Note that Win95 does not support
1047    time of last access. */
1048 
1049 #if (SFX_LEVEL>=ARJSFXV)&&TARGET==DOS
w95_set_dtc(int handle,unsigned long ftime)1050 static int w95_set_dtc(int handle, unsigned long ftime)
1051 {
1052  union REGS regs;
1053  struct SREGS sregs;
1054 
1055  memset(&sregs, 0, sizeof(sregs));
1056  regs.x.bx=handle;
1057  regs.x.cx=(unsigned short)(ftime%65536L);
1058  regs.x.dx=(unsigned short)ftime>>16;
1059  regs.x.si=0;                           /* Number of 1/100ths */
1060  return(call_dos_int(W95_SET_DTC, &regs, &sregs)?-1:0);
1061 }
1062 #endif
1063 
1064 /*
1065  * Now, some less OS-dependent routines.
1066  */
1067 
1068 /* Return pointer to first character following a drivespec/relative pathspec
1069    so names like "\VIRUS.COM" will be transformed to safe "VIRUS.COM" */
1070 
1071 #if SFX_LEVEL>=ARJSFX
1072 #if SFX_LEVEL>=ARJSFXV
validate_path(char * name,int action)1073 static char *validate_path(char *name, int action)
1074 #else
1075 static char *validate_path(char *name)
1076 #endif
1077 {
1078 #if SFX_LEVEL>=ARJSFXV
1079  if(action!=VALIDATE_NOTHING)
1080  {
1081 #endif
1082 #ifdef HAVE_DRIVES
1083   if(name[0]!='\0'&&name[1]==':')
1084    name+=2;                             /* Skip over drivespecs */
1085 #endif
1086 #if SFX_LEVEL>=ARJSFXV
1087   if(action!=VALIDATE_DRIVESPEC)
1088   {
1089 #endif
1090    while (name[0]!='\0'&&
1091           (name[0]=='.'||name[0]==PATHSEP_DEFAULT||name[0]==PATHSEP_UNIX)) {
1092    if(name[0]=='.')
1093    {
1094     if(name[1]=='.'&&(name[2]==PATHSEP_DEFAULT||name[2]==PATHSEP_UNIX))
1095      name++;                            /* "..\\" relative path */
1096     if(name[1]==PATHSEP_DEFAULT||name[1]==PATHSEP_UNIX)
1097      name++;                            /* ".\\" relative path */
1098    }
1099    if(name[0]==PATHSEP_DEFAULT||name[0]==PATHSEP_UNIX)
1100     name++;                             /* "\\" - revert to root */
1101    }
1102 #if SFX_LEVEL>=ARJSFXV
1103   }
1104  }
1105 #endif
1106  return(name);
1107 }
1108 #endif
1109 
1110 /* Convert the extended finddata record to OS-independent internal storage
1111    format */
1112 
1113 #if SFX_LEVEL>=ARJ
finddata_to_properties(struct file_properties * properties,struct new_ffblk * new_ffblk)1114 static void finddata_to_properties(struct file_properties *properties, struct new_ffblk *new_ffblk)
1115 {
1116  #if TARGET==UNIX
1117   int u;
1118  #endif
1119 
1120  properties->ftime=new_ffblk->ff_ftime;
1121  properties->atime=new_ffblk->ff_atime;
1122  properties->ctime=new_ffblk->ff_ctime;
1123  properties->fsize=new_ffblk->ff_fsize;
1124  properties->attrib=(ATTRIB)new_ffblk->ff_attrib;
1125  #if TARGET!=UNIX
1126   properties->type=(new_ffblk->ff_attrib&FATTR_DIREC)?ARJT_DIR:ARJT_BINARY;
1127   properties->isarchive=(new_ffblk->ff_attrib&FATTR_ARCH)?1:0;
1128  #else
1129   u=uftype(new_ffblk->ff_attrib);
1130   if(u&FATTR_DT_DIR)
1131    properties->type=ARJT_DIR;
1132   else if(u&FATTR_DT_UXSPECIAL)
1133    properties->type=ARJT_UXSPECIAL;
1134   else
1135    properties->type=ARJT_BINARY;
1136   /* Can't check fot non-DT_REG since these may be requested by find_file() */
1137   properties->isarchive=1;
1138   /* Hardlink data */
1139   properties->l_search=new_ffblk->l_search;
1140   properties->l_search.ref=0;
1141   properties->islink=0;
1142  #endif
1143 }
1144 #endif
1145 
1146 /* Return pointer to the first path delimiter in given string, or NULL if
1147    nothing found */
1148 
1149 #if SFX_LEVEL>=ARJSFX
find_delimiter(char * path,int datatype)1150 static char *find_delimiter(char *path, int datatype)
1151 {
1152  if(path[0]=='\0')
1153   return(NULL);
1154  while(path[0]!='\0')
1155  {
1156   if(path[0]==PATHSEP_DEFAULT||path[0]==PATHSEP_UNIX)
1157    return(path);
1158   path++;
1159  }
1160  if(datatype==ARJT_DIR)
1161   return(path);
1162  else
1163   return(NULL);
1164 }
1165 #endif
1166 
1167 /*
1168  * Secondary-level file management routines. Usually they must either be
1169  * redirected to Win95 LFN API, or serviced with the C RTL functions.
1170  */
1171 
1172 /* chmod() - Borland's implementation */
1173 
1174 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
file_chmod(char * name,int action,int attrs)1175 int file_chmod(char *name, int action, int attrs)
1176 {
1177  #if TARGET==DOS
1178   if(lfn_supported!=LFN_NOT_SUPPORTED)
1179    return(w95_chmod(name, action, attrs));
1180   else
1181   #if COMPILER==BCC
1182    return(_chmod(name, action, attrs));
1183   #elif COMPILER==MSC
1184    {
1185     int rc;
1186 
1187     if(action)
1188      return(_dos_setfileattr(name, attrs));
1189     else
1190     {
1191      rc=-1;
1192      _dos_getfileattr(name, &rc);
1193      return(rc);
1194     }
1195    }
1196   #endif
1197  #elif TARGET==OS2
1198   #ifdef __32BIT__
1199    FILESTATUS3 fstatus;
1200    int rc;
1201 
1202    rc=DosQueryPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus));
1203    if(action)
1204    {
1205     fstatus.attrFile=attrs;
1206     return(DosSetPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0)?-1:0);
1207    }
1208    else
1209     return(rc?-1:fstatus.attrFile);
1210   #else
1211    USHORT rc;
1212 
1213    if(action)
1214     return(DosSetFileMode(name, attrs, 0L)?-1:0);
1215    else
1216     return(DosQFileMode(name, &rc, 0L)?-1:rc);
1217   #endif
1218  #elif TARGET==WIN32
1219   DWORD rc;
1220 
1221   if(!action)
1222   {
1223    rc=GetFileAttributes(name);
1224    if(rc==0xFFFFFFFF)
1225     return(-1);
1226    else
1227     return((int)rc);
1228   }
1229   else
1230    return(!SetFileAttributes(name, attrs));
1231  #else
1232   struct stat st;
1233 
1234   if(action)
1235   {
1236    if(!lstat(name, &st)&&S_ISLNK(st.st_mode))
1237     return(0);                          /* ASR fix 15/06/2003: don't touch symlinks anymore */
1238    else
1239     return(chmod(name, attrs));
1240   }
1241   else
1242    return(lstat(name, &st)?-1:st.st_mode);
1243  #endif
1244 }
1245 #endif
1246 
1247 /* Manages the access rights for a stream - required to handle the
1248    SFX archives properly */
1249 
1250 #if SFX_LEVEL>=ARJ&&TARGET==UNIX
file_acc(FILE * stream)1251 int file_acc(FILE *stream)
1252 {
1253  struct stat st;
1254 
1255  return(fstat(fileno(stream), &st)?-1:st.st_mode);
1256 }
1257 
1258 /* Duplicates the "R" access bits into "X" for creating a SFX */
1259 
make_executable(FILE * stream)1260 void make_executable(FILE *stream)
1261 {
1262  int stm;
1263 
1264  stm=file_acc(stream);
1265  fchmod(fileno(stream), stm|((stm>>2)&0111));
1266 }
1267 
1268 #endif
1269 
1270 /* access() */
1271 
1272 #if SFX_LEVEL>=ARJSFX||defined(REARJ)||defined(REGISTER)
file_access(char * name,int mode)1273 static int file_access(char *name, int mode)
1274 {
1275  #if TARGET==DOS
1276   #ifndef REGISTER
1277    if(lfn_supported!=LFN_NOT_SUPPORTED)
1278     return(w95_access(name, mode));
1279    else
1280   #endif
1281    return(access(name, mode));
1282  #elif TARGET==OS2||TARGET==WIN32||TARGET==UNIX
1283   return(access(name, mode));
1284  #else
1285   #error No access() defined
1286  #endif
1287 }
1288 #endif
1289 
1290 #if TARGET==UNIX&&(SFX_LEVEL>=ARJSFXV||defined(REARJ))
1291 
1292 /* Locates the first matching dirent, like findnext() but for the first dirent
1293    as well (the UNIX-way). May trash the new_ffblk structures without returning
1294    success, but who cares? */
1295 
roll_dirent(struct new_ffblk * new_ffblk)1296 static int roll_dirent(struct new_ffblk *new_ffblk)
1297 {
1298  struct dirent *ent;
1299  int a, l, m;
1300  struct stat st, resolved_st;
1301  int attrs;
1302  dev_t real_dev;
1303  ino_t real_inode;
1304 
1305  a=ufattr(attrs=new_ffblk->attrs);
1306  strcpy(new_ffblk->ff_name, new_ffblk->dir);
1307  if(!strcmp(new_ffblk->ff_name, cur_dir_spec))
1308   new_ffblk->ff_name[l=0]='\0';
1309  else
1310  {
1311   l=strlen(new_ffblk->ff_name);
1312   if(l==0||new_ffblk->ff_name[l-1]!=PATHSEP_DEFAULT)
1313    new_ffblk->ff_name[l++]=PATHSEP_DEFAULT;
1314  }
1315  /* Now, check all files until we find the matching one */
1316  while((ent=readdir(new_ffblk->ff_handle))!=NULL)
1317  {
1318   strcpy(new_ffblk->ff_name+l, ent->d_name);
1319   if(a!=0)
1320    m=match_unix_attrs(file_chmod(new_ffblk->ff_name, 0, 0), a);
1321   else
1322    m=1;
1323   /* Wildcard matching and attribute check */
1324   if(m&&match_wildcard(ent->d_name, new_ffblk->wildcard))
1325   {
1326    if(lstat(new_ffblk->ff_name, &st))
1327     return(-1);
1328    real_dev=st.st_dev;
1329    real_inode=st.st_ino;
1330 #if SFX_LEVEL>=ARJ
1331    /* Search in the device pool to see if the user forbids archiving for
1332       this device */
1333    if(!is_dev_allowed(real_dev))
1334     continue;
1335 #endif
1336    /* Redo stat if it's a link and we do not handle links (so need it to be
1337       resolved) */
1338    if(!(attrs&FATTR_DT_UXSPECIAL)&&stat(new_ffblk->ff_name, &st))
1339     continue;
1340    /* Sockets aren't supported, check for other types as well */
1341 #if !defined(S_ISSOCK)
1342 #define S_ISSOCK(m)  0
1343 #endif
1344    if(!S_ISSOCK(st.st_mode)&&
1345       (((uftype(attrs)==FATTR_DT_ANY||(uftype(attrs)&FATTR_DT_REG))&&S_ISREG(st.st_mode))||
1346        ((attrs&FATTR_DT_DIR)&&S_ISDIR(st.st_mode))||
1347        (attrs&FATTR_DT_UXSPECIAL)))
1348    {
1349     /* Reestablish the "unqualified" filename */
1350     strcpy(new_ffblk->ff_name, ent->d_name);
1351     /* If it was a link, try to retrieve the mode of file which it points to.
1352        Otherwise, chmod() will trash the mode of original file upon restore */
1353     if(S_ISLNK(st.st_mode)&&stat(new_ffblk->ff_name, &resolved_st)!=-1)
1354     {
1355      new_ffblk->ff_attrib=resolved_st.st_mode&FATTR_UFMASK;
1356      real_dev=resolved_st.st_dev;
1357      real_inode=resolved_st.st_ino;
1358     }
1359     else
1360      new_ffblk->ff_attrib=st.st_mode&FATTR_UFMASK;
1361     /* Convert the remaining structures to new_ffblk and leave the search */
1362     new_ffblk->ff_ftype=st.st_mode;
1363     if(S_ISREG(st.st_mode))
1364      new_ffblk->ff_attrib|=FATTR_DT_REG;
1365     else if(S_ISDIR(st.st_mode))
1366      new_ffblk->ff_attrib|=FATTR_DT_DIR;
1367     else
1368      new_ffblk->ff_attrib|=FATTR_DT_UXSPECIAL;
1369     new_ffblk->ff_ftime=st.st_mtime;
1370     /* Prevent REARJ from complaining about directory size mismatch */
1371     new_ffblk->ff_fsize=(S_ISREG(st.st_mode))?st.st_size:0;
1372     new_ffblk->ff_atime=st.st_atime;
1373     new_ffblk->ff_ctime=st.st_ctime;
1374     /* Special structures for hard links */
1375     new_ffblk->l_search.dev=real_dev;
1376     new_ffblk->l_search.inode=real_inode;
1377     new_ffblk->l_search.refcount=S_ISDIR(st.st_mode)?1:st.st_nlink;
1378     break;
1379    }
1380   }
1381  }
1382  return(ent==NULL?-1:0);
1383 }
1384 
1385 #endif
1386 
1387 #if TARGET==WIN32
1388 
1389 /* Strip NT timestamps -> DOS timestamps */
1390 
1391 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
dosify_time(FILETIME * pft)1392 static unsigned long dosify_time(FILETIME *pft)
1393 {
1394  FILETIME lft;
1395  WORD dd=0x1111, dt=0x1111;
1396 
1397  FileTimeToLocalFileTime(pft, &lft);
1398  FileTimeToDosDateTime(&lft, &dd, &dt);
1399  return(make_ftime(dd, dt));
1400 }
1401 #endif
1402 
1403 /* Expand DOS timestamps into NT UTC timestamps */
1404 
1405 #if SFX_LEVEL>=ARJSFXJR||defined(REARJ)
ntify_time(FILETIME * pft,unsigned long dft)1406 static void ntify_time(FILETIME *pft, unsigned long dft)
1407 {
1408  FILETIME lft;
1409 
1410  DosDateTimeToFileTime((WORD)(dft>>16), (WORD)(dft&0xFFFF), &lft);
1411  LocalFileTimeToFileTime(&lft, pft);
1412 }
1413 #endif
1414 
1415 #endif
1416 
1417 /* findfirst() - Borland's implementation */
1418 
1419 #if SFX_LEVEL>=ARJSFXV||defined(REARJ)
lfn_findfirst(char * path,struct new_ffblk * new_ffblk,int attrib)1420 int lfn_findfirst(char *path, struct new_ffblk *new_ffblk, int attrib)
1421 {
1422  #if TARGET==DOS
1423   /* ASR fix 04/09/2001 for the R11 timestamp format */
1424   new_ffblk->ff_atime=new_ffblk->ff_ctime=0;
1425   if(lfn_supported==LFN_SUPPORTED)
1426    return(w95_findfirst(path, new_ffblk, attrib));
1427   else
1428    #if COMPILER==BCC
1429     return(findfirst(path, (struct ffblk *)new_ffblk, attrib));
1430    #elif COMPILER==MSC
1431     return(_dos_findfirst(path, attrib, (struct find_t *)new_ffblk));
1432    #endif
1433  #elif TARGET==OS2
1434   HDIR handle=HDIR_CREATE;
1435   #ifdef __32BIT__
1436    FILEFINDBUF3 findbuf;
1437    ULONG fcount=1L;
1438   #else
1439    FILEFINDBUF findbuf;
1440    USHORT fcount=1;
1441   #endif
1442 
1443   #ifdef __32BIT__
1444    if(DosFindFirst(path, &handle, attrib, &findbuf, sizeof(findbuf), &fcount, FIL_STANDARD))
1445     return(-1);
1446   #else
1447    if(DosFindFirst(path, &handle, attrib, &findbuf, sizeof(findbuf), &fcount, 0L))
1448     return(-1);
1449   #endif
1450   /* Do the conversion */
1451   new_ffblk->ff_attrib=findbuf.attrFile;
1452   new_ffblk->ff_ftime=make_ftime(findbuf.fdateLastWrite, findbuf.ftimeLastWrite);
1453   new_ffblk->ff_fsize=findbuf.cbFile;
1454   strcpy(new_ffblk->ff_name, findbuf.achName);
1455   new_ffblk->ff_atime=make_ftime(findbuf.fdateLastAccess, findbuf.ftimeLastAccess);
1456   new_ffblk->ff_ctime=make_ftime(findbuf.fdateCreation, findbuf.ftimeCreation);
1457   #if SFX_LEVEL<=ARJSFXV&&!defined(REARJ)
1458    DosFindClose(handle);
1459   #else
1460    new_ffblk->ff_handle=handle;
1461   #endif
1462   return(0);
1463  #elif TARGET==WIN32
1464   WIN32_FIND_DATA wfd;
1465   HANDLE hf;
1466 
1467   if((hf=FindFirstFile(path, &wfd))==INVALID_HANDLE_VALUE)
1468    return(-1);
1469   if(wfd.nFileSizeHigh>0||(long)wfd.nFileSizeLow<0)
1470    return(-1);
1471   new_ffblk->ff_attrib=wfd.dwFileAttributes;
1472   new_ffblk->ff_ftime=dosify_time(&wfd.ftLastWriteTime);
1473   new_ffblk->ff_atime=dosify_time(&wfd.ftLastAccessTime);
1474   new_ffblk->ff_ctime=dosify_time(&wfd.ftCreationTime);
1475   new_ffblk->ff_fsize=wfd.nFileSizeLow;
1476   strcpy(new_ffblk->ff_name, wfd.cFileName);
1477   #if SFX_LEVEL<=ARJSFXV&&!defined(REARJ)
1478    FindClose(hf);
1479   #else
1480    new_ffblk->ff_handle=hf;
1481   #endif
1482   return(0);
1483  #elif TARGET==UNIX
1484   split_name(path, new_ffblk->dir, new_ffblk->wildcard);
1485   if(new_ffblk->wildcard[0]=='\0')
1486    strcpy(new_ffblk->wildcard, all_wildcard);
1487   if(new_ffblk->dir[0]=='\0')
1488    strcpy(new_ffblk->dir, cur_dir_spec);
1489   if((new_ffblk->ff_handle=opendir(new_ffblk->dir))==NULL)
1490    return(-1);
1491   new_ffblk->attrs=attrib;
1492   if(roll_dirent(new_ffblk)==-1)
1493   {
1494    closedir(new_ffblk->ff_handle);
1495    new_ffblk->ff_handle=NULL;           /* Invalidate the new_ffblk */
1496    return(-1);
1497   }
1498   #if SFX_LEVEL<=ARJSFXV&&!defined(REARJ)
1499    closedir(new_ffblk->ff_handle);
1500   #endif
1501   return(0);
1502  #endif
1503 }
1504 #endif
1505 
1506 /* findnext() - Borland's implementation */
1507 
1508 #if SFX_LEVEL>=ARJ||defined(REARJ)
lfn_findnext(struct new_ffblk * new_ffblk)1509 int lfn_findnext(struct new_ffblk *new_ffblk)
1510 {
1511  #if TARGET==DOS
1512   if(lfn_supported==LFN_SUPPORTED)
1513    return(w95_findnext(new_ffblk));
1514   else
1515    #if COMPILER==BCC
1516     return(findnext((struct ffblk *)new_ffblk));
1517    #elif COMPILER==MSC
1518     return(_dos_findnext((struct find_t *)new_ffblk));
1519    #endif
1520  #elif TARGET==OS2
1521   HDIR handle;
1522   #ifdef __32BIT__
1523    FILEFINDBUF3 findbuf;
1524    ULONG fcount=1L;
1525   #else
1526    FILEFINDBUF findbuf;
1527    USHORT fcount=1;
1528   #endif
1529 
1530   handle=new_ffblk->ff_handle;
1531   if(DosFindNext(handle, &findbuf, sizeof(findbuf), &fcount))
1532    return(-1);
1533   /* Do the conversion */
1534   new_ffblk->ff_attrib=findbuf.attrFile;
1535   new_ffblk->ff_ftime=make_ftime(findbuf.fdateLastWrite, findbuf.ftimeLastWrite);
1536   new_ffblk->ff_fsize=findbuf.cbFile;
1537   strcpy(new_ffblk->ff_name, findbuf.achName);
1538   new_ffblk->ff_atime=make_ftime(findbuf.fdateLastAccess, findbuf.ftimeLastAccess);
1539   new_ffblk->ff_ctime=make_ftime(findbuf.fdateCreation, findbuf.ftimeCreation);
1540   return(0);
1541  #elif TARGET==WIN32
1542   WIN32_FIND_DATA wfd;
1543 
1544   if(!FindNextFile(new_ffblk->ff_handle, &wfd))
1545    return(-1);
1546   if(wfd.nFileSizeHigh>0||(long)wfd.nFileSizeLow<0)
1547    return(-1);
1548   new_ffblk->ff_attrib=wfd.dwFileAttributes;
1549   new_ffblk->ff_ftime=dosify_time(&wfd.ftLastWriteTime);
1550   new_ffblk->ff_atime=dosify_time(&wfd.ftLastAccessTime);
1551   new_ffblk->ff_ctime=dosify_time(&wfd.ftCreationTime);
1552   new_ffblk->ff_fsize=wfd.nFileSizeLow;
1553   strcpy(new_ffblk->ff_name, wfd.cFileName);
1554   return(0);
1555  #elif TARGET==UNIX
1556   if(roll_dirent(new_ffblk)==-1)
1557    return(-1);
1558   return(0);
1559  #endif
1560 }
1561 #endif
1562 
1563 /* findclose() */
1564 
1565 #if SFX_LEVEL>=ARJ||defined(REARJ)
lfn_findclose(struct new_ffblk * new_ffblk)1566 void lfn_findclose(struct new_ffblk *new_ffblk)
1567 {
1568  #if TARGET==DOS
1569   if(lfn_supported==LFN_SUPPORTED)
1570    w95_findclose(new_ffblk);
1571  #elif TARGET==OS2
1572   DosFindClose(new_ffblk->ff_handle);
1573  #elif TARGET==WIN32
1574   FindClose(new_ffblk->ff_handle);
1575  #elif TARGET==UNIX
1576   if(new_ffblk->ff_handle!=NULL)
1577    closedir(new_ffblk->ff_handle);
1578   new_ffblk->ff_handle=NULL;    /* Invalidate it! */
1579  #endif
1580 }
1581 #endif
1582 
1583 /* Convert the given symbols to upper case, depending on locale */
1584 
1585 #if SFX_LEVEL>=ARJSFXV||defined(REARJ)
toupper_loc(unsigned char * ptr,int length)1586 void toupper_loc(unsigned char *ptr, int length)
1587 {
1588  #if TARGET==DOS&&defined(ASM8086)
1589   struct
1590   {
1591    int co_date;
1592    char co_curr[5];
1593    char co_thsep[2];
1594    char co_desep[2];
1595    char co_dtsep[2];
1596    char co_tmsep[2];
1597    char co_currstyle;
1598    char co_digits;
1599    char co_time;
1600    long co_case;
1601    char co_dasep[2];
1602    char co_fill[10];
1603   } cty;
1604   static int cty_state=0;                /* 0 if not queried yet */
1605   static char((FAR *ctycnv)());          /* Case map routine */
1606   union REGS regs;
1607   char c;
1608 
1609   if(cty_state==0)
1610   {
1611    cty_state=-1;
1612    if(_osmajor>=3)
1613    {
1614     regs.x.dx=(unsigned int)&cty;
1615     regs.x.ax=0x3800;
1616     intdos(&regs, &regs);
1617     if(!regs.x.cflag)
1618     {
1619      cty_state=1;                        /* Accept any further calls */
1620      ctycnv=(char (FAR *)())cty.co_case;
1621     }
1622    }
1623   }
1624   if(cty_state>0)
1625   {
1626    while(length>0)
1627    {
1628     if(ptr[0]>='a'&&ptr[0]<='z')
1629      ptr[0]-=0x20;                       /* Convert to upper case */
1630     else
1631      if(ptr[0]>=0x80)
1632      {
1633       c=ptr[0];
1634       asm mov al, c;
1635       ctycnv();
1636       asm mov c, al;
1637       ptr[0]=c;
1638      }
1639     ptr++;
1640     length--;
1641    }
1642   }
1643   else
1644   {
1645    while(length>0)
1646    {
1647     if(ptr[0]>='a'&&ptr[0]<='z')
1648      ptr[0]-=('a'-'A');                  /* Convert to upper case */
1649     ptr++;
1650     length--;
1651    }
1652   }
1653  #elif TARGET==OS2
1654   COUNTRYCODE cc;
1655 
1656   cc.country=cc.codepage=0;
1657   DosCaseMap(length, &cc, ptr);
1658  #else
1659   unsigned char x;
1660 
1661   /* ASR fix 10/04/2002: this fixes a GCC v 3.0 optimization bug */
1662   while(length-->0)
1663   {
1664    x=*ptr;
1665    *ptr++=toupper(x);
1666   }
1667  #endif
1668 }
1669 #endif
1670 
1671 /* Sums two unixtime values (for systems with different implementation of
1672    time_t and for Year 2106 compliance) */
1673 
1674 #if SFX_LEVEL>=ARJ
sum_time(time_t t1,time_t t2)1675 time_t sum_time(time_t t1, time_t t2)
1676 {
1677  return(t1+t2);
1678 }
1679 #endif
1680 
1681 /* Subtracts two unixtime values (for systems with different implementation of
1682    time_t and for Year 2106 compliance) */
1683 
1684 #ifdef REARJ
sub_time(time_t t1,time_t t2)1685 time_t sub_time(time_t t1, time_t t2)
1686 {
1687  return(t1-t2);
1688 }
1689 #endif
1690 
1691 /* Depending of LFN support, converts the path specification to UPPERCASE */
1692 
1693 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
case_path(char * s)1694 void case_path(char *s)
1695 {
1696  #if TARGET==DOS
1697   if(lfn_supported==LFN_NOT_SUPPORTED)
1698    strupper(s);
1699  #else
1700   /* Case-preserving or case-sensitive systems have nothing to do here */
1701  #endif
1702 }
1703 #endif
1704 
1705 /* Looks for duplicate drive specifications in the arguments, returns 1 if
1706    found one, or 0 if none were found. */
1707 
1708 #if SFX_LEVEL>=ARJ&&TARGET!=UNIX
find_dupl_drivespecs(char ** argtable,int args)1709 int find_dupl_drivespecs(char **argtable, int args)
1710 {
1711  int cur_arg, cx_arg;
1712 
1713  if(args<=1)
1714  {
1715   if(listchars_allowed==0||argtable[0][0]!=listchar)
1716    return(0);
1717   else
1718    return(1);
1719  }
1720  else
1721  {
1722   for(cur_arg=0; cur_arg<args; cur_arg++)
1723   {
1724    if(argtable[cur_arg][1]!=':'&&strcmp(argtable[cur_arg], nonexist_name))
1725     return(1);
1726   }
1727   for(cur_arg=0; cur_arg<args; cur_arg++)
1728    for(cx_arg=0; cx_arg<args; cx_arg++)
1729    {
1730     if(cx_arg!=cur_arg)
1731     {
1732      if(argtable[cx_arg][0]==argtable[cur_arg][0])
1733       return(1);
1734     }
1735    }
1736   return(0);
1737  }
1738 }
1739 #endif
1740 
1741 /* Returns 0 if monopolized R/O access to the file can be granted, -1 if not */
1742 
1743 #if SFX_LEVEL>=ARJSFXV
file_test_access(char * name)1744 int file_test_access(char *name)
1745 {
1746  #if TARGET==DOS
1747   char tmp_name[CCHMAXPATH];
1748  #endif
1749  int handle;
1750 
1751  #if TARGET==DOS
1752   if(_osmajor>=3&&!disable_sharing)
1753   {
1754    strcpy(tmp_name, name);
1755    if(lfn_supported!=LFN_NOT_SUPPORTED)
1756     w95_get_shortname(name, tmp_name, sizeof(tmp_name));
1757    #if COMPILER==BCC
1758     if((handle=_open(tmp_name, O_BINARY|O_DENYALL|O_RDONLY))==-1)
1759      return(-1);
1760    #elif COMPILER==MSC
1761     if((handle=sopen(tmp_name, O_BINARY|O_RDONLY, SH_DENYRW))==-1)
1762      return(-1);
1763    #endif
1764    close(handle);
1765   }
1766   return(0);
1767  #elif TARGET==OS2||TARGET==WIN32
1768   if((handle=sopen(name, O_BINARY|O_RDONLY, SH_DENYRW))==-1)
1769    return(-1);
1770   close(handle);
1771   return(0);
1772  #elif TARGET==UNIX
1773   struct flock flk;
1774   int rc;
1775 
1776   if((handle=open(name, O_RDONLY))==-1)
1777    return(-1);
1778   memset(&flk, 0, sizeof(flk));
1779   rc=fcntl(handle, F_GETLK, &flk);
1780   close(handle);
1781   return(((rc==-1&&errno!=EINVAL)||(rc!=1&&flk.l_type==F_RDLCK))?-1:0);
1782  #endif
1783 }
1784 #endif
1785 
1786 /* Detect long filename support */
1787 
1788 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
detect_lfns()1789 int detect_lfns()
1790 {
1791  #if TARGET==DOS
1792   if(_osmajor<7)
1793    return(lfn_supported=0);
1794   else
1795    return(lfn_supported=w95_test_for_lfn(drive_c));
1796  #else
1797   return(lfn_supported=1);              /* Setting to 0 will disable DTA/DTC
1798                                            handling! */
1799  #endif
1800 }
1801 #endif
1802 
1803 /* Detect extended attribute support */
1804 
1805 #if SFX_LEVEL>=ARJSFXV
detect_eas()1806 int detect_eas()
1807 {
1808  #if TARGET==OS2
1809   ea_supported=1;
1810  #elif TARGET==WIN32
1811   OSVERSIONINFO osvi;
1812 
1813   osvi.dwOSVersionInfoSize=sizeof(osvi);
1814   GetVersionEx(&osvi);
1815   return(ea_supported=(osvi.dwPlatformId==VER_PLATFORM_WIN32_NT));
1816  #else
1817   ea_supported=0;
1818  #endif
1819  return(ea_supported);
1820 }
1821 #endif
1822 
1823 /* Null subroutine for compiler bugs */
1824 
nullsub(int arg,...)1825 void nullsub(int arg, ...)
1826 {
1827 }
1828 
1829 /* Delay */
1830 
1831 #if SFX_LEVEL>=ARJSFX||defined(REARJ)||defined(REGISTER)||defined(ARJDISP)
arj_delay(unsigned int seconds)1832 void arj_delay(unsigned int seconds)
1833 {
1834  #if TARGET==DOS
1835   #if COMPILER==MSC
1836    long c_time, e_time, t_time;
1837 
1838    /* This is inappropriate for some rare machines with non-standard timer
1839       arrangement, e.g. Tandy 2000 but at least it doesn't involve
1840       reprogramming the timer ports. */
1841    e_time=(long)seconds*182L/10L;
1842    while(e_time--)
1843    {
1844     g_timer(t_time);
1845     c_time=t_time;
1846     do
1847     {
1848      g_timer(c_time);
1849     } while(c_time==t_time);
1850    }
1851   #else
1852    sleep(seconds);
1853   #endif
1854  #elif TARGET==OS2
1855   DosSleep(seconds*1000L);
1856  #elif TARGET==WIN32
1857   Sleep(seconds*1000L);
1858  #else
1859   sleep(seconds);
1860  #endif
1861 }
1862 #endif
1863 
1864 /* Collect memory statistics (for debugging purposes) */
1865 
1866 #if SFX_LEVEL>=ARJSFXV
mem_stats()1867 void mem_stats()
1868 {
1869  if(debug_enabled&&strchr(debug_opt, 'v')!=NULL)
1870  {
1871   #if SFX_LEVEL>=ARJ
1872    msg_cprintf(0, M_MEMSTATS, coreleft(), verify_heap(), farcoreleft(), verify_far_heap(), get_stack_space());
1873   #else
1874    msg_cprintf(0, M_MEMSTATS, coreleft(), farcoreleft());
1875   #endif
1876  }
1877 }
1878 #endif
1879 
1880 /* Interrupt 24h handler */
1881 
1882 #if SFX_LEVEL>=ARJSFXV&&TARGET==DOS
1883 #if COMPILER==BCC
int24_fatal_handler(unsigned int bp,unsigned int di,unsigned int si,unsigned int ds,unsigned int es,unsigned int dx,unsigned int cx,unsigned int bx,unsigned int ax)1884 void interrupt int24_fatal_handler(unsigned int bp, unsigned int di,
1885                                    unsigned int si, unsigned int ds,
1886                                    unsigned int es, unsigned int dx,
1887                                    unsigned int cx, unsigned int bx,
1888                                    unsigned int ax)
1889 #elif COMPILER==MSC
1890 void _interrupt _far int24_fatal_handler( unsigned int es, unsigned int ds,
1891                                             unsigned int di, unsigned int si,
1892                                             unsigned int bp, unsigned int sp,
1893                                             unsigned int bx, unsigned int dx,
1894                                             unsigned int cx, unsigned int ax,
1895                                             unsigned int ip, unsigned int cs,
1896                                             unsigned int flags)
1897 #endif
1898 {
1899  ax=INT24_FAIL;
1900 }
1901 #endif
1902 
1903 /* Check for the existence of file given; INT 24h handler is reset to ensure
1904    that the FAIL action is automatically generated instead of prompting the
1905    user for action. */
1906 
1907 #if SFX_LEVEL>=ARJSFX||defined(REARJ)||defined(REGISTER)
file_exists(char * name)1908 int file_exists(char *name)
1909 {
1910  int rc;
1911 
1912  #if TARGET==DOS
1913   #if COMPILER==BCC
1914    void interrupt (*oldhdl)();
1915   #elif COMPILER==MSC
1916    void (_interrupt _far *oldhdl)();
1917   #endif
1918 
1919   #if SFX_LEVEL>=ARJSFXV
1920    if(is_dos_31)
1921     rc=file_access(name, 0);
1922    else
1923    {
1924     oldhdl=getvect(INT24);
1925     setvect(INT24, int24_fatal_handler);
1926     rc=file_access(name, 0);
1927     setvect(INT24, oldhdl);
1928    }
1929   #else
1930    rc=file_access(name, 0);
1931   #endif
1932  #elif TARGET==OS2
1933   rc=file_access(name, 0);
1934  #else
1935   rc=file_access(name, F_OK);
1936  #endif
1937  return(!rc);
1938 }
1939 #endif
1940 
1941 /* An extended fopen that supports long filenames and uses sharing. */
1942 
1943 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
file_open(char * name,char * mode)1944 FILE *file_open(char *name, char *mode)
1945 {
1946  #if TARGET==DOS
1947   char tmp_name[CCHMAXPATH];
1948  #endif
1949  #if SFX_LEVEL>=ARJSFXV
1950   char tmp_mode[10];
1951  #endif
1952  #if COMPILER!=BCC&&SFX_LEVEL>=ARJSFXV
1953   int shflag;
1954  #endif
1955  #if SFX_LEVEL>=ARJSFXV||TARGET==DOS
1956   int handle;
1957  #endif
1958  #if SFX_LEVEL>=ARJSFXV
1959   int oflag;
1960  #endif
1961 
1962  #if TARGET==DOS
1963   strcpy(tmp_name, name);
1964   if(lfn_supported!=LFN_NOT_SUPPORTED)
1965   {
1966    if(strchr(mode, 'a')!=NULL||strchr(mode, 'w')!=NULL)
1967    {
1968     if(w95_access(name, 0))
1969     {
1970      /* If the file does not exist, continue here, otherwise get its short
1971         name and process with fopen. */
1972      if((handle=w95_creat(name, O_CREAT|O_TRUNC|O_WRONLY))==-1)
1973       return(NULL);
1974      else
1975       close(handle);
1976      /* At this point, the file has been created but has a zero length. Now
1977         we can query its short name and use DOS functions to access it. */
1978     }
1979    }
1980    w95_get_shortname(name, tmp_name, sizeof(tmp_name));
1981   }
1982  #endif
1983  #if SFX_LEVEL>=ARJSFXV
1984   if(disable_sharing)
1985    return(fopen(name, mode));
1986   else
1987   {
1988    strcpyn(tmp_mode, mode, 9);
1989    switch(tmp_mode[0])
1990    {
1991     case 'r': oflag=0; break;
1992     case 'w': oflag=O_CREAT|O_TRUNC; break;
1993     case 'a': oflag=O_CREAT|O_APPEND; break;
1994     default: return(NULL);
1995    }
1996    if(tmp_mode[1]=='+'||(tmp_mode[1]!='\0'&&tmp_mode[2]=='+'))
1997     oflag|=O_RDWR;
1998    else
1999     oflag|=(tmp_mode[0]=='r')?O_RDONLY:O_WRONLY;
2000    #if TARGET!=UNIX
2001     if(tmp_mode[1]=='b'||tmp_mode[2]=='b')
2002      oflag|=O_BINARY;
2003    #endif
2004    #if TARGET==DOS
2005     if(_osmajor>=3)                     /* Sharing modes for DOS v 3.0+ */
2006     {
2007      #if COMPILER==BCC
2008       if(tmp_mode[1]=='+'||tmp_mode[1]!='\0'&&tmp_mode[2]=='+')
2009        oflag|=O_DENYWRITE;
2010       else
2011        oflag|=O_DENYNONE;
2012      #else
2013       shflag=(tmp_mode[1]=='+'||tmp_mode[1]!='\0'&&tmp_mode[2]=='+')?SH_DENYWR:SH_DENYNO;
2014      #endif
2015     }
2016     #if COMPILER==BCC
2017      handle=open(tmp_name, oflag, S_IREAD|S_IWRITE);
2018     #elif COMPILER==MSC                 /* Advanced mode - designed for OS/2 */
2019      if((handle=sopen(tmp_name, oflag, shflag, S_IREAD|S_IWRITE))==-1)
2020      {
2021       if(errno!=EACCES)
2022        return(NULL);
2023       /* Provoke INT 24h call */
2024       f_file_ptr=name;
2025       handle=open(tmp_name, oflag, S_IREAD|S_IWRITE);
2026       f_file_ptr=NULL;
2027       if(handle==-1)                    /* User abort */
2028        return(NULL);
2029       close(handle);
2030       /* Try to reopen the file in shared mode */
2031       if((handle=sopen(tmp_name, oflag, shflag, S_IREAD|S_IWRITE))==-1)
2032        if((handle=open(tmp_name, oflag, S_IREAD|S_IWRITE))==-1)
2033         return(NULL);
2034      }
2035     #endif
2036     if(handle!=-1)
2037      return(fdopen(handle, tmp_mode));
2038     else
2039      return(NULL);
2040    #elif TARGET==OS2||TARGET==WIN32
2041     {
2042      shflag=(mode[1]=='+'||mode[1]!='\0'&&mode[2]=='+')?SH_DENYWR:SH_DENYNO;
2043      handle=sopen(name, oflag, shflag, S_IREAD|S_IWRITE);
2044      if(handle!=-1)
2045       return((FILE *)fdopen(handle, mode));
2046      else
2047       return(NULL);
2048     }
2049    #elif TARGET==UNIX
2050     {
2051      struct flock flk;
2052 
2053      /* Disengage any links so we don't follow them */
2054      if(mode[0]=='w')
2055       unlink(name);
2056      /* Deny write activities if mixed-mode access */
2057      if(mode[1]=='+'||(mode[1]!='\0'&&mode[2]=='+'))
2058      {
2059       memset(&flk, 0, sizeof(flk));
2060       flk.l_type=F_WRLCK;
2061       /* ASR fix 01/10/2003 -- re-fix to handle umask 022 correctly */
2062       if((handle=open(name, oflag, 0644))==-1)
2063        return(NULL);
2064       if(fcntl(handle, F_SETLK, &flk)==-1&&errno!=EINVAL&&errno!=ENOTSUP)
2065       {
2066        close(handle);
2067        return(NULL);
2068       }
2069       return(fdopen(handle, mode));
2070      }
2071      else
2072       return(fopen(name, mode));
2073     }
2074    #endif
2075   }
2076  #else
2077   #if TARGET==DOS
2078    return(fopen(tmp_name, mode));
2079   #else
2080    return(fopen(name, mode));
2081   #endif
2082  #endif
2083 }
2084 #endif
2085 
2086 /* Convert the given path to uppercase and validate it */
2087 
2088 #if SFX_LEVEL>=ARJSFXV
default_case_path(char * dest,char * src)2089 void default_case_path(char *dest, char *src)
2090 {
2091  case_path(strcpy(dest, validate_path(src, validate_style)));
2092 }
2093 #endif
2094 
2095 /* Checks stdin against EOF (for raw input mode) */
2096 
2097 #if (SFX_LEVEL>=ARJSFXV||defined(ARJDISP))&&TARGET==DOS
check_stdin()2098 static void check_stdin()
2099 {
2100  int rc;
2101  union REGS regs;
2102 
2103  regs.x.ax=0x4400;                      /* IOCTL - query device */
2104  regs.x.bx=0;                           /* STDIN */
2105  intdos(&regs, &regs);
2106  rc=regs.x.dx;
2107  #ifndef ARJDISP
2108   if(!(rc&CHDI_NUL))
2109   {
2110    if(rc&CHDI_SET)
2111     return;
2112    if(!eof(0))
2113     return;
2114   }
2115   error(M_CANTREAD);
2116  #endif
2117 }
2118 #endif
2119 
2120 /* Reads character from console */
2121 
2122 #if SFX_LEVEL>=ARJSFXV||defined(ARJDISP)
uni_getch()2123 int uni_getch()
2124 {
2125  #if TARGET==DOS
2126   union REGS regs;
2127 
2128   check_stdin();
2129   regs.h.ah=0x08;                       /* Read character without echo */
2130   intdos(&regs, &regs);
2131   return((int)(regs.h.al==0x0D?0x0A:regs.h.al));
2132  #elif TARGET==OS2
2133   KBDKEYINFO keyinfo;
2134   KbdCharIn(&keyinfo, IO_WAIT, 0);
2135 
2136   return(keyinfo.chChar);
2137  #elif TARGET==WIN32
2138   return(getch());
2139  #elif defined(SUNOS)
2140   static struct termio cookedmode,rawmode;
2141   static int cookedok;
2142   int key;
2143 
2144   if (!cookedok)
2145   {
2146    ioctl(0,TCGETA,&cookedmode);
2147    ioctl(0,TCGETA,&rawmode);
2148    rawmode.c_iflag=IXON|IXOFF;
2149    rawmode.c_oflag&=~OPOST;
2150    rawmode.c_lflag=0;
2151    rawmode.c_cc[VEOF]=1;
2152    cookedok=1;
2153   }
2154   ioctl(0,TCSETAW,&rawmode);
2155   key=getchar();
2156   ioctl(0,TCSETAW,&cookedmode);
2157   return key;
2158  #else
2159   return(getchar());
2160  #endif
2161 }
2162 #endif
2163 
2164 /* Returns current system time, in # of ticks since midnight */
2165 
2166 #if SFX_LEVEL>=ARJSFXV||defined(REGISTER)
get_ticks()2167 unsigned long get_ticks()
2168 {
2169  struct time sttime;
2170 
2171  arj_gettime(&sttime);
2172  return(((unsigned long)sttime.ti_hour*3600L+(unsigned long)sttime.ti_min*60L+
2173         (unsigned long)sttime.ti_sec)*100L+(unsigned long)sttime.ti_hund);
2174 }
2175 #endif
2176 
2177 /* Retrieves current directory */
2178 
2179 #if SFX_LEVEL>=ARJSFX&&SFX_LEVEL<=ARJSFXV
file_getcwd(char * buf,int len)2180 void file_getcwd(char *buf, int len)
2181 {
2182  getcwd(buf, len);
2183 }
2184 #elif defined(REARJ)
file_getcwd(char * buf)2185 char *file_getcwd(char *buf)
2186 {
2187  #if TARGET==DOS
2188   if(lfn_supported!=LFN_NOT_SUPPORTED)
2189    return(w95_cwd(buf));
2190   else
2191    return(getcwd(buf, CCHMAXPATH_W95));
2192  #else
2193   #if COMPILER==ICC
2194    return(_getcwd(buf, CCHMAXPATH));
2195   #else
2196    return(getcwd(buf, CCHMAXPATH));
2197   #endif
2198  #endif
2199 }
2200 #endif
2201 
2202 /* Returns switch character used by OS */
2203 
2204 #ifdef REARJ
get_sw_char()2205 char get_sw_char()
2206 {
2207  #if TARGET==DOS
2208   union REGS regs;
2209 
2210   regs.x.ax=0x3700;
2211   intdos(&regs, &regs);
2212   return(regs.h.dl);
2213  #elif TARGET==OS2
2214   return('/');
2215  #else
2216   return('-');
2217  #endif
2218 }
2219 #endif
2220 
2221 /* Returns the amount of free space for disk on which the given file is
2222    located. */
2223 
2224 #if SFX_LEVEL>=ARJSFXV||defined(REARJ)
file_getfree(char * name)2225 unsigned long file_getfree(char *name)
2226 {
2227  #if TARGET==DOS
2228   #if COMPILER==BCC
2229    struct dfree dtable;
2230   #elif COMPILER==MSC
2231    struct diskfree_t dtable;
2232   #endif
2233   char drive=0;
2234 
2235   while(name[0]==' ')                   /* Skip over leading spaces, if any */
2236    name++;
2237   if(name[1]==':')
2238    drive=toupper(name[0])-0x40;
2239   #if COMPILER==BCC
2240    getdfree(drive, &dtable);
2241    if(dtable.df_sclus==65535)
2242     return(MAXLONG);
2243    else
2244    {
2245     return((LONG_MAX/((long)dtable.df_bsec*dtable.df_sclus)<dtable.df_avail)?
2246            LONG_MAX:
2247            (long)dtable.df_bsec*dtable.df_sclus*dtable.df_avail);
2248    }
2249   #elif COMPILER==MSC
2250    if(_dos_getdiskfree((unsigned int)drive, &dtable))
2251     return(ULONG_MAX);
2252    else
2253    {
2254     return((LONG_MAX/((long)dtable.bytes_per_sector*dtable.sectors_per_cluster)<dtable.avail_clusters)?
2255            LONG_MAX:
2256            (long)dtable.bytes_per_sector*dtable.sectors_per_cluster*dtable.avail_clusters);
2257    }
2258   #endif
2259  #elif TARGET==OS2
2260   USHORT drive=0;
2261   FSALLOCATE fsinfo;
2262 
2263   while(name[0]==' ')
2264    name++;
2265   if(name[1]==':')
2266    drive=toupper(name[0])-0x40;
2267   if(DosQFSInfo(drive, FSIL_ALLOC, (PBYTE)&fsinfo, sizeof(fsinfo)))
2268    return(LONG_MAX);
2269   else
2270    return((LONG_MAX/(fsinfo.cSectorUnit*fsinfo.cbSector)<fsinfo.cUnitAvail)?
2271           LONG_MAX:
2272           fsinfo.cSectorUnit*fsinfo.cbSector*fsinfo.cUnitAvail);
2273  #elif TARGET==WIN32
2274   char tmp[4], *ptmp=NULL;
2275   DWORD bps, spclu, fclu, clu;
2276 
2277   while(name[0]==' ')
2278    name++;
2279   if(name[1]==':')
2280   {
2281    ptmp=tmp;
2282    tmp[0]=toupper(name[0]);
2283    tmp[1]=':';
2284    tmp[2]='\\';
2285    tmp[3]='\0';
2286   }
2287   if(!GetDiskFreeSpace(ptmp, &spclu, &bps, &fclu, &clu))
2288    return(LONG_MAX);
2289   else
2290    return((LONG_MAX/(spclu*bps)<fclu)?LONG_MAX:spclu*bps*fclu);
2291  #elif TARGET==UNIX
2292   #if defined(__QNXNTO__)||defined(__sco__)||defined(SUNOS)
2293    struct statvfs vfs;
2294 
2295    if(statvfs(name, &vfs)==-1)
2296     return(LONG_MAX);
2297    return((LONG_MAX/512<vfs.f_bavail)?LONG_MAX:vfs.f_bavail*512);
2298   #else
2299    struct statfs sfs;
2300 
2301    if(statfs(name, &sfs)==-1)
2302     return(LONG_MAX);
2303    return((LONG_MAX/512<sfs.f_bavail)?LONG_MAX:sfs.f_bavail*512);
2304   #endif
2305  #endif
2306 }
2307 #endif
2308 
2309 /* findfirst() for external use */
2310 
2311 #if SFX_LEVEL>=ARJSFXV
file_find(char * name,struct file_properties * properties)2312 int file_find(char *name, struct file_properties *properties)
2313 {
2314  struct new_ffblk new_ffblk;
2315  int attrib=STD_FI_ATTRS;
2316  #if TARGET==UNIX
2317   int u;
2318  #endif
2319 
2320  if(lfn_findfirst(name, &new_ffblk, attrib)!=0)
2321   return(-1);
2322  else
2323  {
2324   #if SFX_LEVEL>=ARJ
2325    lfn_findclose(&new_ffblk);
2326    finddata_to_properties(properties, &new_ffblk);
2327   #else
2328    properties->ftime=new_ffblk.ff_ftime;
2329    properties->fsize=new_ffblk.ff_fsize;
2330    properties->attrib=(ATTRIB)new_ffblk.ff_attrib;
2331    #if TARGET!=UNIX
2332     properties->type=(new_ffblk.ff_attrib&FATTR_DIREC)?ARJT_DIR:ARJT_BINARY;
2333     properties->isarchive=(new_ffblk.ff_attrib&FATTR_ARCH)?1:0;
2334    #else
2335     u=uftype(new_ffblk.ff_attrib);
2336     if(u&FATTR_DT_DIR)
2337      properties->type=ARJT_DIR;
2338     else if(u&FATTR_DT_UXSPECIAL)
2339      properties->type=ARJT_UXSPECIAL;
2340     else
2341      properties->type=ARJT_BINARY;
2342     properties->isarchive=1;
2343     properties->l_search=new_ffblk.l_search;
2344     properties->l_search.ref=0;
2345     properties->islink=0;
2346    #endif
2347   #endif
2348   return(0);
2349  }
2350 }
2351 #endif
2352 
2353 /* Returns the size of the given file */
2354 
2355 #if SFX_LEVEL>=ARJ||defined(REARJ)
file_getfsize(char * name)2356 long file_getfsize(char *name)
2357 {
2358  #if SFX_LEVEL>=ARJ
2359   struct new_ffblk new_ffblk;
2360   int attrib=STD_FI_ATTRS;
2361 
2362   if(lfn_findfirst(name, &new_ffblk, attrib)!=0)
2363    return(0L);
2364   else
2365   {
2366    lfn_findclose(&new_ffblk);
2367     return(new_ffblk.ff_fsize);
2368   }
2369  #else
2370   FILE *stream;
2371   long rc;
2372 
2373   if((stream=file_open(name, m_rb))==NULL)
2374    return(0);
2375   #if TARGET!=UNIX
2376    rc=filelength(fileno(stream));
2377   #else
2378    fseek(stream, 0L, SEEK_END);
2379    rc=ftell(stream);
2380   #endif
2381   fclose(stream);
2382   return(rc);
2383  #endif
2384 }
2385 #endif
2386 
2387 /* Returns last modification time for the given file */
2388 
2389 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
file_getftime(char * name)2390 unsigned long file_getftime(char *name)
2391 {
2392  #if TARGET==DOS
2393   #if SFX_LEVEL>=ARJSFXV
2394    struct new_ffblk new_ffblk;
2395    int attrib=STD_FI_ATTRS;
2396 
2397    if(lfn_findfirst(name, &new_ffblk, attrib)!=0)
2398     return(0L);
2399    else
2400    {
2401     #if SFX_LEVEL>=ARJ
2402      lfn_findclose(&new_ffblk);         /* Done automatically by ARJSFXV */
2403     #endif
2404     return(new_ffblk.ff_ftime);
2405    }
2406   #else
2407    FILE *stream;
2408    unsigned long rc;
2409 
2410    if((stream=file_open(name, m_rb))==NULL)
2411     return(0L);
2412    #if COMPILER==BCC
2413     getftime(fileno(stream), (struct ftime *)&rc);
2414    #else
2415     _dos_getftime(fileno(stream), (unsigned int *)&rc+1, (unsigned int *)&rc);
2416    #endif
2417    fclose(stream);
2418    return(rc);
2419   #endif
2420  #elif TARGET==OS2
2421   HFILE hf;
2422   #ifdef __32BIT__
2423    ULONG action;
2424   #else
2425    USHORT action;
2426   #endif
2427   FILESTATUS fstatus;
2428 
2429   if(DosOpen(name, &hf, &action, 0L, 0, FILE_OPEN, OPEN_ACCESS_READONLY|OPEN_SHARE_DENYNONE, 0L))
2430    return(0L);
2431   DosQFileInfo(hf, FIL_STANDARD, &fstatus, sizeof(fstatus));
2432   DosClose(hf);
2433   return(make_ftime(fstatus.fdateLastWrite, fstatus.ftimeLastWrite));
2434  #elif TARGET==WIN32
2435   FILETIME ftime, atime, ctime;
2436   HANDLE hf;
2437 
2438   if((hf=CreateFile(name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0))==INVALID_HANDLE_VALUE)
2439    return(0L);
2440   if(!GetFileTime(hf, &ctime, &atime, &ftime))
2441    return(0L);
2442   CloseHandle(hf);
2443   return(dosify_time(&ftime));
2444  #elif TARGET==UNIX
2445   struct stat st;
2446 
2447   if(lstat(name, &st)==-1)
2448    return(0L);
2449   return(st.st_mtime);
2450  #endif
2451 }
2452 #endif
2453 
2454 /* Queries the volume label for the specified drive. The destination buffer
2455    will contain "" if the volume label is missing. */
2456 
2457 #if SFX_LEVEL>=ARJ&&defined(HAVE_VOL_LABELS)
file_getlabel(char * label,char drive,ATTRIB * attrib,unsigned long * ftime)2458 int file_getlabel(char *label, char drive, ATTRIB *attrib, unsigned long *ftime)
2459 {
2460  #if TARGET==DOS
2461   struct new_ffblk new_ffblk;
2462   char wildcard[10];
2463 
2464   if(drive=='\0')
2465    wildcard[0]='\0';
2466   else
2467   {
2468    wildcard[0]=drive;
2469    wildcard[1]=':';
2470    wildcard[2]='\0';
2471   }
2472   strcat(wildcard, root_wildcard);
2473   if(lfn_findfirst(wildcard, &new_ffblk, FATTR_LABEL))
2474    return(0);                            /* Pretty incorrect but, if no files
2475                                             are present, it won't be called */
2476   if(_osmajor>2)
2477   {
2478    while(!(new_ffblk.ff_attrib&FATTR_LABEL))
2479    {
2480     if(!lfn_findnext(&new_ffblk))
2481      return(0);
2482    }
2483    lfn_findclose(&new_ffblk);
2484   }
2485   strcpy(label, new_ffblk.ff_name);
2486   *attrib=(ATTRIB)new_ffblk.ff_attrib;
2487   *ftime=new_ffblk.ff_ftime;
2488   return(0);
2489  #elif TARGET==OS2
2490   FSINFO fsinfo;
2491   USHORT rc;
2492 
2493   rc=DosQFSInfo(drive=='\0'?0:drive-0x40, FSIL_VOLSER, (PBYTE)&fsinfo, sizeof(fsinfo));
2494   if(rc)
2495    return((rc==ERROR_NO_VOLUME_LABEL)?0:-1);
2496   strcpy(label, fsinfo.vol.szVolLabel);
2497   return(0);
2498  #elif TARGET==WIN32
2499   DWORD dummy;
2500 
2501   return(!GetVolumeInformation(NULL, label, CCHMAXPATH, NULL, &dummy, &dummy, NULL, 0));
2502  #endif
2503 }
2504 #endif
2505 
2506 /* Read a line from the stdin w/echo, returning the number of bytes read. */
2507 
2508 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
read_line(char * buf,int size)2509 int read_line(char *buf, int size)
2510 {
2511  #if TARGET==DOS
2512   union REGS regs;
2513   #if SFX_LEVEL>=ARJSFX||defined(REARJ)
2514    char tmp_buf[160];                    /* Actually, DOS limit is 128 */
2515   #endif
2516   unsigned int ioctl_set, ioctl_isbinary, ioctl_response;
2517   int chars_read;
2518   int cchar;
2519 
2520   regs.x.ax=0x4400;                      /* IOCTL - query device */
2521   regs.x.bx=0;                           /* STDIN */
2522   intdos(&regs, &regs);
2523   ioctl_response=regs.x.dx;
2524   ioctl_set=(ioctl_response&CHDI_SET)?1:0;
2525   ioctl_isbinary=(ioctl_response&CHDI_BINARY)?1:0;
2526   #ifdef REARJ
2527    ioctl_isbinary=ioctl_set&ioctl_isbinary;
2528   #endif
2529   if(ioctl_set&&ioctl_isbinary||_osmajor<3)
2530   {
2531    #if SFX_LEVEL>=ARJSFXV
2532     tmp_buf[0]=min(size, INPUT_LIMIT);   /* Number of input positions */
2533     tmp_buf[1]=tmp_buf[0]-1;             /* Number of recallable positions */
2534     regs.h.ah=0x0A;
2535     regs.x.dx=(unsigned int)tmp_buf;
2536     intdos(&regs, &regs);
2537     chars_read=(int)tmp_buf[1];
2538     if(tmp_buf[chars_read+2]=='\x0D')
2539      tmp_buf[chars_read+2]='\0';         /* Convert to ASCIIZ */
2540     strcpy(buf, tmp_buf+2);
2541     nputlf();                            /* v 2.72+ fixup to live happily
2542                                             under Unices */
2543    #elif defined(REARJ)
2544     tmp_buf[0]=min(size, INPUT_LIMIT);   /* Number of input positions */
2545     cgets(tmp_buf);
2546     chars_read=(int)tmp_buf[1];
2547     strcpy(buf, tmp_buf+2);
2548    #else
2549     error(M_RAW_INPUT_REJECTED);
2550    #endif
2551   }
2552   else
2553   {
2554    for(chars_read=0; (cchar=fgetc(stdin))!=EOF&&cchar!=LF; chars_read++)
2555    {
2556     if(chars_read<size-1)
2557      buf[chars_read]=(char)cchar;
2558    }
2559    if(cchar==-1)
2560     error(M_CANTREAD);
2561    buf[chars_read]='\0';
2562   }
2563   msg_cprintf(0, cr);                   /* ASR fix 03/02/2003 for COLOR_OUTPUT */
2564   return(chars_read);
2565  #elif (TARGET==OS2&&(COMPILER==MSC||defined(LIBC)))||TARGET==WIN32||TARGET==UNIX
2566   int chars_read;
2567   int cchar;
2568 
2569   for(chars_read=0; (cchar=fgetc(stdin))!=EOF&&cchar!=LF; chars_read++)
2570   {
2571    if(chars_read<size-1)
2572     buf[chars_read]=(char)cchar;
2573   }
2574   if(cchar==-1)
2575    error(M_CANTREAD);
2576   buf[chars_read]='\0';
2577   return(chars_read);
2578  #else                          	/* A platform-neutral solution */
2579   char *p;
2580 
2581   #ifdef DEBUG
2582    debug_report(dbg_cur_file, __LINE__, 'W');
2583   #endif
2584   fgets(buf, size, stdin);              /* DIRTY HACK */
2585   if((p=strchr(buf, '\n'))!=NULL)
2586    *p='\0';
2587   if((p=strchr(buf, '\r'))!=NULL)
2588    *p='\0';
2589   return(strlen(buf));
2590  #endif
2591 }
2592 #endif
2593 
2594 /* Returns file access mode in character format */
2595 
2596 #if SFX_LEVEL>=ARJSFX
get_mode_str(char * str,unsigned int mode)2597 void get_mode_str(char *str, unsigned int mode)
2598 {
2599  #if TARGET==UNIX
2600   int i;
2601 
2602   str[0]='-';
2603   for(i=0; i<3; i++)
2604   {
2605    str[(2-i)*3+1]=(mode&4)?'r':'-';
2606    str[(2-i)*3+2]=(mode&2)?'w':'-';
2607    str[(2-i)*3+3]=(mode&1)?'x':'-';
2608    mode>>=3;
2609   }
2610   str[10]=' ';
2611   str[11]=(mode&FATTR_SGID)?'G':'-';
2612   str[12]=(mode&FATTR_SUID)?'U':'-';
2613   str[13]=(mode&FATTR_SVTX)?'A':'-';
2614   str[14]='\0';
2615  #else
2616   strcpy(str, attrib_buf);
2617   if(mode&FATTR_ARCH)
2618    str[0]='A';
2619   if(mode&FATTR_SYSTEM)
2620    str[1]='S';
2621   if(mode&FATTR_HIDDEN)
2622    str[2]='H';
2623   if(mode&FATTR_RDONLY)
2624    str[3]='R';
2625  #endif
2626 }
2627 #endif
2628 
2629 /* Retrieves an environment string */
2630 
2631 #if TARGET==OS2&&SFX_LEVEL>=ARJSFX
get_env_str(char * t)2632 static char FAR *get_env_str(char *t)
2633 {
2634  #ifdef __32BIT__
2635   PSZ rc;
2636 
2637   if(DosScanEnv(t, &rc))
2638    return(NULL);
2639   return((char FAR *)rc);
2640  #else
2641   USHORT selector;
2642   USHORT cmd_offset;
2643   char FAR *env_ptr;
2644   int i;
2645 
2646   DosGetEnv(&selector, &cmd_offset);
2647   env_ptr=MAKEP(selector, 0);
2648   while(*env_ptr!='\0')
2649   {
2650    for(i=0; t[i]!='\0'; i++)
2651     if(env_ptr[i]=='\0'||env_ptr[i]!=t[i])
2652      break;
2653    if(t[i]=='\0'&&env_ptr[i]=='=')
2654     return(env_ptr+i+1);
2655    env_ptr+=i;
2656    while(*env_ptr++!='\0');
2657   }
2658   return(NULL);
2659  #endif
2660 }
2661 #endif
2662 
2663 /* Reserves memory and gets an environment string */
2664 
2665 #if TARGET==OS2&&SFX_LEVEL>=ARJSFX
malloc_env_str(char * t)2666 char *malloc_env_str(char *t)
2667 {
2668  char FAR *str, FAR *sptr;
2669  char *rc, *rptr;
2670  int i;
2671 
2672  if((str=get_env_str(t))==NULL)
2673   return(NULL);
2674  i=1;
2675  for(sptr=str; *sptr!='\0'; sptr++)
2676   i++;
2677  if((rc=(char *)malloc(i))==NULL)
2678   return(NULL);                         /* Env. string was too long */
2679  rptr=rc;
2680  for(sptr=str; *sptr!='\0'; sptr++)
2681   *rptr++=*sptr;
2682  *rptr='\0';
2683  return(rc);
2684 }
2685 #endif
2686 
2687 /* A small exported stub for C RTL to be happy */
2688 
2689 #if TARGET==OS2&&COMPILER==MSC&&SFX_LEVEL>=ARJ
getenv(const char * str)2690 char *getenv(const char *str)
2691 {
2692  return(NULL);                          /* No such a string */
2693 }
2694 #endif
2695 
2696 /* Executes the given program directly, returning its RC */
2697 
2698 #if defined(REARJ)||(SFX_LEVEL>=ARJSFX&&TARGET==OS2)
exec_pgm(char * cmdline)2699 int exec_pgm(char *cmdline)
2700 {
2701  char tmp_cmd[CMDLINE_LENGTH+CCHMAXPATH];
2702  #if TARGET==OS2                	/* && SFX_LEVEL>=ARJSFX */
2703   char *params;
2704   int p_pos;
2705   #ifdef REARJ
2706    #ifdef __32BIT__
2707     PPIB ppib=NULL;
2708     PTIB ptib=NULL;
2709     ULONG child_pid, session_pid;
2710     REQUESTDATA qr;
2711     ULONG qrc;
2712     ULONG cb_res;
2713    #else
2714     PID child_pid, session_pid;
2715     PIDINFO pidi;
2716     QUEUERESULT qr;
2717     USHORT qrc;
2718     USHORT cb_res;
2719    #endif
2720    STARTDATA sd;
2721    char qname[CCHMAXPATH];
2722    HQUEUE queue;
2723    USHORT errcode;
2724    PUSHORT res;
2725    BYTE elem_priority;
2726    char *argv[PARAMS_MAX];
2727    int arg;
2728    static char param_sep[]=" ";
2729   #else
2730    RESULTCODES rc;
2731   #endif
2732 
2733   #ifndef REARJ
2734    memset(tmp_cmd, 0, sizeof(tmp_cmd));
2735    if((params=strchr(cmdline, ' '))!=NULL)
2736    {
2737     p_pos=params-cmdline;
2738     if(p_pos>0)
2739      memcpy(tmp_cmd, cmdline, p_pos);
2740     strcpy(tmp_cmd+p_pos+1, params);
2741    }
2742    else
2743     strcpy(tmp_cmd, cmdline);
2744    if(!DosExecPgm(NULL, 0, EXEC_SYNC, tmp_cmd, NULL, &rc, tmp_cmd))
2745     return(rc.codeResult);
2746    else
2747     return(-1);
2748   #else
2749    strncpy(tmp_cmd, cmdline, sizeof(tmp_cmd)-1);
2750    tmp_cmd[sizeof(tmp_cmd)-1]='\0';
2751    argv[0]=strtok(tmp_cmd, param_sep);
2752    if(argv[0]==NULL)
2753     return(-1);
2754    for(arg=1; arg<PARAMS_MAX; arg++)
2755     if((argv[arg]=strtok(NULL, param_sep))==NULL)
2756      break;
2757    if(arg>=PARAMS_MAX)
2758     return(-1);
2759    if((errcode=spawnvp(P_WAIT, argv[0], argv))!=0xFFFF)
2760     return(errcode);
2761    else
2762    {
2763     /* Try running the program asynchronously using the SESMGR */
2764     memset(tmp_cmd, 0, sizeof(tmp_cmd));
2765     if((params=strchr(cmdline, ' '))!=NULL)
2766     {
2767      p_pos=params-cmdline;
2768      if(p_pos>0)
2769       memcpy(tmp_cmd, cmdline, p_pos);
2770      strcpy(tmp_cmd+p_pos+1, params);
2771     }
2772     else
2773      strcpy(tmp_cmd, cmdline);
2774     #ifdef __32BIT__
2775      DosGetInfoBlocks(&ptib, &ppib);    /* Fixed for PJ24109 */
2776      sprintf(qname, rearj_q_fmt, ppib->pib_ulpid);
2777     #else
2778      DosGetPID(&pidi);
2779      sprintf(qname, rearj_q_fmt, pidi.pid);
2780     #endif
2781     if(DosCreateQueue(&queue, QUE_FIFO, qname))
2782      return(-1);
2783     memset(&sd, 0, sizeof(sd));
2784     sd.Length=sizeof(sd);
2785     sd.Related=TRUE;
2786     sd.FgBg=TRUE;                       /* Start in background */
2787     sd.PgmName=tmp_cmd;
2788     sd.PgmInputs=params;
2789     sd.TermQ=qname;
2790     sd.InheritOpt=1;
2791     if(DosStartSession(&sd, &session_pid, &child_pid))
2792      return(-1);
2793     while((qrc=DosReadQueue(queue, &qr, &cb_res, (PVOID FAR *)&res, 0, DCWW_WAIT,
2794                              &elem_priority, 0))==0)
2795     {
2796      errcode=res[1];
2797      #ifdef __32BIT__
2798       DosFreeMem(res);
2799       if(qr.ulData==0)
2800        break;
2801      #else
2802       DosFreeSeg(SELECTOROF(res));
2803       if(qr.usEventCode==0)
2804        break;
2805      #endif
2806     }
2807     DosCloseQueue(queue);
2808     return(errcode);
2809    }
2810   #endif
2811  #else
2812   char *argv[PARAMS_MAX];
2813   int arg;
2814   static char param_sep[]=" ";
2815   #if TARGET==UNIX
2816    int pid, rc, status;
2817    struct sigaction ign_set, intr, quit;
2818   #endif
2819 
2820   strncpy(tmp_cmd, cmdline, sizeof(tmp_cmd)-1);
2821   tmp_cmd[sizeof(tmp_cmd)-1]='\0';
2822   argv[0]=strtok(tmp_cmd, param_sep);
2823   if(argv[0]==NULL)
2824    return(-1);
2825   for(arg=1; arg<PARAMS_MAX; arg++)
2826   {
2827    if((argv[arg]=strtok(NULL, param_sep))==NULL)
2828     break;
2829    #if TARGET==UNIX
2830     if(argv[arg][0]=='"'&&argv[arg][strlen(argv[arg])-1]=='"')
2831     {
2832      argv[arg]++;
2833      argv[arg][strlen(argv[arg])-1]='\0';
2834     }
2835    #endif
2836   }
2837   if(arg>=PARAMS_MAX)
2838    return(-1);
2839   #if TARGET!=UNIX
2840    return(spawnvp(P_WAIT, argv[0], argv));
2841   #else
2842    if((pid=fork())==-1)
2843     return(-1);
2844    if(pid==0)
2845    {
2846     exit(execvp(argv[0], argv));
2847    }
2848    else
2849    {
2850     /* Prevent signals from appearing */
2851     ign_set.sa_handler=SIG_IGN;
2852     ign_set.sa_flags=0;
2853     sigemptyset(&ign_set.sa_mask);
2854     sigaction(SIGINT, &ign_set, &intr);
2855     sigaction(SIGQUIT, &ign_set, &quit);
2856     /* Wait for the child */
2857     do
2858      rc=waitpid(pid, &status, 0);
2859     while(rc==-1&&errno==EINTR);
2860     /* Restore signals */
2861     sigaction(SIGINT, &intr, NULL);
2862     sigaction(SIGQUIT, &quit, NULL);
2863     return(status);
2864    }
2865   #endif
2866  #endif
2867 }
2868 #endif
2869 
2870 /* Executes a program or a shell command */
2871 
2872 #if SFX_LEVEL>=ARJSFX&&TARGET==OS2
system_cmd(char * cmd)2873 int system_cmd(char *cmd)
2874 {
2875  char tmp_cmd[CMDLINE_LENGTH+CCHMAXPATH];
2876  char *comspec;
2877 
2878  comspec=malloc_env_str("COMSPEC");
2879  strcpy(tmp_cmd, (comspec==NULL)?"cmd" EXE_EXTENSION:comspec);
2880  free_env_str(comspec);
2881  strcat(tmp_cmd, " /C");
2882  strcat(tmp_cmd, cmd);
2883  return((exec_pgm(tmp_cmd)==-1)?-1:0);
2884 }
2885 #endif
2886 
2887 /* Retrieves the name of executable */
2888 
2889 #if (SFX_LEVEL>=ARJSFXJR||defined(REARJ))
2890 #ifndef SKIP_GET_EXE_NAME
get_exe_name(char * dest)2891 void get_exe_name(char *dest)
2892 {
2893  #if TARGET==DOS
2894   char FAR *env_ptr;
2895   unsigned short s_seg;
2896   unsigned int i;
2897   unsigned short psp_seg;
2898 
2899   if(_osmajor<3)
2900   {
2901    if(_osmajor!=2||_osminor!=11)
2902     strcpy(dest, default_exe);
2903    else
2904    {
2905     #if COMPILER==BCC
2906      s_seg=*(unsigned short FAR *)MK_FP(_psp, 2)-56;
2907     #else                               /* Microsoft C changes the MCB order */
2908      s_seg=(*(unsigned short FAR *)0x00400013<<6)-56;
2909     #endif
2910     env_ptr=MK_FP(s_seg, 9);            /* Not actually ENV but it works! */
2911     i=0;
2912     while(*env_ptr!='\0'&&i<FILENAME_MAX)
2913      dest[i++]=*(env_ptr++);
2914     dest[i]='\0';
2915     if(dest[i-4]!='.'||dest[i-3]!='E'||dest[i-2]!='X'||dest[i-1]!='E')
2916      strcpy(dest, default_exe);
2917    }
2918   }
2919   else
2920   {
2921    #ifdef ASM8086
2922     asm{
2923      push ax
2924      push bx
2925      mov ah, 62h
2926      int 21h
2927      mov psp_seg, bx
2928      pop bx
2929      pop ax
2930     }
2931    #else
2932     {
2933      union REGS regs;
2934 
2935      regs.x.ax=0x6200;
2936      intdos(&regs, &regs);
2937      psp_seg=regs.x.bx;
2938     }
2939    #endif
2940    env_ptr=MK_FP(*(unsigned short FAR *)MK_FP(psp_seg, 0x2C), 0);
2941    while(*(short FAR *)(env_ptr++)!=0);
2942    env_ptr+=3;
2943    i=0;
2944    while(*env_ptr!='\0'&&i<FILENAME_MAX)
2945     dest[i++]=*(env_ptr++);
2946    dest[i]='\0';
2947   }
2948  #elif TARGET==OS2
2949   #ifdef __32BIT__
2950    PTIB ptib;
2951    PIB *ppib;
2952 
2953    DosGetInfoBlocks(&ptib, &ppib);
2954    DosQueryModuleName(ppib->pib_hmte, CCHMAXPATH, dest);
2955   #else
2956    USHORT selector;
2957    USHORT cmd_offset;
2958    char FAR *sptr;
2959 
2960    DosGetEnv(&selector, &cmd_offset);
2961    sptr=MAKEP(selector, 0);
2962    while(*(SHORT FAR *)sptr!=0)
2963     sptr++;
2964    sptr+=2;
2965    while(*sptr!='\0')
2966     *dest++=*sptr++;
2967    *dest='\0';
2968   #endif
2969  #elif TARGET==WIN32
2970   GetModuleFileName(NULL, dest, CCHMAXPATH);
2971  #endif
2972 }
2973 #else /* SKIP_GET_EXE_NAME */
get_exe_name(char * dest,char * arg)2974 void get_exe_name(char *dest, char *arg)
2975 {
2976  char *ps, *pe;
2977  int l;
2978  int len;
2979 
2980  if(strchr(arg, PATHSEP_DEFAULT)!=NULL)
2981  {
2982   strcpy(dest, arg);
2983   return;
2984  }
2985  len=FILENAME_MAX-2-strlen(arg);
2986  ps=getenv("PATH");
2987  do
2988  {
2989   pe=strchr(ps, ':');
2990   if(pe==NULL)
2991    pe=ps+(l=strlen(ps));
2992   else
2993    l=pe-ps;
2994   if(l>=len)
2995    l=len-1;
2996   memcpy(dest, ps, l);
2997   if(dest[l-1]!=PATHSEP_DEFAULT)
2998    dest[l++]=PATHSEP_DEFAULT;
2999   strcpy(dest+l, arg);
3000   if(!access(dest, F_OK)||errno==EINVAL)
3001    return;
3002   ps=pe+1;
3003  } while(*pe!='\0');
3004  /* Notes to porters: below are the totally unlikely "last-chance" values.
3005     The DOS legacy parts of ARJ open its executable when looking for SFX
3006     modules and help screens. In most cases we are happy with argv[0] and
3007     PATH lookup. When that fails, we assume the locations below, and if
3008     they are missing altogether, the corresponding code will gracefully
3009     terminate. */
3010  #if SFX_LEVEL==ARJ
3011   strcpy(dest, "/usr/local/bin/arj");
3012  #elif SFX_LEVEL==ARJSFXV
3013   strcpy(dest, "./arjsfxv");
3014  #elif SFX_LEVEL==ARJSFX
3015   strcpy(dest, "./arjsfx");
3016  #elif SFX_LEVEL==ARJSFXJR
3017   strcpy(dest, "./arjsfxjr");
3018  #elif defined(REARJ)
3019   strcpy(dest, "/usr/local/bin/rearj");
3020  #else
3021   dest[0]='\0';
3022  #endif
3023 }
3024 #endif
3025 #endif
3026 
3027 /* Read a line from console without echoing it (used only when prompting for
3028    passwords) */
3029 
3030 #if SFX_LEVEL>=ARJSFXV
read_line_noecho(char * buf,int size)3031 int read_line_noecho(char *buf, int size)
3032 {
3033  int chars_read;
3034  int cchar;
3035 
3036  chars_read=0;
3037  cchar=uni_getch();
3038  while(cchar!=LF&&cchar!=CR)
3039  {
3040   if(cchar=='\b')
3041   {
3042    if(chars_read!=0)
3043     chars_read--;
3044   }
3045   else if(chars_read<size-1)
3046    buf[chars_read++]=cchar;
3047   cchar=uni_getch();
3048  }
3049  buf[chars_read]='\0';
3050  nputlf();
3051  return(chars_read);
3052 }
3053 #endif
3054 
3055 /* Returns the number of bytes per allocation unit for the drive that contains
3056    the given file. NOTE: this is an advisory value to align multivolume
3057    archives tightly when the free space is a constraint. Not to be used in
3058    converting allocation units to bytes. */
3059 
3060 #if SFX_LEVEL>=ARJSFXV||defined(REARJ)
get_bytes_per_cluster(char * name)3061 unsigned int get_bytes_per_cluster(char *name)
3062 {
3063  #if TARGET==DOS
3064   #if COMPILER==BCC
3065    struct dfree dtable;
3066   #elif COMPILER==MSC
3067    struct diskfree_t dtable;
3068   #endif
3069   char drive=0;
3070 
3071   while(name[0]==' ')                   /* Skip over leading spaces, if any */
3072    name++;
3073   if(name[1]==':')
3074    drive=toupper(name[0])-0x40;
3075   #if COMPILER==BCC
3076    getdfree(drive, &dtable);
3077    if(dtable.df_sclus==65535)
3078     return(1024);
3079    else
3080     return(dtable.df_bsec*dtable.df_sclus);
3081   #elif COMPILER==MSC
3082    if(_dos_getdiskfree((unsigned int)drive, &dtable))
3083     return(1024);
3084    else
3085     return(dtable.bytes_per_sector*dtable.sectors_per_cluster);
3086   #endif
3087  #elif TARGET==OS2
3088   USHORT drive=0;
3089   FSALLOCATE fsinfo;
3090   unsigned long rc;
3091 
3092   while(name[0]==' ')
3093    name++;
3094   if(name[1]==':')
3095    drive=toupper(name[0])-0x40;
3096   if(DosQFSInfo(drive, FSIL_ALLOC, (PBYTE)&fsinfo, sizeof(fsinfo)))
3097    return(ULONG_MAX);
3098   rc=(unsigned long)fsinfo.cbSector*fsinfo.cSectorUnit;
3099   return(rc>UINT_MAX?UINT_MAX:rc);
3100  #elif TARGET==WIN32
3101   char fpn[CCHMAXPATH];
3102   LPTSTR fnc;
3103   DWORD bps, spclu, fclu, clu;
3104 
3105   if(!GetFullPathName(name, CCHMAXPATH, fpn, &fnc)||fpn[1]!=':')
3106    return(ULONG_MAX);
3107   fpn[3]='\0';
3108   if(!GetDiskFreeSpace(fpn, &spclu, &bps, &fclu, &clu))
3109    return(ULONG_MAX);
3110   else
3111    return(bps*spclu);
3112  #elif TARGET==UNIX
3113   #ifdef linux
3114    struct statvfs vfs;
3115 
3116    if(statvfs(name, &vfs)==-1)
3117     return(512);
3118    else
3119     return(vfs.f_bsize);
3120   #else
3121    return(512);
3122   #endif
3123  #endif
3124 }
3125 #endif
3126 
3127 /* Returns canonical Windows 95 longname for a given file */
3128 
3129 #if SFX_LEVEL>=ARJ&&TARGET==DOS
get_canonical_longname(char * cname,char * name)3130 void get_canonical_longname(char *cname, char *name)
3131 {
3132  int name_ofs;                          /* Offset of LFN within name[] */
3133  char *cname_ptr, *name_ptr;
3134 
3135  if(name[1]==':'||name[0]==PATHSEP_DEFAULT||name[0]==PATHSEP_UNIX||name[0]=='.')
3136   name_ofs=0;
3137  else
3138  {
3139   w95_get_longname(cur_dir_spec, cname, CCHMAXPATH);
3140   name_ofs=strlen(cname);
3141  }
3142  w95_get_longname(name, cname, CCHMAXPATH);
3143  if(name_ofs==0)
3144   return;
3145  cname_ptr=cname;
3146  name_ptr=name+name_ofs;
3147  if(name_ptr[0]==PATHSEP_DEFAULT||name_ptr[0]==PATHSEP_UNIX)
3148   name_ptr++;
3149  while(name_ptr[0]!='\0')
3150  {
3151   (cname_ptr++)[0]=(name_ptr++)[0];
3152  }
3153  cname_ptr[0]='\0';
3154 }
3155 #endif
3156 
3157 /* Returns canonical short name for a given Windows 95 long filename */
3158 
3159 #if SFX_LEVEL>=ARJ&&TARGET==DOS
get_canonical_shortname(char * cname,char * name)3160 void get_canonical_shortname(char *cname, char *name)
3161 {
3162  int name_ofs;                          /* Offset of LFN within name[] */
3163  char *cname_ptr, *name_ptr;
3164 
3165  if(name[1]==':'||name[0]==PATHSEP_DEFAULT||name[0]==PATHSEP_UNIX||name[0]=='.')
3166   name_ofs=0;
3167  else
3168  {
3169   w95_get_shortname(cur_dir_spec, cname, CCHMAXPATH);
3170   name_ofs=strlen(cname);
3171  }
3172  w95_get_shortname(name, cname, CCHMAXPATH);
3173  if(name_ofs==0)
3174   return;
3175  cname_ptr=cname;
3176  name_ptr=name+name_ofs;
3177  if(name_ptr[0]==PATHSEP_DEFAULT||name_ptr[0]==PATHSEP_UNIX)
3178   name_ptr++;
3179  while(name_ptr[0]!='\0')
3180  {
3181   (cname_ptr++)[0]=(name_ptr++)[0];
3182  }
3183  cname_ptr[0]='\0';
3184 }
3185 #endif
3186 
3187 /* Displays a string pointed to by a FAR pointer on the stdout. Used only by
3188    internal functions of ENVIRON.C. */
3189 
3190 #if SFX_LEVEL>=ARJSFXV&&TARGET==DOS
far_ttyout(char FAR * str)3191 static void far_ttyout(char FAR *str)
3192 {
3193  union REGS regs;
3194  char FAR *str_ptr;
3195 
3196  str_ptr=str;
3197  regs.h.ah=2;                           /* Jung does it in the loop but we
3198                                            don't. */
3199  while(str_ptr[0]!='\0')
3200  {
3201   regs.h.dl=(str_ptr++)[0];
3202   intdos(&regs, &regs);
3203  }
3204 }
3205 #endif
3206 
3207 /* Reads one character from keyboard without echo. Used only by internal
3208    functions of ENVIRON.C */
3209 
3210 #if SFX_LEVEL>=ARJSFXV&&TARGET==DOS
flush_and_getch()3211 static int flush_and_getch()
3212 {
3213  union REGS regs;
3214 
3215  regs.x.ax=0xC08;                          /* Clear buffer and then getch */
3216  intdos(&regs, &regs);
3217  return((int)regs.h.al);
3218 }
3219 #endif
3220 
3221 /* "Intelligent" interrupt 24h handler */
3222 
3223 #if SFX_LEVEL>=ARJSFXV&&TARGET==DOS
3224 #if COMPILER==BCC
int24_smart_handler(unsigned int bp,unsigned int di,unsigned int si,unsigned int ds,unsigned int es,unsigned int dx,unsigned int cx,unsigned int bx,unsigned int ax)3225 static void interrupt int24_smart_handler(unsigned int bp, unsigned int di,
3226                                           unsigned int si, unsigned int ds,
3227                                           unsigned int es, unsigned int dx,
3228                                           unsigned int cx, unsigned int bx,
3229                                           unsigned int ax)
3230 #elif COMPILER==MSC
3231 void _interrupt _far int24_smart_handler( unsigned int es, unsigned int ds,
3232                                             unsigned int di, unsigned int si,
3233                                             unsigned int bp, unsigned int sp,
3234                                             unsigned int bx, unsigned int dx,
3235                                             unsigned int cx, unsigned int ax,
3236                                             unsigned int ip, unsigned int cs,
3237                                             unsigned int flags)
3238 #endif
3239 {
3240  char msg[40];
3241  char query[64];
3242  #if COMPILER==BCC
3243   struct DOSERROR exterr;
3244  #elif COMPILER==MSC
3245   union REGS regs;
3246  #endif
3247  char dev[12];
3248  char *action;
3249  FMSG *final_response;
3250  int user_action;
3251  char response;
3252  char drive;
3253  int errcode;
3254  #if COMPILER==MSC
3255   int dos_errcode;
3256  #endif
3257  int dev_ctr;
3258 
3259  #if COMPILER==MSC
3260   _enable();
3261   dos_errcode=errcode=di&0xFF;
3262  #endif
3263  action=malloc_fmsg(ax&INT24_DPF_WRITING?M_WRITING:M_READING);
3264  #if SFX_LEVEL>=ARJ
3265   if(errcode>0x12)
3266    errcode=0x12;                        /* Ignore DOS 4.x error codes */
3267   if(_osmajor>=3)
3268   {
3269    #if COMPILER==BCC
3270     errcode=dosexterr(&exterr);
3271    #elif COMPILER==MSC
3272     regs.h.ah=0x59;
3273     regs.x.bx=0;
3274     intdos(&regs, &regs);
3275     errcode=regs.x.ax;
3276    #endif
3277    if(errcode<0x13||errcode>0x25)
3278     errcode=0x25;                       /* Ignore DOS 2.x/4.x error codes */
3279    errcode-=0x13;
3280   }
3281   msg_strcpyn((FMSG *)msg, DOS_MSGS[errcode], sizeof(msg)-1);
3282  #else
3283   if(errcode>0x0D)
3284    errcode=0x0D;
3285  #endif
3286  if(ax&INT24_IO_ERROR)
3287  {
3288   if(((char *)MK_FP(bp, si))[5]&0x80)
3289    far_ttyout((char FAR *)M_CRIT_ERROR);
3290   else
3291   {
3292    for(dev_ctr=0; dev_ctr<8; dev_ctr++)
3293     dev[dev_ctr]=((char *)MK_FP(bp, si))[10+dev_ctr];
3294    dev[dev_ctr]='\0';
3295    msg_sprintf(query, M_DEVICE, msg, action, dev);
3296    far_ttyout((char FAR *)query);
3297   }
3298  }
3299  else
3300  {
3301   #if COMPILER==MSC
3302    if(f_file_ptr!=NULL&&dos_errcode==0x0D||dos_errcode==0x0E)
3303     msg_sprintf(query, M_FOPEN, msg, f_file_ptr);
3304    else
3305   #endif
3306   {
3307    drive=(char)ax+'A';
3308    msg_sprintf(query, M_DRIVE, msg, action, drive);
3309   }
3310   far_ttyout((char FAR *)query);
3311  }
3312  user_action=1;
3313  if(ignore_errors)
3314  {
3315   free_fmsg(action);
3316   ax=INT24_FAIL;
3317  }
3318  else
3319  {
3320   query[1]=CR;
3321   query[2]=LF;
3322   query[3]='\0';
3323   do
3324   {
3325    far_ttyout((char FAR *)M_OK_TO_RETRY);
3326    query[0]=response=(char)flush_and_getch();
3327    far_ttyout((char FAR *)query);
3328   }
3329   while((final_response=msg_strchr(M_REPLIES, (char)toupper(response)))==NULL||
3330         (user_action=final_response-M_REPLIES)>2);
3331   free_fmsg(action);
3332   if(user_action==0)
3333    ax=INT24_RETRY;
3334   else if(user_action==2||is_dos_31)    /* DOS 2.x/3.0 do not support FAIL */
3335    ax=INT24_ABORT;
3336   else
3337   {
3338    ax=INT24_FAIL;
3339    user_wants_fail=-1;
3340   }
3341  }
3342 }
3343 #endif
3344 
3345 /* Installs the "smart" handler */
3346 
3347 #if SFX_LEVEL>=ARJSFXV
install_smart_handler()3348 void install_smart_handler()
3349 {
3350  #if TARGET==DOS
3351   setvect(INT24, int24_smart_handler);
3352  #elif TARGET==OS2
3353   if(ignore_errors)
3354   {
3355    #ifdef __32BIT__
3356     DosError(FERR_DISABLEHARDERR|FERR_DISABLEEXCEPTION);
3357    #else
3358     DosError(HARDERROR_DISABLE);
3359     DosError(EXCEPTION_DISABLE);
3360    #endif
3361   }
3362  #elif TARGET==UNIX
3363   /* No hard error daemon here */
3364  #endif
3365 }
3366 #endif
3367 
3368 /* Checks if the given file handle actually represents a file */
3369 
3370 #if SFX_LEVEL>=ARJSFXV
is_file(FILE * stream)3371 int is_file(FILE *stream)
3372 {
3373  #if TARGET==DOS
3374   #if COMPILER==BCC
3375    return(ioctl(fileno(stream), 0)&CHDF_NOT_FILE?1:0);
3376   #elif COMPILER==MSC
3377    union REGS regs;
3378 
3379    regs.x.ax=0x4400;
3380    regs.x.bx=fileno(stream);
3381    intdos(&regs, &regs);
3382    return(regs.x.dx&CHDF_NOT_FILE?1:0);
3383   #endif
3384  #elif TARGET==OS2||TARGET==WIN32
3385   return(fileno(stream)<2?1:0);         /* Another dirty hack... */
3386  #else
3387   struct stat st;
3388 
3389   fstat(fileno(stream), &st);
3390   /* ASR fix 02/05/2003: ineed, we shouldn't check for FATTR_DT_REG here! */
3391   return(st.st_mode==S_IFREG);
3392  #endif
3393 }
3394 #endif
3395 
3396 /* Returns 1 if the given file is stored on removable media */
3397 
3398 #if SFX_LEVEL>=ARJSFXV
file_is_removable(char * name)3399 int file_is_removable(char *name)
3400 {
3401  #if TARGET!=UNIX
3402   char drive=0;
3403 
3404   while(name[0]==' ')
3405    name++;
3406   if(name[1]==':')
3407    drive=toupper(name[0])-0x40;
3408   else
3409    drive=getdisk()+1;
3410   #if TARGET==DOS
3411    if(_osmajor<3)                        /* DOS 2.x - A: and B: are removable */
3412     return(drive==1||drive==2);
3413    else
3414    #if COMPILER==BCC
3415     return(ioctl(drive, 8)==0);
3416    #elif COMPILER==MSC
3417    {
3418     union REGS regs;
3419 
3420     regs.x.ax=0x4408;
3421     regs.x.bx=(unsigned int)drive;
3422     intdos(&regs, &regs);
3423     return(regs.x.ax==0);
3424    }
3425   #endif
3426   #elif TARGET==OS2||TARGET==WIN32
3427    return(drive==1||drive==2);
3428   #endif
3429  #else
3430   return(0);                            /* BUGBUG: fix for floppies! */
3431  #endif
3432 }
3433 #endif
3434 
3435 /* Checks if the given file handle represends a terminal or console */
3436 
3437 #if SFX_LEVEL>=ARJSFXV||defined(REARJ)
is_tty(FILE * stream)3438 int is_tty(FILE *stream)
3439 {
3440  return(isatty(fileno(stream))==0?0:1);
3441 }
3442 #endif
3443 
3444 /* mkdir() - Borland's implementation */
3445 
3446 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
file_mkdir(char * name)3447 int file_mkdir(char *name)
3448 {
3449  #if TARGET==DOS
3450   if(lfn_supported!=LFN_NOT_SUPPORTED)
3451    return(w95_mkdir(name));
3452   else
3453    return(mkdir(name));
3454  #elif TARGET==OS2||TARGET==WIN32
3455   #ifdef __EMX__
3456    return(mkdir(name, 0));
3457   #else
3458    return(mkdir(name));
3459   #endif
3460  #else
3461   return(mkdir(name, 0755));
3462  #endif
3463 }
3464 #endif
3465 
3466 #if (TARGET==OS2||TARGET==WIN32)&&!defined(TILED)
3467 
3468 /* The "workhorse" routine for wildcard matching */
3469 
wild_proc(char * wild,char * name,UINT32 * trail,unsigned int first,unsigned int nesting)3470 static int wild_proc(char *wild, char *name, UINT32 *trail, unsigned int first, unsigned int nesting)
3471 {
3472  #define set_trail(w,r) trail[((w)*MAXWILDAST+(r))>>5]|=(1<<(((w)*MAXWILDAST+(r))&31))
3473  #define check_trail(w,r) (trail[((w)*MAXWILDAST+(r))>>5]&(1<<(((w)*MAXWILDAST+(r))&31)))
3474  int rc=1;
3475 
3476  if(nesting>=MAXWILDAST)
3477   return(1);
3478  while(*wild)
3479  {
3480   switch(*wild)
3481   {
3482    case '?':
3483     if(*name=='\0')
3484      return(1);
3485     wild++;
3486     break;
3487    case '*':
3488     if(!check_trail(first, nesting)&&!wild_proc(wild+1, name, trail, first, nesting+1))
3489      return(0);
3490     if(*name=='\0')
3491      return(1);
3492     set_trail(first, nesting);
3493     break;
3494    default:
3495     if(toupper(*name)!=toupper(*wild))
3496      return(1);
3497     wild++;
3498   }
3499   name++;
3500   first++;
3501  }
3502  return(*name!=*wild);
3503  #undef set_trail
3504  #undef check_trail
3505 }
3506 #endif
3507 
3508 /* Returns non-zero if the given filename matches the given wildcard */
3509 
3510 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
match_wildcard(char * name,char * wcard)3511 int match_wildcard(char *name, char *wcard)
3512 {
3513  #if TARGET==DOS
3514   if(!stricmp(wcard, all_wildcard))
3515    return(1);
3516   while(wcard[0]!='\0')
3517   {
3518    switch(wcard[0])
3519    {
3520     case '*':
3521      while(name[0]!='\0'&&name[0]!='.')
3522       name++;
3523      while(wcard[0]!='\0'&&wcard[0]!='.')
3524       wcard++;
3525      break;
3526     case '.':
3527      if(name[0]!='\0')
3528      {
3529       if(name[0]!=wcard[0])
3530        return(0);
3531       name++;
3532      }
3533      wcard++;
3534      break;
3535     case '?':
3536      if(name[0]!='\0'&&name[0]!='.')
3537       name++;
3538      wcard++;
3539      break;
3540     default:
3541      if(toupper(name[0])!=toupper(wcard[0]))
3542       return(0);
3543     name++;
3544     wcard++;
3545    }
3546   }
3547   return(name[0]=='\0'?1:0);
3548  #elif TARGET==OS2&&defined(TILED)
3549   char dest[CCHMAXPATH];
3550 
3551   /* This is a speedy and compact hack for 16-bit mode */
3552   DosEditName(0x0001, name, wcard, dest, CCHMAXPATH);
3553   return(!stricmp(dest, name));
3554  #elif TARGET==OS2||TARGET==WIN32
3555   char tmp_wild[CCHMAXPATH];
3556   /* Bit map: (maximum # of wildcards) x (maximum pattern length) */
3557   UINT32 trail[(MAXWILDAST*CCHMAXPATHCOMP+31)>>5];
3558   int l;
3559 
3560   memcpy(tmp_wild, wcard, (l=strlen(wcard))+1);
3561   memset(trail, 0, sizeof(trail));
3562   if(tmp_wild[l-1]=='.')
3563   {
3564    if(strchr(name, '.')!=NULL)
3565     return(1);
3566    tmp_wild[l-1]='\0';
3567   }
3568   return(!wild_proc(tmp_wild, name, trail, 0, 0));
3569  #else
3570   int rc;
3571 
3572   rc=fnmatch(wcard, name, 0);
3573   #ifndef TOLERANT_FNMATCH
3574    if(rc)
3575     rc=strcmp_os(wcard, name);
3576   #endif
3577   return(!rc);
3578  #endif
3579 }
3580 #endif
3581 
3582 /* rmdir() */
3583 
3584 #if SFX_LEVEL>=ARJ||defined(REARJ)
file_rmdir(char * name)3585 int file_rmdir(char *name)
3586 {
3587  #if TARGET!=UNIX
3588   if(clear_archive_bit)
3589    dos_chmod(name, FATTR_NOARCH);
3590  #endif
3591  #if TARGET==DOS
3592   if(lfn_supported!=LFN_NOT_SUPPORTED)
3593    return(w95_rmdir(name));
3594   else
3595    return(rmdir(name));
3596  #else
3597   return(rmdir(name));
3598  #endif
3599 }
3600 #endif
3601 
3602 /* unlink() */
3603 
3604 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
file_unlink(char * name)3605 int file_unlink(char *name)
3606 {
3607  #if SFX_LEVEL>=ARJSFXV&&TARGET!=UNIX
3608   if(file_test_access(name))
3609    return(-1);
3610   #if SFX_LEVEL>=ARJ
3611    if(clear_archive_bit)
3612     dos_chmod(name, 0);
3613   #else
3614    if(overwrite_ro)
3615     dos_chmod(name, 0);
3616   #endif
3617  #endif
3618  #if TARGET==DOS
3619   if(lfn_supported!=LFN_NOT_SUPPORTED)
3620    return(w95_unlink(name));
3621   else
3622    return(unlink(name));
3623  #else
3624   return(unlink(name));
3625  #endif
3626 }
3627 #endif
3628 
3629 /* rename() */
3630 
3631 #if SFX_LEVEL>=ARJ||defined(REARJ)
file_rename(char * oldname,char * newname)3632 int file_rename(char *oldname, char *newname)
3633 {
3634  #if TARGET==DOS
3635   if(lfn_supported!=LFN_NOT_SUPPORTED)
3636    return(w95_rename(oldname, newname));
3637   else
3638    return(rename(oldname, newname));
3639  #else
3640   return(rename(oldname, newname));
3641  #endif
3642 }
3643 #endif
3644 
3645 /* This INT 24h handler always forces the operation that causes it to fail */
3646 
3647 #if SFX_LEVEL>=ARJ&&TARGET==DOS
3648 #if COMPILER==BCC
int24_autofail_handler(unsigned int bp,unsigned int di,unsigned int si,unsigned int ds,unsigned int es,unsigned int dx,unsigned int cx,unsigned int bx,unsigned int ax)3649 static void interrupt int24_autofail_handler(unsigned int bp, unsigned int di,
3650                                              unsigned int si, unsigned int ds,
3651                                              unsigned int es, unsigned int dx,
3652                                              unsigned int cx, unsigned int bx,
3653                                              unsigned int ax)
3654 #elif COMPILER==MSC
3655 void _interrupt _far int24_autofail_handler(unsigned int es, unsigned int ds,
3656                                            unsigned int di, unsigned int si,
3657                                            unsigned int bp, unsigned int sp,
3658                                            unsigned int bx, unsigned int dx,
3659                                            unsigned int cx, unsigned int ax,
3660                                            unsigned int ip, unsigned int cs,
3661                                            unsigned int flags)
3662 #endif
3663 {
3664  char msg[40];
3665  char query[64];
3666  #if COMPILER==BCC
3667   struct DOSERROR exterr;
3668  #elif COMPILER==MSC
3669   union REGS regs;
3670  #endif
3671  char *action;
3672  char drive;
3673  int errcode;
3674 
3675  #if COMPILER==MSC
3676   _enable();
3677  #endif
3678  action=malloc_fmsg(ax&INT24_DPF_WRITING?M_WRITING:M_READING);
3679  errcode=di&0xFF;
3680  if(errcode>0x12)
3681   errcode=0x12;                         /* Ignore DOS 4.x error codes */
3682  if(_osmajor>=3)
3683  {
3684    #if COMPILER==BCC
3685     errcode=dosexterr(&exterr);
3686    #elif COMPILER==MSC
3687     regs.h.ah=0x59;
3688     regs.x.bx=0;
3689     intdos(&regs, &regs);
3690     errcode=regs.x.ax;
3691    #endif
3692   if(errcode<0x13||errcode>0x25)
3693    errcode=0x25;                        /* Ignore DOS 2.x/4.x error codes */
3694   errcode-=0x13;
3695  }
3696  msg_strcpyn((FMSG *)msg, DOS_MSGS[errcode], sizeof(msg)-1);
3697  drive=(char)(ax&0xFF)+'A';
3698  msg_sprintf(query, M_DRIVE, msg, action, drive);
3699  far_ttyout(query);
3700  free_fmsg(action);
3701  ax=INT24_FAIL;
3702 }
3703 #endif
3704 
3705 /* Clears the archive attribute */
3706 
3707 #if SFX_LEVEL>=ARJ
dos_clear_arch_attr(char * name)3708 int dos_clear_arch_attr(char *name)
3709 {
3710  #if TARGET!=UNIX
3711   int cur_attr, result;
3712   #if TARGET==DOS
3713    #if COMPILER==BCC
3714     void interrupt (*oldhdl)();
3715    #elif COMPILER==MSC
3716     void (_interrupt _far *oldhdl)();
3717    #endif
3718   #endif
3719 
3720   cur_attr=file_chmod(name, 0, 0)&STD_FILE_ATTR;
3721   if((cur_attr&~FATTR_ARCH)==cur_attr)
3722    return(0);
3723   cur_attr&=~FATTR_ARCH;
3724   #if TARGET==DOS
3725    if(is_dos_31)
3726     result=file_chmod(name, 1, cur_attr);
3727    else
3728    {
3729     oldhdl=getvect(INT24);
3730     setvect(INT24, int24_autofail_handler);
3731      result=file_chmod(name, 1, cur_attr);
3732     setvect(INT24, oldhdl);
3733    }
3734   #elif TARGET==OS2||TARGET==WIN32
3735    result=file_chmod(name, 1, cur_attr);
3736   #endif
3737   return(result==-1?-1:0);
3738  #else
3739   return(0);
3740  #endif
3741 }
3742 #endif
3743 
3744 /* Flushes the disk cache and resets the drive (W95) */
3745 
3746 #if SFX_LEVEL>=ARJ&&TARGET==DOS
w95_resetdrive(int drive)3747 static int w95_resetdrive(int drive)
3748 {
3749  union REGS regs;
3750  struct SREGS sregs;
3751 
3752  memset(&sregs, 0, sizeof(sregs));
3753  regs.x.cx=W95_FLUSH_CACHE;
3754  regs.x.dx=drive;
3755  return(call_dos_int(W95_RESETDRIVE, &regs, &sregs)?-1:0);
3756 }
3757 #endif
3758 
3759 /* Flushes the disk cache and resets the drive (W95) */
3760 
3761 #if SFX_LEVEL>=ARJ
reset_drive(char * name)3762 int reset_drive(char *name)
3763 {
3764  #if TARGET==DOS
3765   int drive;
3766 
3767   while(name[0]==' ')
3768    name++;
3769   if(name[1]==':')
3770    drive=(int)(toupper(name[0]))-0x40;
3771   else
3772    drive=getdisk()+1;
3773   if(_osmajor<7)                        /* DOS 2.x - A: and B: are removable */
3774   {
3775    bdos(0x0D, 0, 0);
3776    return(1);
3777   }
3778   else
3779   {
3780    if(w95_test_for_lfn(drive_c))
3781    {
3782     w95_resetdrive(drive);
3783     return(1);
3784    }
3785    else
3786     return(0);
3787   }
3788  #elif TARGET==OS2
3789   HFILE hf;
3790   #ifdef __32BIT__
3791    ULONG action;
3792   #else
3793    USHORT action;
3794   #endif
3795 
3796   if(DosOpen(name, &hf, &action, 0L, 0, FILE_OPEN, OPEN_ACCESS_READONLY|OPEN_SHARE_DENYNONE, 0L))
3797    return(0);
3798   #ifdef TILED
3799    DosBufReset(hf);
3800   #else
3801    DosResetBuffer(hf);
3802   #endif
3803   DosClose(hf);
3804   return(0);
3805  #elif TARGET==WIN32
3806   return(0);
3807  #elif TARGET==UNIX
3808   sync();
3809   return(0);
3810  #endif
3811 }
3812 #endif
3813 
3814 /* Checks for pending keystrokes and clears the keyboard buffer. */
3815 
3816 #if SFX_LEVEL>=ARJSFXV||defined(REARJ)
fetch_keystrokes()3817 int fetch_keystrokes()
3818 {
3819  #if TARGET==DOS
3820   union REGS regs;
3821   int rc=0;
3822 
3823   while(kbhit())
3824   {
3825    regs.h.ah=7;
3826    intdos(&regs, &regs);
3827    rc=1;
3828   }
3829   return(rc);
3830  #elif TARGET==OS2
3831   #if COMPILER==MSC
3832    int rc=0;
3833    KBDKEYINFO keyinfo;
3834 
3835    while(kbhit())
3836    {
3837     rc=1;
3838     KbdCharIn(&keyinfo, IO_WAIT, 0);
3839    }
3840    return(rc);
3841   #else
3842    KBDKEYINFO keyinfo;
3843    int rc, pressed;
3844    int frc=0;
3845 
3846    do
3847    {
3848     rc=KbdPeek(&keyinfo, 0);
3849     pressed=rc?0:(keyinfo.fbStatus&KBDTRF_FINAL_CHAR_IN);
3850     if(pressed)
3851     {
3852      frc=1;
3853      KbdCharIn(&keyinfo, IO_WAIT, 0);
3854     }
3855    } while(pressed);
3856    return(frc);
3857   #endif
3858  #else
3859   return(0);                            /* Not implemented */
3860  #endif
3861 }
3862 #endif
3863 
3864 /* Changes the current directory and/or drive */
3865 
3866 #if SFX_LEVEL>=ARJSFX&&SFX_LEVEL<=ARJSFXV
file_chdir(char * dir)3867 void file_chdir(char *dir)
3868 {
3869  #ifdef HAVE_DRIVES
3870   int l;
3871   char *tmp_dir;
3872 
3873   if((l=strlen(dir))>2)
3874   {
3875    if(dir[1]==':')
3876 
3877    if((dir[l-1]==PATHSEP_DOS||dir[l-1]==PATHSEP_UNIX)&&(dir[1]!=':'||l!=3))
3878    {
3879     tmp_dir=malloc(l);
3880     if(tmp_dir==NULL)                   /* ASR fix 29/10/2000 */
3881      return;
3882     strcpy(tmp_dir, dir);
3883     tmp_dir[l-1]='\0';
3884     chdir(tmp_dir);
3885     free(tmp_dir);
3886    }
3887   }
3888  #else
3889   chdir(dir);
3890  #endif
3891 }
3892 #elif defined(REARJ)                    /* REARJ modification (LFN-capable) */
file_chdir(char * dir)3893 int file_chdir(char *dir)
3894 {
3895  #ifdef HAVE_DRIVES
3896   char dest_disk;
3897 
3898   if(dir[1]==':')
3899   {
3900    dest_disk=toupper(dir[0])-'A';
3901    if(setdisk(dest_disk)<dest_disk)
3902     return(1);
3903    if(dir[2]=='\0')
3904     return(1);
3905   }
3906   #if TARGET==DOS
3907    if(lfn_supported)
3908     return(w95_chdir(dir)?1:0);
3909    else
3910     return(chdir(dir)?1:0);
3911   #elif TARGET==OS2||TARGET==WIN32
3912    return(chdir(dir)?1:0);
3913   #endif
3914  #else
3915   return(chdir(dir));
3916  #endif
3917 }
3918 #endif
3919 
3920 /* This routine needs to be moved on top of file_unlink. */
3921 
3922 #if SFX_LEVEL>=ARJSFX||defined(REARJ)
dos_chmod(char * name,int attrib)3923 int dos_chmod(char *name, int attrib)
3924 {
3925  #if TARGET!=UNIX
3926   return(file_chmod(name, 1, attrib&STD_FILE_ATTR)==-1?-1:0);
3927  #else
3928   return(file_chmod(name, 1, attrib)==-1?-1:0);
3929  #endif
3930 }
3931 #endif
3932 
3933 /* Changes the size of the file (Borland-specific implementation) */
3934 
3935 #if SFX_LEVEL>=ARJ
file_chsize(FILE * stream,unsigned long size)3936 int file_chsize(FILE *stream, unsigned long size)
3937 {
3938  #if TARGET!=UNIX
3939   return(chsize(fileno(stream), size));
3940  #else
3941   return(ftruncate(fileno(stream), size));
3942  #endif
3943 }
3944 #endif
3945 
3946 /* Sets last modification date/time for a file specified by handle */
3947 
3948 #if (SFX_LEVEL==ARJSFXJR||SFX_LEVEL>=ARJ)&&TARGET!=UNIX
file_setftime_on_hf(int hf,unsigned long ftime)3949 int file_setftime_on_hf(int hf, unsigned long ftime)
3950 {
3951  #if TARGET==DOS
3952   #if COMPILER==BCC
3953    return(setftime(hf, (struct ftime *)&ftime));
3954   #elif COMPILER==MSC
3955    return(_dos_setftime(hf, *((unsigned int *)&ftime+1), *(unsigned int *)&ftime));
3956   #endif
3957  #elif TARGET==OS2
3958   HFILE hfc;
3959   FILESTATUS fstatus;
3960 
3961   hfc=(HFILE)hf;                        /* Dirty hack but it works */
3962   DosQFileInfo(hfc, FIL_STANDARD, &fstatus, sizeof(fstatus));
3963   *(USHORT *)&fstatus.fdateLastWrite=ftime>>16;
3964   *(USHORT *)&fstatus.ftimeLastWrite=ftime&0xFFFF;
3965   return(DosSetFileInfo(hfc, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus)));
3966  #elif TARGET==WIN32
3967   return(-1);                           /* Nobody wants to play it under
3968                                            Win32 (fileno is NOT a HANDLE) */
3969  #endif
3970 }
3971 #endif
3972 
3973 /* Updates the modification date/time field in the file's directory entry for
3974    a file that has been already open. */
3975 
3976 #if SFX_LEVEL>=ARJ&&TARGET!=UNIX
file_setftime_on_stream(FILE * stream,unsigned long ftime)3977 int file_setftime_on_stream(FILE *stream, unsigned long ftime)
3978 {
3979  return(file_setftime_on_hf(fileno(stream), ftime));
3980 }
3981 #endif
3982 
3983 /* UNIX file time request router */
3984 
3985 #if TARGET==UNIX&&(SFX_LEVEL>=ARJSFX||defined(REARJ))
ftime_router(char * name,int idx,unsigned long ftime)3986 static int ftime_router(char *name, int idx, unsigned long ftime)
3987 {
3988  struct stat st;
3989  struct utimbuf ut;
3990  int rc;
3991  #if SFX_LEVEL>=ARJ
3992   struct stat resolved_st;
3993   int res_cnt, protect_resolved=0;
3994   char resolved_name[CCHMAXPATH];
3995  #endif
3996 
3997  if(lstat(name, &st)==-1)
3998   return(-1);
3999  /* If it is a symlink, protect the original file */
4000  if(S_ISLNK(st.st_mode))
4001  {
4002   #if SFX_LEVEL>=ARJ
4003    if(!symlink_accuracy)
4004     return(-1);
4005    res_cnt=readlink(name, resolved_name, sizeof(resolved_name)-1);
4006    if(res_cnt>0)
4007    {
4008     resolved_name[res_cnt]='\0';
4009     if(stat(name, &resolved_st)!=-1)
4010      protect_resolved=1;
4011    }
4012   #else
4013    return(-1);
4014   #endif
4015  }
4016  ut.actime=(idx==UFTREQ_ATIME)?ftime:st.st_atime;
4017  ut.modtime=(idx==UFTREQ_FTIME)?ftime:st.st_mtime;
4018  rc=utime(name, &ut);
4019  #if SFX_LEVEL>=ARJ
4020   if(protect_resolved)
4021   {
4022    ut.actime=resolved_st.st_atime;
4023    ut.modtime=resolved_st.st_mtime;
4024    rc=utime(resolved_name, &ut);
4025   }
4026  #endif
4027  return(rc);
4028 }
4029 #endif
4030 
4031 /* Updates the last access date field in the file's directory entry (unlike
4032    file_setftime, standard parameters are passed). */
4033 
4034 #if SFX_LEVEL>=ARJSFXV
file_setatime(char * name,unsigned long ftime)4035 int file_setatime(char *name, unsigned long ftime)
4036 {
4037  #if TARGET==DOS
4038   FILE *stream;
4039   int result;
4040 
4041   if(lfn_supported!=LFN_NOT_SUPPORTED)
4042   {
4043    if((stream=fopen(name, m_rbp))==NULL)
4044     if((stream=fopen(name, m_rb))==NULL)
4045      return(-1);
4046    result=w95_set_dta(fileno(stream), ftime);
4047    fclose(stream);
4048    return(result);
4049   }
4050   else
4051    return(0);
4052  #elif TARGET==OS2
4053   #ifdef __32BIT__
4054    FILESTATUS3 fstatus;
4055   #else
4056    FILESTATUS fstatus;
4057   #endif
4058 
4059   #ifdef __32BIT__
4060    DosQueryPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus));
4061   #else
4062    DosQPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0L);
4063   #endif
4064   *(USHORT *)&fstatus.fdateLastAccess=ftime>>16;
4065   *(USHORT *)&fstatus.ftimeLastAccess=ftime&0xFFFF;
4066   #ifdef __32BIT__
4067    return(DosSetPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0));
4068   #else
4069    return(DosSetPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0, 0L));
4070   #endif
4071  #elif TARGET==WIN32
4072   HANDLE hf;
4073   FILETIME satime, sftime, sctime;
4074 
4075   if((hf=CreateFile(name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0))==INVALID_HANDLE_VALUE)
4076    return(-1);
4077   GetFileTime(hf, &sctime, &satime, &sftime);
4078   ntify_time(&satime, ftime);
4079   SetFileTime(hf, &sctime, &satime, &sftime);
4080   CloseHandle(hf);
4081   return(0);
4082  #elif TARGET==UNIX
4083   return(ftime_router(name, UFTREQ_ATIME, ftime));
4084  #endif
4085 }
4086 #endif
4087 
4088 /* Updates the creation date/time field in the file's directory entry (unlike
4089    file_setftime, standard parameters are passed). */
4090 
4091 #if SFX_LEVEL>=ARJSFXV
file_setctime(char * name,unsigned long ftime)4092 int file_setctime(char *name, unsigned long ftime)
4093 {
4094  #if TARGET==DOS
4095   FILE *stream;
4096   int result;
4097  #endif
4098 
4099  #if TARGET==DOS
4100   if(lfn_supported!=LFN_NOT_SUPPORTED)
4101   {
4102    if((stream=fopen(name, m_rbp))==NULL)
4103     if((stream=fopen(name, m_rb))==NULL)
4104      return(-1);
4105    result=w95_set_dtc(fileno(stream), ftime);
4106    fclose(stream);
4107    return(result);
4108   }
4109   else
4110    return(0);
4111  #elif TARGET==OS2
4112   #ifdef __32BIT__
4113    FILESTATUS3 fstatus;
4114   #else
4115    FILESTATUS fstatus;
4116   #endif
4117 
4118   #ifdef __32BIT__
4119    DosQueryPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus));
4120   #else
4121    DosQPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0L);
4122   #endif
4123   *(USHORT *)&fstatus.fdateCreation=ftime>>16;
4124   *(USHORT *)&fstatus.ftimeCreation=ftime&0xFFFF;
4125   #ifdef __32BIT__
4126    return(DosSetPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0));
4127   #else
4128    return(DosSetPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0, 0L));
4129   #endif
4130  #elif TARGET==WIN32
4131   HANDLE hf;
4132   FILETIME satime, sftime, sctime;
4133 
4134   if((hf=CreateFile(name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0))==INVALID_HANDLE_VALUE)
4135    return(-1);
4136   GetFileTime(hf, &sctime, &satime, &sftime);
4137   ntify_time(&sctime, ftime);
4138   SetFileTime(hf, &sctime, &satime, &sftime);
4139   CloseHandle(hf);
4140   return(0);
4141  #elif TARGET==UNIX
4142   return(ftime_router(name, UFTREQ_CTIME, ftime));
4143  #endif
4144 }
4145 #endif
4146 
4147 /* Updates the modification date/time field in the file's directory entry */
4148 
4149 #if SFX_LEVEL>=ARJSFX||defined(REARJ)||defined(NEED_SETFTIME_HACK)
file_setftime(char * name,unsigned long ftime)4150 int file_setftime(char *name, unsigned long ftime)
4151 {
4152  #if TARGET==DOS
4153   FILE *stream;
4154   int result;
4155 
4156   if((stream=fopen(name, m_rbp))==NULL)
4157   #if SFX_LEVEL>=ARJSFXV
4158    if((stream=fopen(name, m_rb))==NULL)
4159   #endif
4160     return(-1);
4161   #if COMPILER==BCC
4162    result=setftime(fileno(stream), (struct ftime *)&ftime);
4163   #elif COMPILER==MSC
4164   result=_dos_setftime(fileno(stream), *((unsigned int *)&ftime+1), *(unsigned int *)&ftime);
4165   #endif
4166   fclose(stream);
4167   return(result);
4168  #elif TARGET==OS2
4169   #ifdef __32BIT__
4170    FILESTATUS3 fstatus;
4171   #else
4172    FILESTATUS fstatus;
4173   #endif
4174 
4175   #ifdef __32BIT__
4176    DosQueryPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus));
4177   #else
4178    DosQPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0L);
4179   #endif
4180   *(USHORT *)&fstatus.fdateLastWrite=ftime>>16;
4181   *(USHORT *)&fstatus.ftimeLastWrite=ftime&0xFFFF;
4182   #ifdef __32BIT__
4183    return(DosSetPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0));
4184   #else
4185    return(DosSetPathInfo(name, FIL_STANDARD, (PBYTE)&fstatus, sizeof(fstatus), 0, 0L));
4186   #endif
4187  #elif TARGET==WIN32
4188   HANDLE hf;
4189   FILETIME satime, sftime, sctime;
4190 
4191   if((hf=CreateFile(name, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0))==INVALID_HANDLE_VALUE)
4192    return(-1);
4193   GetFileTime(hf, &sctime, &satime, &sftime);
4194   ntify_time(&sftime, ftime);
4195   SetFileTime(hf, &sctime, &satime, &sftime);
4196   CloseHandle(hf);
4197   return(0);
4198  #elif TARGET==UNIX
4199   return(ftime_router(name, UFTREQ_FTIME, ftime));
4200  #endif
4201 }
4202 #endif
4203 
4204 /* Sets the volume label */
4205 
4206 #if SFX_LEVEL>=ARJSFXV&&defined(HAVE_DRIVES)
file_setlabel(char * label,char drive,ATTRIB attrib,unsigned long ftime)4207 int file_setlabel(char *label, char drive, ATTRIB attrib, unsigned long ftime)
4208 {
4209  #if TARGET==DOS
4210   union REGS regs;
4211   char fnm[64];
4212   struct xfcb xfcb;
4213   char dta[64];
4214   char FAR *saved_dta;
4215   int handle;
4216 
4217   if(_osmajor<2)
4218    return(-1);
4219   /* Set DTA so it'll point to an internal structure */
4220   saved_dta=getdta();
4221   setdta((char FAR *)dta);
4222   /* Fill the extended FCB structure */
4223   xfcb.xfcb_flag=0xFF;
4224   xfcb.xfcb_attr=FATTR_LABEL;
4225   if(drive!='\0')
4226    xfcb.xfcb_fcb.fcb_drive=toupper(drive)-0x40;
4227   strcpy(xfcb.xfcb_fcb.fcb_name, fcb_mask);
4228   /* Find first matching file (i.e., volume label) using this FCB. Note that
4229      the current directory does not need to be root. */
4230   regs.h.ah=0x11;                        /* findfirst() for FCB */
4231   regs.x.dx=(unsigned int)&xfcb;
4232   intdos(&regs, &regs);
4233   setdta(saved_dta);                     /* Temporarily restore the DTA */
4234   if(_osmajor==2)
4235   {
4236    /* If there's a label, just rename it */
4237    if(regs.h.al==0)
4238    {
4239     #if COMPILER==BCC
4240      parsfnm(label, (struct fcb *)(dta+0x17), 3);
4241     #elif COMPILER==MSC
4242      regs.x.ax=0x2903;
4243      regs.x.si=(unsigned int)label;
4244      regs.x.di=(unsigned int)(dta+0x17);
4245      intdos(&regs, &regs);
4246     #endif
4247     regs.h.ah=0x17;                       /* rename() for FCB */
4248     regs.x.dx=(unsigned int)dta;
4249     intdos(&regs, &regs);
4250    }
4251    /* Otherwise, create a new file */
4252    else
4253    {
4254     #if COMPILER==BCC
4255      parsfnm(label, &xfcb.xfcb_fcb, 3);
4256     #elif COMPILER==MSC
4257      regs.x.ax=0x2903;
4258      regs.x.si=(unsigned int)label;
4259      regs.x.di=(unsigned int)&xfcb.xfcb_fcb;
4260      intdos(&regs, &regs);
4261     #endif
4262     regs.h.ah=0x16;                       /* create file using FCB */
4263     regs.x.dx=(unsigned int)&xfcb;
4264     intdos(&regs, &regs);
4265     /* Close file if it has been created successfully */
4266     if(regs.h.al==0)
4267     {
4268      regs.h.ah=0x10;                      /* fclose() for FCB */
4269      regs.x.dx=(unsigned int)&xfcb;
4270      intdos(&regs, &regs);
4271     }
4272    }
4273    return((int)regs.h.al);
4274   }
4275   /* DOS 3.x */
4276   else
4277   {
4278    if(regs.h.al==0)                      /* Check RC from findfirst() */
4279    {
4280     regs.h.ah=0x13;                      /* unlink() for FCB */
4281     regs.x.dx=(unsigned int)dta;
4282     intdos(&regs, &regs);
4283    }
4284    if(drive!='\0')
4285    {
4286     fnm[0]=drive;
4287     fnm[1]=':';
4288     fnm[2]='\0';
4289    }
4290    else
4291     fnm[0]='\0';
4292    strcat(fnm, label);
4293    if((handle=_creat(fnm, FATTR_LABEL))==EOF)
4294     return(-1);
4295    #if COMPILER==BCC
4296     setftime(handle, (struct ftime *)&ftime);
4297    #elif COMPILER==MSC
4298     return(_dos_setftime(handle, *((unsigned int *)&ftime+1), *(unsigned int *)&ftime));
4299    #endif
4300    _close(handle);
4301    return(0);
4302   }
4303  #elif TARGET==OS2
4304   VOLUMELABEL vl;
4305 
4306   strcpyn(vl.szVolLabel, label, 11);
4307   vl.cch=strlen(vl.szVolLabel);
4308   return(DosSetFSInfo(drive=='\0'?0:drive-0x40, FSIL_VOLSER, (PBYTE)&vl, sizeof(vl)));
4309  #elif TARGET==WIN32
4310   char vn[4];
4311 
4312   vn[0]=drive;
4313   vn[1]=':';
4314   vn[2]='\\';
4315   vn[3]='\0';
4316   return(!SetVolumeLabel(vn, label));
4317  #endif
4318 }
4319 #endif
4320 
4321 /* Sets the file type */
4322 
4323 #if SFX_LEVEL>=ARJ
file_settype(FILE * stream,int istext)4324 int file_settype(FILE *stream, int istext)
4325 {
4326  #if TARGET!=UNIX
4327   fflush(stream);
4328   #if COMPILER==HIGHC&&!defined(LIBC)
4329    setmode(stream, istext?_O_TEXT:_O_BINARY);
4330   #else
4331    setmode(fileno(stream), istext?O_TEXT:O_BINARY);
4332   #endif
4333  #endif
4334  return(1);
4335 }
4336 #endif
4337 
4338 /* Sets the file API mode */
4339 
4340 #if SFX_LEVEL>=ARJ
set_file_apis(int is_ansi)4341 void set_file_apis(int is_ansi)
4342 {
4343  #if TARGET==WIN32
4344   if(is_ansi)
4345    SetFileApisToANSI();
4346   else
4347    SetFileApisToOEM();
4348  #endif
4349 }
4350 #endif
4351 
4352 /* Creates a subdirectory tree (qmode specifies if the user is to be asked).
4353    Returns 1 if an error occured */
4354 
4355 #if SFX_LEVEL>=ARJSFX
4356 #if SFX_LEVEL>=ARJSFXV
create_subdir_tree(char * path,int qmode,int datatype)4357 int create_subdir_tree(char *path, int qmode, int datatype)
4358 #else
4359 int create_subdir_tree(char *path, int datatype)
4360 #endif
4361 {
4362  char tmp_path[CCHMAXPATH];             /* Jung uses 256 but it's incorrect */
4363  char *tmp_ptr;
4364  int access_status;
4365  int no_queries;                        /* 1 automatically forces "yes" */
4366 
4367  #if SFX_LEVEL>=ARJSFXV
4368   tmp_ptr=validate_path(path, VALIDATE_ALL);
4369   no_queries=qmode||prompt_for_mkdir;
4370  #else
4371   tmp_ptr=validate_path(path);
4372   no_queries=yes_on_all_queries||make_directories;
4373  #endif
4374  while((tmp_ptr=find_delimiter(tmp_ptr, datatype))!=NULL)
4375  {
4376   strcpyn(tmp_path, path, tmp_ptr-path+1);
4377   if((access_status=file_chmod(tmp_path, 0, 0))==-1)
4378   {
4379    if(!no_queries)
4380    {
4381     #if SFX_LEVEL>=ARJSFXV
4382      msg_sprintf(misc_buf, M_QUERY_CREATE_DIR, path);
4383      /* If the user forbids creation, return 1 */
4384      if((no_queries=query_action(0, QUERY_CREATE_DIR, misc_buf))==0)
4385       return(1);
4386     #else
4387      msg_cprintf(0, M_QUERY_CREATE_DIR, path);
4388      if((no_queries=query_action())==0)
4389       return(1);
4390     #endif
4391    }
4392    if(file_mkdir(tmp_path)&&errno!=ENOENT)
4393    {
4394     /* Creation failed, inform the user about it */
4395     #if SFX_LEVEL>=ARJSFXV
4396      msg_cprintf(H_ERR, M_CANT_MKDIR, tmp_path);
4397     #else
4398      msg_cprintf(H_ERR, M_CANT_MKDIR, tmp_path);
4399     #endif
4400     #if SFX_LEVEL>=ARJ
4401      error_report();
4402     #endif
4403     return(1);
4404    }
4405   }
4406   else
4407   {
4408    /* If a file with the same name exists, jerk off... */
4409   #if TARGET!=UNIX
4410    if(!(access_status&FATTR_DIREC))
4411   #else
4412    struct stat st;
4413 
4414    if((stat(tmp_path, &st)==-1)||!S_ISDIR(st.st_mode))
4415   #endif
4416    {
4417     #if SFX_LEVEL>=ARJSFXV
4418      msg_cprintf(H_ERR, M_CANT_MKDIR, tmp_path);
4419     #else
4420      msg_cprintf(H_ERR, M_CANT_MKDIR, tmp_path);
4421     #endif
4422     return(1);
4423    }
4424   }
4425   if(*tmp_ptr!='\0')
4426    tmp_ptr++;
4427  }
4428  return(0);
4429 }
4430 #endif
4431 
4432 /* Returns 1 if the given filename is valid, 0 otherwise */
4433 
4434 #if SFX_LEVEL>=ARJSFXV
is_filename_valid(char * name)4435 int is_filename_valid(char *name)
4436 {
4437  return(name[0]=='\0'?0:1);
4438 }
4439 #endif
4440 
4441 /* Returns 1 if the given file is a directory, 0 otherwise */
4442 
4443 #if SFX_LEVEL>=ARJSFXV
is_directory(char * name)4444 int is_directory(char *name)
4445 {
4446  int attrib;
4447 
4448  attrib=file_chmod(name, 0, 0);
4449  if(attrib==-1)
4450   return(0);
4451  else
4452  #if TARGET!=UNIX
4453   return(attrib&FATTR_DIREC?1:0);
4454  #else
4455   return(S_ISDIR(attrib));
4456  #endif
4457 }
4458 #endif
4459 
4460 /* Allocate memory and create a wildcard that expands to all files of the
4461    subdirectory given. */
4462 
4463 #if SFX_LEVEL>=ARJ
malloc_subdir_wc(char * name)4464 char *malloc_subdir_wc(char *name)
4465 {
4466  char tmp_wc[WC_RESERVE];
4467  char *wc_ptr;
4468 
4469  tmp_wc[0]=PATHSEP_DEFAULT;
4470  strcpy(tmp_wc+1, all_wildcard);
4471  wc_ptr=malloc_msg(strlen(tmp_wc)+strlen(name)+2);
4472  strcpy(wc_ptr, name);
4473  strcat(wc_ptr, tmp_wc);
4474  return(wc_ptr);
4475 }
4476 #endif
4477 
4478 /* Copies one file to another, performing a check if needed. Issues a native
4479    API if the target platform supports it (note: Win32 does not provide a
4480    way to verify the file so we avoid the CopyFile function under Win32) */
4481 
4482 #if SFX_LEVEL>=ARJ
file_copy(char * dest,char * src,int chk)4483 int file_copy(char *dest, char *src, int chk)
4484 {
4485  #if TARGET==OS2
4486   #ifdef __32BIT__
4487    BOOL32 vf;
4488    APIRET rc;
4489   #else
4490    BOOL vf;
4491    USHORT rc;
4492   #endif
4493 
4494   if(chk)
4495   {
4496    #ifdef __32BIT__
4497     DosQueryVerify(&vf);
4498    #else
4499     DosQVerify(&vf);
4500    #endif
4501    DosSetVerify(1);
4502   }
4503   #ifdef __32BIT__
4504    rc=DosCopy(src, dest, DCPY_EXISTING);
4505   #else
4506    rc=DosCopy(src, dest, DCPY_EXISTING, 0);
4507   #endif
4508   if(chk)
4509   {
4510    msg_cprintf(0, M_TESTING, dest);
4511    DosSetVerify(vf);
4512   }
4513   switch(rc)
4514   {
4515    case NO_ERROR:
4516     break;
4517    case ERROR_FILE_NOT_FOUND:
4518    case ERROR_PATH_NOT_FOUND:
4519    case ERROR_ACCESS_DENIED:
4520    case ERROR_SHARING_VIOLATION:
4521     msg_cprintf(H_ERR, M_CANTOPEN, src);
4522     break;
4523    case ERROR_DISK_FULL:
4524     msg_cprintf(0, M_DISK_FULL);
4525     break;
4526    default:
4527     msg_cprintf(0, M_CRC_ERROR);
4528     break;
4529   }
4530   if(rc)
4531   {
4532    nputlf();
4533    return(-1);
4534   }
4535   return(0);
4536  #else
4537   FILE *istream, *ostream;
4538   char *buf, *dbuf;
4539   unsigned int bytes_read;
4540 
4541   istream=file_open(src, m_rb);
4542   if(istream==NULL)
4543   {
4544    error_report();
4545    msg_cprintf(H_ERR, M_CANTOPEN, src);
4546    nputlf();
4547    return(-1);
4548   }
4549   ostream=file_open(dest, m_wb);
4550   if(ostream==NULL)
4551   {
4552    fclose(istream);
4553    error_report();
4554    msg_cprintf(H_ERR, M_CANTOPEN, dest);
4555    nputlf();
4556    return(-1);
4557   }
4558   buf=malloc_msg(PROC_BLOCK_SIZE);
4559   mem_stats();
4560   while((bytes_read=fread(buf, 1, PROC_BLOCK_SIZE, istream))>0)
4561   {
4562    if(fwrite(buf, 1, bytes_read, ostream)!=bytes_read)
4563    {
4564     msg_cprintf(0, M_DISK_FULL);
4565     nputlf();
4566     break;
4567    }
4568   }
4569   free(buf);
4570   if(fclose(ostream))
4571   {
4572    fclose(istream);
4573    return(-1);
4574   }
4575   if(fclose(istream))
4576    return(-1);
4577   if(file_is_removable(dest))
4578    reset_drive(dest);
4579   if(bytes_read==0&&chk)
4580   {
4581    msg_cprintf(0, M_TESTING, dest);
4582    istream=file_open(src, m_rb);
4583    if(istream==NULL)
4584    {
4585     error_report();
4586     msg_cprintf(H_ERR, M_CANTOPEN, src);
4587     nputlf();
4588     return(-1);
4589    }
4590    ostream=file_open(dest, m_rb);
4591    if(ostream==NULL)
4592    {
4593     fclose(istream);
4594     error_report();
4595     msg_cprintf(H_ERR, M_CANTOPEN, dest);
4596     nputlf();
4597     return(-1);
4598    }
4599    buf=malloc_msg(PROC_BLOCK_SIZE/2);
4600    dbuf=malloc_msg(PROC_BLOCK_SIZE/2);
4601    while((bytes_read=fread(buf, 1, PROC_BLOCK_SIZE/2, istream))>0)
4602    {
4603     if(fread(dbuf, 1, PROC_BLOCK_SIZE/2, ostream)!=bytes_read)
4604      break;
4605     if(memcmp(buf, dbuf, bytes_read))
4606      break;
4607    }
4608    free(buf);
4609    free(dbuf);
4610    fclose(ostream);
4611    fclose(istream);
4612    msg_cprintf(0, (FMSG *)vd_space);
4613    msg_cprintf(0, bytes_read==0?M_OK:M_CRC_ERROR);
4614   }
4615   return((bytes_read>0)?-1:0);
4616  #endif
4617 }
4618 #endif
4619 
4620 #if SFX_LEVEL>=ARJ||defined(REARJ)
4621 
4622 /* ASR fix 02/04/2003: Reduce memory consumption on 16-bit systems. */
4623 
4624 #ifdef TILED
pack_fname(char * f)4625 static char *pack_fname(char *f)
4626 {
4627  char *rc;
4628 
4629  if((rc=(char *)realloc(f, strlen(f)+1))==NULL)
4630   return(f);
4631  return(rc);
4632 }
4633 #else
4634  #define pack_fname(f) (f)
4635 #endif
4636 
4637 /* Recursive subdirectory search helper */
4638 
4639 #ifndef REARJ
wild_subdir(struct flist_root * root,struct flist_root * search_flist,char * name,int expand_wildcards,int recurse_subdirs,int file_type,FILE_COUNT * count)4640 int wild_subdir(struct flist_root *root, struct flist_root *search_flist, char *name, int expand_wildcards, int recurse_subdirs, int file_type, FILE_COUNT *count)
4641 #else
4642 int wild_subdir(struct flist_root *root, char *name, int file_type, int expand_wildcards, int recurse_subdirs, FILE_COUNT *count)
4643 #endif
4644 {
4645  int attr_mask;                         /* Narrowing criteria */
4646  struct new_ffblk *pnew_ffblk=NULL;     /* OS-dependent data block */
4647  char *subdir_spec=NULL;                /* Subdirectory name */
4648  char *tmp_name=NULL;
4649  int result=0, rc;
4650  char *subdir_wildcard=NULL;            /* Subdirectory entries */
4651 
4652  if(recurse_subdirs)
4653  {
4654   attr_mask=STD_DIR_ATTR;
4655   if(file_type!=FETCH_DEFAULT)
4656  #if TARGET!=UNIX
4657    attr_mask|=FATTR_HIDDEN|FATTR_SYSTEM|FATTR_RDONLY;
4658  #else
4659    attr_mask|=FATTR_DT_REG|FATTR_DT_UXSPECIAL;
4660  #endif
4661   #ifndef REARJ
4662    #if TARGET==UNIX
4663     if(filter_attrs)
4664     {
4665      if(file_attr_mask&TAG_SYSTEM)
4666       attr_mask|=FATTR_SYSTEM;
4667      if(file_attr_mask&TAG_HIDDEN)
4668       attr_mask|=FATTR_HIDDEN;
4669      if(file_attr_mask&TAG_RDONLY)
4670       attr_mask|=FATTR_RDONLY;
4671      #if TARGET==UNIX
4672       if(file_attr_mask&TAG_UXSPECIAL)
4673        attr_mask|=FATTR_DT_UXSPECIAL;
4674       if(file_attr_mask&TAG_DIREC)
4675        attr_mask|=FATTR_DT_DIR;
4676      #endif
4677     }
4678    #endif
4679   #endif
4680   if((subdir_spec=(char *)malloc(strlen(name)+WC_RESERVE))==NULL)
4681   {
4682    result=-1;
4683    goto l_error;
4684   }
4685   split_name(name, subdir_spec, NULL);
4686   strcat(subdir_spec, all_wildcard);
4687   case_path(subdir_spec);
4688   subdir_spec=pack_fname(subdir_spec);
4689   if((pnew_ffblk=(struct new_ffblk *)malloc(sizeof(struct new_ffblk)))==NULL)
4690   {
4691    result=-1;
4692    goto l_error;
4693   }
4694   rc=lfn_findfirst(subdir_spec, pnew_ffblk, attr_mask);
4695   while(rc==0)
4696   {
4697    if(
4698       /* Entries like "." and ".." are skipped */
4699       pnew_ffblk->ff_attrib&STD_DIR_ATTR&&strcmp(pnew_ffblk->ff_name, cur_dir_spec)&&strcmp(pnew_ffblk->ff_name, up_dir_spec)
4700 #if TARGET==UNIX&&SFX_LEVEL>=ARJ
4701       /* Disallow circular symlinks - the symlink will be stored but will
4702          not be recursed into */
4703       &&link_search(&sl_entries, &pnew_ffblk->l_search, NULL, 0)==FLS_NONE
4704 #endif
4705      )
4706    {
4707     /* Reallocate these */
4708     if((subdir_wildcard=(char *)realloc(subdir_wildcard, CCHMAXPATHCOMP))==NULL||
4709        (tmp_name=(char *)realloc(tmp_name, CCHMAXPATH+20))==NULL)
4710     {
4711      result=-1;
4712      goto l_error;
4713     }
4714     split_name(name, tmp_name, subdir_wildcard);
4715     subdir_wildcard=pack_fname(subdir_wildcard);
4716     if(strlen(tmp_name)+strlen(pnew_ffblk->ff_name)+strlen(subdir_wildcard)+2>=CCHMAXPATHCOMP)
4717      msg_cprintf(H_ERR, M_MAXPATH_EXCEEDED, CCHMAXPATH, tmp_name);
4718     else
4719     {
4720      strcat(tmp_name, pnew_ffblk->ff_name);
4721      strcat(tmp_name, pathsep_str);
4722      strcat(tmp_name, subdir_wildcard);
4723      case_path(tmp_name);
4724      tmp_name=pack_fname(tmp_name);
4725      #ifdef REARJ
4726       if(wild_list(root, tmp_name, file_type, expand_wildcards, recurse_subdirs, count))
4727       {
4728        result=-1;
4729        goto l_error;
4730       }
4731      #else
4732       if(wild_list(root, search_flist, tmp_name, expand_wildcards, recurse_subdirs, file_type, count))
4733       {
4734        result=-1;
4735        goto l_error;
4736       }
4737      #endif
4738     }
4739    }
4740    rc=lfn_findnext(pnew_ffblk);
4741   }
4742   lfn_findclose(pnew_ffblk);
4743  }
4744 l_error:
4745  if(pnew_ffblk!=NULL)
4746   free(pnew_ffblk);
4747  if(subdir_spec!=NULL)
4748   free(subdir_spec);
4749  if(tmp_name!=NULL)
4750   free(tmp_name);
4751  if(subdir_wildcard!=NULL)
4752   free(subdir_wildcard);
4753  return(result);
4754 }
4755 
4756 /* Findfirst/findnext, wildcard expansion and so on... */
4757 
4758 #ifndef REARJ
wild_list(struct flist_root * root,struct flist_root * search_flist,char * name,int expand_wildcards,int recurse_subdirs,int file_type,FILE_COUNT * count)4759 int wild_list(struct flist_root *root, struct flist_root *search_flist, char *name, int expand_wildcards, int recurse_subdirs, int file_type, FILE_COUNT *count)
4760 #else
4761 int wild_list(struct flist_root *root, char *name, int file_type, int expand_wildcards, int recurse_subdirs, FILE_COUNT *count)
4762 #endif
4763 {
4764  int attr_mask;                         /* Narrowing criteria */
4765  struct new_ffblk *pnew_ffblk=NULL;     /* OS-dependent data block */
4766  int result=0, rc;                      /* findfirst/findnext() result */
4767  char *tmp_name=NULL;
4768  int pathspec_len;                      /* Maximum path length */
4769  #ifndef REARJ
4770   struct file_properties properties;    /* Universal block */
4771  #endif
4772 
4773  pathspec_len=strlen(name);
4774  if(pathspec_len<CCHMAXPATH)
4775   pathspec_len=CCHMAXPATH;
4776  flush_kbd();
4777  if(!expand_wildcards)
4778  {
4779   if((tmp_name=(char *)strdup(name))==NULL)
4780   {
4781    result=-1;
4782    goto l_error;
4783   }
4784   case_path(tmp_name);
4785   #ifdef REARJ
4786    if(add_entry(root, tmp_name, count))
4787    {
4788     result=-1;
4789     goto l_error;
4790    }
4791   #else
4792    if(flist_add(root, search_flist, tmp_name, count, NULL))
4793    {
4794     result=-1;
4795     goto l_error;
4796    }
4797   #endif
4798  }
4799  else
4800  {
4801 #ifndef REARJ
4802   /* First, perform recursive subdirectory search if needed */
4803   if(recursion_order==RO_LAST)
4804    result=wild_subdir(root, search_flist, name, expand_wildcards, recurse_subdirs, file_type, count);
4805 #endif
4806   if((tmp_name=(char *)malloc(pathspec_len+50))==NULL)
4807   {
4808    result=-1;
4809    goto l_error;
4810   }
4811   /* Search for the ordinary files */
4812   attr_mask=0;
4813   if(file_type!=FETCH_DEFAULT)
4814   #if TARGET!=UNIX
4815    attr_mask|=FATTR_HIDDEN|FATTR_SYSTEM|FATTR_RDONLY;
4816   #else
4817    attr_mask|=FATTR_DT_REG|FATTR_DT_UXSPECIAL;
4818   #endif
4819   if(file_type==FETCH_DIRS)
4820    attr_mask|=STD_DIR_ATTR;
4821   #if !defined(REARJ)&&TARGET!=UNIX
4822    if(filter_attrs)
4823    {
4824     if(file_attr_mask&TAG_DIREC)
4825      attr_mask|=FATTR_DIREC;
4826     if(file_attr_mask&TAG_SYSTEM)
4827      attr_mask|=FATTR_SYSTEM;
4828     if(file_attr_mask&TAG_HIDDEN)
4829      attr_mask|=FATTR_HIDDEN;
4830     if(file_attr_mask&TAG_RDONLY)
4831      attr_mask|=FATTR_RDONLY;
4832    }
4833   #endif
4834   #if TARGET==UNIX
4835    if(file_attr_mask&TAG_UXSPECIAL)
4836     attr_mask|=FATTR_DT_UXSPECIAL;
4837    if(file_attr_mask&TAG_DIREC)
4838     attr_mask|=FATTR_DT_DIR;
4839   #endif
4840   if((pnew_ffblk=(struct new_ffblk *)malloc(sizeof(struct new_ffblk)))==NULL)
4841   {
4842    result=-1;
4843    goto l_error;
4844   }
4845   rc=lfn_findfirst(name, pnew_ffblk, attr_mask);
4846   while(rc==0)
4847   {
4848    /* Entries like "." and ".." are skipped but symlinks AREN'T */
4849    if((!(pnew_ffblk->ff_attrib&STD_DIR_ATTR)||(strcmp(pnew_ffblk->ff_name, cur_dir_spec)&&strcmp(pnew_ffblk->ff_name, up_dir_spec))))
4850    {
4851     split_name(name, tmp_name, NULL);
4852     /* ASR fix for 2.76.04 */
4853     if(strlen(tmp_name)+strlen(pnew_ffblk->ff_name)>=CCHMAXPATH)
4854      msg_cprintf(H_ERR, M_MAXPATH_EXCEEDED, CCHMAXPATH, pnew_ffblk->ff_name);
4855     else
4856     {
4857      strcat(tmp_name, pnew_ffblk->ff_name);
4858      case_path(tmp_name);
4859      #ifdef REARJ
4860       if(add_entry(root, tmp_name, count))
4861       {
4862        result=-1;
4863        goto l_error;
4864       }
4865      #else
4866       finddata_to_properties(&properties, pnew_ffblk);
4867       if(flist_add(root, search_flist, tmp_name, count, &properties))
4868       {
4869        result=-1;
4870        goto l_error;
4871       }
4872      #endif
4873     }
4874    }
4875    rc=lfn_findnext(pnew_ffblk);
4876   }
4877   lfn_findclose(pnew_ffblk);            /* BUG: Original REARJ v 2.28 didn't
4878                                            close the search -- fixed in 2.42 */
4879   if(tmp_name!=NULL)
4880   {
4881    free(tmp_name);
4882    tmp_name=NULL;
4883   }
4884   if(pnew_ffblk!=NULL)
4885   {
4886    free(pnew_ffblk);
4887    pnew_ffblk=NULL;
4888   }
4889   /* Last, perform recursive subdirectory search if needed */
4890 #ifndef REARJ
4891   if(recursion_order==RO_FIRST)
4892    result=wild_subdir(root, search_flist, name, expand_wildcards, recurse_subdirs, file_type, count);
4893 #else
4894    result=wild_subdir(root, name, file_type, expand_wildcards, recurse_subdirs, count);
4895 #endif
4896  }
4897  /* Return 0 if no errors occured */
4898 l_error:
4899  if(tmp_name!=NULL)
4900   free(tmp_name);
4901  if(pnew_ffblk!=NULL)
4902   free(pnew_ffblk);
4903  return(result);
4904 }
4905 #endif
4906