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