L4Re/departure

Annotated libfsserver/lib/files/opener_resource.cc

214:5bb0970d9eb6
2021-10-13 Paul Boddie Introduced a helper method to get parent filesystem objects.
paul@93 1
/*
paul@93 2
 * A resource offering support for creating contexts and opening files.
paul@93 3
 *
paul@93 4
 * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
paul@93 5
 *
paul@93 6
 * This program is free software; you can redistribute it and/or
paul@93 7
 * modify it under the terms of the GNU General Public License as
paul@93 8
 * published by the Free Software Foundation; either version 2 of
paul@93 9
 * the License, or (at your option) any later version.
paul@93 10
 *
paul@93 11
 * This program is distributed in the hope that it will be useful,
paul@93 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@93 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@93 14
 * GNU General Public License for more details.
paul@93 15
 *
paul@93 16
 * You should have received a copy of the GNU General Public License
paul@93 17
 * along with this program; if not, write to the Free Software
paul@93 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@93 19
 * Boston, MA  02110-1301, USA
paul@93 20
 */
paul@93 21
paul@211 22
#include <string.h>
paul@211 23
paul@10 24
#include "opener_server.h"
paul@10 25
#include "opener_resource.h"
paul@10 26
#include "resource_server.h"
paul@9 27
paul@9 28
/* Support for providing access to files. */
paul@9 29
paul@209 30
OpenerResource::OpenerResource(FileObjectRegistry *registry)
paul@209 31
: _registry(registry)
paul@9 32
{
paul@9 33
}
paul@9 34
paul@156 35
OpenerResource::~OpenerResource()
paul@156 36
{
paul@156 37
}
paul@156 38
paul@10 39
int OpenerResource::expected_items()
paul@9 40
{
paul@10 41
    return Opener_expected_items;
paul@9 42
}
paul@9 43
paul@10 44
ipc_server_handler_type OpenerResource::handler()
paul@10 45
{
paul@10 46
    return (ipc_server_handler_type) handle_Opener;
paul@10 47
}
paul@10 48
paul@10 49
paul@10 50
paul@214 51
/* Obtain the identifier for any active parent directory for a path. */
paul@211 52
paul@214 53
long OpenerResource::get_parent(const char *path, fileid_t *fileid)
paul@211 54
{
paul@211 55
    char *sep = strrchr(path, (int) '/');
paul@211 56
    long err;
paul@211 57
paul@211 58
    /* For top-level paths, use the empty string to get the root directory.
paul@211 59
       Otherwise, obtain the parent directory path to obtain the file
paul@211 60
       identifier. */
paul@211 61
paul@211 62
    if (sep == NULL)
paul@214 63
        err = get_fileid("", 0, fileid);
paul@211 64
    else
paul@211 65
    {
paul@211 66
        char *parent = strndup(path, sep - path + 1);
paul@211 67
paul@211 68
        parent[sep - path] = '\0';
paul@214 69
        err = get_fileid(parent, 0, fileid);
paul@211 70
        free(parent);
paul@211 71
    }
paul@211 72
paul@214 73
    return err;
paul@214 74
}
paul@214 75
paul@214 76
/* Obtain any active parent directory for a path, notifying its subscribers of
paul@214 77
   the file opening event. */
paul@214 78
paul@214 79
long OpenerResource::notify_parent(const char *path)
paul@214 80
{
paul@214 81
    DirectoryProvider *provider;
paul@214 82
    fileid_t fileid;
paul@214 83
    long err;
paul@214 84
paul@214 85
    err = get_parent(path, &fileid);
paul@214 86
paul@211 87
    if (err)
paul@211 88
        return err;
paul@211 89
paul@211 90
    /* Obtain the provider of the parent directory. */
paul@211 91
paul@211 92
    err = _registry->find_directory_provider(fileid, &provider);
paul@211 93
paul@211 94
    if (err)
paul@211 95
        return err;
paul@211 96
paul@211 97
    /* With any active provider, send a notification.
paul@211 98
       NOTE: This should also communicate which file was involved, probably
paul@211 99
       NOTE: using the file identifier of the opened file. */
paul@211 100
paul@211 101
    provider->notify_all(NOTIFY_FILE_OPENED);
paul@211 102
    return L4_EOK;
paul@211 103
}
paul@211 104
paul@211 105
paul@211 106
paul@205 107
/* Return an object for the given path and flags. */
paul@10 108
paul@171 109
long OpenerResource::open(const char *path, flags_t flags, offset_t *size,
paul@171 110
                          l4_cap_idx_t *cap, object_flags_t *object_flags)
paul@9 111
{
paul@214 112
    /* Obtain an identifier for the file, even for new files (subject to use of
paul@214 113
       the appropriate flag). */
paul@156 114
paul@156 115
    fileid_t fileid;
paul@156 116
    long err = get_fileid(path, flags, &fileid);
paul@156 117
paul@156 118
    if (err)
paul@156 119
        return err;
paul@156 120
paul@211 121
    /* Notify listeners subscribed to the parent of the opened object. */
paul@211 122
paul@211 123
    notify_parent(path);
paul@211 124
paul@156 125
    /* Test for file and directory access. */
paul@156 126
paul@156 127
    if (accessing_directory(path, flags, fileid))
paul@171 128
        return get_directory(path, flags, fileid, size, cap, object_flags);
paul@156 129
    else if (accessing_file(path, flags, fileid))
paul@171 130
        return get_file(path, flags, fileid, size, cap, object_flags);
paul@156 131
    else
paul@156 132
        return -L4_EIO;
paul@156 133
}
paul@156 134
paul@156 135
paul@156 136
paul@202 137
/* Return a directory object reference for the given file identifier. */
paul@156 138
paul@171 139
long OpenerResource::get_directory(const char *path, flags_t flags,
paul@171 140
                                   fileid_t fileid, offset_t *size,
paul@202 141
                                   l4_cap_idx_t *cap,
paul@202 142
                                   object_flags_t *object_flags)
paul@156 143
{
paul@202 144
    Resource *directory;
paul@209 145
    long err = _registry->get_directory(this, path, flags, fileid, &directory);
paul@202 146
paul@202 147
    if (err)
paul@202 148
        return err;
paul@202 149
paul@202 150
    /* Provide non-file values for certain outputs. */
paul@202 151
paul@202 152
    *size = 0;
paul@202 153
    *object_flags = 0;
paul@202 154
paul@202 155
    return ResourceServer(directory).start_thread(cap);
paul@156 156
}
paul@156 157
paul@156 158
/* Return a file pager. */
paul@156 159
paul@171 160
long OpenerResource::get_file(const char *path, flags_t flags, fileid_t fileid,
paul@171 161
                              offset_t *size, l4_cap_idx_t *cap,
paul@171 162
                              object_flags_t *object_flags)
paul@156 163
{
paul@157 164
    Pager *pager;
paul@209 165
    long err = _registry->get_pager(this, path, flags, fileid, &pager);
paul@157 166
paul@157 167
    if (err)
paul@157 168
        return err;
paul@157 169
paul@202 170
    /* Obtain the size details from the pager, also providing appropriate
paul@202 171
       flags. */
paul@157 172
paul@157 173
    *size = pager->get_data_size();
paul@202 174
    *object_flags = OBJECT_SUPPORTS_MMAP | OBJECT_HAS_SIZE;
paul@157 175
paul@157 176
    return ResourceServer(pager).start_thread(cap);
paul@9 177
}
paul@9 178
paul@10 179
paul@10 180
paul@10 181
/* Opener interface methods. */
paul@10 182
paul@10 183
long OpenerResource::context(l4_cap_idx_t *context)
paul@10 184
{
paul@10 185
    OpenerContextResource *resource = new OpenerContextResource(this);
paul@10 186
paul@62 187
    /* Complete the initialisation and start a server in a new thread.
paul@120 188
       If the thread does not start, the resource will be finalised. */
paul@10 189
paul@120 190
    return ResourceServer(resource).start_thread(context);
paul@10 191
}
paul@10 192
paul@9 193
// vim: tabstop=4 expandtab shiftwidth=4