OSDN Git Service

Update copyright for 2009.
[pg-rex/syncrep.git] / src / port / dirmod.c
1 /*-------------------------------------------------------------------------
2  *
3  * dirmod.c
4  *        rename/unlink()
5  *
6  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *      These are replacement versions of unlink and rename that work on
10  *      Win32 (NT, Win2k, XP).  replace() doesn't work on Win95/98/Me.
11  *
12  * IDENTIFICATION
13  *        $PostgreSQL: pgsql/src/port/dirmod.c,v 1.56 2009/01/01 17:24:04 momjian Exp $
14  *
15  *-------------------------------------------------------------------------
16  */
17
18 #ifndef FRONTEND
19 #include "postgres.h"
20 #else
21 #include "postgres_fe.h"
22 #endif
23
24 /* Don't modify declarations in system headers */
25 #if defined(WIN32) || defined(__CYGWIN__)
26 #undef rename
27 #undef unlink
28 #endif
29
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <sys/stat.h>
33
34 #if defined(WIN32) || defined(__CYGWIN__)
35 #ifndef __CYGWIN__
36 #include <winioctl.h>
37 #else
38 #include <windows.h>
39 #include <w32api/winioctl.h>
40 #endif
41 #endif
42
43
44 #ifndef FRONTEND
45
46 /*
47  *      On Windows, call non-macro versions of palloc; we can't reference
48  *      CurrentMemoryContext in this file because of PGDLLIMPORT conflict.
49  */
50 #if defined(WIN32) || defined(__CYGWIN__)
51 #undef palloc
52 #undef pstrdup
53 #define palloc(sz)              pgport_palloc(sz)
54 #define pstrdup(str)    pgport_pstrdup(str)
55 #endif
56 #else                                                   /* FRONTEND */
57
58 /*
59  *      In frontend, fake palloc behavior with these
60  */
61 #undef palloc
62 #undef pstrdup
63 #define palloc(sz)              fe_palloc(sz)
64 #define pstrdup(str)    fe_pstrdup(str)
65 #define repalloc(pointer,sz)    fe_repalloc(pointer,sz)
66 #define pfree(pointer)  free(pointer)
67
68 static void *
69 fe_palloc(Size size)
70 {
71         void       *res;
72
73         if ((res = malloc(size)) == NULL)
74         {
75                 fprintf(stderr, _("out of memory\n"));
76                 exit(1);
77         }
78         return res;
79 }
80
81 static char *
82 fe_pstrdup(const char *string)
83 {
84         char       *res;
85
86         if ((res = strdup(string)) == NULL)
87         {
88                 fprintf(stderr, _("out of memory\n"));
89                 exit(1);
90         }
91         return res;
92 }
93
94 static void *
95 fe_repalloc(void *pointer, Size size)
96 {
97         void       *res;
98
99         if ((res = realloc(pointer, size)) == NULL)
100         {
101                 fprintf(stderr, _("out of memory\n"));
102                 exit(1);
103         }
104         return res;
105 }
106 #endif   /* FRONTEND */
107
108
109 #if defined(WIN32) || defined(__CYGWIN__)
110
111 /*
112  *      pgrename
113  */
114 int
115 pgrename(const char *from, const char *to)
116 {
117         int                     loops = 0;
118
119         /*
120          * We need to loop because even though PostgreSQL uses flags that allow
121          * rename while the file is open, other applications might have the file
122          * open without those flags.  However, we won't wait indefinitely for
123          * someone else to close the file.
124          */
125 #if defined(WIN32) && !defined(__CYGWIN__)
126         while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
127 #else
128         while (rename(from, to) < 0)
129 #endif
130         {
131 #if defined(WIN32) && !defined(__CYGWIN__)
132                 if (GetLastError() != ERROR_ACCESS_DENIED)
133 #else
134                 if (errno != EACCES)
135 #endif
136                         /* set errno? */
137                         return -1;
138                 if (++loops > 300)              /* time out after 30 sec */
139                         return -1;
140                 pg_usleep(100000);              /* us */
141         }
142         return 0;
143 }
144
145
146 /*
147  *      pgunlink
148  */
149 int
150 pgunlink(const char *path)
151 {
152         int                     loops = 0;
153
154         /*
155          * We need to loop because even though PostgreSQL uses flags that allow
156          * unlink while the file is open, other applications might have the file
157          * open without those flags.  However, we won't wait indefinitely for
158          * someone else to close the file.
159          */
160         while (unlink(path))
161         {
162                 if (errno != EACCES)
163                         /* set errno? */
164                         return -1;
165                 if (++loops > 300)              /* time out after 30 sec */
166                         return -1;
167                 pg_usleep(100000);              /* us */
168         }
169         return 0;
170 }
171
172 /* We undefined these above; now redefine for possible use below */
173 #define rename(from, to)                pgrename(from, to)
174 #define unlink(path)                    pgunlink(path)
175 #endif   /* defined(WIN32) || defined(__CYGWIN__) */
176
177
178 #if defined(WIN32) && !defined(__CYGWIN__)              /* Cygwin has its own symlinks */
179
180 /*
181  *      pgsymlink support:
182  *
183  *      This struct is a replacement for REPARSE_DATA_BUFFER which is defined in VC6 winnt.h
184  *      but omitted in later SDK functions.
185  *      We only need the SymbolicLinkReparseBuffer part of the original struct's union.
186  */
187 typedef struct
188 {
189         DWORD           ReparseTag;
190         WORD            ReparseDataLength;
191         WORD            Reserved;
192         /* SymbolicLinkReparseBuffer */
193         WORD            SubstituteNameOffset;
194         WORD            SubstituteNameLength;
195         WORD            PrintNameOffset;
196         WORD            PrintNameLength;
197         WCHAR           PathBuffer[1];
198 }       REPARSE_JUNCTION_DATA_BUFFER;
199
200 #define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE   \
201                 FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset)
202
203
204 /*
205  *      pgsymlink - uses Win32 junction points
206  *
207  *      For reference:  http://www.codeproject.com/w2k/junctionpoints.asp
208  */
209 int
210 pgsymlink(const char *oldpath, const char *newpath)
211 {
212         HANDLE          dirhandle;
213         DWORD           len;
214         char            buffer[MAX_PATH * sizeof(WCHAR) + sizeof(REPARSE_JUNCTION_DATA_BUFFER)];
215         char            nativeTarget[MAX_PATH];
216         char       *p = nativeTarget;
217         REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
218
219         CreateDirectory(newpath, 0);
220         dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
221                                                    0, 0, OPEN_EXISTING,
222                            FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
223
224         if (dirhandle == INVALID_HANDLE_VALUE)
225                 return -1;
226
227         /* make sure we have an unparsed native win32 path */
228         if (memcmp("\\??\\", oldpath, 4))
229                 sprintf(nativeTarget, "\\??\\%s", oldpath);
230         else
231                 strcpy(nativeTarget, oldpath);
232
233         while ((p = strchr(p, '/')) != 0)
234                 *p++ = '\\';
235
236         len = strlen(nativeTarget) * sizeof(WCHAR);
237         reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
238         reparseBuf->ReparseDataLength = len + 12;
239         reparseBuf->Reserved = 0;
240         reparseBuf->SubstituteNameOffset = 0;
241         reparseBuf->SubstituteNameLength = len;
242         reparseBuf->PrintNameOffset = len + sizeof(WCHAR);
243         reparseBuf->PrintNameLength = 0;
244         MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1,
245                                                 reparseBuf->PathBuffer, MAX_PATH);
246
247         /*
248          * FSCTL_SET_REPARSE_POINT is coded differently depending on SDK version;
249          * we use our own definition
250          */
251         if (!DeviceIoControl(dirhandle,
252          CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS),
253                                                  reparseBuf,
254         reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE,
255                                                  0, 0, &len, 0))
256         {
257                 LPSTR           msg;
258
259                 errno = 0;
260                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
261                                           NULL, GetLastError(),
262                                           MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
263                                           (LPSTR) & msg, 0, NULL);
264 #ifndef FRONTEND
265                 ereport(ERROR,
266                                 (errcode_for_file_access(),
267                                  errmsg("could not set junction for \"%s\": %s",
268                                                 nativeTarget, msg)));
269 #else
270                 fprintf(stderr, _("could not set junction for \"%s\": %s\n"),
271                                 nativeTarget, msg);
272 #endif
273                 LocalFree(msg);
274
275                 CloseHandle(dirhandle);
276                 RemoveDirectory(newpath);
277                 return -1;
278         }
279
280         CloseHandle(dirhandle);
281
282         return 0;
283 }
284 #endif   /* defined(WIN32) && !defined(__CYGWIN__) */
285
286
287 /*
288  * pgfnames
289  *
290  * return a list of the names of objects in the argument directory.  Caller
291  * must call pgfnames_cleanup later to free the memory allocated by this
292  * function.
293  */
294 char **
295 pgfnames(const char *path)
296 {
297         DIR                *dir;
298         struct dirent *file;
299         char      **filenames;
300         int                     numnames = 0;
301         int                     fnsize = 200;   /* enough for many small dbs */
302
303         dir = opendir(path);
304         if (dir == NULL)
305         {
306 #ifndef FRONTEND
307                 elog(WARNING, "could not open directory \"%s\": %m", path);
308 #else
309                 fprintf(stderr, _("could not open directory \"%s\": %s\n"),
310                                 path, strerror(errno));
311 #endif
312                 return NULL;
313         }
314
315         filenames = (char **) palloc(fnsize * sizeof(char *));
316
317         errno = 0;
318         while ((file = readdir(dir)) != NULL)
319         {
320                 if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0)
321                 {
322                         if (numnames + 1 >= fnsize)
323                         {
324                                 fnsize *= 2;
325                                 filenames = (char **) repalloc(filenames,
326                                                                                            fnsize * sizeof(char *));
327                         }
328                         filenames[numnames++] = pstrdup(file->d_name);
329                 }
330                 errno = 0;
331         }
332 #ifdef WIN32
333
334         /*
335          * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
336          * released version
337          */
338         if (GetLastError() == ERROR_NO_MORE_FILES)
339                 errno = 0;
340 #endif
341         if (errno)
342         {
343 #ifndef FRONTEND
344                 elog(WARNING, "could not read directory \"%s\": %m", path);
345 #else
346                 fprintf(stderr, _("could not read directory \"%s\": %s\n"),
347                                 path, strerror(errno));
348 #endif
349         }
350
351         filenames[numnames] = NULL;
352
353         closedir(dir);
354
355         return filenames;
356 }
357
358
359 /*
360  *      pgfnames_cleanup
361  *
362  *      deallocate memory used for filenames
363  */
364 void
365 pgfnames_cleanup(char **filenames)
366 {
367         char      **fn;
368
369         for (fn = filenames; *fn; fn++)
370                 pfree(*fn);
371
372         pfree(filenames);
373 }
374
375
376 /*
377  *      rmtree
378  *
379  *      Delete a directory tree recursively.
380  *      Assumes path points to a valid directory.
381  *      Deletes everything under path.
382  *      If rmtopdir is true deletes the directory too.
383  *      Returns true if successful, false if there was any problem.
384  *      (The details of the problem are reported already, so caller
385  *      doesn't really have to say anything more, but most do.)
386  */
387 bool
388 rmtree(const char *path, bool rmtopdir)
389 {
390         bool            result = true;
391         char            pathbuf[MAXPGPATH];
392         char      **filenames;
393         char      **filename;
394         struct stat statbuf;
395
396         /*
397          * we copy all the names out of the directory before we start modifying
398          * it.
399          */
400         filenames = pgfnames(path);
401
402         if (filenames == NULL)
403                 return false;
404
405         /* now we have the names we can start removing things */
406         for (filename = filenames; *filename; filename++)
407         {
408                 snprintf(pathbuf, MAXPGPATH, "%s/%s", path, *filename);
409
410                 /*
411                  * It's ok if the file is not there anymore; we were just about to
412                  * delete it anyway.
413                  *
414                  * This is not an academic possibility. One scenario where this
415                  * happens is when bgwriter has a pending unlink request for a file
416                  * in a database that's being dropped. In dropdb(), we call
417                  * ForgetDatabaseFsyncRequests() to flush out any such pending unlink
418                  * requests, but because that's asynchronous, it's not guaranteed
419                  * that the bgwriter receives the message in time.
420                  */
421                 if (lstat(pathbuf, &statbuf) != 0)
422                 {
423                         if (errno != ENOENT)
424                         {
425 #ifndef FRONTEND
426                                 elog(WARNING, "could not stat file or directory \"%s\": %m",
427                                          pathbuf);
428 #else
429                                 fprintf(stderr, _("could not stat file or directory \"%s\": %s\n"),
430                                                 pathbuf, strerror(errno));
431 #endif
432                                 result = false;
433                         }
434                         continue;
435                 }
436
437                 if (S_ISDIR(statbuf.st_mode))
438                 {
439                         /* call ourselves recursively for a directory */
440                         if (!rmtree(pathbuf, true))
441                         {
442                                 /* we already reported the error */
443                                 result = false;
444                         }
445                 }
446                 else
447                 {
448                         if (unlink(pathbuf) != 0)
449                         {
450                                 if (errno != ENOENT)
451                                 {
452 #ifndef FRONTEND
453                                         elog(WARNING, "could not remove file or directory \"%s\": %m",
454                                                  pathbuf);
455 #else
456                                         fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
457                                                         pathbuf, strerror(errno));
458 #endif
459                                         result = false;
460                                 }
461                         }
462                 }
463         }
464
465         if (rmtopdir)
466         {
467                 if (rmdir(path) != 0)
468                 {
469 #ifndef FRONTEND
470                         elog(WARNING, "could not remove file or directory \"%s\": %m",
471                                  path);
472 #else
473                         fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
474                                         path, strerror(errno));
475 #endif
476                         result = false;
477                 }
478         }
479
480         pgfnames_cleanup(filenames);
481
482         return result;
483 }
484
485
486 #if defined(WIN32) && !defined(__CYGWIN__)
487
488 #undef stat
489
490 /*
491  * The stat() function in win32 is not guaranteed to update the st_size
492  * field when run. So we define our own version that uses the Win32 API
493  * to update this field.
494  */
495 int 
496 pgwin32_safestat(const char *path, struct stat *buf)
497 {
498         int r;
499         WIN32_FILE_ATTRIBUTE_DATA attr;
500
501         r = stat(path, buf);
502         if (r < 0)
503                 return r;
504
505         if (!GetFileAttributesEx(path, GetFileExInfoStandard, &attr))
506         {
507                 _dosmaperr(GetLastError());
508                 return -1;
509         }
510
511         /*
512          * XXX no support for large files here, but we don't do that in
513          * general on Win32 yet.
514          */
515         buf->st_size = attr.nFileSizeLow;
516
517         return 0;
518 }
519
520 #endif