1 /* 2 * File operations performed 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 <e2access/access.h> 23 #include <e2access/image.h> 24 #include <e2access/path.h> 25 26 #include "ext2_file_operations.h" 27 28 /* Object type tests. */ 29 30 bool Ext2FileOperations::is_directory(ext2_ino_t ino_file) 31 { 32 std::lock_guard<std::mutex> guard(_lock); 33 34 return _image_isdir(_fs, ino_file); 35 } 36 37 bool Ext2FileOperations::is_file(ext2_ino_t ino_file) 38 { 39 std::lock_guard<std::mutex> guard(_lock); 40 41 return _image_isfile(_fs, ino_file); 42 } 43 44 /* Perform closing operations on a file. */ 45 46 void Ext2FileOperations::close_file(ext2_file_t file) 47 { 48 std::lock_guard<std::mutex> guard(_lock); 49 50 ext2fs_file_flush(file); 51 ext2fs_file_close(file); 52 } 53 54 /* Create a file in the directory indicated by the given inode number with the 55 given filename. The file is created with the given user permissions. */ 56 57 long Ext2FileOperations::create_file(ext2_ino_t ino_parent, const char *filename, 58 user_t user, ext2_ino_t *ino) 59 { 60 if (!path_is_leafname(filename)) 61 return -L4_EINVAL; 62 63 std::lock_guard<std::mutex> guard(_lock); 64 65 struct ext2_inode inode_parent; 66 errcode_t retval = ext2fs_read_inode(_fs, ino_parent, &inode_parent); 67 68 if (retval) 69 return -L4_EIO; 70 71 if (!access_can_write(user, &inode_parent)) 72 return -L4_EPERM; 73 74 if (image_create_file(_fs, ino_parent, filename, 0666 & ~user.umask, 75 user.uid, user.gid, ino)) 76 return -L4_EIO; 77 78 return L4_EOK; 79 } 80 81 /* For the given 'path', return an inode number or indicate the 'remaining' 82 part of the path that cannot be resolved. */ 83 84 long Ext2FileOperations::find_file(const char *path, ext2_ino_t *ino, 85 const char **remaining) 86 { 87 std::lock_guard<std::mutex> guard(_lock); 88 89 *remaining = path; 90 errcode_t retval = image_find_path(_fs, remaining, ino); 91 92 // NOTE: Map error conditions. 93 94 if (retval) 95 return -L4_EIO; 96 97 return L4_EOK; 98 } 99 100 /* Open the file associated with the indicated inode. */ 101 102 long Ext2FileOperations::open_file(ext2_ino_t ino, ext2_file_t *file) 103 { 104 std::lock_guard<std::mutex> guard(_lock); 105 106 errcode_t retval = ext2fs_file_open(_fs, ino, EXT2_FILE_WRITE, file); 107 108 // NOTE: Map error conditions. 109 110 if (retval) 111 return -L4_EIO; 112 113 return L4_EOK; 114 } 115 116 /* Remove an object from a directory. */ 117 118 long Ext2FileOperations::remove(ext2_ino_t ino) 119 { 120 std::lock_guard<std::mutex> guard(_lock); 121 122 errcode_t retval = image_remove_by_inode(_fs, ino); 123 124 // NOTE: Map error conditions. 125 126 if (retval) 127 return -L4_EIO; 128 129 return L4_EOK; 130 } 131 132 /* Rename an object. */ 133 134 long Ext2FileOperations::rename(ext2_ino_t source, 135 ext2_ino_t source_parent, const char *source_basename, 136 ext2_ino_t target_parent, const char *target_basename) 137 { 138 std::lock_guard<std::mutex> guard(_lock); 139 140 errcode_t retval = image_rename(_fs, source, source_parent, source_basename, 141 target_parent, target_basename); 142 143 // NOTE: Map error conditions. 144 145 if (retval) 146 return -L4_EIO; 147 148 return L4_EOK; 149 } 150 151 /* Unlink an object from a directory. */ 152 153 long Ext2FileOperations::unlink(ext2_ino_t ino_parent, ext2_ino_t ino) 154 { 155 std::lock_guard<std::mutex> guard(_lock); 156 157 errcode_t retval = image_unlink_by_inode(_fs, ino_parent, ino); 158 159 // NOTE: Map error conditions. 160 161 if (retval) 162 return -L4_EIO; 163 164 return L4_EOK; 165 } 166 167 168 169 /* Obtain the size of a file. */ 170 171 offset_t Ext2FileOperations::get_size(ext2_file_t file) 172 { 173 std::lock_guard<std::mutex> guard(_lock); 174 175 return ext2fs_file_get_size(file); 176 } 177 178 /* Update the size of a file. */ 179 180 void Ext2FileOperations::set_size(ext2_file_t file, offset_t size) 181 { 182 std::lock_guard<std::mutex> guard(_lock); 183 184 ext2fs_file_set_size(file, size); 185 } 186 187 /* Populate the given memory region with file content. */ 188 189 offset_t Ext2FileOperations::read_file(ext2_file_t file, offset_t filepos, void *addr, offset_t size) 190 { 191 std::lock_guard<std::mutex> guard(_lock); 192 193 unsigned int nread; 194 195 ext2fs_file_llseek(file, filepos, SEEK_SET, NULL); 196 ext2fs_file_read(file, (void *) addr, size, &nread); 197 198 return (offset_t) nread; 199 } 200 201 /* Transfer content from the given memory region to a file. */ 202 203 void Ext2FileOperations::write_file(ext2_file_t file, offset_t filepos, const void *addr, offset_t size) 204 { 205 std::lock_guard<std::mutex> guard(_lock); 206 207 ext2fs_file_llseek(file, filepos, SEEK_SET, NULL); 208 ext2fs_file_write(file, addr, size, NULL); 209 } 210 211 /* Obtain information for the given inode. */ 212 213 long Ext2FileOperations::read_inode(ext2_ino_t ino, struct ext2_inode *inode) 214 { 215 std::lock_guard<std::mutex> guard(_lock); 216 217 if (ext2fs_read_inode(_fs, ino, inode)) 218 return -L4_EIO; 219 220 return L4_EOK; 221 } 222 223 224 225 /* Directory iteration support. */ 226 227 /* Callback function invoking the callback method. */ 228 229 static int _directory_iterate_fn(struct ext2_dir_entry *dir_entry, 230 int offset, int blocksize, char *buf, 231 void *priv_data) 232 { 233 struct Ext2DirectoryIteration *data = reinterpret_cast<struct Ext2DirectoryIteration *>(priv_data); 234 235 return data->ops->directory_iterate_fn(dir_entry, offset, blocksize, buf, data); 236 } 237 238 /* Callback method invoking the actual callback, with control over locking. */ 239 240 int Ext2FileOperations::directory_iterate_fn(struct ext2_dir_entry *dir_entry, 241 int offset, int blocksize, 242 char *buf, struct Ext2DirectoryIteration *priv_data) 243 { 244 /* Release the lock to allow other operations to proceed. */ 245 246 _lock.unlock(); 247 248 /* Invoke the actual callback function. */ 249 250 struct Ext2DirectoryIteration *data = reinterpret_cast<struct Ext2DirectoryIteration *>(priv_data); 251 int result = data->func(dir_entry, offset, blocksize, buf, data->priv_data); 252 253 /* Acquire the lock and continue iteration. */ 254 255 _lock.lock(); 256 return result; 257 } 258 259 /* Initiate iteration over a directory, with the given 'func' being called 260 with directory entry details for each entry. */ 261 262 long Ext2FileOperations::directory_iterate(ext2_ino_t dir, 263 int func(struct ext2_dir_entry *, int, int, 264 char *, void *), 265 void *priv_data) 266 { 267 /* NOTE: Iteration should probably be interrupted if it appears that the 268 directory has been modified and the structure of the data has 269 been changed. This condition might then cause iteration to begin 270 again, skipping ahead to the entry after the last visited entry. */ 271 272 /* Acquire the lock for iteration to proceed safely. */ 273 274 _lock.lock(); 275 276 /* Begin iteration using the given callback function to invoke a callback 277 method in this object that will wrap the actual callback with locking 278 operations. */ 279 280 struct Ext2DirectoryIteration data = {this, func, priv_data}; 281 int result = ext2fs_dir_iterate(_fs, dir, 0, 0, _directory_iterate_fn, &data); 282 283 /* Release the lock upon finishing iteration. */ 284 285 _lock.unlock(); 286 287 if (result) 288 return -L4_EIO; 289 else 290 return L4_EOK; 291 } 292 293 // vim: tabstop=4 expandtab shiftwidth=4