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