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 19 static const int32 kOptimalIOSize = 64 * 1024; 20 static const char* kFSName = "netfs"; 21 22 // constructor 23 RootVolume::RootVolume(VolumeManager* volumeManager) 24 : VirtualVolume(volumeManager) 25 { 26 } 27 28 // destructor 29 RootVolume::~RootVolume() 30 { 31 } 32 33 // Init 34 status_t 35 RootVolume::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 53 void 54 RootVolume::Uninit() 55 { 56 // delete the server manager 57 delete fServerManager; 58 fServerManager = NULL; 59 60 VirtualVolume::Uninit(); 61 } 62 63 // PrepareToUnmount 64 void 65 RootVolume::PrepareToUnmount() 66 { 67 VirtualVolume::PrepareToUnmount(); 68 } 69 70 71 // #pragma mark - 72 // #pragma mark ----- FS ----- 73 74 // Mount 75 status_t 76 RootVolume::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 90 status_t 91 RootVolume::Unmount() 92 { 93 Uninit(); 94 return B_OK; 95 } 96 97 // Sync 98 status_t 99 RootVolume::Sync() 100 { 101 return B_BAD_VALUE; 102 } 103 104 // ReadFSStat 105 status_t 106 RootVolume::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 124 status_t 125 RootVolume::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 135 status_t 136 RootVolume::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 207 void 208 RootVolume::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 257 void 258 RootVolume::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 273 void 274 RootVolume::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 291 ServerVolume* 292 RootVolume::_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 304 ServerVolume* 305 RootVolume::_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