xref: /plan9/sys/src/cmd/fossil/9dir.c (revision 418f3c223ba97d6d4f967eee6f77a8629a37a7eb)
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