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