2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Paweł Dziepak, pdziepak@quarnos.org
14 #include <AutoDeleter.h>
16 #include <NodeMonitor.h>
20 #include "RootInode.h"
24 Inode::CreateState(const char* name
, int mode
, int perms
, OpenState
* state
,
25 OpenDelegationData
* delegationData
) {
27 ASSERT(state
!= NULL
);
28 ASSERT(delegationData
!= NULL
);
32 ChangeInfo changeInfo
;
34 status_t result
= CreateFile(name
, mode
, perms
, state
, &changeInfo
,
35 &fileID
, &handle
, delegationData
);
40 fileInfo
.fFileId
= fileID
;
41 fileInfo
.fHandle
= handle
;
43 fFileSystem
->InoIdMap()->AddName(fileInfo
, fInfo
.fNames
, name
,
44 FileIdToInoT(fileID
));
47 if (fCache
->Valid()) {
48 if (changeInfo
.fAtomic
49 && fCache
->ChangeInfo() == changeInfo
.fBefore
) {
50 fCache
->AddEntry(name
, fileID
, true);
51 fCache
->SetChangeInfo(changeInfo
.fAfter
);
57 state
->fFileSystem
= fFileSystem
;
58 state
->fInfo
= fileInfo
;
59 state
->fMode
= mode
& O_RWMASK
;
66 Inode::Create(const char* name
, int mode
, int perms
, OpenFileCookie
* cookie
,
67 OpenDelegationData
* data
, ino_t
* id
)
70 ASSERT(cookie
!= NULL
);
74 cookie
->fLocks
= NULL
;
76 OpenState
* state
= new(std::nothrow
) OpenState
;
80 status_t result
= CreateState(name
, mode
, perms
, state
, data
);
86 cookie
->fOpenState
= state
;
88 *id
= FileIdToInoT(state
->fInfo
.fFileId
);
90 fFileSystem
->AddOpenFile(state
);
91 fFileSystem
->Root()->MakeInfoInvalid();
93 notify_entry_created(fFileSystem
->DevId(), ID(), name
, *id
);
100 Inode::Open(int mode
, OpenFileCookie
* cookie
)
102 ASSERT(cookie
!= NULL
);
104 MutexLocker
locker(fStateLock
);
106 OpenDelegationData data
;
107 data
.fType
= OPEN_DELEGATE_NONE
;
108 if (fOpenState
== NULL
) {
109 OpenState
* state
= new(std::nothrow
) OpenState
;
113 state
->fInfo
= fInfo
;
114 state
->fFileSystem
= fFileSystem
;
115 state
->fMode
= mode
& O_RWMASK
;
116 status_t result
= OpenFile(state
, mode
, &data
);
117 if (result
!= B_OK
) {
122 fFileSystem
->AddOpenFile(state
);
124 cookie
->fOpenState
= state
;
127 RevalidateFileCache();
129 fOpenState
->AcquireReference();
130 cookie
->fOpenState
= fOpenState
;
133 int newMode
= mode
& O_RWMASK
;
134 int oldMode
= fOpenState
->fMode
& O_RWMASK
;
135 if (oldMode
!= newMode
&& oldMode
!= O_RDWR
) {
136 if (oldMode
== O_RDONLY
)
137 RecallReadDelegation();
139 status_t result
= OpenFile(fOpenState
, O_RDWR
, &data
);
140 if (result
!= B_OK
) {
145 fOpenState
->fMode
= O_RDWR
;
147 if (oldMode
== O_RDONLY
)
148 RevalidateFileCache();
150 int newMode
= mode
& O_RWMASK
;
152 if (newMode
== O_RDWR
|| newMode
== O_RDONLY
)
154 if (newMode
== O_RDWR
|| newMode
== O_WRONLY
)
157 status_t result
= Access(allowed
);
158 if (result
!= B_OK
) {
166 if ((mode
& O_TRUNC
) == O_TRUNC
) {
169 WriteStat(&st
, B_STAT_SIZE
);
170 file_cache_set_size(fFileCache
, 0);
173 cookie
->fMode
= mode
;
174 cookie
->fLocks
= NULL
;
176 if (data
.fType
!= OPEN_DELEGATE_NONE
) {
177 Delegation
* delegation
178 = new(std::nothrow
) Delegation(data
, this, fOpenState
->fClientID
);
179 if (delegation
!= NULL
) {
180 delegation
->fInfo
= fOpenState
->fInfo
;
181 delegation
->fFileSystem
= fFileSystem
;
182 SetDelegation(delegation
);
191 Inode::Close(OpenFileCookie
* cookie
)
193 ASSERT(cookie
!= NULL
);
194 ASSERT(fOpenState
== cookie
->fOpenState
);
196 int mode
= cookie
->fMode
& O_RWMASK
;
197 if (mode
== O_RDWR
|| mode
== O_WRONLY
)
200 MutexLocker
_(fStateLock
);
208 Inode::AttrToFileName(const char* path
)
210 ASSERT(path
!= NULL
);
212 char* name
= strdup(path
);
216 char* current
= strpbrk(name
, "/:");
217 while (current
!= NULL
) {
226 current
= strpbrk(name
, "/:");
234 Inode::OpenAttr(const char* _name
, int mode
, OpenAttrCookie
* cookie
,
235 bool create
, int32 type
)
237 ASSERT(_name
!= NULL
);
238 ASSERT(cookie
!= NULL
);
242 status_t result
= LoadAttrDirHandle();
246 char* name
= AttrToFileName(_name
);
249 MemoryDeleter
nameDeleter(name
);
251 OpenDelegationData data
;
252 data
.fType
= OPEN_DELEGATE_NONE
;
254 OpenState
* state
= new OpenState
;
258 state
->fFileSystem
= fFileSystem
;
259 result
= NFS4Inode::OpenAttr(state
, name
, mode
, &data
, create
);
260 if (result
!= B_OK
) {
265 fFileSystem
->AddOpenFile(state
);
267 cookie
->fOpenState
= state
;
268 cookie
->fMode
= mode
;
270 if (data
.fType
!= OPEN_DELEGATE_NONE
) {
271 Delegation
* delegation
272 = new(std::nothrow
) Delegation(data
, this, state
->fClientID
, true);
273 if (delegation
!= NULL
) {
274 delegation
->fInfo
= state
->fInfo
;
275 delegation
->fFileSystem
= fFileSystem
;
276 state
->fDelegation
= delegation
;
277 fFileSystem
->AddDelegation(delegation
);
281 if (create
|| (mode
& O_TRUNC
) == O_TRUNC
) {
284 WriteStat(&st
, B_STAT_SIZE
, cookie
);
292 Inode::CloseAttr(OpenAttrCookie
* cookie
)
294 ASSERT(cookie
!= NULL
);
296 if (cookie
->fOpenState
->fDelegation
!= NULL
) {
297 cookie
->fOpenState
->fDelegation
->GiveUp();
298 fFileSystem
->RemoveDelegation(cookie
->fOpenState
->fDelegation
);
301 delete cookie
->fOpenState
->fDelegation
;
302 delete cookie
->fOpenState
;
308 Inode::ReadDirect(OpenStateCookie
* cookie
, off_t pos
, void* buffer
,
309 size_t* _length
, bool* eof
)
311 ASSERT(cookie
!= NULL
|| fOpenState
!= NULL
);
312 ASSERT(buffer
!= NULL
);
313 ASSERT(_length
!= NULL
);
319 uint32 ioSize
= fFileSystem
->Root()->IOSize();
320 *_length
= min_c(ioSize
, *_length
);
323 OpenState
* state
= cookie
!= NULL
? cookie
->fOpenState
: fOpenState
;
324 while (size
< *_length
&& !*eof
) {
325 uint32 len
= *_length
- size
;
326 result
= ReadFile(cookie
, state
, pos
+ size
, &len
,
327 reinterpret_cast<char*>(buffer
) + size
, eof
);
328 if (result
!= B_OK
) {
345 Inode::Read(OpenFileCookie
* cookie
, off_t pos
, void* buffer
, size_t* _length
)
347 ASSERT(cookie
!= NULL
);
348 ASSERT(buffer
!= NULL
);
349 ASSERT(_length
!= NULL
);
352 if ((cookie
->fMode
& O_NOCACHE
) != 0)
353 return ReadDirect(cookie
, pos
, buffer
, _length
, &eof
);
354 return file_cache_read(fFileCache
, cookie
, pos
, buffer
, _length
);
359 Inode::WriteDirect(OpenStateCookie
* cookie
, off_t pos
, const void* _buffer
,
362 ASSERT(cookie
!= NULL
|| fOpenState
!= NULL
);
363 ASSERT(_buffer
!= NULL
);
364 ASSERT(_length
!= NULL
);
367 const char* buffer
= reinterpret_cast<const char*>(_buffer
);
369 uint32 ioSize
= fFileSystem
->Root()->IOSize();
370 *_length
= min_c(ioSize
, *_length
);
372 bool attribute
= false;
373 OpenState
* state
= fOpenState
;
374 if (cookie
!= NULL
) {
375 attribute
= cookie
->fOpenState
->fInfo
.fHandle
!= fInfo
.fHandle
;
376 state
= cookie
->fOpenState
;
380 ReadLocker
_(fWriteLock
);
384 while (size
< *_length
) {
385 uint32 len
= *_length
- size
;
386 status_t result
= WriteFile(cookie
, state
, pos
+ size
, &len
,
387 buffer
+ size
, attribute
);
388 if (result
!= B_OK
) {
400 fMetaCache
.GrowFile(size
+ pos
);
401 fFileSystem
->Root()->MakeInfoInvalid();
408 Inode::Write(OpenFileCookie
* cookie
, off_t pos
, const void* _buffer
,
411 ASSERT(cookie
!= NULL
);
412 ASSERT(_buffer
!= NULL
);
413 ASSERT(_length
!= NULL
);
418 if ((cookie
->fMode
& O_RWMASK
) == O_RDONLY
)
419 return B_NOT_ALLOWED
;
421 if ((cookie
->fMode
& O_APPEND
) != 0)
424 uint64 fileSize
= pos
+ *_length
;
425 if (fileSize
> fMaxFileSize
) {
426 status_t result
= file_cache_set_size(fFileCache
, fileSize
);
429 fMaxFileSize
= fileSize
;
430 fMetaCache
.GrowFile(fMaxFileSize
);
433 if ((cookie
->fMode
& O_NOCACHE
) != 0) {
434 WriteDirect(cookie
, pos
, _buffer
, _length
);
438 return file_cache_write(fFileCache
, cookie
, pos
, _buffer
, _length
);
448 WriteLocker
_(fWriteLock
);
449 status_t result
= CommitWrites();