--- src/tar.c.orig	2010-10-24 22:07:55.000000000 +0400
+++ src/tar.c	2011-01-04 16:28:50.000000000 +0300
@@ -273,6 +273,7 @@
   EXCLUDE_TAG_UNDER_OPTION,
   EXCLUDE_TAG_ALL_OPTION,
   EXCLUDE_VCS_OPTION,
+  FIX_PERMISSIONS_OPTION,
   FORCE_LOCAL_OPTION,
   FULL_TIME_OPTION,
   GROUP_OPTION,
@@ -523,6 +524,8 @@
       " directories until the end of extraction"), GRID+1 },
   {"no-delay-directory-restore", NO_DELAY_DIRECTORY_RESTORE_OPTION, 0, 0,
    N_("cancel the effect of --delay-directory-restore option"), GRID+1 },
+  {"fix-permissions", FIX_PERMISSIONS_OPTION, 0, 0,
+   N_("auto fix permissions with chmod +rX when creating the archive"), GRID+1 },
 #undef GRID
 
 #define GRID 60
@@ -2079,6 +2082,10 @@
       same_permissions_option = -1;
       break;
 
+    case FIX_PERMISSIONS_OPTION:
+      fix_permissions_option = -1;
+      break;
+
     case RECURSION_OPTION:
       recursion_option = FNM_LEADING_DIR;
       break;
--- src/common.h.orig	2011-01-05 17:34:08.000000000 +0300
+++ src/common.h	2011-01-05 16:56:55.000000000 +0300
@@ -253,6 +253,9 @@
 /* If positive, preserve permissions when extracting.  */
 GLOBAL int same_permissions_option;
 
+/* If positive, fix permissions with chmod u+rX when creating. */
+GLOBAL int fix_permissions_option;
+
 /* When set, strip the given number of file name components from the file name
    before extracting */
 GLOBAL size_t strip_name_components;
@@ -646,6 +649,12 @@
 int set_file_atime (int fd, int parentfd, char const *file,
 		    struct timespec atime);
 
+int
+chmodat (int fd, const char *name, mode_t mode);
+
+int
+fix_permissions(const char *name, int fd, struct tar_stat_info *st);
+
 /* Module names.c.  */
 
 extern size_t name_count;
--- src/create.c.orig	2011-01-05 17:34:12.000000000 +0300
+++ src/create.c	2011-01-05 16:59:31.000000000 +0300
@@ -1265,6 +1265,7 @@
 char *
 get_directory_entries (struct tar_stat_info *st)
 {
+  fix_permissions(0, st->fd, st);
   while (! (st->dirstream = fdopendir (st->fd)))
     if (! open_failure_recover (st))
       return 0;
@@ -1616,7 +1617,7 @@
   struct timespec original_ctime;
   off_t block_ordinal = -1;
   int fd = 0;
-  bool is_dir;
+  bool is_dir, ctime_ignore = 0;
   struct tar_stat_info const *parent = st->parent;
   bool top_level = ! parent;
   int parentfd = top_level ? chdir_fd : parent->fd;
@@ -1640,6 +1641,8 @@
     diag = stat_diag;
   else if (file_dumpable_p (&st->stat))
     {
+      if (fix_permissions(name, parentfd, st))
+          ctime_ignore = 1;
       fd = subfile_open (parent, name, open_read_flags);
       if (fd < 0)
 	diag = open_diag;
@@ -1785,7 +1788,7 @@
 
       if (ok)
 	{
-	  if ((timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0
+	  if ((!ctime_ignore && timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0
 	       /* Original ctime will change if the file is a directory and
 		  --remove-files is given */
 	       && !(remove_files_option && is_dir))
--- src/incremen.c.orig	2011-01-05 17:34:20.000000000 +0300
+++ src/incremen.c	2011-01-05 17:00:26.000000000 +0300
@@ -734,6 +730,7 @@
 		diag = stat_diag;
 	      else if (S_ISDIR (stsub.stat.st_mode))
 		{
+		  fix_permissions(entry + 1, st->fd, &stsub);
 		  int subfd = subfile_open (st, entry + 1, open_read_flags);
 		  if (subfd < 0)
 		    diag = open_diag;
--- src/misc.c.orig	2011-01-05 17:34:29.000000000 +0300
+++ src/misc.c	2011-01-05 17:02:18.000000000 +0300
@@ -961,3 +961,55 @@
   strcpy (buf->buffer + buf->dir_length, name);
   return buf->buffer;
 }
+
+int
+fix_permissions(const char *name, int fd, struct tar_stat_info *st)
+{
+  // exit codes: 0 - no changes; 1 -  permissions changed
+  int res = 0; mode_t new_mode;
+
+  if (fix_permissions_option == -1)
+  {
+    mode_t check_mode = (S_ISDIR (st->stat.st_mode) != 0) ? S_IRUSR | S_IXUSR : S_IRUSR;
+    if ((st->stat.st_mode & check_mode) != check_mode)
+    {
+      st->stat.st_mode |= check_mode;
+      new_mode = st->stat.st_mode & 07777;
+      if (name && fd != -1)
+      {
+        if ((res = chmodat(fd, name, new_mode)) == -1) call_arg_warn("chmodat", name);
+      } else if (name)
+      {
+        if ((res = chmod(name, new_mode)) == -1) call_arg_warn("chmod", name);
+      } else if (fd)
+      {
+        if ((res = fchmod(fd, new_mode)) == -1) call_arg_warn("fchmod", "unknown");
+      } else
+        return 0;
+      return res == 0;
+    }
+  }
+
+  return 0; // no changes
+}
+
+int
+chmodat (int fd, const char *name, mode_t mode)
+{
+    int cwd, res;
+
+    if ((cwd = open(".", O_RDONLY)) == -1) return -1;
+
+    if (fchdir(fd) == -1)
+    {
+        close(cwd);
+        return -1;
+    }
+
+    res = chmod(name, mode);
+
+    fchdir(cwd);
+    close(cwd);
+    return res;
+}
+
