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 { 32eac83fb3SAxel Dörfler SetTo(NULL, KPath::DEFAULT, bufferSize); 332d690920SAxel Dörfler } 342d690920SAxel Dörfler 350d4c16e0SAxel Dörfler 36eac83fb3SAxel 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 { 43eac83fb3SAxel 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 65eac83fb3SAxel 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 88eac83fb3SAxel 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; 99*f94671c3SAxel Dörfler fPathLength = other.fPathLength; 10056bbbbc9SAxel Dörfler 10156bbbbc9SAxel Dörfler other.fBuffer = NULL; 1024be51875SAxel Dörfler other.fBufferSize = 0; 1034be51875SAxel Dörfler other.fPathLength = 0; 10456bbbbc9SAxel Dörfler } 10556bbbbc9SAxel Dörfler 10656bbbbc9SAxel Dörfler 1072d690920SAxel Dörfler status_t 1082d690920SAxel Dörfler KPath::InitCheck() const 1092d690920SAxel Dörfler { 110e1b4aed0SAxel Dörfler return fBuffer != NULL ? B_OK : B_NO_MEMORY; 1112d690920SAxel Dörfler } 1122d690920SAxel Dörfler 1130d4c16e0SAxel Dörfler 1142d690920SAxel Dörfler status_t 115eac83fb3SAxel Dörfler KPath::SetPath(const char* path, int32 flags) 1162d690920SAxel Dörfler { 1179abf4591Sczeidler if (fBuffer == NULL) 1182d690920SAxel Dörfler return B_NO_INIT; 1190d4c16e0SAxel Dörfler 1209abf4591Sczeidler if (path != NULL) { 121eac83fb3SAxel Dörfler if ((flags & NORMALIZE) != 0) { 1222d690920SAxel Dörfler // normalize path 1232d690920SAxel Dörfler status_t error = vfs_normalize_path(path, fBuffer, fBufferSize, 124eac83fb3SAxel Dörfler (flags & TRAVERSE_LEAF_LINK) != 0, 1252d690920SAxel Dörfler team_get_kernel_team_id() == team_get_current_team_id()); 1262d690920SAxel Dörfler if (error != B_OK) { 1272d690920SAxel Dörfler SetPath(NULL); 1282d690920SAxel Dörfler return error; 1292d690920SAxel Dörfler } 1302d690920SAxel Dörfler fPathLength = strlen(fBuffer); 1312d690920SAxel Dörfler } else { 1322d690920SAxel Dörfler // don't normalize path 1330d4c16e0SAxel Dörfler size_t length = strlen(path); 1340d4c16e0SAxel Dörfler if (length >= fBufferSize) 1352d690920SAxel Dörfler return B_BUFFER_OVERFLOW; 1360d4c16e0SAxel Dörfler 1370d4c16e0SAxel Dörfler memcpy(fBuffer, path, length + 1); 1380d4c16e0SAxel Dörfler fPathLength = length; 1392d690920SAxel Dörfler _ChopTrailingSlashes(); 1402d690920SAxel Dörfler } 1412d690920SAxel Dörfler } else { 1422d690920SAxel Dörfler fBuffer[0] = '\0'; 1432d690920SAxel Dörfler fPathLength = 0; 1442d690920SAxel Dörfler } 1452d690920SAxel Dörfler return B_OK; 1462d690920SAxel Dörfler } 1472d690920SAxel Dörfler 1480d4c16e0SAxel Dörfler 1492d690920SAxel Dörfler const char* 1502d690920SAxel Dörfler KPath::Path() const 1512d690920SAxel Dörfler { 1522d690920SAxel Dörfler return fBuffer; 1532d690920SAxel Dörfler } 1542d690920SAxel Dörfler 1552d690920SAxel Dörfler 1562d690920SAxel Dörfler char* 1572d690920SAxel Dörfler KPath::LockBuffer() 1582d690920SAxel Dörfler { 1599abf4591Sczeidler if (fBuffer == NULL || fLocked) 1602d690920SAxel Dörfler return NULL; 1610d4c16e0SAxel Dörfler 1622d690920SAxel Dörfler fLocked = true; 1632d690920SAxel Dörfler return fBuffer; 1642d690920SAxel Dörfler } 1652d690920SAxel Dörfler 1660d4c16e0SAxel Dörfler 1672d690920SAxel Dörfler void 1682d690920SAxel Dörfler KPath::UnlockBuffer() 1692d690920SAxel Dörfler { 1702d690920SAxel Dörfler if (!fLocked) { 1710d4c16e0SAxel Dörfler TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n")); 1722d690920SAxel Dörfler return; 1732d690920SAxel Dörfler } 1742d690920SAxel Dörfler fLocked = false; 1752d690920SAxel Dörfler fPathLength = strnlen(fBuffer, fBufferSize); 1762d690920SAxel Dörfler if (fPathLength == fBufferSize) { 1770d4c16e0SAxel Dörfler TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n")); 1782d690920SAxel Dörfler fPathLength--; 1792d690920SAxel Dörfler fBuffer[fPathLength] = '\0'; 1802d690920SAxel Dörfler } 1812d690920SAxel Dörfler _ChopTrailingSlashes(); 1822d690920SAxel Dörfler } 1832d690920SAxel Dörfler 1840d4c16e0SAxel Dörfler 185e8d3eff9SIngo Weinhold char* 186e8d3eff9SIngo Weinhold KPath::DetachBuffer() 187e8d3eff9SIngo Weinhold { 188e8d3eff9SIngo Weinhold char* buffer = fBuffer; 189e8d3eff9SIngo Weinhold 190e8d3eff9SIngo Weinhold if (fBuffer != NULL) { 191e8d3eff9SIngo Weinhold fBuffer = NULL; 192e8d3eff9SIngo Weinhold fBufferSize = 0; 193e8d3eff9SIngo Weinhold fPathLength = 0; 194e8d3eff9SIngo Weinhold fLocked = false; 195e8d3eff9SIngo Weinhold } 196e8d3eff9SIngo Weinhold 197e8d3eff9SIngo Weinhold return buffer; 198e8d3eff9SIngo Weinhold } 199e8d3eff9SIngo Weinhold 200e8d3eff9SIngo Weinhold 2012d690920SAxel Dörfler const char* 2022d690920SAxel Dörfler KPath::Leaf() const 2032d690920SAxel Dörfler { 2043582d4feSAxel Dörfler if (fBuffer == NULL) 2052d690920SAxel Dörfler return NULL; 2060d4c16e0SAxel Dörfler 2072d690920SAxel Dörfler for (int32 i = fPathLength - 1; i >= 0; i--) { 2082d690920SAxel Dörfler if (fBuffer[i] == '/') 2092d690920SAxel Dörfler return fBuffer + i + 1; 2102d690920SAxel Dörfler } 211e1b4aed0SAxel Dörfler 2122d690920SAxel Dörfler return fBuffer; 2132d690920SAxel Dörfler } 2142d690920SAxel Dörfler 2150d4c16e0SAxel Dörfler 2162d690920SAxel Dörfler status_t 2172d690920SAxel Dörfler KPath::ReplaceLeaf(const char* newLeaf) 2182d690920SAxel Dörfler { 2192d690920SAxel Dörfler const char* leaf = Leaf(); 2203582d4feSAxel Dörfler if (leaf == NULL) 2212d690920SAxel Dörfler return B_NO_INIT; 2220d4c16e0SAxel Dörfler 2232d690920SAxel Dörfler int32 leafIndex = leaf - fBuffer; 2242d690920SAxel Dörfler // chop off the current leaf (don't replace "/", though) 2252d690920SAxel Dörfler if (leafIndex != 0 || fBuffer[leafIndex - 1]) { 2262d690920SAxel Dörfler fBuffer[leafIndex] = '\0'; 2272d690920SAxel Dörfler fPathLength = leafIndex; 2282d690920SAxel Dörfler _ChopTrailingSlashes(); 2292d690920SAxel Dörfler } 2300d4c16e0SAxel Dörfler 2312d690920SAxel Dörfler // if a leaf was given, append it 2323582d4feSAxel Dörfler if (newLeaf != NULL) 2332d690920SAxel Dörfler return Append(newLeaf); 2342d690920SAxel Dörfler return B_OK; 2352d690920SAxel Dörfler } 2362d690920SAxel Dörfler 2370d4c16e0SAxel Dörfler 2383532662eSIngo Weinhold bool 2393532662eSIngo Weinhold KPath::RemoveLeaf() 2403532662eSIngo Weinhold { 2413532662eSIngo Weinhold // get the leaf -- bail out, if not initialized or only the "/" is left 2423532662eSIngo Weinhold const char* leaf = Leaf(); 243e1b4aed0SAxel Dörfler if (leaf == NULL || leaf == fBuffer || leaf[0] == '\0') 2443532662eSIngo Weinhold return false; 2453532662eSIngo Weinhold 2463532662eSIngo Weinhold // chop off the leaf 2473532662eSIngo Weinhold int32 leafIndex = leaf - fBuffer; 2483532662eSIngo Weinhold fBuffer[leafIndex] = '\0'; 2493532662eSIngo Weinhold fPathLength = leafIndex; 2503532662eSIngo Weinhold _ChopTrailingSlashes(); 2513532662eSIngo Weinhold 2523532662eSIngo Weinhold return true; 2533532662eSIngo Weinhold } 2543532662eSIngo Weinhold 2553532662eSIngo Weinhold 2562d690920SAxel Dörfler status_t 2572d690920SAxel Dörfler KPath::Append(const char* component, bool isComponent) 2582d690920SAxel Dörfler { 2592d690920SAxel Dörfler // check initialization and parameter 2609abf4591Sczeidler if (fBuffer == NULL) 2612d690920SAxel Dörfler return B_NO_INIT; 2629abf4591Sczeidler if (component == NULL) 2632d690920SAxel Dörfler return B_BAD_VALUE; 2642d690920SAxel Dörfler if (fPathLength == 0) 2652d690920SAxel Dörfler return SetPath(component); 2660d4c16e0SAxel Dörfler 2672d690920SAxel Dörfler // get component length 2680d4c16e0SAxel Dörfler size_t componentLength = strlen(component); 2690d4c16e0SAxel Dörfler if (componentLength < 1) 2702d690920SAxel Dörfler return B_OK; 2710d4c16e0SAxel Dörfler 2722d690920SAxel Dörfler // if our current path is empty, we just copy the supplied one 2732d690920SAxel Dörfler // compute the result path len 2742d690920SAxel Dörfler bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/' 2752d690920SAxel Dörfler && component[0] != '/'; 276ea26d9f0SStephan Aßmus size_t resultPathLength = fPathLength + componentLength 277ea26d9f0SStephan Aßmus + (insertSlash ? 1 : 0); 2780d4c16e0SAxel Dörfler if (resultPathLength >= fBufferSize) 2792d690920SAxel Dörfler return B_BUFFER_OVERFLOW; 2800d4c16e0SAxel Dörfler 2812d690920SAxel Dörfler // compose the result path 2822d690920SAxel Dörfler if (insertSlash) 2832d690920SAxel Dörfler fBuffer[fPathLength++] = '/'; 2840d4c16e0SAxel Dörfler memcpy(fBuffer + fPathLength, component, componentLength + 1); 2850d4c16e0SAxel Dörfler fPathLength = resultPathLength; 2862d690920SAxel Dörfler return B_OK; 2872d690920SAxel Dörfler } 2882d690920SAxel Dörfler 2890d4c16e0SAxel Dörfler 290e8d3eff9SIngo Weinhold status_t 291e8d3eff9SIngo Weinhold KPath::Normalize(bool traverseLeafLink) 292e8d3eff9SIngo Weinhold { 293e8d3eff9SIngo Weinhold if (fBuffer == NULL) 294e8d3eff9SIngo Weinhold return B_NO_INIT; 295e8d3eff9SIngo Weinhold if (fPathLength == 0) 296e8d3eff9SIngo Weinhold return B_BAD_VALUE; 297e8d3eff9SIngo Weinhold 298bd5bd2c6SIngo Weinhold status_t error = vfs_normalize_path(fBuffer, fBuffer, fBufferSize, 299bd5bd2c6SIngo Weinhold traverseLeafLink, 300e8d3eff9SIngo Weinhold team_get_kernel_team_id() == team_get_current_team_id()); 301bd5bd2c6SIngo Weinhold if (error != B_OK) { 302bd5bd2c6SIngo Weinhold // vfs_normalize_path() might have screwed up the previous path -- unset 303bd5bd2c6SIngo Weinhold // it completely to avoid weird problems. 304bd5bd2c6SIngo Weinhold fBuffer[0] = '\0'; 305bd5bd2c6SIngo Weinhold fPathLength = 0; 306e1b4aed0SAxel Dörfler return error; 307bd5bd2c6SIngo Weinhold } 308bd5bd2c6SIngo Weinhold 309bd5bd2c6SIngo Weinhold fPathLength = strlen(fBuffer); 310bd5bd2c6SIngo Weinhold return B_OK; 311e8d3eff9SIngo Weinhold } 312e8d3eff9SIngo Weinhold 313e8d3eff9SIngo Weinhold 3142d690920SAxel Dörfler KPath& 3152d690920SAxel Dörfler KPath::operator=(const KPath& other) 3162d690920SAxel Dörfler { 31756bbbbc9SAxel Dörfler SetTo(other.fBuffer, false, other.fBufferSize); 3182d690920SAxel Dörfler return *this; 3192d690920SAxel Dörfler } 3202d690920SAxel Dörfler 3210d4c16e0SAxel Dörfler 3222d690920SAxel Dörfler KPath& 3232d690920SAxel Dörfler KPath::operator=(const char* path) 3242d690920SAxel Dörfler { 325e1b4aed0SAxel Dörfler SetPath(path); 3262d690920SAxel Dörfler return *this; 3272d690920SAxel Dörfler } 3282d690920SAxel Dörfler 3290d4c16e0SAxel Dörfler 3302d690920SAxel Dörfler bool 3312d690920SAxel Dörfler KPath::operator==(const KPath& other) const 3322d690920SAxel Dörfler { 333e1b4aed0SAxel Dörfler if (fBuffer == NULL) 3340d4c16e0SAxel Dörfler return !other.fBuffer; 3350d4c16e0SAxel Dörfler 3363582d4feSAxel Dörfler return other.fBuffer 3372d690920SAxel Dörfler && fPathLength == other.fPathLength 3383582d4feSAxel Dörfler && strcmp(fBuffer, other.fBuffer) == 0; 3392d690920SAxel Dörfler } 3402d690920SAxel Dörfler 3410d4c16e0SAxel Dörfler 3422d690920SAxel Dörfler bool 3432d690920SAxel Dörfler KPath::operator==(const char* path) const 3442d690920SAxel Dörfler { 345e1b4aed0SAxel Dörfler if (fBuffer == NULL) 3462d690920SAxel Dörfler return (!path); 3470d4c16e0SAxel Dörfler 3483582d4feSAxel Dörfler return path && strcmp(fBuffer, path) == 0; 3492d690920SAxel Dörfler } 3502d690920SAxel Dörfler 3510d4c16e0SAxel Dörfler 3522d690920SAxel Dörfler bool 3532d690920SAxel Dörfler KPath::operator!=(const KPath& other) const 3542d690920SAxel Dörfler { 3552d690920SAxel Dörfler return !(*this == other); 3562d690920SAxel Dörfler } 3572d690920SAxel Dörfler 3580d4c16e0SAxel Dörfler 3592d690920SAxel Dörfler bool 3602d690920SAxel Dörfler KPath::operator!=(const char* path) const 3612d690920SAxel Dörfler { 3622d690920SAxel Dörfler return !(*this == path); 3632d690920SAxel Dörfler } 3642d690920SAxel Dörfler 3650d4c16e0SAxel Dörfler 3662d690920SAxel Dörfler void 3672d690920SAxel Dörfler KPath::_ChopTrailingSlashes() 3682d690920SAxel Dörfler { 3693582d4feSAxel Dörfler if (fBuffer != NULL) { 3702d690920SAxel Dörfler while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/') 3712d690920SAxel Dörfler fBuffer[--fPathLength] = '\0'; 3722d690920SAxel Dörfler } 3732d690920SAxel Dörfler } 3742d690920SAxel Dörfler 375