xref: /haiku/src/system/kernel/fs/KPath.cpp (revision 23a60f423e76739d22149d00d6a88cec02a2d776)
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