]> granicus.if.org Git - postgresql/blob - src/port/dirmod.c
Update copyright for the year 2010.
[postgresql] / src / port / dirmod.c
1 /*-------------------------------------------------------------------------
2  *
3  * dirmod.c
4  *        directory handling functions
5  *
6  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *      This includes replacement versions of functions that work on
10  *      Win32 (NT4 and newer).
11  *
12  * IDENTIFICATION
13  *        $PostgreSQL: pgsql/src/port/dirmod.c,v 1.60 2010/01/02 16:58:13 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, as the caller might be holding locks
124          * and blocking other backends.
125          */
126 #if defined(WIN32) && !defined(__CYGWIN__)
127         while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
128 #else
129         while (rename(from, to) < 0)
130 #endif
131         {
132 #if defined(WIN32) && !defined(__CYGWIN__)
133                 DWORD           err = GetLastError();
134
135                 _dosmaperr(err);
136
137                 /*
138                  * Modern NT-based Windows versions return ERROR_SHARING_VIOLATION
139                  * if another process has the file open without FILE_SHARE_DELETE.
140                  * ERROR_LOCK_VIOLATION has also been seen with some anti-virus
141                  * software. This used to check for just ERROR_ACCESS_DENIED, so
142                  * presumably you can get that too with some OS versions. We don't
143                  * expect real permission errors where we currently use rename().
144                  */
145                 if (err != ERROR_ACCESS_DENIED &&
146                         err != ERROR_SHARING_VIOLATION &&
147                         err != ERROR_LOCK_VIOLATION)
148                         return -1;
149 #else
150                 if (errno != EACCES)
151                         return -1;
152 #endif
153
154                 if (++loops > 100)              /* time out after 10 sec */
155                         return -1;
156                 pg_usleep(100000);              /* us */
157         }
158         return 0;
159 }
160
161
162 /*
163  *      pgunlink
164  */
165 int
166 pgunlink(const char *path)
167 {
168         int                     loops = 0;
169
170         /*
171          * We need to loop because even though PostgreSQL uses flags that allow
172          * unlink while the file is open, other applications might have the file
173          * open without those flags.  However, we won't wait indefinitely for
174          * someone else to close the file, as the caller might be holding locks
175          * and blocking other backends.
176          */
177         while (unlink(path))
178         {
179                 if (errno != EACCES)
180                         return -1;
181                 if (++loops > 100)              /* time out after 10 sec */
182                         return -1;
183                 pg_usleep(100000);              /* us */
184         }
185         return 0;
186 }
187
188 /* We undefined these above; now redefine for possible use below */
189 #define rename(from, to)                pgrename(from, to)
190 #define unlink(path)                    pgunlink(path)
191 #endif   /* defined(WIN32) || defined(__CYGWIN__) */
192
193
194 #if defined(WIN32) && !defined(__CYGWIN__)              /* Cygwin has its own symlinks */
195
196 /*
197  *      pgsymlink support:
198  *
199  *      This struct is a replacement for REPARSE_DATA_BUFFER which is defined in VC6 winnt.h
200  *      but omitted in later SDK functions.
201  *      We only need the SymbolicLinkReparseBuffer part of the original struct's union.
202  */
203 typedef struct
204 {
205         DWORD           ReparseTag;
206         WORD            ReparseDataLength;
207         WORD            Reserved;
208         /* SymbolicLinkReparseBuffer */
209         WORD            SubstituteNameOffset;
210         WORD            SubstituteNameLength;
211         WORD            PrintNameOffset;
212         WORD            PrintNameLength;
213         WCHAR           PathBuffer[1];
214 } REPARSE_JUNCTION_DATA_BUFFER;
215
216 #define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE   \
217                 FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset)
218
219
220 /*
221  *      pgsymlink - uses Win32 junction points
222  *
223  *      For reference:  http://www.codeproject.com/w2k/junctionpoints.asp
224  */
225 int
226 pgsymlink(const char *oldpath, const char *newpath)
227 {
228         HANDLE          dirhandle;
229         DWORD           len;
230         char            buffer[MAX_PATH * sizeof(WCHAR) + sizeof(REPARSE_JUNCTION_DATA_BUFFER)];
231         char            nativeTarget[MAX_PATH];
232         char       *p = nativeTarget;
233         REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
234
235         CreateDirectory(newpath, 0);
236         dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
237                                                    0, 0, OPEN_EXISTING,
238                            FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
239
240         if (dirhandle == INVALID_HANDLE_VALUE)
241                 return -1;
242
243         /* make sure we have an unparsed native win32 path */
244         if (memcmp("\\??\\", oldpath, 4))
245                 sprintf(nativeTarget, "\\??\\%s", oldpath);
246         else
247                 strcpy(nativeTarget, oldpath);
248
249         while ((p = strchr(p, '/')) != 0)
250                 *p++ = '\\';
251
252         len = strlen(nativeTarget) * sizeof(WCHAR);
253         reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
254         reparseBuf->ReparseDataLength = len + 12;
255         reparseBuf->Reserved = 0;
256         reparseBuf->SubstituteNameOffset = 0;
257         reparseBuf->SubstituteNameLength = len;
258         reparseBuf->PrintNameOffset = len + sizeof(WCHAR);
259         reparseBuf->PrintNameLength = 0;
260         MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1,
261                                                 reparseBuf->PathBuffer, MAX_PATH);
262
263         /*
264          * FSCTL_SET_REPARSE_POINT is coded differently depending on SDK version;
265          * we use our own definition
266          */
267         if (!DeviceIoControl(dirhandle,
268          CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS),
269                                                  reparseBuf,
270         reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE,
271                                                  0, 0, &len, 0))
272         {
273                 LPSTR           msg;
274
275                 errno = 0;
276                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
277                                           NULL, GetLastError(),
278                                           MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
279                                           (LPSTR) &msg, 0, NULL);
280 #ifndef FRONTEND
281                 ereport(ERROR,
282                                 (errcode_for_file_access(),
283                                  errmsg("could not set junction for \"%s\": %s",
284                                                 nativeTarget, msg)));
285 #else
286                 fprintf(stderr, _("could not set junction for \"%s\": %s\n"),
287                                 nativeTarget, msg);
288 #endif
289                 LocalFree(msg);
290
291                 CloseHandle(dirhandle);
292                 RemoveDirectory(newpath);
293                 return -1;
294         }
295
296         CloseHandle(dirhandle);
297
298         return 0;
299 }
300 #endif   /* defined(WIN32) && !defined(__CYGWIN__) */
301
302
303 /*
304  * pgfnames
305  *
306  * return a list of the names of objects in the argument directory.  Caller
307  * must call pgfnames_cleanup later to free the memory allocated by this
308  * function.
309  */
310 char      **
311 pgfnames(const char *path)
312 {
313         DIR                *dir;
314         struct dirent *file;
315         char      **filenames;
316         int                     numnames = 0;
317         int                     fnsize = 200;   /* enough for many small dbs */
318
319         dir = opendir(path);
320         if (dir == NULL)
321         {
322 #ifndef FRONTEND
323                 elog(WARNING, "could not open directory \"%s\": %m", path);
324 #else
325                 fprintf(stderr, _("could not open directory \"%s\": %s\n"),
326                                 path, strerror(errno));
327 #endif
328                 return NULL;
329         }
330
331         filenames = (char **) palloc(fnsize * sizeof(char *));
332
333         errno = 0;
334         while ((file = readdir(dir)) != NULL)
335         {
336                 if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0)
337                 {
338                         if (numnames + 1 >= fnsize)
339                         {
340                                 fnsize *= 2;
341                                 filenames = (char **) repalloc(filenames,
342                                                                                            fnsize * sizeof(char *));
343                         }
344                         filenames[numnames++] = pstrdup(file->d_name);
345                 }
346                 errno = 0;
347         }
348 #ifdef WIN32
349
350         /*
351          * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
352          * released version
353          */
354         if (GetLastError() == ERROR_NO_MORE_FILES)
355                 errno = 0;
356 #endif
357         if (errno)
358         {
359 #ifndef FRONTEND
360                 elog(WARNING, "could not read directory \"%s\": %m", path);
361 #else
362                 fprintf(stderr, _("could not read directory \"%s\": %s\n"),
363                                 path, strerror(errno));
364 #endif
365         }
366
367         filenames[numnames] = NULL;
368
369         closedir(dir);
370
371         return filenames;
372 }
373
374
375 /*
376  *      pgfnames_cleanup
377  *
378  *      deallocate memory used for filenames
379  */
380 void
381 pgfnames_cleanup(char **filenames)
382 {
383         char      **fn;
384
385         for (fn = filenames; *fn; fn++)
386                 pfree(*fn);
387
388         pfree(filenames);
389 }
390
391
392 /*
393  *      rmtree
394  *
395  *      Delete a directory tree recursively.
396  *      Assumes path points to a valid directory.
397  *      Deletes everything under path.
398  *      If rmtopdir is true deletes the directory too.
399  *      Returns true if successful, false if there was any problem.
400  *      (The details of the problem are reported already, so caller
401  *      doesn't really have to say anything more, but most do.)
402  */
403 bool
404 rmtree(const char *path, bool rmtopdir)
405 {
406         bool            result = true;
407         char            pathbuf[MAXPGPATH];
408         char      **filenames;
409         char      **filename;
410         struct stat statbuf;
411
412         /*
413          * we copy all the names out of the directory before we start modifying
414          * it.
415          */
416         filenames = pgfnames(path);
417
418         if (filenames == NULL)
419                 return false;
420
421         /* now we have the names we can start removing things */
422         for (filename = filenames; *filename; filename++)
423         {
424                 snprintf(pathbuf, MAXPGPATH, "%s/%s", path, *filename);
425
426                 /*
427                  * It's ok if the file is not there anymore; we were just about to
428                  * delete it anyway.
429                  *
430                  * This is not an academic possibility. One scenario where this
431                  * happens is when bgwriter has a pending unlink request for a file in
432                  * a database that's being dropped. In dropdb(), we call
433                  * ForgetDatabaseFsyncRequests() to flush out any such pending unlink
434                  * requests, but because that's asynchronous, it's not guaranteed that
435                  * the bgwriter receives the message in time.
436                  */
437                 if (lstat(pathbuf, &statbuf) != 0)
438                 {
439                         if (errno != ENOENT)
440                         {
441 #ifndef FRONTEND
442                                 elog(WARNING, "could not stat file or directory \"%s\": %m",
443                                          pathbuf);
444 #else
445                                 fprintf(stderr, _("could not stat file or directory \"%s\": %s\n"),
446                                                 pathbuf, strerror(errno));
447 #endif
448                                 result = false;
449                         }
450                         continue;
451                 }
452
453                 if (S_ISDIR(statbuf.st_mode))
454                 {
455                         /* call ourselves recursively for a directory */
456                         if (!rmtree(pathbuf, true))
457                         {
458                                 /* we already reported the error */
459                                 result = false;
460                         }
461                 }
462                 else
463                 {
464                         if (unlink(pathbuf) != 0)
465                         {
466                                 if (errno != ENOENT)
467                                 {
468 #ifndef FRONTEND
469                                         elog(WARNING, "could not remove file or directory \"%s\": %m",
470                                                  pathbuf);
471 #else
472                                         fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
473                                                         pathbuf, strerror(errno));
474 #endif
475                                         result = false;
476                                 }
477                         }
478                 }
479         }
480
481         if (rmtopdir)
482         {
483                 if (rmdir(path) != 0)
484                 {
485 #ifndef FRONTEND
486                         elog(WARNING, "could not remove file or directory \"%s\": %m",
487                                  path);
488 #else
489                         fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
490                                         path, strerror(errno));
491 #endif
492                         result = false;
493                 }
494         }
495
496         pgfnames_cleanup(filenames);
497
498         return result;
499 }
500
501
502 #if defined(WIN32) && !defined(__CYGWIN__)
503
504 #undef stat
505
506 /*
507  * The stat() function in win32 is not guaranteed to update the st_size
508  * field when run. So we define our own version that uses the Win32 API
509  * to update this field.
510  */
511 int
512 pgwin32_safestat(const char *path, struct stat * buf)
513 {
514         int                     r;
515         WIN32_FILE_ATTRIBUTE_DATA attr;
516
517         r = stat(path, buf);
518         if (r < 0)
519                 return r;
520
521         if (!GetFileAttributesEx(path, GetFileExInfoStandard, &attr))
522         {
523                 _dosmaperr(GetLastError());
524                 return -1;
525         }
526
527         /*
528          * XXX no support for large files here, but we don't do that in general on
529          * Win32 yet.
530          */
531         buf->st_size = attr.nFileSizeLow;
532
533         return 0;
534 }
535
536 #endif