Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/sys/mmixware/open.c')
-rw-r--r--newlib/libc/sys/mmixware/open.c147
1 files changed, 138 insertions, 9 deletions
diff --git a/newlib/libc/sys/mmixware/open.c b/newlib/libc/sys/mmixware/open.c
index 26fbbb983..f0b9fbafe 100644
--- a/newlib/libc/sys/mmixware/open.c
+++ b/newlib/libc/sys/mmixware/open.c
@@ -1,6 +1,6 @@
/* open for MMIXware.
- Copyright (C) 2001 Hans-Peter Nilsson
+ Copyright (C) 2001, 2002 Hans-Peter Nilsson
Permission to use, copy, modify, and distribute this software is
freely granted, provided that the above copyright notice, this notice
@@ -11,6 +11,7 @@
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. */
+#include <stdlib.h>
#include <fcntl.h>
#include <_ansi.h>
#include <sys/types.h>
@@ -37,7 +38,9 @@ _open (const char *path,
{
long fileno;
unsigned char mode;
- long fffile = 0;
+ long append_contents = 0;
+ unsigned long prev_contents_size = 0;
+ char *prev_contents = NULL;
long ret;
for (fileno = 0;
@@ -55,7 +58,7 @@ _open (const char *path,
}
/* We map this to a fopen call. The flags parameter is stymied because
- we don't support more other than these flags. */
+ we don't support other than these flags. */
if (flags & ~(O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_APPEND | O_TRUNC))
{
UNIMPLEMENTED (("path: %s, flags: %d", path, flags));
@@ -68,12 +71,12 @@ _open (const char *path,
else if ((flags & (O_WRONLY | O_APPEND)) == (O_WRONLY | O_APPEND))
{
mode = BinaryReadWrite;
- fffile = 1;
+ append_contents = 1;
}
else if ((flags & (O_RDWR | O_APPEND)) == (O_RDWR | O_APPEND))
{
mode = BinaryReadWrite;
- fffile = 1;
+ append_contents = 1;
}
else if ((flags & (O_WRONLY | O_CREAT)) == (O_WRONLY | O_CREAT)
|| (flags & (O_WRONLY | O_TRUNC)) == (O_WRONLY | O_TRUNC))
@@ -88,6 +91,99 @@ _open (const char *path,
return -1;
}
+ if (append_contents)
+ {
+ /* BinaryReadWrite is equal to "w+", so it truncates the file rather
+ than keeping the contents, as can be imagined if you're looking
+ for append functionality. The only way we can keep the contents
+ so we can append to it, is by first reading in and saving the
+ contents, then re-opening the file as BinaryReadWrite and write
+ the previous contents. This seems to work for the needs of
+ simple test-programs. */
+ long openexist = TRAP3f (SYS_Fopen, fileno, path, BinaryRead);
+ if (openexist == 0)
+ {
+ /* Yes, this file exists, now opened, so let's read it and keep
+ the contents. Better have the memory around for this to
+ work. */
+ long seekval = TRAP2f (SYS_Fseek, fileno, -1);
+
+ if (seekval == 0)
+ {
+ prev_contents_size = TRAP1f (SYS_Ftell, fileno);
+
+ /* If the file has non-zero size, we have something to
+ append to. */
+ if (prev_contents_size != 0)
+ {
+ /* Start reading from the beginning. Ignore the return
+ value from this call: we'll notice if we can't read
+ as much as we want. */
+ TRAP2f (SYS_Fseek, fileno, 0);
+
+ prev_contents = malloc (prev_contents_size);
+ if (prev_contents != 0)
+ {
+ /* I don't like the thought of trying to read the
+ whole file all at once, disregarding the size,
+ because the host system might not support that
+ and we'd get funky errors. Read in 32k at a
+ time. */
+ char *ptr = prev_contents;
+ unsigned long read_more = prev_contents_size;
+ unsigned long chunk_size = 1 << 15;
+
+ while (read_more >= chunk_size)
+ {
+ long readval
+ = TRAP3f (SYS_Fread, fileno, ptr, chunk_size);
+
+ if (readval != 0)
+ {
+ free (prev_contents);
+ TRAP1f (SYS_Fclose, fileno);
+ errno = EIO;
+ return -1;
+ }
+ read_more -= chunk_size;
+ ptr += chunk_size;
+ }
+
+ if (read_more != 0)
+ {
+ long readval
+ = TRAP3f (SYS_Fread, fileno, ptr, read_more);
+ if (readval != 0)
+ {
+ free (prev_contents);
+ TRAP1f (SYS_Fclose, fileno);
+ errno = EIO;
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ /* Malloc of area to copy to failed. The glibc
+ manpage says its open can return ENOMEM due to
+ kernel memory failures, so let's do that too
+ here. */
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ /* Seek failed. Gotta be some I/O error. */
+ errno = EIO;
+ return -1;
+ }
+
+ TRAP1f (SYS_Fclose, fileno);
+ }
+ }
+
ret = TRAP3f (SYS_Fopen, fileno, path, mode);
if (ret < 0)
{
@@ -97,12 +193,45 @@ _open (const char *path,
return -1;
}
- _MMIX_allocated_filehandle[fileno] = 1;
-
- if (fffile)
+ if (prev_contents_size != 0)
{
- TRAP2f (SYS_Fseek, fileno, -1);
+ /* Write out the previous contents, a chunk at a time. Leave the
+ file pointer at the end of the file. */
+ unsigned long write_more = prev_contents_size;
+ unsigned long chunk_size = 1 << 15;
+ char *ptr = prev_contents;
+
+ while (write_more >= chunk_size)
+ {
+ long writeval
+ = TRAP3f (SYS_Fwrite, fileno, ptr, chunk_size);
+ if (writeval != 0)
+ {
+ free (prev_contents);
+ TRAP1f (SYS_Fclose, fileno);
+ errno = EIO;
+ return -1;
+ }
+ write_more -= chunk_size;
+ ptr += chunk_size;
+ }
+ if (write_more != 0)
+ {
+ long writeval
+ = TRAP3f (SYS_Fwrite, fileno, ptr, write_more);
+ if (writeval != 0)
+ {
+ free (prev_contents);
+ TRAP1f (SYS_Fclose, fileno);
+ errno = EIO;
+ return -1;
+ }
+ }
+
+ free (prev_contents);
}
+ _MMIX_allocated_filehandle[fileno] = 1;
+
return fileno;
}