10d4c16e0SAxel Dörfler /* 2e8d3eff9SIngo Weinhold * Copyright 2004-2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3e1b4aed0SAxel Dörfler * Copyright 2008-2017, Axel Dörfler, axeld@pinc-software.de. 40d4c16e0SAxel Dörfler * Distributed under the terms of the MIT License. 50d4c16e0SAxel Dörfler */ 62d690920SAxel Dörfler 73582d4feSAxel Dörfler 83582d4feSAxel Dörfler /*! A simple class wrapping a path. Has a fixed-sized buffer. */ 93582d4feSAxel Dörfler 102d690920SAxel Dörfler 1123a60f42SAxel Dörfler #include <fs/KPath.h> 122d690920SAxel Dörfler 130d4c16e0SAxel Dörfler #include <stdlib.h> 140d4c16e0SAxel Dörfler #include <string.h> 152d690920SAxel Dörfler 1623a60f42SAxel Dörfler #include <team.h> 1723a60f42SAxel Dörfler #include <vfs.h> 1823a60f42SAxel Dörfler 190d4c16e0SAxel Dörfler 200d4c16e0SAxel Dörfler // debugging 210d4c16e0SAxel Dörfler #define TRACE(x) ; 220d4c16e0SAxel Dörfler //#define TRACE(x) dprintf x 230d4c16e0SAxel Dörfler 240d4c16e0SAxel Dörfler 250d4c16e0SAxel Dörfler KPath::KPath(size_t bufferSize) 260d4c16e0SAxel Dörfler : 270d4c16e0SAxel Dörfler fBuffer(NULL), 282d690920SAxel Dörfler fBufferSize(0), 292d690920SAxel Dörfler fPathLength(0), 302d690920SAxel Dörfler fLocked(false) 312d690920SAxel Dörfler { 32*eac83fb3SAxel Dörfler SetTo(NULL, KPath::DEFAULT, bufferSize); 332d690920SAxel Dörfler } 342d690920SAxel Dörfler 350d4c16e0SAxel Dörfler 36*eac83fb3SAxel Dörfler KPath::KPath(const char* path, int32 flags, size_t bufferSize) 370d4c16e0SAxel Dörfler : 380d4c16e0SAxel Dörfler fBuffer(NULL), 392d690920SAxel Dörfler fBufferSize(0), 402d690920SAxel Dörfler fPathLength(0), 412d690920SAxel Dörfler fLocked(false) 422d690920SAxel Dörfler { 43*eac83fb3SAxel Dörfler SetTo(path, flags, bufferSize); 442d690920SAxel Dörfler } 452d690920SAxel Dörfler 460d4c16e0SAxel Dörfler 472d690920SAxel Dörfler KPath::KPath(const KPath& other) 480d4c16e0SAxel Dörfler : 490d4c16e0SAxel Dörfler fBuffer(NULL), 502d690920SAxel Dörfler fBufferSize(0), 512d690920SAxel Dörfler fPathLength(0), 522d690920SAxel Dörfler fLocked(false) 532d690920SAxel Dörfler { 542d690920SAxel Dörfler *this = other; 552d690920SAxel Dörfler } 562d690920SAxel Dörfler 570d4c16e0SAxel Dörfler 582d690920SAxel Dörfler KPath::~KPath() 592d690920SAxel Dörfler { 602d690920SAxel Dörfler free(fBuffer); 612d690920SAxel Dörfler } 622d690920SAxel Dörfler 630d4c16e0SAxel Dörfler 642d690920SAxel Dörfler status_t 65*eac83fb3SAxel Dörfler KPath::SetTo(const char* path, int32 flags, size_t bufferSize) 662d690920SAxel Dörfler { 670d4c16e0SAxel Dörfler if (bufferSize == 0) 682d690920SAxel Dörfler bufferSize = B_PATH_NAME_LENGTH; 690d4c16e0SAxel Dörfler 702d690920SAxel Dörfler // free the previous buffer, if the buffer size differs 713582d4feSAxel Dörfler if (fBuffer != NULL && fBufferSize != bufferSize) { 722d690920SAxel Dörfler free(fBuffer); 732d690920SAxel Dörfler fBuffer = NULL; 742d690920SAxel Dörfler fBufferSize = 0; 752d690920SAxel Dörfler } 762d690920SAxel Dörfler fPathLength = 0; 772d690920SAxel Dörfler fLocked = false; 780d4c16e0SAxel Dörfler 792d690920SAxel Dörfler // allocate buffer 803582d4feSAxel Dörfler if (fBuffer == NULL) 812d690920SAxel Dörfler fBuffer = (char*)malloc(bufferSize); 823582d4feSAxel Dörfler if (fBuffer == NULL) 832d690920SAxel Dörfler return B_NO_MEMORY; 843582d4feSAxel Dörfler 852d690920SAxel Dörfler fBufferSize = bufferSize; 862d690920SAxel Dörfler fBuffer[0] = '\0'; 873582d4feSAxel Dörfler 88*eac83fb3SAxel Dörfler return SetPath(path, flags); 892d690920SAxel Dörfler } 902d690920SAxel Dörfler 910d4c16e0SAxel Dörfler 9256bbbbc9SAxel Dörfler void 9356bbbbc9SAxel Dörfler KPath::Adopt(KPath& other) 9456bbbbc9SAxel Dörfler { 9556bbbbc9SAxel Dörfler free(fBuffer); 9656bbbbc9SAxel Dörfler 9756bbbbc9SAxel Dörfler fBuffer = other.fBuffer; 9856bbbbc9SAxel Dörfler fBufferSize = other.fBufferSize; 9956bbbbc9SAxel Dörfler 10056bbbbc9SAxel Dörfler other.fBuffer = NULL; 1014be51875SAxel Dörfler other.fBufferSize = 0; 1024be51875SAxel Dörfler other.fPathLength = 0; 10356bbbbc9SAxel Dörfler } 10456bbbbc9SAxel Dörfler 10556bbbbc9SAxel Dörfler 1062d690920SAxel Dörfler status_t 1072d690920SAxel Dörfler KPath::InitCheck() const 1082d690920SAxel Dörfler { 109e1b4aed0SAxel Dörfler return fBuffer != NULL ? B_OK : B_NO_MEMORY; 1102d690920SAxel Dörfler } 1112d690920SAxel Dörfler 1120d4c16e0SAxel Dörfler 1132d690920SAxel Dörfler status_t 114*eac83fb3SAxel Dörfler KPath::SetPath(const char* path, int32 flags) 1152d690920SAxel Dörfler { 1169abf4591Sczeidler if (fBuffer == NULL) 1172d690920SAxel Dörfler return B_NO_INIT; 1180d4c16e0SAxel Dörfler 1199abf4591Sczeidler if (path != NULL) { 120*eac83fb3SAxel Dörfler if ((flags & NORMALIZE) != 0) { 1212d690920SAxel Dörfler // normalize path 1222d690920SAxel Dörfler status_t error = vfs_normalize_path(path, fBuffer, fBufferSize, 123*eac83fb3SAxel Dörfler (flags & TRAVERSE_LEAF_LINK) != 0, 1242d690920SAxel Dörfler team_get_kernel_team_id() == team_get_current_team_id()); 1252d690920SAxel Dörfler if (error != B_OK) { 1262d690920SAxel Dörfler SetPath(NULL); 1272d690920SAxel Dörfler return error; 1282d690920SAxel Dörfler } 1292d690920SAxel Dörfler fPathLength = strlen(fBuffer); 1302d690920SAxel Dörfler } else { 1312d690920SAxel Dörfler // don't normalize path 1320d4c16e0SAxel Dörfler size_t length = strlen(path); 1330d4c16e0SAxel Dörfler if (length >= fBufferSize) 1342d690920SAxel Dörfler return B_BUFFER_OVERFLOW; 1350d4c16e0SAxel Dörfler 1360d4c16e0SAxel Dörfler memcpy(fBuffer, path, length + 1); 1370d4c16e0SAxel Dörfler fPathLength = length; 1382d690920SAxel Dörfler _ChopTrailingSlashes(); 1392d690920SAxel Dörfler } 1402d690920SAxel Dörfler } else { 1412d690920SAxel Dörfler fBuffer[0] = '\0'; 1422d690920SAxel Dörfler fPathLength = 0; 1432d690920SAxel Dörfler } 1442d690920SAxel Dörfler return B_OK; 1452d690920SAxel Dörfler } 1462d690920SAxel Dörfler 1470d4c16e0SAxel Dörfler 1482d690920SAxel Dörfler const char* 1492d690920SAxel Dörfler KPath::Path() const 1502d690920SAxel Dörfler { 1512d690920SAxel Dörfler return fBuffer; 1522d690920SAxel Dörfler } 1532d690920SAxel Dörfler 1542d690920SAxel Dörfler 1552d690920SAxel Dörfler char* 1562d690920SAxel Dörfler KPath::LockBuffer() 1572d690920SAxel Dörfler { 1589abf4591Sczeidler if (fBuffer == NULL || fLocked) 1592d690920SAxel Dörfler return NULL; 1600d4c16e0SAxel Dörfler 1612d690920SAxel Dörfler fLocked = true; 1622d690920SAxel Dörfler return fBuffer; 1632d690920SAxel Dörfler } 1642d690920SAxel Dörfler 1650d4c16e0SAxel Dörfler 1662d690920SAxel Dörfler void 1672d690920SAxel Dörfler KPath::UnlockBuffer() 1682d690920SAxel Dörfler { 1692d690920SAxel Dörfler if (!fLocked) { 1700d4c16e0SAxel Dörfler TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n")); 1712d690920SAxel Dörfler return; 1722d690920SAxel Dörfler } 1732d690920SAxel Dörfler fLocked = false; 1742d690920SAxel Dörfler fPathLength = strnlen(fBuffer, fBufferSize); 1752d690920SAxel Dörfler if (fPathLength == fBufferSize) { 1760d4c16e0SAxel Dörfler TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n")); 1772d690920SAxel Dörfler fPathLength--; 1782d690920SAxel Dörfler fBuffer[fPathLength] = '\0'; 1792d690920SAxel Dörfler } 1802d690920SAxel Dörfler _ChopTrailingSlashes(); 1812d690920SAxel Dörfler } 1822d690920SAxel Dörfler 1830d4c16e0SAxel Dörfler 184e8d3eff9SIngo Weinhold char* 185e8d3eff9SIngo Weinhold KPath::DetachBuffer() 186e8d3eff9SIngo Weinhold { 187e8d3eff9SIngo Weinhold char* buffer = fBuffer; 188e8d3eff9SIngo Weinhold 189e8d3eff9SIngo Weinhold if (fBuffer != NULL) { 190e8d3eff9SIngo Weinhold fBuffer = NULL; 191e8d3eff9SIngo Weinhold fBufferSize = 0; 192e8d3eff9SIngo Weinhold fPathLength = 0; 193e8d3eff9SIngo Weinhold fLocked = false; 194e8d3eff9SIngo Weinhold } 195e8d3eff9SIngo Weinhold 196e8d3eff9SIngo Weinhold return buffer; 197e8d3eff9SIngo Weinhold } 198e8d3eff9SIngo Weinhold 199e8d3eff9SIngo Weinhold 2002d690920SAxel Dörfler const char* 2012d690920SAxel Dörfler KPath::Leaf() const 2022d690920SAxel Dörfler { 2033582d4feSAxel Dörfler if (fBuffer == NULL) 2042d690920SAxel Dörfler return NULL; 2050d4c16e0SAxel Dörfler 2062d690920SAxel Dörfler for (int32 i = fPathLength - 1; i >= 0; i--) { 2072d690920SAxel Dörfler if (fBuffer[i] == '/') 2082d690920SAxel Dörfler return fBuffer + i + 1; 2092d690920SAxel Dörfler } 210e1b4aed0SAxel Dörfler 2112d690920SAxel Dörfler return fBuffer; 2122d690920SAxel Dörfler } 2132d690920SAxel Dörfler 2140d4c16e0SAxel Dörfler 2152d690920SAxel Dörfler status_t 2162d690920SAxel Dörfler KPath::ReplaceLeaf(const char* newLeaf) 2172d690920SAxel Dörfler { 2182d690920SAxel Dörfler const char* leaf = Leaf(); 2193582d4feSAxel Dörfler if (leaf == NULL) 2202d690920SAxel Dörfler return B_NO_INIT; 2210d4c16e0SAxel Dörfler 2222d690920SAxel Dörfler int32 leafIndex = leaf - fBuffer; 2232d690920SAxel Dörfler // chop off the current leaf (don't replace "/", though) 2242d690920SAxel Dörfler if (leafIndex != 0 || fBuffer[leafIndex - 1]) { 2252d690920SAxel Dörfler fBuffer[leafIndex] = '\0'; 2262d690920SAxel Dörfler fPathLength = leafIndex; 2272d690920SAxel Dörfler _ChopTrailingSlashes(); 2282d690920SAxel Dörfler } 2290d4c16e0SAxel Dörfler 2302d690920SAxel Dörfler // if a leaf was given, append it 2313582d4feSAxel Dörfler if (newLeaf != NULL) 2322d690920SAxel Dörfler return Append(newLeaf); 2332d690920SAxel Dörfler return B_OK; 2342d690920SAxel Dörfler } 2352d690920SAxel Dörfler 2360d4c16e0SAxel Dörfler 2373532662eSIngo Weinhold bool 2383532662eSIngo Weinhold KPath::RemoveLeaf() 2393532662eSIngo Weinhold { 2403532662eSIngo Weinhold // get the leaf -- bail out, if not initialized or only the "/" is left 2413532662eSIngo Weinhold const char* leaf = Leaf(); 242e1b4aed0SAxel Dörfler if (leaf == NULL || leaf == fBuffer || leaf[0] == '\0') 2433532662eSIngo Weinhold return false; 2443532662eSIngo Weinhold 2453532662eSIngo Weinhold // chop off the leaf 2463532662eSIngo Weinhold int32 leafIndex = leaf - fBuffer; 2473532662eSIngo Weinhold fBuffer[leafIndex] = '\0'; 2483532662eSIngo Weinhold fPathLength = leafIndex; 2493532662eSIngo Weinhold _ChopTrailingSlashes(); 2503532662eSIngo Weinhold 2513532662eSIngo Weinhold return true; 2523532662eSIngo Weinhold } 2533532662eSIngo Weinhold 2543532662eSIngo Weinhold 2552d690920SAxel Dörfler status_t 2562d690920SAxel Dörfler KPath::Append(const char* component, bool isComponent) 2572d690920SAxel Dörfler { 2582d690920SAxel Dörfler // check initialization and parameter 2599abf4591Sczeidler if (fBuffer == NULL) 2602d690920SAxel Dörfler return B_NO_INIT; 2619abf4591Sczeidler if (component == NULL) 2622d690920SAxel Dörfler return B_BAD_VALUE; 2632d690920SAxel Dörfler if (fPathLength == 0) 2642d690920SAxel Dörfler return SetPath(component); 2650d4c16e0SAxel Dörfler 2662d690920SAxel Dörfler // get component length 2670d4c16e0SAxel Dörfler size_t componentLength = strlen(component); 2680d4c16e0SAxel Dörfler if (componentLength < 1) 2692d690920SAxel Dörfler return B_OK; 2700d4c16e0SAxel Dörfler 2712d690920SAxel Dörfler // if our current path is empty, we just copy the supplied one 2722d690920SAxel Dörfler // compute the result path len 2732d690920SAxel Dörfler bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/' 2742d690920SAxel Dörfler && component[0] != '/'; 275ea26d9f0SStephan Aßmus size_t resultPathLength = fPathLength + componentLength 276ea26d9f0SStephan Aßmus + (insertSlash ? 1 : 0); 2770d4c16e0SAxel Dörfler if (resultPathLength >= fBufferSize) 2782d690920SAxel Dörfler return B_BUFFER_OVERFLOW; 2790d4c16e0SAxel Dörfler 2802d690920SAxel Dörfler // compose the result path 2812d690920SAxel Dörfler if (insertSlash) 2822d690920SAxel Dörfler fBuffer[fPathLength++] = '/'; 2830d4c16e0SAxel Dörfler memcpy(fBuffer + fPathLength, component, componentLength + 1); 2840d4c16e0SAxel Dörfler fPathLength = resultPathLength; 2852d690920SAxel Dörfler return B_OK; 2862d690920SAxel Dörfler } 2872d690920SAxel Dörfler 2880d4c16e0SAxel Dörfler 289e8d3eff9SIngo Weinhold status_t 290e8d3eff9SIngo Weinhold KPath::Normalize(bool traverseLeafLink) 291e8d3eff9SIngo Weinhold { 292e8d3eff9SIngo Weinhold if (fBuffer == NULL) 293e8d3eff9SIngo Weinhold return B_NO_INIT; 294e8d3eff9SIngo Weinhold if (fPathLength == 0) 295e8d3eff9SIngo Weinhold return B_BAD_VALUE; 296e8d3eff9SIngo Weinhold 297bd5bd2c6SIngo Weinhold status_t error = vfs_normalize_path(fBuffer, fBuffer, fBufferSize, 298bd5bd2c6SIngo Weinhold traverseLeafLink, 299e8d3eff9SIngo Weinhold team_get_kernel_team_id() == team_get_current_team_id()); 300bd5bd2c6SIngo Weinhold if (error != B_OK) { 301bd5bd2c6SIngo Weinhold // vfs_normalize_path() might have screwed up the previous path -- unset 302bd5bd2c6SIngo Weinhold // it completely to avoid weird problems. 303bd5bd2c6SIngo Weinhold fBuffer[0] = '\0'; 304bd5bd2c6SIngo Weinhold fPathLength = 0; 305e1b4aed0SAxel Dörfler return error; 306bd5bd2c6SIngo Weinhold } 307bd5bd2c6SIngo Weinhold 308bd5bd2c6SIngo Weinhold fPathLength = strlen(fBuffer); 309bd5bd2c6SIngo Weinhold return B_OK; 310e8d3eff9SIngo Weinhold } 311e8d3eff9SIngo Weinhold 312e8d3eff9SIngo Weinhold 3132d690920SAxel Dörfler KPath& 3142d690920SAxel Dörfler KPath::operator=(const KPath& other) 3152d690920SAxel Dörfler { 31656bbbbc9SAxel Dörfler SetTo(other.fBuffer, false, other.fBufferSize); 3172d690920SAxel Dörfler return *this; 3182d690920SAxel Dörfler } 3192d690920SAxel Dörfler 3200d4c16e0SAxel Dörfler 3212d690920SAxel Dörfler KPath& 3222d690920SAxel Dörfler KPath::operator=(const char* path) 3232d690920SAxel Dörfler { 324e1b4aed0SAxel Dörfler SetPath(path); 3252d690920SAxel Dörfler return *this; 3262d690920SAxel Dörfler } 3272d690920SAxel Dörfler 3280d4c16e0SAxel Dörfler 3292d690920SAxel Dörfler bool 3302d690920SAxel Dörfler KPath::operator==(const KPath& other) const 3312d690920SAxel Dörfler { 332e1b4aed0SAxel Dörfler if (fBuffer == NULL) 3330d4c16e0SAxel Dörfler return !other.fBuffer; 3340d4c16e0SAxel Dörfler 3353582d4feSAxel Dörfler return other.fBuffer 3362d690920SAxel Dörfler && fPathLength == other.fPathLength 3373582d4feSAxel Dörfler && strcmp(fBuffer, other.fBuffer) == 0; 3382d690920SAxel Dörfler } 3392d690920SAxel Dörfler 3400d4c16e0SAxel Dörfler 3412d690920SAxel Dörfler bool 3422d690920SAxel Dörfler KPath::operator==(const char* path) const 3432d690920SAxel Dörfler { 344e1b4aed0SAxel Dörfler if (fBuffer == NULL) 3452d690920SAxel Dörfler return (!path); 3460d4c16e0SAxel Dörfler 3473582d4feSAxel Dörfler return path && strcmp(fBuffer, path) == 0; 3482d690920SAxel Dörfler } 3492d690920SAxel Dörfler 3500d4c16e0SAxel Dörfler 3512d690920SAxel Dörfler bool 3522d690920SAxel Dörfler KPath::operator!=(const KPath& other) const 3532d690920SAxel Dörfler { 3542d690920SAxel Dörfler return !(*this == other); 3552d690920SAxel Dörfler } 3562d690920SAxel Dörfler 3570d4c16e0SAxel Dörfler 3582d690920SAxel Dörfler bool 3592d690920SAxel Dörfler KPath::operator!=(const char* path) const 3602d690920SAxel Dörfler { 3612d690920SAxel Dörfler return !(*this == path); 3622d690920SAxel Dörfler } 3632d690920SAxel Dörfler 3640d4c16e0SAxel Dörfler 3652d690920SAxel Dörfler void 3662d690920SAxel Dörfler KPath::_ChopTrailingSlashes() 3672d690920SAxel Dörfler { 3683582d4feSAxel Dörfler if (fBuffer != NULL) { 3692d690920SAxel Dörfler while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/') 3702d690920SAxel Dörfler fBuffer[--fPathLength] = '\0'; 3712d690920SAxel Dörfler } 3722d690920SAxel Dörfler } 3732d690920SAxel Dörfler 374