2003-11-12 00:52:45 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* copydir.c
|
|
|
|
* copies a directory
|
|
|
|
*
|
2004-12-31 23:04:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
2003-11-12 00:52:45 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
2003-05-15 19:59:17 +02:00
|
|
|
* While "xcopy /e /i /q" works fine for copying directories, on Windows XP
|
2003-09-10 22:12:01 +02:00
|
|
|
* it requires a Window handle which prevents it from working when invoked
|
2003-05-15 19:59:17 +02:00
|
|
|
* as a service.
|
2003-09-10 22:12:01 +02:00
|
|
|
*
|
2003-11-12 00:52:45 +01:00
|
|
|
* IDENTIFICATION
|
2005-08-02 21:02:32 +02:00
|
|
|
* $PostgreSQL: pgsql/src/port/copydir.c,v 1.12 2005/08/02 19:02:32 tgl Exp $
|
2003-11-12 00:52:45 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
2003-05-15 19:59:17 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2005-08-02 21:02:32 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2004-02-24 00:03:10 +01:00
|
|
|
#include "storage/fd.h"
|
|
|
|
|
2005-08-02 21:02:32 +02:00
|
|
|
|
|
|
|
static void copy_file(char *fromfile, char *tofile);
|
2003-05-16 03:57:52 +02:00
|
|
|
|
|
|
|
|
2003-09-10 22:12:01 +02:00
|
|
|
/*
|
2005-08-02 21:02:32 +02:00
|
|
|
* copydir: copy a directory
|
2003-09-10 22:12:01 +02:00
|
|
|
*
|
2005-08-02 21:02:32 +02:00
|
|
|
* If recurse is false, subdirectories are ignored. Anything that's not
|
|
|
|
* a directory or a regular file is ignored.
|
2003-09-10 22:12:01 +02:00
|
|
|
*/
|
2005-08-02 21:02:32 +02:00
|
|
|
void
|
|
|
|
copydir(char *fromdir, char *todir, bool recurse)
|
2003-05-15 19:59:17 +02:00
|
|
|
{
|
|
|
|
DIR *xldir;
|
|
|
|
struct dirent *xlde;
|
2005-08-02 21:02:32 +02:00
|
|
|
char fromfile[MAXPGPATH];
|
|
|
|
char tofile[MAXPGPATH];
|
2003-05-15 19:59:17 +02:00
|
|
|
|
2005-08-02 21:02:32 +02:00
|
|
|
if (mkdir(todir, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
|
|
|
|
ereport(ERROR,
|
2003-07-27 19:10:07 +02:00
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not create directory \"%s\": %m", todir)));
|
2005-08-02 21:02:32 +02:00
|
|
|
|
2004-02-24 00:03:10 +01:00
|
|
|
xldir = AllocateDir(fromdir);
|
2003-05-15 19:59:17 +02:00
|
|
|
if (xldir == NULL)
|
2005-08-02 21:02:32 +02:00
|
|
|
ereport(ERROR,
|
2003-07-27 19:10:07 +02:00
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not open directory \"%s\": %m", fromdir)));
|
2005-08-02 21:02:32 +02:00
|
|
|
|
|
|
|
while ((xlde = ReadDir(xldir, fromdir)) != NULL)
|
|
|
|
{
|
|
|
|
struct stat fst;
|
|
|
|
|
|
|
|
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 (stat(fromfile, &fst) < 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not stat \"%s\": %m", fromfile)));
|
|
|
|
|
|
|
|
if (fst.st_mode & S_IFDIR)
|
|
|
|
{
|
|
|
|
/* recurse to handle subdirectories */
|
|
|
|
if (recurse)
|
|
|
|
copydir(fromfile, tofile, true);
|
|
|
|
}
|
|
|
|
else if (fst.st_mode & S_IFREG)
|
|
|
|
copy_file(fromfile, tofile);
|
2003-05-15 19:59:17 +02:00
|
|
|
}
|
|
|
|
|
2005-08-02 21:02:32 +02:00
|
|
|
FreeDir(xldir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* copy one file
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
copy_file(char *fromfile, char *tofile)
|
|
|
|
{
|
|
|
|
char buffer[8 * BLCKSZ];
|
|
|
|
int srcfd;
|
|
|
|
int dstfd;
|
|
|
|
int nbytes;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 (;;)
|
2003-05-15 19:59:17 +02:00
|
|
|
{
|
2005-08-02 21:02:32 +02:00
|
|
|
nbytes = read(srcfd, buffer, sizeof(buffer));
|
|
|
|
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)
|
2003-08-04 02:43:34 +02:00
|
|
|
{
|
2005-08-02 21:02:32 +02:00
|
|
|
/* if write didn't set errno, assume problem is no disk space */
|
|
|
|
if (errno == 0)
|
|
|
|
errno = ENOSPC;
|
|
|
|
ereport(ERROR,
|
2003-08-04 02:43:34 +02:00
|
|
|
(errcode_for_file_access(),
|
2005-08-02 21:02:32 +02:00
|
|
|
errmsg("could not write to file \"%s\": %m", tofile)));
|
2003-08-04 02:43:34 +02:00
|
|
|
}
|
2005-03-24 03:11:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-08-02 21:02:32 +02:00
|
|
|
* Be paranoid here to ensure we catch problems.
|
2005-03-24 03:11:20 +01:00
|
|
|
*/
|
2005-08-02 21:02:32 +02:00
|
|
|
if (pg_fsync(dstfd) != 0)
|
|
|
|
ereport(ERROR,
|
2005-03-24 03:11:20 +01:00
|
|
|
(errcode_for_file_access(),
|
2005-08-02 21:02:32 +02:00
|
|
|
errmsg("could not fsync file \"%s\": %m", tofile)));
|
2003-05-15 19:59:17 +02:00
|
|
|
|
2005-08-02 21:02:32 +02:00
|
|
|
if (close(dstfd))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not close file \"%s\": %m", tofile)));
|
|
|
|
|
|
|
|
close(srcfd);
|
2003-05-15 19:59:17 +02:00
|
|
|
}
|