-fskeletons-copy

diff --git a/libasn1compiler/asn1c_compat.c b/libasn1compiler/asn1c_compat.c
index 2a80251..b393d6d 100644
--- a/libasn1compiler/asn1c_compat.c
+++ b/libasn1compiler/asn1c_compat.c
@@ -80,12 +80,19 @@
 	if(fp == NULL) {
 		if(created) unlink(fname);
 		close(fd);
+		return NULL;
 	}
 
 	/* Return the temporary file name */
 	if(opt_tmpname) {
 		*opt_tmpname = strdup(fname);
-		assert(*opt_tmpname);
+		if(*opt_tmpname) {
+			/* Successfull */
+		} else {
+			if(created) unlink(fname);
+			fclose(fp);
+			return NULL;
+		}
 	}
 
 	return fp;
diff --git a/libasn1compiler/asn1c_save.c b/libasn1compiler/asn1c_save.c
index e0a2f67..d35db94 100644
--- a/libasn1compiler/asn1c_save.c
+++ b/libasn1compiler/asn1c_save.c
@@ -280,6 +280,8 @@
 		if(rename(tmpname_c, name_buf)) {
 			unlink(tmpname_c);
 			perror(tmpname_c);
+			free(tmpname_c);
+			free(tmpname_h);
 			return -1;
 		}
 	}
@@ -292,6 +294,8 @@
 		if(rename(tmpname_h, name_buf)) {
 			unlink(tmpname_h);
 			perror(tmpname_h);
+			free(tmpname_c);
+			free(tmpname_h);
 			return -1;
 		}
 	}
@@ -308,11 +312,20 @@
 
 static int
 identical_files(const char *fname1, const char *fname2) {
-	char buf[2][8192];
+	char buf[2][4096];
 	FILE *fp1, *fp2;
 	size_t olen, nlen;
 	int retval = 1;	/* Files are identical */
 
+#ifndef	WIN32
+	struct stat sb;
+
+	if(lstat(fname1, &sb) || !S_ISREG(sb.st_mode)
+	|| lstat(fname2, &sb) || !S_ISREG(sb.st_mode)) {
+		return 0;	/* Files are not identical */
+	}
+#endif
+
 	fp1 = fopen(fname1, "r");
 	if(!fp1) { return 0; }
 	fp2 = fopen(fname2, "r");
@@ -338,7 +351,8 @@
  */
 static int
 real_copy(const char *src, const char *dst) {
-	unsigned char buf[8192];
+	unsigned char buf[4096];
+	char *tmpname;
 	FILE *fpsrc, *fpdst;
 	size_t len;
 	int retval = 0;
@@ -348,36 +362,45 @@
 
 	fpsrc = fopen(src, "r");
 	if(!fpsrc) { errno = EIO; return -1; }
-	fpdst = asn1c_open_file(dst, "", 0);
+	fpdst = asn1c_open_file(dst, "", &tmpname);
 	if(!fpdst) { fclose(fpsrc); errno = EIO; return -1; }
 
 	while(!feof(fpsrc)) {
 		len = fread(buf, 1, sizeof(buf), fpsrc);
 		if(fwrite(buf, 1, len, fpdst) != len) {
+			perror(tmpname);
 			errno = EIO;
 			retval = -1;
 			break;
 		}
 	}
-
 	fclose(fpsrc);
 	fclose(fpdst);
+
+	/* Check if copied correctly, and rename into a permanent name */
+	if(retval) {
+		unlink(tmpname);
+	} else if(rename(tmpname, dst)) {
+		unlink(tmpname);
+		perror(tmpname);
+		retval = -1;
+	}
+	free(tmpname);
 	return retval;
 }
 
 static int
 asn1c_copy_over(arg_t *arg, char *path) {
 	char *fname;
-
-	(void)arg;	/* Unused argument */
+#ifdef	WIN32
+	int use_real_copy = 1;
+#else
+	int use_real_copy = (arg->flags & A1C_SKELETONS_COPY);
+#endif
 
 	fname = a1c_basename(path);
 	if(!fname
-#ifdef	WIN32
-		|| real_copy(path, fname)
-#else
-		|| (1 ? symlink(path, fname) : real_copy(path, fname))
-#endif
+	|| (use_real_copy ? real_copy(path, fname) : symlink(path, fname))
 	) {
 		if(errno == EEXIST) {
 			struct stat sb1, sb2;
@@ -402,13 +425,15 @@
 			/* Ignore this */
 			return 0;
 		} else {
-			fprintf(stderr, "Symlink %s -> %s failed: %s\n",
+			fprintf(stderr, "%s %s -> %s failed: %s\n",
+				use_real_copy ? "Copy" : "Symlink",
 				path, fname, strerror(errno));
 			return -1;
 		}
 	}
 
-	fprintf(stderr, "Symlinked %s\t-> %s\n", path, fname);
+	fprintf(stderr, "%s %s\t-> %s\n",
+		use_real_copy ? "Copied" : "Symlinked", path, fname);
 
 	return 1;
 }
diff --git a/libasn1compiler/asn1compiler.h b/libasn1compiler/asn1compiler.h
index e688018..847300f 100644
--- a/libasn1compiler/asn1compiler.h
+++ b/libasn1compiler/asn1compiler.h
@@ -51,6 +51,11 @@
 	 * Compile members of CHOICE as indirect pointers.
 	 */
 	A1C_INDIRECT_CHOICE	= 0x0400,
+	/*
+	 * -fskeletons-copy
+	 * Copy support files rather than symlink them.
+	 */
+	A1C_SKELETONS_COPY	= 0x0800,
 };
 
 /*