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