amgtar_restore(
    application_argument_t *argument)
{
    char       *cmd;
    GPtrArray  *argv_ptr = g_ptr_array_new();
    GPtrArray  *include_array = g_ptr_array_new();
    char      **env;
    int         j;
    char       *e;
    char       *include_filename = NULL;
    char       *exclude_filename = NULL;
    int         tarpid;
    amwait_t    wait_status;
    int         exit_status = 0;
    char       *errmsg = NULL;
    FILE       *dar_file;

    if (!gnutar_path) {
	error(_("GNUTAR-PATH not defined"));
    }

    if (!check_exec_for_suid(gnutar_path, FALSE)) {
	error("'%s' binary is not secure", gnutar_path);
    }

    cmd = g_strdup(gnutar_path);
    g_ptr_array_add(argv_ptr, g_strdup(gnutar_path));
    g_ptr_array_add(argv_ptr, g_strdup("--numeric-owner"));
    if (gnutar_no_unquote)
	g_ptr_array_add(argv_ptr, g_strdup("--no-unquote"));
    if (gnutar_acls)
	g_ptr_array_add(argv_ptr, g_strdup("--acls"));
    if (gnutar_selinux)
	g_ptr_array_add(argv_ptr, g_strdup("--selinux"));
    if (gnutar_xattrs)
	g_ptr_array_add(argv_ptr, g_strdup("--xattrs"));
    /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
    if (argument->ignore_zeros) {
	g_ptr_array_add(argv_ptr, g_strdup("--ignore-zeros"));
    }
    if (argument->tar_blocksize) {
	g_ptr_array_add(argv_ptr, g_strdup("--blocking-factor"));
	g_ptr_array_add(argv_ptr, g_strdup(argument->tar_blocksize));
    }
    g_ptr_array_add(argv_ptr, g_strdup("-xpGvf"));
    g_ptr_array_add(argv_ptr, g_strdup("-"));
    if (gnutar_directory) {
	struct stat stat_buf;
	if(stat(gnutar_directory, &stat_buf) != 0) {
	    fprintf(stderr, "can not stat directory %s: %s\n",
		    gnutar_directory, strerror(errno));
	    exit(1);
	}
	if (!S_ISDIR(stat_buf.st_mode)) {
	    fprintf(stderr,"%s is not a directory\n", gnutar_directory);
	    exit(1);
	}
	if (access(gnutar_directory, W_OK) != 0) {
	    fprintf(stderr, "Can't write to %s: %s\n",
		    gnutar_directory, strerror(errno));
	    exit(1);
	}
	g_ptr_array_add(argv_ptr, g_strdup("--directory"));
	g_ptr_array_add(argv_ptr, g_strdup(gnutar_directory));
    }

    g_ptr_array_add(argv_ptr, g_strdup("--wildcards"));
    if (argument->dle.exclude_list &&
	argument->dle.exclude_list->nb_element == 1) {
	FILE      *exclude;
	char      *sdisk;
	int        in_argv;
	int        entry_in_exclude = 0;
	char       line[2*PATH_MAX];
	FILE      *exclude_list;

	if (argument->dle.disk) {
	    sdisk = sanitise_filename(argument->dle.disk);
	} else {
	    sdisk = g_strdup_printf("no_dle-%d", (int)getpid());
	}
	exclude_filename= g_strjoin(NULL, AMANDA_TMPDIR, "/", "exclude-",
				    sdisk,  NULL);
	exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
	if (!exclude_list) {
	    fprintf(stderr, "Cannot open exclude file '%s': %s\n",
		    argument->dle.exclude_list->first->name, strerror(errno));
	    error("Cannot open exclude file '%s': %s\n",
		  argument->dle.exclude_list->first->name, strerror(errno));
	    /*NOTREACHED*/
	}
	exclude = fopen(exclude_filename, "w");
	if (!exclude) {
	    fprintf(stderr, "Cannot open exclude file '%s': %s\n",
		    exclude_filename, strerror(errno));
	    fclose(exclude_list);
	    error("Cannot open exclude file '%s': %s\n",
		  exclude_filename, strerror(errno));
	    /*NOTREACHED*/
	}
	while (fgets(line, 2*PATH_MAX, exclude_list)) {
	    char *escaped;
	    line[strlen(line)-1] = '\0'; /* remove '\n' */
	    escaped = escape_tar_glob(line, &in_argv);
	    if (in_argv) {
		g_ptr_array_add(argv_ptr, "--exclude");
		g_ptr_array_add(argv_ptr, escaped);
	    } else {
		fprintf(exclude,"%s\n", escaped);
		entry_in_exclude++;
		amfree(escaped);
	    }
	}
	fclose(exclude_list);
	fclose(exclude);
	g_ptr_array_add(argv_ptr, g_strdup("--exclude-from"));
	g_ptr_array_add(argv_ptr, exclude_filename);
    }

    if (argument->exclude_list_glob) {
	g_ptr_array_add(argv_ptr, g_strdup("--exclude-from"));
	g_ptr_array_add(argv_ptr, g_strdup(argument->exclude_list_glob));
    }

    {
	GPtrArray *argv_include = g_ptr_array_new();
	FILE      *include;
	char      *sdisk;
	int        in_argv;
	guint      i;
	int        entry_in_include = 0;

	if (argument->dle.disk) {
	    sdisk = sanitise_filename(argument->dle.disk);
	} else {
	    sdisk = g_strdup_printf("no_dle-%d", (int)getpid());
	}
	include_filename = g_strjoin(NULL, AMANDA_TMPDIR, "/", "include-", sdisk,  NULL);
	include = fopen(include_filename, "w");
	if (!include) {
	    fprintf(stderr, "Cannot open include file '%s': %s\n",
		    include_filename, strerror(errno));
	    error("Cannot open include file '%s': %s\n",
		  include_filename, strerror(errno));
	    /*NOTREACHED*/
	}
	if (argument->dle.include_list &&
	    argument->dle.include_list->nb_element == 1) {
	    char line[2*PATH_MAX];
	    FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
	    if (!include_list) {
		fclose(include);
		fprintf(stderr, "Cannot open include file '%s': %s\n",
			argument->dle.include_list->first->name,
			strerror(errno));
		error("Cannot open include file '%s': %s\n",
		      argument->dle.include_list->first->name,
		      strerror(errno));
		/*NOTREACHED*/
	    }
	    while (fgets(line, 2*PATH_MAX, include_list)) {
		char *escaped;
		line[strlen(line)-1] = '\0'; /* remove '\n' */
		escaped = escape_tar_glob(line, &in_argv);
		g_ptr_array_add(include_array, g_strdup(escaped));
		if (in_argv) {
		    g_ptr_array_add(argv_include, escaped);
		} else {
		    fprintf(include,"%s\n", escaped);
		    entry_in_include++;
		    amfree(escaped);
		}
	    }
	    fclose(include_list);
	}

	if (argument->dle.include_file) {
	    sle_t *slif;

	    for (slif = argument->dle.include_file->first; slif != NULL; slif = slif->next) {
		char *escaped = escape_tar_glob(slif->name, &in_argv);
		g_ptr_array_add(include_array, g_strdup(escaped));
		if (in_argv) {
		    g_ptr_array_add(argv_include, escaped);
		} else {
		    fprintf(include,"%s\n", escaped);
		    entry_in_include++;
		    amfree(escaped);
		}
	    }
	}

	for (j=1; j< argument->argc; j++) {
	    char *escaped = escape_tar_glob(argument->argv[j], &in_argv);
	    g_ptr_array_add(include_array, g_strdup(escaped));
	    if (in_argv) {
		g_ptr_array_add(argv_include, escaped);
	    } else {
		fprintf(include,"%s\n", escaped);
		entry_in_include++;
		amfree(escaped);
	    }
	}
	fclose(include);

	if (entry_in_include) {
	    g_ptr_array_add(argv_ptr, g_strdup("--files-from"));
	    g_ptr_array_add(argv_ptr, include_filename);
	}

	if (argument->include_list_glob) {
	    g_ptr_array_add(argv_ptr, g_strdup("--files-from"));
	    g_ptr_array_add(argv_ptr, g_strdup(argument->include_list_glob));
	}

	for (i = 0; i < argv_include->len; i++) {
	    g_ptr_array_add(argv_ptr, (char *)g_ptr_array_index(argv_include,i));
	}
	amfree(sdisk);
    }
    g_ptr_array_add(argv_ptr, NULL);

    if (argument->dar) {
	int dar_fd = argument->state_stream;
	if (dar_fd == -1) dar_fd = 3;
	dar_file = fdopen(dar_fd, "w");
	if (!dar_file) {
	    int save_errno = errno;
	    fprintf(stderr, "Can't fdopen the DAR file (fd %d): %s\n",
		    dar_fd, strerror(save_errno));
	    g_debug("Can't fdopen the DAR file (fd %d): %s",
		    dar_fd, strerror(save_errno));
	   exit(1);
	}
	if (argument->recover_dump_state_file &&
		   include_array->len > 0) {
	    char  line[32768];
	    FILE *recover_state_file = fopen(argument->recover_dump_state_file,
					     "r");
	    int   previous_block = -1;

	    while (fgets(line, 32768, recover_state_file) != NULL) {
		off_t     block_no = g_ascii_strtoull(line, NULL, 0);
		gboolean  match    = FALSE;
		char     *filename = strchr(line, ' ');
		char     *ii;
		guint     i;

		if (!filename)
		    continue;

		filename++;
		if (filename[strlen(filename)-1] == '\n')
		    filename[strlen(filename)-1] = '\0';

		g_debug("recover_dump_state_file: %lld %s", (long long)block_no, filename);
		for (i = 0; i < include_array->len; i++) {
		    size_t strlenii;

		    ii = g_ptr_array_index(include_array, i);
		    ii++; // remove leading '.'
		    //g_debug("check %s : %s :", filename, ii);
		    strlenii = strlen(ii);
		    if (g_str_equal(filename, ii) == 1 ||
			(strlenii < strlen(filename) &&
			 strncmp(filename, ii, strlenii) == 0 &&
			 filename[strlenii] == '/')) {
			//g_debug("match %s", ii);
			match = TRUE;
			break;
		    }
		}

		if (match) {
		    if (previous_block < 0)
			previous_block = block_no;
		} else if (previous_block >= 0) {
		    g_debug("restore block %lld (%lld) to %lld (%lld)",
			    (long long)previous_block * 512,
			    (long long)previous_block,
			    (long long)block_no * 512 - 1,
			    (long long)block_no);
		    fprintf(dar_file, "DAR %lld:%lld\n",
			    (long long)previous_block * 512,
			    (long long)block_no * 512- 1);
		    previous_block = -1;
		}
	    }
	    fclose(recover_state_file);
	    if (previous_block >= 0) {
		g_debug("restore block %lld (%lld) to END",
			(long long)previous_block * 512,
			(long long)previous_block);
		fprintf(dar_file, "DAR %lld:-1\n",
			(long long)previous_block * 512);
	    }
	} else {
	    fprintf(dar_file,"DAR 0:-1\n");
	    g_debug("full dar: 0:-1");
	}
	fflush(dar_file);
	fclose(dar_file);
    }

    debug_executing(argv_ptr);

    tarpid = fork();
    switch (tarpid) {
    case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
    case 0:
	env = safe_env();
	become_root();
	execve(cmd, (char **)argv_ptr->pdata, env);
	free_env(env);
	e = strerror(errno);
	error(_("error [exec %s: %s]"), cmd, e);
	break;
    default: break;
    }

    waitpid(tarpid, &wait_status, 0);
    if (WIFSIGNALED(wait_status)) {
	errmsg = g_strdup_printf(_("%s terminated with signal %d: see %s"),
                                 cmd, WTERMSIG(wait_status), dbfn());
	exit_status = 1;
    } else if (WIFEXITED(wait_status)) {
	if (WEXITSTATUS(wait_status) > 0) {
	    errmsg = g_strdup_printf(_("%s exited with status %d: see %s"),
				     cmd, WEXITSTATUS(wait_status), dbfn());
	    exit_status = 1;
	} else {
	    /* Normal exit */
	    exit_status = 0;
	}
    } else {
	errmsg = g_strdup_printf(_("%s got bad exit: see %s"),
				 cmd, dbfn());
	exit_status = 1;
    }
    if (errmsg) {
	dbprintf("%s", errmsg);
	fprintf(stderr, "ERROR %s\n", errmsg);
	amfree(errmsg);
    }

    if (argument->verbose == 0) {
	if (exclude_filename)
	    unlink(exclude_filename);
	unlink(include_filename);
    }
    amfree(cmd);
    amfree(include_filename);
    amfree(exclude_filename);
    exit(exit_status);
}