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 mode, 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(mode); 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 ScopedResource fileref_resource( 65 ppapi(), 66 ppapi()->GetFileRefInterface()->Create(filesystem_resource_, 67 path.Join().c_str())); 68 if (!fileref_resource.pp_resource()) 69 return ENOENT; 70 71 int32_t result = ppapi()->GetFileRefInterface()->MakeDirectory( 72 fileref_resource.pp_resource(), PP_FALSE, PP_BlockUntilComplete()); 73 if (result != PP_OK) 74 return PPErrorToErrno(result); 75 76 return 0; 77 } 78 79 Error MountHtml5Fs::Rmdir(const Path& path) { return Remove(path); } 80 81 Error MountHtml5Fs::Remove(const Path& path) { 82 Error error = BlockUntilFilesystemOpen(); 83 if (error) 84 return error; 85 86 ScopedResource fileref_resource( 87 ppapi(), 88 ppapi()->GetFileRefInterface()->Create(filesystem_resource_, 89 path.Join().c_str())); 90 if (!fileref_resource.pp_resource()) 91 return ENOENT; 92 93 int32_t result = ppapi()->GetFileRefInterface() 94 ->Delete(fileref_resource.pp_resource(), PP_BlockUntilComplete()); 95 if (result != PP_OK) 96 return PPErrorToErrno(result); 97 98 return 0; 99 } 100 101 MountHtml5Fs::MountHtml5Fs() 102 : filesystem_resource_(0), 103 filesystem_open_has_result_(false), 104 filesystem_open_error_(0) {} 105 106 Error MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) { 107 Error error = Mount::Init(dev, args, ppapi); 108 if (error) 109 return error; 110 111 if (!ppapi) 112 return ENOSYS; 113 114 pthread_cond_init(&filesystem_open_cond_, NULL); 115 116 // Parse mount args. 117 PP_FileSystemType filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT; 118 int64_t expected_size = 0; 119 for (StringMap_t::iterator iter = args.begin(), end = args.end(); iter != end; 120 ++iter) { 121 if (iter->first == "type") { 122 if (iter->second == "PERSISTENT") { 123 filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT; 124 } else if (iter->second == "TEMPORARY") { 125 filesystem_type = PP_FILESYSTEMTYPE_LOCALTEMPORARY; 126 } 127 } else if (iter->first == "expected_size") { 128 expected_size = strtoull(iter->second.c_str(), NULL, 10); 129 } 130 } 131 132 // Initialize filesystem. 133 filesystem_resource_ = ppapi->GetFileSystemInterface() 134 ->Create(ppapi_->GetInstance(), filesystem_type); 135 if (filesystem_resource_ == 0) 136 return ENOSYS; 137 138 // We can't block the main thread, so make an asynchronous call if on main 139 // thread. If we are off-main-thread, then don't make an asynchronous call; 140 // otherwise we require a message loop. 141 bool main_thread = ppapi->IsMainThread(); 142 PP_CompletionCallback cc = 143 main_thread ? PP_MakeCompletionCallback( 144 &MountHtml5Fs::FilesystemOpenCallbackThunk, this) 145 : PP_BlockUntilComplete(); 146 147 int32_t result = ppapi->GetFileSystemInterface() 148 ->Open(filesystem_resource_, expected_size, cc); 149 150 if (!main_thread) { 151 filesystem_open_has_result_ = true; 152 filesystem_open_error_ = PPErrorToErrno(result); 153 154 return filesystem_open_error_; 155 } else { 156 // We have to assume the call to Open will succeed; there is no better 157 // result to return here. 158 return 0; 159 } 160 } 161 162 void MountHtml5Fs::Destroy() { 163 ppapi_->ReleaseResource(filesystem_resource_); 164 pthread_cond_destroy(&filesystem_open_cond_); 165 } 166 167 Error MountHtml5Fs::BlockUntilFilesystemOpen() { 168 AUTO_LOCK(filesysem_open_lock_); 169 while (!filesystem_open_has_result_) { 170 pthread_cond_wait(&filesystem_open_cond_, filesysem_open_lock_.mutex()); 171 } 172 return filesystem_open_error_; 173 } 174 175 // static 176 void MountHtml5Fs::FilesystemOpenCallbackThunk(void* user_data, 177 int32_t result) { 178 MountHtml5Fs* self = static_cast<MountHtml5Fs*>(user_data); 179 self->FilesystemOpenCallback(result); 180 } 181 182 void MountHtml5Fs::FilesystemOpenCallback(int32_t result) { 183 AUTO_LOCK(filesysem_open_lock_); 184 filesystem_open_has_result_ = true; 185 filesystem_open_error_ = PPErrorToErrno(result); 186 pthread_cond_signal(&filesystem_open_cond_); 187 } 188 189 } // namespace nacl_io 190 191