1 // Copyright 2014 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/jsfs/js_fs_node.h"
13 #include "nacl_io/jsfs/js_fs.h"
14 #include "nacl_io/kernel_handle.h"
15 #include "nacl_io/log.h"
16 #include "nacl_io/osdirent.h"
17 #include "nacl_io/pepper_interface.h"
18 #include "sdk_util/macros.h"
22 JsFsNode::JsFsNode(Filesystem
* filesystem
, int32_t fd
)
24 ppapi_(filesystem
->ppapi()),
25 array_iface_(ppapi_
->GetVarArrayInterface()),
26 buffer_iface_(ppapi_
->GetVarArrayBufferInterface()),
27 var_iface_(ppapi_
->GetVarInterface()),
31 void JsFsNode::Destroy() {
32 // TODO(binji): implement
35 bool JsFsNode::SendRequestAndWait(ScopedVar
* out_response
,
39 va_start(args
, format
);
40 bool result
= filesystem()->VSendRequestAndWait(out_response
, format
, args
);
45 int JsFsNode::ScanVar(PP_Var var
, const char* format
, ...) {
47 va_start(args
, format
);
48 int result
= filesystem()->VScanVar(var
, format
, args
);
53 bool JsFsNode::CanOpen(int open_flags
) {
55 Error error
= GetStat(&statbuf
);
59 // GetStat cached the mode in stat_.st_mode. Forward to Node::CanOpen,
60 // which will check this mode against open_flags.
61 return Node::CanOpen(open_flags
);
64 Error
JsFsNode::GetStat(struct stat
* stat
) {
65 AUTO_LOCK(node_lock_
);
67 ScopedVar
response(ppapi_
);
68 if (!SendRequestAndWait(&response
, "%s%d", "cmd", "fstat", "fildes", fd_
)) {
69 LOG_ERROR("Failed to send request.");
73 // TODO(binji): find out the size of bionic stat fields.
74 #if defined(__native_client__) && !defined(__BIONIC__)
75 #if defined(__GLIBC__)
76 const char* format
= "%d%lld%d%d%d%d%lld%lld%lld%lld%lld%lld%lld";
78 const char* format
= "%d%lld%d%d%d%d%lld%lld%d%d%lld%lld%lld";
82 if (sizeof(stat->x) == sizeof(int64_t)) \
83 strcat(format, "%lld"); \
84 else if (sizeof(stat->x) == sizeof(int16_t)) \
85 strcat(format, "%hd"); \
89 // For host builds, we'll build up the format string at runtime.
90 char format
[100] = "%d"; // First field is "error".
108 int result
= ScanVar(response
.pp_var(),
111 "st_ino", &stat
->st_ino
,
112 "st_mode", &stat
->st_mode
,
113 "st_nlink", &stat
->st_nlink
,
114 "st_uid", &stat
->st_uid
,
115 "st_gid", &stat
->st_gid
,
116 "st_rdev", &stat
->st_rdev
,
117 "st_size", &stat
->st_size
,
118 "st_blksize", &stat
->st_blksize
,
119 "st_blocks", &stat
->st_blocks
,
120 "st_atime", &stat
->st_atime
,
121 "st_mtime", &stat
->st_mtime
,
122 "st_ctime", &stat
->st_ctime
);
124 if (result
>= 1 && error
)
129 "Expected \"st_*\" and \"error\" fields in response (should be 13 "
130 "total, got %d).", result
);
134 stat
->st_dev
= filesystem()->dev();
139 Error
JsFsNode::GetSize(off_t
* out_size
) {
143 Error error
= GetStat(&statbuf
);
147 *out_size
= stat_
.st_size
;
151 Error
JsFsNode::FSync() {
152 AUTO_LOCK(node_lock_
);
154 ScopedVar
response(ppapi_
);
155 if (!SendRequestAndWait(&response
, "%s%d", "cmd", "fsync", "fildes", fd_
)) {
156 LOG_ERROR("Failed to send request.");
160 return filesystem()->ErrorFromResponse(response
);
163 Error
JsFsNode::FTruncate(off_t length
) {
164 AUTO_LOCK(node_lock_
);
166 ScopedVar
response(ppapi_
);
167 if (!SendRequestAndWait(&response
,
168 "%s%d%lld", "cmd", "ftruncate", "fildes", fd_
, "length", length
)) {
169 LOG_ERROR("Failed to send request.");
173 return filesystem()->ErrorFromResponse(response
);
176 Error
JsFsNode::Read(const HandleAttr
& attr
,
180 AUTO_LOCK(node_lock_
);
184 ScopedVar
response(ppapi_
);
185 if (!SendRequestAndWait(&response
, "%s%d%u%lld",
189 "offset", attr
.offs
)) {
190 LOG_ERROR("Failed to send request.");
198 ScanVar(response
.pp_var(), "%d%p", "error", &error
, "buf", &buf_var
);
199 ScopedVar
scoped_buf_var(ppapi_
, buf_var
);
201 if (result
>= 1 && error
)
205 LOG_ERROR("Expected \"error\" and \"buf\" fields in response.");
209 if (buf_var
.type
!= PP_VARTYPE_ARRAY_BUFFER
) {
210 LOG_ERROR("Expected \"buf\" to be an ArrayBuffer.");
214 uint32_t src_buf_len
;
215 if (!buffer_iface_
->ByteLength(buf_var
, &src_buf_len
)) {
216 LOG_ERROR("Unable to get byteLength of \"buf\".");
220 if (src_buf_len
> count
)
223 void* src_buf
= buffer_iface_
->Map(buf_var
);
224 if (src_buf
== NULL
) {
225 LOG_ERROR("Unable to map \"buf\".");
229 memcpy(buf
, src_buf
, src_buf_len
);
230 *out_bytes
= src_buf_len
;
232 buffer_iface_
->Unmap(buf_var
);
237 Error
JsFsNode::Write(const HandleAttr
& attr
,
241 AUTO_LOCK(node_lock_
);
245 PP_Var buf_var
= buffer_iface_
->Create(count
);
246 ScopedVar
scoped_buf_var(ppapi_
, buf_var
);
248 if (buf_var
.type
!= PP_VARTYPE_ARRAY_BUFFER
) {
249 LOG_ERROR("Unable to create \"buf\" var.");
253 void* dst_buf
= buffer_iface_
->Map(buf_var
);
254 if (dst_buf
== NULL
) {
255 LOG_ERROR("Unable to map \"buf\".");
259 memcpy(dst_buf
, buf
, count
);
261 buffer_iface_
->Unmap(buf_var
);
263 ScopedVar
response(ppapi_
);
264 if (!SendRequestAndWait(&response
, "%s%d%p%u%lld",
269 "offset", attr
.offs
)) {
270 LOG_ERROR("Failed to send request.");
277 ScanVar(response
.pp_var(), "%d%u", "error", &error
, "nwrote", &nwrote
);
279 if (result
>= 1 && error
)
283 LOG_ERROR("Expected \"error\" and \"nwrote\" fields in response.");
291 Error
JsFsNode::GetDents(size_t offs
,
295 AUTO_LOCK(node_lock_
);
299 // Round to the nearest sizeof(dirent) and ask for that.
300 size_t first
= offs
/ sizeof(dirent
);
301 size_t last
= (offs
+ count
+ sizeof(dirent
) - 1) / sizeof(dirent
);
303 ScopedVar
response(ppapi_
);
304 if (!SendRequestAndWait(&response
, "%s%d%u%u",
308 "count", last
- first
)) {
309 LOG_ERROR("Failed to send request.");
315 int result
= ScanVar(
316 response
.pp_var(), "%d%p", "error", &error
, "dirents", &dirents_var
);
318 ScopedVar
scoped_dirents_var(ppapi_
, dirents_var
);
320 if (result
>= 1 && error
)
324 LOG_ERROR("Expected \"error\" and \"dirents\" fields in response.");
328 if (dirents_var
.type
!= PP_VARTYPE_ARRAY
) {
329 LOG_ERROR("Expected \"dirents\" to be an Array.");
333 uint32_t dirents_len
= array_iface_
->GetLength(dirents_var
);
334 uint32_t dirents_byte_len
= dirents_len
* sizeof(dirent
);
336 // Allocate enough full dirents to copy from. This makes it easier if, for
337 // some reason, we are reading unaligned dirents.
338 dirent
* dirents
= static_cast<dirent
*>(malloc(dirents_byte_len
));
340 for (uint32_t i
= 0; i
< dirents_len
; ++i
) {
341 PP_Var dirent_var
= array_iface_
->Get(dirents_var
, i
);
343 result
= ScanVar(dirent_var
,
345 "d_ino", &dirents
[i
].d_ino
,
346 "d_name", &d_name_var
);
347 ScopedVar
scoped_dirent_var(ppapi_
, dirent_var
);
348 ScopedVar
scoped_d_name_var(ppapi_
, d_name_var
);
351 LOG_ERROR("Expected dirent[%d] to have \"d_ino\" and \"d_name\".", i
);
357 const char* d_name
= var_iface_
->VarToUtf8(d_name_var
, &d_name_len
);
359 dirents
[i
].d_reclen
= sizeof(dirent
);
360 strncpy(dirents
[i
].d_name
, d_name
, sizeof(dirents
[i
].d_name
));
363 size_t dirents_offs
= offs
- first
* sizeof(dirent
);
364 if (dirents_offs
+ count
> dirents_byte_len
)
365 count
= dirents_byte_len
- dirents_offs
;
367 memcpy(pdir
, reinterpret_cast<const char*>(dirents
) + dirents_offs
, count
);
374 } // namespace nacl_io