in watchman/fs/FileSystem.cpp [148:263]
FileDescriptor openFileHandle(
const char* path,
const OpenFileHandleOptions& opts) {
#ifndef _WIN32
int flags = (!opts.followSymlinks ? O_NOFOLLOW : 0) |
(opts.closeOnExec ? O_CLOEXEC : 0) |
#ifdef O_PATH
(opts.metaDataOnly ? O_PATH : 0) |
#endif
((opts.readContents && opts.writeContents)
? O_RDWR
: (opts.writeContents ? O_WRONLY
: opts.readContents ? O_RDONLY
: 0)) |
(opts.create ? O_CREAT : 0) | (opts.exclusiveCreate ? O_EXCL : 0) |
(opts.truncate ? O_TRUNC : 0);
auto fd = open(path, flags);
if (fd == -1) {
int err = errno;
throw std::system_error(
err, std::generic_category(), folly::to<std::string>("open: ", path));
}
FileDescriptor file(fd, FileDescriptor::FDType::Unknown);
#else // _WIN32
DWORD access = 0, share = 0, create = 0, attrs = 0;
DWORD err;
auto sec = SECURITY_ATTRIBUTES();
if (!strcmp(path, "/dev/null")) {
path = "NUL:";
}
auto wpath = w_string_piece(path).asWideUNC();
if (opts.metaDataOnly) {
access = 0;
} else {
if (opts.writeContents) {
access |= GENERIC_WRITE;
}
if (opts.readContents) {
access |= GENERIC_READ;
}
}
// We want more posix-y behavior by default
share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
sec.nLength = sizeof(sec);
sec.bInheritHandle = TRUE;
if (opts.closeOnExec) {
sec.bInheritHandle = FALSE;
}
if (opts.create && opts.exclusiveCreate) {
create = CREATE_NEW;
} else if (opts.create && opts.truncate) {
create = CREATE_ALWAYS;
} else if (opts.create) {
create = OPEN_ALWAYS;
} else if (opts.truncate) {
create = TRUNCATE_EXISTING;
} else {
create = OPEN_EXISTING;
}
attrs = FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_BACKUP_SEMANTICS;
if (!opts.followSymlinks) {
attrs |= FILE_FLAG_OPEN_REPARSE_POINT;
}
FileDescriptor file(
intptr_t(CreateFileW(
wpath.c_str(), access, share, &sec, create, attrs, nullptr)),
FileDescriptor::FDType::Unknown);
err = GetLastError();
if (!file) {
throw std::system_error(
err,
std::system_category(),
std::string("CreateFileW for openFileHandle: ") + path);
}
#endif
if (!opts.strictNameChecks) {
return file;
}
auto opened = file.getOpenedPath();
if (w_string_piece(opened).pathIsEqual(path)) {
#if !CAN_OPEN_SYMLINKS
CaseSensitivity caseSensitive = opts.caseSensitive;
if (caseSensitive == CaseSensitivity::Unknown) {
caseSensitive = getCaseSensitivityForPath(path);
}
if (caseSensitive == CaseSensitivity::CaseInSensitive) {
// We need to perform one extra check for case-insensitive
// paths to make sure that we didn't accidentally open
// the wrong case name.
checkCanonicalBaseName(path);
}
#endif
return file;
}
throw std::system_error(
ENOENT,
std::generic_category(),
folly::to<std::string>(
"open(",
path,
"): opened path doesn't match canonical path ",
opened.view()));
}