diff --git a/src/dir.c b/src/dir.c index 386f49bc..96debfa8 100644 --- a/src/dir.c +++ b/src/dir.c @@ -118,7 +118,7 @@ typedef struct TablespaceCreatedList static int BlackListCompare(const void *str1, const void *str2); -static bool dir_check_file(const char *root, pgFile *file); +static char dir_check_file(const char *root, pgFile *file); static void dir_list_file_internal(parray *files, const char *root, pgFile *parent, bool exclude, bool omit_symlink, parray *black_list); @@ -448,6 +448,10 @@ dir_list_file(parray *files, const char *root, bool exclude, bool omit_symlink, pgFileFree(file); } +#define CHECK_FALSE 0 +#define CHECK_TRUE 1 +#define CHECK_EXCLUDE_FALSE 2 + /* * Check file or directory. * @@ -456,16 +460,21 @@ dir_list_file(parray *files, const char *root, bool exclude, bool omit_symlink, * Skip files: * - skip temp tables files * - skip unlogged tables files + * Skip recursive tablespace content * Set flags for: * - database directories * - datafiles */ -static bool +static char dir_check_file(const char *root, pgFile *file) { const char *rel_path; int i; int sscanf_res; + bool in_tablespace = false; + + rel_path = GetRelativePath(file->path, root); + in_tablespace = path_is_prefix_of_path(PG_TBLSPC_DIR, rel_path); /* Check if we need to exclude file by name */ if (S_ISREG(file->mode)) @@ -478,7 +487,7 @@ dir_check_file(const char *root, pgFile *file) { /* Skip */ elog(VERBOSE, "Excluding file: %s", file->name); - return false; + return CHECK_FALSE; } } @@ -487,14 +496,14 @@ dir_check_file(const char *root, pgFile *file) { /* Skip */ elog(VERBOSE, "Excluding file: %s", file->name); - return false; + return CHECK_FALSE; } } /* * If the directory name is in the exclude list, do not list the * contents. */ - else if (S_ISDIR(file->mode)) + else if (S_ISDIR(file->mode) && !in_tablespace) { /* * If the item in the exclude list starts with '/', compare to @@ -510,20 +519,18 @@ dir_check_file(const char *root, pgFile *file) { elog(VERBOSE, "Excluding directory content: %s", file->name); - return false; + return CHECK_EXCLUDE_FALSE; } } else if (strcmp(file->name, pgdata_exclude_dir[i]) == 0) { elog(VERBOSE, "Excluding directory content: %s", file->name); - return false; + return CHECK_EXCLUDE_FALSE; } } } - rel_path = GetRelativePath(file->path, root); - /* * Do not copy tablespaces twice. It may happen if the tablespace is located * inside the PGDATA. @@ -539,14 +546,33 @@ dir_check_file(const char *root, pgFile *file) * pg_tblspc/tblsOid/TABLESPACE_VERSION_DIRECTORY */ if (!path_is_prefix_of_path(PG_TBLSPC_DIR, rel_path)) - return false; + return CHECK_FALSE; sscanf_res = sscanf(rel_path, PG_TBLSPC_DIR "/%u/%s", &tblspcOid, tmp_rel_path); if (sscanf_res == 0) - return false; + return CHECK_FALSE; } - if (path_is_prefix_of_path("global", rel_path)) + if (in_tablespace) + { + char tmp_rel_path[MAXPGPATH]; + + sscanf_res = sscanf(rel_path, PG_TBLSPC_DIR "/%u/%[^/]/%u/", + &(file->tblspcOid), tmp_rel_path, + &(file->dbOid)); + + /* + * We should skip other files and directories rather than + * TABLESPACE_VERSION_DIRECTORY, if this is recursive tablespace. + */ + if (sscanf_res == 2 && strcmp(tmp_rel_path, TABLESPACE_VERSION_DIRECTORY) != 0) + return CHECK_FALSE; + + if (sscanf_res == 3 && S_ISDIR(file->mode) && + strcmp(tmp_rel_path, TABLESPACE_VERSION_DIRECTORY) == 0) + file->is_database = true; + } + else if (path_is_prefix_of_path("global", rel_path)) { file->tblspcOid = GLOBALTABLESPACE_OID; @@ -562,22 +588,10 @@ dir_check_file(const char *root, pgFile *file) if (S_ISDIR(file->mode) && strcmp(file->name, "base") != 0) file->is_database = true; } - else if (path_is_prefix_of_path(PG_TBLSPC_DIR, rel_path)) - { - char tmp_rel_path[MAXPGPATH]; - - sscanf_res = sscanf(rel_path, PG_TBLSPC_DIR "/%u/%[^/]/%u/", - &(file->tblspcOid), tmp_rel_path, - &(file->dbOid)); - - if (sscanf_res == 3 && S_ISDIR(file->mode) && - strcmp(tmp_rel_path, TABLESPACE_VERSION_DIRECTORY) == 0) - file->is_database = true; - } /* Do not backup ptrack_init files */ if (S_ISREG(file->mode) && strcmp(file->name, "ptrack_init") == 0) - return false; + return CHECK_FALSE; /* * Check files located inside database directories including directory @@ -587,10 +601,10 @@ dir_check_file(const char *root, pgFile *file) file->name && file->name[0]) { if (strcmp(file->name, "pg_internal.init") == 0) - return false; + return CHECK_FALSE; /* Do not backup temp files */ else if (file->name[0] == 't' && isdigit(file->name[1])) - return false; + return CHECK_FALSE; else if (isdigit(file->name[0])) { char *fork_name; @@ -605,14 +619,14 @@ dir_check_file(const char *root, pgFile *file) /* Do not backup ptrack files */ if (strcmp(file->forkName, "ptrack") == 0) - return false; + return CHECK_FALSE; } else { len = strlen(file->name); /* reloid.cfm */ if (len > 3 && strcmp(file->name + len - 3, "cfm") == 0) - return true; + return CHECK_TRUE; sscanf_res = sscanf(file->name, "%u.%d.%s", &(file->relOid), &(file->segno), suffix); @@ -624,7 +638,7 @@ dir_check_file(const char *root, pgFile *file) } } - return true; + return CHECK_TRUE; } /* @@ -659,6 +673,7 @@ dir_list_file_internal(parray *files, const char *root, pgFile *parent, { pgFile *file; char child[MAXPGPATH]; + char check_res; join_path_components(child, parent->path, dent->d_name); @@ -694,21 +709,24 @@ dir_list_file_internal(parray *files, const char *root, pgFile *parent, continue; } - /* We add the directory anyway */ - if (S_ISDIR(file->mode)) - parray_append(files, file); - - if (exclude && !dir_check_file(root, file)) + if (exclude) { - if (S_ISREG(file->mode)) + check_res = dir_check_file(root, file); + if (check_res == CHECK_FALSE) + { + /* Skip */ pgFileFree(file); - /* Skip */ - continue; + continue; + } + else if (check_res == CHECK_EXCLUDE_FALSE) + { + /* We add the directory itself which content was excluded */ + parray_append(files, file); + continue; + } } - /* At least add the file */ - if (S_ISREG(file->mode)) - parray_append(files, file); + parray_append(files, file); /* * If the entry is a directory call dir_list_file_internal() @@ -1219,11 +1237,7 @@ print_file_list(FILE *out, const parray *files, const char *root) if (file->is_datafile) fprintf(out, ",\"segno\":\"%d\"", file->segno); -#ifndef WIN32 - if (S_ISLNK(file->mode)) -#else - if (pgwin32_is_junction(file->path)) -#endif + if (file->linked) fprintf(out, ",\"linked\":\"%s\"", file->linked); if (file->n_blocks != BLOCKNUM_INVALID)