12 #include <sys/types.h>
13 #include <sys/statvfs.h>
26 std::unique_ptr<ioHandle::attrDataType> attrData,
27 std::unique_ptr<acl::list> aclData) {
28 return std::unique_ptr<base::writer>(
new writerDaosFs(path, mightAppend,
29 sourceSize, readBlockSize,
39 std::unique_ptr<ioHandle::attrDataType> attrData,
40 std::unique_ptr<acl::list> aclData) {
41 return std::unique_ptr<base::writer>(
new writerDaosFs(path,
50 "duration after which file operations are considered slow",
51 std::chrono::milliseconds(10));
54 const std::string& srcPath,
56 std::vector<std::remove_reference<decltype(path)>::type::value_type> disposable_buffer(path.c_str(), path.c_str() + path.size() + 1);
57 std::string dir(dirname(disposable_buffer.data()));
60 if (stat(dir.c_str(), &statbuf)) {
61 if (errno == ENOENT || errno == ENOTDIR) {
65 auto result = mkdir(dir.c_str(), 0777u);
68 if (result != 0 && errno == EEXIST) {
74 if (
gid != -1 ||
uid != -1) {
79 }
else if (! S_ISDIR(statbuf.st_mode)) {
81 dir,
"ensure parents",
82 "is not a directory (st_mode is ", statbuf.st_mode,
") but should be");
85 struct statvfs fsstat;
99 auto retval = lstat(path.c_str(), &dsttat);
101 if (retval && errno == ENOENT) {
106 if (S_ISDIR(dsttat.st_mode)) {
108 auto retval = rmdir(path.c_str());
117 path,
"remove",
"directory not empty but should be removed");
128 auto retval = unlink(path.c_str());
130 if (retval && errno == ENOENT) {
140 const std::string& toPath) {
142 auto retval = std::rename(fromPath.c_str(), toPath.c_str());
143 if (retval && (errno == ENOENT || errno == ENOTDIR)) {
146 throwcall::good0(retval,
"can't rename '", fromPath,
"' to '", toPath,
"'");
152 const std::unique_ptr<const genericStat>& readInitialStat,
153 const std::string& toPath,
155 struct stat fromPathStatBuf;
158 auto statRetVal = stat(fromPath.c_str(), &fromPathStatBuf);
160 if (statRetVal && (errno == ENOENT || errno == ENOTDIR)) {
161 if (readInitialStat && readInitialStat->
isDir()) {
167 }
else if (statRetVal) {
171 genericStat fromPathStat(fromPathStatBuf, std::chrono::nanoseconds(1));
172 if (!readInitialStat || (! readInitialStat->
isDir() &&
173 (fromPathStat.
size != readInitialStat->
size
176 if (readInitialStat) {
177 std::string initialTime;
178 std::string finalTime;
179 readInitialStat->
getMtime(initialTime);
183 "file (", toPath,
") changed unexpectedly ("
184 , initialTime,
" -> ", finalTime,
", "
185 , readInitialStat->
size,
" -> ", fromPathStat.
size
186 ,
", doing fresh copy");
190 "file (", toPath,
") has no initial stat, doing fresh copy");
195 auto retval = std::rename(fromPath.c_str(), toPath.c_str());
197 if (retval && (errno == ENOENT || errno == ENOTDIR)) {
198 if (readInitialStat->
isDir()) {
204 "vanished unexpectedly, doing fresh copy");
208 throwcall::good0(retval,
"can't rename '", fromPath,
"' to '", toPath,
"'");
216 const std::string& path,
219 auto retval = symlink(target.data(), path.c_str());
220 if (retval != 0 && errno != EEXIST) {
223 if (
static_cast<std::make_signed<decltype(
gid)
>::type>(
gid) != -1
224 ||
static_cast<std::make_signed<decltype(
uid)
>::type>(
uid) != -1) {
232 size_t readBlockSize,
235 std::unique_ptr<ioHandle::attrDataType> aAttrData,
236 std::unique_ptr<acl::list> aAclData,
239 attrData(std::move(aAttrData)),
240 aclData(std::move(aAclData)) {
241 bool haveWriteStat =
false;
246 auto openMode = O_CREAT | O_TRUNC | O_WRONLY;
250 -1,
"can't open ",
path,
" for writing");
251 if (!haveWriteStat) {
256 "can't advise ",
path,
" as sequential");
258 "can't advise ",
path,
" as use only once");
263 std::unique_ptr<ioHandle::attrDataType> aAttrData,
264 std::unique_ptr<acl::list> aAclData,
267 attrData(std::move(aAttrData)),
268 aclData(std::move(aAclData)) {
273 static const std::string pattern(
"XXXXXX.tmp");
274 std::vector<char> tmpName;
275 tmpName.reserve(
path.size() + pattern.size() + 1);
276 tmpName.insert(tmpName.end(),
path.cbegin(),
path.cend());
278 tmpName.insert(tmpName.end(), pattern.cbegin(), pattern.cend());
279 tmpName.push_back(
'\0');
282 -1,
"can't open ", tmpName.data(),
" for writing");
283 aPath.replace(0,
path.size(), tmpName.data(), tmpName.size());
287 "can't advise ",
path,
" as sequential");
289 "can't advise ",
path,
" as use only once");
293 if (close(fd) != 0) {
295 path,
"close during unwind ",
296 std::system_category().default_error_condition(errno).message());
299 path,
"unlink failed copy",
"due to exception");
300 auto retval = unlink(path.c_str());
301 if (retval && errno != ENOENT) {
303 path,
"can't remove bad copy ",
304 std::system_category().default_error_condition(errno).message());
311 closeAndRemoveBadCopy();
317 }
catch (
const std::exception& e) {
319 path,
"set attr at close ",
321 closeAndRemoveBadCopy();
334 -1,
"can't seek ", path,
" to ", position);
337 return writeInitialStat.st_size == 0;
340 return writeInitialStat.st_size;
347 auto currentPosition =
throwcall::badval(lseek(fd, 0, SEEK_CUR), -1,
"lseek to determine position on", path);
349 auto holeEnd = currentPosition + b.
size();
353 "fruncate ", path,
" to ", holeEnd);
357 "can't seek to hole end (", holeEnd,
") in ", path);
361 size_t bytes_writen_so_far = 0;
363 while (bytes_writen_so_far < b.
size()) {
364 auto count = b.
size() - bytes_writen_so_far;
366 if (count > blockSize) {
372 -1,
"write failed on ", path);
374 bytes_writen_so_far += bytes_writen;
380 size_t bytes_writen_so_far = 0;
382 while (bytes_writen_so_far < b.
size()) {
383 auto count = b.
size() - bytes_writen_so_far;
385 if (count > blockSize) {
390 -1,
"write failed on ", path);
391 bytes_writen_so_far += bytes_writen;
397 struct timespec times[2];
408 auto oldmask = umask(0);
414 if (
gid != -1 ||
uid != -1) {
420 "can't set owner/group (", readInitialStat.
ownerUid,
",", readInitialStat.
ownerGid,
") of ",
428 struct timespec times[2];
429 times[0].tv_nsec = UTIME_OMIT;
432 throwcall::good0(utimensat(0, path.c_str(), times, 0),
"can't set mtime on ", path);
438 auto oldmask = umask(0);
444 if (
gid != -1 ||
uid != -1) {
458 return throwcall::badval(pathconf(dirPath.c_str(), _PC_NAME_MAX), -1,
"can't get max name lenght on", dirPath);