void LaosFileSystem::cleanlist() { // * open filename translation table char longname[MAXFILESIZE]; char shortname[SHORTFILESIZE]; char tabletmpname[MAXFILESIZE+SHORTFILESIZE+1]; strcpy (tabletmpname, tablename); tabletmpname[strlen(tabletmpname)-1] = '~'; // make a full copy of the table FILE* fp1 = fopen(tablename, "rb"); if (fp1 == NULL) return; FILE* fp2 = fopen(tabletmpname, "wb"); if (fp2 == NULL) return; while (dirread(longname, shortname, fp1)) dirwrite(longname, shortname, fp2); fclose(fp1); fclose(fp2); fp1 = fopen(tablename, "wb"); if (fp1 == NULL) return; fp2 = fopen(tabletmpname, "rb"); if (fp2 == NULL) return; FILE* fp; while (dirread(longname, shortname, fp2)) { char fullname[MAXFILESIZE+SHORTFILESIZE+1]; sprintf(fullname, "%s%s", pathname, shortname); fp = fopen(fullname, "rb"); if (fp != NULL) { fclose(fp); dirwrite(longname, shortname, fp1); } } fclose(fp1); fclose(fp2); }
void partall(void) { Disk *d; Dir *ent; char *name; int fd, i, n; fd = open("#S", OREAD); if(fd == -1) { fprint(2, "No disk\n"); return; } while((n = dirread(fd, &ent)) > 0) { for(i = 0; i < n; i++) { if(ent[i].mode & DMDIR) { name = smprint("#S/%s/data", ent[i].name); d = opendisk(name, 1, 0); if(!d) { fprint(2, "%s: %r\n", name); continue; } // XXX not safe yet: if(!mbrpart(d) && !cdpart(d) && !p9part(d, "data", 0)) if(!mbrpart(d) && !cdpart(d)) fprint(2, "%s: no partitions\n", name); close(d->fd); } } } close(fd); }
void readalljobs(void) { User *u; Dir *d, *du; char file[128]; int i, n, fd; fd = open("/cron", OREAD); if(fd < 0) fatal("can't open /cron: %r"); while((n = dirread(fd, &d)) > 0){ for(i = 0; i < n; i++){ if(strcmp(d[i].name, "log") == 0 || !(d[i].qid.type & QTDIR)) continue; if(strcmp(d[i].name, d[i].uid) != 0){ syslog(1, CRONLOG, "cron for %s owned by %s", d[i].name, d[i].uid); continue; } u = newuser(d[i].name); snprint(file, sizeof file, "/cron/%s/cron", d[i].name); du = dirstat(file); if(du == nil || qidcmp(u->lastqid, du->qid) != 0){ freejobs(u->jobs); u->jobs = readjobs(file, u); } free(du); } free(d); } close(fd); }
void renamedir(char *d) { int n; Dir *dir; char *sub; int fd, i; Name *na; fd = open(d, OREAD); if (fd == -1) return; while((n = dirread(fd, &dir)) > 0){ for(i = 0; i < n; i++){ if(dir[i].mode & DMDIR){ sub = malloc(strlen(d) + 1 + strlen(dir[i].name) + 1); sprint(sub, "%s/%s", d, dir[i].name); renamedir(sub); free(sub); } if(strlen(dir[i].name) != ENCLEN) continue; for (na = names; na != nil; na = na->next){ if (strcmp(na->shortname, dir[i].name) == 0){ rename(d, dir[i].name, na->longname); break; } } } free(dir); } close(fd); }
void dirtime(char *dir, char *path) { int i, fd, n; void *t; Dir db[32]; char buf[8192]; fd = open(dir, OREAD); if(fd >= 0) { while((n = dirread(fd, db, sizeof db)) > 0){ n /= sizeof(Dir); for(i = 0; i < n; i++){ t = (void *)db[i].mtime; if (!t) /* zero mode file */ continue; sprint(buf, "%s%s", path, db[i].name); if(symlook(buf, S_TIME, 0)) continue; symlook(strdup9(buf), S_TIME, t)->value = t; } } close(fd); } }
void dirtime(char *dir, char *path) { int i, fd, n; ulong mtime; Dir *d; char buf[4096]; fd = open(dir, OREAD); if(fd >= 0){ while((n = dirread(fd, &d)) > 0){ for(i=0; i<n; i++){ mtime = d[i].mtime; /* defensive driving: this does happen */ if(mtime == 0) mtime = 1; snprint(buf, sizeof buf, "%s%s", path, d[i].name); if(symlook(buf, S_TIME, 0) == nil) symlook(strdup(buf), S_TIME, (void*)mtime)->u.value = mtime; } free(d); } close(fd); } }
/* * onlydirs is advisory -- it means you only * need to return the directories. it's okay to * return files too (e.g., on unix where you can't * tell during the readdir), but that just makes * the globber work harder. */ int Readdir(int f, void *p, int onlydirs) { int n; if(f<0 || f>=NFD) return 0; Again: if(dir[f].i==dir[f].n){ /* read */ free(dir[f].dbuf); dir[f].dbuf = 0; n = dirread(f, &dir[f].dbuf); if(n>0){ if(onlydirs){ n = trimdirs(dir[f].dbuf, n); if(n == 0) goto Again; } dir[f].n = n; }else dir[f].n = 0; dir[f].i = 0; } if(dir[f].i == dir[f].n) return 0; strcpy(p, dir[f].dbuf[dir[f].i].name); dir[f].i++; return 1; }
void Xrdfn(void) { int f, len; Dir *e; char envname[Maxenvname]; static Dir *ent, *allocent; static int nent; for(;;){ if(nent == 0){ free(allocent); nent = dirread(envdir, &allocent); ent = allocent; } if(nent <= 0) break; while(nent){ e = ent++; nent--; len = e->length; if(len && strncmp(e->name, "fn#", 3)==0){ snprint(envname, sizeof envname, "/env/%s", e->name); if((f = open(envname, 0))>=0){ execcmds(openfd(f)); return; } } } } close(envdir); Xreturn(); }
void ls(char *file) { Dir *d; int fd, i, nd; fd = open(file, OREAD); if(fd < 0) return; /* * read box to find all messages * each one has a directory, and is in numerical order */ d = dirfstat(fd); if(d == nil){ close(fd); return; } if(!(d->mode & DMDIR)){ fprint(2, "file %s\n", file); free(d); close(fd); return; } free(d); while((nd = dirread(fd, &d)) > 0){ for(i = 0; i < nd; i++){ fprint(2, "%s/%s %c\n", file, d[i].name, "-d"[(d[i].mode & DMDIR) == DMDIR]); } free(d); } close(fd); }
int preaddir(Fid *f, uchar *data, int n, vlong offset) { int r = 0, m; Dir *d; DEBUG(DFD, "\tpreaddir n=%d wo=%lld fo=%lld\n", n, offset, f->offset); if(offset == 0 && f->offset != 0){ if(seek(f->fid, 0, 0) != 0) return -1; f->offset = f->cdir = f->ndir = 0; free(f->dir); f->dir = nil; }else if(offset != f->offset){ werrstr("can't seek dir %lld to %lld", f->offset, offset); return -1; } while(n > 0){ if(f->dir == nil){ f->ndir = dirread(f->fid, &f->dir); if(f->ndir < 0) return f->ndir; if(f->ndir == 0) return r; } d = &f->dir[f->cdir++]; if(exclude){ char *p = makepath(f->f, d->name); if(excludefile(p)){ free(p); goto skipentry; } free(p); } m = convD2M(d, data, n); DEBUG(DFD, "\t\tconvD2M %d\n", m); if(m <= BIT16SZ){ DEBUG(DFD, "\t\t\tneeded %d\n", GBIT16(data)); /* not enough room for full entry; leave for next time */ f->cdir--; return r; }else{ data += m; n -= m; r += m; f->offset += m; } skipentry: if(f->cdir >= f->ndir){ f->cdir = f->ndir = 0; free(f->dir); f->dir = nil; } } return r; }
void refreshwin(void) { char label[128]; int i, fd, lfd, n, nr, nw, m; Dir *pd; if((fd = open("/dev/wsys", OREAD)) < 0) return; nw = 0; /* i'd rather read one at a time but rio won't let me */ while((nr=dirread(fd, &pd)) > 0){ for(i=0; i<nr; i++){ n = atoi(pd[i].name); sprint(label, "/dev/wsys/%d/label", n); if((lfd = open(label, OREAD)) < 0) continue; m = read(lfd, label, sizeof(label)-1); close(lfd); if(m < 0) continue; label[m] = '\0'; if(exclude != nil && regexec(exclude,label,nil,0)) continue; if(nw < nwin && win[nw].n == n && strcmp(win[nw].label, label)==0){ nw++; continue; } if(nw < nwin){ free(win[nw].label); win[nw].label = nil; } if(nw >= mwin){ mwin += 8; win = erealloc(win, mwin*sizeof(win[0])); } win[nw].n = n; win[nw].label = estrdup(label); win[nw].dirty = 1; win[nw].r = Rect(0,0,0,0); nw++; } free(pd); } while(nwin > nw) free(win[--nwin].label); nwin = nw; close(fd); }
void Vinit(void) { int dir, f, len, i, n, nent; char *buf, *s; char envname[Maxenvname]; word *val; Dir *ent; dir = open("/env", OREAD); if(dir<0){ pfmt(err, "rc: can't open /env: %r\n"); return; } ent = nil; for(;;){ nent = dirread(dir, &ent); if(nent <= 0) break; for(i = 0; i<nent; i++){ len = ent[i].length; if(len && strncmp(ent[i].name, "fn#", 3)!=0){ snprint(envname, sizeof envname, "/env/%s", ent[i].name); if((f = open(envname, 0))>=0){ buf = emalloc(len+1); n = readn(f, buf, len); if (n <= 0) buf[0] = '\0'; else buf[n] = '\0'; val = 0; /* Charitably add a 0 at the end if need be */ if(buf[len-1]) buf[len++]='\0'; s = buf+len-1; for(;;){ while(s!=buf && s[-1]!='\0') --s; val = newword(s, val); if(s==buf) break; --s; } setvar(ent[i].name, val); vlook(ent[i].name)->changed = 0; close(f); efree(buf); } } } free(ent); } close(dir); }
vlong du(char *name, Dir *dir) { int fd, i, n; Dir *buf, *d; String *file; vlong nk, t; if(dir == nil) return warn(name); if((dir->qid.type&QTDIR) == 0) return dirval(dir, blkmultiple(dir->length)); fd = open(name, OREAD); if(fd < 0) return warn(name); nk = 0; while((n=dirread(fd, &buf)) > 0) { d = buf; for(i = n; i > 0; i--, d++) { if((d->qid.type&QTDIR) == 0) { nk += dufile(name, d); continue; } if(strcmp(d->name, ".") == 0 || strcmp(d->name, "..") == 0 || /* !readflg && */ seen(d)) continue; /* don't get stuck */ file = s_copy(name); s_append(file, "/"); s_append(file, d->name); t = du(s_to_c(file), d); nk += t; t = dirval(d, t); if(!sflag) printamt(t, s_to_c(file)); s_free(file); } free(buf); } if(n < 0) warn(name); close(fd); return dirval(dir, nk); }
void readenv(void) { char *p; int envf, f; Dir *e; char nam[1024]; int i, n, len; Word *w; rfork(RFENVG); /* use copy of the current environment variables */ envf = open("/env", OREAD); if(envf < 0) return; while((n = dirread(envf, &e)) > 0){ for(i = 0; i < n; i++){ len = e[i].length; /* don't import funny names, NULL values, * or internal mk variables */ if(len <= 0 || *shname(e[i].name) != '\0') continue; if (symlook(e[i].name, S_INTERNAL, 0)) continue; snprint(nam, sizeof nam, "/env/%s", e[i].name); f = open(nam, OREAD); if(f < 0) continue; p = Malloc(len+1); if(read(f, p, len) != len){ perror(nam); close(f); continue; } close(f); if (p[len-1] == 0) len--; else p[len] = 0; w = encodenulls(p, len); free(p); p = strdup(e[i].name); setvar(p, (void *) w); symlook(p, S_EXPORTED, (void*)"")->u.ptr = ""; } free(e); } close(envf); }
void LaosFileSystem::getlongname(char *result, char *searchname) { FILE *fp = fopen(tablename, "r"); if (fp) { char longname[MAXFILESIZE]; char shortname[SHORTFILESIZE]; while (dirread(longname, shortname, fp)) if (! strcmp(shortname, searchname)) break; if (strcmp(shortname, searchname)) strcpy(result, searchname); else strcpy(result, longname); fclose(fp); } else { strcpy(result, searchname); } }
void loadmboxfaces(char *maildir) { int dirfd; Dir *d; int i, n; dirfd = open(maildir, OREAD); if(dirfd >= 0){ chdir(maildir); while((n = dirread(dirfd, &d)) > 0){ for(i=0; i<n; i++) addface(dirface(maildir, d[i].name)); free(d); } close(dirfd); } }
void mkentry(uint16_t inum) { struct dinode rootino; struct direct dentry; uint16_t d; iread(ROOTINODE, &rootino); for (d = 0; d < swizzle32(rootino.i_size)/32; ++d) { dirread(&rootino, d, &dentry); if (dentry.d_ino == 0 && dentry.d_name[0] == '\0') { dentry.d_ino = swizzle16(inum); sprintf(dentry.d_name, "l+f%d", inum); dirwrite(&rootino, d, &dentry); return; } } printf("Sorry... No empty slots in root directory.\n"); }
void LaosFileSystem::getshortname(char* shortname, char* name) { // * open filename translation table // * and see if a file with that name exists if (isshortname(name)) { strcpy(shortname, name); } else { int found = 0; char longname[MAXFILESIZE]; FILE *fp = fopen(tablename, "r"); if (fp) { while (dirread(longname, shortname, fp)) { if (!strcmp(longname, name)) { found = 1; break; } } if (! found) strcpy(shortname, ""); fclose(fp); } } }
void threadmain(int argc, char **argv) { int i, j, fd, n, printstats; Dir *d; char *s; uint64_t u; VacFile *f, *fdiff; VacFs *fsdiff; int blocksize; int outfd; char *stdinname; char *diffvac; uint64_t qid; fmtinstall('F', vtfcallfmt); fmtinstall('H', encodefmt); fmtinstall('V', vtscorefmt); blocksize = BlockSize; stdinname = nil; printstats = 0; fsdiff = nil; diffvac = nil; ARGBEGIN{ case 'V': chattyventi++; break; case 'a': archivefile = EARGF(usage()); break; case 'b': u = unittoull(EARGF(usage())); if(u < 512) u = 512; if(u > VtMaxLumpSize) u = VtMaxLumpSize; blocksize = u; break; case 'd': diffvac = EARGF(usage()); break; case 'e': excludepattern(EARGF(usage())); break; case 'f': vacfile = EARGF(usage()); break; case 'h': host = EARGF(usage()); break; case 'i': stdinname = EARGF(usage()); break; case 'm': merge++; break; case 'q': qdiff++; break; case 's': printstats++; break; case 'v': verbose++; break; case 'x': loadexcludefile(EARGF(usage())); break; default: usage(); }ARGEND if(argc == 0 && !stdinname) usage(); if(archivefile && (vacfile || diffvac)){ fprint(2, "cannot use -a with -f, -d\n"); usage(); } z = vtdial(host); if(z == nil) sysfatal("could not connect to server: %r"); if(vtconnect(z) < 0) sysfatal("vtconnect: %r"); // Setup: // fs is the output vac file system // f is directory in output vac to write new files // fdiff is corresponding directory in existing vac if(archivefile){ VacFile *fp; char yyyy[5]; char mmdd[10]; char oldpath[40]; Tm tm; fdiff = nil; if((outfd = open(archivefile, ORDWR)) < 0){ if(access(archivefile, 0) >= 0) sysfatal("open %s: %r", archivefile); if((outfd = create(archivefile, OWRITE, 0666)) < 0) sysfatal("create %s: %r", archivefile); atexit(removevacfile); // because it is new if((fs = vacfscreate(z, blocksize, 512)) == nil) sysfatal("vacfscreate: %r"); }else{ if((fs = vacfsopen(z, archivefile, VtORDWR, 512)) == nil) sysfatal("vacfsopen %s: %r", archivefile); if((fdiff = recentarchive(fs, oldpath)) != nil){ if(verbose) fprint(2, "diff %s\n", oldpath); }else if(verbose) fprint(2, "no recent archive to diff against\n"); } // Create yyyy/mmdd. tm = *localtime(time(0)); snprint(yyyy, sizeof yyyy, "%04d", tm.year+1900); fp = vacfsgetroot(fs); if((f = vacfilewalk(fp, yyyy)) == nil && (f = vacfilecreate(fp, yyyy, ModeDir|0555)) == nil) sysfatal("vacfscreate %s: %r", yyyy); vacfiledecref(fp); fp = f; snprint(mmdd, sizeof mmdd, "%02d%02d", tm.mon+1, tm.mday); n = 0; while((f = vacfilewalk(fp, mmdd)) != nil){ vacfiledecref(f); n++; snprint(mmdd+4, sizeof mmdd-4, ".%d", n); } f = vacfilecreate(fp, mmdd, ModeDir|0555); if(f == nil) sysfatal("vacfscreate %s/%s: %r", yyyy, mmdd); vacfiledecref(fp); if(verbose) fprint(2, "archive %s/%s\n", yyyy, mmdd); }else{ if(vacfile == nil) outfd = 1; else if((outfd = create(vacfile, OWRITE, 0666)) < 0) sysfatal("create %s: %r", vacfile); atexit(removevacfile); if((fs = vacfscreate(z, blocksize, 512)) == nil) sysfatal("vacfscreate: %r"); f = vacfsgetroot(fs); fdiff = nil; if(diffvac){ if((fsdiff = vacfsopen(z, diffvac, VtOREAD, 128)) == nil) warn("vacfsopen %s: %r", diffvac); else fdiff = vacfsgetroot(fsdiff); } } if(stdinname) vacstdin(f, stdinname); for(i=0; i<argc; i++){ // We can't use / and . and .. and ../.. as valid archive // names, so expand to the list of files in the directory. if(argv[i][0] == 0){ warn("empty string given as command-line argument"); continue; } cleanname(argv[i]); if(strcmp(argv[i], "/") == 0 || strcmp(argv[i], ".") == 0 || strcmp(argv[i], "..") == 0 || (strlen(argv[i]) > 3 && strcmp(argv[i]+strlen(argv[i])-3, "/..") == 0)){ if((fd = open(argv[i], OREAD)) < 0){ warn("open %s: %r", argv[i]); continue; } while((n = dirread(fd, &d)) > 0){ for(j=0; j<n; j++){ s = vtmalloc(strlen(argv[i])+1+strlen(d[j].name)+1); strcpy(s, argv[i]); strcat(s, "/"); strcat(s, d[j].name); cleanname(s); vac(f, fdiff, s, &d[j]); } free(d); } close(fd); continue; } if((d = dirstat(argv[i])) == nil){ warn("stat %s: %r", argv[i]); continue; } vac(f, fdiff, argv[i], d); free(d); } if(fdiff) vacfiledecref(fdiff); /* * Record the maximum qid so that vacs can be merged * without introducing overlapping qids. Older versions * of vac arranged that the root would have the largest * qid in the file system, but we can't do that anymore * (the root gets created first!). */ if(_vacfsnextqid(fs, &qid) >= 0) vacfilesetqidspace(f, 0, qid); vacfiledecref(f); /* * Copy fsdiff's root block score into fs's slot for that, * so that vacfssync will copy it into root.prev for us. * Just nice documentation, no effect. */ if(fsdiff) memmove(fs->score, fsdiff->score, VtScoreSize); if(vacfssync(fs) < 0) fprint(2, "vacfssync: %r\n"); fprint(outfd, "vac:%V\n", fs->score); atexitdont(removevacfile); vacfsclose(fs); vthangup(z); if(printstats){ fprint(2, "%d files, %d files skipped, %d directories\n" "%lld data bytes written, %lld data bytes skipped\n", stats.nfile, stats.skipfiles, stats.ndir, stats.data, stats.skipdata); dup(2, 1); packetstats(); } threadexitsall(0); }
/* * Archive the file named name, which has stat info d, * into the vac directory fp (p = parent). * * If we're doing a vac -d against another archive, the * equivalent directory to fp in that archive is diffp. */ void vac(VacFile *fp, VacFile *diffp, char *name, Dir *d) { char *elem, *s; static char buf[65536]; int fd, i, n, bsize; int64_t off; Dir *dk; // kids VacDir vd, vddiff; VacFile *f, *fdiff; VtEntry e; if(!includefile(name)){ warn("excluding %s%s", name, (d->mode&DMDIR) ? "/" : ""); return; } if(d->mode&DMDIR) stats.ndir++; else stats.nfile++; if(merge && vacmerge(fp, name) >= 0) return; if(verbose) fprint(2, "%s%s\n", name, (d->mode&DMDIR) ? "/" : ""); if((fd = open(name, OREAD)) < 0){ warn("open %s: %r", name); return; } elem = strrchr(name, '/'); if(elem) elem++; else elem = name; plan9tovacdir(&vd, d); if((f = vacfilecreate(fp, elem, vd.mode)) == nil){ warn("vacfilecreate %s: %r", name); return; } if(diffp) fdiff = vacfilewalk(diffp, elem); else fdiff = nil; if(vacfilesetdir(f, &vd) < 0) warn("vacfilesetdir %s: %r", name); if(d->mode&DMDIR){ while((n = dirread(fd, &dk)) > 0){ for(i=0; i<n; i++){ s = vtmalloc(strlen(name)+1+strlen(dk[i].name)+1); strcpy(s, name); strcat(s, "/"); strcat(s, dk[i].name); vac(f, fdiff, s, &dk[i]); free(s); } free(dk); } }else{ off = 0; bsize = fs->bsize; if(fdiff){ /* * Copy fdiff's contents into f by moving the score. * We'll diff and update below. */ if(vacfilegetentries(fdiff, &e, nil) >= 0) if(vacfilesetentries(f, &e, nil) >= 0){ bsize = e.dsize; /* * Or if -q is set, and the metadata looks the same, * don't even bother reading the file. */ if(qdiff && vacfilegetdir(fdiff, &vddiff) >= 0){ if(vddiff.mtime == vd.mtime) if(vddiff.size == vd.size) if(!vddiff.plan9 || (/* vddiff.p9path == vd.p9path && */ vddiff.p9version == vd.p9version)){ stats.skipfiles++; stats.nfile--; vdcleanup(&vddiff); goto Out; } /* * Skip over presumably-unchanged prefix * of an append-only file. */ if(vd.mode&ModeAppend) if(vddiff.size < vd.size) if(vddiff.plan9 && vd.plan9) if(vddiff.p9path == vd.p9path){ off = vd.size/bsize*bsize; if(seek(fd, off, 0) >= 0) stats.skipdata += off; else{ seek(fd, 0, 0); // paranoia off = 0; } } vdcleanup(&vddiff); // XXX different verbose chatty prints for kaminsky? } } } if(qdiff && verbose) fprint(2, "+%s\n", name); while((n = readn(fd, buf, bsize)) > 0){ if(fdiff && sha1matches(f, off/bsize, (uint8_t*)buf, n)){ off += n; stats.skipdata += n; continue; } if(vacfilewrite(f, buf, n, off) < 0){ warn("venti write %s: %r", name); goto Out; } stats.data += n; off += n; } /* * Since we started with fdiff's contents, * set the size in case fdiff was bigger. */ if(fdiff && vacfilesetsize(f, off) < 0) warn("vtfilesetsize %s: %r", name); } Out: vacfileflush(f, 1); vacfiledecref(f); if(fdiff) vacfiledecref(fdiff); close(fd); }
uint textload(Text *t, uint q0, char *file, int setqid) { Rune *rp; Dirlist *dl, **dlp; int fd, i, j, n, ndl, nulls; uint q, q1; Dir *d, *dbuf; char *tmp; Text *u; if(t->ncache!=0 || t->file->nc || t->w==nil || t!=&t->w->body) error("text.load"); if(t->w->isdir && t->file->nname==0){ warning(nil, "empty directory name\n"); return 0; } fd = open(file, OREAD); if(fd < 0){ warning(nil, "can't open %s: %r\n", file); return 0; } d = dirfstat(fd); if(d == nil){ warning(nil, "can't fstat %s: %r\n", file); goto Rescue; } nulls = FALSE; if(d->qid.type & QTDIR){ /* this is checked in get() but it's possible the file changed underfoot */ if(t->file->ntext > 1){ warning(nil, "%s is a directory; can't read with multiple windows on it\n", file); goto Rescue; } t->w->isdir = TRUE; t->w->filemenu = FALSE; if(t->file->name[t->file->nname-1] != '/'){ rp = runemalloc(t->file->nname+1); runemove(rp, t->file->name, t->file->nname); rp[t->file->nname] = '/'; winsetname(t->w, rp, t->file->nname+1); free(rp); } dlp = nil; ndl = 0; dbuf = nil; while((n=dirread(fd, &dbuf)) > 0){ for(i=0; i<n; i++){ dl = emalloc(sizeof(Dirlist)); j = strlen(dbuf[i].name); tmp = emalloc(j+1+1); memmove(tmp, dbuf[i].name, j); if(dbuf[i].qid.type & QTDIR) tmp[j++] = '/'; tmp[j] = '\0'; dl->r = bytetorune(tmp, &dl->nr); dl->wid = stringwidth(t->font, tmp); free(tmp); ndl++; dlp = realloc(dlp, ndl*sizeof(Dirlist*)); dlp[ndl-1] = dl; } free(dbuf); } qsort(dlp, ndl, sizeof(Dirlist*), dircmp); t->w->dlp = dlp; t->w->ndl = ndl; textcolumnate(t, dlp, ndl); q1 = t->file->nc; }else{ t->w->isdir = FALSE; t->w->filemenu = TRUE; q1 = q0 + fileload(t->file, q0, fd, &nulls); } if(setqid){ t->file->dev = d->dev; t->file->mtime = d->mtime; t->file->qidpath = d->qid.path; } close(fd); rp = fbufalloc(); for(q=q0; q<q1; q+=n){ n = q1-q; if(n > RBUFSIZE) n = RBUFSIZE; bufread(t->file, q, rp, n); if(q < t->org) t->org += n; else if(q <= t->org+t->nchars) frinsert(t, rp, rp+n, q-t->org); if(t->lastlinefull) break; } fbuffree(rp); for(i=0; i<t->file->ntext; i++){ u = t->file->text[i]; if(u != t){ if(u->org > u->file->nc) /* will be 0 because of reset(), but safety first */ u->org = 0; textresize(u, u->all); textbacknl(u, u->org, 0); /* go to beginning of line */ } textsetselect(u, q0, q0); } if(nulls) warning(nil, "%s: NUL bytes elided\n", file); free(d); return q1-q0; Rescue: close(fd); return 0; }
static int check_dir(uint32_t ino, uint32_t parentino, const char *pathsofar) { struct sfs_inode sfi; struct sfs_dir *direntries; int *sortvector; uint32_t dirsize, ndirentries, maxdirentries, subdircount, i; int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0; diskread(&sfi, ino); swapinode(&sfi); if (remember_dir(ino, pathsofar)) { /* crosslinked dir */ return 1; } bitmap_mark(ino, B_INODE, ino); count_dirs++; if (sfi.sfi_size % sizeof(struct sfs_dir) != 0) { setbadness(EXIT_RECOV); warnx("Directory /%s has illegal size %lu (fixed)", pathsofar, (unsigned long) sfi.sfi_size); sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size, sizeof(struct sfs_dir)); ichanged = 1; } if (check_inode_blocks(ino, &sfi, 1)) { ichanged = 1; } ndirentries = sfi.sfi_size/sizeof(struct sfs_dir); maxdirentries = SFS_ROUNDUP(ndirentries, SFS_BLOCKSIZE/sizeof(struct sfs_dir)); dirsize = maxdirentries * sizeof(struct sfs_dir); direntries = domalloc(dirsize); sortvector = domalloc(ndirentries * sizeof(int)); dirread(&sfi, direntries, ndirentries); for (i=ndirentries; i<maxdirentries; i++) { direntries[i].sfd_ino = SFS_NOINO; bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name)); } for (i=0; i<ndirentries; i++) { if (check_dir_entry(pathsofar, i, &direntries[i])) { dchanged = 1; } sortvector[i] = i; } sortdir(sortvector, direntries, ndirentries); /* don't use ndirentries-1 here in case ndirentries == 0 */ for (i=0; i+1<ndirentries; i++) { struct sfs_dir *d1 = &direntries[sortvector[i]]; struct sfs_dir *d2 = &direntries[sortvector[i+1]]; assert(d1 != d2); if (d1->sfd_ino == SFS_NOINO) { continue; } if (!strcmp(d1->sfd_name, d2->sfd_name)) { if (d1->sfd_ino == d2->sfd_ino) { setbadness(EXIT_RECOV); warnx("Directory /%s: Duplicate entries for " "%s (merged)", pathsofar, d1->sfd_name); d1->sfd_ino = SFS_NOINO; d1->sfd_name[0] = 0; } else { snprintf(d1->sfd_name, sizeof(d1->sfd_name), "FSCK.%lu.%lu", (unsigned long) d1->sfd_ino, (unsigned long) uniquecounter++); setbadness(EXIT_RECOV); warnx("Directory /%s: Duplicate names %s " "(one renamed: %s)", pathsofar, d2->sfd_name, d1->sfd_name); } dchanged = 1; } } for (i=0; i<ndirentries; i++) { if (!strcmp(direntries[i].sfd_name, ".")) { if (direntries[i].sfd_ino != ino) { setbadness(EXIT_RECOV); warnx("Directory /%s: Incorrect `.' entry " "(fixed)", pathsofar); direntries[i].sfd_ino = ino; dchanged = 1; } assert(dotseen==0); /* due to duplicate checking */ dotseen = 1; } else if (!strcmp(direntries[i].sfd_name, "..")) { if (direntries[i].sfd_ino != parentino) { setbadness(EXIT_RECOV); warnx("Directory /%s: Incorrect `..' entry " "(fixed)", pathsofar); direntries[i].sfd_ino = parentino; dchanged = 1; } assert(dotdotseen==0); /* due to duplicate checking */ dotdotseen = 1; } } if (!dotseen) { if (dir_tryadd(direntries, ndirentries, ".", ino)==0) { setbadness(EXIT_RECOV); warnx("Directory /%s: No `.' entry (added)", pathsofar); dchanged = 1; } else if (dir_tryadd(direntries, maxdirentries, ".", ino)==0) { setbadness(EXIT_RECOV); warnx("Directory /%s: No `.' entry (added)", pathsofar); ndirentries++; dchanged = 1; sfi.sfi_size += sizeof(struct sfs_dir); ichanged = 1; } else { setbadness(EXIT_UNRECOV); warnx("Directory /%s: No `.' entry (NOT FIXED)", pathsofar); } } if (!dotdotseen) { if (dir_tryadd(direntries, ndirentries, "..", parentino)==0) { setbadness(EXIT_RECOV); warnx("Directory /%s: No `..' entry (added)", pathsofar); dchanged = 1; } else if (dir_tryadd(direntries, maxdirentries, "..", parentino)==0) { setbadness(EXIT_RECOV); warnx("Directory /%s: No `..' entry (added)", pathsofar); ndirentries++; dchanged = 1; sfi.sfi_size += sizeof(struct sfs_dir); ichanged = 1; } else { setbadness(EXIT_UNRECOV); warnx("Directory /%s: No `..' entry (NOT FIXED)", pathsofar); } } subdircount=0; for (i=0; i<ndirentries; i++) { if (!strcmp(direntries[i].sfd_name, ".")) { /* nothing */ } else if (!strcmp(direntries[i].sfd_name, "..")) { /* nothing */ } else if (direntries[i].sfd_ino == SFS_NOINO) { /* nothing */ } else { char path[strlen(pathsofar)+SFS_NAMELEN+1]; struct sfs_inode subsfi; diskread(&subsfi, direntries[i].sfd_ino); swapinode(&subsfi); snprintf(path, sizeof(path), "%s/%s", pathsofar, direntries[i].sfd_name); switch (subsfi.sfi_type) { case SFS_TYPE_FILE: if (check_inode_blocks(direntries[i].sfd_ino, &subsfi, 0)) { swapinode(&subsfi); diskwrite(&subsfi, direntries[i].sfd_ino); } observe_filelink(direntries[i].sfd_ino); break; case SFS_TYPE_DIR: if (check_dir(direntries[i].sfd_ino, ino, path)) { setbadness(EXIT_RECOV); warnx("Directory /%s: Crosslink to " "other directory (removed)", path); direntries[i].sfd_ino = SFS_NOINO; direntries[i].sfd_name[0] = 0; dchanged = 1; } else { subdircount++; } break; default: setbadness(EXIT_RECOV); warnx("Object /%s: Invalid inode type " "(removed)", path); direntries[i].sfd_ino = SFS_NOINO; direntries[i].sfd_name[0] = 0; dchanged = 1; break; } } } if (sfi.sfi_linkcount != subdircount+2) { setbadness(EXIT_RECOV); warnx("Directory /%s: Link count %lu should be %lu (fixed)", pathsofar, (unsigned long) sfi.sfi_linkcount, (unsigned long) subdircount+2); sfi.sfi_linkcount = subdircount+2; ichanged = 1; } if (dchanged) { dirwrite(&sfi, direntries, ndirentries); } if (ichanged) { swapinode(&sfi); diskwrite(&sfi, ino); } free(direntries); free(sortvector); return 0; }
void ckdir(uint16_t inum, uint16_t pnum, char *name) { struct dinode ino; struct direct dentry; uint16_t j; int c; int nentries; char ename[150]; iread(inum, &ino); if ((swizzle16(ino.i_mode) & F_MASK) != F_DIR) return; ++depth; if (swizzle32(ino.i_size) % 32 != 0) { printf("Directory inode %d has improper length. Fix? ", inum); if (yes()) { ino.i_size = swizzle32(swizzle32(ino.i_size) & ~0x1f); iwrite(inum, &ino); } } nentries = swizzle32(ino.i_size)/32; for (j = 0; j < nentries; ++j) { dirread(&ino, j, &dentry); #if 1 /**HP**/ { int i; for (i = 0; i < 30; ++i) if (dentry.d_name[i] == '\0') break; for ( ; i < 30; ++i) dentry.d_name[i] = '\0'; dirwrite(&ino, j, &dentry); } #endif if (dentry.d_ino == 0) continue; if (swizzle16(dentry.d_ino) < ROOTINODE || swizzle16(dentry.d_ino) >= 8 * swizzle16(superblock.s_isize)) { printf("Directory entry %s%-1.14s has out-of-range inode %u. Zap? ", name, dentry.d_name, swizzle16(dentry.d_ino)); if (yes()) { dentry.d_ino = 0; dentry.d_name[0] = '\0'; dirwrite(&ino, j, &dentry); continue; } } if (dentry.d_ino && linkmap[swizzle16(dentry.d_ino)] == -1) { printf("Directory entry %s%-1.14s points to bogus inode %u. Zap? ", name, dentry.d_name, swizzle16(dentry.d_ino)); if (yes()) { dentry.d_ino = 0; dentry.d_name[0] = '\0'; dirwrite(&ino, j, &dentry); continue; } } ++linkmap[swizzle16(dentry.d_ino)]; for (c = 0; c < 30 && dentry.d_name[c]; ++c) { if (dentry.d_name[c] == '/') { printf("Directory entry %s%-1.30s contains slash. Fix? ", name, dentry.d_name); if (yes()) { dentry.d_name[c] = 'X'; dirwrite(&ino, j, &dentry); } } } if (strncmp(dentry.d_name, ".", 30) == 0 && swizzle16(dentry.d_ino) != inum) { printf("Dot entry %s%-1.30s points to wrong place. Fix? ", name, dentry.d_name); if (yes()) { dentry.d_ino = swizzle16(inum); dirwrite(&ino, j, &dentry); } } if (strncmp(dentry.d_name, "..", 30) == 0 && swizzle16(dentry.d_ino) != pnum) { printf("DotDot entry %s%-1.30s points to wrong place. Fix? ", name, dentry.d_name); if (yes()) { dentry.d_ino = swizzle16(pnum); dirwrite(&ino, j, &dentry); } } if (swizzle16(dentry.d_ino) != pnum && swizzle16(dentry.d_ino) != inum && depth < MAXDEPTH) { strcpy(ename, name); strcat(ename, dentry.d_name); strcat(ename, "/"); ckdir(swizzle16(dentry.d_ino), inum, ename); } } --depth; }
ssize_t getdents(int fd, void* buf, size_t siz) { struct stat st; if (siz < DIRBLKSIZ) { errno = EINVAL; return(-1); } if (fstat(fd, &st)) return(-1); if (!S_ISDIR(st.st_mode)) { #ifdef ENOTDIR errno = ENOTDIR; #else errno = EBADF; #endif return(-1); } #if _lib_getdirentries { long off; return(getdirentries(fd, buf, siz, &off)); } #else #if _lib_dirread { register char* sp; /* system */ register struct dirent* up; /* user */ char* u; int n; int m; int i; m = (siz * 6) / 10; m = roundof(m, 8); sp = (char*)buf + siz - m - 1; if (!(n = dirread(fd, sp, m))) return(0); if (n > 0) { up = (struct dirent*)buf; sp[n] = 0; while (sp < (char*)buf + siz - m + n) { i = 0; while (*sp >= '0' && *sp <= '9') i = 10 * i + *sp++ - '0'; while (*sp && *sp != '\t') sp++; if (*sp++) { up->d_fileno = i; u = up->d_name; while ((*u = *sp++) && u < up->d_name + MAXNAMLEN) u++; *u = 0; up->d_reclen = sizeof(struct dirent) - sizeof(up->d_name) + (up->d_namlen = u - up->d_name) + 1; up->d_reclen = roundof(up->d_reclen, 8); up = (struct dirent*)((char*)up + up->d_reclen); } } return((char*)up - (char*)buf); } } #else #if _mem_d_reclen_direct return(read(fd, buf, siz)); #else { #define MAXREC roundof(sizeof(*up)-sizeof(up->d_name)+sizeof(sp->d_name)+1,8) register struct direct* sp; /* system */ register struct dirent* up; /* user */ register char* s; register char* u; int n; int m; char tmp[sizeof(sp->d_name) + 1]; /* * we assume sizeof(struct dirent) > sizeof(struct direct) */ up = (struct dirent*)buf; n = (siz / MAXREC) * sizeof(struct direct); if ((!(m = n & ~511) || m < MAXREC) && (!(m = n & ~255) || m < MAXREC)) m = n; do { if ((n = read(fd, (char*)buf + siz - m, m)) <= 0) break; sp = (struct direct*)((char*)buf + siz - m); while (sp < (struct direct*)((char*)buf + siz - m + n)) { if (sp->d_ino) { up->d_fileno = sp->d_ino; s = sp->d_name; u = tmp; while (s < sp->d_name + sizeof(sp->d_name) && *s) *u++ = *s++; *u = 0; strcpy(up->d_name, tmp); up->d_reclen = sizeof(struct dirent) - sizeof(up->d_name) + (up->d_namlen = u - tmp) + 1; up->d_reclen = roundof(up->d_reclen, 8); up = (struct dirent*)((char*)up + up->d_reclen); } sp++; } } while (up == (struct dirent*)buf); return((char*)up - (char*)buf); } #endif #endif #endif }