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
MetadataCache(Inode * inode)17 MetadataCache::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
~MetadataCache()29 MetadataCache::~MetadataCache()
30 {
31 mutex_destroy(&fLock);
32 }
33
34
35 status_t
GetStat(struct stat * st)36 MetadataCache::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
61 void
SetStat(const struct stat & st)62 MetadataCache::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
74 void
GrowFile(size_t newSize)75 MetadataCache::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
88 status_t
GetAccess(uid_t uid,uint32 * allowed)89 MetadataCache::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
112 void
SetAccess(uid_t uid,uint32 allowed)113 MetadataCache::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
129 status_t
LockValid()130 MetadataCache::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
142 void
UnlockValid()143 MetadataCache::UnlockValid()
144 {
145 MutexLocker _(fLock);
146 fExpire = time(NULL) + kExpirationTime;
147 fForceValid = false;
148 }
149
150
151 void
NotifyChanges(const struct stat * oldStat,const struct stat * newStat)152 MetadataCache::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