[flang] Support windows where mkstemp and ftruncate doesn't exist

Original-commit: flang-compiler/f18@7b7e30845d
Reviewed-on: https://github.com/flang-compiler/f18/pull/1069
This commit is contained in:
Isuru Fernando 2020-03-12 15:48:00 -05:00
parent 8004fd500f
commit ddb68d248c
1 changed files with 44 additions and 9 deletions

View File

@ -13,7 +13,12 @@
#include <cstring>
#include <fcntl.h>
#include <stdlib.h>
#ifdef _WIN32
#include <io.h>
#include <windows.h>
#else
#include <unistd.h>
#endif
namespace Fortran::runtime::io {
@ -22,6 +27,35 @@ void OpenFile::set_path(OwningPtr<char> &&path, std::size_t bytes) {
pathLength_ = bytes;
}
static int openfile_mkstemp(IoErrorHandler &handler) {
#ifdef _WIN32
const unsigned int uUnique{0};
// GetTempFileNameA needs a directory name < MAX_PATH-14 characters in length.
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea
char tempDirName[MAX_PATH - 14];
char tempFileName[MAX_PATH];
unsigned long nBufferLength{sizeof(tempDirName)};
nBufferLength = ::GetTempPathA(nBufferLength, tempDirName);
if (nBufferLength > sizeof(tempDirName) || nBufferLength == 0) {
return -1;
}
if (::GetTempFileNameA(tempDirName, "Fortran", uUnique, tempFileName) == 0) {
return -1;
}
int fd{::_open(tempFileName, _O_CREAT | _O_TEMPORARY, _S_IREAD | _S_IWRITE)};
#else
char path[]{"/tmp/Fortran-Scratch-XXXXXX"};
int fd{::mkstemp(path)};
#endif
if (fd < 0) {
handler.SignalErrno();
}
#ifndef _WIN32
::unlink(path);
#endif
return fd;
}
void OpenFile::Open(
OpenStatus status, Position position, IoErrorHandler &handler) {
int flags{mayRead_ ? mayWrite_ ? O_RDWR : O_RDONLY : O_WRONLY};
@ -37,14 +71,7 @@ void OpenFile::Open(
handler.SignalError("FILE= must not appear with STATUS='SCRATCH'");
path_.reset();
}
{
char path[]{"/tmp/Fortran-Scratch-XXXXXX"};
fd_ = ::mkstemp(path);
if (fd_ < 0) {
handler.SignalErrno();
}
::unlink(path);
}
fd_ = openfile_mkstemp(handler);
return;
case OpenStatus::Replace: flags |= O_CREAT | O_TRUNC; break;
case OpenStatus::Unknown:
@ -173,10 +200,18 @@ std::size_t OpenFile::Write(FileOffset at, const char *buffer,
return put;
}
inline static int openfile_ftruncate(int fd, OpenFile::FileOffset at) {
#ifdef _WIN32
return !::_chsize(fd, at);
#else
return ::ftruncate(fd, at);
#endif
}
void OpenFile::Truncate(FileOffset at, IoErrorHandler &handler) {
CheckOpen(handler);
if (!knownSize_ || *knownSize_ != at) {
if (::ftruncate(fd_, at) != 0) {
if (openfile_ftruncate(fd_, at) != 0) {
handler.SignalErrno();
}
knownSize_ = at;