Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / html5fs / html5_fs_node.cc
blobbb3a8f5ac3524d3370ddc2f6f73b2b4aff2b9f08
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"
7 #include <errno.h>
8 #include <fcntl.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>
14 #include <string.h>
15 #include <vector>
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"
25 namespace nacl_io {
27 namespace {
29 struct OutputBuffer {
30 void* data;
31 int element_count;
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;
37 if (count) {
38 output->data = malloc(count * size);
39 if (!output->data)
40 output->element_count = 0;
41 } else {
42 output->data = NULL;
44 return output->data;
47 int32_t OpenFlagsToPPAPIOpenFlags(int open_flags) {
48 int32_t ppapi_flags = 0;
50 switch (open_flags & 3) {
51 default:
52 case O_RDONLY:
53 ppapi_flags = PP_FILEOPENFLAG_READ;
54 break;
55 case O_WRONLY:
56 ppapi_flags = PP_FILEOPENFLAG_WRITE;
57 break;
58 case O_RDWR:
59 ppapi_flags = PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE;
60 break;
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;
70 return ppapi_flags;
73 } // namespace
75 Error Html5FsNode::FSync() {
76 // Cannot call Flush on a directory; simply do nothing.
77 if (IsaDir())
78 return 0;
80 int32_t result =
81 file_io_iface_->Flush(fileio_resource_, PP_BlockUntilComplete());
82 if (result != PP_OK)
83 return PPERROR_TO_ERRNO(result);
84 return 0;
87 Error Html5FsNode::GetDents(size_t offs,
88 struct dirent* pdir,
89 size_t size,
90 int* out_bytes) {
91 *out_bytes = 0;
93 // If this is not a directory, fail
94 if (!IsaDir())
95 return ENOTDIR;
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());
106 if (result != PP_OK)
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)
118 continue;
120 uint32_t file_name_length;
121 const char* file_name =
122 var_iface_->VarToUtf8(file_name_var, &file_name_length);
124 if (file_name) {
125 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
131 // the filename.
132 ino_t child_ino = Html5Fs::HashPathSegment(stat_.st_ino, file_name,
133 file_name_length);
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_);
150 PP_FileInfo info;
151 int32_t result =
152 file_ref_iface_->Query(fileref_resource_, &info, PP_BlockUntilComplete());
153 if (result != PP_OK)
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.
160 switch (info.type) {
161 case PP_FILETYPE_REGULAR:
162 stat->st_mode |= S_IFREG;
163 break;
164 case PP_FILETYPE_DIRECTORY:
165 stat->st_mode |= S_IFDIR;
166 break;
167 case PP_FILETYPE_OTHER:
168 default:
169 break;
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;
176 return 0;
179 Error Html5FsNode::Read(const HandleAttr& attr,
180 void* buf,
181 size_t count,
182 int* out_bytes) {
183 *out_bytes = 0;
185 if (IsaDir())
186 return EISDIR;
188 int32_t result = file_io_iface_->Read(fileio_resource_,
189 attr.offs,
190 static_cast<char*>(buf),
191 static_cast<int32_t>(count),
192 PP_BlockUntilComplete());
193 if (result < 0)
194 return PPERROR_TO_ERRNO(result);
196 *out_bytes = result;
197 return 0;
200 Error Html5FsNode::FTruncate(off_t size) {
201 if (IsaDir())
202 return EISDIR;
204 int32_t result = file_io_iface_->SetLength(
205 fileio_resource_, size, PP_BlockUntilComplete());
206 if (result != PP_OK)
207 return PPERROR_TO_ERRNO(result);
208 return 0;
211 Error Html5FsNode::Write(const HandleAttr& attr,
212 const void* buf,
213 size_t count,
214 int* out_bytes) {
215 *out_bytes = 0;
217 if (IsaDir())
218 return EISDIR;
220 int32_t result = file_io_iface_->Write(fileio_resource_,
221 attr.offs,
222 static_cast<const char*>(buf),
223 static_cast<int32_t>(count),
224 PP_BlockUntilComplete());
225 if (result < 0)
226 return PPERROR_TO_ERRNO(result);
228 *out_bytes = result;
229 return 0;
232 int Html5FsNode::GetType() {
233 return fileio_resource_ ? S_IFREG : S_IFDIR;
236 Error Html5FsNode::GetSize(off_t* out_size) {
237 *out_size = 0;
239 if (IsaDir())
240 return 0;
242 AUTO_LOCK(node_lock_);
244 PP_FileInfo info;
245 int32_t result =
246 file_io_iface_->Query(fileio_resource_, &info, PP_BlockUntilComplete());
247 if (result != PP_OK)
248 return PPERROR_TO_ERRNO(result);
250 *out_size = info.size;
251 return 0;
254 Html5FsNode::Html5FsNode(Filesystem* filesystem, PP_Resource fileref_resource)
255 : Node(filesystem),
256 fileref_resource_(fileref_resource),
257 fileio_resource_(0) {
260 Error Html5FsNode::Init(int open_flags) {
261 Error error = Node::Init(open_flags);
262 if (error)
263 return error;
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 ");
274 return EIO;
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) {
286 return 0;
289 fileio_resource_ =
290 file_io_iface_->Create(filesystem_->ppapi()->GetInstance());
291 if (!fileio_resource_) {
292 LOG_ERROR("Couldn't create FileIo resource.");
293 return EIO;
296 int32_t open_result =
297 file_io_iface_->Open(fileio_resource_,
298 fileref_resource_,
299 OpenFlagsToPPAPIOpenFlags(open_flags),
300 PP_BlockUntilComplete());
301 if (open_result != PP_OK)
302 return PPERROR_TO_ERRNO(open_result);
303 return 0;
306 void Html5FsNode::Destroy() {
307 FSync();
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;
317 Node::Destroy();
320 Error Html5FsNode::Fchmod(mode_t mode) {
321 // html5fs does not support any kinds of permissions or mode bits.
322 return 0;
325 } // namespace nacl_io