diff --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h --- a/flang/include/flang/Runtime/iostat.h +++ b/flang/include/flang/Runtime/iostat.h @@ -75,6 +75,8 @@ IostatBOZInputOverflow, IostatIntegerInputOverflow, IostatRealInputOverflow, + IostatOpenAlreadyConnected, + IostatCannotReposition, }; const char *IostatErrorString(int); diff --git a/flang/runtime/file.h b/flang/runtime/file.h --- a/flang/runtime/file.h +++ b/flang/runtime/file.h @@ -28,8 +28,8 @@ using FileOffset = std::int64_t; const char *path() const { return path_.get(); } - void set_path(OwningPtr &&, std::size_t bytes); std::size_t pathLength() const { return pathLength_; } + void set_path(OwningPtr &&, std::size_t bytes); bool mayRead() const { return mayRead_; } bool mayWrite() const { return mayWrite_; } bool mayPosition() const { return mayPosition_; } diff --git a/flang/runtime/file.cpp b/flang/runtime/file.cpp --- a/flang/runtime/file.cpp +++ b/flang/runtime/file.cpp @@ -377,7 +377,7 @@ SetPosition(at); return true; } else { - handler.SignalErrno(); + handler.SignalError(IostatCannotReposition); return false; } } diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -431,7 +431,9 @@ Terminator oom{sourceFile, sourceLine}; auto trimmed{ SaveDefaultCharacter(path, TrimTrailingSpaces(path, pathLength), oom)}; - if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(trimmed.get())}) { + if (ExternalFileUnit * + unit{ExternalFileUnit::LookUp( + trimmed.get(), std::strlen(trimmed.get()))}) { // INQUIRE(FILE=) to a connected unit return &unit->BeginIoStatement( *unit, sourceFile, sourceLine); diff --git a/flang/runtime/iostat.cpp b/flang/runtime/iostat.cpp --- a/flang/runtime/iostat.cpp +++ b/flang/runtime/iostat.cpp @@ -94,6 +94,11 @@ return "Integer input value overflows variable"; case IostatRealInputOverflow: return "Real or complex input value overflows type"; + case IostatCannotReposition: + return "Attempt to reposition a unit which is connected to a file that can " + "only be processed sequentially"; + case IostatOpenAlreadyConnected: + return "OPEN of file already connected to another unit"; default: return nullptr; } diff --git a/flang/runtime/unit-map.h b/flang/runtime/unit-map.h --- a/flang/runtime/unit-map.h +++ b/flang/runtime/unit-map.h @@ -37,9 +37,9 @@ } // Unit look-up by name is needed for INQUIRE(FILE="...") - ExternalFileUnit *LookUp(const char *path) { + ExternalFileUnit *LookUp(const char *path, std::size_t pathLen) { CriticalSection critical{lock_}; - return Find(path); + return Find(path, pathLen); } ExternalFileUnit &NewUnit(const Terminator &); @@ -84,7 +84,7 @@ } return nullptr; } - ExternalFileUnit *Find(const char *path); + ExternalFileUnit *Find(const char *path, std::size_t pathLen); ExternalFileUnit &Create(int, const Terminator &); diff --git a/flang/runtime/unit-map.cpp b/flang/runtime/unit-map.cpp --- a/flang/runtime/unit-map.cpp +++ b/flang/runtime/unit-map.cpp @@ -111,12 +111,13 @@ } } -ExternalFileUnit *UnitMap::Find(const char *path) { +ExternalFileUnit *UnitMap::Find(const char *path, std::size_t pathLen) { if (path) { // TODO: Faster data structure for (int j{0}; j < buckets_; ++j) { for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) { - if (p->unit.path() && std::strcmp(p->unit.path(), path) == 0) { + if (p->unit.path() && p->unit.pathLength() == pathLen && + std::memcmp(p->unit.path(), path, pathLen) == 0) { return &p->unit; } } diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -50,7 +50,7 @@ int unit, const Terminator &, bool &wasExtant); static ExternalFileUnit &LookUpOrCreateAnonymous(int unit, Direction, std::optional isUnformatted, const Terminator &); - static ExternalFileUnit *LookUp(const char *path); + static ExternalFileUnit *LookUp(const char *path, std::size_t pathLen); static ExternalFileUnit &CreateNew(int unit, const Terminator &); static ExternalFileUnit *LookUpForClose(int unit); static ExternalFileUnit &NewUnit(const Terminator &, bool forChildIo); diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -73,8 +73,9 @@ return result; } -ExternalFileUnit *ExternalFileUnit::LookUp(const char *path) { - return GetUnitMap().LookUp(path); +ExternalFileUnit *ExternalFileUnit::LookUp( + const char *path, std::size_t pathLen) { + return GetUnitMap().LookUp(path, pathLen); } ExternalFileUnit &ExternalFileUnit::CreateNew( @@ -124,6 +125,16 @@ FlushOutput(handler); Close(CloseStatus::Keep, handler); } + if (newPath.get() && newPathLength > 0) { + if (const auto *already{ + GetUnitMap().LookUp(newPath.get(), newPathLength)}) { + handler.SignalError(IostatOpenAlreadyConnected, + "OPEN(UNIT=%d,FILE='%.*s'): file is already connected to unit %d", + unitNumber_, static_cast(newPathLength), newPath.get(), + already->unitNumber_); + return; + } + } set_path(std::move(newPath), newPathLength); Open(status.value_or(OpenStatus::Unknown), action, position, handler); auto totalBytes{knownSize()};