Logo Search packages:      
Sourcecode: postgresql-8.4 version File versions  Download package

copydir.c
/*-------------------------------------------------------------------------
 *
 * copydir.c
 *      copies a directory
 *
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *    While "xcopy /e /i /q" works fine for copying directories, on Windows XP
 *    it requires a Window handle which prevents it from working when invoked
 *    as a service.
 *
 * IDENTIFICATION
 *      $PostgreSQL: pgsql/src/backend/storage/file/copydir.c,v 1.1.2.1 2010/07/02 17:03:38 rhaas Exp $
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

#include "storage/fd.h"
#include "miscadmin.h"

/*
 *    On Windows, call non-macro versions of palloc; we can't reference
 *    CurrentMemoryContext in this file because of PGDLLIMPORT conflict.
 */
#if defined(WIN32) || defined(__CYGWIN__)
#undef palloc
#undef pstrdup
#define palloc(sz)            pgport_palloc(sz)
#define pstrdup(str)    pgport_pstrdup(str)
#endif


static void copy_file(char *fromfile, char *tofile);


/*
 * copydir: copy a directory
 *
 * If recurse is false, subdirectories are ignored.  Anything that's not
 * a directory or a regular file is ignored.
 */
void
copydir(char *fromdir, char *todir, bool recurse)
{
      DIR            *xldir;
      struct dirent *xlde;
      char        fromfile[MAXPGPATH];
      char        tofile[MAXPGPATH];

      if (mkdir(todir, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
            ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not create directory \"%s\": %m", todir)));

      xldir = AllocateDir(fromdir);
      if (xldir == NULL)
            ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not open directory \"%s\": %m", fromdir)));

      while ((xlde = ReadDir(xldir, fromdir)) != NULL)
      {
            struct stat fst;

        /* If we got a cancel signal during the copy of the directory, quit */
        CHECK_FOR_INTERRUPTS();

            if (strcmp(xlde->d_name, ".") == 0 ||
                  strcmp(xlde->d_name, "..") == 0)
                  continue;

            snprintf(fromfile, MAXPGPATH, "%s/%s", fromdir, xlde->d_name);
            snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);

            if (lstat(fromfile, &fst) < 0)
                  ereport(ERROR,
                              (errcode_for_file_access(),
                               errmsg("could not stat file \"%s\": %m", fromfile)));

            if (S_ISDIR(fst.st_mode))
            {
                  /* recurse to handle subdirectories */
                  if (recurse)
                        copydir(fromfile, tofile, true);
            }
            else if (S_ISREG(fst.st_mode))
                  copy_file(fromfile, tofile);
      }

      FreeDir(xldir);
}

/*
 * copy one file
 */
static void
copy_file(char *fromfile, char *tofile)
{
      char     *buffer;
      int               srcfd;
      int               dstfd;
      int               nbytes;

      /* Use palloc to ensure we get a maxaligned buffer */
#define COPY_BUF_SIZE (8 * BLCKSZ)

      buffer = palloc(COPY_BUF_SIZE);

      /*
       * Open the files
       */
      srcfd = BasicOpenFile(fromfile, O_RDONLY | PG_BINARY, 0);
      if (srcfd < 0)
            ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not open file \"%s\": %m", fromfile)));

      dstfd = BasicOpenFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                                      S_IRUSR | S_IWUSR);
      if (dstfd < 0)
            ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not create file \"%s\": %m", tofile)));

      /*
       * Do the data copying.
       */
      for (;;)
      {
        /* If we got a cancel signal during the copy of the file, quit */
        CHECK_FOR_INTERRUPTS();

            nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
            if (nbytes < 0)
                  ereport(ERROR,
                              (errcode_for_file_access(),
                               errmsg("could not read file \"%s\": %m", fromfile)));
            if (nbytes == 0)
                  break;
            errno = 0;
            if ((int) write(dstfd, buffer, nbytes) != nbytes)
            {
                  /* if write didn't set errno, assume problem is no disk space */
                  if (errno == 0)
                        errno = ENOSPC;
                  ereport(ERROR,
                              (errcode_for_file_access(),
                               errmsg("could not write to file \"%s\": %m", tofile)));
            }
      }

      /*
       * Be paranoid here to ensure we catch problems.
       */
      if (pg_fsync(dstfd) != 0)
            ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not fsync file \"%s\": %m", tofile)));

      if (close(dstfd))
            ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not close file \"%s\": %m", tofile)));

      close(srcfd);

      pfree(buffer);
}

Generated by  Doxygen 1.6.0   Back to index