mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-06 05:54:15 +00:00
17c79a9e23
Besides adapting the components to the use of base/log.h, the patch cleans up a few base headers, i.e., it removes unused includes from root/component.h, specifically base/heap.h and ram_session/ram_session.h. Hence, components that relied on the implicit inclusion of those headers have to manually include those headers now. While adjusting the log messages, I repeatedly stumbled over the problem that printing char * arguments is ambiguous. It is unclear whether to print the argument as pointer or null-terminated string. To overcome this problem, the patch introduces a new type 'Cstring' that allows the caller to express that the argument should be handled as null-terminated string. As a nice side effect, with this type in place, the optional len argument of the 'String' class could be removed. Instead of supplying a pair of (char const *, size_t), the constructor accepts a 'Cstring'. This, in turn, clears the way let the 'String' constructor use the new output mechanism to assemble a string from multiple arguments (and thereby getting rid of snprintf within Genode in the near future). To enforce the explicit resolution of the char * ambiguity, the 'char *' overload of the 'print' function is marked as deleted. Issue #1987
190 lines
3.6 KiB
C++
190 lines
3.6 KiB
C++
/*
|
|
* \brief File-system directory node
|
|
* \author Norman Feske
|
|
* \author Christian Helmuth
|
|
* \date 2013-11-11
|
|
*/
|
|
|
|
#ifndef _DIRECTORY_H_
|
|
#define _DIRECTORY_H_
|
|
|
|
/* Genode include */
|
|
#include <file_system/util.h>
|
|
#include <os/path.h>
|
|
|
|
/* local includes */
|
|
#include <node.h>
|
|
#include <file.h>
|
|
|
|
#include <lx_util.h>
|
|
|
|
|
|
namespace File_system {
|
|
using namespace Genode;
|
|
class Directory;
|
|
}
|
|
|
|
|
|
class File_system::Directory : public Node
|
|
{
|
|
private:
|
|
|
|
typedef Genode::Path<MAX_PATH_LEN> Path;
|
|
|
|
DIR *_fd;
|
|
Path _path;
|
|
Allocator &_alloc;
|
|
|
|
unsigned long _inode(char const *path, bool create)
|
|
{
|
|
int ret;
|
|
|
|
if (create) {
|
|
mode_t ugo = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
|
ret = mkdir(path, ugo);
|
|
if (ret == -1)
|
|
throw No_space();
|
|
}
|
|
|
|
struct stat s;
|
|
|
|
ret = lstat(path, &s);
|
|
if (ret == -1)
|
|
throw Lookup_failed();
|
|
|
|
return s.st_ino;
|
|
}
|
|
|
|
DIR *_open(char const *path)
|
|
{
|
|
DIR *fd = opendir(path);
|
|
if (!fd)
|
|
throw Lookup_failed();
|
|
|
|
return fd;
|
|
}
|
|
|
|
public:
|
|
|
|
Directory(Allocator &alloc, char const *path, bool create)
|
|
:
|
|
Node(_inode(path, create)),
|
|
_fd(_open(path)),
|
|
_path(path, "./"),
|
|
_alloc(alloc)
|
|
{
|
|
Node::name(basename(path));
|
|
}
|
|
|
|
virtual ~Directory()
|
|
{
|
|
closedir(_fd);
|
|
}
|
|
|
|
/* FIXME returned file node must be locked */
|
|
File * file(char const *name, Mode mode, bool create)
|
|
{
|
|
File *file = new (&_alloc) File(dirfd(_fd), name, mode, create);
|
|
|
|
file->lock();
|
|
return file;
|
|
}
|
|
|
|
/* FIXME returned directory node must be locked */
|
|
Directory * subdir(char const *path, bool create)
|
|
{
|
|
Path dir_path(path, _path.base());
|
|
|
|
Directory *dir = new (&_alloc) Directory(_alloc, dir_path.base(), create);
|
|
|
|
dir->lock();
|
|
return dir;
|
|
}
|
|
|
|
Node * node(char const *path)
|
|
{
|
|
Path node_path(path, _path.base());
|
|
|
|
/*
|
|
* XXX Currently, symlinks are transparently dereferenced by the
|
|
* use of stat(). For symlink detection we would need lstat()
|
|
* and implement special handling of the root, which may be a
|
|
* link!
|
|
*/
|
|
|
|
struct stat s;
|
|
int ret = stat(node_path.base(), &s);
|
|
if (ret == -1)
|
|
throw Lookup_failed();
|
|
|
|
Node *node = 0;
|
|
|
|
if (S_ISDIR(s.st_mode))
|
|
node = new (&_alloc) Directory(_alloc, node_path.base(), false);
|
|
else if (S_ISREG(s.st_mode))
|
|
node = new (&_alloc) File(node_path.base(), STAT_ONLY);
|
|
else
|
|
throw Lookup_failed();
|
|
|
|
node->lock();
|
|
return node;
|
|
}
|
|
|
|
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
|
{
|
|
if (len < sizeof(Directory_entry)) {
|
|
Genode::error("read buffer too small for directory entry");
|
|
return 0;
|
|
}
|
|
|
|
if (seek_offset % sizeof(Directory_entry)) {
|
|
Genode::error("seek offset not aligned to sizeof(Directory_entry)");
|
|
return 0;
|
|
}
|
|
|
|
seek_off_t index = seek_offset / sizeof(Directory_entry);
|
|
|
|
/* seek to index and read entry */
|
|
struct dirent *dent;
|
|
rewinddir(_fd);
|
|
for (unsigned i = 0; i <= index; ++i) {
|
|
dent = readdir(_fd);
|
|
}
|
|
|
|
if (!dent)
|
|
return 0;
|
|
|
|
Directory_entry *e = (Directory_entry *)(dst);
|
|
|
|
switch (dent->d_type) {
|
|
case DT_REG: e->type = Directory_entry::TYPE_FILE; break;
|
|
case DT_DIR: e->type = Directory_entry::TYPE_DIRECTORY; break;
|
|
case DT_LNK: e->type = Directory_entry::TYPE_SYMLINK; break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
strncpy(e->name, dent->d_name, sizeof(e->name));
|
|
|
|
return sizeof(Directory_entry);
|
|
}
|
|
|
|
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
|
{
|
|
/* writing to directory nodes is not supported */
|
|
return 0;
|
|
}
|
|
|
|
size_t num_entries() const
|
|
{
|
|
unsigned num = 0;
|
|
|
|
rewinddir(_fd);
|
|
while (readdir(_fd)) ++num;
|
|
|
|
return num;
|
|
}
|
|
};
|
|
|
|
#endif /* _DIRECTORY_H_ */
|