1 // ServerVolume.cpp 2 3 #include "ServerVolume.h" 4 5 #include <new> 6 7 #include <AutoDeleter.h> 8 #include <AutoLocker.h> 9 10 #include "Compatibility.h" 11 #include "DebugSupport.h" 12 #include "ExtendedServerInfo.h" 13 #include "QueryManager.h" 14 #include "SendReceiveRequest.h" 15 #include "ServerConnection.h" 16 #include "ServerConnectionProvider.h" 17 #include "ServerQueryIterator.h" 18 #include "ShareVolume.h" 19 #include "VolumeEvent.h" 20 #include "VolumeManager.h" 21 #include "VolumeSupport.h" 22 23 // constructor 24 ServerVolume::ServerVolume(VolumeManager* volumeManager, 25 ExtendedServerInfo* serverInfo) 26 : VirtualVolume(volumeManager), 27 fServerInfo(serverInfo), 28 fConnectionProvider(NULL) 29 { 30 fServerInfo->AddReference(); 31 } 32 33 // destructor 34 ServerVolume::~ServerVolume() 35 { 36 if (fConnectionProvider) 37 fConnectionProvider->RemoveReference(); 38 if (fServerInfo) 39 fServerInfo->RemoveReference(); 40 } 41 42 // GetServerAddress 43 NetAddress 44 ServerVolume::GetServerAddress() 45 { 46 AutoLocker<Locker> _(fLock); 47 return fServerInfo->GetAddress(); 48 } 49 50 // SetServerInfo 51 void 52 ServerVolume::SetServerInfo(ExtendedServerInfo* serverInfo) 53 { 54 if (!serverInfo) 55 return; 56 57 // set the new info 58 fLock.Lock(); 59 fServerInfo->RemoveReference(); 60 fServerInfo = serverInfo; 61 fServerInfo->AddReference(); 62 Reference<ExtendedServerInfo> newReference(fServerInfo); 63 64 // remove shares, that are no longer there 65 66 // init a directory iterator 67 VirtualDirIterator iterator; 68 iterator.SetDirectory(fRootNode, true); 69 70 // iterate through the directory 71 const char* name; 72 Node* node; 73 while (iterator.GetCurrentEntry(&name, &node)) { 74 iterator.NextEntry(); 75 // TODO: Searching by name is currently O(n). 76 bool remove = (!serverInfo->GetShareInfo(name)); 77 fLock.Unlock(); 78 79 if (remove) { 80 PRINT((" removing share: %s\n", name)); 81 if (Volume* volume = GetChildVolume(name)) { 82 volume->SetUnmounting(true); 83 volume->PutVolume(); 84 } 85 } 86 87 fLock.Lock(); 88 } 89 90 // uninit the directory iterator 91 iterator.SetDirectory(NULL); 92 fLock.Unlock(); 93 94 // add new shares 95 int32 count = serverInfo->CountShares(); 96 for (int32 i = 0; i < count; i++) { 97 ExtendedShareInfo* shareInfo = serverInfo->ShareInfoAt(i); 98 const char* shareName = shareInfo->GetShareName(); 99 100 Volume* volume = GetChildVolume(shareName); 101 if (volume) { 102 volume->PutVolume(); 103 } else { 104 PRINT((" adding share: %s\n", shareInfo->GetShareName())); 105 status_t error = _AddShare(shareInfo); 106 if (error != B_OK) { 107 ERROR("ServerVolume::SetServerInfo(): ERROR: Failed to add " 108 "share `%s': %s\n", shareName, strerror(error)); 109 } 110 } 111 } 112 } 113 114 // Init 115 status_t 116 ServerVolume::Init(const char* name) 117 { 118 status_t error = VirtualVolume::Init(name); 119 if (error != B_OK) 120 return error; 121 122 // create the server connection provider 123 fConnectionProvider = new ServerConnectionProvider(fVolumeManager, 124 fServerInfo, GetRootID()); 125 if (!fConnectionProvider) { 126 Uninit(); 127 return B_NO_MEMORY; 128 } 129 error = fConnectionProvider->Init(); 130 if (error != B_OK) { 131 Uninit(); 132 return error; 133 } 134 135 // add share volumes 136 int32 count = fServerInfo->CountShares(); 137 for (int32 i = 0; i < count; i++) { 138 ExtendedShareInfo* shareInfo = fServerInfo->ShareInfoAt(i); 139 140 error = _AddShare(shareInfo); 141 if (error != B_OK) { 142 ERROR("ServerVolume::Init(): ERROR: Failed to add share `%s': " 143 "%s\n", shareInfo->GetShareName(), strerror(error)); 144 } 145 } 146 147 return B_OK; 148 } 149 150 // Uninit 151 void 152 ServerVolume::Uninit() 153 { 154 if (fConnectionProvider) 155 fConnectionProvider->CloseServerConnection(); 156 157 VirtualVolume::Uninit(); 158 } 159 160 // PrepareToUnmount 161 void 162 ServerVolume::PrepareToUnmount() 163 { 164 VirtualVolume::PrepareToUnmount(); 165 } 166 167 // HandleEvent 168 void 169 ServerVolume::HandleEvent(VolumeEvent* event) 170 { 171 if (event->GetType() == CONNECTION_BROKEN_EVENT) { 172 // tell all share volumes that they have been disconnected 173 174 // init a directory iterator 175 fLock.Lock(); 176 VirtualDirIterator iterator; 177 iterator.SetDirectory(fRootNode, true); 178 179 // iterate through the directory 180 const char* name; 181 Node* node; 182 while (iterator.GetCurrentEntry(&name, &node)) { 183 iterator.NextEntry(); 184 Volume* volume = fVolumeManager->GetVolume(node->GetID()); 185 fLock.Unlock(); 186 if (ShareVolume* shareVolume = dynamic_cast<ShareVolume*>(volume)) 187 shareVolume->ConnectionClosed(); 188 if (volume) 189 volume->PutVolume(); 190 fLock.Lock(); 191 } 192 193 // uninit the directory iterator 194 iterator.SetDirectory(NULL); 195 196 // mark ourselves unmounting 197 SetUnmounting(true); 198 fLock.Unlock(); 199 } 200 } 201 202 203 // #pragma mark - 204 // #pragma mark ----- FS ----- 205 206 // Unmount 207 status_t 208 ServerVolume::Unmount() 209 { 210 return B_OK; 211 } 212 213 214 // #pragma mark - 215 // #pragma mark ----- queries ----- 216 217 // OpenQuery 218 status_t 219 ServerVolume::OpenQuery(const char* queryString, uint32 flags, port_id port, 220 int32 token, QueryIterator** _iterator) 221 { 222 // TODO: Do nothing when there are no (mounted) shares. 223 // get connection 224 ServerConnection* serverConnection 225 = fConnectionProvider->GetExistingServerConnection(); 226 if (!serverConnection) 227 return ERROR_NOT_CONNECTED; 228 RequestConnection* connection = serverConnection->GetRequestConnection(); 229 230 // create a query iterator and add it to the query manager 231 ServerQueryIterator* iterator = new(std::nothrow) ServerQueryIterator(this); 232 if (!iterator) 233 return B_NO_MEMORY; 234 QueryManager* queryManager = fVolumeManager->GetQueryManager(); 235 status_t error = queryManager->AddIterator(iterator); 236 if (error != B_OK) { 237 delete iterator; 238 return error; 239 } 240 QueryIteratorPutter iteratorPutter(queryManager, iterator); 241 242 // prepare the request 243 OpenQueryRequest request; 244 request.queryString.SetTo(queryString); 245 request.flags = flags; 246 request.port = port; 247 request.token = token; 248 249 // send the request 250 OpenQueryReply* reply; 251 error = SendRequest(connection, &request, &reply); 252 if (error != B_OK) 253 RETURN_ERROR(error); 254 ObjectDeleter<Request> replyDeleter(reply); 255 if (reply->error != B_OK) 256 RETURN_ERROR(reply->error); 257 258 // set the result 259 iterator->SetRemoteCookie(reply->cookie); 260 *_iterator = iterator; 261 iteratorPutter.Detach(); 262 return B_OK; 263 } 264 265 // FreeQueryIterator 266 void 267 ServerVolume::FreeQueryIterator(QueryIterator* _iterator) 268 { 269 ServerQueryIterator* iterator 270 = dynamic_cast<ServerQueryIterator*>(_iterator); 271 272 int32 cookie = iterator->GetRemoteCookie(); 273 if (cookie >= 0) { 274 // prepare the close request 275 CloseRequest request; 276 request.volumeID = -1; 277 request.cookie = cookie; 278 279 // send the request 280 ServerConnection* serverConnection 281 = fConnectionProvider->GetExistingServerConnection(); 282 if (serverConnection && serverConnection->IsConnected()) { 283 CloseReply* reply; 284 status_t error = SendRequest( 285 serverConnection->GetRequestConnection(), &request, &reply); 286 if (error == B_OK) 287 delete reply; 288 } 289 } 290 291 delete iterator; 292 } 293 294 // ReadQuery 295 status_t 296 ServerVolume::ReadQuery(QueryIterator* _iterator, struct dirent* buffer, 297 size_t bufferSize, int32 count, int32* countRead) 298 { 299 // get connection 300 ServerConnection* serverConnection 301 = fConnectionProvider->GetExistingServerConnection(); 302 if (!serverConnection) 303 return ERROR_NOT_CONNECTED; 304 RequestConnection* connection = serverConnection->GetRequestConnection(); 305 306 ServerQueryIterator* iterator 307 = dynamic_cast<ServerQueryIterator*>(_iterator); 308 309 *countRead = 0; 310 311 for (;;) { 312 // if the iterator hasn't cached any more share volume IDs, we need to 313 // ask the server for the next entry 314 if (!iterator->HasNextShareVolumeID()) { 315 // prepare the request 316 ReadQueryRequest request; 317 request.cookie = iterator->GetRemoteCookie(); 318 request.count = 1; 319 320 // send the request 321 ReadQueryReply* reply; 322 status_t error = SendRequest(connection, &request, &reply); 323 if (error != B_OK) 324 RETURN_ERROR(error); 325 ObjectDeleter<Request> replyDeleter(reply); 326 if (reply->error != B_OK) 327 RETURN_ERROR(reply->error); 328 329 // check, if anything has been read at all 330 if (reply->count == 0) { 331 *countRead = 0; 332 return B_OK; 333 } 334 335 // update the iterator 336 error = iterator->SetEntry(reply->clientVolumeIDs.GetElements(), 337 reply->clientVolumeIDs.CountElements(), reply->dirInfo, 338 reply->entryInfo); 339 if (error != B_OK) 340 return error; 341 } 342 343 // get the next concerned share volume and delegate the rest of the work 344 int32 volumeID = iterator->NextShareVolumeID(); 345 ShareVolume* shareVolume = _GetShareVolume(volumeID); 346 if (!shareVolume) 347 continue; 348 VolumePutter volumePutter(shareVolume); 349 350 return shareVolume->GetQueryEntry(iterator->GetEntryInfo(), 351 iterator->GetDirectoryInfo(), buffer, bufferSize, countRead); 352 } 353 } 354 355 356 // #pragma mark - 357 // #pragma mark ----- private ----- 358 359 // _AddShare 360 status_t 361 ServerVolume::_AddShare(ExtendedShareInfo* shareInfo) 362 { 363 // create the share volume 364 ShareVolume* shareVolume = new(std::nothrow) ShareVolume(fVolumeManager, 365 fConnectionProvider, fServerInfo, shareInfo); 366 if (!shareVolume) 367 return B_NO_MEMORY; 368 status_t error = shareVolume->Init(shareInfo->GetShareName()); 369 if (error != B_OK) { 370 delete shareVolume; 371 return error; 372 } 373 374 // add the volume to the volume manager 375 error = fVolumeManager->AddVolume(shareVolume); 376 if (error != B_OK) { 377 delete shareVolume; 378 return error; 379 } 380 VolumePutter volumePutter(shareVolume); 381 382 // add the volume to us 383 error = AddChildVolume(shareVolume); 384 if (error != B_OK) { 385 shareVolume->SetUnmounting(true); 386 return error; 387 } 388 389 return B_OK; 390 } 391 392 // _GetShareVolume 393 ShareVolume* 394 ServerVolume::_GetShareVolume(int32 volumeID) 395 { 396 AutoLocker<Locker> locker(fLock); 397 VirtualDirIterator dirIterator; 398 dirIterator.SetDirectory(fRootNode, true); 399 400 // iterate through the directory 401 const char* name; 402 Node* node; 403 while (dirIterator.GetCurrentEntry(&name, &node)) { 404 Volume* volume = fVolumeManager->GetVolume(node->GetID()); 405 ShareVolume* shareVolume = dynamic_cast<ShareVolume*>(volume); 406 if (shareVolume && shareVolume->GetID() == volumeID) 407 return shareVolume; 408 409 volume->PutVolume(); 410 dirIterator.NextEntry(); 411 } 412 413 return NULL; 414 } 415 416