Exemplo n.º 1
0
/*
 * List files, symbolic links and directories in the directory "root" and add
 * pgFile objects to "files".  We add "root" to "files" if add_root is true.
 *
 * If the sub-directory name is in "exclude" list, the sub-directory itself is
 * listed but the contents of the sub-directory is ignored.
 *
 * When omit_symlink is true, symbolic link is ignored and only file or
 * directory llnked to will be listed.
 */
void
dir_list_file(parray *files, const char *root, const char *exclude[], bool omit_symlink, bool add_root)
{
	char path[MAXPGPATH];
	char buf[MAXPGPATH * 2];
	char black_item[MAXPGPATH * 2];
	parray *black_list = NULL;

	join_path_components(path, backup_path, PG_BLACK_LIST);
	if (root && pgdata && strcmp(root, pgdata) == 0 &&
	    fileExists(path))
	{
		FILE *black_list_file = NULL;
		black_list = parray_new();
		black_list_file = fopen(path, "r");
		if (black_list_file == NULL)
			ereport(ERROR,
				(errcode(ERROR_SYSTEM),
				 errmsg("could not open black_list: %s", strerror(errno))));
		while (fgets(buf, lengthof(buf), black_list_file) != NULL)
		{
			join_path_components(black_item, pgdata, buf);
			if (black_item[strlen(black_item) - 1] == '\n')
				black_item[strlen(black_item) - 1] = '\0';
			if (black_item[0] == '#' || black_item[0] == '\0')
				continue;
			parray_append(black_list, black_item);
		}
		fclose(black_list_file);
		parray_qsort(black_list, BlackListCompare);
		dir_list_file_internal(files, root, exclude, omit_symlink, add_root, black_list);
	}
	else
		dir_list_file_internal(files, root, exclude, omit_symlink, add_root, NULL);
}
Exemplo n.º 2
0
/*
 * Validate files in the backup and update its status to OK.
 * If any of files are corrupted, update its stutus to CORRUPT.
 */
int
do_validate(pgBackupRange *range)
{
    int		i;
    parray *backup_list;
    int ret;
    bool another_pg_rman = false;

    ret = catalog_lock();
    if (ret == 1)
        another_pg_rman = true;

    /* get backup list matches given range */
    backup_list = catalog_get_backup_list(range);
    if(!backup_list) {
        elog(ERROR_SYSTEM, _("can't process any more."));
    }
    parray_qsort(backup_list, pgBackupCompareId);
    for (i = 0; i < parray_num(backup_list); i++)
    {
        pgBackup *backup = (pgBackup *)parray_get(backup_list, i);

        /* clean extra backups (switch STATUS to ERROR) */
        if(!another_pg_rman &&
                (backup->status == BACKUP_STATUS_RUNNING || backup->status == BACKUP_STATUS_DELETING)) {
            backup->status = BACKUP_STATUS_ERROR;
            pgBackupWriteIni(backup);
        }

        /* Validate completed backups only. */
        if (backup->status != BACKUP_STATUS_DONE)
            continue;

        /* validate with CRC value and update status to OK */
        pgBackupValidate(backup, false, false, (HAVE_DATABASE(backup)));
    }

    /* cleanup */
    parray_walk(backup_list, pgBackupFree);
    parray_free(backup_list);

    catalog_unlock();

    return 0;
}
Exemplo n.º 3
0
/*
 * Construct parray of pgFile from the file list.
 * If root is not NULL, path will be absolute path.
 */
parray *
dir_read_file_list(const char *root, const char *file_txt)
{
	FILE   *fp;
	parray *files;
	char	buf[MAXPGPATH * 2];

	fp = fopen(file_txt, "rt");
	if (fp == NULL)
		ereport(ERROR,
			((errno == ENOENT ? errcode(ERROR_CORRUPTED) : errcode(ERROR_SYSTEM)),
			 errmsg("could not open \"%s\": %s", file_txt, strerror(errno))));

	files = parray_new();

	while (fgets(buf, lengthof(buf), fp))
	{
		char			path[MAXPGPATH];
		char			type;
		unsigned long	write_size;
		pg_crc32c		crc;
		unsigned int	mode;	/* bit length of mode_t depends on platforms */
		struct tm		tm;
		pgFile		   *file;

		memset(&tm, 0, sizeof(tm));
		if (sscanf(buf, "%s %c %lu %u %o %d-%d-%d %d:%d:%d",
			path, &type, &write_size, &crc, &mode,
			&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
			&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 11)
		{
			ereport(ERROR,
				(errcode(ERROR_CORRUPTED),
				 errmsg("invalid format found in \"%s\"", file_txt)));
		}
		if (type != 'f' && type != 'F' && type != 'd' && type != 'l')
		{
			ereport(ERROR,
				(errcode(ERROR_CORRUPTED),
				 errmsg("invalid type '%c' found in \"%s\"", type, file_txt)));
		}
		tm.tm_isdst = -1;

		file = (pgFile *) pgut_malloc(offsetof(pgFile, path) +
					(root ? strlen(root) + 1 : 0) + strlen(path) + 1);

		tm.tm_year -= 1900;
		tm.tm_mon -= 1;
		file->mtime = mktime(&tm);
		file->mode = mode |
			((type == 'f' || type == 'F') ? S_IFREG :
			 type == 'd' ? S_IFDIR : type == 'l' ? S_IFLNK : 0);
		file->size = 0;
		file->read_size = 0;
		file->write_size = write_size;
		file->crc = crc;
		file->is_datafile = (type == 'F' ? true : false);
		file->linked = NULL;
		if (root)
			sprintf(file->path, "%s/%s", root, path);
		else
			strcpy(file->path, path);

		parray_append(files, file);
	}

	fclose(fp);

	/* file.txt is sorted, so this qsort is redundant */
	parray_qsort(files, pgFileComparePath);

	return files;
}
Exemplo n.º 4
0
void
dir_list_file_internal(parray *files, const char *root, const char *exclude[],
			bool omit_symlink, bool add_root, parray *black_list)
{
	pgFile *file;

	file = pgFileNew(root, omit_symlink);
	if (file == NULL)
		return;

	/* skip if the file is in black_list defined by user */
	if (black_list && parray_bsearch(black_list, root, BlackListCompare))
	{
		/* found in black_list. skip this item */
		return;
	}

	if (add_root)
		parray_append(files, file);

	/* chase symbolic link chain and find regular file or directory */
	while (S_ISLNK(file->mode))
	{
		ssize_t	len;
		char	linked[MAXPGPATH];

		len = readlink(file->path, linked, sizeof(linked));
		if (len == -1)
		{
			ereport(ERROR,
				(errcode(ERROR_SYSTEM),
				 errmsg("could not read link \"%s\": %s", file->path, strerror(errno))));
		}
		linked[len] = '\0';
		file->linked = pgut_strdup(linked);

		/* make absolute path to read linked file */
		if (linked[0] != '/')
		{
			char	dname[MAXPGPATH];
			char	absolute[MAXPGPATH];

			strncpy(dname, file->path, lengthof(dname));
			join_path_components(absolute, dirname(dname), linked);
			file = pgFileNew(absolute, omit_symlink);
		}
		else
			file = pgFileNew(file->linked, omit_symlink);

		/* linked file is not found, stop following link chain */
		if (file == NULL)
			return;

		parray_append(files, file);
	}

	/*
	 * If the entry was a directory, add it to the list and add call this
	 * function recursivelly.
	 * If the directory name is in the exclude list, do not list the contents.
	 */
	while (S_ISDIR(file->mode))
	{
		int				i;
		bool			skip = false;
		DIR			    *dir;
		struct dirent   *dent;
		char		    *dirname;

		/* skip entry which matches exclude list */
	   	dirname = strrchr(file->path, '/');
		if (dirname == NULL)
			dirname = file->path;
		else
			dirname++;

		/*
		 * If the item in the exclude list starts with '/', compare to the
		 * absolute path of the directory. Otherwise compare to the directory
		 * name portion.
		 */
		for (i = 0; exclude && exclude[i]; i++)
		{
			if (exclude[i][0] == '/')
			{
				if (strcmp(file->path, exclude[i]) == 0)
				{
					skip = true;
					break;
				}
			}
			else
			{
				if (strcmp(dirname, exclude[i]) == 0)
				{
					skip = true;
					break;
				}
			}
		}
		if (skip)
			break;

		/* open directory and list contents */
		dir = opendir(file->path);
		if (dir == NULL)
		{
			if (errno == ENOENT)
			{
				/* maybe the direcotry was removed */
				return;
			}
			ereport(ERROR,
				(errcode(ERROR_SYSTEM),
				 errmsg("could not open directory \"%s\": %s",
					file->path, strerror(errno))));
		}

		errno = 0;
		while ((dent = readdir(dir)))
		{
			char child[MAXPGPATH];

			/* skip entries point current dir or parent dir */
			if (strcmp(dent->d_name, ".") == 0 ||
				strcmp(dent->d_name, "..") == 0)
				continue;

			join_path_components(child, file->path, dent->d_name);
			dir_list_file_internal(files, child, exclude, omit_symlink, true, black_list);
		}
		if (errno && errno != ENOENT)
		{
			int errno_tmp = errno;
			closedir(dir);
			ereport(ERROR,
				(errcode(ERROR_SYSTEM),
				 errmsg("could not read directory \"%s\": %s",
					file->path, strerror(errno_tmp))));
		}
		closedir(dir);

		break;	/* pseudo loop */
	}

	parray_qsort(files, pgFileComparePath);
}
Exemplo n.º 5
0
/*
 * Delete backup files of the backup and update the status of the backup to
 * BACKUP_STATUS_DELETED.
 */
static int
pgBackupDeleteFiles(pgBackup *backup)
{
	int		i;
	char	path[MAXPGPATH];
	char	timestamp[20];
	parray *files;

	/*
	 * If the backup was deleted already, there is nothing to do.
	 */
	if (backup->status == BACKUP_STATUS_DELETED)
		return 0;

	time2iso(timestamp, lengthof(timestamp), backup->start_time);

	elog(INFO, "delete: %s", timestamp);

	/*
	 * Update STATUS to BACKUP_STATUS_DELETING in preparation for the case which
	 * the error occurs before deleting all backup files.
	 */
	if (!check)
	{
		backup->status = BACKUP_STATUS_DELETING;
		pgBackupWriteIni(backup);
	}

	/* list files to be deleted */
	files = parray_new();
	pgBackupGetPath(backup, path, lengthof(path), DATABASE_DIR);
	dir_list_file(files, path, NULL, true, true);

	/* delete leaf node first */
	parray_qsort(files, pgFileComparePathDesc);
	for (i = 0; i < parray_num(files); i++)
	{
		pgFile *file = (pgFile *) parray_get(files, i);

		/* print progress */
		elog(LOG, "delete file(%d/%lu) \"%s\"", i + 1,
				(unsigned long) parray_num(files), file->path);

		/* skip actual deletion in check mode */
		if (!check)
		{
			if (remove(file->path))
			{
				elog(WARNING, "can't remove \"%s\": %s", file->path,
					strerror(errno));
				parray_walk(files, pgFileFree);
				parray_free(files);
				return 1;
			}
		}
	}

	/*
	 * After deleting all of the backup files, update STATUS to
	 * BACKUP_STATUS_DELETED.
	 */
	if (!check)
	{
		backup->status = BACKUP_STATUS_DELETED;
		pgBackupWriteIni(backup);
	}

	parray_walk(files, pgFileFree);
	parray_free(files);

	return 0;
}