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(®s, ®s, &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(®s, ®s, &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, ®s, &sregs)==0&®s.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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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, ®s, &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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
4246 #endif
4247 regs.h.ah=0x17; /* rename() for FCB */
4248 regs.x.dx=(unsigned int)dta;
4249 intdos(®s, ®s);
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(®s, ®s);
4261 #endif
4262 regs.h.ah=0x16; /* create file using FCB */
4263 regs.x.dx=(unsigned int)&xfcb;
4264 intdos(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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