1 /* @(#)list.c 1.84 20/02/05 Copyright 1985, 1995, 2000-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)list.c 1.84 20/02/05 Copyright 1985, 1995, 2000-2020 J. Schilling";
6 #endif
7 /*
8 * List the content of an archive
9 *
10 * Copyright (c) 1985, 1995, 2000-2020 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/stdio.h>
27 #include "star.h"
28 #include "props.h"
29 #include "table.h"
30 #include <schily/dirent.h>
31 #include <schily/standard.h>
32 #include <schily/stdlib.h>
33 #include <schily/string.h>
34 #define GT_COMERR /* #define comerr gtcomerr */
35 #define GT_ERROR /* #define error gterror */
36 #include <schily/schily.h>
37 #include "starsubs.h"
38 #ifdef USE_FIND
39 #include <schily/walk.h>
40 #endif
41
42 extern FILE *tarf;
43 extern FILE *vpr;
44 extern char *listfile;
45 extern Llong curblockno;
46
47 extern time_t sixmonth; /* 6 months before limit (ls) */
48 extern time_t now; /* now limit (ls) */
49
50 extern BOOL havepat;
51 extern int iftype;
52 extern BOOL paxls;
53 extern int xdebug;
54 extern BOOL numeric;
55 extern int verbose;
56 extern BOOL prblockno;
57 extern BOOL tpath;
58 extern BOOL cflag;
59 extern BOOL xflag;
60 extern BOOL interactive;
61
62 extern BOOL acctime;
63 extern BOOL no_dirslash;
64 extern BOOL Ctime;
65 extern BOOL prinodes;
66
67 extern BOOL listnew;
68 extern BOOL listnewf;
69
70 extern BOOL do_subst;
71
72 #ifdef USE_FIND
73 extern BOOL dofind;
74 #endif
75
76 EXPORT void list __PR((void));
77 LOCAL void modstr __PR((FINFO *info, char *s, mode_t mode));
78 EXPORT void list_file __PR((FINFO *info));
79 EXPORT void vprint __PR((FINFO *info));
80
81 EXPORT void
list()82 list()
83 {
84 #ifdef USE_FIND
85 extern struct WALK walkstate;
86 #endif
87 FINFO finfo;
88 FINFO newinfo;
89 TCB tb;
90 TCB newtb;
91 register TCB *ptb = &tb;
92
93 fillbytes((char *)&finfo, sizeof (finfo), '\0');
94 fillbytes((char *)&newinfo, sizeof (newinfo), '\0');
95
96 if (init_pspace(PS_STDERR, &finfo.f_pname) < 0)
97 return;
98 if (init_pspace(PS_STDERR, &finfo.f_plname) < 0)
99 return;
100 if (listnew || listnewf) {
101 if (init_pspace(PS_STDERR, &newinfo.f_pname) < 0)
102 return;
103 if (init_pspace(PS_STDERR, &newinfo.f_plname) < 0)
104 return;
105 }
106
107 #ifdef USE_FIND
108 if (dofind) {
109 walkopen(&walkstate);
110 walkgethome(&walkstate); /* Needed in case we chdir */
111 }
112 #endif
113 finfo.f_tcb = ptb;
114 for (;;) {
115 if (get_tcb(ptb) == EOF)
116 break;
117 if (prblockno)
118 (void) tblocks(); /* set curblockno */
119
120 finfo.f_name = finfo.f_pname.ps_path;
121 finfo.f_lname = finfo.f_plname.ps_path;
122 if (tcb_to_info(ptb, &finfo) == EOF)
123 break;
124 if (xdebug > 0)
125 dump_info(&finfo);
126
127 #ifdef USE_FIND
128 if (dofind && !findinfo(&finfo)) {
129 void_file(&finfo);
130 continue;
131 }
132 #endif
133
134 if (do_subst) {
135 subst(&finfo);
136 }
137
138 if (listnew || listnewf) {
139 /*
140 * Honor nsecs if part of the archive.
141 */
142 if (((finfo.f_mtime > newinfo.f_mtime) ||
143 ((finfo.f_xflags & XF_MTIME) &&
144 (newinfo.f_xflags & XF_MTIME) &&
145 (finfo.f_mtime == newinfo.f_mtime) &&
146 (finfo.f_mnsec > newinfo.f_mnsec))) &&
147 (!listnewf || is_file(&finfo))) {
148 movebytes(&finfo, &newinfo,
149 offsetof(FINFO, f_pname));
150 movetcb(&tb, &newtb);
151 if (strcpy_pspace(PS_STDERR,
152 &newinfo.f_pname,
153 finfo.f_name) < 0) {
154 newinfo.f_name = "";
155 } else {
156 newinfo.f_name =
157 newinfo.f_pname.ps_path;
158 }
159 if (newinfo.f_lname[0] != '\0') {
160 if (strcpy_pspace(PS_STDERR,
161 &newinfo.f_plname,
162 finfo.f_lname) < 0) {
163 newinfo.f_lname = "";
164 } else {
165 newinfo.f_lname =
166 newinfo.f_plname.ps_path;
167 }
168 }
169 newinfo.f_flags |= F_HAS_NAME;
170 }
171 void_file(&finfo);
172 continue;
173 }
174 if (listfile && !hash_lookup(finfo.f_name)) {
175 void_file(&finfo);
176 continue;
177 }
178 if (hash_xlookup(finfo.f_name)) {
179 void_file(&finfo);
180 continue;
181 }
182 if (havepat && !match(finfo.f_name)) {
183 void_file(&finfo);
184 continue;
185 }
186 list_file(&finfo);
187 void_file(&finfo);
188 }
189 #ifdef USE_FIND
190 if (dofind) {
191 walkhome(&walkstate);
192 walkclose(&walkstate);
193 free(walkstate.twprivate);
194 }
195 #endif
196 if ((listnew || listnewf) && newinfo.f_mtime != 0L) {
197 /*
198 * XXX
199 * XXX Achtung!!! tcb_to_info zerst�rt t_name[NAMSIZ]
200 * XXX und t_linkname[NAMSIZ].
201 * XXX Ist dies noch richtig?
202 * XXX Es sieht so aus as ob nur noch t_name[NAMSIZ] auf ' '
203 * XXX gesetzt wird wenn dort ein null Byte steht.
204 */
205 if ((props.pr_flags & PR_CPIO) == 0) {
206 /*
207 * Needed to set up the uname/gname fields for the
208 * various TAR headers.
209 */
210 tcb_to_info(&newtb, &newinfo);
211 }
212 list_file(&newinfo);
213 }
214 }
215
216 /*
217 * Convert POSIX.1 TAR mode/permission flags into string.
218 */
219 LOCAL void
220 #ifdef PROTOTYPES
modstr(FINFO * info,char * s,register mode_t mode)221 modstr(FINFO *info, char *s, register mode_t mode)
222 #else
223 modstr(info, s, mode)
224 FINFO *info;
225 char *s;
226 register mode_t mode;
227 #endif
228 {
229 register char *mstr = "xwrxwrxwr";
230 register char *str = s;
231 register int i;
232
233 *str++ = '?'; /* Unknown file type */
234 for (i = 9; --i >= 0; ) {
235 if (mode & (1 << i))
236 *str++ = mstr[i];
237 else
238 *str++ = '-';
239 }
240 #ifdef USE_ACL
241 *str++ = ' ';
242 #endif
243 #ifdef USE_XATTR
244 *str++ = '\0'; /* Don't claim space for '@' */
245 #endif
246 *str = '\0';
247 str = s;
248 if (mode & TSVTX) {
249 if (mode & TOEXEC) {
250 str[9] = 't'; /* Sticky & exec. by others */
251 } else {
252 str[9] = 'T'; /* Sticky but !exec. by oth */
253 }
254 }
255 if (mode & TSGID) {
256 if (mode & TGEXEC) {
257 str[6] = 's'; /* Sgid & executable by grp */
258 } else {
259 if (!is_file(info))
260 str[6] = 'S'; /* Sgid directory, or other */
261 else
262 str[6] = 'l'; /* Mandatory lock file */
263 }
264 }
265 if (mode & TSUID) {
266 if (mode & TUEXEC)
267 str[3] = 's'; /* Suid & executable by own. */
268 else
269 str[3] = 'S'; /* Suid but not executable */
270 }
271 i = 10;
272 #ifdef USE_ACL
273 if ((info->f_xflags & (XF_ACL_ACCESS|XF_ACL_DEFAULT|XF_ACL_ACE)) != 0)
274 str[i++] = '+';
275 #endif
276 #ifdef USE_XATTR
277 if ((info->f_xflags & XF_XATTR) != 0)
278 str[i++] = '@';
279 #endif
280 i++; /* Make lint believe that we always use i. */
281 }
282
283 EXPORT void
list_file(info)284 list_file(info)
285 register FINFO *info;
286 {
287 FILE *f;
288 time_t *tp;
289 char *tstr;
290 char mstr[13]; /* 10 UNIX chars + ACL '+' XATTR '@' + nul */
291 char lstr[22]; /* ' ' + link count as string - 64 bits */
292 static char nuid[21]; /* uid as 64 bit long */
293 static char ngid[21]; /* gid as 64 bit long */
294 char *add = "";
295
296 f = vpr;
297 if (prblockno)
298 fgtprintf(f, "block %9lld: ", curblockno);
299 if (cflag)
300 fprintf(f, "a ");
301 else if (xflag)
302 fprintf(f, "x ");
303
304 if (prinodes && info->f_ino > 0)
305 fprintf(f, "%7llu ", (Llong)info->f_ino);
306 if (cflag && is_dir(info) && !no_dirslash) {
307 int len = info->f_namelen;
308
309 if (len == 0)
310 len = strlen(info->f_name);
311 if (info->f_name[len-1] != '/')
312 add = "/";
313 }
314 if (verbose) {
315 register Uint xft = info->f_xftype;
316
317 tp = acctime ? &info->f_atime :
318 (Ctime ? &info->f_ctime : &info->f_mtime);
319 tstr = ctime(tp);
320 if (numeric || info->f_uname == NULL) {
321 sprintf(nuid, "%lld", (Llong)info->f_uid);
322 info->f_uname = nuid;
323 info->f_umaxlen = sizeof (nuid)-1;
324 }
325 if (numeric || info->f_gname == NULL) {
326 sprintf(ngid, "%lld", (Llong)info->f_gid);
327 info->f_gname = ngid;
328 info->f_gmaxlen = sizeof (ngid)-1;
329 }
330
331 if (!paxls) {
332 if (is_special(info))
333 fprintf(f, "%3lu %3lu",
334 info->f_rdevmaj, info->f_rdevmin);
335 else
336 fprintf(f, "%7llu", (Llong)info->f_size);
337 }
338 modstr(info, mstr, info->f_mode);
339
340 if (paxls && info->f_nlink == 0 && is_link(info)) {
341 info->f_nlink = 2;
342 }
343 if (paxls || info->f_nlink > 0) {
344 /*
345 * UNIX ls uses %3d for the link count
346 * and does not claim space for ACL '+'
347 */
348 js_sprintf(lstr, " %2llu", (Ullong)info->f_nlink);
349 } else {
350 lstr[0] = 0;
351 }
352 /*
353 * XXX �bergangsweise, bis die neue Filetypenomenklatur sauber eingebaut ist.
354 */
355 if (xft == 0 || xft == XT_BAD) {
356 xft = info->f_xftype = IFTOXT(info->f_type);
357 errmsgno(EX_BAD, "XXXXX xftype == 0 (typeflag = '%c' 0x%02X)\n",
358 info->f_typeflag, info->f_typeflag);
359 }
360 if (xft == XT_LINK)
361 xft = info->f_rxftype;
362 {
363 char *p = XTTOSTR(xft);
364
365 if (p)
366 mstr[0] = *p;
367 }
368 if (!paxls) {
369 fprintf(f,
370 " %s%s %3.*s/%-3.*s %.12s %4.4s ",
371 mstr,
372 lstr,
373 (int)info->f_umaxlen, info->f_uname,
374 (int)info->f_gmaxlen, info->f_gname,
375 &tstr[4], &tstr[20]);
376 } else {
377 fprintf(f,
378 "%s%s %-8.*s %-8.*s ",
379 mstr,
380 lstr,
381 (int)info->f_umaxlen, info->f_uname,
382 (int)info->f_gmaxlen, info->f_gname);
383 if (is_special(info))
384 fprintf(f, "%3lu %3lu",
385 info->f_rdevmaj, info->f_rdevmin);
386 else
387 fprintf(f, "%7llu", (Llong)info->f_size);
388 if ((*tp < sixmonth) || (*tp > now)) {
389 fprintf(f, " %.6s %4.4s ",
390 &tstr[4], &tstr[20]);
391 } else {
392 fprintf(f, " %.12s ",
393 &tstr[4]);
394 }
395 }
396 }
397 fprintf(f, "%s%s", info->f_name, add);
398 if (tpath) {
399 fprintf(f, "\n");
400 return;
401 }
402 /*
403 * In case of a hardlinked symlink, we currently do not have the symlink
404 * target path and thus cannot check the synlink target. So first check
405 * whether it is a hardlink.
406 */
407 if (is_link(info)) {
408 if (is_dir(info))
409 fgtprintf(f, " directory");
410 fprintf(f, " %s %s",
411 paxls ? "==" : "link to",
412 info->f_lname);
413 } else if (is_symlink(info))
414 fprintf(f, " -> %s", info->f_lname);
415 if (is_volhdr(info))
416 fgtprintf(f, " --Volume Header--");
417 if (is_multivol(info)) {
418 fgtprintf(f, " --Continued at byte %lld--",
419 (Llong)info->f_contoffset);
420 }
421 fprintf(f, "\n");
422 }
423
424 EXPORT void
vprint(info)425 vprint(info)
426 FINFO *info;
427 {
428 FILE *f;
429 char *mode;
430 char *add = "";
431
432 if (verbose || interactive) {
433 if (verbose > 1) {
434 list_file(info);
435 return;
436 }
437
438 f = vpr;
439
440 if (prblockno)
441 fgtprintf(f, "block %9lld: ", curblockno);
442 if (cflag)
443 mode = "a ";
444 else if (xflag)
445 mode = "x ";
446 else
447 mode = "";
448
449 if (cflag && is_dir(info) && !no_dirslash) {
450 int len = info->f_namelen;
451
452 if (len == 0)
453 len = strlen(info->f_name);
454 if (info->f_name[len-1] != '/')
455 add = "/";
456 }
457 if (tpath) {
458 fprintf(f, "%s%s\n", info->f_name, add);
459 return;
460 }
461 if (is_dir(info)) {
462 if (is_link(info)) {
463 fgtprintf(f, "%s%s%s directory %s %s\n",
464 mode, info->f_name, add,
465 paxls ? "==" : "link to",
466 info->f_lname);
467 } else {
468 fgtprintf(f, "%s%s%s directory\n", mode,
469 info->f_name, add);
470 }
471 } else if (is_link(info)) {
472 fprintf(f, "%s%s %s %s\n",
473 mode, info->f_name,
474 paxls ? "==" : "link to",
475 info->f_lname);
476 } else if (is_symlink(info)) {
477 fprintf(f, "%s%s %s %s\n",
478 mode, info->f_name,
479 paxls ? "->" : "symbolic link to",
480 info->f_lname);
481 } else if (is_special(info)) {
482 fgtprintf(f, "%s%s special\n", mode, info->f_name);
483 } else {
484 fgtprintf(f, "%s%s %lld bytes, %lld tape blocks\n",
485 mode, info->f_name, (Llong)info->f_size,
486 (Llong)tarblocks(info->f_rsize));
487 }
488 }
489 }
490