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 <systypes/fcntl.h> 27 #include <systypes/stat.h> 28 29 #include "ext2_directory_accessor.h" 30 #include "ext2_file_accessor.h" 31 #include "ext2_file_opener.h" 32 #include "resource_server.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_EPERM; 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 /* Remove a filesystem object. */ 136 137 long Ext2FileOpener::remove_object(fileid_t fileid) 138 { 139 return _ops->remove((ext2_ino_t) fileid); 140 } 141 142 /* Rename a filesystem object, placing source inside the parent of target. */ 143 144 long Ext2FileOpener::rename_object(const char *source, const char *target) 145 { 146 fileid_t source_fileid, source_parent, target_parent; 147 long err; 148 149 err = get_fileid(source, 0, &source_fileid); 150 151 if (err) 152 return err; 153 154 err = get_parent(source, &source_parent); 155 156 if (err) 157 return err; 158 159 err = get_parent(target, &target_parent); 160 161 if (err) 162 return err; 163 164 return _ops->rename((ext2_ino_t) source_fileid, 165 (ext2_ino_t) source_parent, path_basename(source), 166 (ext2_ino_t) target_parent, path_basename(target)); 167 } 168 169 /* Populate a memory region with statistics metadata for a filesystem object. */ 170 171 long Ext2FileOpener::stat_object(const char *path, void *base, offset_t size) 172 { 173 struct stat st; 174 fileid_t fileid; 175 long err = get_fileid(path, 0, &fileid); 176 177 if (err) 178 return err; 179 180 if (sizeof(struct stat) > size) 181 return -L4_ENOMEM; 182 183 err = _ops->stat_inode((ext2_ino_t) fileid, &st); 184 185 if (err) 186 return err; 187 188 /* Use the systypes version of the structure to permit different library 189 implementations on the client and server sides of an IPC invocation. */ 190 191 systypes_copy_to_sys_stat(&st, (sys_stat_t *) base); 192 193 return L4_EOK; 194 } 195 196 /* Unlink a filesystem object. */ 197 198 long Ext2FileOpener::unlink_object(fileid_t parent_fileid, fileid_t fileid) 199 { 200 return _ops->unlink((ext2_ino_t) parent_fileid, (ext2_ino_t) fileid); 201 } 202 203 // vim: tabstop=4 expandtab shiftwidth=4