| #include "stdinc.h" |
| |
| #include "9.h" |
| |
| /* one entry buffer for reading directories */ |
| struct DirBuf { |
| DirEntryEnum* dee; |
| int valid; |
| DirEntry de; |
| }; |
| |
| static DirBuf* |
| dirBufAlloc(File* file) |
| { |
| DirBuf *db; |
| |
| db = vtmallocz(sizeof(DirBuf)); |
| db->dee = deeOpen(file); |
| if(db->dee == nil){ |
| /* can happen if dir is removed from under us */ |
| vtfree(db); |
| return nil; |
| } |
| return db; |
| } |
| |
| void |
| dirBufFree(DirBuf* db) |
| { |
| if(db == nil) |
| return; |
| |
| if(db->valid) |
| deCleanup(&db->de); |
| deeClose(db->dee); |
| vtfree(db); |
| } |
| |
| int |
| dirDe2M(DirEntry* de, uchar* p, int np) |
| { |
| int n; |
| Dir dir; |
| |
| memset(&dir, 0, sizeof(Dir)); |
| |
| dir.qid.path = de->qid; |
| dir.qid.vers = de->mcount; |
| dir.mode = de->mode & 0777; |
| if(de->mode & ModeAppend){ |
| dir.qid.type |= QTAPPEND; |
| dir.mode |= DMAPPEND; |
| } |
| if(de->mode & ModeExclusive){ |
| dir.qid.type |= QTEXCL; |
| dir.mode |= DMEXCL; |
| } |
| if(de->mode & ModeDir){ |
| dir.qid.type |= QTDIR; |
| dir.mode |= DMDIR; |
| } |
| if(de->mode & ModeSnapshot){ |
| dir.qid.type |= QTMOUNT; /* just for debugging */ |
| dir.mode |= DMMOUNT; |
| } |
| if(de->mode & ModeTemporary){ |
| dir.qid.type |= QTTMP; |
| dir.mode |= DMTMP; |
| } |
| |
| dir.atime = de->atime; |
| dir.mtime = de->mtime; |
| dir.length = de->size; |
| |
| dir.name = de->elem; |
| if((dir.uid = unameByUid(de->uid)) == nil) |
| dir.uid = smprint("(%s)", de->uid); |
| if((dir.gid = unameByUid(de->gid)) == nil) |
| dir.gid = smprint("(%s)", de->gid); |
| if((dir.muid = unameByUid(de->mid)) == nil) |
| dir.muid = smprint("(%s)", de->mid); |
| |
| n = convD2M(&dir, p, np); |
| |
| vtfree(dir.muid); |
| vtfree(dir.gid); |
| vtfree(dir.uid); |
| |
| return n; |
| } |
| |
| int |
| dirRead(Fid* fid, uchar* p, int count, vlong offset) |
| { |
| int n, nb; |
| DirBuf *db; |
| |
| /* |
| * special case of rewinding a directory |
| * otherwise ignore the offset |
| */ |
| if(offset == 0 && fid->db){ |
| dirBufFree(fid->db); |
| fid->db = nil; |
| } |
| |
| if(fid->db == nil){ |
| fid->db = dirBufAlloc(fid->file); |
| if(fid->db == nil) |
| return -1; |
| } |
| |
| db = fid->db; |
| |
| for(nb = 0; nb < count; nb += n){ |
| if(!db->valid){ |
| n = deeRead(db->dee, &db->de); |
| if(n < 0) |
| return -1; |
| if(n == 0) |
| break; |
| db->valid = 1; |
| } |
| n = dirDe2M(&db->de, p+nb, count-nb); |
| if(n <= BIT16SZ) |
| break; |
| db->valid = 0; |
| deCleanup(&db->de); |
| } |
| |
| return nb; |
| } |