delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/04/19/08:10:36

Date: Sat, 19 Apr 2003 13:14:46 +0100
From: "Richard Dawe" <rich AT phekda DOT freeserve DOT co DOT uk>
Sender: rich AT phekda DOT freeserve DOT co DOT uk
To: djgpp-workers AT delorie DOT com
X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6
Subject: fstat, fd_props and inventing inodes, revision 3 [PATCH]
Message-Id: <E196rAk-0007Mp-00@phekda.freeserve.co.uk>
Reply-To: djgpp-workers AT delorie DOT com

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 -


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