Re: errno patches for Windows

2003-10-17 Thread Hrvoje Niksic
Gisle Vanem [EMAIL PROTECTED] writes:

 #ifndef ENOTCONN
 # define ENOTCONN X_ENOTCONN
 #endif

 Except you cannot make Winsock return X_ENOTCONN.

But we don't really care because we're in control of what gets stores
into errno after Winsock calls.  So instead of:

  errno = WSAGetLastError ();

windows_select and friends can go ahead and say:

  errno = winsock_error_to_errno (WSAGetLastError ());

winsock_error_to_errno and esaily convert Winsock errors to errno
errors expected by the rest of Wget, adding support for the missing
ones such as ENOTCONN.

 It returns WSAENOTCONN (def'ed to ENOTCONN in mswindows.h).

If we do this, we should probably remove those defines.  They would no
longer be needed.

 const char *
 windows_strerror (int err)
 {
   /* Leave the standard ones to strerror. */
   if (err  X_ERRBASE)
 return strerror (err);
 
   /* Handle the unsupported ones manually. */
   switch (err)
 {
   case X_ENOTCONN:
 return Connection refused;

 Which AFAICS is the pretty much the same as in my patch.

One difference is that your patch requires the use of special
GET_ERRNO and SET_ERRNO codes that I'm trying to avoid.  Another is
that windows_strerror calls real strerror for everything except for
the few error codes which really are unavailable under Windows, such
as ENOTCONN.  This should (I think) remove the need for the large
switch you have in get_winsock_error.

 Another thing is that Wget could mask errnos for Unix too. In
 connect.c:

  ...
{
  CLOSE (sock);
  sock = -1;
  goto out;
}

 out:
 ...
  else
{
  save_errno = errno;
  if (!silent)
logprintf (LOG_VERBOSE, failed: %s.\n, strerror (errno));
  errno = save_errno;
}

 The close() could possibly set errno too, but we want the errno 
 from bind() or connect() don't we?

For close() to set errno, it would have to fail, and that should not
be possible in normal operation.  (Unlike fclose, close cannot write
data, it should just tell kernel to get rid of the descriptor.)  If
close really fails, then something is seriously wrong and we care
about the errno from close at least as much as we care about errno
from connect or bind.  In practice it probably doesn't make sense to
care about close setting errno.


Re: errno patches for Windows

2003-10-16 Thread Hrvoje Niksic
[ Moving discussion from wget-patches to wget. ]

Gisle Vanem [EMAIL PROTECTED] writes:

 I'm pretty sure that other GNU applications -- that have also been
 ported to Windows -- use errno.  I wonder how they do it...

 Lynx uses this:
   #define SOCKET_ERRNO errno
   #ifdef WINDOWS
   #undef  SOCKET_ERRNO 
   #define SOCKET_ERRNOWSAGetLastError()
   ..

 and never errno for network calls directly.  But then again, it
 never *sets* errno as Wget do.

OK.  So the whole thing with errno is only necessary when dealing with
Winsock errors.  For errors from, say, fopen it's fine to use errno?

There is another possible approach.  We already #define read and write
to call Winsock stuff.  We could add some more magic so that they and
other Winsock invocations automatically set errno to last error value,
translating Windows errors to errno errors.  XEmacs has code that
seems to support that kind of translation (Winsock errors might need
to be handled separately, but they could be added) -- please take a
look:

struct errentry {
  unsigned long oscode;  /* Win32 error */
  int errnocode; /* unix errno */
};

static struct errentry errtable[] = {
  {  ERROR_INVALID_FUNCTION,   EINVAL},  /* 1 */
  {  ERROR_FILE_NOT_FOUND, ENOENT},  /* 2 */
  {  ERROR_PATH_NOT_FOUND, ENOENT},  /* 3 */
  {  ERROR_TOO_MANY_OPEN_FILES,EMFILE},  /* 4 */
  {  ERROR_ACCESS_DENIED,  EACCES},  /* 5 */
  {  ERROR_INVALID_HANDLE, EBADF },  /* 6 */
  {  ERROR_ARENA_TRASHED,  ENOMEM},  /* 7 */
  {  ERROR_NOT_ENOUGH_MEMORY,  ENOMEM},  /* 8 */
  {  ERROR_INVALID_BLOCK,  ENOMEM},  /* 9 */
  {  ERROR_BAD_ENVIRONMENT,E2BIG },  /* 10 */
  {  ERROR_BAD_FORMAT, ENOEXEC   },  /* 11 */
  {  ERROR_INVALID_ACCESS, EINVAL},  /* 12 */
  {  ERROR_INVALID_DATA,   EINVAL},  /* 13 */
  {  ERROR_INVALID_DRIVE,  ENOENT},  /* 15 */
  {  ERROR_CURRENT_DIRECTORY,  EACCES},  /* 16 */
  {  ERROR_NOT_SAME_DEVICE,EXDEV },  /* 17 */
  {  ERROR_NO_MORE_FILES,  ENOENT},  /* 18 */
  {  ERROR_LOCK_VIOLATION, EACCES},  /* 33 */
  {  ERROR_BAD_NETPATH,ENOENT},  /* 53 */
  {  ERROR_NETWORK_ACCESS_DENIED,  EACCES},  /* 65 */
  {  ERROR_BAD_NET_NAME,   ENOENT},  /* 67 */
  {  ERROR_FILE_EXISTS,EEXIST},  /* 80 */
  {  ERROR_CANNOT_MAKE,EACCES},  /* 82 */
  {  ERROR_FAIL_I24,   EACCES},  /* 83 */
  {  ERROR_INVALID_PARAMETER,  EINVAL},  /* 87 */
  {  ERROR_NO_PROC_SLOTS,  EAGAIN},  /* 89 */
  {  ERROR_DRIVE_LOCKED,   EACCES},  /* 108 */
  {  ERROR_BROKEN_PIPE,EPIPE },  /* 109 */
  {  ERROR_DISK_FULL,  ENOSPC},  /* 112 */
  {  ERROR_INVALID_TARGET_HANDLE,  EBADF },  /* 114 */
  {  ERROR_INVALID_HANDLE, EINVAL},  /* 124 */
  {  ERROR_WAIT_NO_CHILDREN,   ECHILD},  /* 128 */
  {  ERROR_CHILD_NOT_COMPLETE, ECHILD},  /* 129 */
  {  ERROR_DIRECT_ACCESS_HANDLE,   EBADF },  /* 130 */
  {  ERROR_NEGATIVE_SEEK,  EINVAL},  /* 131 */
  {  ERROR_SEEK_ON_DEVICE, EACCES},  /* 132 */
  {  ERROR_DIR_NOT_EMPTY,  ENOTEMPTY },  /* 145 */
  {  ERROR_NOT_LOCKED, EACCES},  /* 158 */
  {  ERROR_BAD_PATHNAME,   ENOENT},  /* 161 */
  {  ERROR_MAX_THRDS_REACHED,  EAGAIN},  /* 164 */
  {  ERROR_LOCK_FAILED,EACCES},  /* 167 */
  {  ERROR_ALREADY_EXISTS, EEXIST},  /* 183 */
  {  ERROR_FILENAME_EXCED_RANGE,   ENOENT},  /* 206 */
  {  ERROR_NESTING_NOT_ALLOWED,EAGAIN},  /* 215 */
  {  ERROR_NOT_ENOUGH_QUOTA,   ENOMEM}/* 1816 */
};

/* The following two constants must be the minimum and maximum
   values in the (contiguous) range of Exec Failure errors. */
#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN

/* These are the low and high value in the range of errors that are
   access violations */
#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED

void
mswindows_set_errno (unsigned long win32_error)
{
  int i;

  /* check the table for the OS error code */
  for (i = 0; i  countof (errtable); ++i)
{
  if (win32_error == errtable[i].oscode)
{
  errno = errtable[i].errnocode;
  return;
}
}

  /* The error code wasn't in the table.  We check for a range of
   * EACCES errors or exec failure errors (ENOEXEC).  Otherwise EINVAL is
   * returned. */
  if (win32_error = MIN_EACCES_RANGE  win32_error = MAX_EACCES_RANGE)
errno = EACCES;
  else if (win32_error = MIN_EXEC_ERROR  win32_error = MAX_EXEC_ERROR)
errno = ENOEXEC;
  else
errno = EINVAL;
}

void
mswindows_set_last_errno (void)
{
  mswindows_set_errno (GetLastError ());
}



Re: errno patches for Windows

2003-10-16 Thread Gisle Vanem
Hrvoje Niksic [EMAIL PROTECTED] said:

 OK.  So the whole thing with errno is only necessary when dealing with
 Winsock errors.  For errors from, say, fopen it's fine to use errno?

Yes.
 
 There is another possible approach.  We already #define read and write
 to call Winsock stuff.  We could add some more magic so that they and
 other Winsock invocations automatically set errno to last error value,
 translating Windows errors to errno errors. 

Then all Winsock functions must be wrapped in such macro.
E.g (untested):
#define SOCK_SELECT(fd,rd,wr,ex,tv)  ( \
int _rc = select (fd,rd,wr,ex,tv), \
(int)(WSAGetLastError() ? (errno = WSAGetLastError()) : (0)), \
_rc)

which could get messy; hard to return with a value from such a
macro.

 static struct errentry errtable[] = {
   {  ERROR_INVALID_FUNCTION,   EINVAL},  /* 1 */
   {  ERROR_FILE_NOT_FOUND, ENOENT},  /* 2 */

XEmacs is probably using native Win functions (e.g CreateFile
instead of fopen), so it needs to map them to Unix errnos. Wget only 
uses ANSI/Winsock functions, so only WS errors need attention.

Besides, on Windows there is no suiteable errno.h value for
e.g. ENOTCONN; we must use the winsock*.h value WSAENOTCONN.
So the XEmacs method wouldn't work.

--gv



Re: errno patches for Windows

2003-10-16 Thread Hrvoje Niksic
Gisle Vanem [EMAIL PROTECTED] writes:

 There is another possible approach.  We already #define read and write
 to call Winsock stuff.  We could add some more magic so that they and
 other Winsock invocations automatically set errno to last error value,
 translating Windows errors to errno errors. 

 Then all Winsock functions must be wrapped in such macro.
 E.g (untested):
 #define SOCK_SELECT(fd,rd,wr,ex,tv)  ( \
 int _rc = select (fd,rd,wr,ex,tv), \
 (int)(WSAGetLastError() ? (errno = WSAGetLastError()) : (0)), \
 _rc)

 which could get messy; hard to return with a value from such a
 macro.

How about:

#ifdef WINDOWS
# define select(a, b, c, d) windows_select (a, b, c, d)
#endif

windows_select can be a function defined in mswindows.c that calls
select, performs the necessary error-handling magic, and (easily)
returns a value.  BTW errno should only be modified if _rc0.

 static struct errentry errtable[] = {
   {  ERROR_INVALID_FUNCTION,   EINVAL},  /* 1 */
   {  ERROR_FILE_NOT_FOUND, ENOENT},  /* 2 */

 XEmacs is probably using native Win functions (e.g CreateFile
 instead of fopen), so it needs to map them to Unix errnos.

I believe it calls them in some places, and there it calls
mswindows_set_last_errno to fix up errno in case the callers inspect
it.  This is similar to the strategy I'd like to use in Wget.

 Wget only uses ANSI/Winsock functions, so only WS errors need
 attention.

OK.

 Besides, on Windows there is no suiteable errno.h value for
 e.g. ENOTCONN; we must use the winsock*.h value WSAENOTCONN.  So
 the XEmacs method wouldn't work.

Note that we could always add a version of strerror that supports
those.  For example:

/* mswindows.h */

enum { X_ERRBASE = 1, X_ENOTCONN = 10001, ... };

#ifndef ENOTCONN
# define ENOTCONN X_ENOTCONN
#endif
...

#define strerror(n) windows_strerror (n)

/* mswindows.c */

#undef strerror /* we want the real one here */

const char *
windows_strerror (int err)
{
  /* Leave the standard ones to strerror. */
  if (err  X_ERRBASE)
return strerror (err);

  /* Handle the unsupported ones manually. */
  switch (err)
{
  case X_ENOTCONN:
return Connection refused;
  ...
  default:
abort ();
}
  return NULL;
}

I know this looks like an unnecessary contortion at first, but Wget
*is* targeted to primarily support Unix-like OS'es, specifically GNU.
In this case I believe it makes sense to make the Windows-specific
code more complex to reduce the complexity in the code that assumes
Unix API's.



Re: errno patches for Windows

2003-10-16 Thread Gisle Vanem
Hrvoje Niksic [EMAIL PROTECTED] said:

 #ifdef WINDOWS
 # define select(a, b, c, d) windows_select (a, b, c, d)
 #endif

Okay by me.
 
 #ifndef ENOTCONN
 # define ENOTCONN X_ENOTCONN
 #endif

Except you cannot make Winsock return X_ENOTCONN.
It returns WSAENOTCONN (def'ed to ENOTCONN in
mswindows.h). Winsock errors are in the range
WSABASEERR (1) to 11031 with some holes in
the range.

 const char *
 windows_strerror (int err)
 {
   /* Leave the standard ones to strerror. */
   if (err  X_ERRBASE)
 return strerror (err);
 
   /* Handle the unsupported ones manually. */
   switch (err)
 {
   case X_ENOTCONN:
 return Connection refused;

Which AFAICS is the pretty much the same as in my patch.

Another thing is that Wget could mask errnos for Unix
too. In connect.c:

 ...
   {
 CLOSE (sock);
 sock = -1;
 goto out;
   }

out:
...
 else
   {
 save_errno = errno;
 if (!silent)
   logprintf (LOG_VERBOSE, failed: %s.\n, strerror (errno));
 errno = save_errno;
   }

The close() could possibly set errno too, but we want the errno 
from bind() or connect() don't we?

--gv