1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "nacl_io/jsfs/js_fs_node.h"
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <assert.h>
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <errno.h>
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <fcntl.h>
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <limits.h>
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <string.h>
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "nacl_io/jsfs/js_fs.h"
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "nacl_io/kernel_handle.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "nacl_io/log.h"
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "nacl_io/osdirent.h"
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "nacl_io/pepper_interface.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "sdk_util/macros.h"
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace nacl_io {
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)JsFsNode::JsFsNode(Filesystem* filesystem, int32_t fd)
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : Node(filesystem),
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ppapi_(filesystem->ppapi()),
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      array_iface_(ppapi_->GetVarArrayInterface()),
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      buffer_iface_(ppapi_->GetVarArrayBufferInterface()),
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      var_iface_(ppapi_->GetVarInterface()),
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      fd_(fd) {
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void JsFsNode::Destroy() {
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(binji): implement
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool JsFsNode::SendRequestAndWait(ScopedVar* out_response,
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  const char* format,
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  ...) {
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_list args;
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_start(args, format);
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool result = filesystem()->VSendRequestAndWait(out_response, format, args);
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_end(args);
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return result;
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int JsFsNode::ScanVar(PP_Var var, const char* format, ...) {
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_list args;
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_start(args, format);
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int result = filesystem()->VScanVar(var, format, args);
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  va_end(args);
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return result;
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool JsFsNode::CanOpen(int open_flags) {
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  struct stat statbuf;
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Error error = GetStat(&statbuf);
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (error)
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // GetStat cached the mode in stat_.st_mode. Forward to Node::CanOpen,
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // which will check this mode against open_flags.
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return Node::CanOpen(open_flags);
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error JsFsNode::GetStat(struct stat* stat) {
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  AUTO_LOCK(node_lock_);
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar response(ppapi_);
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!SendRequestAndWait(&response, "%s%d", "cmd", "fstat", "fildes", fd_)) {
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Failed to send request.");
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(binji): find out the size of bionic stat fields.
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(__native_client__) && !defined(__BIONIC__)
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(__GLIBC__)
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char* format = "%d%lld%d%d%d%d%lld%lld%lld%lld%lld%lld%lld";
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#else
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char* format = "%d%lld%d%d%d%d%lld%lld%d%d%lld%lld%lld";
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#else
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define FIELD(x)                              \
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  assert(sizeof(stat->x) >= sizeof(int32_t)); \
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  strcat(format, sizeof(stat->x) == sizeof(int64_t) ? "%lld" : "%d");
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // For host builds, we'll build up the format string at runtime.
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  char format[100] = "%d";  // First field is "error".
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_ino);
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_mode);
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_nlink);
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_uid);
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_gid);
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_rdev);
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_size);
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_blksize);
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_blocks);
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_atime);
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_mtime);
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FIELD(st_ctime);
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#undef FIELD
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int32_t error;
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int result = ScanVar(response.pp_var(),
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       format,
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "error", &error,
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_ino", &stat->st_ino,
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_mode", &stat->st_mode,
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_nlink", &stat->st_nlink,
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_uid", &stat->st_uid,
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_gid", &stat->st_gid,
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_rdev", &stat->st_rdev,
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_size", &stat->st_size,
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_blksize", &stat->st_blksize,
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_blocks", &stat->st_blocks,
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_atime", &stat->st_atime,
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_mtime", &stat->st_mtime,
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                       "st_ctime", &stat->st_ctime);
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (result >= 1 && error)
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return error;
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (result != 13) {
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR(
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        "Expected \"st_*\" and \"error\" fields in response (should be 13 "
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        "total).");
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  stat->st_dev = filesystem()->dev();
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return 0;
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error JsFsNode::GetSize(off_t* out_size) {
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *out_size = 0;
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  struct stat statbuf;
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Error error = GetStat(&statbuf);
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (error)
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return error;
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *out_size = stat_.st_size;
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return 0;
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error JsFsNode::FSync() {
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  AUTO_LOCK(node_lock_);
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar response(ppapi_);
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!SendRequestAndWait(&response, "%s%d", "cmd", "fsync", "fildes", fd_)) {
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Failed to send request.");
153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return filesystem()->ErrorFromResponse(response);
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error JsFsNode::FTruncate(off_t length) {
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  AUTO_LOCK(node_lock_);
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar response(ppapi_);
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!SendRequestAndWait(&response,
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "%s%d%lld", "cmd", "ftruncate", "fildes", fd_, "length", length)) {
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Failed to send request.");
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return filesystem()->ErrorFromResponse(response);
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error JsFsNode::Read(const HandleAttr& attr,
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     void* buf,
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     size_t count,
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     int* out_bytes) {
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  AUTO_LOCK(node_lock_);
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *out_bytes = 0;
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar response(ppapi_);
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!SendRequestAndWait(&response, "%s%d%u%lld",
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "cmd", "pread",
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "fildes", fd_,
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "nbyte", count,
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "offset", attr.offs)) {
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Failed to send request.");
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int32_t error;
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  PP_Var buf_var;
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int result =
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ScanVar(response.pp_var(), "%d%p", "error", &error, "buf", &buf_var);
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar scoped_buf_var(ppapi_, buf_var);
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (result >= 1 && error)
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return error;
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (result != 2) {
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Expected \"error\" and \"buf\" fields in response.");
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (buf_var.type != PP_VARTYPE_ARRAY_BUFFER) {
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Expected \"buf\" to be an ArrayBuffer.");
207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  uint32_t src_buf_len;
211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!buffer_iface_->ByteLength(buf_var, &src_buf_len)) {
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Unable to get byteLength of \"buf\".");
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (src_buf_len > count)
217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    src_buf_len = count;
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void* src_buf = buffer_iface_->Map(buf_var);
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (src_buf == NULL) {
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Unable to map \"buf\".");
222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  memcpy(buf, src_buf, src_buf_len);
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *out_bytes = src_buf_len;
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  buffer_iface_->Unmap(buf_var);
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return 0;
231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error JsFsNode::Write(const HandleAttr& attr,
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      const void* buf,
235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      size_t count,
236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      int* out_bytes) {
237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  AUTO_LOCK(node_lock_);
238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *out_bytes = 0;
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  PP_Var buf_var = buffer_iface_->Create(count);
242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar scoped_buf_var(ppapi_, buf_var);
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (buf_var.type != PP_VARTYPE_ARRAY_BUFFER) {
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Unable to create \"buf\" var.");
246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void* dst_buf = buffer_iface_->Map(buf_var);
250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (dst_buf == NULL) {
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Unable to map \"buf\".");
252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  memcpy(dst_buf, buf, count);
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  buffer_iface_->Unmap(buf_var);
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar response(ppapi_);
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!SendRequestAndWait(&response, "%s%d%p%u%lld",
261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "cmd", "pwrite",
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "fildes", fd_,
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "buf", &buf_var,
264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "nbyte", count,
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "offset", attr.offs)) {
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Failed to send request.");
267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int error;
271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  uint32_t nwrote;
272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int result =
273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ScanVar(response.pp_var(), "%d%u", "error", &error, "nwrote", &nwrote);
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (result >= 1 && error)
276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return error;
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (result != 2) {
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Expected \"error\" and \"nwrote\" fields in response.");
280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *out_bytes = nwrote;
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return 0;
285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Error JsFsNode::GetDents(size_t offs,
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         struct dirent* pdir,
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         size_t count,
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         int* out_bytes) {
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  AUTO_LOCK(node_lock_);
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *out_bytes = 0;
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Round to the nearest sizeof(dirent) and ask for that.
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_t first = offs / sizeof(dirent);
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_t last = (offs + count + sizeof(dirent) - 1) / sizeof(dirent);
298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar response(ppapi_);
300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!SendRequestAndWait(&response, "%s%d%u%u",
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "cmd", "getdents",
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "fildes", fd_,
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "offs", first,
304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          "count", last - first)) {
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Failed to send request.");
306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int error;
310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  PP_Var dirents_var;
311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int result = ScanVar(
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      response.pp_var(), "%d%p", "error", &error, "dirents", &dirents_var);
313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedVar scoped_dirents_var(ppapi_, dirents_var);
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (result >= 1 && error)
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return error;
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (result != 2) {
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Expected \"error\" and \"dirents\" fields in response.");
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (dirents_var.type != PP_VARTYPE_ARRAY) {
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG_ERROR("Expected \"dirents\" to be an Array.");
326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return EINVAL;
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  uint32_t dirents_len = array_iface_->GetLength(dirents_var);
330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  uint32_t dirents_byte_len = dirents_len * sizeof(dirent);
331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Allocate enough full dirents to copy from. This makes it easier if, for
333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // some reason, we are reading unaligned dirents.
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dirent* dirents = static_cast<dirent*>(malloc(dirents_byte_len));
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (uint32_t i = 0; i < dirents_len; ++i) {
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    PP_Var dirent_var = array_iface_->Get(dirents_var, i);
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    PP_Var d_name_var;
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    result = ScanVar(dirent_var,
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     "%lld%p",
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     "d_ino", &dirents[i].d_ino,
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     "d_name", &d_name_var);
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ScopedVar scoped_dirent_var(ppapi_, dirent_var);
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ScopedVar scoped_d_name_var(ppapi_, d_name_var);
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (result != 2) {
347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      LOG_ERROR("Expected dirent[%d] to have \"d_ino\" and \"d_name\".", i);
348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      free(dirents);
349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return EINVAL;
350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    uint32_t d_name_len;
353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const char* d_name = var_iface_->VarToUtf8(d_name_var, &d_name_len);
354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    dirents[i].d_off = sizeof(dirent);
356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    dirents[i].d_reclen = sizeof(dirent);
357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    strncpy(dirents[i].d_name, d_name, sizeof(dirents[i].d_name));
358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_t dirents_offs = offs - first * sizeof(dirent);
361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (dirents_offs + count > dirents_byte_len)
362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    count = dirents_byte_len - dirents_offs;
363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  memcpy(pdir, reinterpret_cast<const char*>(dirents) + dirents_offs, count);
365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  *out_bytes = count;
366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
367f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  free(dirents);
368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return 0;
369f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
370f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace nacl_io
372