1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "nacl_io/html5fs/html5_fs_node.h"
9 #include <ppapi/c/pp_completion_callback.h>
10 #include <ppapi/c/pp_directory_entry.h>
11 #include <ppapi/c/pp_errors.h>
12 #include <ppapi/c/pp_file_info.h>
13 #include <ppapi/c/ppb_file_io.h>
17 #include "nacl_io/filesystem.h"
18 #include "nacl_io/getdents_helper.h"
19 #include "nacl_io/html5fs/html5_fs.h"
20 #include "nacl_io/kernel_handle.h"
21 #include "nacl_io/osdirent.h"
22 #include "nacl_io/pepper_interface.h"
23 #include "sdk_util/auto_lock.h"
34 void* GetOutputBuffer(void* user_data
, uint32_t count
, uint32_t size
) {
35 OutputBuffer
* output
= static_cast<OutputBuffer
*>(user_data
);
36 output
->element_count
= count
;
38 output
->data
= malloc(count
* size
);
40 output
->element_count
= 0;
47 int32_t OpenFlagsToPPAPIOpenFlags(int open_flags
) {
48 int32_t ppapi_flags
= 0;
50 switch (open_flags
& 3) {
53 ppapi_flags
= PP_FILEOPENFLAG_READ
;
56 ppapi_flags
= PP_FILEOPENFLAG_WRITE
;
59 ppapi_flags
= PP_FILEOPENFLAG_READ
| PP_FILEOPENFLAG_WRITE
;
63 if (open_flags
& O_CREAT
)
64 ppapi_flags
|= PP_FILEOPENFLAG_CREATE
;
65 if (open_flags
& O_TRUNC
)
66 ppapi_flags
|= PP_FILEOPENFLAG_TRUNCATE
;
67 if (open_flags
& O_EXCL
)
68 ppapi_flags
|= PP_FILEOPENFLAG_EXCLUSIVE
;
75 Error
Html5FsNode::FSync() {
76 // Cannot call Flush on a directory; simply do nothing.
81 file_io_iface_
->Flush(fileio_resource_
, PP_BlockUntilComplete());
83 return PPERROR_TO_ERRNO(result
);
87 Error
Html5FsNode::GetDents(size_t offs
,
93 // If this is not a directory, fail
97 // TODO(binji): Better handling of ino numbers.
98 const ino_t kCurDirIno
= -1;
99 const ino_t kParentDirIno
= -2;
100 GetDentsHelper
helper(kCurDirIno
, kParentDirIno
);
102 OutputBuffer output_buf
= {NULL
, 0};
103 PP_ArrayOutput output
= {&GetOutputBuffer
, &output_buf
};
104 int32_t result
= file_ref_iface_
->ReadDirectoryEntries(
105 fileref_resource_
, output
, PP_BlockUntilComplete());
107 return PPERROR_TO_ERRNO(result
);
109 PP_DirectoryEntry
* entries
= static_cast<PP_DirectoryEntry
*>(output_buf
.data
);
111 for (int i
= 0; i
< output_buf
.element_count
; ++i
) {
112 PP_Var file_name_var
= file_ref_iface_
->GetName(entries
[i
].file_ref
);
114 // Release the file reference.
115 filesystem_
->ppapi()->ReleaseResource(entries
[i
].file_ref
);
117 if (file_name_var
.type
!= PP_VARTYPE_STRING
)
120 uint32_t file_name_length
;
121 const char* file_name
=
122 var_iface_
->VarToUtf8(file_name_var
, &file_name_length
);
126 std::min(static_cast<size_t>(file_name_length
),
127 MEMBER_SIZE(dirent
, d_name
) - 1); // -1 for NULL.
129 // The INO is based on the running hash of fully qualified path, so
130 // a childs INO must be the parent directories hash, plus '/', plus
132 ino_t child_ino
= Html5Fs::HashPathSegment(stat_
.st_ino
, file_name
,
135 helper
.AddDirent(child_ino
, file_name
, file_name_length
);
138 var_iface_
->Release(file_name_var
);
141 // Release the output buffer.
142 free(output_buf
.data
);
144 return helper
.GetDents(offs
, pdir
, size
, out_bytes
);
147 Error
Html5FsNode::GetStat(struct stat
* stat
) {
148 AUTO_LOCK(node_lock_
);
152 file_ref_iface_
->Query(fileref_resource_
, &info
, PP_BlockUntilComplete());
154 return PPERROR_TO_ERRNO(result
);
156 // Fill in known info here.
157 memcpy(stat
, &stat_
, sizeof(stat_
));
159 // Fill in the additional info from ppapi.
161 case PP_FILETYPE_REGULAR
:
162 stat
->st_mode
|= S_IFREG
;
164 case PP_FILETYPE_DIRECTORY
:
165 stat
->st_mode
|= S_IFDIR
;
167 case PP_FILETYPE_OTHER
:
171 stat
->st_size
= static_cast<off_t
>(info
.size
);
172 stat
->st_atime
= info
.last_access_time
;
173 stat
->st_mtime
= info
.last_modified_time
;
174 stat
->st_ctime
= info
.creation_time
;
179 Error
Html5FsNode::Read(const HandleAttr
& attr
,
188 int32_t result
= file_io_iface_
->Read(fileio_resource_
,
190 static_cast<char*>(buf
),
191 static_cast<int32_t>(count
),
192 PP_BlockUntilComplete());
194 return PPERROR_TO_ERRNO(result
);
200 Error
Html5FsNode::FTruncate(off_t size
) {
204 int32_t result
= file_io_iface_
->SetLength(
205 fileio_resource_
, size
, PP_BlockUntilComplete());
207 return PPERROR_TO_ERRNO(result
);
211 Error
Html5FsNode::Write(const HandleAttr
& attr
,
220 int32_t result
= file_io_iface_
->Write(fileio_resource_
,
222 static_cast<const char*>(buf
),
223 static_cast<int32_t>(count
),
224 PP_BlockUntilComplete());
226 return PPERROR_TO_ERRNO(result
);
232 int Html5FsNode::GetType() {
233 return fileio_resource_
? S_IFREG
: S_IFDIR
;
236 Error
Html5FsNode::GetSize(off_t
* out_size
) {
242 AUTO_LOCK(node_lock_
);
246 file_io_iface_
->Query(fileio_resource_
, &info
, PP_BlockUntilComplete());
248 return PPERROR_TO_ERRNO(result
);
250 *out_size
= info
.size
;
254 Html5FsNode::Html5FsNode(Filesystem
* filesystem
, PP_Resource fileref_resource
)
256 fileref_resource_(fileref_resource
),
257 fileio_resource_(0) {
260 Error
Html5FsNode::Init(int open_flags
) {
261 Error error
= Node::Init(open_flags
);
265 file_io_iface_
= filesystem_
->ppapi()->GetFileIoInterface();
266 file_ref_iface_
= filesystem_
->ppapi()->GetFileRefInterface();
267 var_iface_
= filesystem_
->ppapi()->GetVarInterface();
269 if (!(file_io_iface_
&& file_ref_iface_
&& var_iface_
)) {
270 LOG_ERROR("Got NULL interface(s): %s%s%s",
271 file_ref_iface_
? "" : "FileRef",
272 file_io_iface_
? "" : "FileIo ",
273 var_iface_
? "" : "Var ");
277 // Set all files and directories to RWX.
278 SetMode(S_IWALL
| S_IRALL
| S_IXALL
);
280 // First query the FileRef to see if it is a file or directory.
281 PP_FileInfo file_info
;
282 int32_t query_result
= file_ref_iface_
->Query(
283 fileref_resource_
, &file_info
, PP_BlockUntilComplete());
284 // If this is a directory, do not get a FileIO.
285 if (query_result
== PP_OK
&& file_info
.type
== PP_FILETYPE_DIRECTORY
) {
290 file_io_iface_
->Create(filesystem_
->ppapi()->GetInstance());
291 if (!fileio_resource_
) {
292 LOG_ERROR("Couldn't create FileIo resource.");
296 int32_t open_result
=
297 file_io_iface_
->Open(fileio_resource_
,
299 OpenFlagsToPPAPIOpenFlags(open_flags
),
300 PP_BlockUntilComplete());
301 if (open_result
!= PP_OK
)
302 return PPERROR_TO_ERRNO(open_result
);
306 void Html5FsNode::Destroy() {
309 if (fileio_resource_
) {
310 file_io_iface_
->Close(fileio_resource_
);
311 filesystem_
->ppapi()->ReleaseResource(fileio_resource_
);
314 filesystem_
->ppapi()->ReleaseResource(fileref_resource_
);
315 fileio_resource_
= 0;
316 fileref_resource_
= 0;
320 Error
Html5FsNode::Fchmod(mode_t mode
) {
321 // html5fs does not support any kinds of permissions or mode bits.
325 } // namespace nacl_io