]> granicus.if.org Git - postgresql/blob - src/port/copydir.c
8.4 pgindent run, with new combined Linux/FreeBSD/MinGW typedef list
[postgresql] / src / port / copydir.c
1 /*-------------------------------------------------------------------------
2  *
3  * copydir.c
4  *        copies a directory
5  *
6  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
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.
12  *
13  * IDENTIFICATION
14  *        $PostgreSQL: pgsql/src/port/copydir.c,v 1.23 2009/01/01 17:24:04 momjian Exp $
15  *
16  *-------------------------------------------------------------------------
17  */
18
19 #include "postgres.h"
20
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
24
25 #include "storage/fd.h"
26
27 /*
28  *      On Windows, call non-macro versions of palloc; we can't reference
29  *      CurrentMemoryContext in this file because of PGDLLIMPORT conflict.
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
38
39 static void copy_file(char *fromfile, char *tofile);
40
41
42 /*
43  * copydir: copy a directory
44  *
45  * If recurse is false, subdirectories are ignored.  Anything that's not
46  * a directory or a regular file is ignored.
47  */
48 void
49 copydir(char *fromdir, char *todir, bool recurse)
50 {
51         DIR                *xldir;
52         struct dirent *xlde;
53         char            fromfile[MAXPGPATH];
54         char            tofile[MAXPGPATH];
55
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)));
60
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)));
66
67         while ((xlde = ReadDir(xldir, fromdir)) != NULL)
68         {
69                 struct stat fst;
70
71                 if (strcmp(xlde->d_name, ".") == 0 ||
72                         strcmp(xlde->d_name, "..") == 0)
73                         continue;
74
75                 snprintf(fromfile, MAXPGPATH, "%s/%s", fromdir, xlde->d_name);
76                 snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name);
77
78                 if (lstat(fromfile, &fst) < 0)
79                         ereport(ERROR,
80                                         (errcode_for_file_access(),
81                                          errmsg("could not stat file \"%s\": %m", fromfile)));
82
83                 if (S_ISDIR(fst.st_mode))
84                 {
85                         /* recurse to handle subdirectories */
86                         if (recurse)
87                                 copydir(fromfile, tofile, true);
88                 }
89                 else if (S_ISREG(fst.st_mode))
90                         copy_file(fromfile, tofile);
91         }
92
93         FreeDir(xldir);
94 }
95
96 /*
97  * copy one file
98  */
99 static void
100 copy_file(char *fromfile, char *tofile)
101 {
102         char       *buffer;
103         int                     srcfd;
104         int                     dstfd;
105         int                     nbytes;
106
107         /* Use palloc to ensure we get a maxaligned buffer */
108 #define COPY_BUF_SIZE (8 * BLCKSZ)
109
110         buffer = palloc(COPY_BUF_SIZE);
111
112         /*
113          * Open the files
114          */
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)));
120
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)));
127
128         /*
129          * Do the data copying.
130          */
131         for (;;)
132         {
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)
142                 {
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)));
149                 }
150         }
151
152         /*
153          * Be paranoid here to ensure we catch problems.
154          */
155         if (pg_fsync(dstfd) != 0)
156                 ereport(ERROR,
157                                 (errcode_for_file_access(),
158                                  errmsg("could not fsync file \"%s\": %m", tofile)));
159
160         if (close(dstfd))
161                 ereport(ERROR,
162                                 (errcode_for_file_access(),
163                                  errmsg("could not close file \"%s\": %m", tofile)));
164
165         close(srcfd);
166
167         pfree(buffer);
168 }