1// RootVolume.cpp 2 3#include "RootVolume.h" 4 5#include <new> 6 7#include <AutoLocker.h> 8 9#include "Compatibility.h" 10#include "DebugSupport.h" 11#include "ExtendedServerInfo.h" 12#include "NetAddress.h" 13#include "netfs_ioctl.h" 14#include "ServerVolume.h" 15#include "TaskManager.h" 16#include "VolumeManager.h" 17#include "VolumeSupport.h" 18 19static const int32 kOptimalIOSize = 64 * 1024; 20static const char* kFSName = "netfs"; 21 22// constructor 23RootVolume::RootVolume(VolumeManager* volumeManager) 24 : VirtualVolume(volumeManager) 25{ 26} 27 28// destructor 29RootVolume::~RootVolume() 30{ 31} 32 33// Init 34status_t 35RootVolume::Init() 36{ 37 status_t error = VirtualVolume::Init("Network"); 38 if (error != B_OK) 39 return error; 40 41 // create and init the server manager 42 fServerManager = new(std::nothrow) ServerManager(this); 43 if (!fServerManager) 44 RETURN_ERROR(B_NO_MEMORY); 45 error = fServerManager->Init(); 46 if (error != B_OK) 47 RETURN_ERROR(error); 48 49 return B_OK; 50} 51 52// Uninit 53void 54RootVolume::Uninit() 55{ 56 // delete the server manager 57 delete fServerManager; 58 fServerManager = NULL; 59 60 VirtualVolume::Uninit(); 61} 62 63// PrepareToUnmount 64void 65RootVolume::PrepareToUnmount() 66{ 67 VirtualVolume::PrepareToUnmount(); 68} 69 70 71// #pragma mark - 72// #pragma mark ----- FS ----- 73 74// Mount 75status_t 76RootVolume::Mount(const char* device, uint32 flags, const char* parameters, 77 int32 len) 78{ 79 status_t error = NewVNode(fRootNode->GetID(), fRootNode); 80 if (error != B_OK) 81 RETURN_ERROR(error); 82 83 // start the server manager 84 fServerManager->Run(); 85 86 return B_OK; 87} 88 89// Unmount 90status_t 91RootVolume::Unmount() 92{ 93 Uninit(); 94 return B_OK; 95} 96 97// Sync 98status_t 99RootVolume::Sync() 100{ 101 return B_BAD_VALUE; 102} 103 104// ReadFSStat 105status_t 106RootVolume::ReadFSStat(fs_info* info) 107{ 108 info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME | B_FS_HAS_ATTR 109 | B_FS_IS_SHARED | B_FS_HAS_QUERY; 110 if (fVolumeManager->GetMountFlags() & B_MOUNT_READ_ONLY) 111 info->flags |= B_FS_IS_READONLY; 112 info->block_size = 1024; 113 info->io_size = kOptimalIOSize; 114 info->total_blocks = 0; // TODO: We could at least fill this in. 115 info->free_blocks = LONGLONG_MAX / info->block_size; 116 // keep the Tracker happy 117 strcpy(info->device_name, ""); 118 strcpy(info->volume_name, GetName()); 119 strcpy(info->fsh_name, kFSName); 120 return B_OK; 121} 122 123// WriteFSStat 124status_t 125RootVolume::WriteFSStat(struct fs_info* info, int32 mask) 126{ 127 // TODO: Allow editing the volume name. 128 return B_BAD_VALUE; 129} 130 131// #pragma mark - 132// #pragma mark ----- files ----- 133 134// IOCtl 135status_t 136RootVolume::IOCtl(Node* node, void* cookie, int cmd, void* buffer, 137 size_t bufferSize) 138{ 139 if (node != fRootNode) 140 return B_BAD_VALUE; 141 142 switch (cmd) { 143 case NET_FS_IOCTL_ADD_SERVER: 144 { 145 // check the parameters 146 if (!buffer) 147 return B_BAD_VALUE; 148 netfs_ioctl_add_server* params = (netfs_ioctl_add_server*)buffer; 149 int32 serverNameLen = strnlen(params->serverName, 150 sizeof(params->serverName)); 151 if (serverNameLen == 0 152 || serverNameLen == sizeof(params->serverName)) { 153 return B_BAD_VALUE; 154 } 155 PRINT("RootVolume::IOCtl(): NET_FS_IOCTL_ADD_SERVER: " 156 "`%s'\n", params->serverName); 157 158 // get the server address 159 NetAddress netAddress; 160 NetAddressResolver resolver; 161 status_t error = resolver.GetHostAddress(params->serverName, &netAddress); 162 if (error != B_OK) 163 return error; 164 165 // ask the server manager to add the server 166 return fServerManager->AddServer(netAddress); 167 } 168 case NET_FS_IOCTL_REMOVE_SERVER: 169 { 170 // check the parameters 171 if (!buffer) 172 return B_BAD_VALUE; 173 netfs_ioctl_remove_server* params 174 = (netfs_ioctl_remove_server*)buffer; 175 int32 serverNameLen = strnlen(params->serverName, 176 sizeof(params->serverName)); 177 if (serverNameLen == 0 178 || serverNameLen == sizeof(params->serverName)) { 179 return B_BAD_VALUE; 180 } 181 PRINT("RootVolume::IOCtl(): NET_FS_IOCTL_REMOVE_SERVER:" 182 " `%s'\n", params->serverName); 183 184 // get the server volume 185 ServerVolume* serverVolume = _GetServerVolume(params->serverName); 186 if (!serverVolume) 187 return B_ENTRY_NOT_FOUND; 188 VolumePutter volumePutter(serverVolume); 189 190 // ask the server manager to remove the server 191 fServerManager->RemoveServer(serverVolume->GetServerAddress()); 192 193 return B_OK; 194 } 195 default: 196 PRINT("RootVolume::IOCtl(): unknown ioctl: %d\n", cmd); 197 return B_BAD_VALUE; 198 break; 199 } 200 return B_BAD_VALUE; 201} 202 203 204// #pragma mark - 205 206// ServerAdded 207void 208RootVolume::ServerAdded(ExtendedServerInfo* serverInfo) 209{ 210 PRINT("RootVolume::ServerAdded(%s)\n", serverInfo->GetServerName()); 211 // check, if the server does already exist 212 ServerVolume* serverVolume = _GetServerVolume(serverInfo->GetAddress()); 213 if (serverVolume) { 214 WARN("RootVolume::ServerAdded(): WARNING: ServerVolume does " 215 "already exist.\n"); 216 serverVolume->PutVolume(); 217 return; 218 } 219 220 AutoLocker<Locker> locker(fLock); 221 222 // get a unique name for the server 223 char serverName[B_FILE_NAME_LENGTH]; 224 status_t error = GetUniqueEntryName(serverInfo->GetServerName(), 225 serverName); 226 if (error != B_OK) 227 return; 228 229 // create a server volume 230 serverVolume = new(std::nothrow) ServerVolume(fVolumeManager, serverInfo); 231 if (!serverVolume) 232 return; 233 error = serverVolume->Init(serverName); 234 if (error != B_OK) { 235 delete serverVolume; 236 return; 237 } 238 239 // add the volume to the volume manager 240 error = fVolumeManager->AddVolume(serverVolume); 241 if (error != B_OK) { 242 delete serverVolume; 243 return; 244 } 245 VolumePutter volumePutter(serverVolume); 246 247 // add the volume to us 248 locker.Unlock(); 249 error = AddChildVolume(serverVolume); 250 if (error != B_OK) { 251 serverVolume->SetUnmounting(true); 252 return; 253 } 254} 255 256// ServerUpdated 257void 258RootVolume::ServerUpdated(ExtendedServerInfo* oldInfo, 259 ExtendedServerInfo* newInfo) 260{ 261 PRINT("RootVolume::ServerUpdated(%s)\n", newInfo->GetServerName()); 262 // get the volume 263 ServerVolume* serverVolume = _GetServerVolume(newInfo->GetAddress()); 264 if (!serverVolume) 265 return; 266 267 // set the new server info 268 VolumePutter _(serverVolume); 269 serverVolume->SetServerInfo(newInfo); 270} 271 272// ServerRemoved 273void 274RootVolume::ServerRemoved(ExtendedServerInfo* serverInfo) 275{ 276 PRINT("RootVolume::ServerRemoved(%s)\n", serverInfo->GetServerName()); 277 // get the volume 278 ServerVolume* serverVolume = _GetServerVolume(serverInfo->GetAddress()); 279 if (!serverVolume) 280 return; 281 282 // set it to unmounting 283 VolumePutter _(serverVolume); 284 serverVolume->SetUnmounting(true); 285} 286 287 288// #pragma mark - 289 290// _GetServerVolume 291ServerVolume* 292RootVolume::_GetServerVolume(const char* name) 293{ 294 Volume* volume = GetChildVolume(name); 295 if (!volume) 296 return NULL; 297 if (ServerVolume* serverVolume = dynamic_cast<ServerVolume*>(volume)) 298 return serverVolume; 299 fVolumeManager->PutVolume(volume); 300 return NULL; 301} 302 303// _GetServerVolume 304ServerVolume* 305RootVolume::_GetServerVolume(const NetAddress& address) 306{ 307 AutoLocker<Locker> locker(fLock); 308 309 // init a directory iterator 310 VirtualDirIterator iterator; 311 iterator.SetDirectory(fRootNode, true); 312 313 // iterate through the directory 314 const char* name; 315 Node* node; 316 while (iterator.GetCurrentEntry(&name, &node)) { 317 iterator.NextEntry(); 318 ServerVolume* volume = dynamic_cast<ServerVolume*>(node->GetVolume()); 319 if (volume && volume->GetServerAddress().GetIP() == address.GetIP()) { 320 return dynamic_cast<ServerVolume*>( 321 fVolumeManager->GetVolume(node->GetID())); 322 } 323 } 324 325 return NULL; 326} 327 328