Commit 68fc9d43 authored by ROOL's avatar ROOL 🤖
Browse files

Add fopen's exclusive mode

Detail:
  Remove undocumented 't' mode which forcibly timestamped files, since other operating systems use this to denote a text file (as opposed to 'b' binary mode).
  Add 'x' mode per ISO9899:2018
  * only applies to 'w' mode files (not 'r' or 'a')
  * file must not exist prior to creation
  * beyond that we rely on RISC OS' policy of only allowing a file to be opened once for writing as our exclusivity
  Also fix bug in check for 'Protected disc' error, which only trigged for fsnumber_ADFS (8).
Admin:
  Tested in a ROM build with a simple test harness.
parent f17e234d
......@@ -315,32 +315,31 @@ FILEHANDLE _sys_open(const char *filename, int openmode)
/* a = */ 0x3cc, /* a+ = */ 0x3cc };
if (isttyname(filename)) return TTYHANDLE;
else {
char *name = (char *)filename; /* yuk yuk yuk yuk yuk */
FILEHANDLE fh;
int size = 16 * 1024; /* first try for created files */
int osmode = modtab[(openmode >> 1) & 7]; /* forget the 'b'inary bit */
int osmode = modtab[(openmode >> 1) & 7]; /* forget the 'b' & 'x' bits */
_kernel_osfile_block fb;
/* maybe stamp file with current datestamp */
if ((openmode & OPEN_T) || /* update timestamp requested */
(openmode & OPEN_W) ||
(openmode & ~OPEN_B) == OPEN_A) /* or mode = w, w+, or a */
{ if (_kernel_osfile(9, name, &fb) == _kernel_ERROR)
{ if (_kernel_peek_last_oserror()->errnum == 0x108c9)
if ((openmode & (OPEN_X|OPEN_W)) == OPEN_W || /* mode = w, wb, w+, wb+ */
(openmode & ~OPEN_B) == OPEN_A) /* or a, ab (no plus) */
{ if (_kernel_osfile(9, filename, &fb) == _kernel_ERROR)
{ if ((_kernel_peek_last_oserror()->errnum & ~0xFF00) == 0x100c9)
{ errno = -1;
return NONHANDLE; /* (Protected disc) */
}
}
}
retry_open:
fh = _kernel_osfind(osmode & 0xff, name);
fh = _kernel_osfind(osmode & 0xff, (char *) /* yuk */ filename);
if (osmode <= 0x0cc) { /* r or r+ */
if (fh == _kernel_ERROR) errno = -1;
return (fh <= 0) ? NONHANDLE : /* not found */
fh;
} else if (fh > 0) {
if ((osmode == 0x4cc) || (size == 0))
if (_kernel_osargs(3, fh, 0) == _kernel_ERROR) {
if (((openmode & OPEN_X) && size) || /* found, but want eXclusive */
_kernel_osargs(3, fh, 0) == _kernel_ERROR) { /* truncate err */
_kernel_osfind(0, (char *)fh);
errno = -1;
return NONHANDLE;
......@@ -349,12 +348,12 @@ retry_open:
} else if (fh <= 0) {
/* _kernel_osfile(11) creates an empty file of size 'size', of type */
/* given by fb.load, stamped with the current date & time */
fb.load = (openmode & 1) ? 0xffd : 0xfff; /* data : text */
fb.load = (openmode & OPEN_B) ? 0xffd : 0xfff; /* data : text */
fb.start = 0;
for (; ; size >>= 1) {
if (size < 512) { errno = -1; return NONHANDLE; }
fb.end = size;
if (_kernel_osfile(11, name, &fb) > 0) break;
if (_kernel_osfile(11, filename, &fb) > 0) break;
}
size = 0;
goto retry_open;
......
......@@ -713,7 +713,7 @@ static FILE *freopen_common(const char *name, const char *mode, FILE *iob, int f
int flag, openmode; /* nasty magic numbers for openmode */
fclose(iob);
switch (*mode++)
{ default: return(NULL); /* mode is incorrect */
{ default: return NULL; /* 1st of mode must be r/w/a */
case 'r': flag = _IOREAD; openmode = OPEN_R; break;
case 'w': flag = _IOWRITE; openmode = OPEN_W; break;
case 'a': flag = _IOWRITE | _IOAPPEND;
......@@ -721,13 +721,15 @@ static FILE *freopen_common(const char *name, const char *mode, FILE *iob, int f
}
for (;;)
{ switch (*mode++)
{
{ /* 2nd can be b/+/b+/+b */
case '+': flag |= _IOREAD+_IOWRITE, openmode |= OPEN_PLUS;
continue;
case 'b': flag |= _IOBIN, openmode |= OPEN_B;
continue;
case 'x': if (*mode != '\0' || /* must be last and writing */
!(openmode & OPEN_W)) return NULL;
openmode |= OPEN_X; break;
}
if (*(mode-1) == 't') openmode |= OPEN_T;
break;
}
if ((fh = _sys_open(name, openmode)) == NONHANDLE) return NULL;
......
......@@ -163,20 +163,13 @@ extern struct _svcwto _io_emsg; /* beware only 64 bytes thereof */
extern FILEHANDLE _sys_open(const char *name, int openmode);
/* openmode is a bitmap, whose bits have the following significance ... */
/* most correspond directly to the ANSI mode specification - the */
/* exception is OPEN_T, an extension which requests timestamp update. */
/* This is really a sop to implementation laziness: what is intended is */
/* that the timestamp should be updated if the file is written to or */
/* otherwise modified. But that is known only when the file is closed */
/* and RISC OS has no 'set timestamp given filehandle' operation and the */
/* name by which the file was opened may no longer be valid at the time */
/* of its close. */
/* be careful of the ordering, arithmetic may be performed on openmode */
#define OPEN_R 0
#define OPEN_W 4
#define OPEN_A 8
#define OPEN_B 1
#define OPEN_PLUS 2
#define OPEN_T 16
#define OPEN_W 4
#define OPEN_A 8
#define OPEN_X 16
extern int _sys_close(FILEHANDLE fh);
/* result is 0 or an error indication */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment