extern int close(int fd) { int r; int oerrno; struct stat st; char buf[PATH_MAX]; if (fd >= 0 && fd < elementsof(exe) && exe[fd]) { r = exe[fd]->test; exe[fd]->test = 0; if (r > 0 && !fstat(fd, &st) && st.st_ino == exe[fd]->ino) { if (r = sysclose(fd)) return r; oerrno = errno; if (!stat(exe[fd]->path, &st) && st.st_ino == exe[fd]->ino) { snprintf(buf, sizeof(buf), "%s.exe", exe[fd]->path); sysrename(exe[fd]->path, buf); } errno = oerrno; return 0; } } return sysclose(fd); }
extern int chmod(const char* path, mode_t mode) { int r; int oerrno; char buf[PATH_MAX]; if ((r = syschmod(path, mode)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0)) { errno = oerrno; return syschmod(buf, mode); } if (!(r = syschmod(path, mode)) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH)) && !suffix(path) && (strlen(path) + 4) < sizeof(buf)) { oerrno = errno; if (!magic(path, NiL)) { snprintf(buf, sizeof(buf), "%s.exe", path); sysrename(path, buf); } errno = oerrno; } return r; }
/* * Perform the actual rename. For ease of use under vms5.0, check to see if we * have delete-privilege for the file. If not, try to set it. Returns 0 iff * no error occurred; otherwise the corresponding RMS status code. */ static doit(char *newspec, char *oldspec, GETPROT *prot_) { unsigned status; int modified = FALSE; #define DELETE_MASK ((XAB$M_NODEL << XAB$V_SYS)\ | (XAB$M_NODEL << XAB$V_OWN)\ | (XAB$M_NODEL << XAB$V_GRP)\ | (XAB$M_NODEL << XAB$V_WLD)) #define UNMASK(name,mask) if ((status = chprot(name, mask, 0)) == RMS$_NORMAL)\ status = 0 if (!cmpprot(prot_, "d")) { UNMASK(oldspec, prot_->p_mask & ~DELETE_MASK); if (status != 0) return (status); modified = TRUE; } if (!(status = sysrename(newspec, oldspec))) { if (modified) UNMASK(newspec, prot_->p_mask); } return (status); }
extern int rename(const char* fp, const char* tp) { int r; int oerrno; char fb[PATH_MAX]; char tb[PATH_MAX]; oerrno = errno; if ((r = sysrename(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1)) { if (execrate(tp, tb, sizeof(tb), 1)) tp = tb; errno = oerrno; r = sysrename(fb, tp); } return r; }
static void _writembox(Mailbox *mb, Mlock *lk) { Dir *d; Message *m; String *tmp; int mode, errs; Biobuf *b; tmp = s_copy(mb->path); s_append(tmp, ".tmp"); /* * preserve old files permissions, if possible */ d = dirstat(mb->path); if(d != nil){ mode = d->mode&0777; free(d); } else mode = MBOXMODE; sysremove(s_to_c(tmp)); b = sysopen(s_to_c(tmp), "alc", mode); if(b == 0){ fprint(2, "can't write temporary mailbox %s: %r\n", s_to_c(tmp)); return; } logmsg("writing new mbox", nil); errs = 0; for(m = mb->root->part; m != nil; m = m->next){ if(lk != nil) syslockrefresh(lk); if(m->deleted) continue; logmsg("writing", m); if(Bwrite(b, m->start, m->end - m->start) < 0) errs = 1; if(Bwrite(b, "\n", 1) < 0) errs = 1; } logmsg("wrote new mbox", nil); if(sysclose(b) < 0) errs = 1; if(errs){ fprint(2, "error writing temporary mail file\n"); s_free(tmp); return; } sysremove(mb->path); if(sysrename(s_to_c(tmp), mb->path) < 0) fprint(2, "%s: can't rename %s to %s: %r\n", argv0, s_to_c(tmp), mb->path); s_free(tmp); if(mb->d != nil) free(mb->d); mb->d = dirstat(mb->path); }
// // read in the mailbox and parse into messages. // static char* _readmbox(Mailbox *mb, int doplumb, Mlock *lk) { int fd, n; String *tmp; Dir *d; static char err[128]; Message *m, **l; Inbuf *inb; char *x; l = &mb->root->part; /* * open the mailbox. If it doesn't exist, try the temporary one. */ n = 0; retry: fd = open(mb->path, OREAD); if(fd < 0){ rerrstr(err, sizeof(err)); if(strstr(err, "exclusive lock") != 0 && n++ < 20){ sleep(500); /* wait for lock to go away */ goto retry; } if(strstr(err, "exist") != 0){ tmp = s_copy(mb->path); s_append(tmp, ".tmp"); if(sysrename(s_to_c(tmp), mb->path) == 0){ s_free(tmp); goto retry; } s_free(tmp); } return err; } /* * a new qid.path means reread the mailbox, while * a new qid.vers means read any new messages */ d = dirfstat(fd); if(d == nil){ close(fd); errstr(err, sizeof(err)); return err; } if(mb->d != nil){ if(d->qid.path == mb->d->qid.path && d->qid.vers == mb->d->qid.vers){ close(fd); free(d); return nil; } if(d->qid.path == mb->d->qid.path){ while(*l != nil) l = &(*l)->next; seek(fd, mb->d->length, 0); } free(mb->d); } mb->d = d; mb->vers++; henter(PATH(0, Qtop), mb->name, (Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb); inb = emalloc(sizeof(Inbuf)); inb->rptr = inb->wptr = inb->data; inb->fd = fd; // read new messages snprint(err, sizeof err, "reading '%s'", mb->path); logmsg(err, nil); for(;;){ if(lk != nil) syslockrefresh(lk); m = newmessage(mb->root); m->mallocd = 1; m->inmbox = 1; if(readmessage(m, inb) < 0){ delmessage(mb, m); mb->root->subname--; break; } // merge mailbox versions while(*l != nil){ if(memcmp((*l)->digest, m->digest, SHA1dlen) == 0){ // matches mail we already read, discard logmsg("duplicate", *l); delmessage(mb, m); mb->root->subname--; m = nil; l = &(*l)->next; break; } else { // old mail no longer in box, mark deleted logmsg("disappeared", *l); if(doplumb) mailplumb(mb, *l, 1); (*l)->inmbox = 0; (*l)->deleted = 1; l = &(*l)->next; } } if(m == nil) continue; x = strchr(m->start, '\n'); if(x == nil) m->header = m->end; else m->header = x + 1; m->mheader = m->mhend = m->header; parseunix(m); parse(m, 0, mb, 0); logmsg("new", m); /* chain in */ *l = m; l = &m->next; if(doplumb) mailplumb(mb, m, 0); } logmsg("mbox read", nil); // whatever is left has been removed from the mbox, mark deleted while(*l != nil){ if(doplumb) mailplumb(mb, *l, 1); (*l)->inmbox = 0; (*l)->deleted = 1; l = &(*l)->next; } close(fd); free(inb); return nil; }
extern int unlink(const char* path) { int r; int drive; int mask; int suffix; int stop; int oerrno; unsigned long base; char buf[PATH_MAX]; char tmp[MAX_PATH]; #define DELETED_DIR_1 7 #define DELETED_DIR_2 16 static char deleted[] = "%c:\\temp\\.deleted\\%08x.%03x"; static int count = 0; #if __CYGWIN__ DWORD fattr = FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE; DWORD share = FILE_SHARE_DELETE; HANDLE hp; struct stat st; char nat[MAX_PATH]; oerrno = errno; if (lstat(path, &st) || !S_ISREG(st.st_mode)) goto try_unlink; cygwin_conv_to_full_win32_path(path, nat); if (!strncasecmp(nat + 1, ":\\temp\\", 7)) goto try_unlink; drive = nat[0]; path = (const char*)nat; for (;;) { hp = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL); if (hp != INVALID_HANDLE_VALUE) { CloseHandle(hp); errno = oerrno; return 0; } if (GetLastError() != ERROR_FILE_NOT_FOUND) break; if (path == (const char*)buf || !execrate(path, buf, sizeof(buf), 1)) { errno = ENOENT; return -1; } path = (const char*)buf; } #else if (sysaccess(path, 0)) #if _win32_botch_access { if (errno != ENOENT || !execrate(path, buf, sizeof(buf), 1) || sysaccess(buf, 0)) return -1; path = (const char*)buf; } #else return -1; #endif drive = 'C': #endif /* * rename to a `deleted' path just in case the file is open * otherwise directory readers may choke on phantom entries */ base = ((getuid() & 0xffff) << 16) | (time(NiL) & 0xffff); suffix = (getpid() & 0xfff) + count++; snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix); if (!sysrename(path, tmp)) { path = (const char*)tmp; goto try_delete; } if (errno != ENOTDIR && errno != ENOENT) goto try_unlink; tmp[DELETED_DIR_2] = 0; if (sysaccess(tmp, 0)) { mask = umask(0); tmp[DELETED_DIR_1] = 0; if (sysaccess(tmp, 0) && mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO)) { umask(mask); goto try_unlink; } tmp[DELETED_DIR_1] = '\\'; r = mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO); umask(mask); if (r) goto try_unlink; errno = 0; } tmp[DELETED_DIR_2] = '\\'; if (!errno && !sysrename(path, tmp)) { path = (const char*)tmp; goto try_delete; } #if !__CYGWIN__ if (errno == ENOENT) { #if !_win32_botch_access if (execrate(path, buf, sizeof(buf), 1) && !sysrename(buf, tmp)) path = (const char*)tmp; #endif goto try_unlink; } #endif stop = suffix; do { snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix); if (!sysrename(path, tmp)) { path = (const char*)tmp; goto try_delete; } if (++suffix > 0xfff) suffix = 0; } while (suffix != stop); try_delete: #if __CYGWIN__ hp = CreateFile(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL); if (hp != INVALID_HANDLE_VALUE) { CloseHandle(hp); errno = oerrno; return 0; } #endif try_unlink: errno = oerrno; return sysunlink(path); }