xref: /plan9/sys/src/cmd/fossil/9dir.c (revision 9b943567965ba040fd275927fbe088656eb8ce4f)
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 	if(de->mode & ModeTemporary){
63 		dir.qid.type |= QTTMP;
64 		dir.mode |= DMTMP;
65 	}
66 
67 	dir.atime = de->atime;
68 	dir.mtime = de->mtime;
69 	dir.length = de->size;
70 
71 	dir.name = de->elem;
72 	if((dir.uid = unameByUid(de->uid)) == nil)
73 		dir.uid = smprint("(%s)", de->uid);
74 	if((dir.gid = unameByUid(de->gid)) == nil)
75 		dir.gid = smprint("(%s)", de->gid);
76 	if((dir.muid = unameByUid(de->mid)) == nil)
77 		dir.muid = smprint("(%s)", de->mid);
78 
79 	n = convD2M(&dir, p, np);
80 
81 	vtMemFree(dir.muid);
82 	vtMemFree(dir.gid);
83 	vtMemFree(dir.uid);
84 
85 	return n;
86 }
87 
88 int
89 dirRead(Fid* fid, uchar* p, int count, vlong offset)
90 {
91 	int n, nb;
92 	DirBuf *db;
93 
94 	/*
95 	 * special case of rewinding a directory
96 	 * otherwise ignore the offset
97 	 */
98 	if(offset == 0 && fid->db){
99 		dirBufFree(fid->db);
100 		fid->db = nil;
101 	}
102 
103 	if(fid->db == nil)
104 		fid->db = dirBufAlloc(fid->file);
105 
106 	db = fid->db;
107 
108 	for(nb = 0; nb < count; nb += n){
109 		if(!db->valid){
110 			n = deeRead(db->dee, &db->de);
111 			if(n < 0)
112 				return -1;
113 			if(n == 0)
114 				break;
115 			db->valid = 1;
116 		}
117 		n = dirDe2M(&db->de, p+nb, count-nb);
118 		if(n <= BIT16SZ)
119 			break;
120 		db->valid = 0;
121 		deCleanup(&db->de);
122 	}
123 
124 	return nb;
125 }
126