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