KPath: Add to kernelland_emu.

This replaces the one in the "playground." It's identical to the current
kernel implementation, except with the few VFS functions replaced with
Storage Kit calls.

Userland packagefs will need this.
This commit is contained in:
Augustin Cavalier 2018-10-16 18:50:00 -04:00
parent 85cbf99307
commit 66c7a2ac9c
4 changed files with 451 additions and 331 deletions

View File

@ -7,6 +7,7 @@ SharedLibrary libkernelland_emu.so :
condition_variable.cpp
debug.cpp
device_manager.cpp
KPath.cpp
lock.cpp
low_resource_manager.cpp
misc.cpp

View File

@ -0,0 +1,450 @@
/*
* Copyright 2004-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2008-2017, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
/*! A simple class wrapping a path. Has a fixed-sized buffer. */
#include <fs/KPath.h>
#include <Path.h>
#include <stdlib.h>
#include <string.h>
#include <team.h>
// debugging
#define TRACE(x) ;
//#define TRACE(x) dprintf x
KPath::KPath(size_t bufferSize)
:
fBuffer(NULL),
fBufferSize(0),
fPathLength(0),
fLocked(false),
fLazy(false),
fFailed(false),
fIsNull(false)
{
SetTo(NULL, DEFAULT, bufferSize);
}
KPath::KPath(const char* path, int32 flags, size_t bufferSize)
:
fBuffer(NULL),
fBufferSize(0),
fPathLength(0),
fLocked(false),
fLazy(false),
fFailed(false),
fIsNull(false)
{
SetTo(path, flags, bufferSize);
}
KPath::KPath(const KPath& other)
:
fBuffer(NULL),
fBufferSize(0),
fPathLength(0),
fLocked(false),
fLazy(false),
fFailed(false),
fIsNull(false)
{
*this = other;
}
KPath::~KPath()
{
free(fBuffer);
}
status_t
KPath::SetTo(const char* path, int32 flags, size_t bufferSize)
{
if (bufferSize == 0)
bufferSize = B_PATH_NAME_LENGTH;
// free the previous buffer, if the buffer size differs
if (fBuffer != NULL && fBufferSize != bufferSize) {
free(fBuffer);
fBuffer = NULL;
fBufferSize = 0;
}
fPathLength = 0;
fLocked = false;
fBufferSize = bufferSize;
fLazy = (flags & LAZY_ALLOC) != 0;
fIsNull = path == NULL;
if (path != NULL || !fLazy) {
status_t status = _AllocateBuffer();
if (status != B_OK)
return status;
}
return SetPath(path, flags);
}
void
KPath::Adopt(KPath& other)
{
free(fBuffer);
fBuffer = other.fBuffer;
fBufferSize = other.fBufferSize;
fPathLength = other.fPathLength;
fLazy = other.fLazy;
fFailed = other.fFailed;
fIsNull = other.fIsNull;
other.fBuffer = NULL;
if (!other.fLazy)
other.fBufferSize = 0;
other.fPathLength = 0;
other.fFailed = false;
other.fIsNull = other.fLazy;
}
status_t
KPath::InitCheck() const
{
if (fBuffer != NULL || (fLazy && !fFailed && fBufferSize != 0))
return B_OK;
return fFailed ? B_NO_MEMORY : B_NO_INIT;
}
/*! \brief Sets the buffer to \a path.
\param flags Understands the following two options:
- \c NORMALIZE
- \c TRAVERSE_LEAF_LINK
*/
status_t
KPath::SetPath(const char* path, int32 flags)
{
if (path == NULL && fLazy && fBuffer == NULL) {
fIsNull = true;
return B_OK;
}
if (fBuffer == NULL) {
if (fLazy) {
status_t status = _AllocateBuffer();
if (status != B_OK)
return B_NO_MEMORY;
} else
return B_NO_INIT;
}
fIsNull = false;
if (path != NULL) {
if ((flags & NORMALIZE) != 0) {
// normalize path
status_t status = _Normalize(path,
(flags & TRAVERSE_LEAF_LINK) != 0);
if (status != B_OK)
return status;
} else {
// don't normalize path
size_t length = strlen(path);
if (length >= fBufferSize)
return B_BUFFER_OVERFLOW;
memcpy(fBuffer, path, length + 1);
fPathLength = length;
_ChopTrailingSlashes();
}
} else {
fBuffer[0] = '\0';
fPathLength = 0;
if (fLazy)
fIsNull = true;
}
return B_OK;
}
const char*
KPath::Path() const
{
return fIsNull ? NULL : fBuffer;
}
/*! \brief Locks the buffer for external changes.
\param force In lazy mode, this will allocate a buffer when set.
Otherwise, \c NULL will be returned if set to NULL.
*/
char*
KPath::LockBuffer(bool force)
{
if (fBuffer == NULL && fLazy) {
if (fIsNull && !force)
return NULL;
_AllocateBuffer();
}
if (fBuffer == NULL || fLocked)
return NULL;
fLocked = true;
fIsNull = false;
return fBuffer;
}
void
KPath::UnlockBuffer()
{
if (!fLocked) {
TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n"));
return;
}
fLocked = false;
if (fBuffer == NULL)
return;
fPathLength = strnlen(fBuffer, fBufferSize);
if (fPathLength == fBufferSize) {
TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n"));
fPathLength--;
fBuffer[fPathLength] = '\0';
}
_ChopTrailingSlashes();
}
char*
KPath::DetachBuffer()
{
char* buffer = fBuffer;
if (fBuffer != NULL) {
fBuffer = NULL;
fPathLength = 0;
fLocked = false;
}
return buffer;
}
const char*
KPath::Leaf() const
{
if (fBuffer == NULL)
return NULL;
for (int32 i = fPathLength - 1; i >= 0; i--) {
if (fBuffer[i] == '/')
return fBuffer + i + 1;
}
return fBuffer;
}
status_t
KPath::ReplaceLeaf(const char* newLeaf)
{
const char* leaf = Leaf();
if (leaf == NULL)
return B_NO_INIT;
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();
}
// if a leaf was given, append it
if (newLeaf != NULL)
return Append(newLeaf);
return B_OK;
}
bool
KPath::RemoveLeaf()
{
// get the leaf -- bail out, if not initialized or only the "/" is left
const char* leaf = Leaf();
if (leaf == NULL || leaf == fBuffer || leaf[0] == '\0')
return false;
// chop off the leaf
int32 leafIndex = leaf - fBuffer;
fBuffer[leafIndex] = '\0';
fPathLength = leafIndex;
_ChopTrailingSlashes();
return true;
}
status_t
KPath::Append(const char* component, bool isComponent)
{
// check initialization and parameter
if (fBuffer == NULL)
return B_NO_INIT;
if (component == NULL)
return B_BAD_VALUE;
if (fPathLength == 0)
return SetPath(component);
// get component length
size_t componentLength = strlen(component);
if (componentLength < 1)
return B_OK;
// if our current path is empty, we just copy the supplied one
// compute the result path len
bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/'
&& component[0] != '/';
size_t resultPathLength = fPathLength + componentLength
+ (insertSlash ? 1 : 0);
if (resultPathLength >= fBufferSize)
return B_BUFFER_OVERFLOW;
// compose the result path
if (insertSlash)
fBuffer[fPathLength++] = '/';
memcpy(fBuffer + fPathLength, component, componentLength + 1);
fPathLength = resultPathLength;
return B_OK;
}
status_t
KPath::Normalize(bool traverseLeafLink)
{
if (fBuffer == NULL)
return B_NO_INIT;
if (fPathLength == 0)
return B_BAD_VALUE;
return _Normalize(fBuffer, traverseLeafLink);
}
KPath&
KPath::operator=(const KPath& other)
{
SetTo(other.fBuffer, fLazy ? KPath::LAZY_ALLOC : KPath::DEFAULT,
other.fBufferSize);
return *this;
}
KPath&
KPath::operator=(const char* path)
{
SetPath(path);
return *this;
}
bool
KPath::operator==(const KPath& other) const
{
if (fBuffer == NULL)
return !other.fBuffer;
return other.fBuffer != NULL
&& fPathLength == other.fPathLength
&& strcmp(fBuffer, other.fBuffer) == 0;
}
bool
KPath::operator==(const char* path) const
{
if (fBuffer == NULL)
return path == NULL;
return path != NULL && strcmp(fBuffer, path) == 0;
}
bool
KPath::operator!=(const KPath& other) const
{
return !(*this == other);
}
bool
KPath::operator!=(const char* path) const
{
return !(*this == path);
}
status_t
KPath::_AllocateBuffer()
{
if (fBuffer == NULL && fBufferSize != 0)
fBuffer = (char*)malloc(fBufferSize);
if (fBuffer == NULL) {
fFailed = true;
return B_NO_MEMORY;
}
fBuffer[0] = '\0';
fFailed = false;
return B_OK;
}
status_t
KPath::_Normalize(const char* path, bool traverseLeafLink)
{
BPath normalizedPath;
status_t error = normalizedPath.SetTo(path, NULL, true);
if (error != B_OK) {
fBuffer[0] = '\0';
fPathLength = 0;
return error;
}
strlcpy(fBuffer, normalizedPath.Path(), fBufferSize);
fPathLength = strlen(fBuffer);
return B_OK;
}
void
KPath::_ChopTrailingSlashes()
{
if (fBuffer != NULL) {
while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/')
fBuffer[--fPathLength] = '\0';
}
}

View File

@ -7,7 +7,6 @@ UsePrivateHeaders shared ;
SimpleTest device_manager :
device_manager.cpp
KPath.cpp
bus.cpp
driver.cpp

View File

@ -1,330 +0,0 @@
/*
* Copyright 2004-2006, Ingo Weinhold, bonefish@users.sf.net.
* Distributed under the terms of the MIT License.
*/
/** A simple class wrapping a path. Has a fixed-sized buffer. */
#include <fs/KPath.h>
#include <stdlib.h>
#include <string.h>
#include <Path.h>
// debugging
#define TRACE(x) ;
//#define TRACE(x) dprintf x
KPath::KPath(size_t bufferSize)
:
fBuffer(NULL),
fBufferSize(0),
fPathLength(0),
fLocked(false)
{
SetTo(NULL, false, bufferSize);
}
KPath::KPath(const char* path, bool normalize, size_t bufferSize)
:
fBuffer(NULL),
fBufferSize(0),
fPathLength(0),
fLocked(false)
{
SetTo(path, normalize, bufferSize);
}
KPath::KPath(const KPath& other)
:
fBuffer(NULL),
fBufferSize(0),
fPathLength(0),
fLocked(false)
{
*this = other;
}
KPath::~KPath()
{
free(fBuffer);
}
status_t
KPath::SetTo(const char* path, bool normalize, size_t bufferSize)
{
if (bufferSize == 0)
bufferSize = B_PATH_NAME_LENGTH;
// free the previous buffer, if the buffer size differs
if (fBuffer && fBufferSize != bufferSize) {
free(fBuffer);
fBuffer = NULL;
fBufferSize = 0;
}
fPathLength = 0;
fLocked = false;
// allocate buffer
if (!fBuffer)
fBuffer = (char*)malloc(bufferSize);
if (!fBuffer)
return B_NO_MEMORY;
if (fBuffer) {
fBufferSize = bufferSize;
fBuffer[0] = '\0';
}
return SetPath(path, normalize);
}
void
KPath::Adopt(KPath& other)
{
free(fBuffer);
fBuffer = other.fBuffer;
fBufferSize = other.fBufferSize;
other.fBuffer = NULL;
}
status_t
KPath::InitCheck() const
{
return fBuffer ? B_OK : B_NO_MEMORY;
}
status_t
KPath::SetPath(const char *path, bool normalize)
{
if (!fBuffer)
return B_NO_INIT;
if (path) {
if (normalize) {
// normalize path
BPath normalizedPath;
status_t error = normalizedPath.SetTo(path, NULL, true);
if (error != B_OK) {
SetPath(NULL);
return error;
}
strlcpy(fBuffer, normalizedPath.Path(), fBufferSize);
fPathLength = strlen(fBuffer);
} else {
// don't normalize path
size_t length = strlen(path);
if (length >= fBufferSize)
return B_BUFFER_OVERFLOW;
memcpy(fBuffer, path, length + 1);
fPathLength = length;
_ChopTrailingSlashes();
}
} else {
fBuffer[0] = '\0';
fPathLength = 0;
}
return B_OK;
}
const char*
KPath::Path() const
{
return fBuffer;
}
char *
KPath::LockBuffer()
{
if (!fBuffer || fLocked)
return NULL;
fLocked = true;
return fBuffer;
}
void
KPath::UnlockBuffer()
{
if (!fLocked) {
TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n"));
return;
}
fLocked = false;
fPathLength = strnlen(fBuffer, fBufferSize);
if (fPathLength == fBufferSize) {
TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n"));
fPathLength--;
fBuffer[fPathLength] = '\0';
}
_ChopTrailingSlashes();
}
const char *
KPath::Leaf() const
{
if (!fBuffer)
return NULL;
// 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;
}
status_t
KPath::ReplaceLeaf(const char *newLeaf)
{
const char *leaf = Leaf();
if (!leaf)
return B_NO_INIT;
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();
}
// if a leaf was given, append it
if (newLeaf)
return Append(newLeaf);
return B_OK;
}
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;
}
status_t
KPath::Append(const char *component, bool isComponent)
{
// check initialization and parameter
if (!fBuffer)
return B_NO_INIT;
if (!component)
return B_BAD_VALUE;
if (fPathLength == 0)
return SetPath(component);
// get component length
size_t componentLength = strlen(component);
if (componentLength < 1)
return B_OK;
// if our current path is empty, we just copy the supplied one
// compute the result path len
bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/'
&& component[0] != '/';
size_t resultPathLength = fPathLength + componentLength + (insertSlash ? 1 : 0);
if (resultPathLength >= fBufferSize)
return B_BUFFER_OVERFLOW;
// compose the result path
if (insertSlash)
fBuffer[fPathLength++] = '/';
memcpy(fBuffer + fPathLength, component, componentLength + 1);
fPathLength = resultPathLength;
return B_OK;
}
KPath&
KPath::operator=(const KPath& other)
{
SetTo(other.fBuffer, other.fBufferSize);
return *this;
}
KPath&
KPath::operator=(const char* path)
{
SetTo(path);
return *this;
}
bool
KPath::operator==(const KPath& other) const
{
if (!fBuffer)
return !other.fBuffer;
return (other.fBuffer
&& fPathLength == other.fPathLength
&& strcmp(fBuffer, other.fBuffer) == 0);
}
bool
KPath::operator==(const char* path) const
{
if (!fBuffer)
return (!path);
return path && !strcmp(fBuffer, path);
}
bool
KPath::operator!=(const KPath& other) const
{
return !(*this == other);
}
bool
KPath::operator!=(const char* path) const
{
return !(*this == path);
}
void
KPath::_ChopTrailingSlashes()
{
if (fBuffer) {
while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/')
fBuffer[--fPathLength] = '\0';
}
}