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 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: <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> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 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 #include #include #include #include #include #include #include #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 #include #include #include #include #include #include #include #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 #include #include #include #include #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---