haiku/headers/private/storage/storage_support.h
Augustin Cavalier 8f03af00f8 Storage: Rework LongDirEntry to be a union.
Our dirent structure is "slim": it has a flexible-length array at the
end which must be allocated to whatever size the consumer wants. However,
we use [1] there and not [0] or [], which meant GCC thought it was not
a flexible-length array, and so it optimized various string accesses
that it assumed must be always false. Among these was BDirectory's
check for "." and "..", and so that resulted in infinite loops.

When changing our dirent structure to a proper FLA instead of [1],
GCC then throws errors on LongDirEntry as it has data "after" the
FLA; which is what we want, but there is no way to tell GCC that.
So now we use a union instead, which is the proper way to statically
allocate a FLA.

This is part of #17389, but the real fix requires changing our dirent
structure, which is coming in a separate commit.
2021-11-18 16:00:23 -05:00

155 lines
3.6 KiB
C++

/*
* Copyright 2002-2006, Haiku Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Tyler Dauwalder
*/
#ifndef _STORAGE_SUPPORT_H
#define _STORAGE_SUPPORT_H
/*!
\file storage_support.h
Interface declarations for miscellaneous internal
Storage Kit support functions.
*/
#include <StorageDefs.h>
#include <SupportDefs.h>
#include <dirent.h>
#include <string>
namespace BPrivate {
namespace Storage {
// For convenience:
union LongDirEntry {
struct dirent dirent;
char _[sizeof(struct dirent) + B_PATH_NAME_LENGTH];
};
//! Returns whether the supplied path is absolute.
bool is_absolute_path(const char *path);
status_t parse_path(const char *fullPath, int &dirEnd, int &leafStart,
int &leafEnd);
status_t parse_path(const char *fullPath, char *dirPath, char *leaf);
//! splits a path name into directory path and leaf name
status_t split_path(const char *fullPath, char *&path, char *&leaf);
//! splits a path name into directory path and leaf name
status_t split_path(const char *fullPath, char **path, char **leaf);
//! Parses the first component of a path name.
status_t parse_first_path_component(const char *path, int32& length,
int32& nextComponent);
//! Parses the first component of a path name.
status_t parse_first_path_component(const char *path, char *&component,
int32& nextComponent);
//! Checks whether an entry name is a valid entry name.
status_t check_entry_name(const char *entry);
//! Checks whether a path name is a valid path name.
status_t check_path_name(const char *path);
/*! \brief Returns a copy of \c str in which all alphabetic characters
are lowercase.
Returns \c "(null)" if you're a bonehead and pass in a \c NULL pointer.
*/
std::string to_lower(const char *str);
/*! \brief Places a copy of \c str in \c result in which all alphabetic
characters are lowercase.
Returns \c "(null)" if you're a bonehead and pass in a \c NULL pointer.
*/
void to_lower(const char *str, std::string &result);
/*! \brief Copies \c str into \c result, converting any uppercase alphabetics
to lowercase.
\a str and \a result may point to the same string. \a result is
assumed to be as long as or longer than \a str.
*/
void to_lower(const char *str, char *result);
//! Converts \c str to lowercase.
void to_lower(char *str);
/*! \brief Escapes any whitespace or other special characters in the path
\a result must be large enough to accomodate the addition of
escape sequences to \a str. \a str and \a result may *NOT* point to
the same string.
Note that this function was designed for use with the registrar's
RecentEntries class, and may not create escapes exactly like you're
hoping. Please double check the code for the function to see if this
is the case.
*/
void escape_path(const char *str, char *result);
/*! \brief Escapes any whitespace or other special characters in the path
\a str must be large enough to accomodate the addition of
escape sequences.
*/
void escape_path(char *str);
/*! \brief Returns whether the supplied device ID refers to the root FS.
*/
bool device_is_root_device(dev_t device);
// FDCloser
class FDCloser {
public:
FDCloser(int fd)
: fFD(fd)
{
}
~FDCloser()
{
Close();
}
void SetTo(int fd)
{
Close();
fFD = fd;
}
// implemented in the source file to not expose syscalls to the unit tests
// which include this file too
void Close();
// void Close()
// {
// if (fFD >= 0)
// _kern_close(fFD);
// fFD = -1;
// }
int Detach()
{
int fd = fFD;
fFD = -1;
return fd;
}
private:
int fFD;
};
}; // namespace Storage
}; // namespace BPrivate
using BPrivate::Storage::FDCloser;
#endif // _STORAGE_SUPPORT_H