Mail Archives: djgpp-workers/2003/04/19/08:10:36
Hello.
Here's revision 3 of the patch to fstat, to make it use the filename
from fd_props to generate an inode number, when it can't obtain the inode
from the SFT.
This revision includes the diff to src/libc/dos/dir/makefile.
There are no other changes over revision 2.
OK to commit?
Thanks, bye, Rich =]
Index: include/dir.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/dir.h,v
retrieving revision 1.4
diff -p -u -3 -r1.4 dir.h
--- include/dir.h 4 Feb 2003 20:23:00 -0000 1.4
+++ include/dir.h 19 Apr 2003 12:06:06 -0000
@@ -75,14 +75,20 @@ struct ffblklfn {
#define DIRECTORY 0x08
#define DRIVE 0x10
-int __file_tree_walk(const char *_dir, int (*_fn)(const char *_path, const struct ffblk *_ff));
-int findfirst(const char *_pathname, struct ffblk *_ffblk, int _attrib);
-int findnext(struct ffblk *_ffblk);
-void fnmerge (char *_path, const char *_drive, const char *_dir, const char *_name, const char *_ext);
-int fnsplit (const char *_path, char *_drive, char *_dir, char *_name, char *_ext);
-int getdisk(void);
-char * searchpath(const char *_program);
-int setdisk(int _drive);
+typedef struct {
+ int drive;
+ char share[MAXPATH];
+} drive_mapping;
+
+int __file_tree_walk(const char *_dir, int (*_fn)(const char *_path, const struct ffblk *_ff));
+int findfirst(const char *_pathname, struct ffblk *_ffblk, int _attrib);
+int findnext(struct ffblk *_ffblk);
+void fnmerge (char *_path, const char *_drive, const char *_dir, const char *_name, const char *_ext);
+int fnsplit (const char *_path, char *_drive, char *_dir, char *_name, char *_ext);
+int getdisk(void);
+drive_mapping **__get_drive_mappings (void);
+char * searchpath(const char *_program);
+int setdisk(int _drive);
#endif /* !_POSIX_SOURCE */
#endif /* !__STRICT_ANSI__ */
Index: src/libc/dos/dir/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/dir/makefile,v
retrieving revision 1.1
diff -p -u -3 -r1.1 makefile
--- src/libc/dos/dir/makefile 13 Jun 1995 06:03:36 -0000 1.1
+++ src/libc/dos/dir/makefile 19 Apr 2003 12:06:06 -0000
@@ -1,3 +1,4 @@
+# Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details
# Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
TOP=../..
@@ -8,6 +9,7 @@ SRC += fnsplit.c
SRC += ftreewlk.c
SRC += ftw.c
SRC += getdisk.c
+SRC += getshare.c
SRC += setdisk.c
SRC += srchpath.c
Index: src/libc/posix/sys/stat/fstat.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/fstat.c,v
retrieving revision 1.11
diff -p -u -3 -r1.11 fstat.c
--- src/libc/posix/sys/stat/fstat.c 26 Mar 2003 19:53:43 -0000 1.11
+++ src/libc/posix/sys/stat/fstat.c 19 Apr 2003 12:06:20 -0000
@@ -107,6 +107,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <dos.h>
+#include <dir.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
@@ -175,6 +176,12 @@ static int fstat_count = -1;
/* The address of the PSP of the caller. */
static unsigned long psp_addr;
+/* Drive mappings from UNC paths to drive letters. */
+static drive_mapping **drive_mappings;
+
+/* When were the drive mappings last obtained? */
+static clock_t drive_mappings_time;
+
/* Initialization routine, called once per program run.
* Finds DOS version, SFT entry size and addresses of
* program handle table and first SFT sub-table.
@@ -259,6 +266,7 @@ get_sft_entry(int fhandle)
{
fstat_count = __bss_count;
dos_major = 0;
+ drive_mappings = NULL;
}
/* Find the PSP address of the current process. */
@@ -360,6 +368,71 @@ set_fstat_times (int fhandle, struct sta
}
}
+/* Find a mapping for the UNC path (\\machine\share) in `src', if one
+ * exists. If one exists, copy the path into `dest' and convert the UNC
+ * to the mapped drive, then return `dest'. Otherwise, just return `src'.
+ */
+
+static const char *
+find_mapping_for_unc (const char *src, char *dest)
+{
+ int is_unc = 1;
+ drive_mapping *m = NULL;
+ int i;
+ clock_t t;
+
+ if (!src[0] || (src[0] && !src[1]))
+ is_unc = 0;
+
+ if (is_unc && ((src[0] != '\\') || (src[1] != '\\')))
+ is_unc = 0;
+
+ if (!is_unc)
+ return src;
+
+ /* Update the drive mappings, if: we don't have them; a second has
+ * elapsed; the clock has wrapped. We update every second as a basic
+ * caching mechanism, but also to keep up with changes in the mappings.
+ *
+ * It may get updated more frequently, if the user calls
+ * __get_drive_mappings, but that should not cause any problems,
+ * because drive_mappings is a pointer to a static buffer.
+ */
+ t = clock();
+
+ if ( (drive_mappings == NULL)
+ || ((drive_mappings_time + CLOCKS_PER_SEC) < t)
+ || (t < drive_mappings_time))
+ {
+ drive_mappings = __get_drive_mappings();
+ drive_mappings_time = clock();
+ }
+
+ if (drive_mappings != NULL)
+ {
+ for (i = 0; drive_mappings[i] != NULL; i++)
+ {
+ if (!strnicmp(drive_mappings[i]->share,
+ src,
+ strlen(drive_mappings[i]->share)))
+ {
+ m = drive_mappings[i];
+ break;
+ }
+ }
+ }
+
+ if (m == NULL)
+ return src;
+
+ dest[0] = m->drive + 'A';
+ dest[1] = ':';
+ dest[2] = '\0';
+ strcat(dest, src + strlen(m->share));
+
+ return dest;
+}
+
/* fstat_assist() is where all the actual work is done.
* It uses SFT entry, if available and its contents are verified.
* Otherwise, it finds all the available info by conventional
@@ -381,6 +454,8 @@ fstat_assist(int fhandle, struct stat *s
unsigned short trusted_ftime = 0, trusted_fdate = 0;
long trusted_fsize = 0;
int is_link = 0;
+ char fixbuf[PATH_MAX];
+ const char *filename = "";
if ((dev_info = _get_dev_info(fhandle)) == -1)
return -1; /* errno set by _get_dev_info() */
@@ -434,16 +509,19 @@ fstat_assist(int fhandle, struct stat *s
stat_buf->st_gid = getgid();
stat_buf->st_nlink = 1;
+ /* Get the file name from the file descriptor properties (fd_props),
+ * if possible, and fix it up. */
+ if (__get_fd_name(fhandle))
+ filename = __get_fd_name(fhandle);
+
+ if (*filename)
+ filename = find_mapping_for_unc(filename, fixbuf);
+
/* Get the block size for the device associated with `fhandle'. */
#ifndef NO_ST_BLKSIZE
- if (__get_fd_name(fhandle))
+ if (*filename)
{
- const char *filename;
- char fixed_filename[PATH_MAX + 1];
-
- filename = __get_fd_name(fhandle);
- _fixpath(filename, fixed_filename);
- stat_buf->st_blksize = _get_cached_blksize(fixed_filename);
+ stat_buf->st_blksize = _get_cached_blksize(filename);
if (stat_buf->st_blksize == -1)
return -1; /* errno set by _get_cached_blksize() */
}
@@ -804,13 +882,16 @@ fstat_assist(int fhandle, struct stat *s
}
else
{
- /* Regular file. The inode will be arbitrary, as we don't have
- * this file's name. Sigh...
+ /* Regular file. We may have obtained this file's name
+ * from the file descriptor properties (fd_props). Otherwise
+ * the inode will be arbitrary each time fstat is called.
+ * Sigh...
*/
if ( (_djstat_flags & _STAT_INODE) == 0 )
{
_djstat_fail_bits |= _STFAIL_HASH;
- stat_buf->st_ino = _invent_inode("", dos_ftime, trusted_fsize);
+ stat_buf->st_ino
+ = _invent_inode(filename, dos_ftime, trusted_fsize);
}
if (trusted_fsize == 510)
@@ -914,7 +995,11 @@ fstat(int handle, struct stat *statbuf)
* use a normal stat call. */
if (__get_fd_flags(handle) & FILE_DESC_DIRECTORY)
{
+ char fixbuf[PATH_MAX];
const char *filename = __get_fd_name(handle);
+
+ if (filename)
+ filename = find_mapping_for_unc(filename, fixbuf);
if (filename)
return stat(filename, statbuf);
Index: src/libc/posix/sys/stat/fstat.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/fstat.txh,v
retrieving revision 1.11
diff -p -u -3 -r1.11 fstat.txh
--- src/libc/posix/sys/stat/fstat.txh 1 Apr 2003 20:47:29 -0000 1.11
+++ src/libc/posix/sys/stat/fstat.txh 19 Apr 2003 12:06:22 -0000
@@ -85,10 +85,14 @@ files for identity should include compar
member.)
3. On all versions of Windows except Windows 3.X, the inode number is
-invented. As Windows doesn't provide enough information to identify
-files by the handle on which they are open, @code{fstat} always returns
-different inode numbers for any two files open on different handles,
-even if the same file is open twice on two different handles.
+invented using the file name. @code{fstat} can probably use the file name
+that was used to open the file, when generating the inode. This is done
+such that the same inode will be generated irrespective of the actual path
+used to open the file (e.g.: @samp{foo.txt}, @samp{./foo.txt},
+@samp{../somedir/foo.txt}). If file names cannot be used, @code{fstat}
+always returns different inode numbers for any two files open
+on different handles, even if the same file is open twice
+on two different handles.
4. The WRITE access mode bit is set only for the user (unless the file is
read-only, hidden or system). EXECUTE bit is set for directories, files
Index: src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.151
diff -p -u -3 -r1.151 wc204.txi
--- src/docs/kb/wc204.txi 26 Mar 2003 19:54:46 -0000 1.151
+++ src/docs/kb/wc204.txi 19 Apr 2003 12:06:33 -0000
@@ -944,3 +944,10 @@ to the POSIX functions @code{open}, @cod
@code{fsync} and @code{fdopen} and the ANSI functions @code{fopen},
@code{freopen}, @code{fclose}, @code{ftell}, @code{fseek}
and @code{rewind}, to make them aware of file descriptors for directories.
+
+@findex fstat AT r{, and inodes}
+@code{fstat} will now use the file name used to open the file,
+when inventing inodes. This is done so that the same inode is generated
+irrespective of the actual file path used to open the file. This also
+fixes the problem where multiple calls to fstat
+on the same file descriptor would give different inodes.
--- /dev/null 2003-04-19 13:12:20.000000000 +0000
+++ src/libc/dos/dir/getshare.c 2003-04-02 13:31:10.000000000 +0000
@@ -0,0 +1,179 @@
+/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+#include <libc/stubs.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dir.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <sys/movedata.h>
+#include <libc/dosio.h>
+#include <libc/bss.h>
+
+/* LANMan's use_info_1 structure */
+typedef struct {
+ char local_name[9];
+ char padding;
+ short remote_name_offset;
+ short remote_name_segment;
+ short password_offset;
+ short password_segment;
+ short status;
+ short type;
+ short ignored;
+ short ignored2;
+} share_info __attribute__((packed));
+
+#define SHARE_STATUS_OK 0
+#define SHARE_STATUS_DISCONNECTED 2
+
+#define SHARE_TYPE_WILDCARD -1
+#define SHARE_TYPE_DISK 0
+#define SHARE_TYPE_PRINT 1
+#define SHARE_TYPE_COM 2
+#define SHARE_TYPE_IPC 3
+
+#ifndef __tb_size
+#define __tb_size _go32_info_block.size_of_transfer_buffer
+#endif
+
+/* Allow for 32 drives plus NULL. */
+#define N_DRIVES 32
+static drive_mapping *drive_mappings[N_DRIVES + 1];
+static share_info *share_infos;
+static size_t n_share_infos;
+static size_t n_share_infos_max;
+
+static void
+shares_init (void)
+{
+ static int shares_bss_count = -1;
+ static const size_t default_n_share_infos = N_DRIVES;
+ size_t i;
+
+ if (shares_bss_count != __bss_count) {
+ shares_bss_count = __bss_count;
+
+ n_share_infos_max = __tb_size / sizeof(share_info);
+
+ /* Ensure we don't overflow the transfer buffer. We shouldn't
+ * since it's big enough to store a lot of share info. */
+ n_share_infos = default_n_share_infos;
+ if (n_share_infos > n_share_infos_max)
+ n_share_infos = n_share_infos_max;
+
+ for (i = 0; i < sizeof(drive_mappings) / sizeof(drive_mappings[0]); i++) {
+ drive_mappings[i] = NULL;
+ }
+
+ share_infos = malloc(n_share_infos * sizeof(*share_infos));
+ if (share_infos == NULL)
+ n_share_infos = 0;
+ }
+}
+
+static int
+get_shares_internal (share_info *shares, const size_t n_shares)
+{
+ __dpmi_regs r;
+
+ r.x.ax = 0x5f46; /* LANMan: NetUseEnum */
+ r.x.bx = 0x0001;
+ r.x.cx = sizeof(*shares) * n_shares;
+ r.x.es = __tb >> 4;
+ r.x.di = __tb & 0xf;
+
+ __dpmi_int(0x21, &r);
+
+ if(r.x.flags & 1) {
+ errno = __doserr_to_errno(r.x.ax);
+ return(-1);
+ }
+
+ dosmemget(__tb, r.x.cx * sizeof(*shares), shares);
+
+ return(r.x.cx);
+}
+
+drive_mapping **
+__get_drive_mappings (void)
+{
+ drive_mapping **p = NULL; /* Fail by default. */
+ int drive;
+ char path[MAXPATH];
+ int ret, addr, pos, i;
+
+ shares_init();
+
+ ret = get_shares_internal(share_infos, n_share_infos);
+
+ /* Error or no shares available. */
+ if ((ret < 0) || !ret)
+ return(p);
+
+ for (pos = i = 0; (i < ret) && (pos < N_DRIVES); i++) {
+ drive = share_infos[i].local_name[0];
+
+ /* Skip non-disks & disks without a mapping. */
+ if ((share_infos[i].type != SHARE_TYPE_DISK) || (drive == '\0'))
+ continue;
+
+ /* Check the drive is in range. */
+ if ((drive >= 'a') && (drive <= 'z'))
+ drive -= 'a';
+ else
+ drive -= 'A';
+
+ if (drive >= N_DRIVES)
+ continue;
+
+ /* Get the UNC - the remote name. */
+ addr = share_infos[i].remote_name_segment << 4;
+ addr += share_infos[i].remote_name_offset;
+ dosmemget(addr, sizeof(path), path);
+ path[sizeof(path) - 1] = '\0';
+
+ if (drive_mappings[pos] == NULL)
+ drive_mappings[pos] = malloc(sizeof(drive_mapping));
+
+ if (drive_mappings[pos] != NULL) {
+ drive_mappings[pos]->drive = drive;
+ strcpy(drive_mappings[pos]->share, path);
+ pos++;
+ }
+ }
+
+ /* Clean out stale mappings. */
+ for (i = pos; i <= N_DRIVES; i++) {
+ if (drive_mappings[pos] != NULL) {
+ free(drive_mappings[pos]);
+ drive_mappings[pos] = NULL;
+ }
+ }
+
+ p = drive_mappings;
+
+ return(p);
+}
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (void)
+{
+ drive_mapping **p = __get_drive_mappings();
+ int i;
+
+ if (p != NULL) {
+ for (i = 0; p[i] != NULL; i++) {
+ printf("%c -> %s\n", p[i]->drive + 'A', p[i]->share);
+ }
+ }
+
+ return(EXIT_SUCCESS);
+}
+
+#endif /* TEST */
--- /dev/null 2003-04-19 13:12:20.000000000 +0000
+++ src/libc/dos/dir/getshare.txh 2003-04-02 13:31:52.000000000 +0000
@@ -0,0 +1,54 @@
+@node __get_drive_mappings, dos
+@findex __get_drive_mappings
+@tindex drive_mapping
+@cindex Universal Naming Convention
+@cindex UNC
+
+@subheading Syntax
+
+@example
+#include <dir.h>
+
+drive_mapping **__get_drive_mappings (void);
+@end example
+
+@subheading Description
+
+This function returns a list of the shares currently mapped
+to drive letters. A share is a @dfn{Universal Naming Convention} (@dfn{UNC})
+path of the form @file{\\machine\share}.
+
+@code{drive_mapping} is defined as follows:
+
+@example
+typedef struct @{
+ int drive;
+ char share[MAXPATH];
+@} drive_mapping;
+@end example
+
+@code{drive} is the drive number, where @file{A:} is 0, @file{B:} is 1, etc.
+@code{share} is the UNC path.
+
+@subheading Return Value
+
+NULL, if there are no shares; otherwise a NULL-terminated list
+of pointers to @code{drive_mapping}s. The returned list is to static
+buffers and should not be modified by caller.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+drive_mapping **p = __get_drive_mappings();
+int i;
+
+if (p != NULL) @{
+ for (i = 0; p[i] != NULL; i++) @{
+ printf("%c -> %s\n", p[i]->drive + 'A', p[i]->share);
+ @}
+@}
+@end example
- Raw text -