1 /* 2 * Copyright 2004-2006, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /** A simple class wrapping a path. Has a fixed-sized buffer. */ 7 8 #include <KPath.h> 9 #include <team.h> 10 #include <vfs.h> 11 12 #include <stdlib.h> 13 #include <string.h> 14 15 16 // debugging 17 #define TRACE(x) ; 18 //#define TRACE(x) dprintf x 19 20 21 KPath::KPath(size_t bufferSize) 22 : 23 fBuffer(NULL), 24 fBufferSize(0), 25 fPathLength(0), 26 fLocked(false) 27 { 28 SetTo(NULL, bufferSize); 29 } 30 31 32 KPath::KPath(const char* path, bool normalize, size_t bufferSize) 33 : 34 fBuffer(NULL), 35 fBufferSize(0), 36 fPathLength(0), 37 fLocked(false) 38 { 39 SetTo(path, normalize, bufferSize); 40 } 41 42 43 KPath::KPath(const KPath& other) 44 : 45 fBuffer(NULL), 46 fBufferSize(0), 47 fPathLength(0), 48 fLocked(false) 49 { 50 *this = other; 51 } 52 53 54 KPath::~KPath() 55 { 56 free(fBuffer); 57 } 58 59 60 status_t 61 KPath::SetTo(const char* path, bool normalize, size_t bufferSize) 62 { 63 if (bufferSize == 0) 64 bufferSize = B_PATH_NAME_LENGTH; 65 66 // free the previous buffer, if the buffer size differs 67 if (fBuffer && fBufferSize != bufferSize) { 68 free(fBuffer); 69 fBuffer = NULL; 70 fBufferSize = 0; 71 } 72 fPathLength = 0; 73 fLocked = false; 74 75 // allocate buffer 76 if (!fBuffer) 77 fBuffer = (char*)malloc(bufferSize); 78 if (!fBuffer) 79 return B_NO_MEMORY; 80 if (fBuffer) { 81 fBufferSize = bufferSize; 82 fBuffer[0] = '\0'; 83 } 84 return SetPath(path, normalize); 85 } 86 87 88 status_t 89 KPath::InitCheck() const 90 { 91 return fBuffer ? B_OK : B_NO_MEMORY; 92 } 93 94 95 status_t 96 KPath::SetPath(const char *path, bool normalize) 97 { 98 if (!fBuffer) 99 return B_NO_INIT; 100 101 if (path) { 102 if (normalize) { 103 // normalize path 104 status_t error = vfs_normalize_path(path, fBuffer, fBufferSize, 105 team_get_kernel_team_id() == team_get_current_team_id()); 106 if (error != B_OK) { 107 SetPath(NULL); 108 return error; 109 } 110 fPathLength = strlen(fBuffer); 111 } else { 112 // don't normalize path 113 size_t length = strlen(path); 114 if (length >= fBufferSize) 115 return B_BUFFER_OVERFLOW; 116 117 memcpy(fBuffer, path, length + 1); 118 fPathLength = length; 119 _ChopTrailingSlashes(); 120 } 121 } else { 122 fBuffer[0] = '\0'; 123 fPathLength = 0; 124 } 125 return B_OK; 126 } 127 128 129 const char* 130 KPath::Path() const 131 { 132 return fBuffer; 133 } 134 135 136 char * 137 KPath::LockBuffer() 138 { 139 if (!fBuffer || fLocked) 140 return NULL; 141 142 fLocked = true; 143 return fBuffer; 144 } 145 146 147 void 148 KPath::UnlockBuffer() 149 { 150 if (!fLocked) { 151 TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n")); 152 return; 153 } 154 fLocked = false; 155 fPathLength = strnlen(fBuffer, fBufferSize); 156 if (fPathLength == fBufferSize) { 157 TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n")); 158 fPathLength--; 159 fBuffer[fPathLength] = '\0'; 160 } 161 _ChopTrailingSlashes(); 162 } 163 164 165 const char * 166 KPath::Leaf() const 167 { 168 if (!fBuffer) 169 return NULL; 170 171 // only "/" has trailing slashes -- then we have to return the complete 172 // buffer, as we have to do in case there are no slashes at all 173 if (fPathLength != 1 || fBuffer[0] != '/') { 174 for (int32 i = fPathLength - 1; i >= 0; i--) { 175 if (fBuffer[i] == '/') 176 return fBuffer + i + 1; 177 } 178 } 179 return fBuffer; 180 } 181 182 183 status_t 184 KPath::ReplaceLeaf(const char *newLeaf) 185 { 186 const char *leaf = Leaf(); 187 if (!leaf) 188 return B_NO_INIT; 189 190 int32 leafIndex = leaf - fBuffer; 191 // chop off the current leaf (don't replace "/", though) 192 if (leafIndex != 0 || fBuffer[leafIndex - 1]) { 193 fBuffer[leafIndex] = '\0'; 194 fPathLength = leafIndex; 195 _ChopTrailingSlashes(); 196 } 197 198 // if a leaf was given, append it 199 if (newLeaf) 200 return Append(newLeaf); 201 return B_OK; 202 } 203 204 205 bool 206 KPath::RemoveLeaf() 207 { 208 // get the leaf -- bail out, if not initialized or only the "/" is left 209 const char *leaf = Leaf(); 210 if (!leaf || leaf == fBuffer) 211 return false; 212 213 // chop off the leaf 214 int32 leafIndex = leaf - fBuffer; 215 fBuffer[leafIndex] = '\0'; 216 fPathLength = leafIndex; 217 _ChopTrailingSlashes(); 218 219 return true; 220 } 221 222 223 status_t 224 KPath::Append(const char *component, bool isComponent) 225 { 226 // check initialization and parameter 227 if (!fBuffer) 228 return B_NO_INIT; 229 if (!component) 230 return B_BAD_VALUE; 231 if (fPathLength == 0) 232 return SetPath(component); 233 234 // get component length 235 size_t componentLength = strlen(component); 236 if (componentLength < 1) 237 return B_OK; 238 239 // if our current path is empty, we just copy the supplied one 240 // compute the result path len 241 bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/' 242 && component[0] != '/'; 243 size_t resultPathLength = fPathLength + componentLength + (insertSlash ? 1 : 0); 244 if (resultPathLength >= fBufferSize) 245 return B_BUFFER_OVERFLOW; 246 247 // compose the result path 248 if (insertSlash) 249 fBuffer[fPathLength++] = '/'; 250 memcpy(fBuffer + fPathLength, component, componentLength + 1); 251 fPathLength = resultPathLength; 252 return B_OK; 253 } 254 255 256 KPath& 257 KPath::operator=(const KPath& other) 258 { 259 SetTo(other.fBuffer, other.fBufferSize); 260 return *this; 261 } 262 263 264 KPath& 265 KPath::operator=(const char* path) 266 { 267 SetTo(path); 268 return *this; 269 } 270 271 272 bool 273 KPath::operator==(const KPath& other) const 274 { 275 if (!fBuffer) 276 return !other.fBuffer; 277 278 return (other.fBuffer 279 && fPathLength == other.fPathLength 280 && strcmp(fBuffer, other.fBuffer) == 0); 281 } 282 283 284 bool 285 KPath::operator==(const char* path) const 286 { 287 if (!fBuffer) 288 return (!path); 289 290 return path && !strcmp(fBuffer, path); 291 } 292 293 294 bool 295 KPath::operator!=(const KPath& other) const 296 { 297 return !(*this == other); 298 } 299 300 301 bool 302 KPath::operator!=(const char* path) const 303 { 304 return !(*this == path); 305 } 306 307 308 void 309 KPath::_ChopTrailingSlashes() 310 { 311 if (fBuffer) { 312 while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/') 313 fBuffer[--fPathLength] = '\0'; 314 } 315 } 316 317