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