1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be
3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file.
4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#ifndef BASE_FILES_DIR_READER_LINUX_H_
6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#define BASE_FILES_DIR_READER_LINUX_H_
7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <errno.h>
9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <fcntl.h>
10cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <stddef.h>
11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <stdint.h>
12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <sys/syscall.h>
13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <unistd.h>
14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/logging.h"
16cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "base/macros.h"
17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/posix/eintr_wrapper.h"
18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// See the comments in dir_reader_posix.h about this.
20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base {
22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstruct linux_dirent {
24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  uint64_t        d_ino;
25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int64_t         d_off;
26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  unsigned short  d_reclen;
27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  unsigned char   d_type;
28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  char            d_name[0];
29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat};
30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass DirReaderLinux {
32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public:
33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  explicit DirReaderLinux(const char* directory_path)
34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)),
35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        offset_(0),
36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        size_(0) {
37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    memset(buf_, 0, sizeof(buf_));
38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  ~DirReaderLinux() {
41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (fd_ >= 0) {
42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (IGNORE_EINTR(close(fd_)))
43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        RAW_LOG(ERROR, "Failed to close directory handle");
44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool IsValid() const {
48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return fd_ >= 0;
49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Move to the next entry returning false if the iteration is complete.
52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool Next() {
53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (size_) {
54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      linux_dirent* dirent = reinterpret_cast<linux_dirent*>(&buf_[offset_]);
55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      offset_ += dirent->d_reclen;
56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (offset_ != size_)
59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      return true;
60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_));
62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (r == 0)
63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      return false;
64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (r == -1) {
65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      DPLOG(FATAL) << "getdents64 returned an error: " << errno;
66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      return false;
67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    size_ = r;
69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    offset_ = 0;
70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return true;
71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const char* name() const {
74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (!size_)
75cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko      return nullptr;
76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const linux_dirent* dirent =
78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return dirent->d_name;
80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int fd() const {
83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return fd_;
84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static bool IsFallback() {
87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return false;
88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private:
91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const int fd_;
92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  unsigned char buf_[512];
93cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  size_t offset_;
94cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko  size_t size_;
95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat};
98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace base
100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif  // BASE_FILES_DIR_READER_LINUX_H_
102