#include "a.h"
#define IS_HEADER(p) ((p)[0]=='F'&&(p)[1]=='r'&&(p)[2]=='o'&&(p)[3]=='m'&&(p)[4]==' ')
#define IS_BODY(p) ((p)[0]=='\n'&&(p)[1]==0)
enum {
HEADER,
BOUNDARY,
ENDBOUNDARY,
REGULAR,
ENDF,
};
void
initmsg(Message *m)
{
m->bcc=(*mbox_bcc);
m->body=(*mbox_body);
m->cc=(*mbox_cc);
m->date=(*mbox_date);
m->digest=(*mbox_digest);
m->disposition=(*mbox_disposition);
m->filename=(*mbox_filename);
m->from=(*mbox_from);
m->header=(*mbox_header);
m->info=(*mbox_info);
m->inreplyto=(*mbox_inreplyto);
m->lines=(*mbox_lines);
m->messageid=(*mbox_messageid);
m->mimeheader=(*mbox_mimeheader);
m->raw=(*mbox_raw);
m->rawbody=(*mbox_rawbody);
m->rawheader=(*mbox_rawheader);
m->rawunix=(*mbox_rawunix);
m->replyto=(*mbox_replyto);
m->sender=(*mbox_sender);
m->subject=(*mbox_subject);
m->to=(*mbox_to);
m->type=(*mbox_type);
m->unixdate=(*mbox_unixdate);
m->unixheader=(*mbox_unixheader);
}
void
initbox(Mailbox *b)
{
b->sync=nil;
b->open=(*mbox_open);
b->fetch=(*mbox_fetch);
b->purge=nil;
}
/* I/O routunes */
char*
getline(Biobuf *b)
{
int c;
String *line;
char *res;
line=s_new();
c=Bgetc(b);
while(c > 0 && c != '\n' && c != '\r') {
s_putc(line,c);
c=Bgetc(b);
}
if (c == '\n' || c=='\r')
s_putc(line,'\n');
if (s_len(line) > 0) {
s_terminate(line);
res=estrdup(s_to_c(line));
setmalloctag(res,getcallerpc(&b));
s_free(line);
return res;
}
s_free(line);
return nil;
}
vlong
getdigest(Message *m, char **buff)
{
char *sdigest;
uchar hash[SHA1dlen];
sdigest=emalloc(SHA1dlen*2+1);
sha1(m->cache->b, m->cache->l, hash, nil);
for(int i = 0; i < SHA1dlen; i++)
sprint(sdigest+2*i, "%2.2ux", hash[i]);
sdigest[SHA1dlen+1]=0;
*buff=sdigest;
return (vlong)strlen(*buff);
}
vlong
getdatacache(Message *m, char **buff, vlong offset, vlong len)
{
uchar *pc;
char *ptr;
pc=m->cache->b+offset;
ptr=emalloc(len);
memcpy(ptr,pc,len);
setmalloctag(ptr,getcallerpc(&m));
*buff=ptr;
return len;
}
vlong
getdatadisk(Message *m, char **buff, vlong offset, vlong len)
{
Mailbox *b;
long n;
char *ptr;
b = m->b;
if ( Bseek(&b->br,offset,SEEK_SET) != offset) {
error(DEBUG,"getdatadisk(): error in Bseek (eof?)");
return -1;
}
ptr=emalloc(len);
if ( (n=Bread(&b->br,ptr,len)) != len ) {
error(DEBUG,"getdatadisk(): error in Bread (eof?)");
free(ptr);
return -1;
}
setmalloctag(ptr,getcallerpc(&m));
*buff=ptr;
return (vlong)n;
}
vlong
getdata(Message *m, char **buff, vlong start, vlong end, vlong offset, vlong len)
{
Message *root;
char *cbuff;
char *dbuff;
int merge;
vlong cstart, clen, cend, rlen;
vlong dstart, dlen;
rlen=0;
merge=0;
root=m->root;
if (len == 0 ) {
*buff=nil;
return 0;
}
if ( len > end-start )
len=end-start;
cstart=(start+offset)-root->start;
clen=len;
cend=end-root->start;
if ( cend > CACHELEN )
cend=CACHELEN;
rlen=0;
/* if there is something in cache, read it */
if ( cstart < cend ) {
if ( cstart+clen > cend ) {
merge=1;
clen=cend-cstart;
}
/* rlen is allways clen here */
rlen=getdatacache(m, &cbuff, cstart,clen);
if ( rlen <= 0 ) {
error(DEBUG,"getdata(): I/O error %d\n", rlen);
*buff=nil;
return 0;
}
}
clen=rlen;
/* if we have all, return */
if ( clen == len ) {
*buff=cbuff;
return clen;
}
dstart=start+offset+clen;
dlen=len-clen;
if ( dstart < end ) {
if ( dstart+dlen > end )
dlen=end-dstart;
rlen=getdatadisk(m,&dbuff,dstart,dlen);
if ( rlen < 0 ) {
*buff=nil;
return 0;
} else
dlen=rlen;
} else {
*buff=nil;
return 0;
}
if ( merge == 1 ) {
*buff=emalloc(clen+dlen);
memcpy(*buff,cbuff,clen);
memcpy(*buff+clen,dbuff,dlen);
free(cbuff);
free(dbuff);
} else {
*buff=dbuff;
}
return clen+dlen;
}
char*
gethdr(Message *m, char *term)
{
String *item;
int pos;
vlong hlen;
char *r;
char *hdr;
item=s_newalloc(MAX_LINE); // max line size rfc822
hlen=m->hend-m->hstart;
hlen=getdata(m,&hdr,m->hstart,m->hend,0,hlen);
if ( hdr == nil ) {
return nil;
}
pos=0;
while(hdr[pos] != 0 && pos <= hlen) {
if ( hdr[pos] == '\n' ) {
if ( pos < hlen )
pos++;
if ( hdr[pos] != ' ' && hdr[pos] != '\t' ) {
s_terminate(item);
if (cistrncmp(s_to_c(item),term,strlen(term)) != 0 ) {
s_free(item);
item=s_newalloc(MAX_LINE);
} else {
break;
}
}
} else {
s_putc(item,hdr[pos]);
pos++;
}
}
if ( s_len(item) <= 0 ) {
s_free(item);
free(hdr);
return nil;
}
s_terminate(item);
r=estrdup(s_to_c(item));
s_free(item);
free(hdr);
setmalloctag(r,getcallerpc(&m));
return r;
}
vlong
getterm(Message *m, char **buff, char *term)
{
char *q,*aux,*resp;
aux=gethdr(m,term);
if ( aux == nil ) {
*buff=nil;
return 0;
}
q=strstr(aux,":");
if(q!=nil) {
q++;
resp=strdup(q);
free(aux);
*buff=resp;
return (vlong)strlen(resp);
}
free(aux);
*buff=nil;
return 0;
}
char*
nexttok(char *p,int c)
{
char *q;
q=p;
while( *q != 0 && *q!=c)
q++;
return q;
}
char*
getattr(char *str, char *attr)
{
String *val;
char *v;
char *q;
val=s_new();
q=strtok(str,";");
while (q!=nil) {
q++; //skip ;
while( (*q == ' ' || *q == '\t') && *q != 0 )
q++;
if ( *q != 0 && cistrncmp(q,attr,strlen(attr)) == 0 ) {
q+=strlen(attr)+1; // skip the = sign
if (*q == '"')
q++;
while(*q!=0 && *q!='"') {
s_putc(val,*q);
q++;
}
if( s_len(val) <= 0) {
s_free(val);
return nil;
}
s_terminate(val);
v=strdup(s_to_c(val));
s_free(val);
setmalloctag(v,getcallerpc(&str));
return v;
}
q=strtok(nil,";");
}
s_free(val);
return nil;
}
char*
getval(char *str)
{
char *q;
String *item;
char *v;
q=str;
item=s_new();
while(*q == ' ' || *q == '\t')
q++;
while(*q != ';' && *q != 0) {
s_putc(item,*q);
q++;
}
if( s_len(item) <= 0 ) {
s_free(item);
return nil;
}
s_terminate(item);
v=strdup(s_to_c(item));
s_free(item);
setmalloctag(v,getcallerpc(&str));
return v;
}
int
cache(Message *m, char *buff, int len)
{
if ( buff == nil )
return 0;
if ( m->cache->l >= CACHELEN )
return 0;
if ( (m->cache->l+len) > CACHELEN )
len=CACHELEN-m->cache->l;
memcpy(&m->cache->b[m->cache->l],buff,len);
m->cache->l+=len;
return 1;
}
/* parsing functions */
char*
parsedate(Message *m)
{
char *str;
char *p, *q;
Tm tm;
char *date;
char *resp;
getterm(m,&str, "Received");
if ( str == nil )
return nil;
if((q = strchr(str, ';')) != nil){
p = q;
while((p = strchr(p, '\n')) != nil){
if(p[1] != ' ' && p[1] != '\t' && p[1] != '\n')
break;
p++;
}
if ( strtotm(q+1,&tm) <0) {
free(str);
return nil;
}
} else {
free(str);
return nil;
}
date = asctime(&tm);
if(q = strchr(date, '\n'))
*q = '\0';
free(str);
resp=estrdup(date);
return resp;
}
int
isbox(Mailbox *b)
{
char *line;
vlong pos;
pos=Boffset(&b->br);
line=getline(&b->br);
if ( line == nil )
return 0;
/* A mbox file each msg should start with
From <email> <date>
we just check the From<space> */
Bseek(&b->br, pos, SEEK_SET);
if (IS_HEADER(line)) {
free(line);
return 1;
}else {
free(line);
return 0;
}
}
int
islike(char *b1, char *b2)
{
if ( b1 != nil && b2 != nil)
return cistrncmp(b1,b2,strlen(b2));
else
return -1;
}
int
skipnewlines(Message *m)
{
Mailbox *b;
char *line;
vlong pos;
b=m->b;
while( (line=getline(&b->br)) !=nil) {
if ( line[0]!='\n')
break;
cache(m,line,strlen(line));
free(line);
}
if (line != nil) {
pos=Boffset(&b->br)-strlen(line);
Bseek(&b->br,pos,SEEK_SET);
free(line);
}
return 1;
}
int
ismark(Message *m, char *s, int lastnl)
{
if ( s == nil )
return ENDF;
if (lastnl == '\n' && IS_HEADER(s))
return HEADER;
if (islike(s,m->mime.endboundary) == 0 )
return ENDBOUNDARY;
if (islike(s,m->mime.boundary) == 0)
return BOUNDARY;
return REGULAR;
}
int
parsemime(Message *m)
{
char *str;
char *aux;
int l,r;
r=0;
l=getterm(m,&str,"Content-Type:");
if ( l > 0 ) {
m->mime.type=getval(str);
aux=getattr(str,"boundary");
if ( aux != nil ) {
m->mime.boundary=smprint("--%s",aux);
m->mime.endboundary=smprint("--%s--",aux);
free(aux);
r=1;
}
free(str);
}
l=getterm(m,&str,"Content-Disposition:");
if ( l > 0) {
m->mime.disposition=getval(str);
m->mime.filename=getattr(str,"filename");
free(str);
}
l=getterm(m,&str,"Content-Transfer-Encoding:");
if (l > 0){
m->mime.encoding=getval(str);
free(str);
}
return r;
}
int
parsehdr(Message *m)
{
Mailbox *b;
char *line;
int linelen;
b=m->b;
m->hstart=Boffset(&b->br);
while( (line=getline(&b->br) ) != nil ) {
m->linecount++;
linelen=strlen(line);
if ( cache(m, line, linelen) == 0 )
error(DEBUG,"parsehdr(): error caching line\n");
if ( line[0] == '\n' ) { // end of header is an empty line
m->hend=Boffset(&b->br);
free(line);
return 1;
}
free(line);
}
m->hend=Boffset(&b->br);
return 0;
}
int
parsebody(Message *m)
{
Mailbox *b;
char *line;
int linelen;
vlong pos;
int lastnl;
int q;
b=m->b;
m->bstart=Boffset(&b->br);
lastnl=0;
while ( (line=getline(&b->br) ) != nil ) {
m->linecount++;
linelen=strlen(line);
q=ismark(m,line,lastnl);
if ( q != REGULAR ) {
pos=Boffset(&b->br)-linelen;
Bseek(&b->br,pos,SEEK_SET);
m->bend=pos;
m->end=m->bend;
free(line);
return q;
}
cache(m, line, linelen);
lastnl=line[0];
free(line);
}
m->bend=Boffset(&b->br);
m->end=m->bend;
return 0;
}
void
copymimeboundary(Message *m1, Message *m2)
{
if ( m1 != nil && m2 != nil && m1==m2 )
return;
if (m2->mime.boundary != nil )
m1->mime.boundary=strdup(m2->mime.boundary);
if (m2->mime.endboundary != nil )
m1->mime.endboundary=strdup(m2->mime.endboundary);
}
int
findboundary(Message *m)
{
Mailbox *b;
char *line;
int lastnl,q;
b=m->b;
lastnl=0;
while ( (line=getline(&b->br) ) != nil ) {
q=ismark(m,line,lastnl);
cache(m,line,strlen(line));
if ( q != REGULAR && q != HEADER ) {
free(line);
return q;
}
lastnl=line[0];
free(line);
}
return ENDF;
}
Message*
parseparts(Mailbox *b, Message *last)
{
Message *m, *part, *next;
int r, nparts;
m=newmsg(Boffset(&b->br));
initmsg(m);
m->b=last->b;
m->id=last->id+1;
m->cache=last->cache;
m->root=last->root;
r=parsehdr(m);
if ( r==0 ) {
freem(m);
return nil;
}
r=parsemime(m);
if (r == 0 && last != nil )
copymimeboundary(m,last);
part=nil;
if ( islike(m->mime.type,"multipart/") == 0) {
skipnewlines(m);
do {
r=findboundary(m);
} while ( r != BOUNDARY && r != ENDF);
if ( r == ENDF )
return nil;
m->bstart=Boffset(&b->br);
nparts=0;
do {
if ( (next=parseparts(b,m) ) == nil)
break;
nparts++;
next->id=nparts;
if ( nparts == 1 ) {
m=ptoend(m,next);
part=next;
} else
part=mtoend(part,next);
} while ( next->status == BOUNDARY );
do {
r=findboundary(m);
} while ( r != BOUNDARY && r != ENDBOUNDARY && r != ENDF);
if ( r == ENDF )
return nil;
m->status=r;
skipnewlines(m);
m->end=Boffset(&b->br);
} else
m->status=parsebody(m);
return m;
}
/* interface to fs module */
/* message operations */
vlong
mbox_date(Message *m, char **buff)
{
*buff=parsedate(m);
if ( *buff != nil )
return strlen(*buff);
else
return 0;
}
vlong
mbox_from(Message *m,char **buff)
{
char *str;
vlong len;
len=getterm(m, &str, "From:");
*buff=addrrfc(str);
free(str);
if (*buff !=nil)
return strlen(*buff);
return 0;
}
vlong
mbox_to(Message *m, char **buff)
{
char *str;
vlong len;
len=getterm(m, &str, "To:");
*buff=addrrfc(str);
free(str);
if (*buff !=nil)
return strlen(*buff);
return 0;
}
vlong
mbox_inreplyto(Message *m,char **buff)
{
char *str;
vlong len;
len=getterm(m, &str, "In-Reply-To:");
*buff=addrrfc(str);
free(str);
if (*buff !=nil)
return strlen(*buff);
return 0;
}
vlong
mbox_replyto(Message *m, char **buff)
{
char *str;
vlong len;
len=getterm(m, &str, "Reply-To:");
*buff=addrrfc(str);
free(str);
if (*buff !=nil)
return strlen(*buff);
return 0;
}
vlong
mbox_sender(Message *m,char **buff)
{
char *str;
vlong len;
len=getterm(m, &str, "Sender:");
*buff=addrrfc(str);
free(str);
if (*buff !=nil)
return strlen(*buff);
return 0;
}
vlong
mbox_bcc(Message* m,char **buff)
{
char *str;
vlong len;
len=getterm(m, &str, "Bcc:");
*buff=addrrfc(str);
free(str);
if (*buff !=nil)
return strlen(*buff);
return 0;
}
vlong
mbox_cc(Message* m,char **buff)
{
char *str;
vlong len;
len=getterm(m, &str, "Cc:");
*buff=addrrfc(str);
free(str);
if (*buff !=nil)
return strlen(*buff);
return 0;
}
vlong
mbox_subject(Message *m, char **buff)
{
return getterm(m,buff,"Subject:");
}
vlong
mbox_messageid(Message *m, char **buff)
{
return getterm(m,buff, "Message-ID:");
}
vlong
mbox_disposition(Message *, char **buff)
{
*buff=nil;
return 0;
}
vlong
mbox_filename(Message*,char **buff)
{
*buff=nil;
return 0;
}
vlong
mbox_digest(Message *m, char**buff)
{
return getdigest(m,buff);
}
vlong
mbox_lines(Message *m, char **buff)
{
*buff=smprint("%d",m->linecount);
return (vlong)strlen(*buff);
}
vlong
mbox_header(Message *m ,char **buff)
{
Fmt info;
char *s;
char *a;
fmtstrinit(&info);
getterm(m,&s,"From:");
if ( s!= nil ) {
a=addrrfc(s);
fmtprint(&info,"From: %s\n",a);
free(a);
free(s);
}
getterm(m,&s,"To:");
if ( s!= nil ) {
a=addrrfc(s);
fmtprint(&info,"To: %s\n",a);
free(a);
free(s);
}
getterm(m,&s,"Cc:");
if ( s!= nil ) {
a=addrrfc(s);
fmtprint(&info,"Cc: %s\n",a);
free(a);
free(s);
}
getterm(m,&s,"Reply-To:");
if ( s!= nil ) {
a=addrrfc(s);
fmtprint(&info,"Reply-To: %s\n",a);
free(a);
free(s);
}
s=parsedate(m);
if ( s!= nil ) {
fmtprint(&info,"Date: %s\n",s);
free(s);
}
getterm(m,&s, "Subject:");
if ( s!= nil ) {
a=stringconvert(s);
fmtprint(&info,"Subject: %s\n",a);
free(a);
free(s);
}
getterm(m,&s,"Bcc:");
if ( s!= nil ) {
a=addrrfc(s);
fmtprint(&info,"Bcc: %s\n",a);
free(a);
free(s);
}
getterm(m,&s,"In-Reply-To:");
if ( s!= nil ) {
a=addrrfc(s);
fmtprint(&info,"In-Reply-To: %s\n",a);
free(a);
free(s);
}
*buff=fmtstrflush(&info);
return (vlong)strlen(*buff);
}
/* used by nedmail client
sender address
recipient addresses
cc addresses
reply address
envelope date
subject
MIME content type
MIME disposition
filename
SHA1 digest
bcc addresses
in-reply-to: contents
RFC822 date
message senders
message id
number of lines in body
if not found a \n is returned;
*/
vlong
mbox_info(Message*m, char **buff)
{
Fmt info;
char *s;
char *aux;
fmtstrinit(&info);
getterm(m,&s,"From:");
aux=addrrfc(s);
if ( aux != nil )
fmtprint(&info,"%s\n",aux);
else
fmtprint(&info,"\n");
free(s); free(aux);
getterm(m,&s,"To:");
aux=addrrfc(s);
if ( aux != nil )
fmtprint(&info,"%s\n",aux);
else
fmtprint(&info,"\n");
free(s); free(aux);
getterm(m,&s,"Cc:");
aux=addrrfc(s);
if ( aux != nil )
fmtprint(&info,"%s\n",aux);
else
fmtprint(&info,"\n");
free(s); free(aux);
getterm(m,&s,"Reply-To:");
aux=addrrfc(s);
if ( aux != nil )
fmtprint(&info,"%s\n",aux);
else
fmtprint(&info,"\n");
free(s); free(aux);
s=parsedate(m);
if ( s != nil )
fmtprint(&info,"%s\n",s);
else
fmtprint(&info,"\n");
free(s);
getterm(m,&s, "Subject:");
aux=stringconvert(s);
if ( aux != nil )
fmtprint(&info,"%s\n",aux);
else
fmtprint(&info,"\n");
free(s);free(aux);
if (m->mime.type != nil )
fmtprint(&info,"%s\n",m->mime.type);
else
fmtprint(&info,"\n");
if (m->mime.disposition != nil )
fmtprint(&info,"%s\n",m->mime.disposition);
else
fmtprint(&info,"\n");
if ( m->mime.filename != nil )
fmtprint(&info,"%s\n",m->mime.filename);
else
fmtprint(&info,"\n");
getdigest(m,&s);
if ( s != nil )
fmtprint(&info,"%s\n",s);
else
fmtprint(&info,"\n");
free(s);
getterm(m,&s,"Bcc:");
aux=addrrfc(s);
if ( aux != nil )
fmtprint(&info,"%s\n",aux);
else
fmtprint(&info,"\n");
free(s); free(aux);
getterm(m,&s,"In-Reply-To:");
aux=addrrfc(s);
if ( aux != nil )
fmtprint(&info,"%s\n",aux);
else
fmtprint(&info,"\n");
free(s); free(aux);
s=parsedate(m);
if ( s != nil )
fmtprint(&info,"%s\n",s);
else
fmtprint(&info,"\n");
free(s);
getterm(m,&s,"From:");
aux=stringconvert(s);
if ( aux != nil )
fmtprint(&info,"%s\n",aux);
else
fmtprint(&info,"\n");
free(s); free(aux);
getterm(m,&s,"Message-ID:");
if ( s != nil )
fmtprint(&info,"%s\n",s);
else
fmtprint(&info,"\n");
free(s);
fmtprint(&info,"%8.d\n",m->linecount);
*buff=fmtstrflush(&info);
return (vlong)strlen(*buff);
}
vlong
mbox_mimeheader(Message*,char **buff)
{
*buff=nil;
return 0;
}
vlong
mbox_raw(Message *m,char **buff, vlong offset, vlong len) {
return getdata(m, buff, m->start, m->end, offset, len);
}
vlong
mbox_rawbody(Message *m,char **buff, vlong offset, vlong len) {
return getdata(m, buff, m->bstart, m->bend, offset, len);
}
vlong
mbox_body(Message *m,char **buff, vlong offset, vlong len)
{
return getdata(m, buff, m->bstart, m->bend, offset, len);
}
vlong
mbox_rawheader(Message *m,char **buff, vlong offset, vlong len)
{
return getdata(m, buff, m->hstart, m->hend, offset, len);
}
vlong
mbox_rawunix(Message *m,char **buff, vlong offset, vlong len)
{
return getdata(m, buff, m->start, m->end, offset, len);
}
vlong
mbox_type(Message *m,char **buff) {
return getterm(m,buff, "Content-Type:");
}
vlong
mbox_unixdate(Message *m,char **buff)
{
*buff=parsedate(m);
if ( *buff != nil )
return strlen(*buff);
else
return 0;
}
vlong
mbox_unixheader(Message *m,char **buff)
{
char *str;
str=gethdr(m,"From ");
if ( str == nil )
return 0;
*buff=smprint("%s\n",str);
free(str);
return strlen(*buff);
}
/* box operations */
int
mbox_fetch(Mailbox *b)
{
Message *m, *part, *next;
int r, np;
if ( ! isbox(b) )
error(FATAL,"mbox_fetch(): error in mbox format\n");
do {
m=newmsg(Boffset(&b->br));
initmsg(m);
m->b=b;
m->id=b->idc+1;
m->cache=emalloc(sizeof *b->msgs->cache);
m->cache->l=0;
m->root=m;
r=parsehdr(m);
if ( r==0 ) {
freem(m);
break;
}
r=parsemime(m);
np=1;
part=m;
m->bstart=Boffset(&b->br);
if ( islike(m->mime.type,"multipart/") == 0) {
do {
next=parseparts(b,m);
if ( next == nil )
break;
next->id=np;
if ( np == 1) {
m=ptoend(m,next);
part=next;
} else
part=mtoend(part,next);
r=findboundary(m);
skipnewlines(m);
np++;
} while ( r == BOUNDARY);
} else
r=parsebody(m);
m->bend=Boffset(&b->br);
m->end=m->bend;
b->msgs=mtofront(b->msgs,m);
b->idc++;
} while ( r != ENDF );
return 1;
}
int
mbox_open(Mailbox *b)
{
if ( b->file == nil )
error(FATAL,"mbox_open(): b->name == nil");
b->r=open(b->file,OREAD);
b->w=open(b->file,ORDWR);
b->idc=0;
if ( b->r < 0 || b->w < 0 )
error(FATAL,"Error opening %s\n",b->file);
Binit(&b->br, b->r,OREAD);
Binit(&b->bw,b->w,OWRITE);
return 1;
}
int
mbox_delete(Message *m) {
Dir *d;
int c;
vlong from, to, rpos, wpos, offset, newlen;
Biobuf *r,*w;
r=&m->b->br;
w=&m->b->bw;
from=m->start;
to=m->end;
offset=to-from;
if (offset <=0 )
return -1;
d=dirfstat(Bfildes(r));
if ( d == nil )
return -1;
if ( from > d->length || from < 0 || to > d->length || to < 0 ) {
free(d);
return -1;
}
rpos = Bseek(r, to, SEEK_SET);
if ( rpos == Beof) {
free(d);
return -1;
}
wpos=Bseek(w,from, SEEK_SET);
if ( wpos == Beof) {
free(d);
return -1;
}
newlen=d->length-to;
for(vlong i=0; i<newlen; i++){
c=Bgetc(r);
if ( c != ENDF ) {
if ( Bputc(w,c) == ENDF){
free(d);
return -1;
}
} else {
free(d);
return -1;
}
}
d->length = newlen;
dirfwstat(Bfildes(w),d);
free(d);
return 1;
}
|