Annotation of pgsql/src/port/copydir.c, revision 1.30
1.6 momjian 1: /*-------------------------------------------------------------------------
2: *
3: * copydir.c
4: * copies a directory
5: *
1.24 momjian 6: * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
1.6 momjian 7: * Portions Copyright (c) 1994, Regents of the University of California
8: *
1.1 momjian 9: * While "xcopy /e /i /q" works fine for copying directories, on Windows XP
1.5 tgl 10: * it requires a Window handle which prevents it from working when invoked
1.1 momjian 11: * as a service.
1.5 tgl 12: *
1.6 momjian 13: * IDENTIFICATION
1.30 ! tgl 14: * $PostgreSQL: pgsql/src/port/copydir.c,v 1.29 2010/02/22 00:11:05 stark Exp $
1.6 momjian 15: *
16: *-------------------------------------------------------------------------
1.1 momjian 17: */
18:
19: #include "postgres.h"
20:
1.12 tgl 21: #include <fcntl.h>
22: #include <unistd.h>
23: #include <sys/stat.h>
24:
1.8 tgl 25: #include "storage/fd.h"
26:
1.14 tgl 27: /*
28: * On Windows, call non-macro versions of palloc; we can't reference
1.20 mha 29: * CurrentMemoryContext in this file because of PGDLLIMPORT conflict.
1.14 tgl 30: */
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
37:
1.12 tgl 38:
39: static void copy_file(char *fromfile, char *tofile);
1.26 stark 40: static void fsync_fname(char *fname);
1.2 momjian 41:
42:
1.5 tgl 43: /*
1.12 tgl 44: * copydir: copy a directory
1.5 tgl 45: *
1.12 tgl 46: * If recurse is false, subdirectories are ignored. Anything that's not
47: * a directory or a regular file is ignored.
1.5 tgl 48: */
1.12 tgl 49: void
50: copydir(char *fromdir, char *todir, bool recurse)
1.1 momjian 51: {
52: DIR *xldir;
53: struct dirent *xlde;
1.12 tgl 54: char fromfile[MAXPGPATH];
55: char tofile[MAXPGPATH];
1.1 momjian 56:
1.12 tgl 57: if (mkdir(todir, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
58: ereport(ERROR,
1.3 tgl 59: (errcode_for_file_access(),
60: errmsg("could not create directory \"%s\": %m", todir)));
1.12 tgl 61:
1.8 tgl 62: xldir = AllocateDir(fromdir);
1.1 momjian 63: if (xldir == NULL)
1.12 tgl 64: ereport(ERROR,
1.3 tgl 65: (errcode_for_file_access(),
66: errmsg("could not open directory \"%s\": %m", fromdir)));
1.12 tgl 67:
68: while ((xlde = ReadDir(xldir, fromdir)) != NULL)
69: {
1.15 momjian 70: struct stat fst;
1.12 tgl 71:
1.15 momjian 72: if (strcmp(xlde->d_name, ".") == 0 ||
1.12 tgl 73: strcmp(xlde->d_name, "..") == 0)
1.15 momjian 74: continue;
1.12 tgl 75:
76: snprintf(fromfile, MAXPGPATH, "%s/%s", fromdir, xlde->d_name);
77: snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
78:
1.18 tgl 79: if (lstat(fromfile, &fst) < 0)
1.12 tgl 80: ereport(ERROR,
81: (errcode_for_file_access(),
1.16 petere 82: errmsg("could not stat file \"%s\": %m", fromfile)));
1.12 tgl 83:
1.22 tgl 84: if (S_ISDIR(fst.st_mode))
1.12 tgl 85: {
86: /* recurse to handle subdirectories */
87: if (recurse)
88: copydir(fromfile, tofile, true);
89: }
1.22 tgl 90: else if (S_ISREG(fst.st_mode))
1.12 tgl 91: copy_file(fromfile, tofile);
1.1 momjian 92: }
1.30 ! tgl 93: FreeDir(xldir);
1.1 momjian 94:
1.25 stark 95: /*
1.30 ! tgl 96: * Be paranoid here and fsync all files to ensure the copy is really done.
1.25 stark 97: */
1.30 ! tgl 98: xldir = AllocateDir(todir);
1.26 stark 99: if (xldir == NULL)
1.25 stark 100: ereport(ERROR,
1.26 stark 101: (errcode_for_file_access(),
1.30 ! tgl 102: errmsg("could not open directory \"%s\": %m", todir)));
1.25 stark 103:
1.30 ! tgl 104: while ((xlde = ReadDir(xldir, todir)) != NULL)
1.26 stark 105: {
1.28 stark 106: struct stat fst;
107:
1.26 stark 108: if (strcmp(xlde->d_name, ".") == 0 ||
109: strcmp(xlde->d_name, "..") == 0)
110: continue;
111:
112: snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
1.28 stark 113:
1.30 ! tgl 114: /*
! 115: * We don't need to sync subdirectories here since the recursive
! 116: * copydir will do it before it returns
! 117: */
! 118: if (lstat(tofile, &fst) < 0)
1.28 stark 119: ereport(ERROR,
120: (errcode_for_file_access(),
1.30 ! tgl 121: errmsg("could not stat file \"%s\": %m", tofile)));
! 122:
1.28 stark 123: if (S_ISREG(fst.st_mode))
124: fsync_fname(tofile);
1.26 stark 125: }
126: FreeDir(xldir);
127:
1.28 stark 128: #ifdef NOTYET
1.30 ! tgl 129: /*
! 130: * It's important to fsync the destination directory itself as
1.26 stark 131: * individual file fsyncs don't guarantee that the directory entry
132: * for the file is synced. Recent versions of ext4 have made the
133: * window much wider but it's been true for ext3 and other
1.30 ! tgl 134: * filesystems in the past.
! 135: *
! 136: * However we can't do this just yet, it has portability issues.
1.26 stark 137: */
138: fsync_fname(todir);
1.28 stark 139: #endif
1.12 tgl 140: }
141:
142: /*
143: * copy one file
144: */
145: static void
146: copy_file(char *fromfile, char *tofile)
147: {
1.13 tgl 148: char *buffer;
1.12 tgl 149: int srcfd;
150: int dstfd;
151: int nbytes;
1.26 stark 152: off_t offset;
1.12 tgl 153:
1.13 tgl 154: /* Use palloc to ensure we get a maxaligned buffer */
155: #define COPY_BUF_SIZE (8 * BLCKSZ)
156:
157: buffer = palloc(COPY_BUF_SIZE);
158:
1.12 tgl 159: /*
160: * Open the files
161: */
162: srcfd = BasicOpenFile(fromfile, O_RDONLY | PG_BINARY, 0);
163: if (srcfd < 0)
164: ereport(ERROR,
165: (errcode_for_file_access(),
166: errmsg("could not open file \"%s\": %m", fromfile)));
167:
168: dstfd = BasicOpenFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
169: S_IRUSR | S_IWUSR);
170: if (dstfd < 0)
171: ereport(ERROR,
172: (errcode_for_file_access(),
173: errmsg("could not create file \"%s\": %m", tofile)));
174:
175: /*
176: * Do the data copying.
177: */
1.26 stark 178: for (offset=0; ; offset+=nbytes)
1.1 momjian 179: {
1.13 tgl 180: nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
1.12 tgl 181: if (nbytes < 0)
182: ereport(ERROR,
183: (errcode_for_file_access(),
184: errmsg("could not read file \"%s\": %m", fromfile)));
185: if (nbytes == 0)
186: break;
187: errno = 0;
188: if ((int) write(dstfd, buffer, nbytes) != nbytes)
1.4 momjian 189: {
1.12 tgl 190: /* if write didn't set errno, assume problem is no disk space */
191: if (errno == 0)
192: errno = ENOSPC;
193: ereport(ERROR,
1.4 momjian 194: (errcode_for_file_access(),
1.12 tgl 195: errmsg("could not write to file \"%s\": %m", tofile)));
1.4 momjian 196: }
1.26 stark 197:
198: /*
199: * We fsync the files later but first flush them to avoid spamming
200: * the cache and hopefully get the kernel to start writing them
201: * out before the fsync comes.
202: */
203: pg_flush_data(dstfd, offset, nbytes);
1.11 tgl 204: }
205:
1.12 tgl 206: if (close(dstfd))
207: ereport(ERROR,
1.11 tgl 208: (errcode_for_file_access(),
1.12 tgl 209: errmsg("could not close file \"%s\": %m", tofile)));
1.1 momjian 210:
1.12 tgl 211: close(srcfd);
1.13 tgl 212:
213: pfree(buffer);
1.1 momjian 214: }
1.26 stark 215:
216:
217: /*
218: * fsync a file
219: */
220: static void
221: fsync_fname(char *fname)
222: {
223: int fd = BasicOpenFile(fname,
224: O_RDONLY | PG_BINARY,
225: S_IRUSR | S_IWUSR);
226:
227: if (fd < 0)
228: ereport(ERROR,
229: (errcode_for_file_access(),
230: errmsg("could not open file \"%s\": %m", fname)));
231:
232: if (pg_fsync(fd) != 0)
233: ereport(ERROR,
234: (errcode_for_file_access(),
235: errmsg("could not fsync file \"%s\": %m", fname)));
236: close(fd);
237: }
PostgreSQL CVSweb <[email protected]>