xref: /plan9/sys/src/cmd/fossil/9dir.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
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*
13 dirBufAlloc(File* file)
14 {
15 	DirBuf *db;
16 
17 	db = vtMemAllocZ(sizeof(DirBuf));
18 	db->dee = deeOpen(file);
19 
20 	return db;
21 }
22 
23 void
24 dirBufFree(DirBuf* db)
25 {
26 	if(db == nil)
27 		return;
28 
29 	if(db->valid)
30 		deCleanup(&db->de);
31 	deeClose(db->dee);
32 	vtMemFree(db);
33 }
34 
35 int
36 dirDe2M(DirEntry* de, uchar* p, int np)
37 {
38 	int n;
39 	Dir dir;
40 
41 	memset(&dir, 0, sizeof(Dir));
42 
43 	dir.qid.path = de->qid;
44 	dir.qid.vers = de->mcount;
45 	dir.mode = de->mode & 0777;
46 	if(de->mode & ModeAppend){
47 		dir.qid.type |= QTAPPEND;
48 		dir.mode |= DMAPPEND;
49 	}
50 	if(de->mode & ModeExclusive){
51 		dir.qid.type |= QTEXCL;
52 		dir.mode |= DMEXCL;
53 	}
54 	if(de->mode & ModeDir){
55 		dir.qid.type |= QTDIR;
56 		dir.mode |= DMDIR;
57 	}
58 	if(de->mode & ModeSnapshot){
59 		dir.qid.type |= QTMOUNT;	/* just for debugging */
60 		dir.mode |= DMMOUNT;
61 	}
62 
63 	dir.atime = de->atime;
64 	dir.mtime = de->mtime;
65 	dir.length = de->size;
66 
67 	dir.name = de->elem;
68 	if((dir.uid = unameByUid(de->uid)) == nil)
69 		dir.uid = smprint("(%s)", de->uid);
70 	if((dir.gid = unameByUid(de->gid)) == nil)
71 		dir.gid = smprint("(%s)", de->gid);
72 	if((dir.muid = unameByUid(de->mid)) == nil)
73 		dir.muid = smprint("(%s)", de->mid);
74 
75 	n = convD2M(&dir, p, np);
76 
77 	vtMemFree(dir.muid);
78 	vtMemFree(dir.gid);
79 	vtMemFree(dir.uid);
80 
81 	return n;
82 }
83 
84 int
85 dirRead(Fid* fid, uchar* p, int count, vlong offset)
86 {
87 	int n, nb;
88 	DirBuf *db;
89 
90 	/*
91 	 * special case of rewinding a directory
92 	 * otherwise ignore the offset
93 	 */
94 	if(offset == 0 && fid->db){
95 		dirBufFree(fid->db);
96 		fid->db = nil;
97 	}
98 
99 	if(fid->db == nil)
100 		fid->db = dirBufAlloc(fid->file);
101 
102 	db = fid->db;
103 
104 	for(nb = 0; nb < count; nb += n){
105 		if(!db->valid){
106 			n = deeRead(db->dee, &db->de);
107 			if(n < 0)
108 				return -1;
109 			if(n == 0)
110 				break;
111 			db->valid = 1;
112 		}
113 		n = dirDe2M(&db->de, p+nb, count-nb);
114 		if(n <= BIT16SZ)
115 			break;
116 		db->valid = 0;
117 		deCleanup(&db->de);
118 	}
119 
120 	return nb;
121 }
122