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