aboutsummaryrefslogtreecommitdiff
path: root/posix_extras.h
blob: 9dec22d50aa48796ccf4095420b13fcfabc9b5f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright 2016 Benjamin Barenblat
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations under
// the License.

#ifndef POSIX_EXTRAS_H_
#define POSIX_EXTRAS_H_

#include <cstdint>
#include <experimental/optional>
#include <string>
#include <vector>

#include <dirent.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <time.h>

namespace scoville {

class File;

// RAII wrapper for Unix directory streams.
class Directory {
 public:
  explicit Directory(const File&);
  virtual ~Directory() noexcept;

  long offset() const;

  void Seek(long) noexcept;

  std::experimental::optional<dirent> ReadOne();

 private:
  Directory(const Directory&) = delete;
  Directory(Directory&&) = delete;

  void operator=(const Directory&) = delete;
  void operator=(Directory&&) = delete;

  DIR* stream_;
};

// RAII wrapper for Unix file descriptors.
class File {
 public:
  File(const char* path, int flags) : File(path, flags, 0777) {}
  File(const char* path, int flags, mode_t mode);
  File(const File&);
  File(File&& other) = default;
  virtual ~File() noexcept;

  const std::string& path() const noexcept { return path_; }

  // Calls fstat(2) on the file descriptor.
  struct stat Stat() const;

  // Changes the file mode of the path relative to the file descriptor.  The
  // path must indeed be relative (i.e., it must not start with '/').
  void ChModAt(const char* path, mode_t) const;

  // Calls lstat(2) on the path relative to the file descriptor.  The path must
  // indeed be relative (i.e., it must not start with '/').
  struct stat LinkStatAt(const char* path) const;

  // Creates a directory at the path relative to the file descriptor.  The path
  // must indeed be relative (i.e., it must not start with '/').
  void MkDir(const char* path, mode_t mode) const;

  // Creates a file at the path relative to the file descriptor.  The path must
  // indeed be relative (i.e., it must not start with '/').
  void MkNod(const char* path, mode_t mode, dev_t dev) const;

  // Calls openat(2) on the path relative to the file descriptor.  The path must
  // indeed be relative (i.e., it must not start with '/').
  File OpenAt(const char* const path, const int flags) const {
    return OpenAt(path, flags, 0);
  }
  File OpenAt(const char* path, int flags, mode_t mode) const;

  // Reads exactly the specified number of bytes from the file at the given
  // offset, unless doing so would run past the end of the file, in which case
  // fewer bytes are returned.
  std::vector<std::uint8_t> Read(off_t, size_t) const;

  // Reads the contents of a symbolic link.  The path to the symbolic link is
  // interpreted relative to the file descriptor and must indeed be relative
  // (i.e., it must not start with '/').
  std::string ReadLinkAt(const char* path) const;

  // Renames a file from old_path to new_path.  Both paths are interpreted
  // relative to the file descriptor, and both must indeed be relative (i.e.,
  // they must not start with '/').
  void RenameAt(const char* old_path, const char* new_path) const;

  // Removes the directory at the path relative to the file descriptor.  The
  // path must indeed be relative (i.e., it must not start with '/').
  void RmDirAt(const char* path) const;

  // Retrieves information about the file system containing the referent of the
  // file descriptor.
  struct statvfs StatVFs() const;

  // Creates a symlink at source pointing to target.  target is unvalidated.
  // source is interpreted as a path relative to the file descriptor and must
  // indeed be relative (i.e., it must not start with '/').
  void SymLinkAt(const char* target, const char* source) const;

  // Truncates the file to the specified size.
  void Truncate(off_t);

  // Removes the file at the path relative to the file descriptor.  The path
  // must indeed be relative (i.e., it must not start with '/').
  void UnlinkAt(const char* path) const;

  // Sets the access and modification times of the file at the path relative to
  // the file descriptor.  The path must indeed be relative (i.e., it must not
  // start with '/').  Does not follow symbolic links.
  void UTimeNs(const char* path, const timespec& access,
               const timespec& modification) const;

  // Writes the specified byte vector to the file at the given offset.  Returns
  // the number of bytes written, which will always be the number of bytes given
  // as input.
  size_t Write(off_t, const std::vector<std::uint8_t>&);

 private:
  File() {}

  void operator=(const File&) = delete;
  void operator=(File&&) = delete;

  // Duplicates fd_ and returns the raw new file descriptor.
  int Duplicate() const;

  std::string path_;
  int fd_;

  friend Directory::Directory(const File&);
};

}  // scoville

#endif  // POSIX_EXTRAS_H_