469 lines
15 KiB
C++
469 lines
15 KiB
C++
/*
|
|
|
|
This class is used to organize a directory tree on top of any
|
|
collection that allows for accessing its elements by an id (inode).
|
|
No requirements are imposed on the inodes apart from the forbidden
|
|
value -1 (it is used ot denote a bad inode).
|
|
|
|
The dirspec_t class is used to specialize the dirtree.
|
|
|
|
It can be used to introduce a directory structure for:
|
|
- local types
|
|
- structs
|
|
- enums
|
|
- functions
|
|
- names
|
|
- etc
|
|
|
|
*/
|
|
|
|
#ifndef DIRTREE_HPP
|
|
#define DIRTREE_HPP
|
|
|
|
//------------------------------------------------------------------------
|
|
typedef qvector<inode_t> inodevec_t; // sequence of inodes
|
|
|
|
/// Directory indexes are simple numbers like 0,1,2,3...
|
|
/// They are independent of inode numbers.
|
|
/// The root directory always exists and has the index 0 (\ref direntry_t::ROOTIDX).
|
|
typedef uval_t diridx_t;
|
|
typedef qvector<diridx_t> dirvec_t; // sequence of directory indexes
|
|
|
|
// Directory entry: either a file or directory
|
|
// We use PACKED to save memory, without it we would spend 64 bits instead of
|
|
// 8 bits to store a 1-bit value on ida64.
|
|
#pragma pack(push, 1)
|
|
struct PACKED direntry_t
|
|
{
|
|
uval_t idx; // diridx_t or inode_t
|
|
bool isdir;
|
|
|
|
static const uval_t BADIDX = uval_t(-1);
|
|
static const uval_t ROOTIDX = 0;
|
|
|
|
direntry_t(uval_t i=BADIDX, bool d=false) : idx(i), isdir(d) {}
|
|
bool valid() const { return idx != BADIDX; }
|
|
|
|
bool operator==(const direntry_t &r) const
|
|
{
|
|
return idx == r.idx && isdir == r.isdir;
|
|
}
|
|
bool operator!=(const direntry_t &r) const
|
|
{
|
|
return !(*this == r);
|
|
}
|
|
bool operator<(const direntry_t &r) const
|
|
{
|
|
if ( !isdir && r.isdir )
|
|
return true;
|
|
if ( isdir && !r.isdir )
|
|
return false;
|
|
return idx < r.idx;
|
|
}
|
|
};
|
|
#pragma pack(pop)
|
|
DECLARE_TYPE_AS_MOVABLE(direntry_t);
|
|
typedef qvector<direntry_t> direntry_vec_t;
|
|
|
|
//------------------------------------------------------------------------
|
|
/// Directory tree specialization. This is an abstract base class that
|
|
/// represents 'file items' of our directory structure.
|
|
struct dirspec_t
|
|
{
|
|
uint32 flags;
|
|
enum
|
|
{
|
|
DSF_INODE_EA = 0x01, // inode is EA, will be handled during segment moving
|
|
DSF_PRIVRANGE = 0x02, // inode is tid_t, structure or enum id, will be handled during segment moving
|
|
};
|
|
// netnode name to load/save directory tree
|
|
// if not specified the loading/storing operations are not supported
|
|
qstring nodename;
|
|
|
|
dirspec_t(const char *nm=nullptr, uint32 f=0) : flags(f), nodename(nm) {}
|
|
|
|
virtual ~dirspec_t() {}
|
|
|
|
// get the entry name. for example, the structure name
|
|
// out may be nullptr; in this case get_name can be used to validate an inode.
|
|
// return false if the entry does not exist.
|
|
virtual bool get_name(qstring *out, inode_t inode) = 0;
|
|
// get the entry inode. for example, the structure id
|
|
virtual inode_t get_inode(diridx_t diridx, const char *name) = 0;
|
|
// print additional attributes of the entry. for example, is union? is mapped?
|
|
virtual qstring get_attrs(inode_t inode) const = 0;
|
|
// rename the entry
|
|
virtual bool rename_inode(inode_t inode, const char *newname) = 0;
|
|
// event: unlinked an inode
|
|
virtual void unlink_inode(inode_t) {}
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
/// Position in the directory tree
|
|
struct dirtree_cursor_t
|
|
{
|
|
diridx_t parent;
|
|
size_t rank; // item rank: index into parent.subdirs or parent.inodes
|
|
// if the index value is greated than parent.subdirs.size()
|
|
// then it points to parent.inodes (after -= parent.subdirs.size())
|
|
dirtree_cursor_t(diridx_t _parent=direntry_t::BADIDX, size_t _rank=size_t(-1))
|
|
: parent(_parent), rank(_rank) {}
|
|
bool valid() const { return parent != direntry_t::BADIDX || rank == 0; }
|
|
bool is_root_cursor() const { return parent == direntry_t::BADIDX && rank == 0; }
|
|
void set_root_cursor(void) { parent = direntry_t::BADIDX; rank = 0; }
|
|
|
|
static dirtree_cursor_t root_cursor()
|
|
{
|
|
dirtree_cursor_t c;
|
|
c.set_root_cursor();
|
|
return c;
|
|
}
|
|
|
|
DECLARE_COMPARISONS(dirtree_cursor_t)
|
|
{
|
|
if ( parent < r.parent ) return -1;
|
|
if ( parent > r.parent ) return 1;
|
|
if ( rank < r.rank ) return -1;
|
|
if ( rank > r.rank ) return 1;
|
|
return 0;
|
|
}
|
|
};
|
|
DECLARE_TYPE_AS_MOVABLE(dirtree_cursor_t);
|
|
typedef qvector<dirtree_cursor_t> dirtree_cursor_vec_t;
|
|
|
|
//-------------------------------------------------------------------------
|
|
struct dirtree_selection_t : public dirtree_cursor_vec_t {};
|
|
|
|
//------------------------------------------------------------------------
|
|
/// Helper class to iterate over files
|
|
struct dirtree_iterator_t
|
|
{
|
|
qstring pattern;
|
|
dirtree_cursor_t cursor;
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
// Directory tree: error codes
|
|
enum dterr_t
|
|
{
|
|
DTE_OK, // ok
|
|
DTE_ALREADY_EXISTS, // item already exists
|
|
DTE_NOT_FOUND, // item not found
|
|
DTE_NOT_DIRECTORY, // item is not a directory
|
|
DTE_NOT_EMPTY, // directory is not empty
|
|
DTE_BAD_PATH, // invalid path
|
|
DTE_CANT_RENAME, // failed to rename an item
|
|
DTE_OWN_CHILD, // moving inside subdirectory of itself
|
|
DTE_MAX_DIR, // maximum directory count achieved
|
|
DTE_LAST,
|
|
};
|
|
|
|
class dirtree_t;
|
|
class dirtree_impl_t;
|
|
struct segm_move_infos_t;
|
|
|
|
//------------------------------------------------------------------------
|
|
// internal functions; use dirtree_t members instead
|
|
#ifndef SWIG
|
|
idaman dirtree_impl_t *ida_export create_dirtree(dirtree_t *dt, dirspec_t *ds);
|
|
idaman void ida_export delete_dirtree(dirtree_impl_t *d);
|
|
idaman bool ida_export load_dirtree(dirtree_impl_t *d);
|
|
idaman bool ida_export save_dirtree(dirtree_impl_t *d);
|
|
void reset_dirtree(dirtree_impl_t *d);
|
|
idaman const char *ida_export dirtree_errstr(dterr_t err);
|
|
idaman dterr_t ida_export dirtree_chdir(dirtree_impl_t *d, const char *path);
|
|
idaman void ida_export dirtree_getcwd(qstring *out, const dirtree_impl_t *d);
|
|
idaman void ida_export dirtree_resolve_path(direntry_t *de, const dirtree_impl_t *d, const char *path);
|
|
idaman void ida_export dirtree_resolve_cursor(direntry_t *de, const dirtree_impl_t *d, const dirtree_cursor_t &cursor);
|
|
idaman bool ida_export dirtree_get_entry_name(qstring *out, const dirtree_impl_t *d, const direntry_t &de);
|
|
idaman void ida_export dirtree_get_entry_attrs(qstring *out, const dirtree_impl_t *d, const direntry_t &de);
|
|
idaman ssize_t ida_export dirtree_get_dir_size(dirtree_impl_t *d, diridx_t diridx);
|
|
idaman bool ida_export dirtree_findfirst(dirtree_impl_t *d, dirtree_iterator_t *ff, const char *pattern);
|
|
idaman bool ida_export dirtree_findnext(dirtree_impl_t *d, dirtree_iterator_t *ff);
|
|
idaman bool ida_export dirtree_get_abspath_by_cursor(qstring *out, const dirtree_impl_t *d, const dirtree_cursor_t &cursor);
|
|
idaman bool ida_export dirtree_get_abspath_by_relpath(qstring *out, const dirtree_impl_t *d, const char *relpath);
|
|
idaman dterr_t ida_export dirtree_mkdir(dirtree_impl_t *d, const char *path);
|
|
idaman dterr_t ida_export dirtree_rmdir(dirtree_impl_t *d, const char *path);
|
|
idaman dterr_t ida_export dirtree_link(dirtree_impl_t *d, const char *path, bool do_link);
|
|
idaman dterr_t ida_export dirtree_link_inode(dirtree_impl_t *d, inode_t inode, bool do_link);
|
|
idaman dterr_t ida_export dirtree_rename(dirtree_impl_t *d, const char *from, const char *to);
|
|
idaman ssize_t ida_export dirtree_get_rank(const dirtree_impl_t *d, diridx_t diridx, const direntry_t &de);
|
|
idaman dterr_t ida_export dirtree_change_rank(dirtree_impl_t *d, const char *path, ssize_t rank_delta);
|
|
idaman void ida_export dirtree_get_parent_cursor(dirtree_cursor_t *out, const dirtree_impl_t *d, const dirtree_cursor_t &cursor);
|
|
idaman void ida_export notify_dirtree(dirtree_impl_t *d, bool added, inode_t inode);
|
|
idaman const char *ida_export dirtree_get_nodename(const dirtree_impl_t *d);
|
|
idaman void ida_export dirtree_set_nodename(dirtree_impl_t *d, const char *nm);
|
|
#endif // SWIG
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
/// Directory tree.
|
|
/// This class organizes a virtual directory tree over items that
|
|
/// are represented by dirspec_t.
|
|
class dirtree_t
|
|
{
|
|
dirtree_impl_t *d;
|
|
|
|
|
|
public:
|
|
//lint -sem(dirtree_t::dirtree_t, custodial(1))
|
|
dirtree_t(dirspec_t *ds) { d = create_dirtree(this, ds); }
|
|
~dirtree_t() { delete_dirtree(d); }
|
|
|
|
/// Get textual representation of the error code
|
|
static const char *errstr(dterr_t err) { return dirtree_errstr(err); }
|
|
|
|
/// Change current directory
|
|
/// \param path new current directory
|
|
/// \return \ref dterr_t error code
|
|
dterr_t chdir(const char *path) { return dirtree_chdir(d, path); }
|
|
|
|
/// Get current directory
|
|
/// \return the current working directory
|
|
qstring getcwd() const
|
|
{
|
|
qstring out;
|
|
dirtree_getcwd(&out, d);
|
|
return out;
|
|
}
|
|
|
|
/// Get absolute path pointed by the cursor
|
|
/// \param cursor
|
|
/// \return path; empty string if error
|
|
/// \note see also resolve_cursor()
|
|
qstring get_abspath(const dirtree_cursor_t &cursor) const
|
|
{
|
|
qstring out;
|
|
dirtree_get_abspath_by_cursor(&out, d, cursor);
|
|
return out;
|
|
}
|
|
|
|
/// Construct an absolute path from the specified relative path.
|
|
/// This function verifies the directory part of the specified path.
|
|
/// The last component of the specified path is not verified.
|
|
/// \param relpath relative path
|
|
/// \return path. empty path means wrong directory part of RELPATH
|
|
qstring get_abspath(const char *relpath) const
|
|
{
|
|
qstring out;
|
|
dirtree_get_abspath_by_relpath(&out, d, relpath);
|
|
return out;
|
|
}
|
|
|
|
/// Resolve cursor
|
|
/// \param cursor to analyze
|
|
/// \return directory entry;
|
|
/// if the cursor is bad, the resolved entry will be invalid.
|
|
/// \note see also get_abspath()
|
|
direntry_t resolve_cursor(const dirtree_cursor_t &cursor) const
|
|
{
|
|
direntry_t de;
|
|
dirtree_resolve_cursor(&de, d, cursor);
|
|
return de;
|
|
}
|
|
|
|
/// Resolve path
|
|
/// \param path to analyze
|
|
/// \return directory entry
|
|
direntry_t resolve_path(const char *path) const
|
|
{
|
|
direntry_t de;
|
|
dirtree_resolve_path(&de, d, path);
|
|
return de;
|
|
}
|
|
|
|
static bool isdir(const direntry_t &de) { return de.valid() && de.isdir; }
|
|
static bool isfile(const direntry_t &de) { return de.valid() && !de.isdir; }
|
|
|
|
/// Is a directory?
|
|
/// \param path to analyze
|
|
/// \return true if the specified path is a directory
|
|
bool isdir(const char *path) const
|
|
{
|
|
direntry_t de = resolve_path(path);
|
|
return isdir(de);
|
|
}
|
|
|
|
/// Is a file?
|
|
/// \param path to analyze
|
|
/// \return true if the specified path is a file
|
|
bool isfile(const char *path) const
|
|
{
|
|
direntry_t de = resolve_path(path);
|
|
return isfile(de);
|
|
}
|
|
|
|
/// Get entry name
|
|
/// \param de directory entry
|
|
/// \return name
|
|
qstring get_entry_name(const direntry_t &de) const
|
|
{
|
|
qstring out;
|
|
dirtree_get_entry_name(&out, d, de);
|
|
return out;
|
|
}
|
|
|
|
/// Get dir size
|
|
/// \param diridx directory index
|
|
/// \return number of entries under this directory;
|
|
/// if error, return -1
|
|
ssize_t get_dir_size(diridx_t diridx) const { return dirtree_get_dir_size(d, diridx); }
|
|
|
|
/// Get entry attributes
|
|
/// \param de directory entry
|
|
/// \return name
|
|
qstring get_entry_attrs(const direntry_t &de) const
|
|
{
|
|
qstring out;
|
|
dirtree_get_entry_attrs(&out, d, de);
|
|
return out;
|
|
}
|
|
|
|
/// Start iterating over files in a directory
|
|
/// \param ff directory iterator. it will be initialized by the function
|
|
/// \param pattern pattern to search for
|
|
/// \return success
|
|
bool findfirst(dirtree_iterator_t *ff, const char *pattern) const
|
|
{
|
|
return dirtree_findfirst(d, ff, pattern);
|
|
}
|
|
|
|
/// Continue iterating over files in a directory
|
|
/// \param ff directory iterator
|
|
/// \return success
|
|
bool findnext(dirtree_iterator_t *ff) const
|
|
{
|
|
return dirtree_findnext(d, ff);
|
|
}
|
|
|
|
/// Create a directory.
|
|
/// \param path directory to create
|
|
/// \return \ref dterr_t error code
|
|
dterr_t mkdir(const char *path) { return dirtree_mkdir(d, path); }
|
|
|
|
/// Remove a directory.
|
|
/// \param path directory to delete
|
|
/// \return \ref dterr_t error code
|
|
dterr_t rmdir(const char *path) { return dirtree_rmdir(d, path); }
|
|
|
|
/// Add a file item into a directory.
|
|
/// \param path path to item to add to a directory
|
|
/// \return \ref dterr_t error code
|
|
dterr_t link(const char *path) { return dirtree_link(d, path, true); }
|
|
|
|
/// Remove a file item from a directory.
|
|
/// \param path path to item remove from a directory
|
|
/// \return \ref dterr_t error code
|
|
dterr_t unlink(const char *path) { return dirtree_link(d, path, false); }
|
|
|
|
/// Add an inode into the current directory
|
|
/// \param inode
|
|
/// \return \ref dterr_t error code
|
|
dterr_t link(inode_t inode) { return dirtree_link_inode(d, inode, true); }
|
|
|
|
/// Remove an inode from the current directory
|
|
/// \param inode
|
|
/// \return \ref dterr_t error code
|
|
dterr_t unlink(inode_t inode) { return dirtree_link_inode(d, inode, false); }
|
|
|
|
/// Rename a directory entry.
|
|
/// \param from source path
|
|
/// \param to destination path
|
|
/// \return \ref dterr_t error code
|
|
/// \note This function can also rename the item
|
|
dterr_t rename(const char *from, const char *to)
|
|
{
|
|
return dirtree_rename(d, from, to);
|
|
}
|
|
|
|
/// Get ordering rank of an item.
|
|
/// \param diridx index of the parent directory
|
|
/// \param de directory entry
|
|
/// \return number in a range of [0..n) where n is the number of entries in
|
|
/// the parent directory. -1 if error
|
|
ssize_t get_rank(diridx_t diridx, const direntry_t &de) const
|
|
{
|
|
return dirtree_get_rank(d, diridx, de);
|
|
}
|
|
|
|
/// Change ordering rank of an item.
|
|
/// \param path path to the item
|
|
/// \param delta the amount of the change. positive numbers mean to move down
|
|
/// in the list; negative numbers mean to move up.
|
|
/// \return \ref dterr_t error code
|
|
/// \note All subdirectories go before all file entries.
|
|
dterr_t change_rank(const char *path, ssize_t rank_delta)
|
|
{
|
|
return dirtree_change_rank(d, path, rank_delta);
|
|
}
|
|
|
|
/// Get parent cursor.
|
|
/// \param cursor a valid ditree cursor
|
|
/// \return cursor's parent
|
|
dirtree_cursor_t get_parent_cursor(const dirtree_cursor_t &cursor) const
|
|
{
|
|
dirtree_cursor_t parent;
|
|
dirtree_get_parent_cursor(&parent, d, cursor);
|
|
return parent;
|
|
}
|
|
|
|
/// Load the tree structure from the netnode.
|
|
/// If dirspec_t::nodename is empty, the operation will be considered a success.
|
|
/// In addition, calling load() more than once will not do anything,
|
|
/// and will be considered a success.
|
|
/// \return success
|
|
/// \see dirspec_t::nodename.
|
|
bool load()
|
|
{
|
|
return load_dirtree(d);
|
|
}
|
|
|
|
/// Save the tree structure to the netnode.
|
|
/// \return success
|
|
/// \see dirspec_t::nodename.
|
|
bool save() const
|
|
{
|
|
return save_dirtree(d);
|
|
}
|
|
|
|
/// netnode name
|
|
const char *get_nodename() const
|
|
{
|
|
return dirtree_get_nodename(d);
|
|
}
|
|
|
|
void set_nodename(const char *nm)
|
|
{
|
|
return dirtree_set_nodename(d, nm);
|
|
}
|
|
|
|
/// Notify dirtree about a change of an inode.
|
|
/// \param add are we adding or deleting an inode?
|
|
/// \param inode inode in question
|
|
void notify_dirtree(bool added, inode_t inode)
|
|
{
|
|
::notify_dirtree(d, added, inode);
|
|
}
|
|
|
|
};
|
|
|
|
/// Built-in dirtree specializations:
|
|
enum dirtree_id_t
|
|
{
|
|
DIRTREE_LOCAL_TYPES,
|
|
DIRTREE_STRUCTS,
|
|
DIRTREE_ENUMS,
|
|
DIRTREE_FUNCS,
|
|
DIRTREE_NAMES,
|
|
DIRTREE_IMPORTS,
|
|
DIRTREE_IDAPLACE_BOOKMARKS,
|
|
DIRTREE_STRUCTS_BOOKMARKS,
|
|
DIRTREE_ENUMS_BOOKMARKS,
|
|
DIRTREE_END,
|
|
};
|
|
idaman dirtree_t *ida_export get_std_dirtree(dirtree_id_t id);
|
|
|
|
|
|
#endif // define DIRTREE_HPP
|