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