Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc

Issue 349703003: [NaCl SDK] Add some more logging to nacl_io. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix linux host build Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "nacl_io/fusefs/fuse_fs.h" 5 #include "nacl_io/fusefs/fuse_fs.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <string.h> 9 #include <string.h>
10 10
11 #include <algorithm> 11 #include <algorithm>
12 12
13 #include "nacl_io/getdents_helper.h" 13 #include "nacl_io/getdents_helper.h"
14 #include "nacl_io/kernel_handle.h" 14 #include "nacl_io/kernel_handle.h"
15 #include "nacl_io/log.h"
15 #include "sdk_util/macros.h" 16 #include "sdk_util/macros.h"
16 17
17 namespace nacl_io { 18 namespace nacl_io {
18 19
19 namespace { 20 namespace {
20 21
21 struct FillDirInfo { 22 struct FillDirInfo {
22 FillDirInfo(GetDentsHelper* getdents, size_t num_bytes) 23 FillDirInfo(GetDentsHelper* getdents, size_t num_bytes)
23 : getdents(getdents), num_bytes(num_bytes), wrote_offset(false) {} 24 : getdents(getdents), num_bytes(num_bytes), wrote_offset(false) {}
24 25
25 GetDentsHelper* getdents; 26 GetDentsHelper* getdents;
26 size_t num_bytes; 27 size_t num_bytes;
27 bool wrote_offset; 28 bool wrote_offset;
28 }; 29 };
29 30
30 } // namespace 31 } // namespace
31 32
32 FuseFs::FuseFs() : fuse_ops_(NULL), fuse_user_data_(NULL) { 33 FuseFs::FuseFs() : fuse_ops_(NULL), fuse_user_data_(NULL) {
33 } 34 }
34 35
35 Error FuseFs::Init(const FsInitArgs& args) { 36 Error FuseFs::Init(const FsInitArgs& args) {
36 Error error = Filesystem::Init(args); 37 Error error = Filesystem::Init(args);
37 if (error) 38 if (error)
38 return error; 39 return error;
39 40
40 fuse_ops_ = args.fuse_ops; 41 fuse_ops_ = args.fuse_ops;
41 if (fuse_ops_ == NULL) 42 if (fuse_ops_ == NULL) {
43 LOG_ERROR("fuse_ops_ is NULL.");
42 return EINVAL; 44 return EINVAL;
45 }
43 46
44 if (fuse_ops_->init) { 47 if (fuse_ops_->init) {
45 struct fuse_conn_info info; 48 struct fuse_conn_info info;
46 fuse_user_data_ = fuse_ops_->init(&info); 49 fuse_user_data_ = fuse_ops_->init(&info);
47 } 50 }
48 51
49 return 0; 52 return 0;
50 } 53 }
51 54
52 void FuseFs::Destroy() { 55 void FuseFs::Destroy() {
53 if (fuse_ops_ && fuse_ops_->destroy) 56 if (fuse_ops_ && fuse_ops_->destroy)
54 fuse_ops_->destroy(fuse_user_data_); 57 fuse_ops_->destroy(fuse_user_data_);
55 } 58 }
56 59
57 Error FuseFs::Access(const Path& path, int a_mode) { 60 Error FuseFs::Access(const Path& path, int a_mode) {
58 if (!fuse_ops_->access) 61 if (!fuse_ops_->access) {
62 LOG_TRACE("fuse_ops_->access is NULL.");
59 return ENOSYS; 63 return ENOSYS;
64 }
60 65
61 int result = fuse_ops_->access(path.Join().c_str(), a_mode); 66 int result = fuse_ops_->access(path.Join().c_str(), a_mode);
62 if (result < 0) 67 if (result < 0)
63 return -result; 68 return -result;
64 69
65 return 0; 70 return 0;
66 } 71 }
67 72
68 Error FuseFs::Open(const Path& path, int open_flags, ScopedNode* out_node) { 73 Error FuseFs::Open(const Path& path, int open_flags, ScopedNode* out_node) {
69 std::string path_str = path.Join(); 74 std::string path_str = path.Join();
(...skipping 10 matching lines...) Expand all
80 mode_t mode = S_IRALL | S_IWALL; 85 mode_t mode = S_IRALL | S_IWALL;
81 if (fuse_ops_->create) { 86 if (fuse_ops_->create) {
82 result = fuse_ops_->create(path_cstr, mode, &fi); 87 result = fuse_ops_->create(path_cstr, mode, &fi);
83 if (result < 0) 88 if (result < 0)
84 return -result; 89 return -result;
85 } else if (fuse_ops_->mknod) { 90 } else if (fuse_ops_->mknod) {
86 result = fuse_ops_->mknod(path_cstr, mode, dev_); 91 result = fuse_ops_->mknod(path_cstr, mode, dev_);
87 if (result < 0) 92 if (result < 0)
88 return -result; 93 return -result;
89 } else { 94 } else {
95 LOG_TRACE("fuse_ops_->create and fuse_ops_->mknod are NULL.");
90 return ENOSYS; 96 return ENOSYS;
91 } 97 }
92 } else { 98 } else {
93 // First determine if this is a regular file or a directory. 99 // First determine if this is a regular file or a directory.
94 if (fuse_ops_->getattr) { 100 if (fuse_ops_->getattr) {
95 struct stat statbuf; 101 struct stat statbuf;
96 result = fuse_ops_->getattr(path_cstr, &statbuf); 102 result = fuse_ops_->getattr(path_cstr, &statbuf);
97 if (result < 0) 103 if (result < 0)
98 return -result; 104 return -result;
99 105
100 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { 106 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
101 // This is a directory. Don't try to open, just create a new node with 107 // This is a directory. Don't try to open, just create a new node with
102 // this path. 108 // this path.
103 ScopedNode node(new DirFuseFsNode(this, fuse_ops_, fi, path_cstr)); 109 ScopedNode node(new DirFuseFsNode(this, fuse_ops_, fi, path_cstr));
104 Error error = node->Init(open_flags); 110 Error error = node->Init(open_flags);
105 if (error) 111 if (error)
106 return error; 112 return error;
107 113
108 *out_node = node; 114 *out_node = node;
109 return 0; 115 return 0;
110 } 116 }
111 } 117 }
112 118
113 // Existing file. 119 // Existing file.
114 if (open_flags & O_TRUNC) { 120 if (open_flags & O_TRUNC) {
115 // According to the FUSE docs, O_TRUNC does two calls: first truncate() 121 // According to the FUSE docs, O_TRUNC does two calls: first truncate()
116 // then open(). 122 // then open().
117 if (!fuse_ops_->truncate) 123 if (!fuse_ops_->truncate) {
124 LOG_TRACE("fuse_ops_->truncate is NULL.");
118 return ENOSYS; 125 return ENOSYS;
126 }
119 result = fuse_ops_->truncate(path_cstr, 0); 127 result = fuse_ops_->truncate(path_cstr, 0);
120 if (result < 0) 128 if (result < 0)
121 return -result; 129 return -result;
122 } 130 }
123 131
124 if (!fuse_ops_->open) 132 if (!fuse_ops_->open) {
133 LOG_TRACE("fuse_ops_->open is NULL.");
125 return ENOSYS; 134 return ENOSYS;
135 }
126 result = fuse_ops_->open(path_cstr, &fi); 136 result = fuse_ops_->open(path_cstr, &fi);
127 if (result < 0) 137 if (result < 0)
128 return -result; 138 return -result;
129 } 139 }
130 140
131 ScopedNode node(new FileFuseFsNode(this, fuse_ops_, fi, path_cstr)); 141 ScopedNode node(new FileFuseFsNode(this, fuse_ops_, fi, path_cstr));
132 Error error = node->Init(open_flags); 142 Error error = node->Init(open_flags);
133 if (error) 143 if (error)
134 return error; 144 return error;
135 145
136 *out_node = node; 146 *out_node = node;
137 return 0; 147 return 0;
138 } 148 }
139 149
140 Error FuseFs::Unlink(const Path& path) { 150 Error FuseFs::Unlink(const Path& path) {
141 if (!fuse_ops_->unlink) 151 if (!fuse_ops_->unlink) {
152 LOG_TRACE("fuse_ops_->unlink is NULL.");
142 return ENOSYS; 153 return ENOSYS;
154 }
143 155
144 int result = fuse_ops_->unlink(path.Join().c_str()); 156 int result = fuse_ops_->unlink(path.Join().c_str());
145 if (result < 0) 157 if (result < 0)
146 return -result; 158 return -result;
147 159
148 return 0; 160 return 0;
149 } 161 }
150 162
151 Error FuseFs::Mkdir(const Path& path, int perm) { 163 Error FuseFs::Mkdir(const Path& path, int perm) {
152 if (!fuse_ops_->mkdir) 164 if (!fuse_ops_->mkdir) {
165 LOG_TRACE("fuse_ops_->mkdir is NULL.");
153 return ENOSYS; 166 return ENOSYS;
167 }
154 168
155 int result = fuse_ops_->mkdir(path.Join().c_str(), perm); 169 int result = fuse_ops_->mkdir(path.Join().c_str(), perm);
156 if (result < 0) 170 if (result < 0)
157 return -result; 171 return -result;
158 172
159 return 0; 173 return 0;
160 } 174 }
161 175
162 Error FuseFs::Rmdir(const Path& path) { 176 Error FuseFs::Rmdir(const Path& path) {
163 if (!fuse_ops_->rmdir) 177 if (!fuse_ops_->rmdir) {
178 LOG_TRACE("fuse_ops_->rmdir is NULL.");
164 return ENOSYS; 179 return ENOSYS;
180 }
165 181
166 int result = fuse_ops_->rmdir(path.Join().c_str()); 182 int result = fuse_ops_->rmdir(path.Join().c_str());
167 if (result < 0) 183 if (result < 0)
168 return -result; 184 return -result;
169 185
170 return 0; 186 return 0;
171 } 187 }
172 188
173 Error FuseFs::Remove(const Path& path) { 189 Error FuseFs::Remove(const Path& path) {
174 ScopedNode node; 190 ScopedNode node;
175 Error error = Open(path, O_RDONLY, &node); 191 Error error = Open(path, O_RDONLY, &node);
176 if (error) 192 if (error)
177 return error; 193 return error;
178 194
179 struct stat statbuf; 195 struct stat statbuf;
180 error = node->GetStat(&statbuf); 196 error = node->GetStat(&statbuf);
181 if (error) 197 if (error)
182 return error; 198 return error;
183 199
184 node.reset(); 200 node.reset();
185 201
186 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { 202 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
187 return Rmdir(path); 203 return Rmdir(path);
188 } else { 204 } else {
189 return Unlink(path); 205 return Unlink(path);
190 } 206 }
191 } 207 }
192 208
193 Error FuseFs::Rename(const Path& path, const Path& newpath) { 209 Error FuseFs::Rename(const Path& path, const Path& newpath) {
194 if (!fuse_ops_->rename) 210 if (!fuse_ops_->rename) {
211 LOG_TRACE("fuse_ops_->rename is NULL.");
195 return ENOSYS; 212 return ENOSYS;
213 }
196 214
197 int result = fuse_ops_->rename(path.Join().c_str(), newpath.Join().c_str()); 215 int result = fuse_ops_->rename(path.Join().c_str(), newpath.Join().c_str());
198 if (result < 0) 216 if (result < 0)
199 return -result; 217 return -result;
200 218
201 return 0; 219 return 0;
202 } 220 }
203 221
204 FuseFsNode::FuseFsNode(Filesystem* filesystem, 222 FuseFsNode::FuseFsNode(Filesystem* filesystem,
205 struct fuse_operations* fuse_ops, 223 struct fuse_operations* fuse_ops,
(...skipping 17 matching lines...) Expand all
223 int result; 241 int result;
224 if (fuse_ops_->fgetattr) { 242 if (fuse_ops_->fgetattr) {
225 result = fuse_ops_->fgetattr(path_.c_str(), stat, &info_); 243 result = fuse_ops_->fgetattr(path_.c_str(), stat, &info_);
226 if (result < 0) 244 if (result < 0)
227 return -result; 245 return -result;
228 } else if (fuse_ops_->getattr) { 246 } else if (fuse_ops_->getattr) {
229 result = fuse_ops_->getattr(path_.c_str(), stat); 247 result = fuse_ops_->getattr(path_.c_str(), stat);
230 if (result < 0) 248 if (result < 0)
231 return -result; 249 return -result;
232 } else { 250 } else {
251 LOG_TRACE("fuse_ops_->fgetattr and fuse_ops_->getattr are NULL.");
233 return ENOSYS; 252 return ENOSYS;
234 } 253 }
235 254
236 // Also update the cached stat values. 255 // Also update the cached stat values.
237 stat_ = *stat; 256 stat_ = *stat;
238 return 0; 257 return 0;
239 } 258 }
240 259
241 Error FuseFsNode::VIoctl(int request, va_list args) { 260 Error FuseFsNode::VIoctl(int request, va_list args) {
242 // TODO(binji): implement 261 LOG_ERROR("Ioctl not implemented for fusefs.");
243 return ENOSYS; 262 return ENOSYS;
244 } 263 }
245 264
246 Error FuseFsNode::Tcflush(int queue_selector) { 265 Error FuseFsNode::Tcflush(int queue_selector) {
247 // TODO(binji): use ioctl for this? 266 LOG_ERROR("Tcflush not implemented for fusefs.");
248 return ENOSYS; 267 return ENOSYS;
249 } 268 }
250 269
251 Error FuseFsNode::Tcgetattr(struct termios* termios_p) { 270 Error FuseFsNode::Tcgetattr(struct termios* termios_p) {
252 // TODO(binji): use ioctl for this? 271 LOG_ERROR("Tcgetattr not implemented for fusefs.");
253 return ENOSYS; 272 return ENOSYS;
254 } 273 }
255 274
256 Error FuseFsNode::Tcsetattr(int optional_actions, 275 Error FuseFsNode::Tcsetattr(int optional_actions,
257 const struct termios* termios_p) { 276 const struct termios* termios_p) {
258 // TODO(binji): use ioctl for this? 277 LOG_ERROR("Tcsetattr not implemented for fusefs.");
259 return ENOSYS; 278 return ENOSYS;
260 } 279 }
261 280
262 Error FuseFsNode::GetSize(off_t* out_size) { 281 Error FuseFsNode::GetSize(off_t* out_size) {
263 struct stat statbuf; 282 struct stat statbuf;
264 Error error = GetStat(&statbuf); 283 Error error = GetStat(&statbuf);
265 if (error) 284 if (error)
266 return error; 285 return error;
267 286
268 *out_size = stat_.st_size; 287 *out_size = stat_.st_size;
269 return 0; 288 return 0;
270 } 289 }
271 290
272 FileFuseFsNode::FileFuseFsNode(Filesystem* filesystem, 291 FileFuseFsNode::FileFuseFsNode(Filesystem* filesystem,
273 struct fuse_operations* fuse_ops, 292 struct fuse_operations* fuse_ops,
274 struct fuse_file_info& info, 293 struct fuse_file_info& info,
275 const std::string& path) 294 const std::string& path)
276 : FuseFsNode(filesystem, fuse_ops, info, path) { 295 : FuseFsNode(filesystem, fuse_ops, info, path) {
277 } 296 }
278 297
279 void FileFuseFsNode::Destroy() { 298 void FileFuseFsNode::Destroy() {
280 if (!fuse_ops_->release) 299 if (!fuse_ops_->release)
281 return; 300 return;
282 fuse_ops_->release(path_.c_str(), &info_); 301 fuse_ops_->release(path_.c_str(), &info_);
283 } 302 }
284 303
285 Error FileFuseFsNode::FSync() { 304 Error FileFuseFsNode::FSync() {
286 if (!fuse_ops_->fsync) 305 if (!fuse_ops_->fsync) {
306 LOG_ERROR("fuse_ops_->fsync is NULL.");
287 return ENOSYS; 307 return ENOSYS;
308 }
288 309
289 int datasync = 0; 310 int datasync = 0;
290 int result = fuse_ops_->fsync(path_.c_str(), datasync, &info_); 311 int result = fuse_ops_->fsync(path_.c_str(), datasync, &info_);
291 if (result < 0) 312 if (result < 0)
292 return -result; 313 return -result;
293 return 0; 314 return 0;
294 } 315 }
295 316
296 Error FileFuseFsNode::FTruncate(off_t length) { 317 Error FileFuseFsNode::FTruncate(off_t length) {
297 if (!fuse_ops_->ftruncate) 318 if (!fuse_ops_->ftruncate) {
319 LOG_ERROR("fuse_ops_->ftruncate is NULL.");
298 return ENOSYS; 320 return ENOSYS;
321 }
299 322
300 int result = fuse_ops_->ftruncate(path_.c_str(), length, &info_); 323 int result = fuse_ops_->ftruncate(path_.c_str(), length, &info_);
301 if (result < 0) 324 if (result < 0)
302 return -result; 325 return -result;
303 return 0; 326 return 0;
304 } 327 }
305 328
306 Error FileFuseFsNode::Read(const HandleAttr& attr, 329 Error FileFuseFsNode::Read(const HandleAttr& attr,
307 void* buf, 330 void* buf,
308 size_t count, 331 size_t count,
309 int* out_bytes) { 332 int* out_bytes) {
310 if (!fuse_ops_->read) 333 if (!fuse_ops_->read) {
334 LOG_ERROR("fuse_ops_->read is NULL.");
311 return ENOSYS; 335 return ENOSYS;
336 }
312 337
313 char* cbuf = static_cast<char*>(buf); 338 char* cbuf = static_cast<char*>(buf);
314 339
315 int result = fuse_ops_->read(path_.c_str(), cbuf, count, attr.offs, &info_); 340 int result = fuse_ops_->read(path_.c_str(), cbuf, count, attr.offs, &info_);
316 if (result < 0) 341 if (result < 0)
317 return -result; 342 return -result;
318 343
319 // Fuse docs say that a read() call will always completely fill the buffer 344 // Fuse docs say that a read() call will always completely fill the buffer
320 // (padding with zeroes) unless the direct_io filesystem flag is set. 345 // (padding with zeroes) unless the direct_io filesystem flag is set.
321 // TODO(binji): support the direct_io flag 346 // TODO(binji): support the direct_io flag
322 if (static_cast<size_t>(result) < count) 347 if (static_cast<size_t>(result) < count)
323 memset(&cbuf[result], 0, count - result); 348 memset(&cbuf[result], 0, count - result);
324 349
325 *out_bytes = count; 350 *out_bytes = count;
326 return 0; 351 return 0;
327 } 352 }
328 353
329 Error FileFuseFsNode::Write(const HandleAttr& attr, 354 Error FileFuseFsNode::Write(const HandleAttr& attr,
330 const void* buf, 355 const void* buf,
331 size_t count, 356 size_t count,
332 int* out_bytes) { 357 int* out_bytes) {
333 if (!fuse_ops_->write) 358 if (!fuse_ops_->write) {
359 LOG_ERROR("fuse_ops_->write is NULL.");
334 return ENOSYS; 360 return ENOSYS;
361 }
335 362
336 int result = fuse_ops_->write( 363 int result = fuse_ops_->write(
337 path_.c_str(), static_cast<const char*>(buf), count, attr.offs, &info_); 364 path_.c_str(), static_cast<const char*>(buf), count, attr.offs, &info_);
338 if (result < 0) 365 if (result < 0)
339 return -result; 366 return -result;
340 367
341 // Fuse docs say that a write() call will always write the entire buffer 368 // Fuse docs say that a write() call will always write the entire buffer
342 // unless the direct_io filesystem flag is set. 369 // unless the direct_io filesystem flag is set.
343 // TODO(binji): What should we do if the user breaks this contract? Warn? 370 // TODO(binji): What should we do if the user breaks this contract? Warn?
344 // TODO(binji): support the direct_io flag 371 // TODO(binji): support the direct_io flag
345 *out_bytes = result; 372 *out_bytes = result;
346 return 0; 373 return 0;
347 } 374 }
348 375
349 DirFuseFsNode::DirFuseFsNode(Filesystem* filesystem, 376 DirFuseFsNode::DirFuseFsNode(Filesystem* filesystem,
350 struct fuse_operations* fuse_ops, 377 struct fuse_operations* fuse_ops,
351 struct fuse_file_info& info, 378 struct fuse_file_info& info,
352 const std::string& path) 379 const std::string& path)
353 : FuseFsNode(filesystem, fuse_ops, info, path) { 380 : FuseFsNode(filesystem, fuse_ops, info, path) {
354 } 381 }
355 382
356 void DirFuseFsNode::Destroy() { 383 void DirFuseFsNode::Destroy() {
357 if (!fuse_ops_->releasedir) 384 if (!fuse_ops_->releasedir)
358 return; 385 return;
359 fuse_ops_->releasedir(path_.c_str(), &info_); 386 fuse_ops_->releasedir(path_.c_str(), &info_);
360 } 387 }
361 388
362 Error DirFuseFsNode::FSync() { 389 Error DirFuseFsNode::FSync() {
363 if (!fuse_ops_->fsyncdir) 390 if (!fuse_ops_->fsyncdir) {
391 LOG_ERROR("fuse_ops_->fsyncdir is NULL.");
364 return ENOSYS; 392 return ENOSYS;
393 }
365 394
366 int datasync = 0; 395 int datasync = 0;
367 int result = fuse_ops_->fsyncdir(path_.c_str(), datasync, &info_); 396 int result = fuse_ops_->fsyncdir(path_.c_str(), datasync, &info_);
368 if (result < 0) 397 if (result < 0)
369 return -result; 398 return -result;
370 return 0; 399 return 0;
371 } 400 }
372 401
373 Error DirFuseFsNode::GetDents(size_t offs, 402 Error DirFuseFsNode::GetDents(size_t offs,
374 struct dirent* pdir, 403 struct dirent* pdir,
375 size_t count, 404 size_t count,
376 int* out_bytes) { 405 int* out_bytes) {
377 if (!fuse_ops_->readdir) 406 if (!fuse_ops_->readdir) {
407 LOG_ERROR("fuse_ops_->readdir is NULL.");
378 return ENOSYS; 408 return ENOSYS;
409 }
379 410
380 bool opened_dir = false; 411 bool opened_dir = false;
381 int result; 412 int result;
382 413
383 // Opendir is not necessary, only readdir. Call it anyway, if it is defined. 414 // Opendir is not necessary, only readdir. Call it anyway, if it is defined.
384 if (fuse_ops_->opendir) { 415 if (fuse_ops_->opendir) {
385 result = fuse_ops_->opendir(path_.c_str(), &info_); 416 result = fuse_ops_->opendir(path_.c_str(), &info_);
386 if (result < 0) 417 if (result < 0)
387 return -result; 418 return -result;
388 419
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 } else { 477 } else {
447 fill_info->getdents->AddDirent(ino, name, strlen(name)); 478 fill_info->getdents->AddDirent(ino, name, strlen(name));
448 fill_info->num_bytes -= sizeof(dirent); 479 fill_info->num_bytes -= sizeof(dirent);
449 // According to the docs, we can never return 1 (buffer full) when the 480 // According to the docs, we can never return 1 (buffer full) when the
450 // offset is zero (the user is probably ignoring the result anyway). 481 // offset is zero (the user is probably ignoring the result anyway).
451 return 0; 482 return 0;
452 } 483 }
453 } 484 }
454 485
455 } // namespace nacl_io 486 } // namespace nacl_io
OLDNEW
« no previous file with comments | « native_client_sdk/src/libraries/nacl_io/filesystem.cc ('k') | native_client_sdk/src/libraries/nacl_io/getdents_helper.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698