1/*
2 * Copyright 2012-2016 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Pawe�� Dziepak, pdziepak@quarnos.org
7 */
8
9
10#include "MetadataCache.h"
11
12#include <NodeMonitor.h>
13
14#include "Inode.h"
15
16
17MetadataCache::MetadataCache(Inode* inode)
18	:
19	fExpire(0),
20	fForceValid(false),
21	fInode(inode),
22	fInited(false)
23{
24	ASSERT(inode != NULL);
25	mutex_init(&fLock, NULL);
26}
27
28
29MetadataCache::~MetadataCache()
30{
31	mutex_destroy(&fLock);
32}
33
34
35status_t
36MetadataCache::GetStat(struct stat* st)
37{
38	ASSERT(st != NULL);
39
40	MutexLocker _(fLock);
41	if (fForceValid || fExpire > time(NULL)) {
42		// Do not touch other members of struct stat
43		st->st_size = fStatCache.st_size;
44		st->st_mode = fStatCache.st_mode;
45		st->st_nlink = fStatCache.st_nlink;
46		st->st_uid = fStatCache.st_uid;
47		st->st_gid = fStatCache.st_gid;
48		st->st_atim = fStatCache.st_atim;
49		st->st_ctim = fStatCache.st_ctim;
50		st->st_crtim = fStatCache.st_crtim;
51		st->st_mtim = fStatCache.st_mtim;
52		st->st_blksize = fStatCache.st_blksize;
53		st->st_blocks = fStatCache.st_blocks;
54		return B_OK;
55	}
56
57	return B_ERROR;
58}
59
60
61void
62MetadataCache::SetStat(const struct stat& st)
63{
64	MutexLocker _(fLock);
65	if (fInited)
66		NotifyChanges(&fStatCache, &st);
67
68	fStatCache = st;
69	fExpire = time(NULL) + kExpirationTime;
70	fInited = true;
71}
72
73
74void
75MetadataCache::GrowFile(size_t newSize)
76{
77	MutexLocker _(fLock);
78	off_t oldSize = fStatCache.st_size;
79	fStatCache.st_size = max_c((off_t)newSize, fStatCache.st_size);
80
81	if (oldSize != fStatCache.st_size) {
82		notify_stat_changed(fInode->GetFileSystem()->DevId(), -1, fInode->ID(),
83			B_STAT_SIZE);
84	}
85}
86
87
88status_t
89MetadataCache::GetAccess(uid_t uid, uint32* allowed)
90{
91	ASSERT(allowed != NULL);
92
93	MutexLocker _(fLock);
94	AVLTreeMap<uid_t, AccessEntry>::Iterator it = fAccessCache.Find(uid);
95	if (!it.HasCurrent())
96		return B_ENTRY_NOT_FOUND;
97
98	if (!fForceValid)
99		it.CurrentValuePointer()->fForceValid = false;
100
101	if (!it.Current().fForceValid && it.Current().fExpire < time(NULL)) {
102		it.Remove();
103		return B_ERROR;
104	}
105
106	*allowed = it.Current().fAllowed;
107
108	return B_OK;
109}
110
111
112void
113MetadataCache::SetAccess(uid_t uid, uint32 allowed)
114{
115	MutexLocker _(fLock);
116	AVLTreeMap<uid_t, AccessEntry>::Iterator it = fAccessCache.Find(uid);
117	if (it.HasCurrent())
118		it.Remove();
119
120	AccessEntry entry;
121	entry.fAllowed = allowed;
122	entry.fExpire = time(NULL) + kExpirationTime;
123	entry.fForceValid = fForceValid;
124
125	fAccessCache.Insert(uid, entry);
126}
127
128
129status_t
130MetadataCache::LockValid()
131{
132	MutexLocker _(fLock);
133	if (fForceValid || fExpire > time(NULL)) {
134		fForceValid = true;
135		return B_OK;
136	}
137
138	return B_ERROR;
139}
140
141
142void
143MetadataCache::UnlockValid()
144{
145	MutexLocker _(fLock);
146	fExpire = time(NULL) + kExpirationTime;
147	fForceValid = false;
148}
149
150
151void
152MetadataCache::NotifyChanges(const struct stat* oldStat,
153	const struct stat* newStat)
154{
155	ASSERT(oldStat != NULL);
156	ASSERT(newStat != NULL);
157
158	uint32 flags = 0;
159	if (oldStat->st_size != newStat->st_size)
160		flags |= B_STAT_SIZE;
161	if (oldStat->st_mode != newStat->st_mode)
162		flags |= B_STAT_MODE;
163	if (oldStat->st_uid != newStat->st_uid)
164		flags |= B_STAT_UID;
165	if (oldStat->st_gid != newStat->st_gid)
166		flags |= B_STAT_GID;
167
168	if (memcmp(&oldStat->st_atim, &newStat->st_atim,
169		sizeof(struct timespec)) == 0)
170		flags |= B_STAT_ACCESS_TIME;
171
172	if (memcmp(&oldStat->st_ctim, &newStat->st_ctim,
173		sizeof(struct timespec)) == 0)
174		flags |= B_STAT_CHANGE_TIME;
175
176	if (memcmp(&oldStat->st_crtim, &newStat->st_crtim,
177		sizeof(struct timespec)) == 0)
178		flags |= B_STAT_CREATION_TIME;
179
180	if (memcmp(&oldStat->st_mtim, &newStat->st_mtim,
181		sizeof(struct timespec)) == 0)
182		flags |= B_STAT_MODIFICATION_TIME;
183
184	notify_stat_changed(fInode->GetFileSystem()->DevId(), -1, fInode->ID(),
185		flags);
186}
187
188