L4Re/departure

libfsserver/lib/files/ext2_file_opener.cc

590:30ec30848a39
9 months ago Paul Boddie Allow stat operations on objects without needing access. Otherwise, no metadata is available for things like directory listings.
     1 /*     2  * An opener for a file provided by an Ext2-compatible filesystem.     3  *     4  * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software; you can redistribute it and/or     7  * modify it under the terms of the GNU General Public License as     8  * published by the Free Software Foundation; either version 2 of     9  * the License, or (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program; if not, write to the Free Software    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    19  * Boston, MA  02110-1301, USA    20  */    21     22 #include <string.h>    23     24 #include <e2access/path.h>    25 #include <fsclient/client.h>    26 #include <resource/resource_server.h>    27 #include <systypes/fcntl.h>    28 #include <systypes/stat.h>    29     30 #include "ext2_directory_accessor.h"    31 #include "ext2_file_accessor.h"    32 #include "ext2_file_opener.h"    33     34     35     36 Ext2FileOpener::~Ext2FileOpener()    37 {    38 }    39     40 /* Test if a directory is being accessed. */    41     42 bool Ext2FileOpener::accessing_directory(flags_t flags, fileid_t fileid)    43 {    44     (void) flags;    45     return _ops->is_directory((ext2_ino_t) fileid);    46 }    47     48 /* Test if a file is being accessed. */    49     50 bool Ext2FileOpener::accessing_file(flags_t flags, fileid_t fileid)    51 {    52     (void) flags;    53     return _ops->is_file((ext2_ino_t) fileid);    54 }    55     56 /* Test if a directory is empty. */    57     58 bool Ext2FileOpener::directory_is_empty(fileid_t fileid)    59 {    60     return _ops->directory_is_empty(fileid);    61 }    62     63 /* Return a file identifier for the given 'path'. */    64     65 long Ext2FileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid)    66 {    67     ext2_ino_t ino;    68     const char *remaining;    69     long err = _ops->find_file(path, &ino, &remaining);    70     71     /* Return an existing file. */    72     73     if (!err)    74     {    75         if (!_ops->can_access(_user, flags, ino))    76             return -L4_EACCESS;    77     78         *fileid = (fileid_t) ino;    79         return L4_EOK;    80     }    81     82     *fileid = FILEID_INVALID;    83     84     /* Create a missing file if possible. */    85     86     if ((flags & O_CREAT) && (flags & ~O_DIRECTORY))    87     {    88         /* Determine whether only the leafname is left of the path, with    89            the inode number referring to the parent directory. */    90     91         if (path_is_leafname(remaining))    92         {    93             err = _ops->create_file(ino, remaining, _user, &ino);    94             if (err)    95                 return err;    96     97             *fileid = (fileid_t) ino;    98             return L4_EOK;    99         }   100     }   101    102     return -L4_ENOENT;   103 }   104    105 /* Return a new accessor for 'fileid'. */   106    107 long Ext2FileOpener::make_accessor(flags_t flags, fileid_t fileid,   108                                    Accessor **accessor)   109 {   110     (void) flags;   111    112     ext2_file_t file;   113     long err = _ops->open_file((ext2_ino_t) fileid, &file);   114    115     if (err)   116         return err;   117    118     *accessor = new Ext2FileAccessor(_ops, file, fileid);   119     return L4_EOK;   120 }   121    122 /* Return a directory object reference for the given file identifier. */   123    124 long Ext2FileOpener::make_directory_accessor(flags_t flags, fileid_t fileid,   125                                              DirectoryAccessor **accessor)   126 {   127     (void) flags;   128    129     *accessor = new Ext2DirectoryAccessor(_ops, fileid);   130     return L4_EOK;   131 }   132    133    134    135 /* Make a new directory. */   136    137 long Ext2FileOpener::make_directory_object(const char *path, sys_mode_t mode)   138 {   139     fileid_t fileid, parent;   140     long err;   141    142     /* Test for an existing object. */   143    144     err = get_fileid(path, 0, &fileid);   145    146     if (!err)   147         return -L4_EEXIST;   148    149     if (err != -L4_ENOENT)   150         return err;   151    152     /* Obtain the parent of the new directory. */   153    154     err = get_parent(path, &parent);   155    156     if (err)   157         return err;   158    159     return _ops->mkdir((ext2_ino_t) parent, path_basename(path),   160                        systypes_from_sys_mode(mode), _user);   161 }   162    163 /* Remove a filesystem object. */   164    165 long Ext2FileOpener::remove_object(fileid_t fileid)   166 {   167     return _ops->remove((ext2_ino_t) fileid);   168 }   169    170 /* Rename a filesystem object, placing source inside the parent of target. */   171    172 long Ext2FileOpener::rename_object(const char *source, const char *target)   173 {   174     fileid_t source_fileid, source_parent, target_parent;   175     long err;   176    177     err = get_fileid(source, 0, &source_fileid);   178    179     if (err)   180         return err;   181    182     err = get_parent(source, &source_parent);   183    184     if (err)   185         return err;   186    187     err = get_parent(target, &target_parent);   188    189     if (err)   190         return err;   191    192     return _ops->rename((ext2_ino_t) source_fileid,   193                         (ext2_ino_t) source_parent, path_basename(source),   194                         (ext2_ino_t) target_parent, path_basename(target));   195 }   196    197 /* Populate a memory region with statistics metadata for a filesystem object. */   198    199 long Ext2FileOpener::stat_object(const char *path, void *base, offset_t size)   200 {   201     struct stat st;   202     fileid_t fileid;   203    204     /* Find the object without access restrictions since the metadata is not   205        sensitive. */   206    207     ext2_ino_t ino;   208     const char *remaining;   209     long err = _ops->find_file(path, &ino, &remaining);   210    211     if (err)   212         return -L4_ENOENT;   213    214     fileid = (fileid_t) ino;   215    216     if (sizeof(struct stat) > size)   217         return -L4_ENOMEM;   218    219     err = _ops->stat_inode((ext2_ino_t) fileid, &st);   220    221     if (err)   222         return err;   223    224     /* Use the systypes version of the structure to permit different library   225        implementations on the client and server sides of an IPC invocation. */   226    227     systypes_copy_to_sys_stat(&st, (sys_stat_t *) base);   228    229     return L4_EOK;   230 }   231    232 /* Unlink a filesystem object. */   233    234 long Ext2FileOpener::unlink_object(fileid_t parent_fileid, fileid_t fileid)   235 {   236     return _ops->unlink((ext2_ino_t) parent_fileid, (ext2_ino_t) fileid);   237 }   238    239 // vim: tabstop=4 expandtab shiftwidth=4