Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/testing/web-platform/tests/css/css-syntax/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 96 B image not shown  

Quellcode-Bibliothek basebackup_server.c  Sprache: unbekannt

 
/*-------------------------------------------------------------------------
 *
 * basebackup_server.c
 *   store basebackup archives on the server
 *
 * IDENTIFICATION
 *   src/backend/backup/basebackup_server.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/xact.h"
#include "backup/basebackup_sink.h"
#include "catalog/pg_authid.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/wait_event.h"

typedef struct bbsink_server
{
 /* Common information for all types of sink. */
 bbsink  base;

 /* Directory in which backup is to be stored. */
 char    *pathname;

 /* Currently open file (or 0 if nothing open). */
 File  file;

 /* Current file position. */
 off_t  filepos;
} bbsink_server;

static void bbsink_server_begin_archive(bbsink *sink,
          const char *archive_name);
static void bbsink_server_archive_contents(bbsink *sink, size_t len);
static void bbsink_server_end_archive(bbsink *sink);
static void bbsink_server_begin_manifest(bbsink *sink);
static void bbsink_server_manifest_contents(bbsink *sink, size_t len);
static void bbsink_server_end_manifest(bbsink *sink);

static const bbsink_ops bbsink_server_ops = {
 .begin_backup = bbsink_forward_begin_backup,
 .begin_archive = bbsink_server_begin_archive,
 .archive_contents = bbsink_server_archive_contents,
 .end_archive = bbsink_server_end_archive,
 .begin_manifest = bbsink_server_begin_manifest,
 .manifest_contents = bbsink_server_manifest_contents,
 .end_manifest = bbsink_server_end_manifest,
 .end_backup = bbsink_forward_end_backup,
 .cleanup = bbsink_forward_cleanup
};

/*
 * Create a new 'server' bbsink.
 */

bbsink *
bbsink_server_new(bbsink *next, char *pathname)
{
 bbsink_server *sink = palloc0(sizeof(bbsink_server));

 *((const bbsink_ops **) &sink->base.bbs_ops) = &bbsink_server_ops;
 sink->pathname = pathname;
 sink->base.bbs_next = next;

 /* Replication permission is not sufficient in this case. */
 StartTransactionCommand();
 if (!has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
  ereport(ERROR,
    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     errmsg("permission denied to create backup stored on server"),
     errdetail("Only roles with privileges of the \"%s\" role may create a backup stored on the server.",
         "pg_write_server_files")));
 CommitTransactionCommand();

 /*
  * It's not a good idea to store your backups in the same directory that
  * you're backing up. If we allowed a relative path here, that could
  * easily happen accidentally, so we don't. The user could still
  * accomplish the same thing by including the absolute path to $PGDATA in
  * the pathname, but that's likely an intentional bad decision rather than
  * an accident.
 */

 if (!is_absolute_path(pathname))
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_NAME),
     errmsg("relative path not allowed for backup stored on server")));

 switch (pg_check_dir(pathname))
 {
  case 0:

   /*
    * Does not exist, so create it using the same permissions we'd
    * use for a new subdirectory of the data directory itself.
 */

   if (MakePGDirectory(pathname) < 0)
    ereport(ERROR,
      (errcode_for_file_access(),
       errmsg("could not create directory \"%s\": %m", pathname)));
   break;

  case 1:
   /* Exists, empty. */
   break;

  case 2:
  case 3:
  case 4:
   /* Exists, not empty. */
   ereport(ERROR,
     (errcode(ERRCODE_DUPLICATE_FILE),
      errmsg("directory \"%s\" exists but is not empty",
       pathname)));
   break;

  default:
   /* Access problem. */
   ereport(ERROR,
     (errcode_for_file_access(),
      errmsg("could not access directory \"%s\": %m",
       pathname)));
 }

 return &sink->base;
}

/*
 * Open the correct output file for this archive.
 */

static void
bbsink_server_begin_archive(bbsink *sink, const char *archive_name)
{
 bbsink_server *mysink = (bbsink_server *) sink;
 char    *filename;

 Assert(mysink->file == 0);
 Assert(mysink->filepos == 0);

 filename = psprintf("%s/%s", mysink->pathname, archive_name);

 mysink->file = PathNameOpenFile(filename,
         O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
 if (mysink->file <= 0)
  ereport(ERROR,
    (errcode_for_file_access(),
     errmsg("could not create file \"%s\": %m", filename)));

 pfree(filename);

 bbsink_forward_begin_archive(sink, archive_name);
}

/*
 * Write the data to the output file.
 */

static void
bbsink_server_archive_contents(bbsink *sink, size_t len)
{
 bbsink_server *mysink = (bbsink_server *) sink;
 int   nbytes;

 nbytes = FileWrite(mysink->file, mysink->base.bbs_buffer, len,
        mysink->filepos, WAIT_EVENT_BASEBACKUP_WRITE);

 if (nbytes != len)
 {
  if (nbytes < 0)
   ereport(ERROR,
     (errcode_for_file_access(),
      errmsg("could not write file \"%s\": %m",
       FilePathName(mysink->file)),
      errhint("Check free disk space.")));
  /* short write: complain appropriately */
  ereport(ERROR,
    (errcode(ERRCODE_DISK_FULL),
     errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
      FilePathName(mysink->file),
      nbytes, (int) len, (unsigned) mysink->filepos),
     errhint("Check free disk space.")));
 }

 mysink->filepos += nbytes;

 bbsink_forward_archive_contents(sink, len);
}

/*
 * fsync and close the current output file.
 */

static void
bbsink_server_end_archive(bbsink *sink)
{
 bbsink_server *mysink = (bbsink_server *) sink;

 /*
  * We intentionally don't use data_sync_elevel here, because the server
  * shouldn't PANIC just because we can't guarantee that the backup has
  * been written down to disk. Running recovery won't fix anything in this
  * case anyway.
 */

 if (FileSync(mysink->file, WAIT_EVENT_BASEBACKUP_SYNC) < 0)
  ereport(ERROR,
    (errcode_for_file_access(),
     errmsg("could not fsync file \"%s\": %m",
      FilePathName(mysink->file))));


 /* We're done with this file now. */
 FileClose(mysink->file);
 mysink->file = 0;
 mysink->filepos = 0;

 bbsink_forward_end_archive(sink);
}

/*
 * Open the output file to which we will write the manifest.
 *
 * Just like pg_basebackup, we write the manifest first under a temporary
 * name and then rename it into place after fsync. That way, if the manifest
 * is there and under the correct name, the user can be sure that the backup
 * completed.
 */

static void
bbsink_server_begin_manifest(bbsink *sink)
{
 bbsink_server *mysink = (bbsink_server *) sink;
 char    *tmp_filename;

 Assert(mysink->file == 0);

 tmp_filename = psprintf("%s/backup_manifest.tmp", mysink->pathname);

 mysink->file = PathNameOpenFile(tmp_filename,
         O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
 if (mysink->file <= 0)
  ereport(ERROR,
    (errcode_for_file_access(),
     errmsg("could not create file \"%s\": %m", tmp_filename)));

 pfree(tmp_filename);

 bbsink_forward_begin_manifest(sink);
}

/*
 * Each chunk of manifest data is sent using a CopyData message.
 */

static void
bbsink_server_manifest_contents(bbsink *sink, size_t len)
{
 bbsink_server *mysink = (bbsink_server *) sink;
 int   nbytes;

 nbytes = FileWrite(mysink->file, mysink->base.bbs_buffer, len,
        mysink->filepos, WAIT_EVENT_BASEBACKUP_WRITE);

 if (nbytes != len)
 {
  if (nbytes < 0)
   ereport(ERROR,
     (errcode_for_file_access(),
      errmsg("could not write file \"%s\": %m",
       FilePathName(mysink->file)),
      errhint("Check free disk space.")));
  /* short write: complain appropriately */
  ereport(ERROR,
    (errcode(ERRCODE_DISK_FULL),
     errmsg("could not write file \"%s\": wrote only %d of %d bytes at offset %u",
      FilePathName(mysink->file),
      nbytes, (int) len, (unsigned) mysink->filepos),
     errhint("Check free disk space.")));
 }

 mysink->filepos += nbytes;

 bbsink_forward_manifest_contents(sink, len);
}

/*
 * fsync the backup manifest, close the file, and then rename it into place.
 */

static void
bbsink_server_end_manifest(bbsink *sink)
{
 bbsink_server *mysink = (bbsink_server *) sink;
 char    *tmp_filename;
 char    *filename;

 /* We're done with this file now. */
 FileClose(mysink->file);
 mysink->file = 0;

 /*
  * Rename it into place. This also fsyncs the temporary file, so we don't
  * need to do that here. We don't use data_sync_elevel here for the same
  * reasons as in bbsink_server_end_archive.
 */

 tmp_filename = psprintf("%s/backup_manifest.tmp", mysink->pathname);
 filename = psprintf("%s/backup_manifest", mysink->pathname);
 durable_rename(tmp_filename, filename, ERROR);
 pfree(filename);
 pfree(tmp_filename);

 bbsink_forward_end_manifest(sink);
}

Messung V0.5 in Prozent
C=93 H=96 G=94

[Seitenstruktur0.17Druckenetwas mehr zur Ethik2026-09-28]