#include <new>
#include <ctype.h>
#include <string.h>
#include <StorageDefs.h>
#include <SupportDefs.h>
#include <syscalls.h>
#include "storage_support.h"
using std::nothrow;
namespace BPrivate {
namespace Storage {
bool
is_absolute_path(const char *path)
{
return (path && path[0] == '/');
}
status_t
parse_path(const char *fullPath, int &dirEnd, int &leafStart, int &leafEnd)
{
if (!fullPath)
return B_BAD_VALUE;
int pathLen = strlen(fullPath);
if (pathLen == 0)
return B_BAD_VALUE;
int i = pathLen - 1;
while (i >= 0 && fullPath[i] == '/')
i--;
leafEnd = i + 1;
if (leafEnd == 0) {
dirEnd = leafStart = leafEnd = 1;
return B_OK;
}
while (i >= 0 && fullPath[i] != '/')
i--;
leafStart = i + 1;
if (leafStart == 0) {
dirEnd = leafStart = leafEnd;
return B_OK;
}
while (i >= 0 && fullPath[i] == '/')
i--;
dirEnd = i + 1;
if (dirEnd == 0)
dirEnd = 1;
return B_OK;
}
status_t
parse_path(const char *fullPath, char *dirPath, char *leaf)
{
int leafStart, leafEnd, dirEnd;
status_t error = parse_path(fullPath, dirEnd, leafStart, leafEnd);
if (error != B_OK)
return error;
if (dirEnd >= B_PATH_NAME_LENGTH
|| leafEnd - leafStart >= B_FILE_NAME_LENGTH) {
return B_NAME_TOO_LONG;
}
if (dirPath)
strlcpy(dirPath, fullPath, dirEnd + 1);
if (leaf)
strlcpy(leaf, fullPath + leafStart, leafEnd - leafStart + 1);
return B_OK;
}
static
void
internal_parse_path(const char *fullPath, int &leafStart, int &leafEnd,
int &pathEnd)
{
if (fullPath == NULL)
return;
enum PathParserState { PPS_START, PPS_LEAF } state = PPS_START;
int len = strlen(fullPath);
leafStart = -1;
leafEnd = -1;
pathEnd = -2;
bool loop = true;
for (int pos = len-1; ; pos--) {
if (pos < 0)
break;
switch (state) {
case PPS_START:
if (fullPath[pos] != '/') {
leafEnd = pos;
state = PPS_LEAF;
}
break;
case PPS_LEAF:
if (fullPath[pos] == '/') {
leafStart = pos+1;
pathEnd = pos-1;
loop = false;
}
break;
}
if (!loop)
break;
}
}
status_t
split_path(const char *fullPath, char *&path, char *&leaf)
{
return split_path(fullPath, &path, &leaf);
}
status_t
split_path(const char *fullPath, char **path, char **leaf)
{
if (path)
*path = NULL;
if (leaf)
*leaf = NULL;
if (fullPath == NULL)
return B_BAD_VALUE;
int leafStart, leafEnd, pathEnd, len;
internal_parse_path(fullPath, leafStart, leafEnd, pathEnd);
try {
if (leafEnd == -1) {
if (fullPath[0] == '/') {
if (path) {
*path = new char[2];
(*path)[0] = '/';
(*path)[1] = 0;
}
if (leaf) {
*leaf = new char[2];
(*leaf)[0] = '.';
(*leaf)[1] = 0;
}
return B_OK;
} else if (fullPath[0] == 0) {
if (path) {
*path = new char[1];
(*path)[0] = 0;
}
if (leaf) {
*leaf = new char[2];
(*leaf)[0] = '.';
(*leaf)[1] = 0;
}
return B_OK;
}
} else if (leafStart == -1) {
leafStart = 0;
} else if (pathEnd == -1) {
pathEnd = 0;
}
if (path) {
if (pathEnd == -2) {
*path = new char[2];
(*path)[0] = '.';
(*path)[1] = 0;
} else {
len = pathEnd + 1;
*path = new char[len+1];
memcpy(*path, fullPath, len);
(*path)[len] = 0;
}
}
if (leaf) {
len = leafEnd - leafStart + 1;
*leaf = new char[len+1];
memcpy(*leaf, fullPath + leafStart, len);
(*leaf)[len] = 0;
}
} catch (std::bad_alloc& exception) {
if (path)
delete[] *path;
if (leaf)
delete[] *leaf;
return B_NO_MEMORY;
}
return B_OK;
}
status_t
parse_first_path_component(const char *path, int32& length,
int32& nextComponent)
{
status_t error = (path ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
int32 i = 0;
for (; path[i] != '/' && path[i] != '\0'; i++);
if (i == 0 && path[i] != '\0')
i = 1;
length = i;
for (; path[i] == '/' && path[i] != '\0'; i++);
if (path[i] == '\0')
nextComponent = 0;
else
nextComponent = i;
}
return error;
}
status_t
parse_first_path_component(const char *path, char *&component,
int32& nextComponent)
{
int32 length;
status_t error = parse_first_path_component(path, length, nextComponent);
if (error == B_OK) {
component = new(nothrow) char[length + 1];
if (component) {
strncpy(component, path, length);
component[length] = '\0';
} else
error = B_NO_MEMORY;
}
return error;
}
status_t
check_entry_name(const char *entry)
{
status_t error = (entry ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
if (strlen(entry) >= B_FILE_NAME_LENGTH)
error = B_NAME_TOO_LONG;
}
if (error == B_OK) {
for (int32 i = 0; error == B_OK && entry[i] != '\0'; i++) {
if (entry[i] == '/')
error = B_BAD_VALUE;
}
}
return error;
}
status_t
check_path_name(const char *path)
{
status_t error = (path ? B_OK : B_BAD_VALUE);
if (error == B_BAD_VALUE)
return error;
const char *remainder = path;
int32 length, nextComponent;
do {
error = parse_first_path_component(remainder, length, nextComponent);
if (error == B_OK) {
if (length >= B_FILE_NAME_LENGTH)
error = B_NAME_TOO_LONG;
remainder += nextComponent;
}
} while (error == B_OK && nextComponent != 0);
if (error == B_OK && strlen(path) >= B_PATH_NAME_LENGTH)
error = B_NAME_TOO_LONG;
return error;
}
std::string
to_lower(const char *str)
{
std::string result;
to_lower(str, result);
return result;
}
void
to_lower(const char *str, std::string &result)
{
if (str) {
result = "";
for (int i = 0; i < (int)strlen(str); i++)
result += tolower((unsigned char)str[i]);
} else
result = "(null)";
}
void
to_lower(const char *str, char *result)
{
if (str && result) {
int i;
for (i = 0; i < (int)strlen(str); i++)
result[i] = tolower((unsigned char)str[i]);
result[i] = 0;
}
}
void
to_lower(char *str)
{
to_lower(str, str);
}
void escape_path(const char *str, char *result)
{
if (str && result) {
int32 len = strlen(str);
for (int32 i = 0; i < len; i++) {
char ch = str[i];
char escapeChar = 0;
switch (ch) {
case ' ':
case '\'':
case '"':
case '?':
case '\\':
case '(':
case ')':
case '[':
case ']':
case '*':
case '^':
escapeChar = ch;
break;
}
if (escapeChar) {
*(result++) = '\\';
*(result++) = escapeChar;
} else {
*(result++) = ch;
}
}
*result = 0;
}
}
void escape_path(char *str)
{
if (str) {
char *copy = new(nothrow) char[strlen(str)+1];
if (copy) {
strcpy(copy, str);
escape_path(copy, str);
}
delete [] copy;
}
}
bool
device_is_root_device(dev_t device)
{
return device == 1;
}
void
FDCloser::Close()
{
if (fFD >= 0)
_kern_close(fFD);
fFD = -1;
}
};
};