Fix pg_dump bug in the database-level collation patch. "datcollate" and
[PostgreSQL.git] / src / port / copydir.c
blob8d8c24f5bf52e803fd43926756289864d6448e1f
1 /*-------------------------------------------------------------------------
3 * copydir.c
4 * copies a directory
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * While "xcopy /e /i /q" works fine for copying directories, on Windows XP
10 * it requires a Window handle which prevents it from working when invoked
11 * as a service.
13 * IDENTIFICATION
14 * $PostgreSQL$
16 *-------------------------------------------------------------------------
19 #include "postgres.h"
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
25 #include "storage/fd.h"
28 * On Windows, call non-macro versions of palloc; we can't reference
29 * CurrentMemoryContext in this file because of PGDLLIMPORT conflict.
31 #if defined(WIN32) || defined(__CYGWIN__)
32 #undef palloc
33 #undef pstrdup
34 #define palloc(sz) pgport_palloc(sz)
35 #define pstrdup(str) pgport_pstrdup(str)
36 #endif
39 static void copy_file(char *fromfile, char *tofile);
43 * copydir: copy a directory
45 * If recurse is false, subdirectories are ignored. Anything that's not
46 * a directory or a regular file is ignored.
48 void
49 copydir(char *fromdir, char *todir, bool recurse)
51 DIR *xldir;
52 struct dirent *xlde;
53 char fromfile[MAXPGPATH];
54 char tofile[MAXPGPATH];
56 if (mkdir(todir, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
57 ereport(ERROR,
58 (errcode_for_file_access(),
59 errmsg("could not create directory \"%s\": %m", todir)));
61 xldir = AllocateDir(fromdir);
62 if (xldir == NULL)
63 ereport(ERROR,
64 (errcode_for_file_access(),
65 errmsg("could not open directory \"%s\": %m", fromdir)));
67 while ((xlde = ReadDir(xldir, fromdir)) != NULL)
69 struct stat fst;
71 if (strcmp(xlde->d_name, ".") == 0 ||
72 strcmp(xlde->d_name, "..") == 0)
73 continue;
75 snprintf(fromfile, MAXPGPATH, "%s/%s", fromdir, xlde->d_name);
76 snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
78 if (lstat(fromfile, &fst) < 0)
79 ereport(ERROR,
80 (errcode_for_file_access(),
81 errmsg("could not stat file \"%s\": %m", fromfile)));
83 if (S_ISDIR(fst.st_mode))
85 /* recurse to handle subdirectories */
86 if (recurse)
87 copydir(fromfile, tofile, true);
89 else if (S_ISREG(fst.st_mode))
90 copy_file(fromfile, tofile);
93 FreeDir(xldir);
97 * copy one file
99 static void
100 copy_file(char *fromfile, char *tofile)
102 char *buffer;
103 int srcfd;
104 int dstfd;
105 int nbytes;
107 /* Use palloc to ensure we get a maxaligned buffer */
108 #define COPY_BUF_SIZE (8 * BLCKSZ)
110 buffer = palloc(COPY_BUF_SIZE);
113 * Open the files
115 srcfd = BasicOpenFile(fromfile, O_RDONLY | PG_BINARY, 0);
116 if (srcfd < 0)
117 ereport(ERROR,
118 (errcode_for_file_access(),
119 errmsg("could not open file \"%s\": %m", fromfile)));
121 dstfd = BasicOpenFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
122 S_IRUSR | S_IWUSR);
123 if (dstfd < 0)
124 ereport(ERROR,
125 (errcode_for_file_access(),
126 errmsg("could not create file \"%s\": %m", tofile)));
129 * Do the data copying.
131 for (;;)
133 nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
134 if (nbytes < 0)
135 ereport(ERROR,
136 (errcode_for_file_access(),
137 errmsg("could not read file \"%s\": %m", fromfile)));
138 if (nbytes == 0)
139 break;
140 errno = 0;
141 if ((int) write(dstfd, buffer, nbytes) != nbytes)
143 /* if write didn't set errno, assume problem is no disk space */
144 if (errno == 0)
145 errno = ENOSPC;
146 ereport(ERROR,
147 (errcode_for_file_access(),
148 errmsg("could not write to file \"%s\": %m", tofile)));
153 * Be paranoid here to ensure we catch problems.
155 if (pg_fsync(dstfd) != 0)
156 ereport(ERROR,
157 (errcode_for_file_access(),
158 errmsg("could not fsync file \"%s\": %m", tofile)));
160 if (close(dstfd))
161 ereport(ERROR,
162 (errcode_for_file_access(),
163 errmsg("could not close file \"%s\": %m", tofile)));
165 close(srcfd);
167 pfree(buffer);