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