L4Re/departure

Annotated libfsserver/lib/files/file_object_registry.cc

220:8bf9abc10ae7
2021-10-17 Paul Boddie Reorganised the mechanism of obtaining providers and resources in the registry.
paul@93 1
/*
paul@202 2
 * File registry and opening functionality.
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@202 22
#include "directory_resource.h"
paul@209 23
#include "file_object_registry.h"
paul@79 24
#include "file_pager.h"
paul@9 25
paul@85 26
#include <systypes/fcntl.h>
paul@85 27
paul@79 28
paul@79 29
paul@209 30
/* The file object registry provides a memory page collection to the page
paul@200 31
   mappers it creates. */
paul@200 32
paul@209 33
FileObjectRegistry::FileObjectRegistry(Pages *pages)
paul@200 34
: _pages(pages)
paul@94 35
{
paul@94 36
}
paul@94 37
paul@85 38
paul@85 39
paul@87 40
/* Convert opening flags to map-compatible paging flags. */
paul@85 41
paul@209 42
map_flags_t FileObjectRegistry::get_flags(flags_t flags)
paul@85 43
{
paul@87 44
    return flags & (O_WRONLY | O_RDWR) ? L4RE_DS_MAP_FLAG_RW : L4RE_DS_MAP_FLAG_RO;
paul@85 45
}
paul@85 46
paul@85 47
paul@85 48
paul@220 49
/* Make a directory provider. */
paul@202 50
paul@220 51
long FileObjectRegistry::make_directory_provider(FileOpening *opening,
paul@220 52
                                                 const char *path, flags_t flags,
paul@220 53
                                                 fileid_t fileid,
paul@220 54
                                                 Provider **provider)
paul@208 55
{
paul@202 56
    /* Make an accessor and a provider to encapsulate it. */
paul@202 57
paul@202 58
    DirectoryAccessor *accessor;
paul@220 59
    long err = opening->make_directory_accessor(path, flags, fileid, &accessor);
paul@202 60
paul@202 61
    if (err)
paul@202 62
        return err;
paul@202 63
paul@220 64
    *provider = new DirectoryProvider(accessor);
paul@200 65
paul@202 66
    /* Register the provider. */
paul@202 67
paul@220 68
    set(fileid, *provider);
paul@202 69
    return L4_EOK;
paul@202 70
}
paul@202 71
paul@220 72
/* Make a file provider. */
paul@202 73
paul@220 74
long FileObjectRegistry::make_file_provider(FileOpening *opening,
paul@220 75
                                            const char *path, flags_t flags,
paul@220 76
                                            fileid_t fileid,
paul@220 77
                                            Provider **provider)
paul@220 78
{
paul@200 79
    /* Make an accessor, page mapper, and a provider to encapsulate them. */
paul@79 80
paul@143 81
    Accessor *accessor;
paul@144 82
    long err = opening->make_accessor(path, flags, fileid, &accessor);
paul@106 83
paul@143 84
    if (err)
paul@143 85
        return err;
paul@106 86
paul@200 87
    PageMapper *mapper = new PageMapper(accessor, _pages);
paul@220 88
    *provider = new FileProvider(mapper);
paul@79 89
paul@200 90
    /* Register the provider. */
paul@79 91
paul@220 92
    set(fileid, *provider);
paul@143 93
    return L4_EOK;
paul@79 94
}
paul@79 95
paul@220 96
/* Make a provider of the appropriate type. */
paul@220 97
paul@220 98
long FileObjectRegistry::make_provider(FileOpening *opening,
paul@220 99
                                       const char *path, flags_t flags,
paul@220 100
                                       fileid_t fileid,
paul@220 101
                                       Provider **provider)
paul@220 102
{
paul@220 103
    if (opening->accessing_directory(path, flags, fileid))
paul@220 104
        return make_directory_provider(opening, path, flags, fileid, provider);
paul@220 105
    else if (opening->accessing_file(path, flags, fileid))
paul@220 106
        return make_file_provider(opening, path, flags, fileid, provider);
paul@220 107
    else
paul@220 108
        return -L4_EIO;
paul@220 109
}
paul@220 110
paul@79 111
paul@79 112
paul@202 113
/* Return a directory resource initialised with a provider. */
paul@202 114
paul@220 115
long FileObjectRegistry::make_directory_resource(fileid_t fileid, offset_t *size,
paul@220 116
                                                 object_flags_t *object_flags,
paul@220 117
                                                 DirectoryProvider *provider,
paul@220 118
                                                 Resource **resource)
paul@202 119
{
paul@218 120
    /* Provide non-file values for certain outputs. */
paul@218 121
paul@218 122
    *size = 0;
paul@218 123
    *object_flags = 0;
paul@218 124
paul@202 125
    /* Initialise the resource with the provider and a reference to this object
paul@202 126
       for detaching from the provider. */
paul@202 127
paul@202 128
    provider->attach();
paul@202 129
    *resource = new DirectoryResource(fileid, provider, this);
paul@202 130
    return L4_EOK;
paul@202 131
}
paul@202 132
paul@218 133
/* Return a file pager initialised with a provider, page mapper and accessor. */
paul@79 134
paul@220 135
long FileObjectRegistry::make_file_resource(flags_t flags, fileid_t fileid,
paul@220 136
                                            offset_t *size,
paul@220 137
                                            object_flags_t *object_flags,
paul@220 138
                                            FileProvider *provider,
paul@220 139
                                            Resource **resource)
paul@79 140
{
paul@200 141
    /* Initialise the pager with the provider and a reference to this object for
paul@202 142
       detaching from the provider. */
paul@79 143
paul@218 144
    FilePager *pager = new FilePager(fileid, provider, get_flags(flags), this);
paul@218 145
paul@218 146
    /* Obtain the size details from the pager, also providing appropriate
paul@218 147
       flags. */
paul@218 148
paul@218 149
    *size = pager->get_data_size();
paul@218 150
    *object_flags = OBJECT_SUPPORTS_MMAP | OBJECT_HAS_SIZE;
paul@218 151
paul@200 152
    provider->attach();
paul@218 153
    *resource = pager;
paul@143 154
    return L4_EOK;
paul@79 155
}
paul@79 156
paul@220 157
/* Make a resource of the appropriate type. */
paul@220 158
paul@220 159
long FileObjectRegistry::make_resource(flags_t flags, fileid_t fileid,
paul@220 160
                                       offset_t *size,
paul@220 161
                                       object_flags_t *object_flags,
paul@220 162
                                       Provider *provider, Resource **resource)
paul@220 163
{
paul@220 164
    DirectoryProvider *dp = dynamic_cast<DirectoryProvider *>(provider);
paul@220 165
paul@220 166
    if (dp != NULL)
paul@220 167
        return make_directory_resource(fileid, size, object_flags, dp, resource);
paul@220 168
paul@220 169
    FileProvider *fp = dynamic_cast<FileProvider *>(provider);
paul@220 170
paul@220 171
    if (fp != NULL)
paul@220 172
        return make_file_resource(flags, fileid, size, object_flags, fp, resource);
paul@220 173
paul@220 174
    return -L4_EIO;
paul@220 175
}
paul@220 176
paul@218 177
paul@218 178
paul@218 179
/* Return a resource for a filesystem object. */
paul@218 180
paul@218 181
long FileObjectRegistry::get_resource(FileOpening *opening, const char *path,
paul@218 182
                                      flags_t flags, offset_t *size,
paul@218 183
                                      object_flags_t *object_flags,
paul@218 184
                                      Resource **resource)
paul@218 185
{
paul@218 186
    std::lock_guard<std::mutex> guard(_lock);
paul@218 187
paul@220 188
    /* Obtain an identifier for the object, even for new files (subject to use
paul@220 189
       of the appropriate flag). */
paul@218 190
paul@218 191
    fileid_t fileid;
paul@218 192
    long err = opening->get_fileid(path, flags, &fileid);
paul@218 193
paul@218 194
    if (err)
paul@218 195
        return err;
paul@218 196
paul@220 197
    /* Obtain a provider for the object. */
paul@220 198
paul@220 199
    Provider *provider;
paul@220 200
    err = find_provider(fileid, &provider);
paul@220 201
paul@220 202
    /* Make a new provider if necessary. */
paul@220 203
paul@220 204
    if (err == -L4_ENOENT)
paul@220 205
        err = make_provider(opening, path, flags, fileid, &provider);
paul@220 206
paul@220 207
    if (err)
paul@220 208
        return err;
paul@220 209
paul@220 210
    /* Make a resource for the provider. */
paul@220 211
paul@220 212
    return make_resource(flags, fileid, size, object_flags, provider, resource);
paul@220 213
}
paul@220 214
paul@220 215
paul@218 216
paul@220 217
/* Obtain any active provider for the given 'fileid'. */
paul@220 218
paul@220 219
long FileObjectRegistry::find_provider(fileid_t fileid, Provider **provider)
paul@220 220
{
paul@220 221
    /* Obtain any registered provider. */
paul@220 222
paul@220 223
    Accountable *accountable = get(fileid);
paul@220 224
paul@220 225
    if (accountable != NULL)
paul@220 226
    {
paul@220 227
        *provider = dynamic_cast<Provider *>(accountable);
paul@220 228
paul@220 229
        if ((*provider) != NULL)
paul@220 230
            return L4_EOK;
paul@220 231
        else
paul@220 232
            return -L4_EIO;
paul@220 233
    }
paul@220 234
paul@220 235
    return -L4_ENOENT;
paul@218 236
}
paul@218 237
paul@9 238
// vim: tabstop=4 expandtab shiftwidth=4