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