Will Coleda via RT wrote:
On Tue Jul 22 23:34:13 2008, [EMAIL PROTECTED] wrote:
Christoph Otto via RT wrote:
This version of the patch should dtrt with all versions of
strerror_r. It
works on my Debian/x86 box and I'll be testing it on any *nix I can
get my
hands on Tuesday. If it works fine there, if someone can test it on
windows
and if the patch looks OK, I'll commit it and close this ticket.
Christoph
This patch contains a fix and a simplification. It should now be
cross-platform and thread-safe. I'll test on some other *nixes and go
on from
there. If nothing else it works fine on Ubuntu/x86.
Based on Christoph's instructions in #parrot, I tested this using an MSVC compiler, with the
following results:
<snip explodey brokenness>
Here's v8 of the patch. After poking around on gcc/win, msvc and gcc/linux
I'm pretty sure this will at least pass all tests on all those platforms and
anything else that has a sufficiently POSIXy strerror_r. Unfortunately it
seems that strerror_s (MS' strerror_r) isn't available to gcc on windows, so
that platform may be stuck with a non-thread-safe file PMC. An updated patch
proving me wrong would be welcome.
It'd be good to get this patch reviewed before it's applied, but the main goal
is to get all tests passing on Linux/gcc, msvc and win/gcc.
Index: src/pmc/file.pmc
===================================================================
--- src/pmc/file.pmc (revision 30979)
+++ src/pmc/file.pmc (working copy)
@@ -24,8 +24,56 @@
#include "parrot/parrot.h"
-/* RT#46681 apparently, strerror_r is thread-safe and should be used instead.*/
+/* strerror_r should truncate the message if it's too long for the supplied
+ * buffer. It's probably best to just specify a sane default buffer size than
+ * to worry about retrying calls. */
+#define ERRBUF_SIZE 128
+/* use POSIXy strerror_r (*nix) or strerror_s macro (msvc)*/
+#if (!defined(WIN32) && !defined(_GNU_SOURCE)) || \
+ (defined(_MSC_VER) && defined(WIN32))
+# define THROW_FILE_EXCEPTION(interp, func) \
+ { \
+ char errmsg[ERRBUF_SIZE]; \
+ int err_status; \
+ err_status = strerror_r(errno, errmsg, ERRBUF_SIZE); \
+ /* Linux's POSIXy strerror_r returns -1 on error, others return an error code */ \
+ if (err_status == -1) \
+ err_status = errno; \
+ \
+ if (err_status == 0 || err_status == ERANGE) { \
+ Parrot_ex_throw_from_c_args(\
+ (interp), NULL, EXCEPTION_LIBRARY_ERROR, "%s", errmsg); \
+ } \
+ else if (err_status == EINVAL){ \
+ Parrot_ex_throw_from_c_args((interp), NULL, EXCEPTION_LIBRARY_ERROR, \
+ "%s returned an invalid error code (%d)", #func, errno); \
+ } \
+ else { \
+ Parrot_ex_throw_from_c_args((interp), NULL, EXCEPTION_LIBRARY_ERROR, \
+ "strerror_r() returned an unknown error code: %d", err_status); \
+ } \
+ }
+
+/* use GNU-specific strerror_r */
+#elif defined(_GNU_SOURCE)
+# define THROW_FILE_EXCEPTION(interp, func) \
+ { \
+ /* GNU strerror_r DTRT for unknown error codes */ \
+ char errmsg[ERRBUF_SIZE]; \
+ char *errstr = strerror_r(errno, errmsg, ERRBUF_SIZE); \
+ Parrot_ex_throw_from_c_args((interp), NULL, EXCEPTION_LIBRARY_ERROR, "%s", errstr); \
+ }
+
+/* using gcc on windows, so we're stuck with plain strerror */
+#else
+# define THROW_FILE_EXCEPTION(interp, func) \
+ { \
+ char *errmsg = strerror(errno); \
+ Parrot_ex_throw_from_c_args((interp), NULL, EXCEPTION_LIBRARY_ERROR, "%s",errmsg); \
+ }
+#endif
+
static PMC *File_PMC;
pmclass File singleton {
@@ -73,9 +121,18 @@
#endif
string_cstring_free(cpath);
- if (error)
+ if (error && errno == ENOENT) {
RETURN(INTVAL 0);
+ }
+ else if (error) {
+#ifdef WIN32
+ THROW_FILE_EXCEPTION(INTERP, stat);
+#else
+ THROW_FILE_EXCEPTION(INTERP, lstat);
+#endif
+ }
+
RETURN(INTVAL 1);
}
@@ -89,6 +146,7 @@
*/
+
METHOD is_dir(STRING *path) {
struct stat info;
char *cpath = string_to_cstring(interp, path);
@@ -100,9 +158,11 @@
string_cstring_free(cpath);
if (error) {
- char *errmsg = strerror(errno);
- Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
- errmsg);
+#ifdef WIN32
+ THROW_FILE_EXCEPTION(INTERP, stat);
+#else
+ THROW_FILE_EXCEPTION(INTERP, lstat);
+#endif
}
if (S_ISDIR(info.st_mode))
@@ -132,9 +192,11 @@
string_cstring_free(cpath);
if (error) {
- char *errmsg = strerror(errno);
- Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
- errmsg);
+#ifdef WIN32
+ THROW_FILE_EXCEPTION(INTERP, stat);
+#else
+ THROW_FILE_EXCEPTION(INTERP, lstat);
+#endif
}
if (S_ISREG(info.st_mode))
@@ -155,20 +217,20 @@
METHOD is_link(STRING *path) {
#ifdef WIN32
- /* I love win32 implementations */
+ /* I love win32. */
RETURN(INTVAL 0);
#else
struct stat info;
+ char *cpath;
+ int error;
- char *cpath = string_to_cstring(interp, path);
- int error = lstat(cpath, &info);
+ cpath = string_to_cstring(interp, path);
+ error = lstat(cpath, &info);
string_cstring_free(cpath);
if (error) {
- char *errmsg = strerror(errno);
- Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
- errmsg);
+ THROW_FILE_EXCEPTION(INTERP, lstat);
}
if (S_ISLNK(info.st_mode))
@@ -197,11 +259,13 @@
METHOD copy(STRING *from, STRING *to) {
#define CHUNK_SIZE 1024
+ char errmsg[ERRBUF_SIZE];
char *cfrom = string_to_cstring(interp, from);
FILE *source = fopen(cfrom, "rb");
string_cstring_free(cfrom);
+
if (source) {
char *cto = string_to_cstring(interp, to);
FILE *target = fopen(cto, "w+b");
@@ -226,16 +290,12 @@
fclose(target);
}
else {
- char *errmsg = strerror(errno);
- Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
- errmsg);
+ THROW_FILE_EXCEPTION(INTERP, fopen);
}
fclose(source);
}
else {
- char *errmsg = strerror(errno);
- Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
- errmsg);
+ THROW_FILE_EXCEPTION(INTERP, fopen);
}
#undef CHUNK_SIZE
}
@@ -259,9 +319,7 @@
string_cstring_free(cto);
if (error) {
- char *errmsg = strerror(errno);
- Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
- errmsg);
+ THROW_FILE_EXCEPTION(INTERP, rename);
}
}
}
Index: config/gen/platform/win32/string.h
===================================================================
--- config/gen/platform/win32/string.h (revision 30979)
+++ config/gen/platform/win32/string.h (working copy)
@@ -12,6 +12,8 @@
# if _MSC_VER >= 1400
# define strdup _strdup
# endif
+/* This is only useful with msvc. gcc/mingw can't use strerror_s afaict. */
+# define strerror_r(errnum, buf, buflen) strerror_s((buf), (buflen), (errnum))
#endif
#endif /* PARROT_PLATFORM_WIN32_STRING_H_GUARD */