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]>