/*
* a modified 'ls' that works by processing proto(3) files
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <fcall.h> /* dirmodefmt */
#include <disk.h>
#include <libsec.h>
#include <String.h>
#define dirbuf p9dirbuf /* avoid conflict on sun */
int errs = 0;
int aflag;
int lflag;
int mflag;
int pflag;
int qflag;
int Qflag;
int sflag;
int Fflag;
int Dflag;
int ls(char*, int);
char* asciitime(long);
void format(Dir*, char*);
void output(void);
ulong clk;
int swidth; /* max width of -s size */
int qwidth; /* max width of -q version */
int vwidth; /* max width of dev */
int uwidth; /* max width of userid */
int mwidth; /* max width of muid */
int glwidth; /* max width of groupid and length */
void usage(void);
char *argv0;
Biobuf *b;
Biobuf bin;
char *proto;
char *root;
static void addprotofile(char *new, char *old, Dir *d, void *a);
static int
digestfmt(Fmt *fmt)
{
char buf[MD5dlen*2+1];
uchar *p;
int i;
p = va_arg(fmt->args, uchar*);
for(i=0; i<MD5dlen; i++)
sprint(buf+2*i, "%.2ux", p[i]);
return fmtstrcpy(fmt, buf);
}
void
usage(void)
{
fprint(2, "usage: %s [-almpqsDFQ] [-R root] proto...\n", argv0);
exits("usage");
}
void
main(int argc, char **argv)
{
int i, errs;
void *a = nil;
root = ".";
Binit(&bin, 1, OWRITE);
ARGBEGIN{
case 'a': aflag++; break;
case 'F': Fflag++; break;
case 'l': lflag++; break;
case 'm': mflag++; break;
case 'p': pflag++; break;
case 'q': qflag++; break;
case 'Q': Qflag++; break;
case 's': sflag++; break;
case 'D': Dflag++; break;
case 'R':
root = EARGF(usage());
break;
default:
usage();
}ARGEND
doquote = needsrcquote;
quotefmtinstall();
fmtinstall('M', dirmodefmt);
fmtinstall('m', digestfmt);
if(argc < 1)
usage();
if(lflag)
clk = time(0);
errs = 0;
for(i = 0; i< argc; i++){
proto = argv[i];
b = Bopen(proto, OREAD);
if(b == nil)
sysfatal("can't open %s: %r", argv[i]);
if((errs = rdproto(proto, root, addprotofile, 0, a)) < 0)
sysfatal("rdproto: %r");
Bterm(b);
}
exits(errs? "errors" : 0);
}
static void
addprotofile(char *new, char *old, Dir *d, void *a)
{
if(Dflag){
Bprint(&bin, " new: %s\n", new);
Bprint(&bin, " old: %s\n", old);
Bprint(&bin, " name: %s\n", d->name);
}
// skip directories if listing for tar format
if(!(aflag && (QTDIR & d->qid.type))){
char *p, *name;
p = utfrune(new, '/');
name = p+1; // skips the default '/'
format(d, name);
Bflush(&bin);
}
}
char*
fileflag(Dir *db)
{
if(Fflag == 0)
return "";
if(QTDIR & db->qid.type)
return "/";
if(0111 & db->mode)
return "*";
return "";
}
void
format(Dir *db, char *name)
{
if(sflag)
Bprint(&bin, "%*llud ",
swidth, (db->length+1023)/1024);
if(qflag)
Bprint(&bin, "(%.16llux %*lud %.2ux) ",
db->qid.path,
qwidth, db->qid.vers,
db->qid.type);
if(lflag)
Bprint(&bin,
"%M %C %*ud %*s %s %*llud %s ",
db->mode, db->type,
vwidth, db->dev,
-uwidth, db->uid,
db->gid,
(int)(glwidth-strlen(db->gid)), db->length,
asciitime(db->mtime));
if(mflag) {
uchar digest[MD5dlen];
memset(digest, 0, sizeof digest);
if(!(QTDIR & db->qid.type)) {
int n, fd;
uchar buf[8192];
DigestState *s;
String *path = nil;
path = s_new();
s_append(path, root);
s_append(path, "/");
s_append(path, name);
fd = open(s_to_c(path), OREAD);
if(path)
s_free(path);
if(fd < 0){
Bprint(&bin, "md5sum: can't open %s: %r\n", name);
return;
}
s = md5(nil, 0, nil, nil);
while((n = read(fd, buf, sizeof buf)) > 0)
md5(buf, n, nil, s);
md5(nil, 0, digest, s);
close(fd);
}
Bprint(&bin, "%m\t", digest);
}
if(!pflag)
if(strcmp(root, ".") != 0)
Bprint(&bin, "%s/", root);
if(pflag) {
char *p = utfrrune(name, '/');
if(p){
name = p+1;
}
}
Bprint(&bin,
Qflag? "%s%s\n" : "%q%s\n",
name, fileflag(db));
}
char*
asciitime(long l)
{
static char buf[32];
char *t;
t = ctime(l);
/* 6 months in the past or a day in the future */
if(l<clk-180L*24*60*60 || clk+24L*60*60<l){
memmove(buf, t+4, 7); /* month and day */
memmove(buf+7, t+23, 5); /* year */
}else
memmove(buf, t+4, 12); /* skip day of week */
buf[12] = 0;
return buf;
}
|