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