1 /* 2 * A resource offering support for accessing directories. 3 * 4 * Copyright (C) 2021 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 <thread> 23 24 #include <fsclient/client.h> 25 #include <ipc/cap_alloc.h> 26 27 #include "directory_resource.h" 28 #include "directory_object_server.h" 29 30 31 32 DirectoryResource::DirectoryResource(fileid_t fileid, 33 DirectoryProvider *provider, 34 FileRegistry *registry) 35 : _registry(registry), _provider(provider), fileid(fileid) 36 { 37 } 38 39 DirectoryResource::~DirectoryResource() 40 { 41 } 42 43 44 45 int DirectoryResource::expected_items() 46 { 47 return DirectoryObject_expected_items; 48 } 49 50 ipc_server_handler_type DirectoryResource::handler() 51 { 52 return (ipc_server_handler_type) handle_DirectoryObject; 53 } 54 55 56 57 /* Close the resource, removing the provider from the registry if 58 appropriate. */ 59 60 void DirectoryResource::close() 61 { 62 /* Detach the resource, potentially removing the file provider. */ 63 64 _registry->detach(fileid, _provider); 65 } 66 67 68 69 /* Thread payload for directory listing production. */ 70 71 static void read_directory(FileRegistry *registry, DirectoryProvider *provider, 72 fileid_t fileid, file_t *writer) 73 { 74 DirectoryAccessor *accessor = provider->accessor(); 75 76 /* Attach to the provider to keep it available, even if the directory 77 resource is released. */ 78 79 provider->attach(); 80 81 /* Invoke the directory reading mechanism. */ 82 83 accessor->read_directory(writer); 84 85 /* Close and detach from the registry. */ 86 87 client_close(writer); 88 registry->detach(fileid, provider); 89 } 90 91 92 93 /* Open a directory to read the directory entries via a file-like object. */ 94 95 long DirectoryResource::opendir(offset_t *size, l4_cap_idx_t *file, 96 object_flags_t *object_flags) 97 { 98 file_t *reader, *writer; 99 100 /* Mapping of the reader's memory region should be avoided because no use 101 of the reader will be made here. */ 102 103 long err = client_pipe(&reader, &writer, 0); 104 105 if (err) 106 return err; 107 108 *size = reader->size; 109 *file = reader->ref; 110 *object_flags = 0; /* does not support mmap, has no fixed size */ 111 112 /* Discard the reader structure but preserve the capability. */ 113 114 reader->ref = L4_INVALID_CAP; 115 file_close(reader); 116 117 /* Initiate the reading process. */ 118 119 std::thread(read_directory, _registry, _provider, fileid, writer).detach(); 120 121 /* Send the capability immediately, discarding it afterwards. */ 122 123 complete_Directory_opendir(*size, *file, *object_flags); 124 ipc_cap_free_um(*file); 125 126 return IPC_MESSAGE_SENT; 127 } 128 129 130 131 /* NOTE: These methods are effectively the same as the FilePager methods. */ 132 133 /* Subscribe to notifications. */ 134 135 long DirectoryResource::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags) 136 { 137 _endpoint = _provider->subscribe(endpoint, flags); 138 return L4_EOK; 139 } 140 141 long DirectoryResource::unsubscribe(l4_cap_idx_t endpoint) 142 { 143 _provider->unsubscribe(_endpoint, endpoint); 144 return L4_EOK; 145 } 146 147 // vim: tabstop=4 expandtab shiftwidth=4