1 // Copyright (c) 2013 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/getdents_helper.h"
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10
11 #include <algorithm>
12
13 #include "sdk_util/macros.h"
14
15 namespace nacl_io {
16
GetDentsHelper()17 GetDentsHelper::GetDentsHelper()
18 : curdir_ino_(0), parentdir_ino_(0), init_defaults_(false) {
19 Initialize();
20 }
21
GetDentsHelper(ino_t curdir_ino,ino_t parentdir_ino)22 GetDentsHelper::GetDentsHelper(ino_t curdir_ino, ino_t parentdir_ino)
23 : curdir_ino_(curdir_ino),
24 parentdir_ino_(parentdir_ino),
25 init_defaults_(true) {
26 Initialize();
27 }
28
Reset()29 void GetDentsHelper::Reset() {
30 dirents_.clear();
31 Initialize();
32 }
33
Initialize()34 void GetDentsHelper::Initialize() {
35 if (init_defaults_) {
36 // Add the default entries: "." and ".."
37 AddDirent(curdir_ino_, ".", 1);
38 AddDirent(parentdir_ino_, "..", 2);
39 }
40 }
41
AddDirent(ino_t ino,const char * name,size_t namelen)42 void GetDentsHelper::AddDirent(ino_t ino, const char* name, size_t namelen) {
43 assert(name != NULL);
44 dirents_.push_back(dirent());
45 dirent& entry = dirents_.back();
46 entry.d_ino = ino;
47 entry.d_off = sizeof(dirent);
48 entry.d_reclen = sizeof(dirent);
49
50 if (namelen == 0)
51 namelen = strlen(name);
52
53 size_t d_name_max = MEMBER_SIZE(dirent, d_name) - 1; // -1 for \0.
54 size_t copylen = std::min(d_name_max, namelen);
55 strncpy(&entry.d_name[0], name, copylen);
56 entry.d_name[copylen] = 0;
57 }
58
GetDents(size_t offs,dirent * pdir,size_t size,int * out_bytes) const59 Error GetDentsHelper::GetDents(size_t offs,
60 dirent* pdir,
61 size_t size,
62 int* out_bytes) const {
63 *out_bytes = 0;
64
65 // If the buffer pointer is invalid, fail
66 if (NULL == pdir)
67 return EINVAL;
68
69 // If the buffer is too small, fail
70 if (size < sizeof(dirent))
71 return EINVAL;
72
73 // Force size to a multiple of dirent
74 size -= size % sizeof(dirent);
75
76 size_t max = dirents_.size() * sizeof(dirent);
77 if (offs >= max) {
78 // OK, trying to read past the end.
79 return 0;
80 }
81
82 if (offs + size >= max)
83 size = max - offs;
84
85 memcpy(pdir, reinterpret_cast<const char*>(dirents_.data()) + offs, size);
86 *out_bytes = size;
87 return 0;
88 }
89
90 } // namespace nacl_io
91