1 #include "stdinc.h"
2
3 #include "9.h"
4
5 /* one entry buffer for reading directories */
6 struct DirBuf {
7 DirEntryEnum* dee;
8 int valid;
9 DirEntry de;
10 };
11
12 static DirBuf*
dirBufAlloc(File * file)13 dirBufAlloc(File* file)
14 {
15 DirBuf *db;
16
17 db = vtMemAllocZ(sizeof(DirBuf));
18 db->dee = deeOpen(file);
19 if(db->dee == nil){
20 /* can happen if dir is removed from under us */
21 vtMemFree(db);
22 return nil;
23 }
24 return db;
25 }
26
27 void
dirBufFree(DirBuf * db)28 dirBufFree(DirBuf* db)
29 {
30 if(db == nil)
31 return;
32
33 if(db->valid)
34 deCleanup(&db->de);
35 deeClose(db->dee);
36 vtMemFree(db);
37 }
38
39 int
dirDe2M(DirEntry * de,uchar * p,int np)40 dirDe2M(DirEntry* de, uchar* p, int np)
41 {
42 int n;
43 Dir dir;
44
45 memset(&dir, 0, sizeof(Dir));
46
47 dir.qid.path = de->qid;
48 dir.qid.vers = de->mcount;
49 dir.mode = de->mode & 0777;
50 if(de->mode & ModeAppend){
51 dir.qid.type |= QTAPPEND;
52 dir.mode |= DMAPPEND;
53 }
54 if(de->mode & ModeExclusive){
55 dir.qid.type |= QTEXCL;
56 dir.mode |= DMEXCL;
57 }
58 if(de->mode & ModeDir){
59 dir.qid.type |= QTDIR;
60 dir.mode |= DMDIR;
61 }
62 if(de->mode & ModeSnapshot){
63 dir.qid.type |= QTMOUNT; /* just for debugging */
64 dir.mode |= DMMOUNT;
65 }
66 if(de->mode & ModeTemporary){
67 dir.qid.type |= QTTMP;
68 dir.mode |= DMTMP;
69 }
70
71 dir.atime = de->atime;
72 dir.mtime = de->mtime;
73 dir.length = de->size;
74
75 dir.name = de->elem;
76 if((dir.uid = unameByUid(de->uid)) == nil)
77 dir.uid = smprint("(%s)", de->uid);
78 if((dir.gid = unameByUid(de->gid)) == nil)
79 dir.gid = smprint("(%s)", de->gid);
80 if((dir.muid = unameByUid(de->mid)) == nil)
81 dir.muid = smprint("(%s)", de->mid);
82
83 n = convD2M(&dir, p, np);
84
85 vtMemFree(dir.muid);
86 vtMemFree(dir.gid);
87 vtMemFree(dir.uid);
88
89 return n;
90 }
91
92 int
dirRead(Fid * fid,uchar * p,int count,vlong offset)93 dirRead(Fid* fid, uchar* p, int count, vlong offset)
94 {
95 int n, nb;
96 DirBuf *db;
97
98 /*
99 * special case of rewinding a directory
100 * otherwise ignore the offset
101 */
102 if(offset == 0 && fid->db){
103 dirBufFree(fid->db);
104 fid->db = nil;
105 }
106
107 if(fid->db == nil){
108 fid->db = dirBufAlloc(fid->file);
109 if(fid->db == nil)
110 return -1;
111 }
112
113 db = fid->db;
114
115 for(nb = 0; nb < count; nb += n){
116 if(!db->valid){
117 n = deeRead(db->dee, &db->de);
118 if(n < 0)
119 return -1;
120 if(n == 0)
121 break;
122 db->valid = 1;
123 }
124 n = dirDe2M(&db->de, p+nb, count-nb);
125 if(n <= BIT16SZ)
126 break;
127 db->valid = 0;
128 deCleanup(&db->de);
129 }
130
131 return nb;
132 }
133