1 /*-------------------------------------------------------------------------
2  *
3  * copydir.c
4  *	  copies a directory
5  *
6  * Portions Copyright (c) 1996-2019, 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  *	  src/backend/storage/file/copydir.c
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/copydir.h"
26 #include "storage/fd.h"
27 #include "miscadmin.h"
28 #include "pgstat.h"
29 
30 /*
31  * copydir: copy a directory
32  *
33  * If recurse is false, subdirectories are ignored.  Anything that's not
34  * a directory or a regular file is ignored.
35  */
36 void
37 copydir(char *fromdir, char *todir, bool recurse)
38 {
39 	DIR		   *xldir;
40 	struct dirent *xlde;
41 	char		fromfile[MAXPGPATH * 2];
42 	char		tofile[MAXPGPATH * 2];
43 
44 	if (MakePGDirectory(todir) != 0)
45 		ereport(ERROR,
46 				(errcode_for_file_access(),
47 				 errmsg("could not create directory \"%s\": %m", todir)));
48 
49 	xldir = AllocateDir(fromdir);
50 
51 	while ((xlde = ReadDir(xldir, fromdir)) != NULL)
52 	{
53 		struct stat fst;
54 
55 		/* If we got a cancel signal during the copy of the directory, quit */
56 		CHECK_FOR_INTERRUPTS();
57 
58 		if (strcmp(xlde->d_name, ".") == 0 ||
59 			strcmp(xlde->d_name, "..") == 0)
60 			continue;
61 
62 		snprintf(fromfile, sizeof(fromfile), "%s/%s", fromdir, xlde->d_name);
63 		snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
64 
65 		if (lstat(fromfile, &fst) < 0)
66 			ereport(ERROR,
67 					(errcode_for_file_access(),
68 					 errmsg("could not stat file \"%s\": %m", fromfile)));
69 
70 		if (S_ISDIR(fst.st_mode))
71 		{
72 			/* recurse to handle subdirectories */
73 			if (recurse)
74 				copydir(fromfile, tofile, true);
75 		}
76 		else if (S_ISREG(fst.st_mode))
77 			copy_file(fromfile, tofile);
78 	}
79 	FreeDir(xldir);
80 
81 	/*
82 	 * Be paranoid here and fsync all files to ensure the copy is really done.
83 	 * But if fsync is disabled, we're done.
84 	 */
85 	if (!enableFsync)
86 		return;
87 
88 	xldir = AllocateDir(todir);
89 
90 	while ((xlde = ReadDir(xldir, todir)) != NULL)
91 	{
92 		struct stat fst;
93 
94 		if (strcmp(xlde->d_name, ".") == 0 ||
95 			strcmp(xlde->d_name, "..") == 0)
96 			continue;
97 
98 		snprintf(tofile, sizeof(tofile), "%s/%s", todir, xlde->d_name);
99 
100 		/*
101 		 * We don't need to sync subdirectories here since the recursive
102 		 * copydir will do it before it returns
103 		 */
104 		if (lstat(tofile, &fst) < 0)
105 			ereport(ERROR,
106 					(errcode_for_file_access(),
107 					 errmsg("could not stat file \"%s\": %m", tofile)));
108 
109 		if (S_ISREG(fst.st_mode))
110 			fsync_fname(tofile, false);
111 	}
112 	FreeDir(xldir);
113 
114 	/*
115 	 * It's important to fsync the destination directory itself as individual
116 	 * file fsyncs don't guarantee that the directory entry for the file is
117 	 * synced. Recent versions of ext4 have made the window much wider but
118 	 * it's been true for ext3 and other filesystems in the past.
119 	 */
120 	fsync_fname(todir, true);
121 }
122 
123 /*
124  * copy one file
125  */
126 void
127 copy_file(char *fromfile, char *tofile)
128 {
129 	char	   *buffer;
130 	int			srcfd;
131 	int			dstfd;
132 	int			nbytes;
133 	off_t		offset;
134 	off_t		flush_offset;
135 
136 	/* Size of copy buffer (read and write requests) */
137 #define COPY_BUF_SIZE (8 * BLCKSZ)
138 
139 	/*
140 	 * Size of data flush requests.  It seems beneficial on most platforms to
141 	 * do this every 1MB or so.  But macOS, at least with early releases of
scan_sound_chans(beg = 0, fin = false, snd = false, edpos = false, &body)142 	 * APFS, is really unfriendly to small mmap/msync requests, so there do it
143 	 * only every 32MB.
144 	 */
145 #if defined(__darwin__)
146 #define FLUSH_DISTANCE (32 * 1024 * 1024)
147 #else
148 #define FLUSH_DISTANCE (1024 * 1024)
149 #endif
150 
151 	/* Use palloc to ensure we get a maxaligned buffer */
152 	buffer = palloc(COPY_BUF_SIZE);
153 
154 	/*
155 	 * Open the files
156 	 */
157 	srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
158 	if (srcfd < 0)
159 		ereport(ERROR,
160 				(errcode_for_file_access(),
161 				 errmsg("could not open file \"%s\": %m", fromfile)));
162 
map_sound_chans(beg = 0, fin = false, edname = false, snd = false, edpos = false, &body)163 	dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
164 	if (dstfd < 0)
165 		ereport(ERROR,
166 				(errcode_for_file_access(),
167 				 errmsg("could not create file \"%s\": %m", tofile)));
168 
169 	/*
170 	 * Do the data copying.
171 	 */
172 	flush_offset = 0;
173 	for (offset = 0;; offset += nbytes)
174 	{
175 		/* If we got a cancel signal during the copy of the file, quit */
176 		CHECK_FOR_INTERRUPTS();
177 
scan_all_chans(beg = 0, fin = false, edpos = false, &body)178 		/*
179 		 * We fsync the files later, but during the copy, flush them every so
180 		 * often to avoid spamming the cache and hopefully get the kernel to
181 		 * start writing them out before the fsync comes.
182 		 */
183 		if (offset - flush_offset >= FLUSH_DISTANCE)
184 		{
185 			pg_flush_data(dstfd, flush_offset, offset - flush_offset);
186 			flush_offset = offset;
187 		}
188 
189 		pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ);
190 		nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
191 		pgstat_report_wait_end();
192 		if (nbytes < 0)
193 			ereport(ERROR,
194 					(errcode_for_file_access(),
195 					 errmsg("could not read file \"%s\": %m", fromfile)));
196 		if (nbytes == 0)
197 			break;
198 		errno = 0;
map_all_chans(beg = 0, fin = false, edname = false, edpos = false, &body)199 		pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE);
200 		if ((int) write(dstfd, buffer, nbytes) != nbytes)
201 		{
202 			/* if write didn't set errno, assume problem is no disk space */
203 			if (errno == 0)
204 				errno = ENOSPC;
205 			ereport(ERROR,
206 					(errcode_for_file_access(),
207 					 errmsg("could not write to file \"%s\": %m", tofile)));
208 		}
209 		pgstat_report_wait_end();
210 	}
211 
212 	if (offset > flush_offset)
213 		pg_flush_data(dstfd, flush_offset, offset - flush_offset);
214 
scan_chans(beg = 0, fin = false, edpos = false, &body)215 	if (CloseTransientFile(dstfd))
216 		ereport(ERROR,
217 				(errcode_for_file_access(),
218 				 errmsg("could not close file \"%s\": %m", tofile)));
219 
220 	if (CloseTransientFile(srcfd))
221 		ereport(ERROR,
222 				(errcode_for_file_access(),
223 				 errmsg("could not close file \"%s\": %m", fromfile)));
224 
225 	pfree(buffer);
226 }
227