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.
Index: src/pmc/file.pmc
===================================================================
--- src/pmc/file.pmc (revision 29691)
+++ src/pmc/file.pmc (working copy)
@@ -24,8 +24,50 @@
#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
+#ifndef _GNU_SOURCE
+/* use POSIXy strerror_r */
+# define STRERROR_R_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) { \
+ STRING *errmsg_pstring = string_make((interp), errmsg, strlen(errmsg), NULL, 0); \
+ real_exception((interp), NULL, E_SystemError, "%Ss", errmsg_pstring); \
+ } \
+ else if (err_status == EINVAL){ \
+ real_exception((interp), NULL, E_SystemError, \
+ "%s returned an invalid error code (%d)", #func, errno); \
+ } \
+ else { \
+ real_exception((interp), NULL, E_SystemError, \
+ "strerror_r() returned an unknown error code: %d", err_status); \
+ } \
+ }
+#else
+/* use GNU-specific strerror_r */
+# define STRERROR_R_EXCEPTION(interp, func) \
+ { \
+ /* GNU strerror_r DTRT for unknown error codes */ \
+ char errmsg[ERRBUF_SIZE]; \
+ char *errstr = strerror_r(errno, errmsg, ERRBUF_SIZE); \
+ STRING *errmsg_pstring = string_make((interp), errstr, strlen(errstr), NULL, 0); \
+ real_exception((interp), NULL, E_SystemError, "%Ss", errmsg_pstring); \
+ }
+#endif
+
+
+
+
static PMC *File_PMC;
pmclass File singleton {
@@ -89,6 +131,7 @@
*/
+
METHOD is_dir(STRING *path) {
struct stat info;
char *cpath = string_to_cstring(interp, path);
@@ -100,8 +143,11 @@
string_cstring_free(cpath);
if (error) {
- char *errmsg = strerror(errno);
- real_exception(interp, NULL, E_SystemError, errmsg);
+#ifdef WIN32
+ STRERROR_R_EXCEPTION(INTERP, stat);
+#else
+ STRERROR_R_EXCEPTION(INTERP, lstat);
+#endif
}
if (S_ISDIR(info.st_mode))
@@ -131,8 +177,11 @@
string_cstring_free(cpath);
if (error) {
- char *errmsg = strerror(errno);
- real_exception(interp, NULL, E_SystemError, errmsg);
+#ifdef WIN32
+ STRERROR_R_EXCEPTION(INTERP, stat);
+#else
+ STRERROR_R_EXCEPTION(INTERP, lstat);
+#endif
}
if (S_ISREG(info.st_mode))
@@ -164,8 +213,7 @@
string_cstring_free(cpath);
if (error) {
- char *errmsg = strerror(errno);
- real_exception(interp, NULL, E_SystemError, errmsg);
+ STRERROR_R_EXCEPTION(INTERP, lstat);
}
if (S_ISLNK(info.st_mode))
@@ -199,6 +247,8 @@
string_cstring_free(cfrom);
+ char errmsg[ERRBUF_SIZE];
+
if (source) {
char *cto = string_to_cstring(interp, to);
FILE *target = fopen(cto, "w+b");
@@ -223,14 +273,12 @@
fclose(target);
}
else {
- char *errmsg = strerror(errno);
- real_exception(interp, NULL, E_SystemError, errmsg);
+ STRERROR_R_EXCEPTION(INTERP, fopen);
}
fclose(source);
}
else {
- char *errmsg = strerror(errno);
- real_exception(interp, NULL, E_SystemError, errmsg);
+ STRERROR_R_EXCEPTION(INTERP, fopen);
}
#undef CHUNK_SIZE
}
@@ -254,8 +302,7 @@
string_cstring_free(cto);
if (error) {
- char *errmsg = strerror(errno);
- real_exception(interp, NULL, E_SystemError, errmsg);
+ STRERROR_R_EXCEPTION(INTERP, rename);
}
}
}
Index: config/gen/platform/win32/string.h
===================================================================
--- config/gen/platform/win32/string.h (revision 29691)
+++ config/gen/platform/win32/string.h (working copy)
@@ -14,6 +14,8 @@
# endif
#endif
+#define strerror_r(errnum, buf, buflen) strerror_s((buf), (buflen), (errnum))
+
#endif /* PARROT_PLATFORM_WIN32_STRING_H_GUARD */
/*