1 /* 2 * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. 3 * This file may be used under the terms of the MIT License. 4 */ 5 6 //! connection between pure inode and kernel_interface attributes 7 8 9 #include "Attribute.h" 10 11 12 // ToDo: clean this up, find a better separation between Inode and this class 13 // ToDo: even after Create(), the attribute cannot be stat() for until the first write 14 15 16 extern void fill_stat_buffer(Inode *inode, struct stat &stat); 17 18 19 Attribute::Attribute(Inode *inode) 20 : 21 fNodeGetter(inode->GetVolume()), 22 fInode(inode), 23 fSmall(NULL), 24 fAttribute(NULL), 25 fName(NULL) 26 { 27 } 28 29 30 Attribute::Attribute(Inode *inode, attr_cookie *cookie) 31 : 32 fNodeGetter(inode->GetVolume()), 33 fInode(inode), 34 fSmall(NULL), 35 fAttribute(NULL), 36 fName(NULL) 37 { 38 Get(cookie->name); 39 } 40 41 42 Attribute::~Attribute() 43 { 44 Put(); 45 } 46 47 48 status_t 49 Attribute::InitCheck() 50 { 51 return (fSmall != NULL || fAttribute != NULL) ? B_OK : B_NO_INIT; 52 } 53 54 55 status_t 56 Attribute::CheckAccess(const char *name, int openMode) 57 { 58 // Opening the name attribute using this function is not allowed, 59 // also using the reserved indices name, last_modified, and size 60 // shouldn't be allowed. 61 // ToDo: we might think about allowing to update those values, but 62 // really change their corresponding values in the bfs_inode structure 63 if (name[0] == FILE_NAME_NAME && name[1] == '\0' 64 || !strcmp(name, "name") 65 || !strcmp(name, "last_modified") 66 || !strcmp(name, "size")) 67 RETURN_ERROR(B_NOT_ALLOWED); 68 69 return fInode->CheckPermissions(openModeToAccess(openMode) 70 | (openMode & O_TRUNC ? W_OK : 0)); 71 } 72 73 74 status_t 75 Attribute::Get(const char *name) 76 { 77 Put(); 78 79 fName = name; 80 81 // try to find it in the small data region 82 if (fInode->SmallDataLock().Lock() == B_OK) { 83 fNodeGetter.SetToNode(fInode); 84 fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char *)name); 85 if (fSmall != NULL) 86 return B_OK; 87 88 fInode->SmallDataLock().Unlock(); 89 fNodeGetter.Unset(); 90 } 91 92 // then, search in the attribute directory 93 return fInode->GetAttribute(name, &fAttribute); 94 } 95 96 97 void 98 Attribute::Put() 99 { 100 if (fSmall != NULL) { 101 fInode->SmallDataLock().Unlock(); 102 fNodeGetter.Unset(); 103 fSmall = NULL; 104 } 105 106 if (fAttribute != NULL) { 107 fInode->ReleaseAttribute(fAttribute); 108 fAttribute = NULL; 109 } 110 } 111 112 113 status_t 114 Attribute::Create(const char *name, type_code type, int openMode, attr_cookie **_cookie) 115 { 116 status_t status = CheckAccess(name, openMode); 117 if (status < B_OK) 118 return status; 119 120 attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie)); 121 if (cookie == NULL) 122 RETURN_ERROR(B_NO_MEMORY); 123 124 fName = name; 125 126 // initialize the cookie 127 strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH); 128 cookie->type = type; 129 cookie->open_mode = openMode; 130 cookie->create = true; 131 132 if (Get(name) == B_OK) { 133 // attribute already exists 134 if ((openMode & O_TRUNC) != 0) 135 _Truncate(); 136 } 137 *_cookie = cookie; 138 return B_OK; 139 } 140 141 142 status_t 143 Attribute::Open(const char *name, int openMode, attr_cookie **_cookie) 144 { 145 status_t status = CheckAccess(name, openMode); 146 if (status < B_OK) 147 return status; 148 149 status = Get(name); 150 if (status < B_OK) 151 return status; 152 153 attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie)); 154 if (cookie == NULL) 155 RETURN_ERROR(B_NO_MEMORY); 156 157 // initialize the cookie 158 strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH); 159 cookie->open_mode = openMode; 160 cookie->create = false; 161 162 // Should we truncate the attribute? 163 if ((openMode & O_TRUNC) != 0) 164 _Truncate(); 165 166 *_cookie = cookie; 167 return B_OK; 168 } 169 170 171 status_t 172 Attribute::Stat(struct stat &stat) 173 { 174 if (fSmall == NULL && fAttribute == NULL) 175 return B_NO_INIT; 176 177 if (fSmall != NULL) { 178 fill_stat_buffer(fInode, stat); 179 180 // overwrite some data to suit our needs 181 stat.st_type = fSmall->Type(); 182 stat.st_size = fSmall->DataSize(); 183 } 184 185 if (fAttribute != NULL) 186 fill_stat_buffer(fAttribute, stat); 187 188 return B_OK; 189 } 190 191 192 status_t 193 Attribute::Read(attr_cookie *cookie, off_t pos, uint8 *buffer, size_t *_length) 194 { 195 if (fSmall == NULL && fAttribute == NULL) 196 return B_NO_INIT; 197 198 // ToDo: move small_data logic from Inode::ReadAttribute() over to here! 199 return fInode->ReadAttribute(cookie->name, 0, pos, buffer, _length); 200 } 201 202 203 status_t 204 Attribute::Write(Transaction &transaction, attr_cookie *cookie, 205 off_t pos, const uint8 *buffer, size_t *_length) 206 { 207 if (!cookie->create && fSmall == NULL && fAttribute == NULL) 208 return B_NO_INIT; 209 210 return fInode->WriteAttribute(transaction, cookie->name, cookie->type, 211 pos, buffer, _length); 212 } 213 214 215 status_t 216 Attribute::_Truncate() 217 { 218 if (fSmall != NULL) { 219 // TODO: as long as Inode::_AddSmallData() works like it does, 220 // we've got nothing to do here 221 return B_OK; 222 } 223 224 if (fAttribute != NULL) { 225 WriteLocked locked(fAttribute->Lock()); 226 Transaction transaction(fAttribute->GetVolume(), fAttribute->BlockNumber()); 227 228 status_t status = fAttribute->SetFileSize(transaction, 0); 229 if (status >= B_OK) 230 status = fAttribute->WriteBack(transaction); 231 232 if (status < B_OK) 233 return status; 234 235 transaction.Done(); 236 } 237 238 return B_OK; 239 } 240 241