10d4c16e0SAxel Dörfler /* 20d4c16e0SAxel Dörfler * Copyright 2004-2006, Ingo Weinhold, bonefish@users.sf.net. 30d4c16e0SAxel Dörfler * Distributed under the terms of the MIT License. 40d4c16e0SAxel Dörfler */ 52d690920SAxel Dörfler 60d4c16e0SAxel Dörfler /** A simple class wrapping a path. Has a fixed-sized buffer. */ 72d690920SAxel Dörfler 8*23a60f42SAxel Dörfler #include <fs/KPath.h> 92d690920SAxel Dörfler 100d4c16e0SAxel Dörfler #include <stdlib.h> 110d4c16e0SAxel Dörfler #include <string.h> 122d690920SAxel Dörfler 13*23a60f42SAxel Dörfler #include <team.h> 14*23a60f42SAxel Dörfler #include <vfs.h> 15*23a60f42SAxel Dörfler 160d4c16e0SAxel Dörfler 170d4c16e0SAxel Dörfler // debugging 180d4c16e0SAxel Dörfler #define TRACE(x) ; 190d4c16e0SAxel Dörfler //#define TRACE(x) dprintf x 200d4c16e0SAxel Dörfler 210d4c16e0SAxel Dörfler 220d4c16e0SAxel Dörfler KPath::KPath(size_t bufferSize) 230d4c16e0SAxel Dörfler : 240d4c16e0SAxel Dörfler fBuffer(NULL), 252d690920SAxel Dörfler fBufferSize(0), 262d690920SAxel Dörfler fPathLength(0), 272d690920SAxel Dörfler fLocked(false) 282d690920SAxel Dörfler { 295fce1ce7SStefano Ceccherini SetTo(NULL, false, bufferSize); 302d690920SAxel Dörfler } 312d690920SAxel Dörfler 320d4c16e0SAxel Dörfler 330d4c16e0SAxel Dörfler KPath::KPath(const char* path, bool normalize, size_t bufferSize) 340d4c16e0SAxel Dörfler : 350d4c16e0SAxel Dörfler fBuffer(NULL), 362d690920SAxel Dörfler fBufferSize(0), 372d690920SAxel Dörfler fPathLength(0), 382d690920SAxel Dörfler fLocked(false) 392d690920SAxel Dörfler { 402d690920SAxel Dörfler SetTo(path, normalize, bufferSize); 412d690920SAxel Dörfler } 422d690920SAxel Dörfler 430d4c16e0SAxel Dörfler 442d690920SAxel Dörfler KPath::KPath(const KPath& other) 450d4c16e0SAxel Dörfler : 460d4c16e0SAxel Dörfler fBuffer(NULL), 472d690920SAxel Dörfler fBufferSize(0), 482d690920SAxel Dörfler fPathLength(0), 492d690920SAxel Dörfler fLocked(false) 502d690920SAxel Dörfler { 512d690920SAxel Dörfler *this = other; 522d690920SAxel Dörfler } 532d690920SAxel Dörfler 540d4c16e0SAxel Dörfler 552d690920SAxel Dörfler KPath::~KPath() 562d690920SAxel Dörfler { 572d690920SAxel Dörfler free(fBuffer); 582d690920SAxel Dörfler } 592d690920SAxel Dörfler 600d4c16e0SAxel Dörfler 612d690920SAxel Dörfler status_t 620d4c16e0SAxel Dörfler KPath::SetTo(const char* path, bool normalize, size_t bufferSize) 632d690920SAxel Dörfler { 640d4c16e0SAxel Dörfler if (bufferSize == 0) 652d690920SAxel Dörfler bufferSize = B_PATH_NAME_LENGTH; 660d4c16e0SAxel Dörfler 672d690920SAxel Dörfler // free the previous buffer, if the buffer size differs 682d690920SAxel Dörfler if (fBuffer && fBufferSize != bufferSize) { 692d690920SAxel Dörfler free(fBuffer); 702d690920SAxel Dörfler fBuffer = NULL; 712d690920SAxel Dörfler fBufferSize = 0; 722d690920SAxel Dörfler } 732d690920SAxel Dörfler fPathLength = 0; 742d690920SAxel Dörfler fLocked = false; 750d4c16e0SAxel Dörfler 762d690920SAxel Dörfler // allocate buffer 772d690920SAxel Dörfler if (!fBuffer) 782d690920SAxel Dörfler fBuffer = (char*)malloc(bufferSize); 792d690920SAxel Dörfler if (!fBuffer) 802d690920SAxel Dörfler return B_NO_MEMORY; 812d690920SAxel Dörfler if (fBuffer) { 822d690920SAxel Dörfler fBufferSize = bufferSize; 832d690920SAxel Dörfler fBuffer[0] = '\0'; 842d690920SAxel Dörfler } 852d690920SAxel Dörfler return SetPath(path, normalize); 862d690920SAxel Dörfler } 872d690920SAxel Dörfler 880d4c16e0SAxel Dörfler 892d690920SAxel Dörfler status_t 902d690920SAxel Dörfler KPath::InitCheck() const 912d690920SAxel Dörfler { 920d4c16e0SAxel Dörfler return fBuffer ? B_OK : B_NO_MEMORY; 932d690920SAxel Dörfler } 942d690920SAxel Dörfler 950d4c16e0SAxel Dörfler 962d690920SAxel Dörfler status_t 972d690920SAxel Dörfler KPath::SetPath(const char *path, bool normalize) 982d690920SAxel Dörfler { 992d690920SAxel Dörfler if (!fBuffer) 1002d690920SAxel Dörfler return B_NO_INIT; 1010d4c16e0SAxel Dörfler 1022d690920SAxel Dörfler if (path) { 1032d690920SAxel Dörfler if (normalize) { 1042d690920SAxel Dörfler // normalize path 1052d690920SAxel Dörfler status_t error = vfs_normalize_path(path, fBuffer, fBufferSize, 1062d690920SAxel Dörfler team_get_kernel_team_id() == team_get_current_team_id()); 1072d690920SAxel Dörfler if (error != B_OK) { 1082d690920SAxel Dörfler SetPath(NULL); 1092d690920SAxel Dörfler return error; 1102d690920SAxel Dörfler } 1112d690920SAxel Dörfler fPathLength = strlen(fBuffer); 1122d690920SAxel Dörfler } else { 1132d690920SAxel Dörfler // don't normalize path 1140d4c16e0SAxel Dörfler size_t length = strlen(path); 1150d4c16e0SAxel Dörfler if (length >= fBufferSize) 1162d690920SAxel Dörfler return B_BUFFER_OVERFLOW; 1170d4c16e0SAxel Dörfler 1180d4c16e0SAxel Dörfler memcpy(fBuffer, path, length + 1); 1190d4c16e0SAxel Dörfler fPathLength = length; 1202d690920SAxel Dörfler _ChopTrailingSlashes(); 1212d690920SAxel Dörfler } 1222d690920SAxel Dörfler } else { 1232d690920SAxel Dörfler fBuffer[0] = '\0'; 1242d690920SAxel Dörfler fPathLength = 0; 1252d690920SAxel Dörfler } 1262d690920SAxel Dörfler return B_OK; 1272d690920SAxel Dörfler } 1282d690920SAxel Dörfler 1290d4c16e0SAxel Dörfler 1302d690920SAxel Dörfler const char* 1312d690920SAxel Dörfler KPath::Path() const 1322d690920SAxel Dörfler { 1332d690920SAxel Dörfler return fBuffer; 1342d690920SAxel Dörfler } 1352d690920SAxel Dörfler 1362d690920SAxel Dörfler 1372d690920SAxel Dörfler char * 1382d690920SAxel Dörfler KPath::LockBuffer() 1392d690920SAxel Dörfler { 1402d690920SAxel Dörfler if (!fBuffer || fLocked) 1412d690920SAxel Dörfler return NULL; 1420d4c16e0SAxel Dörfler 1432d690920SAxel Dörfler fLocked = true; 1442d690920SAxel Dörfler return fBuffer; 1452d690920SAxel Dörfler } 1462d690920SAxel Dörfler 1470d4c16e0SAxel Dörfler 1482d690920SAxel Dörfler void 1492d690920SAxel Dörfler KPath::UnlockBuffer() 1502d690920SAxel Dörfler { 1512d690920SAxel Dörfler if (!fLocked) { 1520d4c16e0SAxel Dörfler TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n")); 1532d690920SAxel Dörfler return; 1542d690920SAxel Dörfler } 1552d690920SAxel Dörfler fLocked = false; 1562d690920SAxel Dörfler fPathLength = strnlen(fBuffer, fBufferSize); 1572d690920SAxel Dörfler if (fPathLength == fBufferSize) { 1580d4c16e0SAxel Dörfler TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n")); 1592d690920SAxel Dörfler fPathLength--; 1602d690920SAxel Dörfler fBuffer[fPathLength] = '\0'; 1612d690920SAxel Dörfler } 1622d690920SAxel Dörfler _ChopTrailingSlashes(); 1632d690920SAxel Dörfler } 1642d690920SAxel Dörfler 1650d4c16e0SAxel Dörfler 1662d690920SAxel Dörfler const char * 1672d690920SAxel Dörfler KPath::Leaf() const 1682d690920SAxel Dörfler { 1692d690920SAxel Dörfler if (!fBuffer) 1702d690920SAxel Dörfler return NULL; 1710d4c16e0SAxel Dörfler 1722d690920SAxel Dörfler // only "/" has trailing slashes -- then we have to return the complete 1732d690920SAxel Dörfler // buffer, as we have to do in case there are no slashes at all 1742d690920SAxel Dörfler if (fPathLength != 1 || fBuffer[0] != '/') { 1752d690920SAxel Dörfler for (int32 i = fPathLength - 1; i >= 0; i--) { 1762d690920SAxel Dörfler if (fBuffer[i] == '/') 1772d690920SAxel Dörfler return fBuffer + i + 1; 1782d690920SAxel Dörfler } 1792d690920SAxel Dörfler } 1802d690920SAxel Dörfler return fBuffer; 1812d690920SAxel Dörfler } 1822d690920SAxel Dörfler 1830d4c16e0SAxel Dörfler 1842d690920SAxel Dörfler status_t 1852d690920SAxel Dörfler KPath::ReplaceLeaf(const char *newLeaf) 1862d690920SAxel Dörfler { 1872d690920SAxel Dörfler const char *leaf = Leaf(); 1882d690920SAxel Dörfler if (!leaf) 1892d690920SAxel Dörfler return B_NO_INIT; 1900d4c16e0SAxel Dörfler 1912d690920SAxel Dörfler int32 leafIndex = leaf - fBuffer; 1922d690920SAxel Dörfler // chop off the current leaf (don't replace "/", though) 1932d690920SAxel Dörfler if (leafIndex != 0 || fBuffer[leafIndex - 1]) { 1942d690920SAxel Dörfler fBuffer[leafIndex] = '\0'; 1952d690920SAxel Dörfler fPathLength = leafIndex; 1962d690920SAxel Dörfler _ChopTrailingSlashes(); 1972d690920SAxel Dörfler } 1980d4c16e0SAxel Dörfler 1992d690920SAxel Dörfler // if a leaf was given, append it 2002d690920SAxel Dörfler if (newLeaf) 2012d690920SAxel Dörfler return Append(newLeaf); 2022d690920SAxel Dörfler return B_OK; 2032d690920SAxel Dörfler } 2042d690920SAxel Dörfler 2050d4c16e0SAxel Dörfler 2063532662eSIngo Weinhold bool 2073532662eSIngo Weinhold KPath::RemoveLeaf() 2083532662eSIngo Weinhold { 2093532662eSIngo Weinhold // get the leaf -- bail out, if not initialized or only the "/" is left 2103532662eSIngo Weinhold const char *leaf = Leaf(); 2113532662eSIngo Weinhold if (!leaf || leaf == fBuffer) 2123532662eSIngo Weinhold return false; 2133532662eSIngo Weinhold 2143532662eSIngo Weinhold // chop off the leaf 2153532662eSIngo Weinhold int32 leafIndex = leaf - fBuffer; 2163532662eSIngo Weinhold fBuffer[leafIndex] = '\0'; 2173532662eSIngo Weinhold fPathLength = leafIndex; 2183532662eSIngo Weinhold _ChopTrailingSlashes(); 2193532662eSIngo Weinhold 2203532662eSIngo Weinhold return true; 2213532662eSIngo Weinhold } 2223532662eSIngo Weinhold 2233532662eSIngo Weinhold 2242d690920SAxel Dörfler status_t 2252d690920SAxel Dörfler KPath::Append(const char *component, bool isComponent) 2262d690920SAxel Dörfler { 2272d690920SAxel Dörfler // check initialization and parameter 2282d690920SAxel Dörfler if (!fBuffer) 2292d690920SAxel Dörfler return B_NO_INIT; 2302d690920SAxel Dörfler if (!component) 2312d690920SAxel Dörfler return B_BAD_VALUE; 2322d690920SAxel Dörfler if (fPathLength == 0) 2332d690920SAxel Dörfler return SetPath(component); 2340d4c16e0SAxel Dörfler 2352d690920SAxel Dörfler // get component length 2360d4c16e0SAxel Dörfler size_t componentLength = strlen(component); 2370d4c16e0SAxel Dörfler if (componentLength < 1) 2382d690920SAxel Dörfler return B_OK; 2390d4c16e0SAxel Dörfler 2402d690920SAxel Dörfler // if our current path is empty, we just copy the supplied one 2412d690920SAxel Dörfler // compute the result path len 2422d690920SAxel Dörfler bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/' 2432d690920SAxel Dörfler && component[0] != '/'; 2440d4c16e0SAxel Dörfler size_t resultPathLength = fPathLength + componentLength + (insertSlash ? 1 : 0); 2450d4c16e0SAxel Dörfler if (resultPathLength >= fBufferSize) 2462d690920SAxel Dörfler return B_BUFFER_OVERFLOW; 2470d4c16e0SAxel Dörfler 2482d690920SAxel Dörfler // compose the result path 2492d690920SAxel Dörfler if (insertSlash) 2502d690920SAxel Dörfler fBuffer[fPathLength++] = '/'; 2510d4c16e0SAxel Dörfler memcpy(fBuffer + fPathLength, component, componentLength + 1); 2520d4c16e0SAxel Dörfler fPathLength = resultPathLength; 2532d690920SAxel Dörfler return B_OK; 2542d690920SAxel Dörfler } 2552d690920SAxel Dörfler 2560d4c16e0SAxel Dörfler 2572d690920SAxel Dörfler KPath& 2582d690920SAxel Dörfler KPath::operator=(const KPath& other) 2592d690920SAxel Dörfler { 2602d690920SAxel Dörfler SetTo(other.fBuffer, other.fBufferSize); 2612d690920SAxel Dörfler return *this; 2622d690920SAxel Dörfler } 2632d690920SAxel Dörfler 2640d4c16e0SAxel Dörfler 2652d690920SAxel Dörfler KPath& 2662d690920SAxel Dörfler KPath::operator=(const char* path) 2672d690920SAxel Dörfler { 2682d690920SAxel Dörfler SetTo(path); 2692d690920SAxel Dörfler return *this; 2702d690920SAxel Dörfler } 2712d690920SAxel Dörfler 2720d4c16e0SAxel Dörfler 2732d690920SAxel Dörfler bool 2742d690920SAxel Dörfler KPath::operator==(const KPath& other) const 2752d690920SAxel Dörfler { 2762d690920SAxel Dörfler if (!fBuffer) 2770d4c16e0SAxel Dörfler return !other.fBuffer; 2780d4c16e0SAxel Dörfler 2792d690920SAxel Dörfler return (other.fBuffer 2802d690920SAxel Dörfler && fPathLength == other.fPathLength 2812d690920SAxel Dörfler && strcmp(fBuffer, other.fBuffer) == 0); 2822d690920SAxel Dörfler } 2832d690920SAxel Dörfler 2840d4c16e0SAxel Dörfler 2852d690920SAxel Dörfler bool 2862d690920SAxel Dörfler KPath::operator==(const char* path) const 2872d690920SAxel Dörfler { 2882d690920SAxel Dörfler if (!fBuffer) 2892d690920SAxel Dörfler return (!path); 2900d4c16e0SAxel Dörfler 2910d4c16e0SAxel Dörfler return path && !strcmp(fBuffer, path); 2922d690920SAxel Dörfler } 2932d690920SAxel Dörfler 2940d4c16e0SAxel Dörfler 2952d690920SAxel Dörfler bool 2962d690920SAxel Dörfler KPath::operator!=(const KPath& other) const 2972d690920SAxel Dörfler { 2982d690920SAxel Dörfler return !(*this == other); 2992d690920SAxel Dörfler } 3002d690920SAxel Dörfler 3010d4c16e0SAxel Dörfler 3022d690920SAxel Dörfler bool 3032d690920SAxel Dörfler KPath::operator!=(const char* path) const 3042d690920SAxel Dörfler { 3052d690920SAxel Dörfler return !(*this == path); 3062d690920SAxel Dörfler } 3072d690920SAxel Dörfler 3080d4c16e0SAxel Dörfler 3092d690920SAxel Dörfler void 3102d690920SAxel Dörfler KPath::_ChopTrailingSlashes() 3112d690920SAxel Dörfler { 3122d690920SAxel Dörfler if (fBuffer) { 3132d690920SAxel Dörfler while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/') 3142d690920SAxel Dörfler fBuffer[--fPathLength] = '\0'; 3152d690920SAxel Dörfler } 3162d690920SAxel Dörfler } 3172d690920SAxel Dörfler 318