#include <object.h>
#include <list.h>
#include <clock.h>
+#include <sync.h>
#define PATH_DELIMITER_CHAR '/'
#define PATH_DELIMITER_STRING "/"
#define MOUNT_FLAG_READONLY (1 << 0)
+#define EVENT_QUEUE_CAPACITY 256
+
typedef struct mounted_volume mounted_volume_t;
typedef struct file file_t;
typedef struct file_instance file_instance_t;
clock_time_t last_access_time;
} file_time_info_t;
+typedef struct
+{
+ dword_t type;
+ char filename[VARIABLE_SIZE];
+} file_event_t;
+
+typedef struct
+{
+ list_entry_t list;
+ file_event_t event;
+} event_queue_entry_t;
+
+typedef struct
+{
+ list_entry_t list;
+ lock_t lock;
+ file_instance_t *directory;
+ dword_t event_mask;
+ semaphore_t event_semaphore;
+ list_entry_t event_queue;
+} event_watch_entry_t;
+
struct file
{
object_t header;
object_t header;
file_t *global;
dword_t mode;
+ event_watch_entry_t *watch;
};
#include <device.h>
static DECLARE_LIST(fs_driver_list);
static DECLARE_LIST(volumes);
+static DECLARE_LIST(event_watch_list);
lock_t fs_driver_list_lock = 0;
+lock_t event_watch_list_lock = 0;
resource_t volume_list_res = 0;
static inline int count_delimiters(const char *string)
void file_instance_cleanup(file_instance_t *instance)
{
file_t *file = instance->global;
+
+ if (instance->watch)
+ {
+ ASSERT(file->attributes & FILE_ATTR_DIRECTORY);
+ ASSERT(instance->watch->directory == instance);
+
+ acquire_lock(&event_watch_list_lock);
+ list_remove(&instance->watch->list);
+ release_lock(&event_watch_list_lock);
+
+ ASSERT(!instance->watch->lock);
+
+ while (instance->watch->event_queue.next != &instance->watch->event_queue)
+ {
+ event_queue_entry_t *entry = CONTAINER_OF(instance->watch->event_queue.next, event_queue_entry_t, list);
+ list_remove(&entry->list);
+ free(entry);
+ }
+
+ free(instance->watch);
+ instance->watch = NULL;
+ }
+
file->volume->driver->close_file(instance);
if (instance->mode & FILE_MODE_DELETE_ON_CLOSE)
dereference(&file->header);
return ret;
}
+
+dword_t wait_directory_event(handle_t handle, dword_t event_mask, file_event_t *buffer, size_t size, dword_t timeout)
+{
+ file_instance_t *directory;
+
+ if (get_previous_mode() == USER_MODE && !check_usermode(buffer, size)) return ERR_BADPTR;
+ if (!reference_by_handle(handle, OBJECT_FILE_INSTANCE, (object_t**)&directory)) return ERR_INVALID;
+
+ if (!(directory->global->attributes & FILE_ATTR_DIRECTORY))
+ {
+ dereference(&directory->header);
+ return ERR_ISNOTDIR;
+ }
+
+ if (directory->watch == NULL)
+ {
+ event_watch_entry_t *watch = (event_watch_entry_t*)malloc(sizeof(event_watch_entry_t));
+ watch->directory = directory;
+ init_semaphore(&watch->event_semaphore, 0, EVENT_QUEUE_CAPACITY);
+ list_init(&watch->event_queue);
+
+ acquire_lock(&event_watch_list_lock);
+ list_append(&event_watch_list, &watch->list);
+
+ if (!__sync_bool_compare_and_swap(&directory->watch, NULL, watch))
+ {
+ list_remove(&watch->list);
+ free(watch);
+ }
+
+ release_lock(&event_watch_list_lock);
+ }
+
+ directory->watch->event_mask = event_mask;
+
+ dword_t ret = wait_semaphore(&directory->watch->event_semaphore, 1, timeout);
+ if (ret != ERR_SUCCESS)
+ {
+ dereference(&directory->header);
+ return ret;
+ }
+
+ acquire_lock(&directory->watch->lock);
+
+ event_queue_entry_t *entry = CONTAINER_OF(directory->watch->event_queue.next, event_queue_entry_t, list);
+ dword_t event_size = sizeof(entry->event) + strlen(entry->event.filename) + 1;
+
+ if (size >= event_size)
+ {
+ EH_TRY memcpy(buffer, &entry->event, event_size);
+ EH_CATCH ret = ERR_BADPTR;
+ EH_DONE;
+
+ if (ret == ERR_SUCCESS)
+ {
+ list_remove(&entry->list);
+ free(entry);
+ }
+ }
+ else
+ {
+ ret = ERR_SMALLBUF;
+ }
+
+ if (ret != ERR_SUCCESS) release_semaphore(&directory->watch->event_semaphore, 1);
+ release_lock(&directory->watch->lock);
+ dereference(&directory->header);
+ return ret;
+}