17 "preserve atime of inpout files",
false);
28 std::vector<char>& target) {
30 auto linklength = readlink(path.c_str(), target.data(), target.size());
31 if (linklength == -1 && errno == ENOENT) {
35 if (linklength >=
static_cast<ssize_t
>(target.size())) {
36 throw std::runtime_error(
"link size increased after stat for " + path);
38 target[linklength] =
'\0';
51 fd = open(
path.c_str(), O_RDONLY);
64 "can't advise ",
path,
" as sequential");
69 "can't advise ",
path,
" as use only once");
79 path,
"close during unwind ",
80 std::system_category().default_error_condition(errno).message());
85 struct timespec times[2];
86 readInitialStat.getAtime(times[0]);
87 times[1].tv_nsec = UTIME_OMIT;
89 throwcall::good0(futimens(fd, times),
"can't set time stamps on ", path,
" to old values");
104 if (readInitialStat.size < readInitialStat.blksize) {
107 if (sparseHandling ==
"auto" &&
108 readInitialStat.size <= readInitialStat.sizeOnDisk) {
110 }
else if (sparseHandling ==
"never") {
113 auto what = SEEK_HOLE;
114 for (std::remove_const<decltype(readInitialStat.size)>::type pos = 0;
115 pos < readInitialStat.size;
116 what = what == SEEK_HOLE ? SEEK_DATA : SEEK_HOLE) {
119 auto result = lseek(fd, pos, what);
120 if (result == -1 && errno == ENXIO) {
121 next = readInitialStat.size;
124 "seek ", path,
" for ", what == SEEK_HOLE ?
"hole" :
"data",
125 ", from offset ", pos);
129 regions.emplace_back(pos, next, what == SEEK_DATA);
135 return !regions.empty();
141 -1,
"can't seek ", path,
" to ", pos);
142 if (! regions.empty()) {
143 while (regions.front().getEnd() < pos) {
145 if (regions.empty()) {
152 return regions.empty();
155 b.
clear(totalBytesRead);
156 bool lastblock =
false;
159 if (!regions.empty()) {
160 auto region = regions.front();
161 if (region.isHole()) {
166 auto result = lseek(fd, totalBytesRead, SEEK_DATA);
167 if (result == -1 && errno == ENXIO) {
168 nextData = region.getEnd();
170 throwcall::badval(result, -1,
"seek in ", path,
" to data after ", totalBytesRead);
173 totalBytesRead += region.size();
174 if (nextData != totalBytesRead) {
176 std::to_string(totalBytesRead) +
178 std::to_string(nextData) +
182 return regions.empty();
184 if (region.getEnd() < totalBytesRead + bytesToRead) {
185 bytesToRead = region.getEnd() - totalBytesRead;
187 if (region.getEnd() == totalBytesRead + bytesToRead) {
193 while (b.
size() + blockSize <= bytesToRead) {
197 -1,
"read failed on ", path);
199 if (bytes_read == 0) {
201 if (totalBytesRead < readInitialStat.size) {
203 std::to_string(readInitialStat.size) +
205 std::to_string(totalBytesRead) +
210 totalBytesRead += bytes_read;
211 if (totalBytesRead > readInitialStat.size) {
213 std::to_string(readInitialStat.size) +
215 std::to_string(totalBytesRead) +
227 if (!regions.empty()) {
228 throw std::logic_error(
"parallel read attempted on sparse file");
234 -1,
"read failed on ", path);
235 if (bytes_read == 0) {
239 if (b.
size() > bytesToRead) {
243 if (b.
size() < bytesToRead) {
245 + std::to_string(bytesToRead)
247 + std::to_string(b.
size()));
253 struct stat readFinalStatBuf;
256 throwcall::good0(fstat(fd, &readFinalStatBuf),
"can't stat path file ", path);
258 genericStat readFinalStat(readFinalStatBuf, std::chrono::nanoseconds(1));
259 if (readFinalStat.
size != readInitialStat.size) {
261 std::to_string(readInitialStat.size) +
263 std::to_string(readFinalStat.
size) +
264 ") during reading on " + path);
269 std::to_string(std::chrono::duration_cast<std::chrono::duration<double>>(readFinalStat.
getMtime() - readInitialStat.getMtime()).count()) +
270 "s different mtime) during reading");
279 if (closedir(dir) != 0) {
281 "",
"close directory during unwind ",
282 std::system_category().default_error_condition(errno).message());
292 while (
auto entry = readdir(dir)) {
294 if (entry->d_name[entry->d_name[0] !=
'.' ? 0 : entry->d_name[1] !=
'.' ? 1 : 2] ==
'\0') {
301 auto result = fstatat(dirfd(dir), entry->d_name, &statbuf, AT_SYMLINK_NOFOLLOW);
302 if (result != 0 && errno == ENOENT && ignoreMissing) {
307 auto genStat = std::unique_ptr<const genericStat>(
new genericStat(statbuf, std::chrono::nanoseconds(1)));
308 return std::unique_ptr<Entry>(
new Entry(entry->d_name, genStat));