mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-25 08:21:08 +00:00
24b1f269be
The intention of Packet_ref was to allow clients to place opaque references into the packet descriptor itself, which could be observed on packet completion. Currently no component in our sources uses this feature and beyond that it is questionable if it should be used at all: If the server tampers with the ref the client may easily be confused into observing an incorrect or invalid context. It seems better to remove the opaque context from the descriptor and leave the actual implementation to the client and its needs.
242 lines
5.2 KiB
C++
242 lines
5.2 KiB
C++
/*
|
|
* \brief Utilities
|
|
* \author Norman Feske
|
|
* \date 2012-04-11
|
|
*/
|
|
|
|
#ifndef _FILE_SYSTEM__UTIL_H_
|
|
#define _FILE_SYSTEM__UTIL_H_
|
|
|
|
#include <file_system_session/file_system_session.h>
|
|
#include <os/path.h>
|
|
|
|
namespace File_system {
|
|
|
|
/**
|
|
* Return true if character 'c' occurs in null-terminated string 'str'
|
|
*/
|
|
inline bool string_contains(char const *str, char c)
|
|
{
|
|
for (; *str; str++)
|
|
if (*str == c)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Return base-name portion of null-terminated path string
|
|
*/
|
|
static inline char const *basename(char const *path)
|
|
{
|
|
char const *start = path;
|
|
|
|
for (; *path; path++)
|
|
if (*path == '/')
|
|
start = path + 1;
|
|
|
|
return start;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return true if specified path is a base name (contains no path delimiters)
|
|
*/
|
|
static inline bool is_basename(char const *path)
|
|
{
|
|
for (; *path; path++)
|
|
if (*path == '/')
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return true if 'str' is a valid node name
|
|
*/
|
|
static inline bool valid_name(char const *str)
|
|
{
|
|
if (string_contains(str, '/')) return false;
|
|
|
|
/* must have at least one character */
|
|
if (str[0] == 0) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Open a directory, ensuring all parent directories exists.
|
|
*/
|
|
static inline Dir_handle ensure_dir(Session &fs, char const *path)
|
|
{
|
|
try {
|
|
return fs.dir(path, false);
|
|
} catch (Lookup_failed) {
|
|
try {
|
|
return fs.dir(path, true);
|
|
} catch (Lookup_failed) {
|
|
Genode::Path<MAX_PATH_LEN> target(path);
|
|
target.strip_last_element();
|
|
target.remove_trailing('/');
|
|
fs.close(ensure_dir(fs, target.base()));
|
|
}
|
|
}
|
|
return fs.dir(path, true);
|
|
}
|
|
|
|
|
|
/**
|
|
* Collect pending packet acknowledgements, freeing the space occupied
|
|
* by the packet in the bulk buffer
|
|
*
|
|
* This function should be called prior enqueing new packets into the
|
|
* packet stream to free up space in the bulk buffer.
|
|
*/
|
|
static void collect_acknowledgements(Session::Tx::Source &source)
|
|
{
|
|
while (source.ack_avail())
|
|
source.release_packet(source.get_acked_packet());
|
|
}
|
|
|
|
|
|
/**
|
|
* Read file content
|
|
*/
|
|
static inline size_t read(Session &fs, Node_handle const &node_handle,
|
|
void *dst, size_t count, seek_off_t seek_offset = 0)
|
|
{
|
|
bool success = true;
|
|
Session::Tx::Source &source = *fs.tx();
|
|
|
|
size_t const max_packet_size = source.bulk_buffer_size() / 2;
|
|
|
|
size_t remaining_count = count;
|
|
|
|
while (remaining_count && success) {
|
|
|
|
collect_acknowledgements(source);
|
|
|
|
size_t const curr_packet_size = min(remaining_count, max_packet_size);
|
|
|
|
Packet_descriptor
|
|
packet(source.alloc_packet(curr_packet_size),
|
|
node_handle,
|
|
File_system::Packet_descriptor::READ,
|
|
curr_packet_size,
|
|
seek_offset);
|
|
|
|
/* pass packet to server side */
|
|
source.submit_packet(packet);
|
|
|
|
packet = source.get_acked_packet();
|
|
success = packet.succeeded();
|
|
|
|
size_t const read_num_bytes = min(packet.length(), curr_packet_size);
|
|
|
|
/* copy-out payload into destination buffer */
|
|
memcpy(dst, source.packet_content(packet), read_num_bytes);
|
|
|
|
source.release_packet(packet);
|
|
|
|
/* prepare next iteration */
|
|
seek_offset += read_num_bytes;
|
|
dst = (void *)((Genode::addr_t)dst + read_num_bytes);
|
|
remaining_count -= read_num_bytes;
|
|
|
|
/*
|
|
* If we received less bytes than requested, we reached the end
|
|
* of the file.
|
|
*/
|
|
if (read_num_bytes < curr_packet_size)
|
|
break;
|
|
}
|
|
|
|
return count - remaining_count;
|
|
}
|
|
|
|
|
|
/**
|
|
* Write file content
|
|
*/
|
|
static inline size_t write(Session &fs, Node_handle const &node_handle,
|
|
void const *src, size_t count, seek_off_t seek_offset = 0)
|
|
{
|
|
bool success = true;
|
|
Session::Tx::Source &source = *fs.tx();
|
|
|
|
size_t const max_packet_size = source.bulk_buffer_size() / 2;
|
|
|
|
size_t remaining_count = count;
|
|
|
|
while (remaining_count && success) {
|
|
|
|
collect_acknowledgements(source);
|
|
|
|
size_t const curr_packet_size = min(remaining_count, max_packet_size);
|
|
|
|
Packet_descriptor
|
|
packet(source.alloc_packet(curr_packet_size),
|
|
node_handle,
|
|
File_system::Packet_descriptor::WRITE,
|
|
curr_packet_size,
|
|
seek_offset);
|
|
|
|
/* copy-out source buffer into payload */
|
|
memcpy(source.packet_content(packet), src, curr_packet_size);
|
|
|
|
/* pass packet to server side */
|
|
source.submit_packet(packet);
|
|
|
|
packet = source.get_acked_packet();;
|
|
success = packet.succeeded();
|
|
source.release_packet(packet);
|
|
|
|
/* prepare next iteration */
|
|
seek_offset += curr_packet_size;
|
|
src = (void *)((Genode::addr_t)src + curr_packet_size);
|
|
remaining_count -= curr_packet_size;
|
|
}
|
|
|
|
return count - remaining_count;
|
|
}
|
|
|
|
|
|
class Handle_guard
|
|
{
|
|
private:
|
|
|
|
Session &_session;
|
|
Node_handle _handle;
|
|
|
|
public:
|
|
|
|
Handle_guard(Session &session, Node_handle handle)
|
|
: _session(session), _handle(handle) { }
|
|
|
|
~Handle_guard() { _session.close(_handle); }
|
|
};
|
|
|
|
class Packet_guard
|
|
{
|
|
private:
|
|
|
|
Session::Tx::Source &_source;
|
|
File_system::Packet_descriptor _packet;
|
|
|
|
public:
|
|
|
|
Packet_guard(Session::Tx::Source &source,
|
|
File_system::Packet_descriptor packet)
|
|
: _source(source), _packet(packet) { }
|
|
|
|
~Packet_guard()
|
|
{
|
|
_source.release_packet(_packet);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif /* _FILE_SYSTEM__UTIL_H_ */
|