1 /* 2 * An opener for a "host" file provided via the C library. 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 <stdio.h> 23 #include <sys/stat.h> 24 #include <unistd.h> 25 26 #include <fsclient/client.h> 27 28 #include "host_directory_accessor.h" 29 #include "host_file_accessor.h" 30 #include "host_file_opener.h" 31 #include "resource_server.h" 32 33 34 35 HostFileOpener::~HostFileOpener() 36 { 37 } 38 39 bool HostFileOpener::accessing_directory(flags_t flags, fileid_t fileid) 40 { 41 (void) flags; 42 43 const char *path = _get_path(fileid); 44 45 if (path == NULL) 46 return false; 47 48 struct stat st; 49 50 if (stat(path, &st)) 51 return false; 52 53 return (st.st_mode & S_IFDIR) ? true : false; 54 } 55 56 bool HostFileOpener::accessing_file(flags_t flags, fileid_t fileid) 57 { 58 (void) flags; 59 struct stat st; 60 61 const char *path = _get_path(fileid); 62 63 if (path == NULL) 64 return false; 65 66 if (stat(path, &st)) 67 return false; 68 69 return (st.st_mode & S_IFREG) ? true : false; 70 } 71 72 /* Return a file identifier for the given 'path'. */ 73 74 long HostFileOpener::get_fileid(const char *path, flags_t flags, fileid_t *fileid) 75 { 76 (void) flags; 77 78 /* Test for a valid file. */ 79 80 FILE *fp = fopen(path, "r"); 81 82 if (fp == NULL) 83 return -L4_ENOENT; 84 85 fclose(fp); 86 87 *fileid = _get_fileid(path, true); 88 return L4_EOK; 89 } 90 91 fileid_t HostFileOpener::_get_fileid(const char *path, bool create) 92 { 93 std::lock_guard<std::mutex> guard(_lock); 94 95 /* The inode number would be a good choice, but the L4Re read-only file 96 implementation just provides the value of a counter! 97 98 See: pkg/l4re-core/l4re_vfs/include/impl/ro_file_impl.h */ 99 100 std::string s(path); 101 102 HostFileIdentifiers::iterator it = _fileids.find(s); 103 104 if (it != _fileids.end()) 105 return it->second; 106 107 if (!create) 108 return FILEID_INVALID; 109 110 fileid_t fileid = _fileids.size(); 111 112 _fileids[s] = fileid; 113 _paths[fileid] = s; 114 115 return fileid; 116 } 117 118 const char *HostFileOpener::_get_path(fileid_t fileid) 119 { 120 std::lock_guard<std::mutex> guard(_lock); 121 122 HostFilePaths::iterator it = _paths.find(fileid); 123 124 if (it != _paths.end()) 125 return it->second.c_str(); 126 else 127 return NULL; 128 } 129 130 /* Return a new accessor for 'fileid'. */ 131 132 long HostFileOpener::make_accessor(flags_t flags, fileid_t fileid, 133 Accessor **accessor) 134 { 135 // NOTE: Not testing for create or write flags. 136 137 (void) flags; 138 139 const char *path = _get_path(fileid); 140 141 if (path == NULL) 142 return -L4_ENOENT; 143 144 FILE *fp = fopen(path, "r"); 145 146 if (fp == NULL) 147 return -L4_ENOENT; 148 149 *accessor = new HostFileAccessor(fp, fileid); 150 return L4_EOK; 151 } 152 153 /* Return a directory accessor for 'fileid'. */ 154 155 long HostFileOpener::make_directory_accessor(flags_t flags, fileid_t fileid, 156 DirectoryAccessor **accessor) 157 { 158 (void) flags; 159 160 const char *path = _get_path(fileid); 161 162 if (path == NULL) 163 return -L4_ENOENT; 164 165 *accessor = new HostDirectoryAccessor(path); 166 return L4_EOK; 167 } 168 169 /* Remove a filesystem object. */ 170 171 long HostFileOpener::remove_object(fileid_t fileid) 172 { 173 (void) fileid; 174 return L4_EOK; 175 } 176 177 /* Rename a filesystem object, placing source inside the parent of target. */ 178 179 long HostFileOpener::rename_object(const char *source, const char *target) 180 { 181 /* NOTE: Should propagate a more meaningful error. */ 182 183 if (rename(source, target)) 184 return -L4_EIO; 185 186 return L4_EOK; 187 } 188 189 /* Unlink a filesystem object. */ 190 191 long HostFileOpener::unlink_object(fileid_t parent_fileid, fileid_t fileid) 192 { 193 /* Ignore the parent and always use the path. */ 194 195 (void) parent_fileid; 196 197 const char *path = _get_path(fileid); 198 199 if (path == NULL) 200 return -L4_ENOENT; 201 202 // NOTE: Return code may need converting. 203 204 int err = unlink(path); 205 206 if (err) 207 return err; 208 209 /* Remove the file identifier mapping. */ 210 211 std::string s(path); 212 213 HostFileIdentifiers::iterator it = _fileids.find(s); 214 215 if (it != _fileids.end()) 216 _fileids.erase(it); 217 218 HostFilePaths::iterator pit = _paths.find(fileid); 219 220 if (pit != _paths.end()) 221 _paths.erase(pit); 222 223 return L4_EOK; 224 } 225 226 // vim: tabstop=4 expandtab shiftwidth=4