* Flatten() would create an invalid entry ref if the path did not exist, or the

path was not yet initialized. It will now fail instead.
* Got rid of EBadInput - _MustNormalize() can now return an error code instead.
* Style cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30787 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-05-18 09:09:23 +00:00
parent 2ae482f582
commit 49fb9a2eab
2 changed files with 306 additions and 280 deletions
+54 -78
View File
@@ -1,103 +1,79 @@
//---------------------------------------------------------------------- /*
// This software is part of the OpenBeOS distribution and is covered * Copyright 2002-2009, Haiku, Inc. All Rights Reserved.
// by the OpenBeOS license. * Distributed under the terms of the MIT License.
//--------------------------------------------------------------------- */
/*!
\file Path.h
BPath interface declaration.
*/
#ifndef _PATH_H #ifndef _PATH_H
#define _PATH_H #define _PATH_H
#include <Flattenable.h>
#include <StorageDefs.h>
#include <Message.h> /* for convenience, as in R5 */
#ifdef USE_OPENBEOS_NAMESPACE #include <Flattenable.h>
namespace OpenBeOS { #include <Message.h>
#endif #include <StorageDefs.h>
// Forward declarations // Forward declarations
class BDirectory; class BDirectory;
class BEntry; class BEntry;
struct entry_ref; struct entry_ref;
/*!
\class BPath
\brief An absolute pathname wrapper class
Provides a convenient means of managing pathnames.
\author <a href='mailto:[email protected]'>Ingo Weinhold</a>
\author <a href="mailto:[email protected]">Tyler Dauwalder</a>
\version 0.0.0
*/
class BPath : public BFlattenable { class BPath : public BFlattenable {
public: public:
BPath();
BPath(const BPath& path);
BPath(const entry_ref* ref);
BPath(const BEntry* entry);
BPath(const char* dir, const char* leaf = NULL,
bool normalize = false);
BPath(const BDirectory* dir, const char* leaf,
bool normalize = false);
BPath(); virtual ~BPath();
BPath(const BPath &path);
BPath(const entry_ref *ref);
BPath(const BEntry *entry);
BPath(const char *dir, const char *leaf = NULL, bool normalize = false);
BPath(const BDirectory *dir, const char *leaf, bool normalize = false);
virtual ~BPath();
status_t InitCheck() const; status_t InitCheck() const;
status_t SetTo(const entry_ref* ref);
status_t SetTo(const BEntry* entry);
status_t SetTo(const char* path, const char* leaf = NULL,
bool normalize = false);
status_t SetTo(const BDirectory* dir, const char* path,
bool normalize = false);
void Unset();
status_t Append(const char* path, bool normalize = false);
const char* Path() const;
const char* Leaf() const;
status_t GetParent(BPath* path) const;
bool operator==(const BPath& item) const;
bool operator==(const char* path) const;
bool operator!=(const BPath& item) const;
bool operator!=(const char* path) const;
BPath& operator=(const BPath& item);
BPath& operator=(const char* path);
status_t SetTo(const entry_ref *ref);
status_t SetTo(const BEntry *entry);
status_t SetTo(const char *path, const char *leaf = NULL,
bool normalize = false);
status_t SetTo(const BDirectory *dir, const char *path,
bool normalize = false);
void Unset();
status_t Append(const char *path, bool normalize = false);
const char *Path() const;
const char *Leaf() const;
status_t GetParent(BPath *path) const;
bool operator==(const BPath &item) const;
bool operator==(const char *path) const;
bool operator!=(const BPath &item) const;
bool operator!=(const char *path) const;
BPath& operator=(const BPath &item);
BPath& operator=(const char *path);
// BFlattenable protocol // BFlattenable protocol
virtual bool IsFixedSize() const; virtual bool IsFixedSize() const;
virtual type_code TypeCode() const; virtual type_code TypeCode() const;
virtual ssize_t FlattenedSize() const; virtual ssize_t FlattenedSize() const;
virtual status_t Flatten(void *buffer, ssize_t size) const; virtual status_t Flatten(void* buffer, ssize_t size) const;
virtual bool AllowsTypeCode(type_code code) const; virtual bool AllowsTypeCode(type_code code) const;
virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); virtual status_t Unflatten(type_code code, const void* buffer,
ssize_t size);
private: private:
virtual void _WarPath1(); virtual void _WarPath1();
virtual void _WarPath2(); virtual void _WarPath2();
virtual void _WarPath3(); virtual void _WarPath3();
uint32 _warData[4]; status_t _SetPath(const char* path);
static bool _MustNormalize(const char* path, status_t* _error);
char *fName; uint32 _reserved[4];
status_t fCStatus;
class EBadInput { }; char* fName;
status_t fCStatus;
status_t set_path(const char *path);
static bool MustNormalize(const char *path);
}; };
#ifdef USE_OPENBEOS_NAMESPACE
}; // namespace OpenBeOS
#endif
#endif // _PATH_H #endif // _PATH_H
+252 -202
View File
@@ -1,15 +1,21 @@
//---------------------------------------------------------------------- /*
// This software is part of the OpenBeOS distribution and is covered * Copyright 2002-2009, Haiku Inc.
// by the OpenBeOS license. * Distributed under the terms of the MIT License.
//--------------------------------------------------------------------- *
* Authors:
* Tyler Dauwalder
* Ingo Weinhold, [email protected]
*/
/*! /*!
\file Path.cpp \file Path.cpp
BPath implementation. BPath implementation.
*/ */
#include <Path.h>
#include <new> #include <new>
#include <Path.h>
#include <Directory.h> #include <Directory.h>
#include <Entry.h> #include <Entry.h>
#include <StorageDefs.h> #include <StorageDefs.h>
@@ -21,66 +27,74 @@
using namespace std; using namespace std;
#ifdef USE_OPENBEOS_NAMESPACE
using namespace OpenBeOS;
#endif
//! Creates an uninitialized BPath object. //! Creates an uninitialized BPath object.
BPath::BPath() BPath::BPath()
: fName(NULL), :
fCStatus(B_NO_INIT) fName(NULL),
fCStatus(B_NO_INIT)
{ {
} }
//! Creates a copy of the given BPath object.
/*! \param path the object to be copied /*! Creates a copy of the given BPath object.
\param path the object to be copied
*/ */
BPath::BPath(const BPath &path) BPath::BPath(const BPath& path)
: fName(NULL), :
fCStatus(B_NO_INIT) fName(NULL),
fCStatus(B_NO_INIT)
{ {
*this = path; *this = path;
} }
/*! \brief Creates a BPath object and initializes it to the filesystem entry /*! \brief Creates a BPath object and initializes it to the filesystem entry
specified by the given entry_ref struct. specified by the given entry_ref struct.
\param ref the entry_ref \param ref the entry_ref
*/ */
BPath::BPath(const entry_ref *ref) BPath::BPath(const entry_ref* ref)
: fName(NULL), :
fCStatus(B_NO_INIT) fName(NULL),
fCStatus(B_NO_INIT)
{ {
SetTo(ref); SetTo(ref);
} }
/*! Creates a BPath object and initializes it to the filesystem entry
/*! \brief Creates a BPath object and initializes it to the filesystem entry
specified by the given BEntry object. specified by the given BEntry object.
\param entry the BEntry object \param entry the BEntry object
*/ */
BPath::BPath(const BEntry *entry) BPath::BPath(const BEntry* entry)
: fName(NULL), :
fCStatus(B_NO_INIT) fName(NULL),
fCStatus(B_NO_INIT)
{ {
SetTo(entry); SetTo(entry);
} }
/*! \brief Creates a BPath object and initializes it to the specified path or /*! \brief Creates a BPath object and initializes it to the specified path or
path and filename combination. path and filename combination.
\param dir The base component of the pathname. May be absolute or relative. \param dir The base component of the pathname. May be absolute or relative.
If relative, it is reckoned off the current working directory. If relative, it is reckoned off the current working directory.
\param leaf The (optional) leaf component of the pathname. Must be \param leaf The (optional) leaf component of the pathname. Must be
relative. The value of leaf is concatenated to the end of \a dir relative. The value of leaf is concatenated to the end of \a dir
(a "/" will be added as a separator, if necessary). (a "/" will be added as a separator, if necessary).
\param normalize boolean flag used to force normalization; normalization \param normalize boolean flag used to force normalization; normalization
may occur even if false (see \ref MustNormalize). may occur even if false (see \ref _MustNormalize).
*/ */
BPath::BPath(const char *dir, const char *leaf, bool normalize) BPath::BPath(const char* dir, const char* leaf, bool normalize)
: fName(NULL), :
fCStatus(B_NO_INIT) fName(NULL),
fCStatus(B_NO_INIT)
{ {
SetTo(dir, leaf, normalize); SetTo(dir, leaf, normalize);
} }
/*! \brief Creates a BPath object and initializes it to the specified directory /*! \brief Creates a BPath object and initializes it to the specified directory
and filename combination. and filename combination.
\param dir Refers to the directory that provides the base component of the \param dir Refers to the directory that provides the base component of the
@@ -89,23 +103,26 @@ BPath::BPath(const char *dir, const char *leaf, bool normalize)
relative. The value of leaf is concatenated to the end of \a dir relative. The value of leaf is concatenated to the end of \a dir
(a "/" will be added as a separator, if necessary). (a "/" will be added as a separator, if necessary).
\param normalize boolean flag used to force normalization; normalization \param normalize boolean flag used to force normalization; normalization
may occur even if false (see \ref MustNormalize). may occur even if false (see \ref _MustNormalize).
*/ */
BPath::BPath(const BDirectory *dir, const char *leaf, bool normalize) BPath::BPath(const BDirectory* dir, const char* leaf, bool normalize)
: fName(NULL), :
fCStatus(B_NO_INIT) fName(NULL),
fCStatus(B_NO_INIT)
{ {
SetTo(dir, leaf, normalize); SetTo(dir, leaf, normalize);
} }
//! Destroys the BPath object and frees any of its associated resources. //! Destroys the BPath object and frees any of its associated resources.
BPath::~BPath() BPath::~BPath()
{ {
Unset(); Unset();
} }
//! Returns the status of the most recent construction or SetTo() call.
/*! \return \c B_OK, if the BPath object is properly initialized, an error /*! \brief Returns the status of the most recent construction or SetTo() call.
\return \c B_OK, if the BPath object is properly initialized, an error
code otherwise. code otherwise.
*/ */
status_t status_t
@@ -114,6 +131,7 @@ BPath::InitCheck() const
return fCStatus; return fCStatus;
} }
/*! \brief Reinitializes the object to the filesystem entry specified by the /*! \brief Reinitializes the object to the filesystem entry specified by the
given entry_ref struct. given entry_ref struct.
\param ref the entry_ref \param ref the entry_ref
@@ -124,21 +142,24 @@ BPath::InitCheck() const
- other error codes. - other error codes.
*/ */
status_t status_t
BPath::SetTo(const entry_ref *ref) BPath::SetTo(const entry_ref* ref)
{ {
Unset(); Unset();
if (!ref) if (!ref)
return (fCStatus = B_BAD_VALUE); return fCStatus = B_BAD_VALUE;
char path[B_PATH_NAME_LENGTH]; char path[B_PATH_NAME_LENGTH];
status_t error = _kern_entry_ref_to_path(ref->device, ref->directory, fCStatus = _kern_entry_ref_to_path(ref->device, ref->directory,
ref->name, path, sizeof(path)); ref->name, path, sizeof(path));
if (error != B_OK) if (fCStatus != B_OK)
return (fCStatus = error); return fCStatus;
fCStatus = set_path(path); // the path is already normalized
fCStatus = _SetPath(path);
// the path is already normalized
return fCStatus; return fCStatus;
} }
/*! \brief Reinitializes the object to the specified filesystem entry. /*! \brief Reinitializes the object to the specified filesystem entry.
\param entry the BEntry \param entry the BEntry
\return \return
@@ -148,25 +169,27 @@ BPath::SetTo(const entry_ref *ref)
- other error codes. - other error codes.
*/ */
status_t status_t
BPath::SetTo(const BEntry *entry) BPath::SetTo(const BEntry* entry)
{ {
Unset(); Unset();
status_t error = (entry ? B_OK : B_BAD_VALUE); if (entry == NULL)
return B_BAD_VALUE;
entry_ref ref; entry_ref ref;
if (error == B_OK) fCStatus = entry->GetRef(&ref);
error = entry->GetRef(&ref); if (fCStatus == B_OK)
if (error == B_OK) fCStatus = SetTo(&ref);
error = SetTo(&ref);
fCStatus = error; return fCStatus;
return error;
} }
/*! \brief Reinitializes the object to the specified path or path and file /*! \brief Reinitializes the object to the specified path or path and file
name combination. name combination.
\param path the path name \param path the path name
\param leaf the leaf name (may be \c NULL) \param leaf the leaf name (may be \c NULL)
\param normalize boolean flag used to force normalization; normalization \param normalize boolean flag used to force normalization; normalization
may occur even if false (see \ref MustNormalize). may occur even if false (see \ref _MustNormalize).
\return \return
- \c B_OK: The initialization was successful. - \c B_OK: The initialization was successful.
- \c B_BAD_VALUE: \c NULL \a path or absolute \a leaf. - \c B_BAD_VALUE: \c NULL \a path or absolute \a leaf.
@@ -175,7 +198,7 @@ BPath::SetTo(const BEntry *entry)
\note \code path.SetTo(path.Path(), "new leaf") \endcode is safe. \note \code path.SetTo(path.Path(), "new leaf") \endcode is safe.
*/ */
status_t status_t
BPath::SetTo(const char *path, const char *leaf, bool normalize) BPath::SetTo(const char* path, const char* leaf, bool normalize)
{ {
status_t error = (path ? B_OK : B_BAD_VALUE); status_t error = (path ? B_OK : B_BAD_VALUE);
if (error == B_OK && leaf && BPrivate::Storage::is_absolute_path(leaf)) if (error == B_OK && leaf && BPrivate::Storage::is_absolute_path(leaf))
@@ -207,13 +230,9 @@ BPath::SetTo(const char *path, const char *leaf, bool normalize)
} }
} }
// check, if necessary to normalize // check, if necessary to normalize
if (error == B_OK && !normalize) { if (error == B_OK && !normalize)
try { normalize = normalize || _MustNormalize(newPath, &error);
normalize = normalize || MustNormalize(newPath);
} catch (BPath::EBadInput) {
error = B_BAD_VALUE;
}
}
// normalize the path, if necessary, otherwise just set it // normalize the path, if necessary, otherwise just set it
if (error == B_OK) { if (error == B_OK) {
if (normalize) { if (normalize) {
@@ -223,7 +242,7 @@ BPath::SetTo(const char *path, const char *leaf, bool normalize)
if (error == B_OK) if (error == B_OK)
return SetTo(&entry); return SetTo(&entry);
} else } else
error = set_path(newPath); error = _SetPath(newPath);
} }
} }
// cleanup, if something went wrong // cleanup, if something went wrong
@@ -232,14 +251,15 @@ BPath::SetTo(const char *path, const char *leaf, bool normalize)
fCStatus = error; fCStatus = error;
return error; return error;
} }
/*! \brief Reinitializes the object to the specified directory and relative /*! \brief Reinitializes the object to the specified directory and relative
path combination. path combination.
\param dir Refers to the directory that provides the base component of the \param dir Refers to the directory that provides the base component of the
pathname. pathname.
\param path the relative path name (may be \c NULL) \param path the relative path name (may be \c NULL)
\param normalize boolean flag used to force normalization; normalization \param normalize boolean flag used to force normalization; normalization
may occur even if false (see \ref MustNormalize). may occur even if false (see \ref _MustNormalize).
\return \return
- \c B_OK: The initialization was successful. - \c B_OK: The initialization was successful.
- \c B_BAD_VALUE: \c NULL \a dir or absolute \a path. - \c B_BAD_VALUE: \c NULL \a dir or absolute \a path.
@@ -247,7 +267,7 @@ BPath::SetTo(const char *path, const char *leaf, bool normalize)
- other error codes. - other error codes.
*/ */
status_t status_t
BPath::SetTo(const BDirectory *dir, const char *path, bool normalize) BPath::SetTo(const BDirectory* dir, const char* path, bool normalize)
{ {
status_t error = (dir && dir->InitCheck() == B_OK ? B_OK : B_BAD_VALUE); status_t error = (dir && dir->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
// get the path of the BDirectory // get the path of the BDirectory
@@ -265,23 +285,25 @@ BPath::SetTo(const BDirectory *dir, const char *path, bool normalize)
fCStatus = error; fCStatus = error;
return error; return error;
} }
/*! \brief Returns the object to an uninitialized state. The object frees any /*! \brief Returns the object to an uninitialized state. The object frees any
resources it allocated and marks itself as uninitialized. resources it allocated and marks itself as uninitialized.
*/ */
void void
BPath::Unset() BPath::Unset()
{ {
set_path(NULL); _SetPath(NULL);
fCStatus = B_NO_INIT; fCStatus = B_NO_INIT;
} }
/*! \brief Appends the given (relative) path to the end of the current path. /*! \brief Appends the given (relative) path to the end of the current path.
This call fails if the path is absolute or the object to which you're This call fails if the path is absolute or the object to which you're
appending is uninitialized. appending is uninitialized.
\param path relative pathname to append to current path (may be \c NULL). \param path relative pathname to append to current path (may be \c NULL).
\param normalize boolean flag used to force normalization; normalization \param normalize boolean flag used to force normalization; normalization
may occur even if false (see \ref MustNormalize). may occur even if false (see \ref _MustNormalize).
\return \return
- \c B_OK: The initialization was successful. - \c B_OK: The initialization was successful.
- \c B_BAD_VALUE: The object is not properly initialized. - \c B_BAD_VALUE: The object is not properly initialized.
@@ -289,7 +311,7 @@ BPath::Unset()
- other error codes. - other error codes.
*/ */
status_t status_t
BPath::Append(const char *path, bool normalize) BPath::Append(const char* path, bool normalize)
{ {
status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
if (error == B_OK) if (error == B_OK)
@@ -299,41 +321,45 @@ BPath::Append(const char *path, bool normalize)
fCStatus = error; fCStatus = error;
return error; return error;
} }
//! Returns the object's complete path name.
/*! \return /*! \brief Returns the object's complete path name.
\return
- the object's path name, or - the object's path name, or
- \c NULL, if it is not properly initialized. - \c NULL, if it is not properly initialized.
*/ */
const char * const char*
BPath::Path() const BPath::Path() const
{ {
return fName; return fName;
} }
//! Returns the leaf portion of the object's path name.
/*! The leaf portion is defined as the string after the last \c '/'. For /*! \brief Returns the leaf portion of the object's path name.
The leaf portion is defined as the string after the last \c '/'. For
the root path (\c "/") it is the empty string (\c ""). the root path (\c "/") it is the empty string (\c "").
\return \return
- the leaf portion of the object's path name, or - the leaf portion of the object's path name, or
- \c NULL, if it is not properly initialized. - \c NULL, if it is not properly initialized.
*/ */
const char * const char*
BPath::Leaf() const BPath::Leaf() const
{ {
const char *result = NULL; if (InitCheck() != B_OK)
if (InitCheck() == B_OK) { return NULL;
result = fName + strlen(fName);
// There should be no need for the second condition, since we deal const char* result = fName + strlen(fName);
// with absolute paths only and those contain at least one '/'. // There should be no need for the second condition, since we deal
// However, it doesn't harm. // with absolute paths only and those contain at least one '/'.
while (*result != '/' && result > fName) // However, it doesn't harm.
result--; while (*result != '/' && result > fName)
result++; result--;
} result++;
return result; return result;
} }
/*! \brief Calls the argument's SetTo() method with the name of the /*! \brief Calls the argument's SetTo() method with the name of the
object's parent directory. object's parent directory.
No normalization is done. No normalization is done.
@@ -346,96 +372,107 @@ BPath::Leaf() const
- other error code returned by SetTo(). - other error code returned by SetTo().
*/ */
status_t status_t
BPath::GetParent(BPath *path) const BPath::GetParent(BPath* path) const
{ {
status_t error = (path ? B_OK : B_BAD_VALUE); if (path == NULL)
if (error == B_OK) return B_BAD_VALUE;
error = InitCheck();
if (error == B_OK) { status_t error = InitCheck();
int32 len = strlen(fName); if (error != B_OK)
if (len == 1) // handle "/" return error;
error = B_ENTRY_NOT_FOUND;
else { int32 length = strlen(fName);
char parentPath[B_PATH_NAME_LENGTH]; if (length == 1) {
len--; // handle "/" (path is supposed to be absolute)
while (fName[len] != '/' && len > 0) return B_ENTRY_NOT_FOUND;
len--;
if (len == 0) // parent dir is "/"
len++;
memcpy(parentPath, fName, len);
parentPath[len] = 0;
error = path->SetTo(parentPath);
}
} }
return error;
char parentPath[B_PATH_NAME_LENGTH];
length--;
while (fName[length] != '/' && length > 0)
length--;
if (length == 0) {
// parent dir is "/"
length++;
}
memcpy(parentPath, fName, length);
parentPath[length] = '\0';
return path->SetTo(parentPath);
} }
//! Performs a simple (string-wise) comparison of paths.
/*! No normalization takes place! Uninitialized BPath objects are considered /*! \brief Performs a simple (string-wise) comparison of paths.
No normalization takes place! Uninitialized BPath objects are considered
to be equal. to be equal.
\param item the BPath object to be compared with \param item the BPath object to be compared with
\return \c true, if the path names are equal, \c false otherwise. \return \c true, if the path names are equal, \c false otherwise.
*/ */
bool bool
BPath::operator==(const BPath &item) const BPath::operator==(const BPath& item) const
{ {
return (*this == item.Path()); return *this == item.Path();
} }
//! Performs a simple (string-wise) comparison of paths.
/*! No normalization takes place! /*! \brief Performs a simple (string-wise) comparison of paths.
No normalization takes place!
\param path the path name to be compared with \param path the path name to be compared with
\return \c true, if the path names are equal, \c false otherwise. \return \c true, if the path names are equal, \c false otherwise.
*/ */
bool bool
BPath::operator==(const char *path) const BPath::operator==(const char* path) const
{ {
return ((InitCheck() != B_OK && path == NULL) return (InitCheck() != B_OK && path == NULL)
|| (fName != NULL && path != NULL && strcmp(fName, path) == 0)); || (fName != NULL && path != NULL && strcmp(fName, path) == 0);
} }
//! Performs a simple (string-wise) comparison of paths.
/*! No normalization takes place! Uninitialized BPath objects are considered /*! \brief Performs a simple (string-wise) comparison of paths.
No normalization takes place! Uninitialized BPath objects are considered
to be equal. to be equal.
\param item the BPath object to be compared with \param item the BPath object to be compared with
\return \c true, if the path names are not equal, \c false otherwise. \return \c true, if the path names are not equal, \c false otherwise.
*/ */
bool bool
BPath::operator!=(const BPath &item) const BPath::operator!=(const BPath& item) const
{ {
return !(*this == item); return !(*this == item);
} }
//! Performs a simple (string-wise) comparison of paths.
/*! No normalization takes place! /*! \brief Performs a simple (string-wise) comparison of paths.
No normalization takes place!
\param path the path name to be compared with \param path the path name to be compared with
\return \c true, if the path names are not equal, \c false otherwise. \return \c true, if the path names are not equal, \c false otherwise.
*/ */
bool bool
BPath::operator!=(const char *path) const BPath::operator!=(const char* path) const
{ {
return !(*this == path); return !(*this == path);
} }
//! Initializes the object to be a copy of the argument.
/*! \param item the BPath object to be copied /*! \brief Initializes the object to be a copy of the argument.
\param item the BPath object to be copied
\return \c *this \return \c *this
*/ */
BPath& BPath&
BPath::operator=(const BPath &item) BPath::operator=(const BPath& item)
{ {
if (this != &item) if (this != &item)
*this = item.Path(); *this = item.Path();
return *this; return *this;
} }
//! Initializes the object to be a copy of the argument.
/*! Has the same effect as \code SetTo(path) \endcode. /*! \brief Initializes the object to be a copy of the argument.
Has the same effect as \code SetTo(path) \endcode.
\param path the path name to be assigned to this object \param path the path name to be assigned to this object
\return \c *this \return \c *this
*/ */
BPath& BPath&
BPath::operator=(const char *path) BPath::operator=(const char* path)
{ {
if (path == NULL) if (path == NULL)
Unset(); Unset();
@@ -445,7 +482,8 @@ BPath::operator=(const char *path)
} }
// BFlattenable functionality // #pragma mark - BFlattenable functionality
// that's the layout of a flattened entry_ref // that's the layout of a flattened entry_ref
struct flattened_entry_ref { struct flattened_entry_ref {
@@ -459,8 +497,8 @@ static const size_t flattened_entry_ref_size
= sizeof(dev_t) + sizeof(ino_t); = sizeof(dev_t) + sizeof(ino_t);
//! Returns \c false. /*! \brief Returns \c false.
/*! Implements BFlattenable. Implements BFlattenable.
\return \c false \return \c false
*/ */
bool bool
@@ -468,9 +506,10 @@ BPath::IsFixedSize() const
{ {
return false; return false;
} }
//! Returns \c B_REF_TYPE.
/*! Implements BFlattenable. /*! \brief Returns \c B_REF_TYPE.
Implements BFlattenable.
\return \c B_REF_TYPE \return \c B_REF_TYPE
*/ */
type_code type_code
@@ -478,7 +517,8 @@ BPath::TypeCode() const
{ {
return B_REF_TYPE; return B_REF_TYPE;
} }
/*! \brief Returns the size of the flattened entry_ref structure that /*! \brief Returns the size of the flattened entry_ref structure that
represents the pathname. represents the pathname.
Implements BFlattenable. Implements BFlattenable.
@@ -497,7 +537,8 @@ BPath::FlattenedSize() const
} }
return size; return size;
} }
/*! \brief Converts the object's pathname to an entry_ref and writes it into /*! \brief Converts the object's pathname to an entry_ref and writes it into
buffer. buffer.
Implements BFlattenable. Implements BFlattenable.
@@ -510,43 +551,52 @@ BPath::FlattenedSize() const
\todo Reimplement for performance reasons: Don't call FlattenedSize(). \todo Reimplement for performance reasons: Don't call FlattenedSize().
*/ */
status_t status_t
BPath::Flatten(void *buffer, ssize_t size) const BPath::Flatten(void* buffer, ssize_t size) const
{ {
status_t error = (buffer ? B_OK : B_BAD_VALUE); if (buffer == NULL)
if (error == B_OK) { return B_BAD_VALUE;
ssize_t flattenedSize = FlattenedSize();
if (flattenedSize < 0) ssize_t flattenedSize = FlattenedSize();
error = flattenedSize; if (flattenedSize < 0)
if (error == B_OK && size < flattenedSize) return flattenedSize;
error = B_BAD_VALUE; if (size < flattenedSize)
if (error == B_OK) { return B_BAD_VALUE;
// convert the path to an entry_ref status_t status = InitCheck();
BEntry entry; if (status != B_OK)
entry_ref ref; return status;
if (InitCheck() == B_OK && entry.SetTo(Path()) == B_OK)
entry.GetRef(&ref); // convert the path to an entry_ref
// store the entry_ref in the buffer BEntry entry;
flattened_entry_ref &fref = *(flattened_entry_ref*)buffer; entry_ref ref;
fref.device = ref.device; status = entry.SetTo(Path());
fref.directory = ref.directory; if (status == B_OK)
if (ref.name) status = entry.GetRef(&ref);
strcpy(fref.name, ref.name); if (status != B_OK)
} return status;
}
return error; // store the entry_ref in the buffer
flattened_entry_ref& fref = *(flattened_entry_ref*)buffer;
fref.device = ref.device;
fref.directory = ref.directory;
if (ref.name)
strcpy(fref.name, ref.name);
return B_OK;
} }
//! Returns \c true if code is \c B_REF_TYPE, and false otherwise.
/*! Implements BFlattenable. /*! \brief Returns \c true if code is \c B_REF_TYPE, and false otherwise.
Implements BFlattenable.
\param code the type code in question \param code the type code in question
\return \c true if code is \c B_REF_TYPE, and false otherwise. \return \c true if code is \c B_REF_TYPE, and false otherwise.
*/ */
bool bool
BPath::AllowsTypeCode(type_code code) const BPath::AllowsTypeCode(type_code code) const
{ {
return (code == B_REF_TYPE); return code == B_REF_TYPE;
} }
/*! \brief Initializes the BPath with the flattened entry_ref data that's /*! \brief Initializes the BPath with the flattened entry_ref data that's
found in the supplied buffer. found in the supplied buffer.
The type code must be \c B_REF_TYPE. The type code must be \c B_REF_TYPE.
@@ -561,12 +611,12 @@ BPath::AllowsTypeCode(type_code code) const
- other error codes. - other error codes.
*/ */
status_t status_t
BPath::Unflatten(type_code code, const void *buf, ssize_t size) BPath::Unflatten(type_code code, const void* buffer, ssize_t size)
{ {
Unset(); Unset();
status_t error = B_OK; status_t error = B_OK;
// check params // check params
if (!(code == B_REF_TYPE && buf if (!(code == B_REF_TYPE && buffer != NULL
&& size >= (ssize_t)flattened_entry_ref_size)) { && size >= (ssize_t)flattened_entry_ref_size)) {
error = B_BAD_VALUE; error = B_BAD_VALUE;
} }
@@ -575,7 +625,8 @@ BPath::Unflatten(type_code code, const void *buf, ssize_t size)
// already Unset(); // already Unset();
} else { } else {
// reconstruct the entry_ref from the buffer // reconstruct the entry_ref from the buffer
const flattened_entry_ref &fref = *(const flattened_entry_ref*)buf; const flattened_entry_ref& fref
= *(const flattened_entry_ref*)buffer;
BString name(fref.name, size - flattened_entry_ref_size); BString name(fref.name, size - flattened_entry_ref_size);
entry_ref ref(fref.device, fref.directory, name.String()); entry_ref ref(fref.device, fref.directory, name.String());
error = SetTo(&ref); error = SetTo(&ref);
@@ -586,10 +637,12 @@ BPath::Unflatten(type_code code, const void *buf, ssize_t size)
return error; return error;
} }
void BPath::_WarPath1() {} void BPath::_WarPath1() {}
void BPath::_WarPath2() {} void BPath::_WarPath2() {}
void BPath::_WarPath3() {} void BPath::_WarPath3() {}
/*! \brief Sets the supplied path. /*! \brief Sets the supplied path.
The path is copied. If \c NULL, the object's path is set to NULL as well. The path is copied. If \c NULL, the object's path is set to NULL as well.
The object's old path is deleted. The object's old path is deleted.
@@ -599,10 +652,10 @@ void BPath::_WarPath3() {}
- \c B_NO_MEMORY: Insufficient memory. - \c B_NO_MEMORY: Insufficient memory.
*/ */
status_t status_t
BPath::set_path(const char *path) BPath::_SetPath(const char* path)
{ {
status_t error = B_OK; status_t error = B_OK;
const char *oldPath = fName; const char* oldPath = fName;
// set the new path // set the new path
if (path) { if (path) {
fName = new(nothrow) char[strlen(path) + 1]; fName = new(nothrow) char[strlen(path) + 1];
@@ -612,37 +665,39 @@ BPath::set_path(const char *path)
error = B_NO_MEMORY; error = B_NO_MEMORY;
} else } else
fName = NULL; fName = NULL;
// delete the old one // delete the old one
delete[] oldPath; delete[] oldPath;
return error; return error;
} }
/*! \brief Checks a path to see if normalization is required. /*! \brief Checks a path to see if normalization is required.
The following items require normalization: The following items require normalization:
- Relative pathnames (after concatenation; e.g. "boot/ltj") - Relative pathnames (after concatenation; e.g. "boot/ltj")
- The presence of "." or ".." ("/boot/ltj/../ltj/./gwar") - The presence of "." or ".." ("/boot/ltj/../ltj/./gwar")
- Redundant slashes ("/boot//ltj") - Redundant slashes ("/boot//ltj")
- A trailing slash ("/boot/ltj/") - A trailing slash ("/boot/ltj/")
\param _error A pointer to an error variable that will be set if the input
is not a valid path.
\return \return
- \c true: \a path requires normalization - \c true: \a path requires normalization
- \c false: \a path does not require normalization - \c false: \a path does not require normalization
*/
\exception BPath::EBadInput : \a path is \c NULL or an empty string.
*/
bool bool
BPath::MustNormalize(const char *path) BPath::_MustNormalize(const char* path, status_t* _error)
{ {
// Check for useless input // Check for useless input
if (path == NULL || path[0] == 0) if (path == NULL || path[0] == 0) {
throw BPath::EBadInput(); if (_error != NULL)
*_error = B_BAD_VALUE;
int len = strlen(path); return false;
}
int len = strlen(path);
/* Look for anything in the string that forces us to normalize: /* Look for anything in the string that forces us to normalize:
+ No leading / + No leading /
+ any occurence of /./ or /../ or //, or a trailing /. or /.. + any occurence of /./ or /../ or //, or a trailing /. or /..
@@ -661,54 +716,52 @@ BPath::MustNormalize(const char *path)
OneDot, OneDot,
TwoDots TwoDots
} state = NoMatch; } state = NoMatch;
for (int i = 0; path[i] != 0; i++) { for (int i = 0; path[i] != 0; i++) {
switch (state) { switch (state) {
case NoMatch: case NoMatch:
if (path[i] == '/') if (path[i] == '/')
state = InitialSlash; state = InitialSlash;
break; break;
case InitialSlash: case InitialSlash:
if (path[i] == '/') if (path[i] == '/')
return true; // "*//*" return true; // "*//*"
else if (path[i] == '.')
if (path[i] == '.')
state = OneDot; state = OneDot;
else else
state = NoMatch; state = NoMatch;
break; break;
case OneDot: case OneDot:
if (path[i] == '/') if (path[i] == '/')
return true; // "*/./*" return true; // "*/./*"
else if (path[i] == '.')
if (path[i] == '.')
state = TwoDots; state = TwoDots;
else else
state = NoMatch; state = NoMatch;
break; break;
case TwoDots: case TwoDots:
if (path[i] == '/') if (path[i] == '/')
return true; // "*/../*" return true; // "*/../*"
else
state = NoMatch; state = NoMatch;
break; break;
} }
} }
// If we hit the end of the string while in either // If we hit the end of the string while in either
// of these two states, there was a trailing /. or /.. // of these two states, there was a trailing /. or /..
if (state == OneDot || state == TwoDots) if (state == OneDot || state == TwoDots)
return true; return true;
else
return false; return false;
} }
} }
/*! \class BPath::EBadInput
\brief Internal exception class thrown by BPath::MustNormalize() when given
invalid input.
*/
/*! /*!
\var char *BPath::fName \var char *BPath::fName
@@ -719,6 +772,3 @@ BPath::MustNormalize(const char *path)
\var status_t BPath::fCStatus \var status_t BPath::fCStatus
\brief The object's initialization status. \brief The object's initialization status.
*/ */