- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / mount_html5fs.cc
1 // Copyright (c) 2012 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.
4
5 #include "nacl_io/mount_html5fs.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <ppapi/c/pp_completion_callback.h>
10 #include <ppapi/c/pp_errors.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <algorithm>
14 #include "nacl_io/mount_node_html5fs.h"
15 #include "sdk_util/auto_lock.h"
16
17 namespace nacl_io {
18
19 namespace {
20
21 #if defined(WIN32)
22 int64_t strtoull(const char* nptr, char** endptr, int base) {
23   return _strtoui64(nptr, endptr, base);
24 }
25 #endif
26
27 }  // namespace
28
29 Error MountHtml5Fs::Access(const Path& path, int a_mode) {
30   // a_mode is unused, since all files are readable, writable and executable.
31   ScopedMountNode node;
32   return Open(path, O_RDONLY, &node);
33 }
34
35 Error MountHtml5Fs::Open(const Path& path,
36                          int open_flags,
37                          ScopedMountNode* out_node) {
38   out_node->reset(NULL);
39   Error error = BlockUntilFilesystemOpen();
40   if (error)
41     return error;
42
43   PP_Resource fileref = ppapi()->GetFileRefInterface()
44       ->Create(filesystem_resource_, path.Join().c_str());
45   if (!fileref)
46     return ENOENT;
47
48   ScopedMountNode node(new MountNodeHtml5Fs(this, fileref));
49   error = node->Init(open_flags);
50   if (error)
51     return error;
52
53   *out_node = node;
54   return 0;
55 }
56
57 Error MountHtml5Fs::Unlink(const Path& path) { return Remove(path); }
58
59 Error MountHtml5Fs::Mkdir(const Path& path, int permissions) {
60   Error error = BlockUntilFilesystemOpen();
61   if (error)
62     return error;
63
64   // FileRef returns PP_ERROR_NOACCESS which is translated to EACCES if you
65   // try to create the root directory. EEXIST is a better errno here.
66   if (path.Top())
67     return EEXIST;
68
69   ScopedResource fileref_resource(
70       ppapi(),
71       ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
72                                              path.Join().c_str()));
73   if (!fileref_resource.pp_resource())
74     return ENOENT;
75
76   int32_t result = ppapi()->GetFileRefInterface()->MakeDirectory(
77       fileref_resource.pp_resource(), PP_FALSE, PP_BlockUntilComplete());
78   if (result != PP_OK)
79     return PPErrorToErrno(result);
80
81   return 0;
82 }
83
84 Error MountHtml5Fs::Rmdir(const Path& path) { return Remove(path); }
85
86 Error MountHtml5Fs::Remove(const Path& path) {
87   Error error = BlockUntilFilesystemOpen();
88   if (error)
89     return error;
90
91   ScopedResource fileref_resource(
92       ppapi(),
93       ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
94                                              path.Join().c_str()));
95   if (!fileref_resource.pp_resource())
96     return ENOENT;
97
98   int32_t result = ppapi()->GetFileRefInterface()
99       ->Delete(fileref_resource.pp_resource(), PP_BlockUntilComplete());
100   if (result != PP_OK)
101     return PPErrorToErrno(result);
102
103   return 0;
104 }
105
106 MountHtml5Fs::MountHtml5Fs()
107     : filesystem_resource_(0),
108       filesystem_open_has_result_(false),
109       filesystem_open_error_(0) {}
110
111 Error MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
112   Error error = Mount::Init(dev, args, ppapi);
113   if (error)
114     return error;
115
116   if (!ppapi)
117     return ENOSYS;
118
119   pthread_cond_init(&filesystem_open_cond_, NULL);
120
121   // Parse mount args.
122   PP_FileSystemType filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
123   int64_t expected_size = 0;
124   for (StringMap_t::iterator iter = args.begin(), end = args.end(); iter != end;
125        ++iter) {
126     if (iter->first == "type") {
127       if (iter->second == "PERSISTENT") {
128         filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
129       } else if (iter->second == "TEMPORARY") {
130         filesystem_type = PP_FILESYSTEMTYPE_LOCALTEMPORARY;
131       }
132     } else if (iter->first == "expected_size") {
133       expected_size = strtoull(iter->second.c_str(), NULL, 10);
134     }
135   }
136
137   // Initialize filesystem.
138   filesystem_resource_ = ppapi->GetFileSystemInterface()
139       ->Create(ppapi_->GetInstance(), filesystem_type);
140   if (filesystem_resource_ == 0)
141     return ENOSYS;
142
143   // We can't block the main thread, so make an asynchronous call if on main
144   // thread. If we are off-main-thread, then don't make an asynchronous call;
145   // otherwise we require a message loop.
146   bool main_thread = ppapi->GetCoreInterface()->IsMainThread();
147   PP_CompletionCallback cc =
148       main_thread ? PP_MakeCompletionCallback(
149                         &MountHtml5Fs::FilesystemOpenCallbackThunk, this)
150                   : PP_BlockUntilComplete();
151
152   int32_t result = ppapi->GetFileSystemInterface()
153       ->Open(filesystem_resource_, expected_size, cc);
154
155   if (!main_thread) {
156     filesystem_open_has_result_ = true;
157     filesystem_open_error_ = PPErrorToErrno(result);
158
159     return filesystem_open_error_;
160   }
161
162   // We have to assume the call to Open will succeed; there is no better
163   // result to return here.
164   return 0;
165 }
166
167 void MountHtml5Fs::Destroy() {
168   ppapi_->ReleaseResource(filesystem_resource_);
169   pthread_cond_destroy(&filesystem_open_cond_);
170 }
171
172 Error MountHtml5Fs::BlockUntilFilesystemOpen() {
173   AUTO_LOCK(filesysem_open_lock_);
174   while (!filesystem_open_has_result_) {
175     pthread_cond_wait(&filesystem_open_cond_, filesysem_open_lock_.mutex());
176   }
177   return filesystem_open_error_;
178 }
179
180 // static
181 void MountHtml5Fs::FilesystemOpenCallbackThunk(void* user_data,
182                                                int32_t result) {
183   MountHtml5Fs* self = static_cast<MountHtml5Fs*>(user_data);
184   self->FilesystemOpenCallback(result);
185 }
186
187 void MountHtml5Fs::FilesystemOpenCallback(int32_t result) {
188   AUTO_LOCK(filesysem_open_lock_);
189   filesystem_open_has_result_ = true;
190   filesystem_open_error_ = PPErrorToErrno(result);
191   pthread_cond_signal(&filesystem_open_cond_);
192 }
193
194 }  // namespace nacl_io
195