Compare commits

...

8 commits

Author SHA1 Message Date
cinap_lenrek
ddaadd65b4 libdisk: cleanname() paths for setname()/mkpath(), avoid utfrrune() 2024-12-09 13:57:39 +00:00
cinap_lenrek
9d552b68e4 nusb/lib: decode classcode() 0xFF -> vendor, 0xFE -> application (-specific) 2024-12-09 13:00:16 +00:00
Ori Bernstein
8e2a071b8b acme/Mail: fix redrawn line offsets, add support for flag filters
maintaining ->nsub was fragile, and didn't save very many cycles;
instead just compute it every time; it's only going to hurt with
a ton of giant threads.
2024-12-09 05:27:05 +00:00
Ori Bernstein
af83b606f9 upas/Mail: Add support for message filtering 2024-12-09 03:58:40 +00:00
cinap_lenrek
aa1e68e9fe nusbrd: pass $usbdebug to nusb/usbd
This can be usefull for debugging usb enumeration issues from boot,
if one has the chance to pass parameters on the bootloader.

It was initially suggested in a troubleshooting session todo as
a quick modification, but it can be usefull in general.
2024-12-09 01:30:16 +00:00
cinap_lenrek
eb52c928b1 nusb/usbd: improve debugging, dont portfail() when port attaches/detaches too fast, cleanup
- always dprint() all the port state transitions.
- when port is attaching in short succession and we'r reaching the limit,
  don't return -1 as that would cause portfail(), return 1 instead
  which would make us ignore it.
- cleanup portattach(), use Dev *d instead of h->dev.
2024-12-08 01:10:41 +00:00
cinap_lenrek
8cc080311f nusb/lib: decode more base class codes in classname() 2024-12-07 15:55:12 +00:00
cinap_lenrek
eab5162760 nusb/audio: fix wrong emallocz() call in getclockrange() 2024-12-07 15:54:07 +00:00
9 changed files with 202 additions and 89 deletions

View file

@ -101,13 +101,26 @@ are listed in
.IR upasfs (4) .IR upasfs (4)
.PD 0 .PD 0
.TP .TP
.B Filter [filter] [*flags]
Shows only messages where the sender or subject match
the
.I filter
regexp,
or where the
.I flags
string matches the state of the message. The flags
used are the same as for Mark, with the addition of
.I u
to represent unread messages.
Filter without an argument resets the filtering,
showing all messages again.
.PD 0
.TP
.B Redraw .B Redraw
Redraws the contents of the mailbox. Redraws the contents of the mailbox.
.PP .PP
The following text commands are recognized by the message The following text commands are recognized by the message
view: view:
.TP .TP
.B Reply [all] .B Reply [all]
Replies to a message, quoting it. Replies to a message, quoting it.
@ -120,15 +133,12 @@ As with the message view, but applied to the open message.
.TP .TP
.B Mark .B Mark
As with the message view, but applied to the open message. As with the message view, but applied to the open message.
.PP .PP
The following text commands are recognized by the composition The following text commands are recognized by the composition
window: window:
.TP .TP
.B Post .B Post
Sends the message currently being composed. Sends the message currently being composed.
.SS Format strings .SS Format strings
The formatting of messages in the list view is controlled by the The formatting of messages in the list view is controlled by the
format string defined through the format string defined through the

View file

@ -448,7 +448,7 @@ will appear when using the WIFI interface for netbooting.
To avoid the prompt, the To avoid the prompt, the
.I password .I password
can be specified with the boot parameter above. can be specified with the boot parameter above.
.SS \fLwpaopts=\fivalue\fP .SS \fLwpaopts=\fIvalue\fP
Pass Pass
.I value .I value
as additional options to as additional options to
@ -956,6 +956,14 @@ When defined,
.IR nusbrc (8) .IR nusbrc (8)
will use the dynamically assigned usb device address to name will use the dynamically assigned usb device address to name
usb devices instead of the device unique name. usb devices instead of the device unique name.
.SS \fLusbdebug=\fIvalue\fP
When defined, pass
.I value
as arguments to
.IR usbd (4).
Usually used to pass
.B -d
flags for verbose debug printing.
.SS VIDEO .SS VIDEO
.SS \fL*nocga=\fP .SS \fL*nocga=\fP
This inhibits the kernel and This inhibits the kernel and

View file

@ -5,7 +5,7 @@ if(! bind -a '#u' /dev)
mkdir -p -m 700 '#σc/usb' mkdir -p -m 700 '#σc/usb'
mkdir -p -m 700 '#σc/usbnet' mkdir -p -m 700 '#σc/usbnet'
if(! nusb/usbd) if(! nusb/usbd $usbdebug)
exit exit
@{ @{

View file

@ -266,17 +266,15 @@ parseasdesc1(Desc *dd, Aconf *c)
c->bits = b[4]; c->bits = b[4];
if(b[5] == 0){ /* continuous frequency range */ if(b[5] == 0){ /* continuous frequency range */
c->nfreq = 1; c->nfreq = 1;
c->freq = emallocz(sizeof(*f), 1); c->freq = emallocz(sizeof(*f), 0);
c->freq->min = b[6] | b[7]<<8 | b[8]<<16; c->freq->min = b[6] | (int)b[7]<<8 | (int)b[8]<<16;
c->freq->max = b[9] | b[10]<<8 | b[11]<<16; c->freq->max = b[9] | (int)b[10]<<8 | (int)b[11]<<16;
} else { /* discrete sampling frequencies */ } else { /* discrete sampling frequencies */
c->nfreq = b[5]; c->nfreq = b[5];
c->freq = emallocz(c->nfreq * sizeof(*f), 1); c->freq = emallocz(c->nfreq * sizeof(*f), 0);
b += 6; b += 6;
for(f = c->freq; f < c->freq+c->nfreq; f++, b += 3){ for(f = c->freq; f < c->freq+c->nfreq; f++, b += 3)
f->min = b[0] | b[1]<<8 | b[2]<<16; f->min = f->max = b[0] | (int)b[1]<<8 | (int)b[2]<<16;
f->max = f->min;
}
} }
break; break;
} }
@ -356,8 +354,8 @@ getclockrange(Aconf *c)
werrstr("invalid response"); werrstr("invalid response");
return -1; return -1;
} }
c->freq = emallocz(n, sizeof(Range));
c->nfreq = n; c->nfreq = n;
c->freq = emallocz(n*sizeof(Range), 0);
for(i = 0; i < n; i++) for(i = 0; i < n; i++)
c->freq[i] = (Range){GET4(&b[2 + i*12]), GET4(&b[6 + i*12])}; c->freq[i] = (Range){GET4(&b[2 + i*12]), GET4(&b[6 + i*12])};
return 0; return 0;

View file

@ -9,8 +9,25 @@ static char *edir[] = {"in", "out", "inout"};
static char *etype[] = {"ctl", "iso", "bulk", "intr"}; static char *etype[] = {"ctl", "iso", "bulk", "intr"};
static char* cnames[] = static char* cnames[] =
{ {
"none", "audio", "comms", "hid", "", [0x00] "none",
"", "", "printer", "storage", "hub", "data" [0x01] "audio",
[0x02] "comms",
[0x03] "hid",
[0x05] "phys",
[0x06] "image",
[0x07] "printer",
[0x08] "storage",
[0x09] "hub",
[0x0A] "data",
[0x0B] "smartcard",
[0x0D] "drm",
[0x0E] "video",
[0x0F] "healthcare",
[0x10] "av",
[0x11] "billboard",
[0x12] "usbc",
[0x13] "display",
[0x14] "mctp",
}; };
static char* devstates[] = static char* devstates[] =
{ {
@ -20,12 +37,25 @@ static char* devstates[] =
char* char*
classname(int c) classname(int c)
{ {
static char buf[30]; static char buf[12];
if(c >= 0 && c < nelem(cnames)) if(c >= 0 && c < nelem(cnames) && cnames[c] != nil && cnames[c][0] != '\0')
return cnames[c]; return cnames[c];
else{ switch(c){
seprint(buf, buf+30, "%d", c); case 0x3C: /* I3C Device Class */
return "i3c";
case 0xDC: /* Diagnostic Device */
return "debug";
case 0xE0: /* Wireless Controller */
return "wireless";
case 0xEF: /* Miscellaneous */
return "misc";
case 0xFE: /* Application specific */
return "application";
case 0xFF: /* Vendor specific */
return "vendor";
default:
snprint(buf, sizeof(buf), "%d", c);
return buf; return buf;
} }
} }
@ -146,11 +176,9 @@ emallocz(ulong size, int zero)
{ {
void *x; void *x;
x = malloc(size); x = mallocz(size, zero);
if(x == nil) if(x == nil)
sysfatal("malloc: %r"); sysfatal("malloc: %r");
if(zero)
memset(x, 0, size);
setmalloctag(x, getcallerpc(&size)); setmalloctag(x, getcallerpc(&size));
return x; return x;
} }

View file

@ -419,17 +419,13 @@ getmaxpkt(Dev *d)
* BUG: does not consider max. power avail. * BUG: does not consider max. power avail.
*/ */
static int static int
portattach(Hub *h, int p, u32int sts) portattach(Hub *h, int p)
{ {
Dev *d; Dev *nd, *d;
Port *pp; Port *pp;
Dev *nd; char *sp, fname[80], buf[40];
char fname[80]; int mp, nr, i;
char buf[40]; u32int sts;
char *sp;
int mp;
int nr;
int i;
d = h->dev; d = h->dev;
pp = &h->port[p]; pp = &h->port[p];
@ -445,9 +441,11 @@ portattach(Hub *h, int p, u32int sts)
if(++pp->acount > Attachcount){ if(++pp->acount > Attachcount){
fprint(2, "%s: %s: port %d: too many attaches in short succession\n", fprint(2, "%s: %s: port %d: too many attaches in short succession\n",
argv0, d->dir, p); argv0, d->dir, p);
return -1; /* don't call portfail() */
return 1;
} }
if(h->dev->isusb3){ if(d->isusb3){
sts = pp->sts;
sp = "super"; sp = "super";
} else { } else {
if(portfeature(h, p, Fportreset, 1) < 0){ if(portfeature(h, p, Fportreset, 1) < 0){
@ -463,12 +461,12 @@ portattach(Hub *h, int p, u32int sts)
if(sts & PShigh) if(sts & PShigh)
sp = "high"; sp = "high";
} }
dprint(2, "%s: %s: port %d: attached status %s %#ux, speed %s\n", argv0, d->dir, p,
stsstr(sts, d->isusb3), sts, sp);
if((sts & PSenable) == 0){ if((sts & PSenable) == 0){
dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p); dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p);
return -1; return -1;
} }
dprint(2, "%s: %s: port %d: attached status %s %#ux, speed %s\n", argv0, d->dir, p,
stsstr(sts, h->dev->isusb3), sts, sp);
pp->sts = sts; pp->sts = sts;
pp->state = Pattached; pp->state = Pattached;
if(devctl(d, "newdev %s %d", sp, p) < 0){ if(devctl(d, "newdev %s %d", sp, p) < 0){
@ -490,8 +488,8 @@ portattach(Hub *h, int p, u32int sts)
return -1; return -1;
} }
pp->dev = nd; pp->dev = nd;
nd->depth = h->dev->depth+1; nd->depth = d->depth+1;
nd->isusb3 = h->dev->isusb3; nd->isusb3 = d->isusb3;
if(usbdebug > 2) if(usbdebug > 2)
devctl(nd, "debug 1"); devctl(nd, "debug 1");
for(i=1;; i++){ for(i=1;; i++){
@ -659,6 +657,11 @@ enumhub(Hub *h, int p)
} }
onhubs = nhubs; onhubs = nhubs;
pp = &h->port[p]; pp = &h->port[p];
if(sts != pp->sts){
dprint(2, "%s: %s port %d: sts %s %#ux ->", argv0, d->dir, p,
stsstr(pp->sts, d->isusb3), pp->sts);
dprint(2, " %s %#ux\n", stsstr(sts, d->isusb3), sts);
}
if((sts & PSpresent) == 0 && (pp->sts & PSpresent) != 0){ if((sts & PSpresent) == 0 && (pp->sts & PSpresent) != 0){
pp->sts = sts; pp->sts = sts;
portdetach(h, p); portdetach(h, p);
@ -670,17 +673,14 @@ enumhub(Hub *h, int p)
portfail(h, p, "reset"); portfail(h, p, "reset");
} else if((sts & PSpresent) != 0 && (pp->sts & PSpresent) == 0){ } else if((sts & PSpresent) != 0 && (pp->sts & PSpresent) == 0){
pp->sts = sts; pp->sts = sts;
if(portattach(h, p, sts) < 0){ if(portattach(h, p) < 0){
if(h->failed) if(h->failed)
return -1; return -1;
if(pp->state != Pdisabled) if(pp->state != Pdisabled)
pp->sts = 0; /* force re-attach */ pp->sts = 0; /* force re-attach */
portfail(h, p, "attach"); portfail(h, p, "attach");
} }
} else if(sts != pp->sts){ } else {
dprint(2, "%s: %s port %d: sts %s %#ux ->", argv0, d->dir, p,
stsstr(pp->sts, d->isusb3), pp->sts);
dprint(2, " %s %#ux\n", stsstr(sts, d->isusb3), sts);
pp->sts = sts; pp->sts = sts;
} }
return onhubs != nhubs; return onhubs != nhubs;

View file

@ -16,6 +16,7 @@ enum {
Stoplev = 1<<1, /* not a response to anything */ Stoplev = 1<<1, /* not a response to anything */
Sopen = 1<<2, /* opened for viewing */ Sopen = 1<<2, /* opened for viewing */
Szap = 1<<3, /* flushed, to be removed from list */ Szap = 1<<3, /* flushed, to be removed from list */
Shide = 1<<4, /* hidden from view */
}; };
enum { enum {
@ -95,7 +96,6 @@ struct Mesg {
Mesg *parent; Mesg *parent;
Mesg **child; Mesg **child;
int nchild; int nchild;
int nsub; /* transitive children */
Mesg *body; /* best attachment to use, or nil */ Mesg *body; /* best attachment to use, or nil */
Mesg **parts; Mesg **parts;

View file

@ -31,6 +31,8 @@ char *listfmt = "%>48s\t<%f>";
Mesg dead = {.messageid="", .hash=42}; Mesg dead = {.messageid="", .hash=42};
Reprog *mesgpat; Reprog *mesgpat;
Reprog *filterpat;
char *filterflags;
int threadsort = 1; int threadsort = 1;
int sender; int sender;
@ -124,6 +126,45 @@ rcmpmesg(void *pa, void *pb)
return a->time - b->time; return a->time - b->time;
} }
static int
matchfilter(Mesg *m)
{
char *p;
int ok;
ok = 1;
if(filterpat != nil
&& m->subject != nil
&& m->from != nil){
if(!regexec(filterpat, m->subject, nil, 0)
&& !regexec(filterpat, m->from, nil, 0))
ok = 0;
}
for(p = filterflags; p && *p; p++){
switch(*p){
case 's': ok = ok && (m->flags & Fseen); break;
case 'u': ok = ok && !(m->flags & Fseen); break;
case 'a': ok = ok && (m->flags & Fresp); break;
}
}
return ok;
}
static int
nsub(Mesg *m)
{
Mesg *c;
int n, i;
n = 0;
for(i = 0; i < m->nchild; i++){
c = m->child[i];
if(!(c->state & (Sdummy|Shide)))
n += nsub(c)+1;
}
return n;
}
static int static int
mesglineno(Mesg *msg, int *depth) mesglineno(Mesg *msg, int *depth)
{ {
@ -142,9 +183,9 @@ mesglineno(Mesg *msg, int *depth)
for(i = 0; i < p->nchild; i++){ for(i = 0; i < p->nchild; i++){
if(p->child[i] == m) if(p->child[i] == m)
break; break;
o += p->child[i]->nsub + 1; o += nsub(p->child[i]) + 1;
} }
if(!(p->state & (Sdummy|Szap))){ if(!(p->state & (Sdummy|Shide))){
o++; o++;
d++; d++;
} }
@ -156,8 +197,8 @@ mesglineno(Mesg *msg, int *depth)
if(m == p) if(m == p)
break; break;
if(m->state & Stoplev){ if(m->state & Stoplev){
n += mbox.mesg[i]->nsub; n += nsub(mbox.mesg[i]);
if(!(m->state & (Sdummy|Szap))) if(!(m->state & (Sdummy|Szap|Shide)))
n++; n++;
} }
@ -169,7 +210,7 @@ mesglineno(Mesg *msg, int *depth)
} }
static int static int
addchild(Mesg *p, Mesg *m, int d) addchild(Mesg *p, Mesg *m)
{ {
Mesg *q; Mesg *q;
@ -181,8 +222,6 @@ addchild(Mesg *p, Mesg *m, int d)
if(m->time > q->time) if(m->time > q->time)
q->time = m->time; q->time = m->time;
} }
for(q = p; q != nil; q = q->parent)
q->nsub += d;
p->child = erealloc(p->child, ++p->nchild*sizeof(Mesg*)); p->child = erealloc(p->child, ++p->nchild*sizeof(Mesg*));
p->child[p->nchild - 1] = m; p->child[p->nchild - 1] = m;
qsort(p->child, p->nchild, sizeof(Mesg*), rcmpmesg); qsort(p->child, p->nchild, sizeof(Mesg*), rcmpmesg);
@ -346,7 +385,6 @@ static Mesg*
load(char *name, char *digest, int ins) load(char *name, char *digest, int ins)
{ {
Mesg *m, *p; Mesg *m, *p;
int d;
if(strncmp(name, mbox.path, strlen(mbox.path)) == 0) if(strncmp(name, mbox.path, strlen(mbox.path)) == 0)
name += strlen(mbox.path); name += strlen(mbox.path);
@ -356,13 +394,10 @@ load(char *name, char *digest, int ins)
if(digest != nil && strcmp(digest, m->digest) != 0) if(digest != nil && strcmp(digest, m->digest) != 0)
goto error; goto error;
/* if we already have a dummy, populate it */ /* if we already have a dummy, populate it */
d = 1;
p = lookupid(m->messageid); p = lookupid(m->messageid);
if(p != nil && (p->state & Sdummy)){ if(p != nil && (p->state & Sdummy)){
d = p->nsub + 1;
m->child = p->child; m->child = p->child;
m->nchild = p->nchild; m->nchild = p->nchild;
m->nsub = p->nsub;
mesgclear(p); mesgclear(p);
memcpy(p, m, sizeof(*p)); memcpy(p, m, sizeof(*p));
free(m); free(m);
@ -386,8 +421,10 @@ load(char *name, char *digest, int ins)
p = lookupid(m->inreplyto); p = lookupid(m->inreplyto);
if(p == nil) if(p == nil)
p = placeholder(m->inreplyto, m->time, ins); p = placeholder(m->inreplyto, m->time, ins);
if(!addchild(p, m, d)) if(!addchild(p, m))
m->state |= Stoplev; m->state |= Stoplev;
if(!matchfilter(m))
m->state |= Shide;
return m; return m;
error: error:
mesgfree(m); mesgfree(m);
@ -575,13 +612,12 @@ fmtmesg(Biobuf *bp, char *fmt, Mesg *m, int depth)
Bputc(bp, '\n'); Bputc(bp, '\n');
} }
static void static void
showmesg(Biobuf *bfd, Mesg *m, int depth, int recurse) showmesg(Biobuf *bfd, Mesg *m, int depth, int recurse)
{ {
int i; int i;
if(!(m->state & Sdummy)){ if(!(m->state & (Sdummy|Shide))){
fmtmesg(bfd, listfmt, m, depth); fmtmesg(bfd, listfmt, m, depth);
depth++; depth++;
} }
@ -654,7 +690,7 @@ mbmark(char **f, int nf)
static void static void
relinkmsg(Mesg *p, Mesg *m) relinkmsg(Mesg *p, Mesg *m)
{ {
Mesg *c, *pp; Mesg *c;
int i, j; int i, j;
/* remove child, preserving order */ /* remove child, preserving order */
@ -664,14 +700,12 @@ relinkmsg(Mesg *p, Mesg *m)
p->child[j++] = p->child[i]; p->child[j++] = p->child[i];
} }
p->nchild = j; p->nchild = j;
for(pp = p; pp != nil; pp = pp->parent)
pp->nsub -= m->nsub + 1;
/* reparent children */ /* reparent children */
for(i = 0; i < m->nchild; i++){ for(i = 0; i < m->nchild; i++){
c = m->child[i]; c = m->child[i];
c->parent = nil; c->parent = nil;
addchild(p, c, c->nsub + 1); addchild(p, c);
} }
} }
@ -694,17 +728,15 @@ mbflush(char **, int)
continue; continue;
ln = mesglineno(m, nil); ln = mesglineno(m, nil);
fprint(mbox.addr, "%d,%d", ln, ln+m->nsub); fprint(mbox.addr, "%d,%d", ln, ln+nsub(m));
write(mbox.data, "", 0); write(mbox.data, "", 0);
if(m->flags & Ftodel) if(m->flags & Ftodel)
fprint(fd, "delete %s %d", mailbox, atoi(m->name)); fprint(fd, "delete %s %d", mailbox, atoi(m->name));
removeid(m); removeid(m);
m->state |= Szap; m->state |= Szap;
if(p == nil && m->nsub != 0){ if(p == nil && nsub(m) != 0)
p = placeholder(m->messageid, m->time, 1); p = placeholder(m->messageid, m->time, 1);
p->nsub = m->nsub + 1;
}
if(p != nil) if(p != nil)
relinkmsg(p, m); relinkmsg(p, m);
for(j = 0; j < m->nchild; j++) for(j = 0; j < m->nchild; j++)
@ -814,10 +846,10 @@ changemesg(Plumbmsg *pm)
for(r = m; r->parent != nil; r = r->parent) for(r = m; r->parent != nil; r = r->parent)
/* nothing */; /* nothing */;
/* Bump whole thread up in list */ /* Bump whole thread up in list */
if(r->nsub > 0){ if(nsub(r) > 0){
ln = mesglineno(r, nil); ln = mesglineno(r, nil);
nr = r->nsub-1; nr = nsub(r)-1;
if(!(r->state & Sdummy)) if(!(r->state & (Sdummy|Shide)))
nr++; nr++;
/* /*
* We can end up with an empty container * We can end up with an empty container
@ -868,6 +900,46 @@ redraw(char **, int)
showlist(); showlist();
} }
static void
filter(char **filt, int nfilt)
{
Mesg *m;
int i;
if(nfilt > 2){
Usage:
fprint(2, "usage: Filter [regexp] [*flags]");
return;
}
free(filterpat);
free(filterflags);
filterpat = nil;
filterflags = nil;
for(i = 0; i < nfilt; i++){
if(*filt[i] == '*'){
if(filterflags != nil)
goto Usage;
filterflags = strdup(filt[i]+1);
}else{
if(filterpat != nil)
goto Usage;
filterpat = regcomp(filt[i]);
if(filterpat == nil){
fprint(2, "recomp: %r");
return;
}
}
}
for(i = 0; i < mbox.nmesg; i++){
m = mbox.mesg[i];
m->state &= ~Shide;
if(!matchfilter(m))
m->state |= Shide;
}
fprint(mbox.addr, ",");
showlist();
}
static void static void
nextunread(char **, int) nextunread(char **, int)
{ {
@ -886,8 +958,8 @@ Fn mboxfn[] = {
{"Redraw", redraw}, {"Redraw", redraw},
{"Next", nextunread}, {"Next", nextunread},
{"Mark", mbmark}, {"Mark", mbmark},
#ifdef NOTYET
{"Filter", filter}, {"Filter", filter},
#ifdef NOTYET
{"Get", mbrefresh}, {"Get", mbrefresh},
#endif #endif
{nil} {nil}

View file

@ -229,8 +229,8 @@ enum {
static void static void
setname(Mkaux *mkaux, Name *name, File *f) setname(Mkaux *mkaux, Name *name, File *f)
{ {
char *s1, *s2, *ss; char *s1, *s2;
int l; int n;
s1 = mkaux->root; s1 = mkaux->root;
s2 = ""; s2 = "";
@ -242,18 +242,14 @@ setname(Mkaux *mkaux, Name *name, File *f)
s2 = f->old; s2 = f->old;
}else }else
s2 = f->new; s2 = f->new;
n = strlen(s1) + strlen(s2) + 2;
l = strlen(s1); if(name->n < n+SLOP/2) {
ss = (*s1 && *s2 && *s2 != '/' && s1[l-1] != '/') ? "/" : "";
l += strlen(ss);
l += strlen(s2);
l++;
if(name->n < l+SLOP/2) {
free(name->s); free(name->s);
name->s = emalloc(mkaux, l+SLOP); name->s = emalloc(mkaux, n+SLOP);
name->n = l+SLOP; name->n = n+SLOP;
} }
snprint(name->s, name->n, "%s%s%s", s1, ss, s2); snprint(name->s, name->n, "%s/%s", s1, s2);
cleanname(name->s);
} }
@ -311,10 +307,8 @@ mkpath(Mkaux *mkaux, char *prefix, char *elem)
n = strlen(prefix) + strlen(elem) + 2; n = strlen(prefix) + strlen(elem) + 2;
p = emalloc(mkaux, n); p = emalloc(mkaux, n);
strcpy(p, prefix); snprint(p, n, "%s/%s", prefix, elem);
strcat(p, "/"); return cleanname(p);
strcat(p, elem);
return p;
} }
static int static int
@ -552,8 +546,11 @@ loop:
f = emalloc(mkaux, sizeof *f); f = emalloc(mkaux, sizeof *f);
f->new = mkpath(mkaux, old->new, elem); f->new = mkpath(mkaux, old->new, elem);
if((s = strrchr(f->new, '/')) != nil)
f->elem = s+1;
else
f->elem = f->new;
free(elem); free(elem);
f->elem = utfrrune(f->new, L'/') + 1;
if((p = getmode(mkaux, p, &f->mode)) == nil){ if((p = getmode(mkaux, p, &f->mode)) == nil){
freefile(f); freefile(f);