diff --git a/src/fileio.c b/src/fileio.c
index d21d8993..52e9afef 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -100,11 +100,8 @@ static int fileio_num(struct fioparms * fio,
 		char * filename, FILE * f, AVRMEM * mem, int size,
 		FILEFMT fmt);
 
-static int fmt_autodetect(char * fname);
 
-
-
-char * fmtstr(FILEFMT format)
+char * fileio_fmtstr(FILEFMT format)
 {
   switch (format) {
     case FMT_AUTO : return "auto-detect"; break;
@@ -349,7 +346,7 @@ static int ihex2b(char * infile, FILE * inf,
           return -1;
         }
         nextaddr = ihex.loadofs + baseaddr - fileoffset;
-        if (nextaddr + ihex.reclen > bufsize) {
+        if (nextaddr + ihex.reclen > (unsigned) bufsize) {
           avrdude_message(MSG_INFO, "%s: ERROR: address 0x%04x out of range at line %d of %s\n",
                           progname, nextaddr+ihex.reclen, lineno, infile);
           return -1;
@@ -415,7 +412,6 @@ static int b2srec(unsigned char * inbuf, int bufsize,
   unsigned char * buf;
   unsigned int nextaddr;
   int n, nbytes, addr_width;
-  int i;
   unsigned char cksum;
 
   char * tmpl=0;
@@ -463,10 +459,10 @@ static int b2srec(unsigned char * inbuf, int bufsize,
 
       cksum += n + addr_width + 1;
 
-      for (i=addr_width; i>0; i--) 
+      for (int i=addr_width; i>0; i--)
         cksum += (nextaddr >> (i-1) * 8) & 0xff;
 
-      for (i=nextaddr; i<nextaddr + n; i++) {
+      for (unsigned i=nextaddr; i<nextaddr + n; i++) {
         fprintf(outf, "%02X", buf[i]);
         cksum += buf[i];
       }
@@ -497,7 +493,7 @@ static int b2srec(unsigned char * inbuf, int bufsize,
     addr_width = 3;
     tmpl="S9%02X%06X";
   }
-  else if (startaddr <= 0xffffffff) {
+  else if ((unsigned) startaddr <= 0xffffffff) {
     addr_width = 4;
     tmpl="S9%02X%08X";
   }
@@ -505,7 +501,7 @@ static int b2srec(unsigned char * inbuf, int bufsize,
   fprintf(outf, tmpl, n + addr_width + 1, nextaddr);
 
   cksum += n + addr_width +1;
-  for (i=addr_width; i>0; i--) 
+  for (int i=addr_width; i>0; i--)
     cksum += (nextaddr >> (i - 1) * 8) & 0xff;
   cksum = 0xff - cksum;
   fprintf(outf, "%02X\n", cksum);
@@ -600,7 +596,7 @@ static int srec2b(char * infile, FILE * inf,
   int len;
   struct ihexrec srec;
   int rc;
-  int reccount;
+  unsigned int reccount;
   unsigned char datarec;
 
   char * msg = 0;
@@ -690,7 +686,7 @@ static int srec2b(char * infile, FILE * inf,
         return -1;
       }
       nextaddr -= fileoffset;
-      if (nextaddr + srec.reclen > bufsize) {
+      if (nextaddr + srec.reclen > (unsigned) bufsize) {
         avrdude_message(MSG_INFO, msg, progname, nextaddr+srec.reclen, "",
                 lineno, infile);
         return -1;
@@ -1009,8 +1005,7 @@ static int elf2b(char * infile, FILE * inf,
        * ELF file region for these, and extract the actual byte to write
        * from it, using the "foff" offset obtained above.
        */
-      if (mem->size != 1 &&
-          sh->sh_size > mem->size) {
+      if (mem->size != 1 && sh->sh_size > (unsigned) mem->size) {
         avrdude_message(MSG_INFO, "%s: ERROR: section \"%s\" does not fit into \"%s\" memory:\n"
                         "    0x%x + %u > %u\n",
                         progname, sname, mem->desc,
@@ -1402,7 +1397,7 @@ int fileio_setparms(int op, struct fioparms * fp,
 
 
 
-static int fmt_autodetect(char * fname)
+int fileio_fmt_autodetect(const char * fname)
 {
   FILE * f;
   unsigned char buf[MAX_LINE_LEN];
@@ -1510,7 +1505,7 @@ int fileio(int oprwv, char * filename, FILEFMT format,
   if (rc < 0)
     return -1;
 
-  if (fio.op == FIO_READ)
+  if (size < 0 || fio.op == FIO_READ)
     size = mem->size;
 
   if (fio.op == FIO_READ) {
@@ -1547,7 +1542,7 @@ int fileio(int oprwv, char * filename, FILEFMT format,
       return -1;
     }
 
-    format_detect = fmt_autodetect(fname);
+    format_detect = fileio_fmt_autodetect(fname);
     if (format_detect < 0) {
       avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n",
                       progname, fname);
@@ -1556,8 +1551,8 @@ int fileio(int oprwv, char * filename, FILEFMT format,
     format = format_detect;
 
     if (quell_progress < 2) {
-      avrdude_message(MSG_INFO, "%s: %s file %s auto detected as %s\n",
-              progname, fio.iodesc, fname, fmtstr(format));
+      avrdude_message(MSG_NOTICE, "%s: %s file %s auto detected as %s\n",
+              progname, fio.iodesc, fname, fileio_fmtstr(format));
     }
   }
 
diff --git a/src/libavrdude.h b/src/libavrdude.h
index 23905953..5e8fc5d2 100644
--- a/src/libavrdude.h
+++ b/src/libavrdude.h
@@ -872,7 +872,9 @@ enum {
 extern "C" {
 #endif
 
-char * fmtstr(FILEFMT format);
+char * fileio_fmtstr(FILEFMT format);
+
+int fileio_fmt_autodetect(const char * fname);
 
 int fileio(int oprwv, char * filename, FILEFMT format,
            struct avrpart * p, char * memtype, int size);
@@ -936,6 +938,14 @@ const char *update_inname(const char *fn);
 const char *update_outname(const char *fn);
 const char *update_interval(int a, int b);
 
+// Helper functions for dry run to determine file access
+int update_is_okfile(const char *fn);
+int update_is_writeable(const char *fn);
+int update_is_readable(const char *fn);
+
+int update_dryrun(struct avrpart *p, UPDATE *upd);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/main.c b/src/main.c
index 9f72847f..de991aab 100644
--- a/src/main.c
+++ b/src/main.c
@@ -901,11 +901,13 @@ int main(int argc, char * argv [])
   }
 
   /*
-   * Now that we know which part we are going to program, locate any
-   * -U options using the default memory region, and fill in the
-   * device-dependent default region name, either "application" (for
-   * Xmega devices), or "flash" (everything else).
+   * Now that we know which part we are going to program, locate any -U
+   * options using the default memory region, fill in the device-dependent
+   * default region name ("application" for Xmega parts or "flash" otherwise)
+   * and check for basic problems with memory names or file access with a
+   * view to exit before programming.
    */
+  int doexit = 0;
   for (ln=lfirst(updates); ln; ln=lnext(ln)) {
     upd = ldata(ln);
     if (upd->memtype == NULL) {
@@ -920,12 +922,12 @@ int main(int argc, char * argv [])
       }
     }
 
-    if (!avr_mem_might_be_known(upd->memtype)) {
-      avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, upd->memtype);
-      exit(1);
-    }
-    // TODO: check whether filename other than "-" is readable/writable
+    rc = update_dryrun(p, upd);
+    if (rc && rc != LIBAVRDUDE_SOFTFAIL)
+      doexit = 1;
   }
+  if(doexit)
+    exit(1);
 
   /*
    * open the programmer
diff --git a/src/msvc/msvc_compat.h b/src/msvc/msvc_compat.h
index eb3e026a..2c072b3b 100644
--- a/src/msvc/msvc_compat.h
+++ b/src/msvc/msvc_compat.h
@@ -28,6 +28,11 @@
 #pragma comment(lib, "ws2_32.lib")
 #pragma comment(lib, "setupapi.lib")
 
+#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
+
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
 #define F_OK 0
 
 #define PATH_MAX _MAX_PATH
diff --git a/src/update.c b/src/update.c
index 2aa2579b..b79f6442 100644
--- a/src/update.c
+++ b/src/update.c
@@ -24,6 +24,9 @@
 #include <errno.h>
 #include <string.h>
 #include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include "ac_cfg.h"
 #include "avrdude.h"
@@ -319,6 +322,145 @@ const char *update_interval(int a, int b) {
 }
 
 
+// Helper functions for dry run to determine file access
+
+int update_is_okfile(const char *fn) {
+  struct stat info;
+
+  // File exists and is a regular file or a character file, eg, /dev/urandom
+  return fn && *fn && stat(fn, &info) == 0 && !!(info.st_mode & (S_IFREG | S_IFCHR));
+}
+
+int update_is_writeable(const char *fn) {
+  if(!fn || !*fn)
+    return 0;
+
+  // Assume writing to stdout will be OK
+  if(!strcmp(fn, "-"))
+    return 1;
+
+  // File exists? If so return whether it's readable and an OK file type
+  if(access(fn, F_OK) == 0)
+    return access(fn, W_OK) == 0 && update_is_okfile(fn);
+
+  // File does not exist: try to create it
+  FILE *test = fopen(fn, "w");
+  if(test) {
+    unlink(fn);
+    fclose(test);
+  }
+  return !!test;
+}
+
+int update_is_readable(const char *fn) {
+  if(!fn || !*fn)
+    return 0;
+
+  // Assume reading from stdin will be OK
+  if(!strcmp(fn, "-"))
+    return 1;
+
+  // File exists, is readable by the process and an OK file type?
+  return access(fn, R_OK) == 0 && update_is_okfile(fn);
+}
+
+
+static void ioerror(const char *iotype, UPDATE *upd) {
+  avrdude_message(MSG_INFO, "%s: file %s is not %s",
+    progname, update_outname(upd->filename), iotype);
+  if(errno)
+    avrdude_message(MSG_INFO, ". %s", strerror(errno));
+  else if(upd->filename && *upd->filename)
+    avrdude_message(MSG_INFO, " (not a regular or character file?)");
+  avrdude_message(MSG_INFO, "\n");
+}
+
+// Basic checks to reveal serious failure before programming
+int update_dryrun(struct avrpart *p, UPDATE *upd) {
+  static char **wrote;
+  static int nfwritten;
+
+  int known, format_detect, ret = LIBAVRDUDE_SUCCESS;
+
+  /*
+   * Reject an update if memory name is not known amongst any part (suspect a typo)
+   * but accept when the specific part does not have it (allow unifying i/faces)
+   */
+  if(!avr_mem_might_be_known(upd->memtype)) {
+    avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, upd->memtype);
+    ret = LIBAVRDUDE_GENERAL_FAILURE;
+  } else if(p && !avr_locate_mem(p, upd->memtype))
+    ret = LIBAVRDUDE_SOFTFAIL;
+
+  known = 0;
+  // Necessary to check whether the file is readable?
+  if(upd->op == DEVICE_VERIFY || upd->op == DEVICE_WRITE || upd->format == FMT_AUTO) {
+    if(upd->format != FMT_IMM) {
+      // Need to read the file: was it written before, so will be known?
+      for(int i = 0; i < nfwritten; i++)
+        if(!wrote || (upd->filename && !strcmp(wrote[i], upd->filename)))
+          known = 1;
+
+      errno = 0;
+      if(!known && !update_is_readable(upd->filename)) {
+        ioerror("readable", upd);
+        ret = LIBAVRDUDE_GENERAL_FAILURE;
+        known = 1;                // Pretend we know it, so no auto detect needed
+      }
+    }
+  }
+
+  if(!known && upd->format == FMT_AUTO) {
+    if(!strcmp(upd->filename, "-")) {
+      avrdude_message(MSG_INFO, "%s: can't auto detect file format for stdin/out, "
+        "specify explicitly\n", progname);
+      ret = LIBAVRDUDE_GENERAL_FAILURE;
+    } else if((format_detect = fileio_fmt_autodetect(upd->filename)) < 0) {
+      avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n",
+        progname, upd->filename);
+      ret = LIBAVRDUDE_GENERAL_FAILURE;
+    } else {
+      // Set format now, no need to repeat auto detection later
+      upd->format = format_detect;
+      if(quell_progress < 2)
+        avrdude_message(MSG_NOTICE, "%s: %s file %s auto detected as %s\n",
+          progname, upd->op == DEVICE_READ? "output": "input", upd->filename,
+            fileio_fmtstr(upd->format));
+    }
+  }
+
+  switch(upd->op) {
+  case DEVICE_READ:
+    if(upd->format == FMT_IMM) {
+      avrdude_message(MSG_INFO,
+        "%s: invalid file format 'immediate' for output\n", progname);
+      ret = LIBAVRDUDE_GENERAL_FAILURE;
+    } else {
+      errno = 0;
+      if(!update_is_writeable(upd->filename)) {
+        ioerror("writeable", upd);
+        ret = LIBAVRDUDE_GENERAL_FAILURE;
+      } else if(upd->filename) { // Record filename (other than stdout) is available for future reads
+        if(strcmp(upd->filename, "-") && (wrote = realloc(wrote, sizeof(*wrote) * (nfwritten+1))))
+          wrote[nfwritten++] = upd->filename;
+      }
+    }
+    break;
+
+  case DEVICE_VERIFY:           // Already checked that file is readable
+  case DEVICE_WRITE:
+    break;
+
+  default:
+    avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n",
+      progname, upd->op);
+    ret = LIBAVRDUDE_GENERAL_FAILURE;
+  }
+
+  return ret;
+}
+
+
 int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags)
 {
   struct avrpart * v;
@@ -346,7 +488,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
     // Read out the specified device memory and write it to a file
     if (upd->format == FMT_IMM) {
       avrdude_message(MSG_INFO,
-        "%s: Invalid file format 'immediate' for output\n", progname);
+        "%s: invalid file format 'immediate' for output\n", progname);
       return LIBAVRDUDE_GENERAL_FAILURE;
     }
     if (quell_progress < 2)
@@ -383,15 +525,15 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
     // Write the selected device memory using data from a file
 
     rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
-    if (quell_progress < 2)
-      avrdude_message(MSG_INFO, "%s: reading input file %s for %s%s\n",
-        progname, update_inname(upd->filename), mem->desc, alias_mem_desc);
     if (rc < 0) {
       avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
         progname, update_inname(upd->filename));
       return LIBAVRDUDE_GENERAL_FAILURE;
     }
     size = rc;
+    if (quell_progress < 2)
+      avrdude_message(MSG_INFO, "%s: reading input file %s for %s%s\n",
+        progname, update_inname(upd->filename), mem->desc, alias_mem_desc);
 
     if(memstats(p, upd->memtype, size, &fs) < 0)
       return LIBAVRDUDE_GENERAL_FAILURE;