delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/01/24/09:02:02

Sender: rich AT phekda DOT freeserve DOT co DOT uk
Message-ID: <3E3142BD.F9B0E165@phekda.freeserve.co.uk>
Date: Fri, 24 Jan 2003 13:42:21 +0000
From: Richard Dawe <rich AT phekda DOT freeserve DOT co DOT uk>
X-Mailer: Mozilla 4.77 [en] (X11; U; Linux 2.2.23 i586)
X-Accept-Language: de,fr
MIME-Version: 1.0
To: djgpp-workers AT delorie DOT com
Subject: _creatnew again [Was: Re: redirection problem with perl]
References: <Pine DOT SUN DOT 3 DOT 91 DOT 1020128134413 DOT 26430D-100000 AT is> <3CAB1FDB DOT 68F9CF2F AT phekda DOT freeserve DOT co DOT uk> <7704-Fri05Apr2002112312+0300-eliz AT is DOT elta DOT co DOT il> <3CAD6FE7 DOT 1384C841 AT phekda DOT freeserve DOT co DOT uk> <8582-Fri05Apr2002142726+0300-eliz AT is DOT elta DOT co DOT il> <3CAD9FB1 DOT 4DEC7F58 AT phekda DOT freeserve DOT co DOT uk>
Reply-To: djgpp-workers AT delorie DOT com

Hello.

Richard Dawe wrote:
> 
> Eli Zaretskii wrote:
> [snip]
> > I guess that's because you can't create a file without asking to
> > write to it.
> 
> That makes sense, but I have no idea if it's true. I'll write a test program
> later.

I've finally written some test programs: try-wronly.c and try-wronly2.c. They
are at the bottom of this mail:

* try-wronly.c tests extended open-create: INT 21h, AX=6c00h. (DOS 4 and
later)
* try-wronly2.c tests regular open-create: INT 21h, AX=5b00h. (DOS 3)
* try-rdonly.c tests opening a read-only file and then writing to it.

It seems that the extended open-create call has two distinct functions:

(1) Create and open the file in whatever mode you specify.
(2) Set the attributes to whatever you specify.

It seems like (1) controls access through the returned descriptor and (2)
controls subsequent access to the file (e.g.: after you've closed the
descriptor).
 
So it's possibly to open a file for read-write, but set the file's attributes
to read-write. You can also create file & simultaneously open it for
read-only/read-write/write-only and have it read-only subsequently (on disk).

So you don't need to open the file for writing, to create it with INT 21h,
AX=6c00h.

INT 21h, AX=5bh also allows you to create a read-only file, but gives you no
control over what mode of read-only/read-write/write-only is used.

> > Should we reopen it with the correct open mode once it's created?
[snip]

In my original mail I missed that the open flags and the file attribute flags
are different.

It seems like the INT 21h, AX=6c00h path opens in read-write mode, to behave
like INT 21h, AX=5b00h. Since both paths set the read-only attribute on the
file OK, I don't think there is a bug for the handling of read-only or
read-write files. For write-only files, there will always be a problem, since
there is no DOS attribute for write-only.

As long as _creatnew is called with the right attributes, we end up with a
file with the right attributes for processes that use it later.

But we still have the problem of being able to open() a file as read-only and
then writing to it successfully with write(). try-rdonly.c shows this problem.
This is because the flags we pass to INT 21h, AX=6c00h are not based on the
actual file attributes. O_RDONLY, etc. is used to set the file attributes for
creation of the file, but not the flags to the AX=6c00h call for opening the
file (which is always set up as read-write).

This problem is whether we want _creatnew to behave consistently across all
DOS versions or use the right open mode, when we can.

Bye, Rich =]

-- 
Richard Dawe [ http://www.phekda.freeserve.co.uk/richdawe/ ]

---Start try-wronly.c---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <dpmi.h>
#include <go32.h>
#include <libc/dosio.h>

#define TEST_FILE "foo.dat"

int
main (int argc, char *argv[])
{
  __dpmi_regs r;
  int ok = 1;

  memset(&r, 0, sizeof(r));

  if (!access(TEST_FILE, F_OK) && remove(TEST_FILE))
    {
      fprintf(stderr, "%s: remove(" TEST_FILE ") failed!\n", argv[0]);
      ok = 0;
    }

  _put_path(TEST_FILE);

/* #define DO_WRONLY 1 */
#undef DO_WRONLY
#define DO_RW_RDONLY 1

  r.x.ax = 0x6c00;
  r.x.bx  = 0x2000; /* Disallow INT 24h */
  r.x.bx |= 0x1000; /* Allow extended files */
#if DO_WRONLY
  r.x.bx |= 0x0001; /* Write-only */
#else
/* Read-only */
#ifdef DO_RW_RDONLY
  r.x.bx |= 0x0002; /* Read-write */
#endif
#endif
  r.x.dx = 0x0010;  /* Create, fail if exists */
  r.x.ds = __tb_segment;
  r.x.si = __tb_offset;
  r.x.cx = 0;       /* Default attributes */
#if DO_WRONLY
#else
  r.x.cx |= 0x0001; /* Read-only */
#endif

  __dpmi_int(0x21, &r);
  if (r.x.flags & 1)
    {
      errno = __doserr_to_errno(r.x.ax);
      perror(argv[0]);
      ok = 0;
    }

#if 0
  puts("sleep() before remove()...");
  sleep(10);

  if (!access(TEST_FILE, F_OK) && remove(TEST_FILE))
    {
      fprintf(stderr, "%s: remove(\"" TEST_FILE "\") failed!\n", argv[0]);
      ok = 0;
    }
#endif

  if (!ok)
    {
      puts("FAIL");
      return(EXIT_FAILURE);
    }

  puts("PASS");
  return(EXIT_SUCCESS);
}
---End try-wronly.c---

---Start try-wronly2.c---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <dpmi.h>
#include <go32.h>
#include <libc/dosio.h>

#define TEST_FILE "foo2.dat"

int
main (int argc, char *argv[])
{
  __dpmi_regs r;
  int ok = 1;

  memset(&r, 0, sizeof(r));

  if (!access(TEST_FILE, F_OK) && remove(TEST_FILE))
    {
      fprintf(stderr, "%s: remove(" TEST_FILE ") failed!\n", argv[0]);
      ok = 0;
    }

  _put_path(TEST_FILE);

/* #define DO_WRONLY 1 */
#undef DO_WRONLY

  r.x.ax = 0x5b00;
  r.x.ds = __tb_segment;
  r.x.dx = __tb_offset;
#if DO_WRONLY
#else
  r.x.cx |= 0x0001; /* Read-only */
#endif

  __dpmi_int(0x21, &r);
  if (r.x.flags & 1)
    {
      errno = __doserr_to_errno(r.x.ax);
      perror(argv[0]);
      ok = 0;
    }

#if 0
  puts("sleep() before remove()...");
  sleep(10);

  if (!access(TEST_FILE, F_OK) && remove(TEST_FILE))
    {
      fprintf(stderr, "%s: remove(\"" TEST_FILE "\") failed!\n", argv[0]);
      ok = 0;
    }
#endif

  if (!ok)
    {
      puts("FAIL");
      return(EXIT_FAILURE);
    }

  puts("PASS");
  return(EXIT_SUCCESS);
}
---End try-wronly2.c---

---Start try-rdonly.c---
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define TEST_FILE "foo3.dat"

int
main (int argc, char *argv[])
{
  int fd, ret;
  int ok = 1;
  char buf[128] = "foo";

  if (!access(TEST_FILE, F_OK) && remove(TEST_FILE))
    {
      fprintf(stderr, "%s: remove(" TEST_FILE ") failed!\n", argv[0]);
      ok = 0;
    }

  fd = open(TEST_FILE, O_RDONLY|O_CREAT|O_EXCL, S_IRUSR);
  if (fd < 0)
    {
      perror(argv[0]);
      ok = 0;
    }

  if (!access(TEST_FILE, F_OK) && ((ret = write(fd, buf, sizeof(buf))) >= 0))
    {
      fprintf(stderr,
	      "%s: Should not be able to write to " TEST_FILE "!\n"
	      "%s: ret=%d\n",
	      argv[0], argv[0], ret);
      ok = 0;
    }

  if (!ok)
    {
      puts("FAIL");
      return(EXIT_FAILURE);
    }

  puts("PASS");
  return(EXIT_SUCCESS);
}
---End try-rdonly.c---

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019