aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/fossil/9dir.c
blob: fdba20d0802df323dbf7e698637af9448da7de41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#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;
}