adlr@google.com | 3defe6a | 2009-12-04 20:57:17 +0000 | [diff] [blame^] | 1 | // Copyright (c) 2009 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 | #ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_FILESYSTEM_ITERATOR_H__ |
| 6 | #define CHROMEOS_PLATFORM_UPDATE_ENGINE_FILESYSTEM_ITERATOR_H__ |
| 7 | |
| 8 | // This class is used to walk a filesystem. It will iterate over every file |
| 9 | // on the same device as the file passed in the ctor. Directories will be |
| 10 | // visited before their children. Children will be visited in no particular |
| 11 | // order. |
| 12 | |
| 13 | // The iterator is a forward iterator. It's not random access nor can it be |
| 14 | // decremented. |
| 15 | |
| 16 | // Note: If the iterator comes across a mount point where another filesystem |
| 17 | // is mounted, that mount point will be present, but none of its children |
| 18 | // will be. Technically the mount point is on the other filesystem (and |
| 19 | // the Stat() call will verify that), but we return it anyway since: |
| 20 | // 1. Such a folder must exist in the first filesystem if it got used |
| 21 | // as a mount point. |
| 22 | // 2. You probably want to copy if it you're using the iterator to do a |
| 23 | // filesystem copy |
| 24 | // 3. If you don't want that, you can just check Stat().st_dev and skip |
| 25 | // foreign filesystems manually. |
| 26 | |
| 27 | #include <sys/stat.h> |
| 28 | #include <sys/types.h> |
| 29 | #include <dirent.h> |
| 30 | #include <unistd.h> |
| 31 | #include <string> |
| 32 | #include <set> |
| 33 | #include <vector> |
| 34 | |
| 35 | namespace chromeos_update_engine { |
| 36 | |
| 37 | class FilesystemIterator { |
| 38 | public: |
| 39 | FilesystemIterator(const std::string& path, |
| 40 | const std::set<std::string>& excl_prefixes); |
| 41 | |
| 42 | ~FilesystemIterator(); |
| 43 | |
| 44 | // Returns stat struct for the current file. |
| 45 | struct stat GetStat() const { |
| 46 | return stbuf_; |
| 47 | } |
| 48 | |
| 49 | // Returns full path for current file. |
| 50 | std::string GetFullPath() const; |
| 51 | |
| 52 | // Returns the path that's part of the iterator. For example, if |
| 53 | // the object were constructed by passing in "/foo/bar" and Path() |
| 54 | // returns "/foo/bar/baz/bat.txt", IterPath would return |
| 55 | // "/baz/bat.txt". When this object is on root (ie, the very first |
| 56 | // path), IterPath will return "", otherwise the first character of |
| 57 | // IterPath will be "/". |
| 58 | std::string GetPartialPath() const; |
| 59 | |
| 60 | // Returns name for current file. |
| 61 | std::string GetBasename() const { |
| 62 | return names_.back(); |
| 63 | } |
| 64 | |
| 65 | // Increments to the next file. |
| 66 | void Increment(); |
| 67 | |
| 68 | // If we're at the end. If at the end, do not call Stat(), Path(), etc., |
| 69 | // since this iterator currently isn't pointing to any file at all. |
| 70 | bool IsEnd() const { |
| 71 | return is_end_; |
| 72 | } |
| 73 | |
| 74 | // Returns true if the iterator is in an error state. |
| 75 | bool IsErr() const { |
| 76 | return is_err_; |
| 77 | } |
| 78 | private: |
| 79 | // Helper for Increment. |
| 80 | void IncrementInternal(); |
| 81 | |
| 82 | // Returns true if path exists and it's a directory. |
| 83 | bool DirectoryExists(const std::string& path); |
| 84 | |
| 85 | // In general (i.e., not midway through a call to Increment()), there is a |
| 86 | // relationship between dirs_ and names_: dirs[i] == names_[i - 1]. |
| 87 | // For example, say we are asked to iterate "/usr/local" and we're currently |
| 88 | // at /usr/local/share/dict/words. dirs_ contains DIR* variables for the |
| 89 | // dirs at: {"/usr/local", ".../share", ".../dict"} and names_ contains: |
| 90 | // {"share", "dict", "words"}. root_path_ contains "/usr/local". |
| 91 | // root_dev_ would be the dev for root_path_ |
| 92 | // (and /usr/local/share/dict/words). stbuf_ would be the stbuf for |
| 93 | // /usr/local/share/dict/words. |
| 94 | |
| 95 | // All opened directories. If this is empty, we're currently on the root, |
| 96 | // but not descended into the root. |
| 97 | // This will always contain the current directory and all it's ancestors |
| 98 | // in root-to-leaf order. For more details, see comment above. |
| 99 | std::vector<DIR*> dirs_; |
| 100 | |
| 101 | // The list of all filenames for the current path that we've descended into. |
| 102 | std::vector<std::string> names_; |
| 103 | |
| 104 | // The device of the root path we've been asked to iterate. |
| 105 | dev_t root_dev_; |
| 106 | |
| 107 | // The root path we've been asked to iteratate. |
| 108 | std::string root_path_; |
| 109 | |
| 110 | // Exclude items w/ this prefix. |
| 111 | std::set<std::string> excl_prefixes_; |
| 112 | |
| 113 | // The struct stat of the current file we're at. |
| 114 | struct stat stbuf_; |
| 115 | |
| 116 | // Generally false; set to true when we reach the end of files to iterate |
| 117 | // or error occurs. |
| 118 | bool is_end_; |
| 119 | |
| 120 | // Generally false; set to true if an error occurrs. |
| 121 | bool is_err_; |
| 122 | }; |
| 123 | |
| 124 | } // namespace chromeos_update_engine |
| 125 | |
| 126 | #endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_FILESYSTEM_ITERATOR_H__ |