Files
haiku-beta6/src/servers/package/FSUtils.h
T
Ingo Weinhold 23733521a7 package daemon: Implement writable files handling
* Move Volume::Exception to top level and into own files.
* Add utility class FSUtils, move Volume::RelativePath there and add a
  bunch of FS utility functionality.
* Add FSTransaction, a helper class to record FS operations and revert
  them.
* When activating a package we now extract the writable
  files/directories it declares. The handling is not quite complete:
  - We don't handle merges yet. I.e. the user will have to do that
    manually for now.
  - We don't propagate issues/infos regarding the writable files (e.g.
    that a manual intervention is required) to the user yet.
2013-09-27 00:51:30 +02:00

230 lines
4.8 KiB
C++

/*
* Copyright 2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef FS_UTILS_H
#define FS_UTILS_H
#include <new>
#include <String.h>
#include <EntryOperationEngineBase.h>
class BDirectory;
class BFile;
class BPositionIO;
class BSymLink;
class FSUtils {
public:
typedef ::BPrivate::BEntryOperationEngineBase::Entry Entry;
public:
struct RelativePath {
RelativePath(const char* component1 = NULL,
const char* component2 = NULL, const char* component3 = NULL)
:
fComponentCount(kMaxComponentCount)
{
fComponents[0] = component1;
fComponents[1] = component2;
fComponents[2] = component3;
for (size_t i = 0; i < kMaxComponentCount; i++) {
if (fComponents[i] == NULL) {
fComponentCount = i;
break;
}
}
}
bool IsEmpty() const
{
return fComponentCount == 0;
}
RelativePath HeadPath(size_t componentsToDropCount = 1)
{
RelativePath result;
if (componentsToDropCount < fComponentCount) {
result.fComponentCount
= fComponentCount - componentsToDropCount;
for (size_t i = 0; i < result.fComponentCount; i++)
result.fComponents[i] = fComponents[i];
}
return result;
}
const char* LastComponent() const
{
return fComponentCount > 0
? fComponents[fComponentCount - 1] : NULL;
}
BString ToString() const
{
if (fComponentCount == 0)
return BString();
size_t length = fComponentCount - 1;
for (size_t i = 0; i < fComponentCount; i++)
length += strlen(fComponents[i]);
BString result;
char* buffer = result.LockBuffer(length + 1);
if (buffer == NULL)
return BString();
for (size_t i = 0; i < fComponentCount; i++) {
if (i > 0) {
*buffer = '/';
buffer++;
}
strcpy(buffer, fComponents[i]);
buffer += strlen(buffer);
}
return result.UnlockBuffer();
}
private:
static const size_t kMaxComponentCount = 3;
const char* fComponents[kMaxComponentCount];
size_t fComponentCount;
};
// throwing std::bad_alloc()
class Path {
public:
Path(const char* path)
:
fPath(path)
{
if (fPath.IsEmpty()) {
if (path[0] != '\0')
throw std::bad_alloc();
} else {
// remove duplicate '/'s
char* buffer = fPath.LockBuffer(fPath.Length());
int32 k = 0;
for (int32 i = 0; buffer[i] != '\0'; i++) {
if (buffer[i] == '/' && k > 0 && buffer[k - 1] == '/')
continue;
buffer[k++] = buffer[i];
}
// remove trailing '/'
if (k > 1 && buffer[k - 1] == '/')
k--;
fPath.LockBuffer(k);
}
}
Path& AppendComponent(const char* component)
{
if (fPath.IsEmpty()) {
fPath = component;
if (fPath.IsEmpty() && component[0] != '\0')
throw std::bad_alloc();
} else {
int32 length = fPath.Length();
if (fPath[length - 1] != '/') {
fPath += '/';
if (++length != fPath.Length())
throw std::bad_alloc();
}
fPath += component;
if (fPath.Length() <= length)
throw std::bad_alloc();
}
return *this;
}
Path& RemoveLastComponent()
{
int32 index = fPath.FindLast('/');
if (index < 0 || (index == 0 && fPath.Length() == 1))
fPath.Truncate(0);
else if (index == 0)
fPath.Truncate(1);
else
fPath.Truncate(index - 1);
return *this;
}
const char* Leaf() const
{
int32 index = fPath.FindLast('/');
if (index < 0 || (index == 0 && fPath.Length() == 1))
return fPath.String();
return fPath.String() + index + 1;
}
const BString ToString() const
{
return fPath;
}
const char* ToCString() const
{
return fPath.String();
}
operator const BString&() const
{
return fPath;
}
operator const char*() const
{
return fPath;
}
private:
BString fPath;
};
public:
static BString ShellEscapeString(const BString& string);
// throw std::bad_alloc
static status_t OpenSubDirectory(BDirectory& baseDirectory,
const RelativePath& path, bool create,
BDirectory& _directory);
static status_t CompareFileContent(const Entry& entry1,
const Entry& entry2, bool& _equal);
static status_t CompareFileContent(BPositionIO& content1,
BPositionIO& content2, bool& _equal);
static status_t CompareSymLinks(const Entry& entry1,
const Entry& entry2, bool& _equal);
static status_t CompareSymLinks(BSymLink& symLink1,
BSymLink& symLink2, bool& _equal);
static status_t ExtractPackageContent(const Entry& packageEntry,
const char* contentPath,
const Entry& targetDirectoryEntry);
static status_t ExtractPackageContent(const char* packagePath,
const char* contentPath,
const char* targetDirectoryPath);
private:
static status_t _OpenFile(const Entry& entry, BFile& file);
static status_t _OpenSymLink(const Entry& entry,
BSymLink& symLink);
};
#endif // FS_UTILS_H