Bug Summary

File:src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp
Location:line 108, column 3
Description:Memory allocated by strdup() should be deallocated by free(), not 'delete'

Annotated Source Code

1/*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
8
9
10#include <stdio.h>
11
12#include <AutoDeleter.h>
13#include <fs_cache.h>
14#include <fs_interface.h>
15
16#include "Connection.h"
17#include "FileSystem.h"
18#include "IdMap.h"
19#include "Inode.h"
20#include "NFS4Defs.h"
21#include "RequestBuilder.h"
22#include "ReplyInterpreter.h"
23#include "RootInode.h"
24#include "RPCCallbackServer.h"
25#include "RPCServer.h"
26#include "VnodeToInode.h"
27#include "WorkQueue.h"
28
29#ifdef DEBUG
30#define TRACE_NFS4
31#endif
32
33#ifdef TRACE_NFS4
34static mutex gTraceLock = MUTEX_INITIALIZER(NULL){ __null, __null, -1, 0 };
35
36#define TRACE(x...)(void)0 \
37 { \
38 mutex_lock(&gTraceLock); \
39 dprintf("nfs4: %s(): ", __FUNCTION__); \
40 dprintf(x); \
41 dprintf("\n"); \
42 mutex_unlock(&gTraceLock); \
43 }
44#else
45#define TRACE(x...)(void)0 (void)0
46#endif
47
48extern fs_volume_ops gNFSv4VolumeOps;
49extern fs_vnode_ops gNFSv4VnodeOps;
50
51
52RPC::ServerManager* gRPCServerManager;
53
54
55RPC::ProgramData*
56CreateNFS4Server(RPC::Server* serv)
57{
58 return new NFS4Server(serv);
59}
60
61
62// Format: ip{4,6}_address:path options
63// Available options:
64// hard - retry requests until success
65// soft - retry requests no more than retrans times (default)
66// timeo=X - request time limit before next retransmission (default: 60s)
67// retrans=X - retry requests X times (default: 5)
68// ac - use metadata cache (default)
69// noac - do not use metadata cache
70// xattr-emu - emulate named attributes
71// noxattr-emu - do not emulate named attributes (default)
72// port=X - connect to port X (default: 2049)
73// proto=X - user transport protocol X (default: tcp)
74// dirtime=X - attempt revalidate directory cache not more often than each X
75// seconds
76static status_t
77ParseArguments(const char* _args, AddressResolver** address, char** _server,
78 char** _path, MountConfiguration* conf)
79{
80 if (_args == NULL__null)
5
Taking false branch
81 return B_BAD_VALUE((-2147483647 - 1) + 5);
82
83 char* args = strdup(_args);
84 if (args == NULL__null)
6
Taking false branch
85 return B_NO_MEMORY((-2147483647 - 1) + 0);
86 MemoryDeleter argsDeleter(args);
87
88 char* options = strchr(args, ' ');
89 if (options != NULL__null)
7
Taking false branch
90 *options++ = '\0';
91
92 char* path = strrchr(args, ':');
93 if (path == NULL__null)
8
Taking false branch
94 return B_MISMATCHED_VALUES((-2147483647 - 1) + 6);
95 *path++ = '\0';
96
97 *_server = strdup(args);
9
Memory is allocated
98 if (*_server == NULL__null)
10
Taking false branch
99 return B_NO_MEMORY((-2147483647 - 1) + 0);
100 *address = new AddressResolver(args);
101 if (*address == NULL__null) {
11
Taking false branch
102 delete *_server;
103 return B_NO_MEMORY((-2147483647 - 1) + 0);
104 }
105
106 *_path = strdup(path);
107 if (*_path == NULL__null) {
12
Taking true branch
108 delete *_server;
13
Memory allocated by strdup() should be deallocated by free(), not 'delete'
109 delete *address;
110 return B_NO_MEMORY((-2147483647 - 1) + 0);
111 }
112
113 conf->fHard = false;
114 conf->fRetryLimit = 5;
115 conf->fRequestTimeout = sSecToBigTime(60);
116 conf->fEmulateNamedAttrs = false;
117 conf->fCacheMetadata = true;
118 conf->fDirectoryCacheTime = sSecToBigTime(5);
119
120 char* optionsEnd = NULL__null;
121 if (options != NULL__null)
122 optionsEnd = strchr(options, ' ');
123 while (options != NULL__null && *options != '\0') {
124 if (optionsEnd != NULL__null)
125 *optionsEnd++ = '\0';
126
127 if (strcmp(options, "hard") == 0)
128 conf->fHard = true;
129 else if (strncmp(options, "retrans=", 8) == 0) {
130 options += strlen("retrans=");
131 conf->fRetryLimit = atoi(options);
132 } else if (strncmp(options, "timeo=", 6) == 0) {
133 options += strlen("timeo=");
134 conf->fRequestTimeout = atoi(options);
135 } else if (strcmp(options, "noac") == 0)
136 conf->fCacheMetadata = false;
137 else if (strcmp(options, "xattr-emu") == 0)
138 conf->fEmulateNamedAttrs = true;
139 else if (strncmp(options, "port=", 5) == 0) {
140 options += strlen("port=");
141 (*address)->ForcePort(atoi(options));
142 } else if (strncmp(options, "proto=", 6) == 0) {
143 options += strlen("proto=");
144 (*address)->ForceProtocol(options);
145 } else if (strncmp(options, "dirtime=", 8) == 0) {
146 options += strlen("dirtime=");
147 conf->fDirectoryCacheTime = sSecToBigTime(atoi(options));
148 }
149
150 options = optionsEnd;
151 if (options != NULL__null)
152 optionsEnd = strchr(options, ' ');
153 }
154
155 return B_OK((int)0);
156}
157
158
159static status_t
160nfs4_mount(fs_volume* volume, const char* device, uint32 flags,
161 const char* args, ino_t* _rootVnodeID)
162{
163 TRACE("volume = %p, device = %s, flags = %" B_PRIu32 ", args = %s", volume,(void)0
164 device, flags, args)(void)0;
165
166 status_t result;
167
168 /* prepare idmapper server */
169 MutexLocker locker(gIdMapperLock);
170 gIdMapper = new(std::nothrow) IdMap;
171 if (gIdMapper == NULL__null)
1
Taking false branch
172 return B_NO_MEMORY((-2147483647 - 1) + 0);
173
174 result = gIdMapper->InitStatus();
175 if (result != B_OK((int)0)) {
2
Assuming 'result' is equal to 0
3
Taking false branch
176 delete gIdMapper;
177 gIdMapper = NULL__null;
178 return result;
179 }
180 locker.Unlock();
181
182 AddressResolver* resolver;
183 MountConfiguration config;
184 char* path;
185 char* serverName;
186 result = ParseArguments(args, &resolver, &serverName, &path, &config);
4
Calling 'ParseArguments'
187 if (result != B_OK((int)0))
188 return result;
189 MemoryDeleter pathDeleter(path);
190
191 RPC::Server* server;
192 result = gRPCServerManager->Acquire(&server, resolver, CreateNFS4Server);
193 delete resolver;
194 if (result != B_OK((int)0))
195 return result;
196
197 FileSystem* fs;
198 result = FileSystem::Mount(&fs, server, serverName, path, volume->id,
199 config);
200 free(serverName);
201 if (result != B_OK((int)0)) {
202 gRPCServerManager->Release(server);
203 return result;
204 }
205
206 Inode* inode = fs->Root();
207 if (inode == NULL__null) {
208 delete fs;
209 gRPCServerManager->Release(server);
210
211 return B_IO_ERROR((-2147483647 - 1) + 1);
212 }
213
214 volume->private_volume = fs;
215 volume->ops = &gNFSv4VolumeOps;
216
217 VnodeToInode* vti = new VnodeToInode(inode->ID(), fs);
218 if (vti == NULL__null) {
219 delete fs;
220 gRPCServerManager->Release(server);
221 return B_NO_MEMORY((-2147483647 - 1) + 0);
222 }
223
224 vti->Replace(inode);
225 result = publish_vnode(volume, inode->ID(), vti, &gNFSv4VnodeOps,
226 inode->Type(), 0);
227 if (result != B_OK((int)0))
228 return result;
229
230 *_rootVnodeID = inode->ID();
231
232 TRACE("*_rootVnodeID = %" B_PRIi64, inode->ID())(void)0;
233
234 return B_OK((int)0);
235}
236
237
238static status_t
239nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type,
240 uint32* _flags, bool reenter)
241{
242 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
243 TRACE("volume = %p, id = %" B_PRIi64, volume, id)(void)0;
244
245 VnodeToInode* vnodeToInode = new VnodeToInode(id, fs);
246 if (vnodeToInode == NULL__null)
247 return B_NO_MEMORY((-2147483647 - 1) + 0);
248
249 Inode* inode;
250 status_t result = fs->GetInode(id, &inode);
251 if (result != B_OK((int)0)) {
252 delete vnodeToInode;
253 return result;
254 }
255
256 vnodeToInode->Replace(inode);
257 vnode->ops = &gNFSv4VnodeOps;
258 vnode->private_node = vnodeToInode;
259
260 *_type = inode->Type();
261 *_flags = 0;
262
263 return B_OK((int)0);
264}
265
266
267static status_t
268nfs4_unmount(fs_volume* volume)
269{
270 TRACE("volume = %p", volume)(void)0;
271 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
272 RPC::Server* server = fs->Server();
273
274 delete fs;
275 gRPCServerManager->Release(server);
276
277 return B_OK((int)0);
278}
279
280
281static status_t
282nfs4_read_fs_info(fs_volume* volume, struct fs_info* info)
283{
284 TRACE("volume = %p", volume)(void)0;
285
286 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
287 RootInode* inode = reinterpret_cast<RootInode*>(fs->Root());
288 return inode->ReadInfo(info);
289}
290
291
292static status_t
293nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id)
294{
295 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node);
296
297 if (!strcmp(name, ".")) {
298 *_id = vti->ID();
299 void* ptr;
300 return get_vnode(volume, *_id, &ptr);
301 }
302
303 VnodeToInodeLocker locker(vti);
304
305 Inode* inode = vti->Get();
306 if (inode == NULL__null)
307 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
308
309 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s", volume, vti->ID(),(void)0
310 name)(void)0;
311
312 status_t result = inode->LookUp(name, _id);
313 if (result != B_OK((int)0))
314 return result;
315 locker.Unlock();
316
317 TRACE("*_id = %" B_PRIi64, *_id)(void)0;
318
319 // If VTI holds an outdated Inode next operation performed on it will
320 // return either ERR_STALE or ERR_FHEXPIRED. Both of these error codes
321 // will cause FileInfo data to be updated (the former will also cause Inode
322 // object to be recreated). We are taking an optimistic (an lazy) approach
323 // here. The following code just ensures VTI won't be removed too soon.
324 void* ptr;
325 result = get_vnode(volume, *_id, &ptr);
326 if (result == B_OK((int)0))
327 unremove_vnode(volume, *_id);
328
329 return result;
330}
331
332
333static status_t
334nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
335{
336 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
337 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID())(void)0;
338
339 delete vti;
340 return B_OK((int)0);
341}
342
343
344static status_t
345nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
346{
347 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
348 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
349 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID())(void)0;
350
351 if (fs->Root() == vti->GetPointer())
352 return B_OK((int)0);
353
354 ASSERT(vti->GetPointer() == NULL)do { if (!(vti->GetPointer() == __null)) { panic("ASSERT FAILED (%s:%d): %s"
, "/home/haiku/haiku/haiku/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp"
, 354, "vti->GetPointer() == __null"); } } while (0)
;
355 delete vti;
356
357 return B_OK((int)0);
358}
359
360
361static status_t
362nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos,
363 const iovec* vecs, size_t count, size_t* _numBytes)
364{
365 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
366 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \(void)0
367 ", count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos,(void)0
368 count, *_numBytes)(void)0;
369
370 VnodeToInodeLocker _(vti);
371 Inode* inode = vti->Get();
372 if (inode == NULL__null)
373 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
374
375 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
376
377 status_t result;
378 size_t totalRead = 0;
379 bool eof = false;
380 for (size_t i = 0; i < count && !eof; i++) {
381 size_t bytesLeft = vecs[i].iov_len;
382 char* buffer = reinterpret_cast<char*>(vecs[i].iov_base);
383
384 do {
385 size_t bytesRead = bytesLeft;
386 result = inode->ReadDirect(cookie, pos, buffer, &bytesRead, &eof);
387 if (result != B_OK((int)0))
388 return result;
389
390 totalRead += bytesRead;
391 pos += bytesRead;
392 buffer += bytesRead;
393 bytesLeft -= bytesRead;
394 } while (bytesLeft > 0 && !eof);
395 }
396
397 *_numBytes = totalRead;
398
399 TRACE("*numBytes = %lu", totalRead)(void)0;
400
401 return B_OK((int)0);
402}
403
404
405static status_t
406nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos,
407 const iovec* vecs, size_t count, size_t* _numBytes)
408{
409 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
410 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \(void)0
411 ", count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos,(void)0
412 count, *_numBytes)(void)0;
413
414 VnodeToInodeLocker _(vti);
415 Inode* inode = vti->Get();
416 if (inode == NULL__null)
417 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
418
419 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
420
421 status_t result;
422 for (size_t i = 0; i < count; i++) {
423 uint64 bytesLeft = vecs[i].iov_len;
424 if (pos + bytesLeft > inode->MaxFileSize())
425 bytesLeft = inode->MaxFileSize() - pos;
426
427 char* buffer = reinterpret_cast<char*>(vecs[i].iov_base);
428
429 do {
430 size_t bytesWritten = bytesLeft;
431
432 result = inode->WriteDirect(cookie, pos, buffer, &bytesWritten);
433 if (result != B_OK((int)0))
434 return result;
435
436 bytesLeft -= bytesWritten;
437 pos += bytesWritten;
438 buffer += bytesWritten;
439 } while (bytesLeft > 0);
440 }
441
442 return B_OK((int)0);
443}
444
445
446static status_t
447nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request)
448{
449 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
450 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p", volume, vti->ID(),(void)0
451 cookie)(void)0;
452
453 VnodeToInodeLocker _(vti);
454 Inode* inode = vti->Get();
455 if (inode == NULL__null)
456 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
457
458 IORequestArgs* args = new(std::nothrow) IORequestArgs;
459 if (args == NULL__null) {
460 notify_io_request(request, B_NO_MEMORY((-2147483647 - 1) + 0));
461 return B_NO_MEMORY((-2147483647 - 1) + 0);
462 }
463 args->fRequest = request;
464 args->fInode = inode;
465
466 status_t result = gWorkQueue->EnqueueJob(IORequest, args);
467 if (result != B_OK((int)0))
468 notify_io_request(request, result);
469
470 return result;
471}
472
473
474static status_t
475nfs4_get_file_map(fs_volume* volume, fs_vnode* vnode, off_t _offset,
476 size_t size, struct file_io_vec* vecs, size_t* _count)
477{
478 return B_ERROR(-1);
479}
480
481
482static status_t
483nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags)
484{
485 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, flags = %d", volume,(void)0
486 reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie,(void)0
487 flags)(void)0;
488
489 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
490 cookie->fMode = (cookie->fMode & ~(O_APPEND0x00000800 | O_NONBLOCK0x00000080)) | flags;
491 return B_OK((int)0);
492}
493
494
495static status_t
496nfs4_fsync(fs_volume* volume, fs_vnode* vnode)
497{
498 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
499 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID())(void)0;
500
501 VnodeToInodeLocker _(vti);
502 Inode* inode = vti->Get();
503 if (inode == NULL__null)
504 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
505
506 return inode->SyncAndCommit();
507}
508
509
510static status_t
511nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer,
512 size_t* _bufferSize)
513{
514 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(link->private_node);
515 TRACE("volume = %p, link = %" B_PRIi64, volume, vti->ID())(void)0;
516
517 VnodeToInodeLocker _(vti);
518 Inode* inode = vti->Get();
519 if (inode == NULL__null)
520 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
521
522 return inode->ReadLink(buffer, _bufferSize);
523}
524
525
526static status_t
527nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name,
528 const char* path, int mode)
529{
530 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node);
531 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, path = %s, mode = %d",(void)0
532 volume, vti->ID(), name, path, mode)(void)0;
533
534 VnodeToInodeLocker _(vti);
535 Inode* inode = vti->Get();
536 if (inode == NULL__null)
537 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
538
539 ino_t id;
540 status_t result = inode->CreateLink(name, path, mode, &id);
541 if (result != B_OK((int)0))
542 return result;
543
544 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
545 if (result == B_OK((int)0)) {
546 unremove_vnode(volume, id);
547 vti->Clear();
548 put_vnode(volume, id);
549 }
550
551 return B_OK((int)0);
552}
553
554
555static status_t
556nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode)
557{
558 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
559 VnodeToInode* dirVti = reinterpret_cast<VnodeToInode*>(dir->private_node);
560 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, vnode = %" B_PRIi64,(void)0
561 volume, dirVti->ID(), name, vti->ID())(void)0;
562
563 VnodeToInodeLocker _dir(dirVti);
564 Inode* dirInode = dirVti->Get();
565 if (dirInode == NULL__null)
566 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
567
568
569 VnodeToInodeLocker _(vti);
570 Inode* inode = vti->Get();
571 if (inode == NULL__null)
572 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
573
574 return inode->Link(dirInode, name);
575}
576
577
578static status_t
579nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
580{
581 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node);
582
583 VnodeToInodeLocker locker(vti);
584 Inode* inode = vti->Get();
585 if (inode == NULL__null)
586 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
587
588 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s", volume, vti->ID(),(void)0
589 name)(void)0;
590
591 ino_t id;
592 status_t result = inode->Remove(name, NF4REG, &id);
593 if (result != B_OK((int)0))
594 return result;
595 locker.Unlock();
596
597 result = acquire_vnode(volume, id);
598 if (result == B_OK((int)0)) {
599 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
600 ASSERT(result == B_OK)do { if (!(result == ((int)0))) { panic("ASSERT FAILED (%s:%d): %s"
, "/home/haiku/haiku/haiku/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp"
, 600, "result == ((int)0)"); } } while (0)
;
601
602 if (vti->Unlink(inode->fInfo.fNames, name))
603 remove_vnode(volume, id);
604
605 put_vnode(volume, id);
606 put_vnode(volume, id);
607 }
608
609 return B_OK((int)0);
610}
611
612
613static status_t
614nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName,
615 fs_vnode* toDir, const char* toName)
616{
617 VnodeToInode* fromVti
618 = reinterpret_cast<VnodeToInode*>(fromDir->private_node);
619 VnodeToInode* toVti = reinterpret_cast<VnodeToInode*>(toDir->private_node);
620 TRACE("volume = %p, fromDir = %" B_PRIi64 ", toDir = %" B_PRIi64 "," \(void)0
621 " fromName = %s, toName = %s", volume, fromVti->ID(), toVti->ID(), \(void)0
622 fromName, toName)(void)0;
623
624 VnodeToInodeLocker _from(fromVti);
625 Inode* fromInode = fromVti->Get();
626 if (fromInode == NULL__null)
627 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
628
629
630 VnodeToInodeLocker _to(toVti);
631 Inode* toInode = toVti->Get();
632 if (toInode == NULL__null)
633 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
634
635 ino_t id;
636 ino_t oldID;
637 status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false,
638 &id, &oldID);
639 if (result != B_OK((int)0))
640 return result;
641
642 VnodeToInode* vti;
643
644 if (oldID != 0) {
645 // we have overriden an inode
646 result = acquire_vnode(volume, oldID);
647 if (result == B_OK((int)0)) {
648 result = get_vnode(volume, oldID, reinterpret_cast<void**>(&vti));
649 ASSERT(result == B_OK)do { if (!(result == ((int)0))) { panic("ASSERT FAILED (%s:%d): %s"
, "/home/haiku/haiku/haiku/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp"
, 649, "result == ((int)0)"); } } while (0)
;
650 if (vti->Unlink(toInode->fInfo.fNames, toName))
651 remove_vnode(volume, oldID);
652
653 put_vnode(volume, oldID);
654 put_vnode(volume, oldID);
655 }
656 }
657
658 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
659 if (result == B_OK((int)0)) {
660 Inode* child = vti->Get();
661 if (child == NULL__null) {
662 put_vnode(volume, id);
663 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
664 }
665
666 unremove_vnode(volume, id);
667 child->fInfo.fNames->RemoveName(fromInode->fInfo.fNames, fromName);
668 child->fInfo.fNames->AddName(toInode->fInfo.fNames, toName);
669 put_vnode(volume, id);
670 }
671
672 return B_OK((int)0);
673}
674
675
676static status_t
677nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode)
678{
679 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
680 TRACE("volume = %p, vnode = %" B_PRIi64 ", mode = %d", volume, vti->ID(),(void)0
681 mode)(void)0;
682
683 VnodeToInodeLocker _(vti);
684 Inode* inode = vti->Get();
685 if (inode == NULL__null)
686 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
687
688 return inode->Access(mode);
689}
690
691
692static status_t
693nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat)
694{
695 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
696 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID())(void)0;
697
698 VnodeToInodeLocker _(vti);
699 Inode* inode = vti->Get();
700 if (inode == NULL__null)
701 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
702
703 status_t result = inode->Stat(stat);
704 if (inode->GetOpenState() != NULL__null)
705 stat->st_size = inode->MaxFileSize();
706 return result;
707}
708
709
710static status_t
711nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat,
712 uint32 statMask)
713{
714 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
715 TRACE("volume = %p, vnode = %" B_PRIi64 ", statMask = %" B_PRIu32, volume,(void)0
716 vti->ID(), statMask)(void)0;
717
718 VnodeToInodeLocker _(vti);
719 Inode* inode = vti->Get();
720 if (inode == NULL__null)
721 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
722
723 return inode->WriteStat(stat, statMask);
724}
725
726
727static status_t
728get_new_vnode(fs_volume* volume, ino_t id, VnodeToInode** _vti)
729{
730 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
731 Inode* inode;
732 VnodeToInode* vti;
733
734 status_t result = acquire_vnode(volume, id);
735 if (result == B_OK((int)0)) {
736 ASSERT(get_vnode(volume, id, reinterpret_cast<void**>(_vti)) == B_OK)do { if (!(get_vnode(volume, id, reinterpret_cast<void**>
(_vti)) == ((int)0))) { panic("ASSERT FAILED (%s:%d): %s", "/home/haiku/haiku/haiku/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp"
, 736, "get_vnode(volume, id, reinterpret_cast<void**>(_vti)) == ((int)0)"
); } } while (0)
;
737 unremove_vnode(volume, id);
738
739 // Release after acquire
740 put_vnode(volume, id);
741
742 vti = *_vti;
743
744 if (vti->Get() == NULL__null) {
745 result = fs->GetInode(id, &inode);
746 if (result != B_OK((int)0)) {
747 put_vnode(volume, id);
748 return result;
749 }
750
751 vti->Replace(inode);
752 }
753 return B_OK((int)0);
754 }
755
756 return get_vnode(volume, id, reinterpret_cast<void**>(_vti));
757}
758
759
760static status_t
761nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode,
762 int perms, void** _cookie, ino_t* _newVnodeID)
763{
764 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
765
766 OpenFileCookie* cookie = new OpenFileCookie(fs);
767 if (cookie == NULL__null)
768 return B_NO_MEMORY((-2147483647 - 1) + 0);
769 *_cookie = cookie;
770
771 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node);
772 TRACE("volume = %p, dir = %" B_PRIi64 ", name = %s, openMode = %d," \(void)0
773 " perms = %d", volume, vti->ID(), name, openMode, perms)(void)0;
774
775 VnodeToInodeLocker _(vti);
776 Inode* inode = vti->Get();
777 if (inode == NULL__null)
778 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
779
780 MutexLocker createLocker(fs->CreateFileLock());
781
782 OpenDelegationData data;
783 status_t result = inode->Create(name, openMode, perms, cookie, &data,
784 _newVnodeID);
785 if (result != B_OK((int)0)) {
786 delete cookie;
787 return result;
788 }
789
790 result = get_new_vnode(volume, *_newVnodeID, &vti);
791 if (result != B_OK((int)0)) {
792 delete cookie;
793 return result;
794 }
795
796 VnodeToInodeLocker _child(vti);
797 Inode* child = vti->Get();
798 if (child == NULL__null) {
799 delete cookie;
800 put_vnode(volume, *_newVnodeID);
801 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
802 }
803
804 child->SetOpenState(cookie->fOpenState);
805
806 if (data.fType != OPEN_DELEGATE_NONE) {
807 Delegation* delegation
808 = new(std::nothrow) Delegation(data, child,
809 cookie->fOpenState->fClientID);
810 if (delegation != NULL__null) {
811 delegation->fInfo = cookie->fOpenState->fInfo;
812 delegation->fFileSystem = child->GetFileSystem();
813 child->SetDelegation(delegation);
814 }
815 }
816
817 TRACE("*cookie = %p, *newVnodeID = %" B_PRIi64, *_cookie, *_newVnodeID)(void)0;
818 return result;
819}
820
821
822static status_t
823nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
824{
825 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
826 TRACE("volume = %p, vnode = %" B_PRIi64 ", openMode = %d", volume,(void)0
827 vti->ID(), openMode)(void)0;
828
829 VnodeToInodeLocker _(vti);
830 Inode* inode = vti->Get();
831 if (inode == NULL__null)
832 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
833
834 if (inode->Type() == S_IFDIR00000040000 || inode->Type() == S_IFLNK00000120000) {
835 *_cookie = NULL__null;
836 return B_OK((int)0);
837 }
838
839 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
840 OpenFileCookie* cookie = new OpenFileCookie(fs);
841 if (cookie == NULL__null)
842 return B_NO_MEMORY((-2147483647 - 1) + 0);
843 *_cookie = cookie;
844
845 status_t result = inode->Open(openMode, cookie);
846 if (result != B_OK((int)0))
847 delete cookie;
848
849 TRACE("*cookie = %p", *_cookie)(void)0;
850
851 return result;
852}
853
854
855static status_t
856nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie)
857{
858 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
859
860 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p", volume, vti->ID(),(void)0
861 _cookie)(void)0;
862
863 VnodeToInodeLocker _(vti);
864 Inode* inode = vti->Get();
865 if (inode == NULL__null)
866 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
867
868
869 if (inode->Type() == S_IFDIR00000040000 || inode->Type() == S_IFLNK00000120000)
870 return B_OK((int)0);
871
872 Cookie* cookie = reinterpret_cast<Cookie*>(_cookie);
873 return cookie->CancelAll();
874}
875
876
877static status_t
878nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie)
879{
880 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
881
882 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p", volume, vti->ID(),(void)0
883 _cookie)(void)0;
884
885 VnodeToInodeLocker _(vti);
886 Inode* inode = vti->Get();
887 if (inode == NULL__null)
888 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
889
890 if (inode->Type() == S_IFDIR00000040000 || inode->Type() == S_IFLNK00000120000)
891 return B_OK((int)0);
892
893 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
894
895 inode->Close(cookie);
896 delete cookie;
897
898 return B_OK((int)0);
899}
900
901
902static status_t
903nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
904 void* buffer, size_t* length)
905{
906 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
907 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \(void)0
908 ", length = %lu", volume, vti->ID(), _cookie, pos, *length)(void)0;
909
910 VnodeToInodeLocker _(vti);
911 Inode* inode = vti->Get();
912 if (inode == NULL__null)
913 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
914
915 if (inode->Type() == S_IFDIR00000040000)
916 return B_IS_A_DIRECTORY(((-2147483647 - 1) + 0x6000) + 9);
917
918 if (inode->Type() == S_IFLNK00000120000)
919 return B_BAD_VALUE((-2147483647 - 1) + 5);
920
921 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
922
923 return inode->Read(cookie, pos, buffer, length);;
924}
925
926
927static status_t
928nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
929 const void* _buffer, size_t* length)
930{
931 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
932 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, pos = %" B_PRIi64 \(void)0
933 ", length = %lu", volume, vti->ID(), _cookie, pos, *length)(void)0;
934
935 VnodeToInodeLocker _(vti);
936 Inode* inode = vti->Get();
937 if (inode == NULL__null)
938 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
939
940 if (inode->Type() == S_IFDIR00000040000)
941 return B_IS_A_DIRECTORY(((-2147483647 - 1) + 0x6000) + 9);
942
943 if (inode->Type() == S_IFLNK00000120000)
944 return B_BAD_VALUE((-2147483647 - 1) + 5);
945
946 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
947
948 return inode->Write(cookie, pos, _buffer, length);
949}
950
951
952static status_t
953nfs4_create_dir(fs_volume* volume, fs_vnode* parent, const char* name,
954 int mode)
955{
956 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(parent->private_node);
957 TRACE("volume = %p, parent = %" B_PRIi64 ", mode = %d", volume, vti->ID(),(void)0
958 mode)(void)0;
959
960 VnodeToInodeLocker _(vti);
961 Inode* inode = vti->Get();
962 if (inode == NULL__null)
963 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
964
965 ino_t id;
966 status_t result = inode->CreateDir(name, mode, &id);
967 if (result != B_OK((int)0))
968 return result;
969
970 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
971 if (result == B_OK((int)0)) {
972 unremove_vnode(volume, id);
973 vti->Clear();
974 put_vnode(volume, id);
975 }
976
977 return B_OK((int)0);
978}
979
980
981static status_t
982nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
983{
984 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(parent->private_node);
985 TRACE("volume = %p, parent = %" B_PRIi64 ", name = %s", volume, vti->ID(),(void)0
986 name)(void)0;
987
988 VnodeToInodeLocker _(vti);
989 Inode* inode = vti->Get();
990 if (inode == NULL__null)
991 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
992
993 ino_t id;
994 status_t result = inode->Remove(name, NF4DIR, &id);
995 if (result != B_OK((int)0))
996 return result;
997
998 result = acquire_vnode(volume, id);
999 if (result == B_OK((int)0)) {
1000 result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
1001 ASSERT(result == B_OK)do { if (!(result == ((int)0))) { panic("ASSERT FAILED (%s:%d): %s"
, "/home/haiku/haiku/haiku/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp"
, 1001, "result == ((int)0)"); } } while (0)
;
1002
1003 if (vti->Unlink(inode->fInfo.fNames, name))
1004 remove_vnode(volume, id);
1005
1006 put_vnode(volume, id);
1007 put_vnode(volume, id);
1008 }
1009
1010 return B_OK((int)0);
1011}
1012
1013
1014static status_t
1015nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
1016{
1017 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
1018 OpenDirCookie* cookie = new(std::nothrow) OpenDirCookie(fs);
1019 if (cookie == NULL__null)
1020 return B_NO_MEMORY((-2147483647 - 1) + 0);
1021 *_cookie = cookie;
1022
1023 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1024 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID())(void)0;
1025
1026 VnodeToInodeLocker _(vti);
1027 Inode* inode = vti->Get();
1028 if (inode == NULL__null)
1029 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1030
1031 status_t result = inode->OpenDir(cookie);
1032 if (result != B_OK((int)0))
1033 delete cookie;
1034
1035 TRACE("*cookie = %p", *_cookie)(void)0;
1036
1037 return result;
1038}
1039
1040
1041static status_t
1042nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie)
1043{
1044 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p", volume,(void)0
1045 reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie)(void)0;
1046
1047 Cookie* cookie = reinterpret_cast<Cookie*>(_cookie);
1048 return cookie->CancelAll();
1049}
1050
1051
1052static status_t
1053nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
1054{
1055 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p", volume,(void)0
1056 reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), cookie)(void)0;
1057
1058 delete reinterpret_cast<OpenDirCookie*>(cookie);
1059 return B_OK((int)0);
1060}
1061
1062
1063static status_t
1064nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie,
1065 struct dirent* buffer, size_t bufferSize, uint32* _num)
1066{
1067 OpenDirCookie* cookie = reinterpret_cast<OpenDirCookie*>(_cookie);
1068 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1069 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p", volume, vti->ID(),(void)0
1070 _cookie)(void)0;
1071
1072 VnodeToInodeLocker _(vti);
1073 Inode* inode = vti->Get();
1074 if (inode == NULL__null)
1075 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1076
1077 return inode->ReadDir(buffer, bufferSize, _num, cookie);
1078}
1079
1080
1081static status_t
1082nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie)
1083{
1084 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p", volume,(void)0
1085 reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie)(void)0;
1086
1087 OpenDirCookie* cookie = reinterpret_cast<OpenDirCookie*>(_cookie);
1088 cookie->fSpecial = 0;
1089 if (cookie->fSnapshot != NULL__null)
1090 cookie->fSnapshot->ReleaseReference();
1091 cookie->fSnapshot = NULL__null;
1092 cookie->fCurrent = NULL__null;
1093 cookie->fEOF = false;
1094
1095 return B_OK((int)0);
1096}
1097
1098
1099static status_t
1100nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
1101{
1102 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
1103 OpenDirCookie* cookie = new(std::nothrow) OpenDirCookie(fs);
1104 if (cookie == NULL__null)
1105 return B_NO_MEMORY((-2147483647 - 1) + 0);
1106 *_cookie = cookie;
1107
1108 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1109 TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID())(void)0;
1110
1111 VnodeToInodeLocker _(vti);
1112 Inode* inode = vti->Get();
1113 if (inode == NULL__null)
1114 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1115
1116 status_t result = inode->OpenAttrDir(cookie);
1117 if (result != B_OK((int)0))
1118 delete cookie;
1119
1120 return result;
1121}
1122
1123
1124static status_t
1125nfs4_close_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
1126{
1127 return nfs4_close_dir(volume, vnode, cookie);
1128}
1129
1130
1131static status_t
1132nfs4_free_attr_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
1133{
1134 return nfs4_free_dir_cookie(volume, vnode, cookie);
1135}
1136
1137
1138static status_t
1139nfs4_read_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie,
1140 struct dirent* buffer, size_t bufferSize, uint32* _num)
1141{
1142 return nfs4_read_dir(volume, vnode, cookie, buffer, bufferSize, _num);
1143}
1144
1145
1146static status_t
1147nfs4_rewind_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
1148{
1149 return nfs4_rewind_dir(volume, vnode, cookie);
1150}
1151
1152
1153static status_t
1154nfs4_create_attr(fs_volume* volume, fs_vnode* vnode, const char* name,
1155 uint32 type, int openMode, void** _cookie)
1156{
1157 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1158
1159 VnodeToInodeLocker _(vti);
1160 Inode* inode = vti->Get();
1161 if (inode == NULL__null)
1162 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1163
1164 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
1165 OpenAttrCookie* cookie = new OpenAttrCookie(fs);
1166 if (cookie == NULL__null)
1167 return B_NO_MEMORY((-2147483647 - 1) + 0);
1168 *_cookie = cookie;
1169
1170 status_t result = inode->OpenAttr(name, openMode, cookie, true, type);
1171 if (result != B_OK((int)0))
1172 delete cookie;
1173
1174 return result;
1175}
1176
1177
1178static status_t
1179nfs4_open_attr(fs_volume* volume, fs_vnode* vnode, const char* name,
1180 int openMode, void** _cookie)
1181{
1182 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1183
1184 VnodeToInodeLocker _(vti);
1185 Inode* inode = vti->Get();
1186 if (inode == NULL__null)
1187 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1188
1189 FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
1190 OpenAttrCookie* cookie = new OpenAttrCookie(fs);
1191 if (cookie == NULL__null)
1192 return B_NO_MEMORY((-2147483647 - 1) + 0);
1193 *_cookie = cookie;
1194
1195 status_t result = inode->OpenAttr(name, openMode, cookie, false);
1196 if (result != B_OK((int)0))
1197 delete cookie;
1198
1199 return result;
1200}
1201
1202
1203static status_t
1204nfs4_close_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie)
1205{
1206 Cookie* cookie = reinterpret_cast<Cookie*>(_cookie);
1207 return cookie->CancelAll();
1208}
1209
1210
1211static status_t
1212nfs4_free_attr_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie)
1213{
1214 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1215
1216 VnodeToInodeLocker _(vti);
1217 Inode* inode = vti->Get();
1218 if (inode == NULL__null)
1219 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1220
1221 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
1222 inode->CloseAttr(cookie);
1223 delete cookie;
1224
1225 return B_OK((int)0);
1226}
1227
1228
1229static status_t
1230nfs4_read_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
1231 void* buffer, size_t* length)
1232{
1233 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1234 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
1235 bool eof;
1236
1237 VnodeToInodeLocker _(vti);
1238 Inode* inode = vti->Get();
1239 if (inode == NULL__null)
1240 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1241
1242 return inode->ReadDirect(cookie, pos, buffer, length, &eof);
1243}
1244
1245
1246static status_t
1247nfs4_write_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
1248 const void* buffer, size_t* length)
1249{
1250 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1251 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
1252
1253 VnodeToInodeLocker _(vti);
1254 Inode* inode = vti->Get();
1255 if (inode == NULL__null)
1256 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1257
1258 return inode->WriteDirect(cookie, pos, buffer, length);
1259}
1260
1261
1262static status_t
1263nfs4_read_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie,
1264 struct stat* stat)
1265{
1266 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1267 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
1268
1269 VnodeToInodeLocker _(vti);
1270 Inode* inode = vti->Get();
1271 if (inode == NULL__null)
1272 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1273
1274 return inode->Stat(stat, cookie);
1275}
1276
1277
1278static status_t
1279nfs4_write_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie,
1280 const struct stat* stat, int statMask)
1281{
1282 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1283 OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
1284
1285 VnodeToInodeLocker _(vti);
1286 Inode* inode = vti->Get();
1287 if (inode == NULL__null)
1288 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1289
1290 return inode->WriteStat(stat, statMask, cookie);
1291}
1292
1293
1294static status_t
1295nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName,
1296 fs_vnode* toVnode, const char* toName)
1297{
1298 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(toVnode->private_node);
1299 VnodeToInodeLocker to(vti);
1300 Inode* toInode = vti->Get();
1301 if (toInode == NULL__null)
1302 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1303
1304 vti = reinterpret_cast<VnodeToInode*>(fromVnode->private_node);
1305 VnodeToInodeLocker from(vti);
1306 Inode* fromInode = vti->Get();
1307 if (fromInode == NULL__null)
1308 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1309
1310 return Inode::Rename(fromInode, toInode, fromName, toName, true);
1311}
1312
1313
1314static status_t
1315nfs4_remove_attr(fs_volume* volume, fs_vnode* vnode, const char* name)
1316{
1317 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1318
1319 VnodeToInodeLocker _(vti);
1320 Inode* inode = vti->Get();
1321 if (inode == NULL__null)
1322 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1323
1324 return inode->Remove(name, NF4NAMEDATTR, NULL__null);
1325}
1326
1327
1328static status_t
1329nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
1330 struct flock* lock)
1331{
1332 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1333 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
1334 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, lock = %p", volume,(void)0
1335 vti->ID(), _cookie, lock)(void)0;
1336
1337 VnodeToInodeLocker _(vti);
1338 Inode* inode = vti->Get();
1339 if (inode == NULL__null)
1340 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1341
1342 return inode->TestLock(cookie, lock);
1343}
1344
1345
1346static status_t
1347nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
1348 const struct flock* lock, bool wait)
1349{
1350 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1351 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
1352 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, lock = %p", volume,(void)0
1353 vti->ID(), _cookie, lock)(void)0;
1354
1355
1356 VnodeToInodeLocker _(vti);
1357 Inode* inode = vti->Get();
1358 if (inode == NULL__null)
1359 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1360
1361 inode->RevalidateFileCache();
1362 return inode->AcquireLock(cookie, lock, wait);
1363}
1364
1365
1366static status_t
1367nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
1368 const struct flock* lock)
1369{
1370 VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
1371 TRACE("volume = %p, vnode = %" B_PRIi64 ", cookie = %p, lock = %p", volume,(void)0
1372 vti->ID(), _cookie, lock)(void)0;
1373
1374 VnodeToInodeLocker _(vti);
1375 Inode* inode = vti->Get();
1376 if (inode == NULL__null)
1377 return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3);
1378
1379 if (inode->Type() == S_IFDIR00000040000 || inode->Type() == S_IFLNK00000120000)
1380 return B_OK((int)0);
1381
1382 OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
1383
1384 if (lock != NULL__null)
1385 return inode->ReleaseLock(cookie, lock);
1386 else
1387 return inode->ReleaseAllLocks(cookie);
1388}
1389
1390
1391status_t
1392nfs4_init()
1393{
1394 gRPCServerManager = new(std::nothrow) RPC::ServerManager;
1395 if (gRPCServerManager == NULL__null)
1396 return B_NO_MEMORY((-2147483647 - 1) + 0);
1397
1398 mutex_init(&gIdMapperLock, "idmapper Init Lock");
1399 gIdMapper = NULL__null;
1400
1401 gWorkQueue = new(std::nothrow) WorkQueue;
1402 if (gWorkQueue == NULL__null || gWorkQueue->InitStatus() != B_OK((int)0)) {
1403 delete gWorkQueue;
1404 mutex_destroy(&gIdMapperLock);
1405 delete gRPCServerManager;
1406 return B_NO_MEMORY((-2147483647 - 1) + 0);
1407 }
1408
1409 return B_OK((int)0);
1410}
1411
1412
1413status_t
1414nfs4_uninit()
1415{
1416 RPC::CallbackServer::ShutdownAll();
1417
1418 delete gIdMapper;
1419 delete gWorkQueue;
1420 delete gRPCServerManager;
1421
1422 mutex_destroy(&gIdMapperLock);
1423
1424 return B_OK((int)0);
1425}
1426
1427
1428static status_t
1429nfs4_std_ops(int32 op, ...)
1430{
1431 switch (op) {
1432 case B_MODULE_INIT1:
1433 return nfs4_init();
1434 case B_MODULE_UNINIT2:
1435 return nfs4_uninit();
1436 default:
1437 return B_ERROR(-1);
1438 }
1439}
1440
1441
1442fs_volume_ops gNFSv4VolumeOps = {
1443 nfs4_unmount,
1444 nfs4_read_fs_info,
1445 NULL__null,
1446 NULL__null,
1447 nfs4_get_vnode,
1448};
1449
1450fs_vnode_ops gNFSv4VnodeOps = {
1451 nfs4_lookup,
1452 NULL__null, // get_vnode_name()
1453 nfs4_put_vnode,
1454 nfs4_remove_vnode,
1455
1456 /* VM file access */
1457 NULL__null, // can_page()
1458 nfs4_read_pages,
1459 nfs4_write_pages,
1460
1461 nfs4_io,
1462 NULL__null, // cancel_io()
1463
1464 nfs4_get_file_map,
1465
1466 NULL__null, // ioctl()
1467 nfs4_set_flags,
1468 NULL__null, // fs_select()
1469 NULL__null, // fs_deselect()
1470 nfs4_fsync,
1471
1472 nfs4_read_symlink,
1473 nfs4_create_symlink,
1474
1475 nfs4_link,
1476 nfs4_unlink,
1477 nfs4_rename,
1478
1479 nfs4_access,
1480 nfs4_read_stat,
1481 nfs4_write_stat,
1482 NULL__null, // fs_preallocate()
1483
1484 /* file operations */
1485 nfs4_create,
1486 nfs4_open,
1487 nfs4_close,
1488 nfs4_free_cookie,
1489 nfs4_read,
1490 nfs4_write,
1491
1492 /* directory operations */
1493 nfs4_create_dir,
1494 nfs4_remove_dir,
1495 nfs4_open_dir,
1496 nfs4_close_dir,
1497 nfs4_free_dir_cookie,
1498 nfs4_read_dir,
1499 nfs4_rewind_dir,
1500
1501 /* attribute directory operations */
1502 nfs4_open_attr_dir,
1503 nfs4_close_attr_dir,
1504 nfs4_free_attr_dir_cookie,
1505 nfs4_read_attr_dir,
1506 nfs4_rewind_attr_dir,
1507
1508 /* attribute operations */
1509 nfs4_create_attr,
1510 nfs4_open_attr,
1511 nfs4_close_attr,
1512 nfs4_free_attr_cookie,
1513 nfs4_read_attr,
1514 nfs4_write_attr,
1515
1516 nfs4_read_attr_stat,
1517 nfs4_write_attr_stat,
1518 nfs4_rename_attr,
1519 nfs4_remove_attr,
1520
1521 /* support for node and FS layers */
1522 NULL__null, // create_special_node
1523 NULL__null, // get_super_vnode
1524
1525 /* lock operations */
1526 nfs4_test_lock,
1527 nfs4_acquire_lock,
1528 nfs4_release_lock,
1529};
1530
1531static file_system_module_info sNFSv4ModuleInfo = {
1532 {
1533 "file_systems/nfs4" B_CURRENT_FS_API_VERSION"/v1",
1534 0,
1535 nfs4_std_ops,
1536 },
1537
1538 "nfs4", // short_name
1539 "Network File System version 4", // pretty_name
1540
1541 // DDM flags
1542 0,
1543
1544 // scanning
1545 NULL__null, // identify_partition()
1546 NULL__null, // scan_partition()
1547 NULL__null, // free_identify_partition_cookie()
1548 NULL__null, // free_partition_content_cookie()
1549
1550 nfs4_mount,
1551};
1552
1553module_info* modules[] = {
1554 (module_info*)&sNFSv4ModuleInfo,
1555 NULL__null,
1556};
1557