Annotation of pgsql/src/port/copydir.c, revision 1.16.2.2

1.6       momjian     1: /*-------------------------------------------------------------------------
                      2:  *
                      3:  * copydir.c
                      4:  *       copies a directory
                      5:  *
1.10      pgsql       6:  * Portions Copyright (c) 1996-2005, 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.16.2.2! stark      14:  *       $PostgreSQL: pgsql/src/port/copydir.c,v 1.16.2.1 2008/03/31 01:32:48 tgl 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
                     29:  *     CurrentMemoryContext in this file because of DLLIMPORT 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: 
1.12      tgl        38: 
                     39: static void copy_file(char *fromfile, char *tofile);
1.2       momjian    40: 
                     41: 
1.5       tgl        42: /*
1.12      tgl        43:  * copydir: copy a directory
1.5       tgl        44:  *
1.12      tgl        45:  * If recurse is false, subdirectories are ignored.  Anything that's not
                     46:  * a directory or a regular file is ignored.
1.5       tgl        47:  */
1.12      tgl        48: void
                     49: copydir(char *fromdir, char *todir, bool recurse)
1.1       momjian    50: {
                     51:        DIR                *xldir;
                     52:        struct dirent *xlde;
1.16.2.2! stark      53:        int         dirfd;
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: 
                     79:                if (stat(fromfile, &fst) < 0)
                     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.16.2.1  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.16.2.1  tgl        90:                else if (S_ISREG(fst.st_mode))
1.12      tgl        91:                        copy_file(fromfile, tofile);
1.1       momjian    92:        }
                     93: 
1.12      tgl        94:        FreeDir(xldir);
1.16.2.2! stark      95: 
        !            96:        /*
        !            97:         * fsync the directory to make sure not just the data but also the
        !            98:         * new directory file entries have reached the disk. While needed
        !            99:         * by most filesystems, the window got bigger with newer ones like
        !           100:         * ext4.
        !           101:         */
        !           102:        dirfd = BasicOpenFile(todir,
        !           103:                              O_RDONLY | PG_BINARY,
        !           104:                              S_IRUSR | S_IWUSR);
        !           105:        if(dirfd == -1)
        !           106:                ereport(ERROR,
        !           107:                        (errcode_for_file_access(),
        !           108:                         errmsg("could not open directory for fsync \"%s\": %m", todir)));
        !           109: 
        !           110:        if(pg_fsync(dirfd) == -1)
        !           111:                ereport(ERROR,
        !           112:                                (errcode_for_file_access(),
        !           113:                                 errmsg("could not fsync directory \"%s\": %m", todir)));
        !           114:        close(dirfd);
1.12      tgl       115: }
                    116: 
                    117: /*
                    118:  * copy one file
                    119:  */
                    120: static void
                    121: copy_file(char *fromfile, char *tofile)
                    122: {
1.13      tgl       123:        char       *buffer;
1.12      tgl       124:        int                     srcfd;
                    125:        int                     dstfd;
                    126:        int                     nbytes;
                    127: 
1.13      tgl       128:        /* Use palloc to ensure we get a maxaligned buffer */
                    129: #define COPY_BUF_SIZE (8 * BLCKSZ)
                    130: 
                    131:        buffer = palloc(COPY_BUF_SIZE);
                    132: 
1.12      tgl       133:        /*
                    134:         * Open the files
                    135:         */
                    136:        srcfd = BasicOpenFile(fromfile, O_RDONLY | PG_BINARY, 0);
                    137:        if (srcfd < 0)
                    138:                ereport(ERROR,
                    139:                                (errcode_for_file_access(),
                    140:                                 errmsg("could not open file \"%s\": %m", fromfile)));
                    141: 
                    142:        dstfd = BasicOpenFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
                    143:                                                  S_IRUSR | S_IWUSR);
                    144:        if (dstfd < 0)
                    145:                ereport(ERROR,
                    146:                                (errcode_for_file_access(),
                    147:                                 errmsg("could not create file \"%s\": %m", tofile)));
                    148: 
                    149:        /*
                    150:         * Do the data copying.
                    151:         */
                    152:        for (;;)
1.1       momjian   153:        {
1.13      tgl       154:                nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
1.12      tgl       155:                if (nbytes < 0)
                    156:                        ereport(ERROR,
                    157:                                        (errcode_for_file_access(),
                    158:                                         errmsg("could not read file \"%s\": %m", fromfile)));
                    159:                if (nbytes == 0)
                    160:                        break;
                    161:                errno = 0;
                    162:                if ((int) write(dstfd, buffer, nbytes) != nbytes)
1.4       momjian   163:                {
1.12      tgl       164:                        /* if write didn't set errno, assume problem is no disk space */
                    165:                        if (errno == 0)
                    166:                                errno = ENOSPC;
                    167:                        ereport(ERROR,
1.4       momjian   168:                                        (errcode_for_file_access(),
1.12      tgl       169:                                         errmsg("could not write to file \"%s\": %m", tofile)));
1.4       momjian   170:                }
1.11      tgl       171:        }
                    172: 
                    173:        /*
1.12      tgl       174:         * Be paranoid here to ensure we catch problems.
1.11      tgl       175:         */
1.12      tgl       176:        if (pg_fsync(dstfd) != 0)
                    177:                ereport(ERROR,
                    178:                                (errcode_for_file_access(),
                    179:                                 errmsg("could not fsync file \"%s\": %m", tofile)));
                    180: 
                    181:        if (close(dstfd))
                    182:                ereport(ERROR,
1.11      tgl       183:                                (errcode_for_file_access(),
1.12      tgl       184:                                 errmsg("could not close file \"%s\": %m", tofile)));
1.1       momjian   185: 
1.12      tgl       186:        close(srcfd);
1.13      tgl       187: 
                    188:        pfree(buffer);
1.1       momjian   189: }

PostgreSQL CVSweb <[email protected]>