From b16e82f866f7d6b996eeebcfec4948e963d90252 Mon Sep 17 00:00:00 2001 From: David Brown Date: Wed, 30 Nov 2016 18:13:32 +0000 Subject: [PATCH] Update open FileDescs at deregistration resulting from delete, rename or register. --- bootstrap/unix-44/Files.c | 32 +++++++++++++++++++++- bootstrap/unix-48/Files.c | 32 +++++++++++++++++++++- bootstrap/unix-88/Files.c | 32 +++++++++++++++++++++- bootstrap/windows-48/Files.c | 32 +++++++++++++++++++++- bootstrap/windows-88/Files.c | 32 +++++++++++++++++++++- src/runtime/Files.Mod | 52 ++++++++++++++++++++++++++++++++---- 6 files changed, 202 insertions(+), 10 deletions(-) diff --git a/bootstrap/unix-44/Files.c b/bootstrap/unix-44/Files.c index 3b5fd2eb..763569cc 100644 --- a/bootstrap/unix-44/Files.c +++ b/bootstrap/unix-44/Files.c @@ -68,6 +68,7 @@ export void Files_Close (Files_File f); static void Files_CloseOSFile (Files_File f); static void Files_Create (Files_File f); export void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res); +static void Files_Deregister (CHAR *name, ADDRESS name__len); static void Files_Err (CHAR *s, ADDRESS s__len, Files_File f, INT16 errcode); static void Files_Finalize (SYSTEM_PTR o); static void Files_FlipBytes (SYSTEM_BYTE *src, ADDRESS src__len, SYSTEM_BYTE *dest, ADDRESS dest__len); @@ -222,9 +223,35 @@ static void Files_GetTempName (CHAR *finalName, ADDRESS finalName__len, CHAR *na __DEL(finalName); } -static void Files_Create (Files_File f) +static void Files_Deregister (CHAR *name, ADDRESS name__len) { Platform_FileIdentity identity; + Files_File osfile = NIL; + INT16 error; + __DUP(name, name__len, CHAR); + if (Platform_IdentifyByName(name, name__len, &identity, Platform_FileIdentity__typ) == 0) { + osfile = (Files_File)Files_files; + while ((osfile != NIL && !Platform_SameFile(osfile->identity, identity))) { + osfile = (Files_File)osfile->next; + } + if (osfile != NIL) { + __ASSERT(!osfile->tempFile, 0); + __ASSERT(osfile->fd >= 0, 0); + __COPY(osfile->workName, osfile->registerName, 101); + Files_GetTempName(osfile->registerName, 101, (void*)osfile->workName, 101); + osfile->tempFile = 1; + osfile->state = 0; + error = Platform_Rename((void*)osfile->registerName, 101, (void*)osfile->workName, 101); + if (error != 0) { + Files_Err((CHAR*)"Couldn't rename previous version of file being registered", 58, osfile, error); + } + } + } + __DEL(name); +} + +static void Files_Create (Files_File f) +{ BOOLEAN done; INT16 error; CHAR err[32]; @@ -234,6 +261,7 @@ static void Files_Create (Files_File f) f->tempFile = 1; } else { __ASSERT(f->state == 2, 0); + Files_Deregister(f->registerName, 101); __COPY(f->registerName, f->workName, 101); f->registerName[0] = 0x00; f->tempFile = 0; @@ -714,6 +742,7 @@ void Files_WriteBytes (Files_Rider *r, ADDRESS *r__typ, SYSTEM_BYTE *x, ADDRESS void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res) { __DUP(name, name__len, CHAR); + Files_Deregister(name, name__len); *res = Platform_Unlink((void*)name, name__len); __DEL(name); } @@ -789,6 +818,7 @@ void Files_Register (Files_File f) } Files_Close(f); if (f->registerName[0] != 0x00) { + Files_Deregister(f->registerName, 101); Files_Rename(f->workName, 101, f->registerName, 101, &errcode); if (errcode != 0) { Files_Err((CHAR*)"Couldn't rename temp name as register name", 43, f, errcode); diff --git a/bootstrap/unix-48/Files.c b/bootstrap/unix-48/Files.c index 3b5fd2eb..763569cc 100644 --- a/bootstrap/unix-48/Files.c +++ b/bootstrap/unix-48/Files.c @@ -68,6 +68,7 @@ export void Files_Close (Files_File f); static void Files_CloseOSFile (Files_File f); static void Files_Create (Files_File f); export void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res); +static void Files_Deregister (CHAR *name, ADDRESS name__len); static void Files_Err (CHAR *s, ADDRESS s__len, Files_File f, INT16 errcode); static void Files_Finalize (SYSTEM_PTR o); static void Files_FlipBytes (SYSTEM_BYTE *src, ADDRESS src__len, SYSTEM_BYTE *dest, ADDRESS dest__len); @@ -222,9 +223,35 @@ static void Files_GetTempName (CHAR *finalName, ADDRESS finalName__len, CHAR *na __DEL(finalName); } -static void Files_Create (Files_File f) +static void Files_Deregister (CHAR *name, ADDRESS name__len) { Platform_FileIdentity identity; + Files_File osfile = NIL; + INT16 error; + __DUP(name, name__len, CHAR); + if (Platform_IdentifyByName(name, name__len, &identity, Platform_FileIdentity__typ) == 0) { + osfile = (Files_File)Files_files; + while ((osfile != NIL && !Platform_SameFile(osfile->identity, identity))) { + osfile = (Files_File)osfile->next; + } + if (osfile != NIL) { + __ASSERT(!osfile->tempFile, 0); + __ASSERT(osfile->fd >= 0, 0); + __COPY(osfile->workName, osfile->registerName, 101); + Files_GetTempName(osfile->registerName, 101, (void*)osfile->workName, 101); + osfile->tempFile = 1; + osfile->state = 0; + error = Platform_Rename((void*)osfile->registerName, 101, (void*)osfile->workName, 101); + if (error != 0) { + Files_Err((CHAR*)"Couldn't rename previous version of file being registered", 58, osfile, error); + } + } + } + __DEL(name); +} + +static void Files_Create (Files_File f) +{ BOOLEAN done; INT16 error; CHAR err[32]; @@ -234,6 +261,7 @@ static void Files_Create (Files_File f) f->tempFile = 1; } else { __ASSERT(f->state == 2, 0); + Files_Deregister(f->registerName, 101); __COPY(f->registerName, f->workName, 101); f->registerName[0] = 0x00; f->tempFile = 0; @@ -714,6 +742,7 @@ void Files_WriteBytes (Files_Rider *r, ADDRESS *r__typ, SYSTEM_BYTE *x, ADDRESS void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res) { __DUP(name, name__len, CHAR); + Files_Deregister(name, name__len); *res = Platform_Unlink((void*)name, name__len); __DEL(name); } @@ -789,6 +818,7 @@ void Files_Register (Files_File f) } Files_Close(f); if (f->registerName[0] != 0x00) { + Files_Deregister(f->registerName, 101); Files_Rename(f->workName, 101, f->registerName, 101, &errcode); if (errcode != 0) { Files_Err((CHAR*)"Couldn't rename temp name as register name", 43, f, errcode); diff --git a/bootstrap/unix-88/Files.c b/bootstrap/unix-88/Files.c index 74c2d809..e2cf2f3a 100644 --- a/bootstrap/unix-88/Files.c +++ b/bootstrap/unix-88/Files.c @@ -68,6 +68,7 @@ export void Files_Close (Files_File f); static void Files_CloseOSFile (Files_File f); static void Files_Create (Files_File f); export void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res); +static void Files_Deregister (CHAR *name, ADDRESS name__len); static void Files_Err (CHAR *s, ADDRESS s__len, Files_File f, INT16 errcode); static void Files_Finalize (SYSTEM_PTR o); static void Files_FlipBytes (SYSTEM_BYTE *src, ADDRESS src__len, SYSTEM_BYTE *dest, ADDRESS dest__len); @@ -222,9 +223,35 @@ static void Files_GetTempName (CHAR *finalName, ADDRESS finalName__len, CHAR *na __DEL(finalName); } -static void Files_Create (Files_File f) +static void Files_Deregister (CHAR *name, ADDRESS name__len) { Platform_FileIdentity identity; + Files_File osfile = NIL; + INT16 error; + __DUP(name, name__len, CHAR); + if (Platform_IdentifyByName(name, name__len, &identity, Platform_FileIdentity__typ) == 0) { + osfile = (Files_File)Files_files; + while ((osfile != NIL && !Platform_SameFile(osfile->identity, identity))) { + osfile = (Files_File)osfile->next; + } + if (osfile != NIL) { + __ASSERT(!osfile->tempFile, 0); + __ASSERT(osfile->fd >= 0, 0); + __COPY(osfile->workName, osfile->registerName, 101); + Files_GetTempName(osfile->registerName, 101, (void*)osfile->workName, 101); + osfile->tempFile = 1; + osfile->state = 0; + error = Platform_Rename((void*)osfile->registerName, 101, (void*)osfile->workName, 101); + if (error != 0) { + Files_Err((CHAR*)"Couldn't rename previous version of file being registered", 58, osfile, error); + } + } + } + __DEL(name); +} + +static void Files_Create (Files_File f) +{ BOOLEAN done; INT16 error; CHAR err[32]; @@ -234,6 +261,7 @@ static void Files_Create (Files_File f) f->tempFile = 1; } else { __ASSERT(f->state == 2, 0); + Files_Deregister(f->registerName, 101); __COPY(f->registerName, f->workName, 101); f->registerName[0] = 0x00; f->tempFile = 0; @@ -714,6 +742,7 @@ void Files_WriteBytes (Files_Rider *r, ADDRESS *r__typ, SYSTEM_BYTE *x, ADDRESS void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res) { __DUP(name, name__len, CHAR); + Files_Deregister(name, name__len); *res = Platform_Unlink((void*)name, name__len); __DEL(name); } @@ -789,6 +818,7 @@ void Files_Register (Files_File f) } Files_Close(f); if (f->registerName[0] != 0x00) { + Files_Deregister(f->registerName, 101); Files_Rename(f->workName, 101, f->registerName, 101, &errcode); if (errcode != 0) { Files_Err((CHAR*)"Couldn't rename temp name as register name", 43, f, errcode); diff --git a/bootstrap/windows-48/Files.c b/bootstrap/windows-48/Files.c index 07f758d2..aa879424 100644 --- a/bootstrap/windows-48/Files.c +++ b/bootstrap/windows-48/Files.c @@ -68,6 +68,7 @@ export void Files_Close (Files_File f); static void Files_CloseOSFile (Files_File f); static void Files_Create (Files_File f); export void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res); +static void Files_Deregister (CHAR *name, ADDRESS name__len); static void Files_Err (CHAR *s, ADDRESS s__len, Files_File f, INT16 errcode); static void Files_Finalize (SYSTEM_PTR o); static void Files_FlipBytes (SYSTEM_BYTE *src, ADDRESS src__len, SYSTEM_BYTE *dest, ADDRESS dest__len); @@ -222,9 +223,35 @@ static void Files_GetTempName (CHAR *finalName, ADDRESS finalName__len, CHAR *na __DEL(finalName); } -static void Files_Create (Files_File f) +static void Files_Deregister (CHAR *name, ADDRESS name__len) { Platform_FileIdentity identity; + Files_File osfile = NIL; + INT16 error; + __DUP(name, name__len, CHAR); + if (Platform_IdentifyByName(name, name__len, &identity, Platform_FileIdentity__typ) == 0) { + osfile = (Files_File)Files_files; + while ((osfile != NIL && !Platform_SameFile(osfile->identity, identity))) { + osfile = (Files_File)osfile->next; + } + if (osfile != NIL) { + __ASSERT(!osfile->tempFile, 0); + __ASSERT(osfile->fd >= 0, 0); + __COPY(osfile->workName, osfile->registerName, 101); + Files_GetTempName(osfile->registerName, 101, (void*)osfile->workName, 101); + osfile->tempFile = 1; + osfile->state = 0; + error = Platform_Rename((void*)osfile->registerName, 101, (void*)osfile->workName, 101); + if (error != 0) { + Files_Err((CHAR*)"Couldn't rename previous version of file being registered", 58, osfile, error); + } + } + } + __DEL(name); +} + +static void Files_Create (Files_File f) +{ BOOLEAN done; INT16 error; CHAR err[32]; @@ -234,6 +261,7 @@ static void Files_Create (Files_File f) f->tempFile = 1; } else { __ASSERT(f->state == 2, 0); + Files_Deregister(f->registerName, 101); __COPY(f->registerName, f->workName, 101); f->registerName[0] = 0x00; f->tempFile = 0; @@ -714,6 +742,7 @@ void Files_WriteBytes (Files_Rider *r, ADDRESS *r__typ, SYSTEM_BYTE *x, ADDRESS void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res) { __DUP(name, name__len, CHAR); + Files_Deregister(name, name__len); *res = Platform_Unlink((void*)name, name__len); __DEL(name); } @@ -789,6 +818,7 @@ void Files_Register (Files_File f) } Files_Close(f); if (f->registerName[0] != 0x00) { + Files_Deregister(f->registerName, 101); Files_Rename(f->workName, 101, f->registerName, 101, &errcode); if (errcode != 0) { Files_Err((CHAR*)"Couldn't rename temp name as register name", 43, f, errcode); diff --git a/bootstrap/windows-88/Files.c b/bootstrap/windows-88/Files.c index 1db4ed49..f83fafeb 100644 --- a/bootstrap/windows-88/Files.c +++ b/bootstrap/windows-88/Files.c @@ -69,6 +69,7 @@ export void Files_Close (Files_File f); static void Files_CloseOSFile (Files_File f); static void Files_Create (Files_File f); export void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res); +static void Files_Deregister (CHAR *name, ADDRESS name__len); static void Files_Err (CHAR *s, ADDRESS s__len, Files_File f, INT16 errcode); static void Files_Finalize (SYSTEM_PTR o); static void Files_FlipBytes (SYSTEM_BYTE *src, ADDRESS src__len, SYSTEM_BYTE *dest, ADDRESS dest__len); @@ -223,9 +224,35 @@ static void Files_GetTempName (CHAR *finalName, ADDRESS finalName__len, CHAR *na __DEL(finalName); } -static void Files_Create (Files_File f) +static void Files_Deregister (CHAR *name, ADDRESS name__len) { Platform_FileIdentity identity; + Files_File osfile = NIL; + INT16 error; + __DUP(name, name__len, CHAR); + if (Platform_IdentifyByName(name, name__len, &identity, Platform_FileIdentity__typ) == 0) { + osfile = (Files_File)Files_files; + while ((osfile != NIL && !Platform_SameFile(osfile->identity, identity))) { + osfile = (Files_File)osfile->next; + } + if (osfile != NIL) { + __ASSERT(!osfile->tempFile, 0); + __ASSERT(osfile->fd >= 0, 0); + __COPY(osfile->workName, osfile->registerName, 101); + Files_GetTempName(osfile->registerName, 101, (void*)osfile->workName, 101); + osfile->tempFile = 1; + osfile->state = 0; + error = Platform_Rename((void*)osfile->registerName, 101, (void*)osfile->workName, 101); + if (error != 0) { + Files_Err((CHAR*)"Couldn't rename previous version of file being registered", 58, osfile, error); + } + } + } + __DEL(name); +} + +static void Files_Create (Files_File f) +{ BOOLEAN done; INT16 error; CHAR err[32]; @@ -235,6 +262,7 @@ static void Files_Create (Files_File f) f->tempFile = 1; } else { __ASSERT(f->state == 2, 0); + Files_Deregister(f->registerName, 101); __COPY(f->registerName, f->workName, 101); f->registerName[0] = 0x00; f->tempFile = 0; @@ -715,6 +743,7 @@ void Files_WriteBytes (Files_Rider *r, ADDRESS *r__typ, SYSTEM_BYTE *x, ADDRESS void Files_Delete (CHAR *name, ADDRESS name__len, INT16 *res) { __DUP(name, name__len, CHAR); + Files_Deregister(name, name__len); *res = Platform_Unlink((void*)name, name__len); __DEL(name); } @@ -791,6 +820,7 @@ void Files_Register (Files_File f) } Files_Close(f); if (f->registerName[0] != 0x00) { + Files_Deregister(f->registerName, 101); Files_Rename(f->workName, 101, f->registerName, 101, &errcode); if (errcode != 0) { Files_Err((CHAR*)"Couldn't rename temp name as register name", 43, f, errcode); diff --git a/src/runtime/Files.Mod b/src/runtime/Files.Mod index 4b0c9e44..7bbecbf7 100644 --- a/src/runtime/Files.Mod +++ b/src/runtime/Files.Mod @@ -122,16 +122,51 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files name[i] := 0X END GetTempName; + (* When registering a file, it may turn out that the name we want to use + is aready in use by another File. E.g. the compiler opens and reads + an existing symbol file if present before creating an updated one. + When this happens on Windows, creation of the new file will be blocked + by the presence of the old one because it is in a open state. Further, + on both Unix and Windows systems we want behaviour to match that of + a real Oberon system, where registering the new file has the effect of + unregistering the old file. To simulate this we need to change the old + Files.File back to a temp file. *) + PROCEDURE Deregister(name: ARRAY OF CHAR); + VAR + identity: Platform.FileIdentity; + osfile: File; + error: Platform.ErrorCode; + BEGIN + IF Platform.IdentifyByName(name, identity) = 0 THEN + (* The name we are registering is an already existing file. *) + osfile := files; + WHILE (osfile # NIL) & ~Platform.SameFile(osfile.identity, identity) DO osfile := osfile.next END; + IF osfile # NIL THEN + (* osfile is the FileDesc corresponding to the file name we are hoping + to register. Turn it into a temporary file. *) + ASSERT(~osfile.tempFile); ASSERT(osfile.fd >= 0); + osfile.registerName := osfile.workName; + GetTempName(osfile.registerName, osfile.workName); + osfile.tempFile := TRUE; + osfile.state := open; + error := Platform.Rename(osfile.registerName, osfile.workName); + IF error # 0 THEN + Err("Couldn't rename previous version of file being registered", osfile, error) + END + END + END + END Deregister; + + PROCEDURE Create(f: File); (* Makes sure there is an OS file backing this Oberon file. Used when more data has been written to an unregistered new file than buffers can hold, or when registering a new file whose data is all in buffers. *) VAR - identity: Platform.FileIdentity; - done: BOOLEAN; - error: Platform.ErrorCode; - err: ARRAY 32 OF CHAR; + done: BOOLEAN; + error: Platform.ErrorCode; + err: ARRAY 32 OF CHAR; BEGIN (* Out.String("Files.Create fd = "); Out.Int(f.fd,1); @@ -149,6 +184,7 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files ASSERT(f.state = close); (* New file with all data in buffers being registered. No need for a temp file, will just write the buffers to the registerName. *) + Deregister(f.registerName); f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE END; error := Platform.Unlink(f.workName); (*unlink first to avoid stale NFS handles and to avoid reuse of inodes*) @@ -509,7 +545,10 @@ Especially Length would become fairly complex. *) PROCEDURE Delete*(name: ARRAY OF CHAR; VAR res: INTEGER); - BEGIN res := Platform.Unlink(name) END Delete; + BEGIN + Deregister(name); + res := Platform.Unlink(name) + END Delete; PROCEDURE Rename* (old, new: ARRAY OF CHAR; VAR res: INTEGER); VAR @@ -531,6 +570,8 @@ Especially Length would become fairly complex. END; error := Platform.Rename(old, new); (* Out.String("Platform.Rename error code "); Out.Int(error,1); Out.Ln; *) + (* TODO, if we already have a FileDesc for old, it ought to be updated + with the new workname. *) IF ~Platform.DifferentFilesystems(error) THEN res := error; RETURN ELSE @@ -572,6 +613,7 @@ Especially Length would become fairly complex. IF (f.state = create) & (f.registerName # "") THEN f.state := close (* shortcut renaming *) END; Close(f); IF f.registerName # "" THEN + Deregister(f.registerName); Rename(f.workName, f.registerName, errcode); (* Out.String("Renamed (for register) f.fd = "); Out.Int(f.fd,1);