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 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 29 MetadataCache::~MetadataCache() 30 { 31 mutex_destroy(&fLock); 32 } 33 34 35 status_t 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 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 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 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 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 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 143 MetadataCache::UnlockValid() 144 { 145 MutexLocker _(fLock); 146 fExpire = time(NULL) + kExpirationTime; 147 fForceValid = false; 148 } 149 150 151 void 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