X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f From: To: djgpp AT delorie DOT com Subject: network files unc under windows xp Date: Sun, 12 Dec 2004 17:16:34 +0200 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=____1102864594009_u)0iT_6e-o" Message-Id: <20041212151634.CMIQ11445.fep4@[212.117.129.234]> Reply-To: djgpp AT delorie DOT com This is a multi-part message in MIME format. ------=____1102864594009_u)0iT_6e-o Content-Type: text/plain; charset=windows-1255 Content-Transfer-Encoding: 7bit i have recently run into a failure to open unc named files locate on a network, when the os is windows xp. unc file format: \\servername\directory_tree\filename. this occures with files named //servername/..., which is the default notation under djgpp (e.g., argv[0]). thus, every filename should have the path separator converted to '\', before been submitted to open(), access(), etc. fortunately, there is a routine in the djdev source tree, which is been called before any os file access: putpath(). the djdev source tree may be downloaded at ftp://ftp.delorie.com/pub/djgpp/current/v2/djlsr203.zip, and src/libc/dos/io/putpath.c should be applied the following patch: --- /dosdev/djgpp/src/libc/dos/io/putpath.c 1999-06-03 13:27:36.000000000 +0000 +++ ./putpath.c 2004-12-12 17:06:30.000000000 +0000 @@ -144,12 +144,17 @@ path = p + 5; } + for (p = path; *p; ++p) + { + if (*p == '/') + *p = '\\'; + } /* collapse multiple slashes to a single slash */ - for (; *path; path++) + for (p = path; *p; ++p) { - if (path[0] != '/' || path[1] != '/') + if (*p != '\\' || *(p + 1) != '\\' || p == path) { - _farnspokeb(o, *path); + _farnspokeb(o, *p); o++; if (--space < 2) /* safety check */ break; @@ -159,7 +164,7 @@ /* remove trailing slash if it doesn't represent the root directory */ if (o-2 >= __tb+offset - && _farnspeekb(o-1) == '/' + && _farnspeekb(o-1) == '\\' && _farnspeekb(o-2) != ':') o--; best would be to re-make the whole libc, but even mere linking of the patched putpath.c (included for your convenience) in your project will do the magic. of course, this solution will help with dos compatible file systems only, but we are dealing with dos software. best regards, alex ------=____1102864594009_u)0iT_6e-o Content-Type: text/plain; name="putpath.c" Content-Disposition: inline; filename="putpath.c" /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include #include #include #include #include #include static const char env_delim = '~'; /* Can't use stackavail, since it pollutes the namespace... */ static int __inline__ enough_stack_p(void) { extern unsigned __djgpp_stack_limit; unsigned sp; __asm__ __volatile__ ("movl %%esp,%k0\n" : "=r" (sp) : ); return (int) (sp - __djgpp_stack_limit) > 4*1024; } int _put_path(const char *path) { return _put_path2(path, 0); } int _put_path2(const char *path, int offset) { int o = __tb+offset; int space = _go32_info_block.size_of_transfer_buffer - offset; const char *p = path; if (path == 0) { errno = EFAULT; abort(); } _farsetsel(_dos_ds); if (p[0] && p[1] == ':') p += 2; if (strncmp(p, "/dev/", 5) == 0) { if (strcmp(p+5, "null") == 0) path = "nul"; else if (strcmp(p+5, "tty") == 0) path = "con"; else if (((p[5] >= 'a' && p[5] <= 'z') || (p[5] >= 'A' && p[5] <= 'Z')) && (p[6] == '/' || p[6] == '\\' || p[6] == '\0')) { /* map /dev/a/ to a:/ */ _farnspokeb(o++, p[5]); _farnspokeb(o++, ':'); path = p + 6; space -= 2; } else if (strncmp(p+5, "env", 3) == 0 && (p[8] == '/' || p[8] == '\\') && p[9]) { /* /dev/env/FOO/bar: expand env var FOO and generate %FOO%/bar */ char *var_name, *d; char *var_value; int new_offset; int use_default = 1; int c; p += 9; /* point to the beginning of the variable name */ var_name = alloca(strlen (p) + 1); for (d = var_name; *p && *p != '/' && *p != '\\'; *d++ = *p++) if (*p == env_delim) { if (p[1] == env_delim) /* two ~ in a row mean a literal ~ */ p++; else break; } *d = '\0'; var_value = getenv(d = var_name); if (var_value && *var_value) { /* The value of the env var can include special constructs like /dev/x/foo or even a reference to another env var, so we need to recursively invoke ourselves. */ if (!enough_stack_p()) { /* This is probably a case of infinite recursion caused by a self-referencing /dev/env/foo value, in which case ENAMETOOLONG is probably right. But it could also happen if they were short on stack to begin with, in which case we would lie if we use ENAMETOOLONG. So: */ errno = ENOMEM; return offset; } new_offset = _put_path2(var_value, offset); space -= new_offset - offset; o += new_offset - offset; use_default = 0; } if (*p == env_delim) /* use or skip the default value if present */ { for (++p; *p; p++) { if (*p == env_delim) { if (p[1] == env_delim) p++; else break; } if (use_default) *d++ = *p; } if (use_default) { *d = '\0'; /* The default value may use special constructs as well. */ if (!enough_stack_p()) /* infinite recursion? */ { errno = ENOMEM; return offset; } new_offset = _put_path2(var_name, offset); space -= new_offset - offset; o += new_offset - offset; } if (*p == env_delim) /* a luser could forget the trailing '~' */ p++; } /* if the rest of path begins with a slash, remove the trailing slash in the transfer buffer */ if ((*p == '/' || *p == '\\') && o-1 >= __tb+offset && ((c = _farnspeekb(o-1)) == '/' || c == '\\')) o--; path = p; } else if (p[5]) path = p + 5; } for (p = path; *p; ++p) { if (*p == '/') *p = '\\'; } /* collapse multiple slashes to a single slash */ for (p = path; *p; ++p) { if (*p != '\\' || *(p + 1) != '\\' || p == path) { _farnspokeb(o, *p); o++; if (--space < 2) /* safety check */ break; } } /* remove trailing slash if it doesn't represent the root directory */ if (o-2 >= __tb+offset && _farnspeekb(o-1) == '\\' && _farnspeekb(o-2) != ':') o--; /* null terminate it */ _farnspokeb(o, 0); return o - __tb; } ------=____1102864594009_u)0iT_6e-o--