123733521SIngo Weinhold/*
223733521SIngo Weinhold * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
323733521SIngo Weinhold * Distributed under the terms of the MIT License.
423733521SIngo Weinhold */
523733521SIngo Weinhold#ifndef FS_UTILS_H
623733521SIngo Weinhold#define FS_UTILS_H
723733521SIngo Weinhold
823733521SIngo Weinhold
923733521SIngo Weinhold#include <new>
1023733521SIngo Weinhold
1123733521SIngo Weinhold#include <String.h>
1223733521SIngo Weinhold
1323733521SIngo Weinhold#include <EntryOperationEngineBase.h>
1423733521SIngo Weinhold
1523733521SIngo Weinhold
1623733521SIngo Weinholdclass BDirectory;
1723733521SIngo Weinholdclass BFile;
1823733521SIngo Weinholdclass BPositionIO;
1923733521SIngo Weinholdclass BSymLink;
2023733521SIngo Weinhold
2123733521SIngo Weinhold
2223733521SIngo Weinholdclass FSUtils {
2323733521SIngo Weinholdpublic:
2423733521SIngo Weinhold	typedef ::BPrivate::BEntryOperationEngineBase::Entry Entry;
2523733521SIngo Weinhold
2623733521SIngo Weinholdpublic:
2723733521SIngo Weinhold	struct RelativePath {
2823733521SIngo Weinhold		RelativePath(const char* component1 = NULL,
2923733521SIngo Weinhold			const char* component2 = NULL, const char* component3 = NULL)
3023733521SIngo Weinhold			:
3123733521SIngo Weinhold			fComponentCount(kMaxComponentCount)
3223733521SIngo Weinhold		{
3323733521SIngo Weinhold			fComponents[0] = component1;
3423733521SIngo Weinhold			fComponents[1] = component2;
3523733521SIngo Weinhold			fComponents[2] = component3;
3623733521SIngo Weinhold
3723733521SIngo Weinhold			for (size_t i = 0; i < kMaxComponentCount; i++) {
3823733521SIngo Weinhold				if (fComponents[i] == NULL) {
3923733521SIngo Weinhold					fComponentCount = i;
4023733521SIngo Weinhold					break;
4123733521SIngo Weinhold				}
4223733521SIngo Weinhold			}
4323733521SIngo Weinhold		}
4423733521SIngo Weinhold
4523733521SIngo Weinhold		bool IsEmpty() const
4623733521SIngo Weinhold		{
4723733521SIngo Weinhold			return fComponentCount == 0;
4823733521SIngo Weinhold		}
4923733521SIngo Weinhold
5023733521SIngo Weinhold		RelativePath HeadPath(size_t componentsToDropCount = 1)
5123733521SIngo Weinhold		{
5223733521SIngo Weinhold			RelativePath result;
5323733521SIngo Weinhold			if (componentsToDropCount < fComponentCount) {
5423733521SIngo Weinhold				result.fComponentCount
5523733521SIngo Weinhold					= fComponentCount - componentsToDropCount;
5623733521SIngo Weinhold				for (size_t i = 0; i < result.fComponentCount; i++)
5723733521SIngo Weinhold					result.fComponents[i] = fComponents[i];
5823733521SIngo Weinhold			}
5923733521SIngo Weinhold
6023733521SIngo Weinhold			return result;
6123733521SIngo Weinhold		}
6223733521SIngo Weinhold
6323733521SIngo Weinhold		const char* LastComponent() const
6423733521SIngo Weinhold		{
6523733521SIngo Weinhold			return fComponentCount > 0
6623733521SIngo Weinhold				? fComponents[fComponentCount - 1] : NULL;
6723733521SIngo Weinhold		}
6823733521SIngo Weinhold
6923733521SIngo Weinhold		BString ToString() const
7023733521SIngo Weinhold		{
7123733521SIngo Weinhold			if (fComponentCount == 0)
7223733521SIngo Weinhold				return BString();
7323733521SIngo Weinhold
7423733521SIngo Weinhold			size_t length = fComponentCount - 1;
7523733521SIngo Weinhold			for (size_t i = 0; i < fComponentCount; i++)
7623733521SIngo Weinhold				length += strlen(fComponents[i]);
7723733521SIngo Weinhold
7823733521SIngo Weinhold			BString result;
7923733521SIngo Weinhold			char* buffer = result.LockBuffer(length + 1);
8023733521SIngo Weinhold			if (buffer == NULL)
8123733521SIngo Weinhold				return BString();
8223733521SIngo Weinhold
8323733521SIngo Weinhold			for (size_t i = 0; i < fComponentCount; i++) {
8423733521SIngo Weinhold				if (i > 0) {
8523733521SIngo Weinhold					*buffer = '/';
8623733521SIngo Weinhold					buffer++;
8723733521SIngo Weinhold				}
8823733521SIngo Weinhold				strcpy(buffer, fComponents[i]);
8923733521SIngo Weinhold				buffer += strlen(buffer);
9023733521SIngo Weinhold			}
9123733521SIngo Weinhold
9223733521SIngo Weinhold			return result.UnlockBuffer();
9323733521SIngo Weinhold		}
9423733521SIngo Weinhold
9523733521SIngo Weinhold	private:
9623733521SIngo Weinhold		static const size_t	kMaxComponentCount = 3;
9723733521SIngo Weinhold
9823733521SIngo Weinhold		const char*	fComponents[kMaxComponentCount];
9923733521SIngo Weinhold		size_t		fComponentCount;
10023733521SIngo Weinhold	};
10123733521SIngo Weinhold
10223733521SIngo Weinhold	// throwing std::bad_alloc()
10323733521SIngo Weinhold	class Path {
10423733521SIngo Weinhold	public:
10523733521SIngo Weinhold		Path(const char* path)
10623733521SIngo Weinhold			:
10723733521SIngo Weinhold			fPath(path)
10823733521SIngo Weinhold		{
10923733521SIngo Weinhold			if (fPath.IsEmpty()) {
11023733521SIngo Weinhold				if (path[0] != '\0')
11123733521SIngo Weinhold					throw std::bad_alloc();
11223733521SIngo Weinhold			} else {
11323733521SIngo Weinhold				// remove duplicate '/'s
11423733521SIngo Weinhold				char* buffer = fPath.LockBuffer(fPath.Length());
11523733521SIngo Weinhold				int32 k = 0;
11623733521SIngo Weinhold				for (int32 i = 0; buffer[i] != '\0'; i++) {
11723733521SIngo Weinhold					if (buffer[i] == '/' && k > 0 && buffer[k - 1] == '/')
11823733521SIngo Weinhold						continue;
11923733521SIngo Weinhold					buffer[k++] = buffer[i];
12023733521SIngo Weinhold				}
12123733521SIngo Weinhold
12223733521SIngo Weinhold				// remove trailing '/'
12323733521SIngo Weinhold				if (k > 1 && buffer[k - 1] == '/')
12423733521SIngo Weinhold					k--;
12523733521SIngo Weinhold
12623733521SIngo Weinhold				fPath.LockBuffer(k);
12723733521SIngo Weinhold			}
12823733521SIngo Weinhold		}
12923733521SIngo Weinhold
13023733521SIngo Weinhold		Path& AppendComponent(const char* component)
13123733521SIngo Weinhold		{
13223733521SIngo Weinhold			if (fPath.IsEmpty()) {
13323733521SIngo Weinhold				fPath = component;
13423733521SIngo Weinhold				if (fPath.IsEmpty() && component[0] != '\0')
13523733521SIngo Weinhold					throw std::bad_alloc();
13623733521SIngo Weinhold			} else {
13723733521SIngo Weinhold				int32 length = fPath.Length();
13823733521SIngo Weinhold				if (fPath[length - 1] != '/') {
13923733521SIngo Weinhold					fPath += '/';
14023733521SIngo Weinhold					if (++length != fPath.Length())
14123733521SIngo Weinhold						throw std::bad_alloc();
14223733521SIngo Weinhold				}
14323733521SIngo Weinhold
14423733521SIngo Weinhold				fPath += component;
14523733521SIngo Weinhold				if (fPath.Length() <= length)
14623733521SIngo Weinhold					throw std::bad_alloc();
14723733521SIngo Weinhold			}
14823733521SIngo Weinhold
14923733521SIngo Weinhold			return *this;
15023733521SIngo Weinhold		}
15123733521SIngo Weinhold
15223733521SIngo Weinhold		Path& RemoveLastComponent()
15323733521SIngo Weinhold		{
15423733521SIngo Weinhold			int32 index = fPath.FindLast('/');
15523733521SIngo Weinhold			if (index < 0 || (index == 0 && fPath.Length() == 1))
15623733521SIngo Weinhold				fPath.Truncate(0);
15723733521SIngo Weinhold			else if (index == 0)
15823733521SIngo Weinhold				fPath.Truncate(1);
15923733521SIngo Weinhold			else
160579efee7SJessica Hamilton				fPath.Truncate(index);
16123733521SIngo Weinhold			return *this;
16223733521SIngo Weinhold		}
16323733521SIngo Weinhold
16423733521SIngo Weinhold		const char* Leaf() const
16523733521SIngo Weinhold		{
16623733521SIngo Weinhold			int32 index = fPath.FindLast('/');
16723733521SIngo Weinhold			if (index < 0 || (index == 0 && fPath.Length() == 1))
16823733521SIngo Weinhold				return fPath.String();
16923733521SIngo Weinhold			return fPath.String() + index + 1;
17023733521SIngo Weinhold		}
17123733521SIngo Weinhold
17223733521SIngo Weinhold		const BString ToString() const
17323733521SIngo Weinhold		{
17423733521SIngo Weinhold			return fPath;
17523733521SIngo Weinhold		}
17623733521SIngo Weinhold
17723733521SIngo Weinhold		const char* ToCString() const
17823733521SIngo Weinhold		{
17923733521SIngo Weinhold			return fPath.String();
18023733521SIngo Weinhold		}
18123733521SIngo Weinhold
18223733521SIngo Weinhold		operator const BString&() const
18323733521SIngo Weinhold		{
18423733521SIngo Weinhold			return fPath;
18523733521SIngo Weinhold		}
18623733521SIngo Weinhold
18723733521SIngo Weinhold		operator const char*() const
18823733521SIngo Weinhold		{
18923733521SIngo Weinhold			return fPath;
19023733521SIngo Weinhold		}
19123733521SIngo Weinhold
19223733521SIngo Weinhold	private:
19323733521SIngo Weinhold		BString	fPath;
19423733521SIngo Weinhold	};
19523733521SIngo Weinhold
19623733521SIngo Weinholdpublic:
19723733521SIngo Weinhold	static	BString				ShellEscapeString(const BString& string);
19823733521SIngo Weinhold									// throw std::bad_alloc
19923733521SIngo Weinhold
2000fea5e93SIngo Weinhold	static	status_t			OpenSubDirectory(
2010fea5e93SIngo Weinhold									const BDirectory& baseDirectory,
20223733521SIngo Weinhold									const RelativePath& path, bool create,
20323733521SIngo Weinhold									BDirectory& _directory);
20423733521SIngo Weinhold
20523733521SIngo Weinhold	static	status_t			CompareFileContent(const Entry& entry1,
20623733521SIngo Weinhold									const Entry& entry2, bool& _equal);
20723733521SIngo Weinhold	static	status_t			CompareFileContent(BPositionIO& content1,
20823733521SIngo Weinhold									BPositionIO& content2, bool& _equal);
20923733521SIngo Weinhold
21023733521SIngo Weinhold	static	status_t			CompareSymLinks(const Entry& entry1,
21123733521SIngo Weinhold									const Entry& entry2, bool& _equal);
21223733521SIngo Weinhold	static	status_t			CompareSymLinks(BSymLink& symLink1,
21323733521SIngo Weinhold									BSymLink& symLink2, bool& _equal);
21423733521SIngo Weinhold
21523733521SIngo Weinhold	static	status_t			ExtractPackageContent(const Entry& packageEntry,
21623733521SIngo Weinhold									const char* contentPath,
21723733521SIngo Weinhold									const Entry& targetDirectoryEntry);
21823733521SIngo Weinhold	static	status_t			ExtractPackageContent(const char* packagePath,
21923733521SIngo Weinhold									const char* contentPath,
22023733521SIngo Weinhold									const char* targetDirectoryPath);
22123733521SIngo Weinhold
22223733521SIngo Weinholdprivate:
22323733521SIngo Weinhold	static	status_t			_OpenFile(const Entry& entry, BFile& file);
22423733521SIngo Weinhold	static	status_t			_OpenSymLink(const Entry& entry,
22523733521SIngo Weinhold									BSymLink& symLink);
22623733521SIngo Weinhold};
22723733521SIngo Weinhold
22823733521SIngo Weinhold
22923733521SIngo Weinhold
23023733521SIngo Weinhold#endif	// FS_UTILS_H
231