Mail Archives: djgpp-workers/2003/05/03/10:34:25
Hello.
Here's revision 4 of the fstat patch to fix the way it invents inodes
for files where it can't find an SFT entry. The patch may apply with
a little fuzz, because I hacked out some diffs relating only
to __tb_size.
Changes:
* Split out __find_mapping_for_unc into a separate module.
This involved adding some __bss_count handling.
* Add __find_mapping_to_unc, to map from a drive-letter qualified
filename to a UNC filename.
* Add documentation for __find_mapping*.
* Fix texinfo mark-up.
* Fix stat to use the UNC-mapping code too. Mention that we've fixed
stat too.
I haven't done anything about the memory allocation issue. I don't think
we should have a static buffer, because that's about 8K of memory
up-front. It will only allocate memory, if it encounters a UNC path.
(__find_mapping_for_unc doesn't get the mappings, until it needs to.)
This probably isn't the final revision, because:
* __find_mapping_to_unc should just return, if the path is already a UNC.
* I haven't looked at the problems in _fixpath with UNCs yet.
So this is more a WIP.
Bye, Rich =]
Index: include/dir.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/dir.h,v
retrieving revision 1.4
diff -p -c -3 -r1.4 dir.h
*** include/dir.h 4 Feb 2003 20:23:00 -0000 1.4
--- include/dir.h 3 May 2003 14:19:14 -0000
*************** struct ffblklfn {
*** 75,88 ****
#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);
#endif /* !_POSIX_SOURCE */
#endif /* !__STRICT_ANSI__ */
--- 75,94 ----
#define DIRECTORY 0x08
#define DRIVE 0x10
! 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: include/sys/stat.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/sys/stat.h,v
retrieving revision 1.9
diff -p -c -3 -r1.9 stat.h
*** include/sys/stat.h 8 Mar 2003 00:40:39 -0000 1.9
--- include/sys/stat.h 3 May 2003 14:19:14 -0000
*************** mode_t umask(mode_t _cmask);
*** 89,94 ****
--- 89,96 ----
#define S_IFLABEL 0x5000
#define S_ISLABEL(m) (((m) & 0xf000) == 0x5000)
+ const char * __find_mapping_for_unc(const char *_src, char *_dest);
+ const char * __find_mapping_to_unc(const char *_src, char *_dest);
void _fixpath(const char *, char *);
char * __canonicalize_path(const char *, char *, size_t);
unsigned short _get_magic(const char *, int);
Index: src/libc/dos/dir/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/dir/makefile,v
retrieving revision 1.1
diff -p -c -3 -r1.1 makefile
*** src/libc/dos/dir/makefile 13 Jun 1995 06:03:36 -0000 1.1
--- src/libc/dos/dir/makefile 3 May 2003 14:19:19 -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=../..
*************** SRC += fnsplit.c
*** 8,13 ****
--- 9,15 ----
SRC += ftreewlk.c
SRC += ftw.c
SRC += getdisk.c
+ SRC += getshare.c
SRC += setdisk.c
SRC += srchpath.c
Index: src/libc/posix/sys/stat/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/makefile,v
retrieving revision 1.5
diff -p -c -3 -r1.5 makefile
*** src/libc/posix/sys/stat/makefile 8 Mar 2003 00:41:17 -0000 1.5
--- src/libc/posix/sys/stat/makefile 3 May 2003 14:19:24 -0000
*************** SRC += mkfifo.c
*** 17,22 ****
--- 17,23 ----
SRC += st_loss.c
SRC += stat.c
SRC += umask.c
+ SRC += unc_map.c
SRC += xstat.c
include $(TOP)/../makefile.inc
Index: src/libc/posix/sys/stat/fstat.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/fstat.c,v
retrieving revision 1.12
diff -p -c -3 -r1.12 fstat.c
*** src/libc/posix/sys/stat/fstat.c 23 Apr 2003 19:13:26 -0000 1.12
--- src/libc/posix/sys/stat/fstat.c 3 May 2003 14:19:33 -0000
*************** fstat_assist(int fhandle, struct stat *s
*** 381,386 ****
--- 381,387 ----
unsigned short trusted_ftime = 0, trusted_fdate = 0;
long trusted_fsize = 0;
int is_link = 0;
+ char fixbuf[PATH_MAX];
const char *fd_name = NULL;
const char *filename = "";
*************** fstat_assist(int fhandle, struct stat *s
*** 437,446 ****
stat_buf->st_nlink = 1;
/* Get the file name from the file descriptor properties (fd_props),
! * if possible, and fix it up. */
fd_name = __get_fd_name(fhandle);
! if (fd_name != NULL)
! filename = fd_name;
/* Get the block size for the device associated with `fhandle'. */
#ifndef NO_ST_BLKSIZE
--- 438,456 ----
stat_buf->st_nlink = 1;
/* Get the file name from the file descriptor properties (fd_props),
! * if possible, and fix it up.
! *
! * Convert a UNC (\\somemachine\someshare\somefile) to a path
! * with the mapped drive, if any. This ensures that fstat always returns
! * the same information when it invents an inode for the file,
! * irrespective or whether it is accessed via the UNC or a mapped path.*/
fd_name = __get_fd_name(fhandle);
!
! if (fd_name)
! filename = fd_name;
!
! if (*filename)
! filename = __find_mapping_for_unc(filename, fixbuf);
/* Get the block size for the device associated with `fhandle'. */
#ifndef NO_ST_BLKSIZE
*************** fstat(int handle, struct stat *statbuf)
*** 920,926 ****
--- 930,940 ----
* 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/lstat.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/lstat.c,v
retrieving revision 1.12
diff -p -c -3 -r1.12 lstat.c
*** src/libc/posix/sys/stat/lstat.c 14 Jun 2002 14:26:15 -0000 1.12
--- src/libc/posix/sys/stat/lstat.c 3 May 2003 14:19:43 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
***************
*** 12,18 ****
*
* Note:
*
! * The actual function implemented here is lstat(), not stat(). The
* stat() now is just a lstat() wrapper.
*
* Rationale:
--- 13,19 ----
*
* Note:
*
! * The actual function implemented here is lstat(), not stat().
* stat() now is just a lstat() wrapper.
*
* Rationale:
*************** stat_assist(const char *path, struct sta
*** 437,442 ****
--- 438,444 ----
{
struct ffblk ff_blk;
char canon_path[MAX_TRUE_NAME];
+ char fixbuf[MAX_TRUE_NAME];
char pathname[MAX_TRUE_NAME];
short drv_no;
unsigned dos_ftime;
*************** stat_assist(const char *path, struct sta
*** 558,563 ****
--- 560,572 ----
_djstat_fail_bits |= _STFAIL_TRUENAME;
}
+
+ /* Convert a UNC (\\somemachine\someshare\somefile) to a path
+ with the mapped drive, if any. This ensures that stat always returns
+ the same information when it invents an inode for the file,
+ irrespective or whether it is accessed via the UNC or a mapped path. */
+ if (__find_mapping_for_unc (canon_path, fixbuf) != canon_path)
+ strcpy(fixbuf, canon_path);
/* Call DOS FindFirst function, which will bring us most of the info. */
if (!__findfirst(pathname, &ff_blk, ALL_FILES))
Index: src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.154
diff -p -c -3 -r1.154 wc204.txi
*** src/docs/kb/wc204.txi 23 Apr 2003 19:20:39 -0000 1.154
--- src/docs/kb/wc204.txi 3 May 2003 14:20:07 -0000
*************** and @code{rewind}, to make them aware of
*** 948,959 ****
@findex fstat AT r{, and inodes}
@findex stat AT r{, and inodes}
! @strong{Simple temporary fix - TODO: more complete fix}: @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.
@code{stat} and @code{fstat} should now return the same inode for a file
in most cases.
--- 948,965 ----
@findex fstat AT r{, and inodes}
@findex stat 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,
! even if the file can be opened through a UNC path
! (@file{\\somemachine\someshare\somefile}) or a mapped drive.
! This fixes the problem where multiple calls to fstat on the same file
! descriptor would give different inodes.
!
! When @code{stat} cannot determine the inode for a file, it will now ensure
! that the same inode is generated, even if the file can be accessed
! through a UNC path (@file{\\somemachine\someshare\somefile})
! or a mapped drive.
@code{stat} and @code{fstat} should now return the same inode for a file
in most cases.
Index: tests/libc/posix/sys/stat/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/posix/sys/stat/makefile,v
retrieving revision 1.5
diff -p -c -3 -r1.5 makefile
*** tests/libc/posix/sys/stat/makefile 8 Mar 2003 00:42:43 -0000 1.5
--- tests/libc/posix/sys/stat/makefile 3 May 2003 14:20:07 -0000
***************
*** 1,6 ****
--- 1,7 ----
TOP=../../..
SRC += fixpath.c
+ SRC += fixpath2.c
SRC += fstat.c
SRC += leak.c
SRC += lstat.c
*** /dev/null Sat May 3 15:25:38 2003
--- src/libc/dos/dir/getshare.c Sat May 3 14:02:46 2003
***************
*** 0 ****
--- 1,188 ----
+ /* 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
+
+ /* 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);
+ }
+
+ /* Protect from buffer overflow. */
+ if (r.x.cx > n_shares) {
+ errno = ENOMEM;
+ 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();
+ unsigned long i;
+
+ if (p != NULL) {
+ for (i = 0; p[i] != NULL; i++) {
+ printf("%c -> %s\n", p[i]->drive + 'A', p[i]->share);
+ }
+ }
+
+ #ifdef TEST_PERF
+ for (i = 0; i < 1000000; i++) {
+ if (get_shares_internal(share_infos, n_share_infos) < 0)
+ break;
+ }
+ #endif /* TEST_PERF */
+
+ return(EXIT_SUCCESS);
+ }
+
+ #endif /* TEST */
*** /dev/null Sat May 3 15:25:38 2003
--- src/libc/dos/dir/getshare.txh Wed Apr 2 13:31:52 2003
***************
*** 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
*** /dev/null Sat May 3 15:25:38 2003
--- src/libc/posix/sys/stat/unc_map.c Sat May 3 15:10:42 2003
***************
*** 0 ****
--- 1,206 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+ #include <stdio.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <errno.h>
+ #include <limits.h>
+ #include <time.h>
+ #include <dir.h>
+ #include <sys/stat.h>
+ #include <libc/bss.h>
+
+ /* Holds the last seen value of __bss_count, to be safe for
+ * restarted programs (emacs). */
+ static int mappings_count = 0;
+
+ /* 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;
+
+ static void
+ mappings_init (void)
+ {
+ if (mappings_count != __bss_count)
+ {
+ mappings_count = __bss_count;
+ drive_mappings = NULL;
+ }
+ }
+
+ static void
+ mappings_check_for_update (void)
+ {
+ clock_t t;
+
+ mappings_init();
+
+ /*
+ * 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.
+ *
+ * The mappings may get updated behind this module's back, 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();
+ }
+ }
+
+ /*
+ * 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'.
+ */
+
+ const char *
+ __find_mapping_for_unc (const char *src, char *dest)
+ {
+ int is_unc = 1;
+ drive_mapping *m = NULL;
+ int i;
+
+ 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;
+
+ mappings_check_for_update();
+
+ 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;
+ }
+
+ const char *
+ __find_mapping_to_unc (const char *src, char *dest)
+ {
+ int drive = -1;
+ drive_mapping *m = NULL;
+ char cwd[FILENAME_MAX];
+ char fixbuf[FILENAME_MAX];
+ int i;
+
+ if (src[0] && (src[1] == ':'))
+ {
+ drive = src[0];
+ }
+ else
+ {
+ if (getcwd(cwd, sizeof(cwd)) != NULL)
+ {
+ drive = cwd[0];
+ }
+ }
+
+ /* No drive information => just return original. */
+ if (drive == -1)
+ return src;
+
+ /* Find a mapping for this drive, if any. */
+ if ((drive >= 'a') || (drive <= 'z'))
+ drive -= 'a';
+ else
+ drive -= 'A';
+
+ mappings_check_for_update();
+
+ for (i = 0; drive_mappings[i] != NULL; i++)
+ {
+ if (drive_mappings[i]->drive == drive)
+ {
+ m = drive_mappings[i];
+ break;
+ }
+ }
+
+ if (m == NULL)
+ return src;
+
+ /* We have a mapping. Fix up the path first, so we can expand
+ * the drive letter without worrying about relative paths. */
+ _fixpath(src, fixbuf);
+
+ if ((strlen(fixbuf) - 2 + strlen(m->share) + 1 /* nul */) > FILENAME_MAX)
+ {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+
+ strcpy(dest, m->share);
+ strcat(dest, fixbuf + 2); /* skip X: */
+
+ return dest;
+ }
+
+ #ifdef TEST
+
+ #include <stdlib.h>
+
+ int
+ main (int argc, char *argv[])
+ {
+ char buf[FILENAME_MAX];
+ const char *p;
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ p = NULL;
+
+ if (strcmp(argv[i], "--from-unc") == 0)
+ {
+ i++;
+ p = __find_mapping_for_unc(argv[i], buf);
+ }
+ else if (strcmp(argv[i], "--to-unc") == 0)
+ {
+ i++;
+ p = __find_mapping_to_unc(argv[i], buf);
+ }
+ else
+ {
+ fprintf(stderr, "Unknown parameter '%s' - ignoring\n", argv[i]);
+ }
+
+ if (p != NULL)
+ printf("%s -> %s\n", argv[i], p);
+ }
+
+ return EXIT_SUCCESS;
+ }
+
+ #endif /* TEST */
*** /dev/null Sat May 3 15:25:38 2003
--- src/libc/posix/sys/stat/unc_map.txh Sat May 3 15:22:42 2003
***************
*** 0 ****
--- 1,67 ----
+ @node __find_mapping_for_unc, file system
+ @findex __find_mapping_for_unc
+
+ @subheading Syntax
+
+ @example
+ #include <sys/stat.h>
+
+ const char *__find_mapping_for_unc(const char *src, char *dest);
+ @end example
+
+ @subheading Description
+
+ This internal function collapses UNC paths like
+ @file{\\machine\share\somefile.txt} into normal drive-letter-qualified
+ paths like @file{x:\somefile.txt}, where possible. If no drive mapping
+ exists for the UNC path, then it will not modify the filename.
+
+ The caller should ensure there is enough space in the buffer pointed to by
+ @var{dest}. Using ANSI-standard constant @code{FILENAME_MAX}
+ (defined on @file{stdio.h}) or Posix-standard constant @code{PATH_MAX}
+ (defined on @file{limits.h}) for the buffer size is recommended.
+
+ @subheading Return Value
+
+ A pointer to the filename, with a drive letter, if possible. If a mapping
+ was not found, then the original filename is returned.
+
+ @subheading Portability
+
+ @portability !ansi, !posix
+
+ @node __find_mapping_to_unc, file system
+ @findex __find_mapping_to_unc
+
+ @subheading Syntax
+
+ @example
+ #include <sys/stat.h>
+
+ const char *__find_mapping_to_unc(const char *src, char *dest);
+ @end example
+
+ @subheading Description
+
+ This internal function expands drive-letter-qualified paths like
+ @file{x:\somefile.txt} into UNC paths like
+ @file{\\machine\share\somefile.txt}, where possible. If no drive mapping
+ exists for the UNC path, then it will not modify the filename.
+
+ Since the returned path name can be longer than the original one, the
+ caller should ensure there is enough space in the buffer pointed to by
+ @var{dest}. Using ANSI-standard constant @code{FILENAME_MAX}
+ (defined on @file{stdio.h}) or Posix-standard constant @code{PATH_MAX}
+ (defined on @file{limits.h}) for the buffer size is recommended.
+
+ @subheading Return Value
+
+ A pointer to the filename, converted to a UNC, if possible. If a mapping
+ was not found, then the original filename is returned.
+
+ If the length of the returned path name exceeds @code{FILENAME_MAX},
+ @code{NULL} is returned and @code{errno} is set to @code{ENAMETOOLONG}.
+
+ @subheading Portability
+
+ @portability !ansi, !posix
- Raw text -