2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Paweł Dziepak, pdziepak@quarnos.org
17 #include "RootInode.h"
21 Inode::CreateDir(const char* name
, int mode
, ino_t
* id
)
23 return CreateObject(name
, NULL
, mode
, NF4DIR
, id
);
28 Inode::OpenDir(OpenDirCookie
* cookie
)
30 ASSERT(cookie
!= NULL
);
33 return B_NOT_A_DIRECTORY
;
35 status_t result
= Access(R_OK
);
40 cookie
->fSnapshot
= NULL
;
41 cookie
->fCurrent
= NULL
;
43 cookie
->fAttrDir
= false;
50 Inode::OpenAttrDir(OpenDirCookie
* cookie
)
52 ASSERT(cookie
!= NULL
);
55 cookie
->fSnapshot
= NULL
;
56 cookie
->fCurrent
= NULL
;
58 cookie
->fAttrDir
= true;
60 return LoadAttrDirHandle();
65 Inode::LoadAttrDirHandle()
67 if (fInfo
.fAttrDir
.fSize
!= 0)
73 if (fFileSystem
->NamedAttrs()) {
74 result
= NFS4Inode::OpenAttrDir(&handle
);
76 fInfo
.fAttrDir
= handle
;
80 if (result
!= B_UNSUPPORTED
)
83 fFileSystem
->SetNamedAttrs(false);
86 if (!fFileSystem
->GetConfiguration().fEmulateNamedAttrs
)
90 = reinterpret_cast<char*>(malloc(strlen(Name()) + 32));
94 strcat(attrDir
, Name());
95 strcat(attrDir
, "-haiku-attrs");
97 result
= NFS4Inode::LookUp(attrDir
, NULL
, NULL
, &handle
, true);
98 if (result
== B_ENTRY_NOT_FOUND
) {
102 st
.st_mode
|= S_IXUSR
| S_IXGRP
| S_IXOTH
;
103 result
= NFS4Inode::CreateObject(attrDir
, NULL
, st
.st_mode
, NF4DIR
,
104 &change
, NULL
, &handle
, true);
112 fInfo
.fAttrDir
= handle
;
118 Inode::FillDirEntry(struct dirent
* de
, ino_t id
, const char* name
, uint32 pos
,
122 ASSERT(name
!= NULL
);
124 uint32 nameSize
= strlen(name
) + 1;
125 const uint32 entSize
= sizeof(struct dirent
);
127 if (pos
+ entSize
+ nameSize
> size
)
128 return B_BUFFER_OVERFLOW
;
130 de
->d_dev
= fFileSystem
->DevId();
132 de
->d_reclen
= entSize
+ nameSize
;
133 if (de
->d_reclen
% 8 != 0)
134 de
->d_reclen
+= 8 - de
->d_reclen
% 8;
136 strcpy(de
->d_name
, name
);
143 Inode::ReadDirUp(struct dirent
* de
, uint32 pos
, uint32 size
)
149 RPC::Server
* serv
= fFileSystem
->Server();
150 Request
request(serv
, fFileSystem
);
151 RequestBuilder
& req
= request
.Builder();
153 req
.PutFH(fInfo
.fHandle
);
157 if (fFileSystem
->IsAttrSupported(FATTR4_FILEID
)) {
158 Attribute attr
[] = { FATTR4_FILEID
};
159 req
.GetAttr(attr
, sizeof(attr
) / sizeof(Attribute
));
162 status_t result
= request
.Send();
166 ReplyInterpreter
& reply
= request
.Reply();
168 if (HandleErrors(attempt
, reply
.NFS4Error(), serv
))
172 result
= reply
.LookUpUp();
180 if (fFileSystem
->IsAttrSupported(FATTR4_FILEID
)) {
183 result
= reply
.GetAttr(&values
, &count
);
187 fileId
= values
[0].fData
.fValue64
;
190 fileId
= fFileSystem
->AllocFileId();
192 return FillDirEntry(de
, FileIdToInoT(fileId
), "..", pos
, size
);
198 FileToAttrName(const char* path
)
200 ASSERT(path
!= NULL
);
202 char* name
= strdup(path
);
206 char* current
= strpbrk(name
, "#$");
207 while (current
!= NULL
) {
216 current
= strpbrk(name
, "#$");
224 Inode::GetDirSnapshot(DirectoryCacheSnapshot
** _snapshot
,
225 OpenDirCookie
* cookie
, uint64
* _change
, bool attribute
)
227 ASSERT(_snapshot
!= NULL
);
229 DirectoryCacheSnapshot
* snapshot
= new DirectoryCacheSnapshot
;
230 if (snapshot
== NULL
)
234 uint64 dirCookie
= 0;
235 uint64 dirCookieVerf
= 0;
242 status_t result
= ReadDirOnce(&dirents
, &count
, cookie
, &eof
, &change
,
243 &dirCookie
, &dirCookieVerf
, attribute
);
244 if (result
!= B_OK
) {
250 for (i
= 0; i
< count
; i
++) {
252 // FATTR4_FSID is mandatory
253 void* data
= dirents
[i
].fAttrs
[0].fData
.fPointer
;
254 FileSystemId
* fsid
= reinterpret_cast<FileSystemId
*>(data
);
255 if (*fsid
!= fFileSystem
->FsId())
258 if (strstr(dirents
[i
].fName
, "-haiku-attrs") != NULL
)
263 if (dirents
[i
].fAttrCount
== 2)
264 id
= FileIdToInoT(dirents
[i
].fAttrs
[1].fData
.fValue64
);
266 id
= FileIdToInoT(fFileSystem
->AllocFileId());
270 const char* name
= dirents
[i
].fName
;
272 name
= FileToAttrName(name
);
279 NameCacheEntry
* entry
= new NameCacheEntry(name
, id
);
281 free(const_cast<char*>(name
));
283 if (entry
== NULL
|| entry
->fName
== NULL
) {
290 snapshot
->fEntries
.Add(entry
);
296 *_snapshot
= snapshot
;
304 Inode::ReadDir(void* _buffer
, uint32 size
, uint32
* _count
,
305 OpenDirCookie
* cookie
)
307 ASSERT(_buffer
!= NULL
);
308 ASSERT(_count
!= NULL
);
309 ASSERT(cookie
!= NULL
);
317 DirectoryCache
* cache
= cookie
->fAttrDir
? fAttrCache
: fCache
;
318 if (cookie
->fSnapshot
== NULL
) {
320 result
= cache
->Revalidate();
321 if (result
!= B_OK
) {
326 DirectoryCacheSnapshot
* snapshot
;
327 result
= cache
->GetSnapshot(&snapshot
);
328 if (result
!= B_OK
) {
333 cookie
->fSnapshot
= new DirectoryCacheSnapshot(*snapshot
);
336 if (cookie
->fSnapshot
== NULL
)
340 char* buffer
= reinterpret_cast<char*>(_buffer
);
343 bool overflow
= false;
345 if (cookie
->fSpecial
== 0 && i
< *_count
&& !cookie
->fAttrDir
) {
346 struct dirent
* de
= reinterpret_cast<dirent
*>(buffer
+ pos
);
349 result
= FillDirEntry(de
, fInfo
.fFileId
, ".", pos
, size
);
351 if (result
== B_BUFFER_OVERFLOW
)
353 else if (result
== B_OK
) {
361 if (cookie
->fSpecial
== 1 && i
< *_count
&& !cookie
->fAttrDir
) {
362 struct dirent
* de
= reinterpret_cast<dirent
*>(buffer
+ pos
);
365 result
= ReadDirUp(de
, pos
, size
);
366 if (result
== B_ENTRY_NOT_FOUND
) {
367 result
= FillDirEntry(de
, FileIdToInoT(fInfo
.fFileId
), "..", pos
,
371 if (result
== B_BUFFER_OVERFLOW
)
373 else if (result
== B_OK
) {
381 MutexLocker
_(cookie
->fSnapshot
->fLock
);
382 for (; !overflow
&& i
< *_count
; i
++) {
383 struct dirent
* de
= reinterpret_cast<dirent
*>(buffer
+ pos
);
384 NameCacheEntry
* temp
= cookie
->fCurrent
;
386 if (cookie
->fCurrent
== NULL
)
387 cookie
->fCurrent
= cookie
->fSnapshot
->fEntries
.Head();
390 = cookie
->fSnapshot
->fEntries
.GetNext(cookie
->fCurrent
);
393 if (cookie
->fCurrent
== NULL
) {
398 if (FillDirEntry(de
, cookie
->fCurrent
->fNode
, cookie
->fCurrent
->fName
,
399 pos
, size
) == B_BUFFER_OVERFLOW
) {
400 cookie
->fCurrent
= temp
;
408 if (i
== 0 && overflow
)
409 return B_BUFFER_OVERFLOW
;