2006-03-05 21:11:59 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2004-2006, Ingo Weinhold, bonefish@users.sf.net.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*/
|
2004-10-28 01:41:16 +04:00
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
/** A simple class wrapping a path. Has a fixed-sized buffer. */
|
2004-10-28 01:41:16 +04:00
|
|
|
|
|
|
|
#include <KPath.h>
|
2004-10-29 02:16:41 +04:00
|
|
|
#include <team.h>
|
|
|
|
#include <vfs.h>
|
2004-10-28 01:41:16 +04:00
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
// debugging
|
2006-03-05 21:11:59 +03:00
|
|
|
#define TRACE(x) ;
|
|
|
|
//#define TRACE(x) dprintf x
|
|
|
|
|
|
|
|
|
|
|
|
KPath::KPath(size_t bufferSize)
|
|
|
|
:
|
|
|
|
fBuffer(NULL),
|
|
|
|
fBufferSize(0),
|
|
|
|
fPathLength(0),
|
|
|
|
fLocked(false)
|
2004-10-28 01:41:16 +04:00
|
|
|
{
|
|
|
|
SetTo(NULL, bufferSize);
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
|
|
|
KPath::KPath(const char* path, bool normalize, size_t bufferSize)
|
|
|
|
:
|
|
|
|
fBuffer(NULL),
|
|
|
|
fBufferSize(0),
|
|
|
|
fPathLength(0),
|
|
|
|
fLocked(false)
|
2004-10-28 01:41:16 +04:00
|
|
|
{
|
2004-10-29 02:16:41 +04:00
|
|
|
SetTo(path, normalize, bufferSize);
|
2004-10-28 01:41:16 +04:00
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
KPath::KPath(const KPath& other)
|
2006-03-05 21:11:59 +03:00
|
|
|
:
|
|
|
|
fBuffer(NULL),
|
|
|
|
fBufferSize(0),
|
|
|
|
fPathLength(0),
|
|
|
|
fLocked(false)
|
2004-10-28 01:41:16 +04:00
|
|
|
{
|
|
|
|
*this = other;
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
KPath::~KPath()
|
|
|
|
{
|
|
|
|
free(fBuffer);
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
status_t
|
2006-03-05 21:11:59 +03:00
|
|
|
KPath::SetTo(const char* path, bool normalize, size_t bufferSize)
|
2004-10-28 01:41:16 +04:00
|
|
|
{
|
2006-03-05 21:11:59 +03:00
|
|
|
if (bufferSize == 0)
|
2004-10-28 01:41:16 +04:00
|
|
|
bufferSize = B_PATH_NAME_LENGTH;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
// free the previous buffer, if the buffer size differs
|
|
|
|
if (fBuffer && fBufferSize != bufferSize) {
|
|
|
|
free(fBuffer);
|
|
|
|
fBuffer = NULL;
|
|
|
|
fBufferSize = 0;
|
|
|
|
}
|
|
|
|
fPathLength = 0;
|
|
|
|
fLocked = false;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
// allocate buffer
|
|
|
|
if (!fBuffer)
|
|
|
|
fBuffer = (char*)malloc(bufferSize);
|
|
|
|
if (!fBuffer)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
if (fBuffer) {
|
|
|
|
fBufferSize = bufferSize;
|
|
|
|
fBuffer[0] = '\0';
|
|
|
|
}
|
2004-10-29 02:16:41 +04:00
|
|
|
return SetPath(path, normalize);
|
2004-10-28 01:41:16 +04:00
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
status_t
|
|
|
|
KPath::InitCheck() const
|
|
|
|
{
|
2006-03-05 21:11:59 +03:00
|
|
|
return fBuffer ? B_OK : B_NO_MEMORY;
|
2004-10-28 01:41:16 +04:00
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
status_t
|
2004-10-29 02:16:41 +04:00
|
|
|
KPath::SetPath(const char *path, bool normalize)
|
2004-10-28 01:41:16 +04:00
|
|
|
{
|
|
|
|
if (!fBuffer)
|
|
|
|
return B_NO_INIT;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
if (path) {
|
2004-10-29 02:16:41 +04:00
|
|
|
if (normalize) {
|
|
|
|
// normalize path
|
|
|
|
status_t error = vfs_normalize_path(path, fBuffer, fBufferSize,
|
|
|
|
team_get_kernel_team_id() == team_get_current_team_id());
|
|
|
|
if (error != B_OK) {
|
|
|
|
SetPath(NULL);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
fPathLength = strlen(fBuffer);
|
|
|
|
} else {
|
|
|
|
// don't normalize path
|
2006-03-05 21:11:59 +03:00
|
|
|
size_t length = strlen(path);
|
|
|
|
if (length >= fBufferSize)
|
2004-10-29 02:16:41 +04:00
|
|
|
return B_BUFFER_OVERFLOW;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
|
|
|
memcpy(fBuffer, path, length + 1);
|
|
|
|
fPathLength = length;
|
2004-10-29 02:16:41 +04:00
|
|
|
_ChopTrailingSlashes();
|
|
|
|
}
|
2004-10-28 01:41:16 +04:00
|
|
|
} else {
|
|
|
|
fBuffer[0] = '\0';
|
|
|
|
fPathLength = 0;
|
|
|
|
}
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
const char*
|
|
|
|
KPath::Path() const
|
|
|
|
{
|
|
|
|
return fBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
KPath::LockBuffer()
|
|
|
|
{
|
|
|
|
if (!fBuffer || fLocked)
|
|
|
|
return NULL;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
fLocked = true;
|
|
|
|
return fBuffer;
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
void
|
|
|
|
KPath::UnlockBuffer()
|
|
|
|
{
|
|
|
|
if (!fLocked) {
|
2006-03-05 21:11:59 +03:00
|
|
|
TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n"));
|
2004-10-28 01:41:16 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
fLocked = false;
|
|
|
|
fPathLength = strnlen(fBuffer, fBufferSize);
|
|
|
|
if (fPathLength == fBufferSize) {
|
2006-03-05 21:11:59 +03:00
|
|
|
TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n"));
|
2004-10-28 01:41:16 +04:00
|
|
|
fPathLength--;
|
|
|
|
fBuffer[fPathLength] = '\0';
|
|
|
|
}
|
2004-10-28 19:09:48 +04:00
|
|
|
_ChopTrailingSlashes();
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 19:09:48 +04:00
|
|
|
const char *
|
|
|
|
KPath::Leaf() const
|
|
|
|
{
|
|
|
|
if (!fBuffer)
|
|
|
|
return NULL;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 19:09:48 +04:00
|
|
|
// only "/" has trailing slashes -- then we have to return the complete
|
|
|
|
// buffer, as we have to do in case there are no slashes at all
|
|
|
|
if (fPathLength != 1 || fBuffer[0] != '/') {
|
|
|
|
for (int32 i = fPathLength - 1; i >= 0; i--) {
|
|
|
|
if (fBuffer[i] == '/')
|
|
|
|
return fBuffer + i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fBuffer;
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 19:09:48 +04:00
|
|
|
status_t
|
|
|
|
KPath::ReplaceLeaf(const char *newLeaf)
|
|
|
|
{
|
|
|
|
const char *leaf = Leaf();
|
|
|
|
if (!leaf)
|
|
|
|
return B_NO_INIT;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 19:09:48 +04:00
|
|
|
int32 leafIndex = leaf - fBuffer;
|
|
|
|
// chop off the current leaf (don't replace "/", though)
|
|
|
|
if (leafIndex != 0 || fBuffer[leafIndex - 1]) {
|
|
|
|
fBuffer[leafIndex] = '\0';
|
|
|
|
fPathLength = leafIndex;
|
|
|
|
_ChopTrailingSlashes();
|
|
|
|
}
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 19:09:48 +04:00
|
|
|
// if a leaf was given, append it
|
|
|
|
if (newLeaf)
|
|
|
|
return Append(newLeaf);
|
|
|
|
return B_OK;
|
2004-10-28 01:41:16 +04:00
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2007-07-15 04:34:17 +04:00
|
|
|
bool
|
|
|
|
KPath::RemoveLeaf()
|
|
|
|
{
|
|
|
|
// get the leaf -- bail out, if not initialized or only the "/" is left
|
|
|
|
const char *leaf = Leaf();
|
|
|
|
if (!leaf || leaf == fBuffer)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// chop off the leaf
|
|
|
|
int32 leafIndex = leaf - fBuffer;
|
|
|
|
fBuffer[leafIndex] = '\0';
|
|
|
|
fPathLength = leafIndex;
|
|
|
|
_ChopTrailingSlashes();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
status_t
|
2004-10-28 19:09:48 +04:00
|
|
|
KPath::Append(const char *component, bool isComponent)
|
2004-10-28 01:41:16 +04:00
|
|
|
{
|
|
|
|
// check initialization and parameter
|
|
|
|
if (!fBuffer)
|
|
|
|
return B_NO_INIT;
|
|
|
|
if (!component)
|
|
|
|
return B_BAD_VALUE;
|
2004-10-28 19:09:48 +04:00
|
|
|
if (fPathLength == 0)
|
|
|
|
return SetPath(component);
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 19:09:48 +04:00
|
|
|
// get component length
|
2006-03-05 21:11:59 +03:00
|
|
|
size_t componentLength = strlen(component);
|
|
|
|
if (componentLength < 1)
|
2004-10-28 01:41:16 +04:00
|
|
|
return B_OK;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
// if our current path is empty, we just copy the supplied one
|
|
|
|
// compute the result path len
|
2004-10-28 19:09:48 +04:00
|
|
|
bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/'
|
|
|
|
&& component[0] != '/';
|
2006-03-05 21:11:59 +03:00
|
|
|
size_t resultPathLength = fPathLength + componentLength + (insertSlash ? 1 : 0);
|
|
|
|
if (resultPathLength >= fBufferSize)
|
2004-10-28 01:41:16 +04:00
|
|
|
return B_BUFFER_OVERFLOW;
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
// compose the result path
|
|
|
|
if (insertSlash)
|
|
|
|
fBuffer[fPathLength++] = '/';
|
2006-03-05 21:11:59 +03:00
|
|
|
memcpy(fBuffer + fPathLength, component, componentLength + 1);
|
|
|
|
fPathLength = resultPathLength;
|
2004-10-28 01:41:16 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
KPath&
|
|
|
|
KPath::operator=(const KPath& other)
|
|
|
|
{
|
|
|
|
SetTo(other.fBuffer, other.fBufferSize);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
KPath&
|
|
|
|
KPath::operator=(const char* path)
|
|
|
|
{
|
|
|
|
SetTo(path);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
bool
|
|
|
|
KPath::operator==(const KPath& other) const
|
|
|
|
{
|
|
|
|
if (!fBuffer)
|
2006-03-05 21:11:59 +03:00
|
|
|
return !other.fBuffer;
|
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
return (other.fBuffer
|
|
|
|
&& fPathLength == other.fPathLength
|
|
|
|
&& strcmp(fBuffer, other.fBuffer) == 0);
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
bool
|
|
|
|
KPath::operator==(const char* path) const
|
|
|
|
{
|
|
|
|
if (!fBuffer)
|
|
|
|
return (!path);
|
2006-03-05 21:11:59 +03:00
|
|
|
|
|
|
|
return path && !strcmp(fBuffer, path);
|
2004-10-28 01:41:16 +04:00
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
bool
|
|
|
|
KPath::operator!=(const KPath& other) const
|
|
|
|
{
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 01:41:16 +04:00
|
|
|
bool
|
|
|
|
KPath::operator!=(const char* path) const
|
|
|
|
{
|
|
|
|
return !(*this == path);
|
|
|
|
}
|
|
|
|
|
2006-03-05 21:11:59 +03:00
|
|
|
|
2004-10-28 19:09:48 +04:00
|
|
|
void
|
|
|
|
KPath::_ChopTrailingSlashes()
|
|
|
|
{
|
|
|
|
if (fBuffer) {
|
|
|
|
while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/')
|
|
|
|
fBuffer[--fPathLength] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|