upas/common: deliver mail to mdir as .tmp file and rename after it has been fully written

theres a race condition when mail delivery to mdir is slow,
then upas/fs sees partial mail file and caches the truncated
file size.

to avoid this, delivery will create the new mail file with
the .tmp extension (which is ignored by upas/fs) and after
everything has been written, rename it to the final name.
This commit is contained in:
cinap_lenrek 2017-04-08 22:50:17 +02:00
parent 00fbdd622a
commit fd78f6722e
2 changed files with 37 additions and 39 deletions

View file

@ -41,7 +41,7 @@ int returnable(char*);
/* folder.c */ /* folder.c */
Biobuf *openfolder(char*, long); Biobuf *openfolder(char*, long);
int closefolder(Biobuf*); int closefolder(Biobuf*);
int appendfolder(Biobuf*, char*, long*, int); int appendfolder(Biobuf*, char*, int);
int fappendfolder(char*, long, char *, int); int fappendfolder(char*, long, char *, int);
int fappendfile(char*, char*, int); int fappendfile(char*, char*, int);
char* foldername(char*, char*, char*); char* foldername(char*, char*, char*);

View file

@ -12,6 +12,7 @@ struct Folder{
int type; int type;
Biobuf *out; Biobuf *out;
Mlock *l; Mlock *l;
long t;
}; };
static Folder ftab[5]; static Folder ftab[5];
@ -44,12 +45,12 @@ putfolder(Folder *f)
r = 0; r = 0;
if(f->l) if(f->l)
sysunlock(f->l); sysunlock(f->l);
if(f->out) if(f->out){
r |= Bterm(f->out); r |= Bterm(f->out);
if(f->ofd > 0){
close(f->ofd);
free(f->out); free(f->out);
} }
if(f->ofd >= 0)
close(f->ofd);
memset(f, 0, sizeof *f); memset(f, 0, sizeof *f);
return r; return r;
} }
@ -59,7 +60,7 @@ mboxopen(char *s)
{ {
Folder *f; Folder *f;
f = getfolder(0); f = getfolder(nil);
f->l = syslock(s); /* traditional botch: ignore failure */ f->l = syslock(s); /* traditional botch: ignore failure */
if((f->ofd = open(s, OWRITE)) == -1) if((f->ofd = open(s, OWRITE)) == -1)
if((f->ofd = create(s, OWRITE|OEXCL, DMAPPEND|0600)) == -1){ if((f->ofd = create(s, OWRITE|OEXCL, DMAPPEND|0600)) == -1){
@ -79,13 +80,13 @@ mboxopen(char *s)
static Biobuf* static Biobuf*
mdiropen(char *s, long t) mdiropen(char *s, long t)
{ {
char buf[64]; char buf[Pathlen];
long i;
Folder *f; Folder *f;
int i;
f = getfolder(0); f = getfolder(nil);
for(i = 0; i < 100; i++){ for(i = 0; i < 100; i++){
snprint(buf, sizeof buf, "%s/%lud.%.2ld", s, t, i); snprint(buf, sizeof buf, "%s/%lud.%.2d.tmp", s, t, i);
if((f->ofd = create(buf, OWRITE|OEXCL, DMAPPEND|0660)) != -1) if((f->ofd = create(buf, OWRITE|OEXCL, DMAPPEND|0660)) != -1)
goto found; goto found;
} }
@ -96,6 +97,7 @@ found:
f->out = malloc(sizeof *f->out); f->out = malloc(sizeof *f->out);
Binit(f->out, f->ofd, OWRITE); Binit(f->out, f->ofd, OWRITE);
f->type = Mdir; f->type = Mdir;
f->t = t;
return f->out; return f->out;
} }
@ -121,31 +123,30 @@ openfolder(char *s, long t)
return mboxopen(s); return mboxopen(s);
} }
int
renamefolder(Biobuf *b, long t)
{
char buf[32];
int i;
Dir d;
Folder *f;
f = getfolder(b);
if(f->type != Mdir)
return 0;
for(i = 0; i < 100; i++){
nulldir(&d);
snprint(buf, sizeof buf, "%lud.%.2d", t, i);
d.name = buf;
if(dirfwstat(Bfildes(b), &d) > 0)
return 0;
}
return -1;
}
int int
closefolder(Biobuf *b) closefolder(Biobuf *b)
{ {
return putfolder(getfolder(b)); char buf[32];
Folder *f;
Dir d;
int i;
if(b == nil)
return 0;
f = getfolder(b);
if(f->type != Mdir)
return putfolder(f);
if(Bflush(b) == 0){
for(i = 0; i < 100; i++){
nulldir(&d);
snprint(buf, sizeof buf, "%lud.%.2d", f->t, i);
d.name = buf;
if(dirfwstat(f->ofd, &d) > 0)
return putfolder(f);
}
}
putfolder(f);
return -1;
} }
/* /*
@ -181,7 +182,7 @@ mboxesc(Biobuf *in, Biobuf *out, int type)
} }
int int
appendfolder(Biobuf *b, char *addr, long *t, int fd) appendfolder(Biobuf *b, char *addr, int fd)
{ {
char *s; char *s;
int r; int r;
@ -194,9 +195,9 @@ appendfolder(Biobuf *b, char *addr, long *t, int fd)
Binit(&bin, fd, OREAD); Binit(&bin, fd, OREAD);
s = Brdstr(&bin, '\n', 0); s = Brdstr(&bin, '\n', 0);
if(!s || strncmp(s, "From ", 5)) if(!s || strncmp(s, "From ", 5))
Bprint(f->out, "From %s %.28s\n", addr, ctime(*t)); Bprint(f->out, "From %s %.28s\n", addr, ctime(f->t));
else if(fromtotm(s, &tm) >= 0) else if(fromtotm(s, &tm) >= 0)
*t = tm2sec(&tm); f->t = tm2sec(&tm);
if(s) if(s)
Bwrite(f->out, s, strlen(s)); Bwrite(f->out, s, strlen(s));
free(s); free(s);
@ -207,16 +208,13 @@ appendfolder(Biobuf *b, char *addr, long *t, int fd)
int int
fappendfolder(char *addr, long t, char *s, int fd) fappendfolder(char *addr, long t, char *s, int fd)
{ {
long t0, r;
Biobuf *b; Biobuf *b;
int r;
b = openfolder(s, t); b = openfolder(s, t);
if(b == nil) if(b == nil)
return -1; return -1;
t0 = t; r = appendfolder(b, addr, fd);
r = appendfolder(b, addr, &t, fd);
if(t != t0)
renamefolder(b, t);
r |= closefolder(b); r |= closefolder(b);
return r; return r;
} }