delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/03/04/10:15:38

Sender: rich AT phekda DOT freeserve DOT co DOT uk
Message-ID: <3E64C271.556CBDF2@phekda.freeserve.co.uk>
Date: Tue, 04 Mar 2003 15:12:49 +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 <djgpp-workers AT delorie DOT com>, Jim Meyering <jim AT meyering DOT net>
Subject: Design for fchdir
Reply-To: djgpp-workers AT delorie DOT com

Hello.

Below is a design for adding the fchdir function to DJGPP. This is a (new?)
POSIX function. Please let me know if this looks sane and I'll code it up. Any
comments welcome.

You can also read it here:

    http://www.phekda.freeserve.co.uk/richdawe/djgpp/2.04/fchdir.txt

Thanks, bye, Rich =]

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

Design for fchdir in DJGPP
~~~~~~~~~~~~~~~~~~~~~~~~~~

The new POSIX standard requires that an implementation provides
the fchdir function. DJGPP CVS (to be 2.04) could support
an fchdir function. fchdir is like chdir, but it changes to the directory
specified by a file descriptor. This file descriptor refers to a directory.
So supporting fchdir would require the normal Unixy I/O functions -
open, read, write, etc. - to work with file descriptors referring
to directories.

The fd_props mechanism, which associates some flags and a filename
with a file descriptor, can be used, to mark the file descriptor
as a directory. This will allow the Unixy I/O functions
to handle directories specially. A new flag FILE_DESC_DIRECTORY
would be added.

One concern with requiring fd_props for a file descriptor is
that the file descriptor may be used with functions that are
not aware of directories, e.g.: _dos_write. It may also be inherited -
the child program will have no access to fd_props. To handle these cases,
I suggest that the directory's file descriptor be dup'd off nul.
The file mode should also be set to binary. We could use __FSEXT_alloc_fd
to do this.

It may also be wise to ensure that file descriptors for directories
cannot be inherited, by setting the no-inherit (close-on-exec) bit using
fcntl(..., F_GETFD) and fcntl(..., F_SETFD, FD_CLOEXEC|...).

POSIX allows us to restrict how directories are handled by
the Unixy I/O functions. So let's make the following restrictions:

* Directories can only be opened read-only.
* Directories can only be read using readdir().

The directory-specific code would be after File System Extensions
(FSEXTs) have had their chance to handle I/O operations.

Now to how specific functions would be updated or implemented:

open
----

src/libc/posix/fcntl/open.c
src/dos/io/_creat.c
src/dos/io/_creat_n.c
src/dos/io/_open.c

I suggest that directories are handled first as a special case
in open. If the filename refers to a directory (check with
access(..., D_OK), open would call this function, say __opendir_as_fd,
and then return its return code.

__opendir_as_fd would:

* call the FSEXT handler with __FSEXT_open, to allow hooking,
  then return appropriately, if the FSEXT handled it;

* check that the directory was being opened as read-only - if not,
  fail with errno == EISDIR;

* use __FSEXT_alloc_fd, to allocate a file descriptor for the directory;

* set the FILE_DESC_DIRECTORY flag in fd_props for the file descriptor;

* return this file descriptor.

We should probably also check that O_APPEND was not specified.
If it has, return errno == EINVAL.

Since _open is a DOS-specific function described as "a direct connection
to the MS-DOS open function call", it requires no attention. It fails
for directories.

ISSUE: Do we want to support the O_DIRECTORY option that Linux does?
Here's a description, taken from open(2):

"O_DIRECTORY
              If pathname is not a directory, cause the  open  to
              fail.   This  flag is Linux-specific, and was added
              in kernel version 2.1.126, to avoid  denial-of-ser-
              vice  problems if opendir(3) is called on a FIFO or
              tape device, but should not be used outside of  the
              implementation of opendir."

I think not, but I mention it here for completeness. If we ever
want to use open in libc to create a directory, then we should
support O_DIRECTORY. But I can't think of any another reason.

read
----

src/libc/posix/unistd/read.c
src/libc/dos/io/_read.c

We can handle both read and _read, by adding a check to _read,
after the FSEXT handler has been called. It would try to find the flags
for the file descriptor by using __get_fd_flags. If it can
and the file descriptor refers to a directory, it would fail with
errno == EISDIR. (EISDIR indicates that readdir should be used instead.)

write
-----

src/libc/posix/unistd/write.c
src/libc/dos/io/_write.c

We can handle both write and _write, by adding a check to _write,
after the FSEXT handler has been called. It would try to find the flags
for the file descriptor by using __get_fd_flags. If it can
and the file descriptor refers to a directory, it would fail with
errno == EACCES.

NOTE: POSIX seems a bit unclear here to me. It says that the errno == EBADF
should be used when "The fildes argument is not a valid file descriptor
open for writing." This covers two error conditions: invalid file
descriptor; file descriptor not open for writing. So I'm not sure that
errno == EACCES is correct above.

IMPLEMENTATION NOTE: It'll be important here that the file descriptor
is in binary mode, so that no ASCII-conversion code is executed
in write for the directory's file descriptor. If the file descriptor
is in binary mode, it will just call _write.

close
-----

No changes would be required.

lseek, llseek, tell
-------------------

src/libc/posix/unistd/lseek.c
src/libc/compat/unistd/llseek.c
src/libc/dos/io/tell.c

These all go through llseek. It would try to find the flags
for the file descriptor by using __get_fd_flags. If it can
and the file descriptor refers to a directory, it would always
return 0.

ftruncate
---------

src/libc/compat/unistd/ftruncat.c

It would try to find the flags for the file descriptor by using
__get_fd_flags. If it can and the file descriptor refers to a directory,
it would fail with errno == EINVAL.

fchmod
------

src/libc/posix/sys/stat/fchmod.c
src/libc/posix/sys/stat/chmod.c

There is currently a patch (by me) outstanding to add fchmod support.
No changes would be required, since this uses chmod() on the file name
obtained from fd_props or the long filename (LFN) API.

fchown
------

src/libc/compat/unistd/fchown.c

As fchown.c says:

/* MS-DOS couldn't care less about file ownerships, so we
   at least check if given handle is valid. */

Since the directory will be dup'd off nul, it will have a valid handle
(aka file descriptor). No changes would be required.

ioctl
-----

src/libc/compat/ioctl/ioctl.c

DOS ioctls:  Assume the programmer knows what he/she is doing.
Unix ioctls: There aren't any interesting ones.

No changes would be required.

fcntl
-----

src/libc/posix/fcntl/fcntl.c

No changes would be required.

lockf, llockf
-------------

src/libc/compat/unistd/lockf.c
src/libc/compat/unistd/llockf.c

These use the fcntl interface. No changes would be required.

fstat
-----

src/libc/posix/sys/stat/fstat.c

fstat_assist currently assumes that it will not have to handle
directories, because directories cannot be opened. This will
need re-examining.

select
------

src/libc/compat/time/time.c

select() assumes that the file descriptor refers to a file or device.
Disk files are always considered to be ready for reading and writing.
I suggest that directories should always be considered to be ready
for reading and never for writing (since they're supposed to be read-only).

fd_input_ready and fd_output_ready could be modified to check
for directories. Or perhaps it would be better to add another check
after the __FSEXT_ready check, so that we don't pollute
fd_(in|out)put_ready with directory-specific code.

fsync
-----

src/libc/compat/unistd/fsync.c

This would fail with errno == EINVAL, since we can't sync directories.

fchdir
------

Phew, finally. 8)

Probably: src/libc/posix/unistd/fchdir.c

This would the get the directory's filename from the fd_props
and use chdir to change to it. If fchdir was called on a normal file,
it would fail with errno == ENOTDIR.

Richard Dawe <rich AT phekda DOT freeserve DOT co DOT uk>

$Id: fchdir.txt,v 1.1 2003/03/04 15:07:29 rich Exp $

- Raw text -


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