OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |