1 
2 /*
3  * xvvd.c - extract archived file automatically and regard it as a
4  *          (virtual) directory.
5  */
6 
7 #define NEEDSDIR
8 
9 #include "xv.h"
10 
11 #ifdef AUTO_EXPAND
12 
13 static void  vd_Dirtovd    		PARM((char *));
14 static void  vd_Vdtodir    		PARM((char *));
15 static int   vd_Mkvdir    		PARM((char *));
16 static int   vd_Rmvdir     		PARM((char *));
17 static int   vd_Movevdir  		PARM((char *, char *));
18 static void  vd_addvdtable		PARM((char *));
19 static void  vd_packvdtable		PARM((void));
20 static int   vd_recursive_mkdir		PARM((char *));
21 static int   vd_recursive_rmdir		PARM((char *));
22 static void  vd_optimize_path		PARM((char *));
23 static int   vd_ftype			PARM((char *));
24 static int   vd_compp			PARM((char *, char *));
25 static int   vd_UncompressFile		PARM((char *, char *));
26 static int   vd_tarc			PARM((char *));
27 static u_int vd_tar_sumchk		PARM((char *));
28 
29 #define VD_VDTABLESIZE	100
30 
31 #define VD_ERR -2
32 #define VD_UKN -1
33 
34 static char *ext_command[] = {
35 /* KEEP 0 */
36     NULL,
37 #define VD_ARC 1
38     "arc xo %s",
39 #define VD_ARJ 2
40     "unarj x %s",
41 #define VD_LZH 3
42     "lha -xf %s",
43 #define VD_TAR 4
44     "tar xvf %s",
45 #define VD_ZIP 5
46     "unzip -xo %s",
47 #define VD_ZOO 6
48     "zoo xOS %s",
49 };
50 
51 int vdcount = 0;
52 
53 static char vdroot[MAXPATHLEN+1];
54 static char *vdtable[VD_VDTABLESIZE];
55 
56 /*
57  * These functions initialize and settle virtual directory system.
58  * Vdinit:
59  *	creates root of virtual directory.
60  * Vdsettle:
61  *	sweeps virtual directories.
62  */
Vdinit()63 void Vdinit()
64 {
65 #ifndef VMS
66     char tmp[MAXPATHLEN+1];
67 
68     xv_getwd(tmp, MAXPATHLEN+1);
69     if (chdir(tmpdir)) {
70 	fprintf(stderr, "Warning: cannot chdir to tmpdir = '%s'.\n", tmpdir);
71 	fprintf(stderr,
72 		"         I will use current directory '%s' instead of tmpdir.\n",
73 		tmp);
74     }
75     xv_getwd(vdroot, MAXPATHLEN+1);
76     strcat(vdroot, "/.xvvdXXXXXX");
77     chdir(tmp);
78 #else
79     sprintf(vdroot, "Sys$Scratch:xvvdXXXXXX");
80 #endif /* VMS */
81 #ifdef USE_MKSTEMP
82     close(mkstemp(vdroot));
83 #else
84     mktemp(vdroot);
85 #endif
86 
87     if (!vd_recursive_mkdir(vdroot))
88 	tmpdir = vdroot;
89 }
90 
Vdsettle()91 void Vdsettle()
92 {
93     int i;
94 
95     for (i = 0; i < vdcount; i++)
96 	free(vdtable[i]);
97 
98     vdcount = 0;
99 
100     vd_recursive_rmdir(vdroot);
101 }
102 
103 /*
104  * This function chdir to virtual directory, if specified path is in
105  * virtual directlry.
106  */
Chvdir(dir)107 int Chvdir(dir)
108 char *dir;
109 {
110     char buf[MAXPATHLEN+1];
111 
112     if (Mkvdir(dir) == VD_ERR)
113 	return -1;
114 
115     strcpy(buf, dir);
116     Dirtovd(buf);
117 
118     return (chdir(buf));
119 }
120 
121 /*
122  * These functions convert directory <-> virtual directory.
123  * Dirtovd:
124  *	front interface of vd_Dirtovd.
125  * vd_Dirtovd:
126  *	converts directory to virtual directory.
127  * Vdtodir:
128  *	front interface of vd_Vdtodir.
129  * vd_Vdtodir:
130  *	converts virtual directory to normal directory.
131  * Dirtosubst:
132  *	converts directory to substance of archive.
133  */
Dirtovd(dir)134 void Dirtovd(dir)
135 char *dir;
136 {
137     vd_optimize_path(dir);
138 
139     vd_Dirtovd(dir);
140 }
141 
vd_Dirtovd(dir)142 static void vd_Dirtovd(dir)
143 char *dir;
144 {
145     int i;
146 
147     for (i = 0; i < vdcount; i++)
148 	if (!strncmp(dir, vdtable[i], strlen(vdtable[i]))) {
149 	    char tmp[MAXPATHLEN+1];
150 
151 	    sprintf(tmp, "%s%s", vdroot, dir);
152 	    strcpy(dir, tmp);
153 	    Dirtovd(dir);
154 	}
155 }
156 
Vdtodir(dir)157 void Vdtodir(dir)
158 char *dir;
159 {
160     vd_optimize_path(dir);
161 
162     vd_Vdtodir(dir);
163 }
164 
vd_Vdtodir(vd)165 static void vd_Vdtodir(vd)
166 char *vd;
167 {
168     int i;
169     char tmp[MAXPATHLEN+1];
170 
171     for (i = vdcount-1; i >= 0; i--) {
172 	sprintf(tmp, "%s%s", vdroot, vdtable[i]);
173 	if(!strncmp(vd, tmp, strlen(tmp))) {
174 	    strcpy(tmp, vd+strlen(vdroot));
175 	    strcpy(vd, tmp);
176 	    Vdtodir(vd);
177 	}
178     }
179 }
180 
Dirtosubst(dir)181 void Dirtosubst(dir)
182 char *dir;
183 {
184     char tmp[MAXPATHLEN+1];
185 
186     Dirtovd(dir);
187 
188     strcpy(tmp, dir+strlen(vdroot));
189 
190     if (Isarchive(tmp))
191 	strcpy(dir, tmp);
192 }
193 
194 /*
195  * These functions make virtual directory and extracts archive, if
196  * specified path is archive.
197  * Mkvdir:
198  *	front interface of vd_Mkvdir.
199  * vd_Mkvdir:
200  *	does real work.
201  * Mkvdir_force: (used by makeThumbDir(in xvbrowse.c) only)
202  *	make virtual directory by force.
203  */
Mkvdir(dir)204 int Mkvdir(dir)
205 char *dir;
206 {
207     char dir1[MAXPATHLEN+1], dir2[MAXPATHLEN+1];
208     char *d1, *d2;
209     int rv;
210 
211 #if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
212     sighold(SIGHUP);
213     sighold(SIGCHLD);
214 #else
215     int mask;
216     mask = sigblock(sigmask(SIGHUP)|sigmask(SIGCHLD));
217 #endif
218 
219     strcpy(dir1, dir);
220     vd_optimize_path(dir1);
221 
222     if ((rv = vd_Mkvdir(dir1)) != VD_ERR)
223 	goto MKVDIR_END;
224 
225     strcpy(dir2, dir1);
226     d2 = dir2 + strlen(dir2);
227     while (rv == VD_ERR) {
228 	d2--;
229 	while (*d2 != '/')
230 	    d2--;
231 	*d2 = '\0';
232 	rv = vd_Mkvdir(dir2);
233     }
234     d1 = dir1 + strlen(dir2);
235     while ((rv != VD_ERR) && (*d1 != '\0')) {
236 	*d2++ = *d1++;
237 	while ((*d1 != '/') && (*d1 != '\0'))
238 	    *d2++ = *d1++;
239 	*d2 = '\0';
240 	rv = vd_Mkvdir(dir2);
241     }
242 
243 MKVDIR_END:
244 #if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
245     sigrelse(SIGHUP);
246     sigrelse(SIGCHLD);
247 #else
248     sigsetmask(mask);
249 #endif
250 
251     return rv;
252 }
253 
vd_Mkvdir(dir)254 static int vd_Mkvdir(dir)
255 char *dir;
256 {
257     char dir1[MAXPATHLEN+1], dir2[MAXPATHLEN+1], tmp[MAXPATHLEN+1];
258     int ftype, i;
259     struct stat st;
260     FILE *pfp;
261 
262     strcpy(dir1, dir);
263     Dirtovd(dir1);
264     strcpy(dir2, dir1);
265 
266     WaitCursor();
267 
268     if ((ftype = vd_ftype(dir1)) < 0) {
269 	SetCursors(-1);
270 	return ftype;
271     }
272     if (ftype == RFT_COMPRESS) {
273 	if (!(ftype = vd_compp(dir1, tmp))) {
274 	    SetCursors(-1);
275 	    return ftype;
276 	}
277 	strcpy(dir1, tmp);
278     }
279 
280     if (!stat(dir1, &st)) {
281 	for(i = 0; i < vdcount; i++)
282 	    if (!strcmp(vdtable[i], dir2)) {
283 		SetCursors(-1);
284 		return 0;
285 	    }
286 
287 	if (!S_ISDIR(st.st_mode)) {
288 	    char origdir[MAXPATHLEN+1], buf[MAXPATHLEN+10], buf1[100];
289 
290 	    if (vdcount >= VD_VDTABLESIZE) {
291 		ErrPopUp("Sorry, you can't make virtual directory any more.",
292 			 "\nBummer!");
293 		goto VD_MKVDIR_ERR;
294 	    }
295 
296 	    WaitCursor();
297 
298 	    xv_getwd(origdir, MAXPATHLEN+1);
299 
300 	    sprintf(tmp, "%s%s", vdroot, dir2);
301 	    if (vd_recursive_mkdir(tmp) || chdir(tmp)) {
302 		SetISTR(ISTR_INFO, "fail to make virtual directory.");
303 		Warning();
304 		goto VD_MKVDIR_ERR;
305 	    }
306 	    sprintf(buf, ext_command[ftype], dir1);
307 
308 	    WaitCursor();
309 
310 	    if((pfp = popen(buf, "r")) == NULL) {
311 		SetISTR(ISTR_INFO, "fail to extract archive '%s'.",
312 			BaseName(dir2));
313 		Warning();
314 		goto VD_MKVDIR_ERR;
315 	    }
316 	    while (1) {
317 		if (fread(buf1, 1, sizeof(buf1), pfp) < sizeof(buf1))
318 		    break;
319 		WaitCursor();
320 	    }
321 	    if (!feof(pfp)) {
322 		SetISTR(ISTR_INFO, "Pipe was broken.");
323 		Warning();
324 		pclose(pfp);
325 		goto VD_MKVDIR_ERR;
326 	    }
327 	    pclose(pfp);
328 
329 	    if (strcmp(dir1, dir2))
330 		unlink(dir1);
331 
332 	    vd_addvdtable(dir2);
333 	    Dirtovd(origdir);
334 	    chdir(origdir);
335 	    SetCursors(-1);
336 	    return 0;
337 
338 VD_MKVDIR_ERR:
339 	    if (strcmp(dir1, dir2))
340 		unlink(dir1);
341 	    SetCursors(-1);
342 	    return VD_ERR;
343 	}
344     }
345     SetCursors(-1);
346     return VD_ERR;
347 }
348 
349 #ifdef VIRTUAL_TD
Mkvdir_force(dir)350 void Mkvdir_force(dir)
351 char *dir;
352 {
353     char tmp[MAXPATHLEN+1];
354 
355     if (vdcount >= VD_VDTABLESIZE) {
356       ErrPopUp("Sorry, you can't make virtual directory any more.",
357 	       "\nBummer!");
358       return;
359     }
360 
361     sprintf(tmp, "%s%s", vdroot, dir);
362     if (vd_recursive_mkdir(tmp)) {
363       SetISTR(ISTR_INFO, "Failed to make virtual directory.");
364       Warning();
365       return;
366     }
367 
368     vd_addvdtable(dir);
369 }
370 #endif /* VIRTUAL_TD */
371 
372 /*
373  * These functions remove virtual directory, if exists.
374  * Rmvdir:
375  *	front interface of vd_Rmvdir.
376  * vd_Rmvdir:
377  *	remove virtual directory function.
378  */
Rmvdir(dir)379 int Rmvdir(dir)
380 char *dir;
381 {
382     int rv;
383     char buf[MAXPATHLEN+1];
384 
385     strcpy(buf, dir);
386     vd_optimize_path(buf);
387 
388     rv = vd_Rmvdir(buf);
389     vd_packvdtable();
390     return rv;
391 }
392 
vd_Rmvdir(dir)393 static int vd_Rmvdir(dir)
394 char *dir;
395 {
396     int i;
397     char tmp[MAXPATHLEN+1];
398 
399     for(i = 0; i < vdcount; i++)
400 	if (!strncmp(dir, vdtable[i], strlen(dir))) {
401 	    sprintf(tmp, "%s%s", vdroot, vdtable[i]);
402 	    if (vd_Rmvdir(tmp))
403 		return 1;
404 	    if (vd_recursive_rmdir(tmp))
405 		return 1;
406 	    vdtable[i][0] = '\0';
407 	}
408     return 0;
409 }
410 
411 /*
412  * These functions move virtual directory, if exists.
413  * Movevdir:
414  *	front interface of move virtual directory function.
415  * vd_Movevdir:
416  *	does real work.
417  */
Movevdir(src,dst)418 int Movevdir(src, dst)
419 char *src, *dst;
420 {
421 /*
422     char sbuf[MAXPATHLEN+1], dbuf[MAXPATHLEN+1];
423 
424     strcpy(sbuf, src);
425     vd_optimize_path(sbuf);
426 
427     strcpy(dbuf, dst);
428     vd_optimize_path(dbuf);
429 
430     return (vd_Movevdir(sbuf, dbuf));
431 */
432     return (vd_Movevdir(src, dst));
433 }
434 
vd_Movevdir(src,dst)435 static int vd_Movevdir(src, dst)
436 char *src, *dst;
437 {
438     int i;
439     char *p, *pp;
440     char tmp[MAXPATHLEN+1], tmps[MAXPATHLEN+1], tmpd[MAXPATHLEN+1];
441 
442     for (i = 0; i < vdcount; i++)
443 	if (!strncmp(src, vdtable[i], strlen(src))) {
444 	    sprintf(tmps, "%s%s", vdroot, vdtable[i]);
445 	    sprintf(tmp, "%s%s", dst, vdtable[i]+strlen(src));
446 	    sprintf(tmpd, "%s%s", vdroot, tmp);
447 
448 	    if (vd_Movevdir(tmps, tmpd))
449 		return 1;
450 
451 	    pp = vdtable[i];
452 	    p = (char *) malloc(strlen(tmp)+1);
453 	    strcpy(p, tmp);
454 	    vdtable[i] = p;
455 
456 	    strcpy(tmp, tmpd);
457 	    for (p = tmp+strlen(tmp); *p != '/'; p--)
458 		;
459 	    *p = '\0';
460 
461 	    if (vd_recursive_mkdir(tmp))
462 		goto VD_MOVEVDIR_ERR;
463 
464 	    if (rename(tmps, tmpd) < 0)
465 		goto VD_MOVEVDIR_ERR;
466 
467 	    free(pp);
468 	}
469     return 0;
470 
471 VD_MOVEVDIR_ERR:
472     free(vdtable[i]);
473     vdtable[i] = pp;
474     return 1;
475 }
476 
477 /*
478  * These functions handle table of virtual directories.
479  * vd_addvdtable:
480  *	adds virtual directory to table.
481  * vd_packvdtable:
482  *	removes disused virtual directories from table.
483  */
vd_addvdtable(vd)484 static void vd_addvdtable(vd)
485 char *vd;
486 {
487     char *p;
488     p = (char *) malloc(strlen(vd)+1);
489     strcpy(p, vd);
490     vdtable[vdcount] = p;
491     vdcount++;
492 }
493 
vd_packvdtable()494 static void vd_packvdtable()
495 {
496     int i, j;
497 
498     for (i = j = 0; i < vdcount; i++)
499 	if (vdtable[i][0] != '\0')
500 	    vdtable[j++] = vdtable[i];
501 	else
502 	    free(vdtable[i]);
503 
504     vdcount = j;
505 }
506 
507 /*
508  * These are utility functions.
509  * vd_recursive_mkdir:
510  *	makes directories recursively.
511  * vd_recursive_rmdir
512  *	removes directories recursively.
513  */
vd_recursive_mkdir(dir)514 static int vd_recursive_mkdir(dir)
515 char *dir;
516 {
517     char buf[MAXPATHLEN+1], *p;
518     struct stat st;
519 
520     strcpy(buf, dir);
521 
522     if (buf[strlen(buf) - 1] == '/')
523 	buf[strlen(buf) - 1] = '\0';
524 
525     p = rindex(buf, '/');
526     *p = '\0';
527 
528     if (stat(buf, &st) < 0)
529 	if (vd_recursive_mkdir(buf) < 0)
530 	    return (-1);
531 
532     *p = '/';
533     if (mkdir(buf, 0700) < 0)
534 	return (-1);
535 
536     return (0);
537 }
538 
vd_recursive_rmdir(dir)539 static int vd_recursive_rmdir(dir)
540 char *dir;
541 {
542     char buf[MAXPATHLEN+1], buf2[MAXPATHLEN+1];
543     DIR *dp;
544     struct dirent *di;
545 
546     strcpy(buf, dir);
547 
548     if (buf[strlen(buf) - 1] == '/')
549 	buf[strlen(buf) - 1] = '\0';
550 
551     if ((dp = opendir(buf)) == NULL)
552 	return (-1);
553 
554     while ((di = readdir(dp)) != NULL) {
555 	struct stat st;
556 
557 	if (!strcmp(di->d_name, ".") || !strcmp(di->d_name, ".."))
558 	    continue;
559 
560 	sprintf(buf2, "%s/%s", dir, di->d_name);
561 
562 	stat(buf2, &st);
563 	if (S_ISDIR(st.st_mode)) {
564 	    if (vd_recursive_rmdir(buf2) < 0)
565 		goto VD_RECURSIVE_RMDIR_ERR;
566 	} else
567 	    unlink(buf2);
568     }
569     if (rmdir(buf) < 0)
570 	goto VD_RECURSIVE_RMDIR_ERR;
571 
572     closedir(dp);
573     return (0);
574 
575 VD_RECURSIVE_RMDIR_ERR:
576     closedir(dp);
577     return (-1);
578 }
579 
580 /*
581  * These functions test specified path.
582  * Isarchive:
583  *	tests whether it's an archive?
584  * Isvdir:
585  *	tests whether it's in the virtual directory?
586  */
Isarchive(path)587 int Isarchive(path)
588 char *path;
589 {
590     int ftype;
591 
592     if ((ftype = vd_ftype(path)) < 0)
593 	return 0;
594 
595     if (ftype == RFT_COMPRESS)
596 	if (!(ftype = vd_compp(path, NULL)))
597 	    return 0;
598 
599     return ftype;
600 }
601 
Isvdir(path)602 int Isvdir(path)
603 char *path;
604 {
605     int rv = 0;
606     char tmp1[MAXPATHLEN+1], tmp2[MAXPATHLEN+1];
607     int archive1, archive2;
608 
609     strcpy(tmp1, path);
610     strcpy(tmp2, path);
611 
612     vd_optimize_path(tmp1);
613     Dirtovd(tmp2);
614 
615     archive1 = Isarchive(tmp1);
616     archive2 = Isarchive(tmp2);
617 
618     if (strcmp(tmp1, tmp2)) {
619 	char tmp3[MAXPATHLEN+1], tmp4[MAXPATHLEN+1];
620 	int archive3, archive4;
621 
622 	sprintf(tmp3, "%s%s", vdroot, tmp1);
623 	strcpy(tmp4, tmp2+strlen(vdroot));
624 
625 	archive3 = Isarchive(tmp3);
626 	archive4 = Isarchive(tmp4);
627 
628 	if (archive4 && !strcmp(tmp1, tmp4)) {
629 	    rv |= 06;
630 	    return rv;
631 	}
632 	rv |= 01;
633 	if (archive2)
634 	    rv |= 02;
635 	else if (archive4)
636 	    rv |= 06;
637 	return rv;
638     }
639     if (archive1)
640 	rv |= 02;
641 
642     return rv;
643 }
644 
645 /*
646  * This function optimizes given path.
647  * Expand '~' to home directory and removes '.', and treat '..'.
648  */
vd_optimize_path(path)649 static void vd_optimize_path(path)
650 char *path;
651 {
652     char *tmp, *reserve;
653 
654     if (!strcmp(path, STDINSTR))
655 	return;
656 
657     if (*path == '\0') {
658 	xv_getwd(path, MAXPATHLEN+1);
659 	return;
660     }
661     if (*path == '~')
662 	Globify(path);
663     if (*path != '/') {
664 	char tmp[MAXPATHLEN+1];
665 
666 	strcpy(tmp, path);
667 	xv_getwd(path, MAXPATHLEN+1);
668 	strcat(path, "/");
669 	strcat(path, tmp);
670     }
671 
672     reserve = tmp = path;
673     while(*path != '\0') {
674 	if (*path == '/') {
675 	    *tmp++ = *path;
676 	    while (*++path == '/')
677 		;
678 	    continue;
679 	}
680 	if ((*path == '.') && (*(path-1) == '/')) {
681 	    if (*(path+1) == '/') {
682 		tmp--;
683 		path++;
684 		continue;
685 	    } else if (*(path+1) == '\0') {
686 		tmp--;
687 		break;
688 	    } else if (*(path+1) == '.') {
689 		if (*(path+2) == '/') {
690 		    if ((tmp - reserve) > 1)
691 			for (tmp-=2; (*tmp != '/'); tmp--)
692 			    ;
693 		    else
694 			tmp = reserve;
695 		    path+=2;
696 		    continue;
697 		} else if (*(path+2) == '\0') {
698 		    if ((tmp - reserve) > 1)
699 			for (tmp-=2; (*tmp != '/'); tmp--)
700 			    ;
701 		    else
702 			tmp = reserve+1;
703 		    break;
704 		}
705 	    }
706 	}
707 	*tmp++ = *path++;
708     }
709     if (((tmp - reserve) > 1) && *(tmp-1) == '/')
710 	tmp--;
711     if (tmp == reserve)
712 	*tmp++ = '/';
713 
714     *tmp = '\0';
715 }
716 
717 /*
718  * These functions detect file type.
719  */
vd_ftype(fname)720 static int vd_ftype(fname)
721 char *fname;
722 {
723     /* check archive type */
724 
725     FILE *fp;
726     byte  magicno[30];    /* first 30 bytes of file */
727     int   rv, n;
728     struct stat st;
729 
730     if (!fname) return VD_ERR;   /* shouldn't happen */
731 
732     if ((!stat(fname, &st)) && (st.st_mode & S_IFMT) == S_IFDIR)
733 	return VD_UKN;
734     fp = xv_fopen(fname, "r");
735     if (!fp) return VD_ERR;
736 
737     n = fread(magicno, (size_t) 1, (size_t) 30, fp);
738     fclose(fp);
739 
740     if (n<30) return VD_UKN;    /* files less than 30 bytes long... */
741 
742     rv = VD_UKN;
743 
744     if (magicno[0] == 0x60 && magicno[1]==0xea) rv = VD_ARJ;
745 
746     else if (magicno[2] == '-' && magicno[3] == 'l' &&
747 	     magicno[4] == 'h') rv = VD_LZH;
748 
749     else if (strncmp((char *) magicno,"PK", (size_t) 2)==0) rv = VD_ZIP;
750 
751     else if (magicno[20]==0xdc && magicno[21]==0xa7 &&
752 	     magicno[22]==0xc4 && magicno[23]==0xfd) rv = VD_ZOO;
753 
754     else if (vd_tarc(fname)) rv = VD_TAR;
755 
756     else if (magicno[0]==0x1f && magicno[1]==0x9d) rv = RFT_COMPRESS;
757 
758     else if (!strncmp((char *) &magicno[11], "MAJYO", (size_t) 5))
759 	     rv = VD_UKN; /* XXX */
760 
761     else if (magicno[0] == 26) rv = VD_ARC;
762 
763 #ifdef GUNZIP
764     else if (magicno[0]==0x1f && magicno[1]==0x8b) rv = RFT_COMPRESS;/* gzip */
765     else if (magicno[0]==0x1f && magicno[1]==0x9e) rv = RFT_COMPRESS;/*  old */
766     else if (magicno[0]==0x1f && magicno[1]==0x1e) rv = RFT_COMPRESS;/* pack */
767 #endif
768 
769     return rv;
770 }
771 
vd_compp(path,newpath)772 static int vd_compp(path, newpath)
773 char *path, *newpath;
774 {
775     /*
776      * uncompress and check archive type.
777      *
778      * If newpath is NULL, uncompress only 512 byte of 'path' and
779      * check archive type, so it is for SPEED-UP strategy.
780      * In this case, caller this function does not have to unlink
781      * tempoary file.
782      * Unfortunately it does not work in VMS system.
783      */
784 
785     int file_type, r;
786     char uncompname[128], basename[128];
787     int comptype;
788 
789     if (newpath) *newpath = '\0';
790     strncpy(basename, path, 127);
791     comptype = ReadFileType(path);
792 #if (defined(VMS) && !defined(GUNZIP))
793     /* VMS decompress doesn't like the file to have a trailing .Z in fname
794     however, GUnZip is OK with it, which we are calling UnCompress */
795     *rindex (basename, '.') = '\0';
796 #endif
797 #ifdef VMS
798     if (UncompressFile(basename, uncompname)) {
799 #else
800     if (newpath == NULL)
801 	r = vd_UncompressFile(basename, uncompname);
802     else
803 	r = UncompressFile(basename, uncompname, comptype);
804     if (r) {
805 #endif
806 	if ((file_type = vd_ftype(uncompname)) < 0) {
807 	    unlink(uncompname);
808 	    return 0;
809 	}
810 	if (newpath) strcpy(newpath, uncompname);
811 	else unlink(uncompname);
812     } else {
813 	return 0;
814     }
815     return file_type;
816 }
817 
818 #define HEADERSIZE 512
819 
820 static void  vd_Dirtovd    		PARM((char *));
821 static int   stderr_on			PARM((void));
822 static int   stderr_off			PARM((void));
823 static FILE  *popen_nul			PARM((char *, char *));
824 
vd_UncompressFile(name,uncompname)825 static int vd_UncompressFile(name, uncompname)
826 char *name, *uncompname;
827 {
828     /* Yap, I`m nearly same as original `UncompnameFile' function, but,
829        1) I extract `name' file ONLY first 512 byte.
830        2) I'm called only from UNIX and UNIX like OS, *NOT* VMS */
831     /* returns '1' on success, with name of uncompressed file in uncompname
832        returns '0' on failure */
833 
834     char namez[128], *fname, buf[512], tmp[HEADERSIZE];
835     int n, tmpfd;
836     FILE *pfp, *tfp;
837 
838     fname = name;
839     namez[0] = '\0';
840 
841 
842 #ifndef GUNZIP
843     /* see if compressed file name ends with '.Z'.  If it *doesn't*, we need
844        to temporarily rename it so it *does*, uncompress it, and rename it
845        *back* to what it was.  necessary because uncompress doesn't handle
846        files that don't end with '.Z' */
847 
848     if (strlen(name) >= (size_t) 2            &&
849 	strcmp(name + strlen(name)-2,".Z")!=0 &&
850 	strcmp(name + strlen(name)-2,".z")!=0) {
851 	strcpy(namez, name);
852 	strcat(namez,".Z");
853 
854 	if (rename(name, namez) < 0) {
855 	    sprintf(buf, "Error renaming '%s' to '%s':  %s",
856 		    name, namez, ERRSTR(errno));
857 	    ErrPopUp(buf, "\nBummer!");
858 	    return 0;
859 	}
860 
861 	fname = namez;
862     }
863 #endif   /* not GUNZIP */
864 
865     sprintf(uncompname, "%s/xvuXXXXXX", tmpdir);
866 #ifdef USE_MKSTEMP
867     tmpfd = mkstemp(uncompname);
868 #else
869     mktemp(uncompname);
870 #endif
871 
872     sprintf(buf,"%s -c %s", UNCOMPRESS, fname);
873     SetISTR(ISTR_INFO, "Uncompressing Header '%s'...", BaseName(fname));
874     if ((pfp = popen_nul(buf, "r")) == NULL) {
875 	SetISTR(ISTR_INFO, "Cannot extract for archive '%s'.",
876 		BaseName(fname));
877 	Warning();
878 #ifdef USE_MKSTEMP
879 	if (tmpfd >= 0)
880 	    close(tmpfd);
881 #endif
882 	return 0;
883     }
884 #ifdef USE_MKSTEMP
885     if (tmpfd < 0)
886 #else
887     if ((tmpfd = open(uncompname,O_WRONLY|O_CREAT|O_EXCL,S_IRWUSR)) < 0)
888 #endif
889     {
890 	SetISTR(ISTR_INFO, "Unable to create temporary file.",
891 		BaseName(uncompname));
892 	Warning();
893 	pclose(pfp);
894     }
895     if ((tfp = fdopen(tmpfd, "w")) == NULL) {
896 	SetISTR(ISTR_INFO, "Unable to create temporary file.",
897 		BaseName(uncompname));
898 	Warning();
899 	close(tmpfd);
900 	pclose(pfp);
901 	return 0;
902     }
903     if ((n = fread(tmp, 1, sizeof(tmp), pfp)) != HEADERSIZE) {
904 	SetISTR(ISTR_INFO, "Unable to read '%s'.",
905 		BaseName(fname));
906 	Warning();
907 	pclose(pfp);
908 	fflush(tfp);
909 	fclose(tfp);
910 	close(tmpfd);
911 	return 0;
912     }
913     fwrite(tmp, 1, n, tfp);
914     fflush(tfp);
915     fclose(tfp);
916     close(tmpfd);
917     pclose(pfp);
918 
919     /* if we renamed the file to end with a .Z for the sake of 'uncompress',
920        rename it back to what it once was... */
921 
922     if (strlen(namez)) {
923 	if (rename(namez, name) < 0) {
924 	    sprintf(buf, "Error renaming '%s' to '%s':  %s",
925 		    namez, name, ERRSTR(errno));
926 	    ErrPopUp(buf, "\nBummer!");
927 	}
928     }
929 
930     return 1;
931 }
932 
933 #define TARBLOCK 512
934 #define CKSTART 148 /* XXX */
935 #define CKSIZE 8
936 
937 /*
938  * Tar file: 1, other: 0
939  */
vd_tarc(fname)940 static int vd_tarc(fname)
941 char *fname;
942 {
943     FILE *fp;
944     unsigned int sum;
945     char *ckp, buf[TARBLOCK];
946 
947     if ((fp = fopen(fname, "r")) == NULL)
948 	return 0;
949 
950     fread(buf, TARBLOCK, 1, fp);
951     fclose(fp);
952 
953     for (sum = 0, ckp = buf + CKSTART;
954 	 (ckp < buf + CKSTART + CKSIZE) && *ckp != '\0';
955 	 ckp++) {
956 	sum *= 8;
957 	if (*ckp == ' ')
958 	    continue;
959 	if (*ckp < '0' || '7' < *ckp)
960 	    return 0;
961 	sum += *ckp - '0';
962     }
963     if (sum != vd_tar_sumchk(buf))
964 	return 0;
965 
966     return 1;
967 }
968 
vd_tar_sumchk(buf)969 static unsigned int vd_tar_sumchk(buf)
970 char *buf;
971 {
972     int i;
973     unsigned int sum = 0;
974 
975     for (i = 0; i < CKSTART; i++) {
976 	sum += *(buf + i);
977     }
978     sum += ' ' * 8;
979     for (i += 8; i < TARBLOCK; i++) {
980 	sum += *(buf + i);
981     }
982     return sum;
983 }
984 
985 
986 static int stde = -1;        /*  fd of stderr    */
987 static int nul = -1;         /*  fd of /dev/null */
988 
989 /*
990  * switch off the output to stderr(bypass to /dev/null).
991  */
stderr_off()992 static int stderr_off()
993 {
994     if (nul < 0)
995       nul = open("/dev/null", O_RDONLY);
996     if (nul < 0) {
997 	fprintf(stderr, "/dev/null open failure\n");
998 	return -1;
999     }
1000     if (stde < 0)
1001 	stde = dup(2);
1002     if (stde < 0) {
1003 	fprintf(stderr, "duplicate stderr failure\n");
1004 	return -1;
1005     }
1006     close(2);
1007     dup(nul);
1008     return 0;
1009 }
1010 
1011 /*
1012  * turn on stderr output.
1013  */
stderr_on()1014 static int stderr_on()
1015 {
1016     if ((stde < 0) || (nul < 0)) {
1017 	fprintf(stderr, "stderr_on should call after stderr_off\n");
1018 	return -1;
1019     }
1020     close(2);
1021     dup(stde);
1022     return 0;
1023 }
1024 
1025 /*
1026  * popen with no output to stderr.
1027  */
popen_nul(prog,mode)1028 static FILE *popen_nul(prog, mode)
1029 char *prog, *mode;
1030 {
1031     FILE *fp;
1032 
1033     stderr_off();
1034     fp = popen(prog, mode);
1035     stderr_on();
1036     return fp;
1037 }
1038 
1039 /*
1040  * These functions are for SIGNAL.
1041  * If XV end by C-c, there are dust of directory which name is .xvvd???,
1042  * made by xvvd. Then, I handle SIGINT, and add good finish.
1043  */
vd_HUPhandler()1044 void vd_HUPhandler()
1045 {
1046 #if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
1047     sighold(SIGHUP);
1048 #else
1049     int mask;
1050     mask = sigblock(sigmask(SIGHUP));
1051 #endif
1052 
1053   Vdsettle();
1054 
1055 #if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
1056     sigrelse(SIGHUP);
1057     signal(SIGHUP, (void (*)PARM((int))) vd_HUPhandler);
1058 #else
1059     sigsetmask(mask);
1060 #endif
1061 }
1062 
1063 int InSignal = 0;
1064 
vd_handler(sig)1065 void vd_handler(sig)
1066 int sig;
1067 {
1068 #if defined(SYSV) || defined(SVR4) || defined(__USE_XOPEN_EXTENDED)
1069     sighold(sig);
1070 #else
1071     sigblock(sigmask(sig));
1072 #endif
1073     InSignal = 1;
1074     Quit(1); /*exit(1);*/
1075 }
1076 
vd_Xhandler(disp,event)1077 int vd_Xhandler(disp,event)
1078 Display *disp;
1079 XErrorEvent *event;
1080 {
1081     Quit(1); /*exit(1);*/
1082     return (1); /* Not reached */
1083 }
1084 
vd_XIOhandler(disp)1085 int vd_XIOhandler(disp)
1086 Display *disp;
1087 {
1088     fprintf(stderr, "XIO  fatal IO error ? (?) on X server\n");
1089     fprintf(stderr, "You must exit normally in xv usage.\n");
1090     Quit(1); /*exit(1);*/
1091     return (1); /* Not reached */
1092 }
1093 
vd_handler_setup()1094 void vd_handler_setup()
1095 {
1096     signal(SIGHUP, (void (*)PARM((int))) vd_HUPhandler);
1097     signal(SIGINT, (void (*)PARM((int))) vd_handler);
1098     signal(SIGTERM,(void (*)PARM((int))) vd_handler);
1099 
1100     (void)XSetErrorHandler(vd_Xhandler);
1101     (void)XSetIOErrorHandler(vd_XIOhandler);
1102 }
1103 #endif /* AUTO_EXPAND */
1104