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 /* Invoke the directory reading mechanism. */ 76 77 accessor->read_directory(writer); 78 79 /* Close and detach from the registry. */ 80 81 client_close(writer); 82 provider->registry()->detach(fileid, provider); 83 } 84 85 86 87 /* Open a directory to read the directory entries via a file-like object. */ 88 89 long DirectoryResource::opendir(offset_t *size, l4_cap_idx_t *file, 90 object_flags_t *object_flags) 91 { 92 file_t *reader, *writer; 93 94 /* Mapping of the reader's memory region should be avoided because no use 95 of the reader will be made here. */ 96 97 long err = client_pipe(&reader, &writer, 0); 98 99 if (err) 100 return err; 101 102 *size = reader->size; 103 *file = discard_cap(reader->ref); 104 *object_flags = 0; /* does not support mmap, has no fixed size */ 105 106 /* Discard the reader structure but preserve the capability. */ 107 108 reader->ref = L4_INVALID_CAP; 109 file_close(reader); 110 111 /* Attach to the provider to keep it available, even if the directory 112 resource is released. */ 113 114 _provider->attach(); 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 return L4_EOK; 123 } 124 125 126 127 /* NOTE: These methods are effectively the same as the FilePager methods. */ 128 129 /* Subscribe to notifications. */ 130 131 long DirectoryResource::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags) 132 { 133 _endpoint = _provider->subscribe(endpoint, flags); 134 return L4_EOK; 135 } 136 137 long DirectoryResource::unsubscribe(l4_cap_idx_t endpoint) 138 { 139 _provider->unsubscribe(_endpoint, endpoint); 140 return L4_EOK; 141 } 142 143 // vim: tabstop=4 expandtab shiftwidth=4