00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifndef FRONTEND
00019 #include "postgres.h"
00020 #else
00021 #include "postgres_fe.h"
00022 #endif
00023
00024
00025 #if defined(WIN32) || defined(__CYGWIN__)
00026 #undef rename
00027 #undef unlink
00028 #endif
00029
00030 #include <unistd.h>
00031 #include <dirent.h>
00032 #include <sys/stat.h>
00033
00034 #if defined(WIN32) || defined(__CYGWIN__)
00035 #ifndef __CYGWIN__
00036 #include <winioctl.h>
00037 #else
00038 #include <windows.h>
00039 #include <w32api/winioctl.h>
00040 #endif
00041 #endif
00042
00043 #if defined(WIN32) || defined(__CYGWIN__)
00044
00045
00046
00047
00048 int
00049 pgrename(const char *from, const char *to)
00050 {
00051 int loops = 0;
00052
00053
00054
00055
00056
00057
00058
00059
00060 #if defined(WIN32) && !defined(__CYGWIN__)
00061 while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
00062 #else
00063 while (rename(from, to) < 0)
00064 #endif
00065 {
00066 #if defined(WIN32) && !defined(__CYGWIN__)
00067 DWORD err = GetLastError();
00068
00069 _dosmaperr(err);
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 if (err != ERROR_ACCESS_DENIED &&
00080 err != ERROR_SHARING_VIOLATION &&
00081 err != ERROR_LOCK_VIOLATION)
00082 return -1;
00083 #else
00084 if (errno != EACCES)
00085 return -1;
00086 #endif
00087
00088 if (++loops > 100)
00089 return -1;
00090 pg_usleep(100000);
00091 }
00092 return 0;
00093 }
00094
00095
00096
00097
00098
00099 int
00100 pgunlink(const char *path)
00101 {
00102 int loops = 0;
00103
00104
00105
00106
00107
00108
00109
00110
00111 while (unlink(path))
00112 {
00113 if (errno != EACCES)
00114 return -1;
00115 if (++loops > 100)
00116 return -1;
00117 pg_usleep(100000);
00118 }
00119 return 0;
00120 }
00121
00122
00123 #define rename(from, to) pgrename(from, to)
00124 #define unlink(path) pgunlink(path)
00125 #endif
00126
00127
00128 #if defined(WIN32) && !defined(__CYGWIN__)
00129
00130
00131
00132
00133
00134
00135
00136
00137 typedef struct
00138 {
00139 DWORD ReparseTag;
00140 WORD ReparseDataLength;
00141 WORD Reserved;
00142
00143 WORD SubstituteNameOffset;
00144 WORD SubstituteNameLength;
00145 WORD PrintNameOffset;
00146 WORD PrintNameLength;
00147 WCHAR PathBuffer[1];
00148 } REPARSE_JUNCTION_DATA_BUFFER;
00149
00150 #define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE \
00151 FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset)
00152
00153
00154
00155
00156
00157
00158
00159 int
00160 pgsymlink(const char *oldpath, const char *newpath)
00161 {
00162 HANDLE dirhandle;
00163 DWORD len;
00164 char buffer[MAX_PATH * sizeof(WCHAR) + sizeof(REPARSE_JUNCTION_DATA_BUFFER)];
00165 char nativeTarget[MAX_PATH];
00166 char *p = nativeTarget;
00167 REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
00168
00169 CreateDirectory(newpath, 0);
00170 dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
00171 0, 0, OPEN_EXISTING,
00172 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
00173
00174 if (dirhandle == INVALID_HANDLE_VALUE)
00175 return -1;
00176
00177
00178 if (memcmp("\\??\\", oldpath, 4))
00179 sprintf(nativeTarget, "\\??\\%s", oldpath);
00180 else
00181 strcpy(nativeTarget, oldpath);
00182
00183 while ((p = strchr(p, '/')) != NULL)
00184 *p++ = '\\';
00185
00186 len = strlen(nativeTarget) * sizeof(WCHAR);
00187 reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
00188 reparseBuf->ReparseDataLength = len + 12;
00189 reparseBuf->Reserved = 0;
00190 reparseBuf->SubstituteNameOffset = 0;
00191 reparseBuf->SubstituteNameLength = len;
00192 reparseBuf->PrintNameOffset = len + sizeof(WCHAR);
00193 reparseBuf->PrintNameLength = 0;
00194 MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1,
00195 reparseBuf->PathBuffer, MAX_PATH);
00196
00197
00198
00199
00200
00201 if (!DeviceIoControl(dirhandle,
00202 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS),
00203 reparseBuf,
00204 reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE,
00205 0, 0, &len, 0))
00206 {
00207 LPSTR msg;
00208
00209 errno = 0;
00210 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00211 NULL, GetLastError(),
00212 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
00213 (LPSTR) &msg, 0, NULL);
00214 #ifndef FRONTEND
00215 ereport(ERROR,
00216 (errcode_for_file_access(),
00217 errmsg("could not set junction for \"%s\": %s",
00218 nativeTarget, msg)));
00219 #else
00220 fprintf(stderr, _("could not set junction for \"%s\": %s\n"),
00221 nativeTarget, msg);
00222 #endif
00223 LocalFree(msg);
00224
00225 CloseHandle(dirhandle);
00226 RemoveDirectory(newpath);
00227 return -1;
00228 }
00229
00230 CloseHandle(dirhandle);
00231
00232 return 0;
00233 }
00234
00235
00236
00237
00238 int
00239 pgreadlink(const char *path, char *buf, size_t size)
00240 {
00241 DWORD attr;
00242 HANDLE h;
00243 char buffer[MAX_PATH * sizeof(WCHAR) + sizeof(REPARSE_JUNCTION_DATA_BUFFER)];
00244 REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
00245 DWORD len;
00246 int r;
00247
00248 attr = GetFileAttributes(path);
00249 if (attr == INVALID_FILE_ATTRIBUTES)
00250 {
00251 _dosmaperr(GetLastError());
00252 return -1;
00253 }
00254 if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
00255 {
00256 errno = EINVAL;
00257 return -1;
00258 }
00259
00260 h = CreateFile(path,
00261 GENERIC_READ,
00262 FILE_SHARE_READ | FILE_SHARE_WRITE,
00263 NULL,
00264 OPEN_EXISTING,
00265 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
00266 0);
00267 if (h == INVALID_HANDLE_VALUE)
00268 {
00269 _dosmaperr(GetLastError());
00270 return -1;
00271 }
00272
00273 if (!DeviceIoControl(h,
00274 FSCTL_GET_REPARSE_POINT,
00275 NULL,
00276 0,
00277 (LPVOID) reparseBuf,
00278 sizeof(buffer),
00279 &len,
00280 NULL))
00281 {
00282 LPSTR msg;
00283
00284 errno = 0;
00285 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00286 NULL, GetLastError(),
00287 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
00288 (LPSTR) &msg, 0, NULL);
00289 #ifndef FRONTEND
00290 ereport(ERROR,
00291 (errcode_for_file_access(),
00292 errmsg("could not get junction for \"%s\": %s",
00293 path, msg)));
00294 #else
00295 fprintf(stderr, _("could not get junction for \"%s\": %s\n"),
00296 path, msg);
00297 #endif
00298 LocalFree(msg);
00299 CloseHandle(h);
00300 errno = EINVAL;
00301 return -1;
00302 }
00303 CloseHandle(h);
00304
00305
00306 if (reparseBuf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
00307 {
00308 errno = EINVAL;
00309 return -1;
00310 }
00311
00312 r = WideCharToMultiByte(CP_ACP, 0,
00313 reparseBuf->PathBuffer, -1,
00314 buf,
00315 size,
00316 NULL, NULL);
00317
00318 if (r <= 0)
00319 {
00320 errno = EINVAL;
00321 return -1;
00322 }
00323
00324
00325
00326
00327
00328 if (r > 4 && strncmp(buf, "\\??\\", 4) == 0)
00329 {
00330 memmove(buf, buf + 4, strlen(buf + 4) + 1);
00331 r -= 4;
00332 }
00333 return r;
00334 }
00335
00336
00337
00338
00339
00340 bool
00341 pgwin32_is_junction(char *path)
00342 {
00343 DWORD attr = GetFileAttributes(path);
00344
00345 if (attr == INVALID_FILE_ATTRIBUTES)
00346 {
00347 _dosmaperr(GetLastError());
00348 return false;
00349 }
00350 return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT);
00351 }
00352 #endif
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 char **
00363 pgfnames(const char *path)
00364 {
00365 DIR *dir;
00366 struct dirent *file;
00367 char **filenames;
00368 int numnames = 0;
00369 int fnsize = 200;
00370
00371 dir = opendir(path);
00372 if (dir == NULL)
00373 {
00374 #ifndef FRONTEND
00375 elog(WARNING, "could not open directory \"%s\": %m", path);
00376 #else
00377 fprintf(stderr, _("could not open directory \"%s\": %s\n"),
00378 path, strerror(errno));
00379 #endif
00380 return NULL;
00381 }
00382
00383 filenames = (char **) palloc(fnsize * sizeof(char *));
00384
00385 errno = 0;
00386 while ((file = readdir(dir)) != NULL)
00387 {
00388 if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0)
00389 {
00390 if (numnames + 1 >= fnsize)
00391 {
00392 fnsize *= 2;
00393 filenames = (char **) repalloc(filenames,
00394 fnsize * sizeof(char *));
00395 }
00396 filenames[numnames++] = pstrdup(file->d_name);
00397 }
00398 errno = 0;
00399 }
00400 #ifdef WIN32
00401
00402
00403
00404
00405
00406 if (GetLastError() == ERROR_NO_MORE_FILES)
00407 errno = 0;
00408 #endif
00409 if (errno)
00410 {
00411 #ifndef FRONTEND
00412 elog(WARNING, "could not read directory \"%s\": %m", path);
00413 #else
00414 fprintf(stderr, _("could not read directory \"%s\": %s\n"),
00415 path, strerror(errno));
00416 #endif
00417 }
00418
00419 filenames[numnames] = NULL;
00420
00421 closedir(dir);
00422
00423 return filenames;
00424 }
00425
00426
00427
00428
00429
00430
00431
00432 void
00433 pgfnames_cleanup(char **filenames)
00434 {
00435 char **fn;
00436
00437 for (fn = filenames; *fn; fn++)
00438 pfree(*fn);
00439
00440 pfree(filenames);
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 bool
00456 rmtree(const char *path, bool rmtopdir)
00457 {
00458 bool result = true;
00459 char pathbuf[MAXPGPATH];
00460 char **filenames;
00461 char **filename;
00462 struct stat statbuf;
00463
00464
00465
00466
00467
00468 filenames = pgfnames(path);
00469
00470 if (filenames == NULL)
00471 return false;
00472
00473
00474 for (filename = filenames; *filename; filename++)
00475 {
00476 snprintf(pathbuf, MAXPGPATH, "%s/%s", path, *filename);
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 if (lstat(pathbuf, &statbuf) != 0)
00490 {
00491 if (errno != ENOENT)
00492 {
00493 #ifndef FRONTEND
00494 elog(WARNING, "could not stat file or directory \"%s\": %m",
00495 pathbuf);
00496 #else
00497 fprintf(stderr, _("could not stat file or directory \"%s\": %s\n"),
00498 pathbuf, strerror(errno));
00499 #endif
00500 result = false;
00501 }
00502 continue;
00503 }
00504
00505 if (S_ISDIR(statbuf.st_mode))
00506 {
00507
00508 if (!rmtree(pathbuf, true))
00509 {
00510
00511 result = false;
00512 }
00513 }
00514 else
00515 {
00516 if (unlink(pathbuf) != 0)
00517 {
00518 if (errno != ENOENT)
00519 {
00520 #ifndef FRONTEND
00521 elog(WARNING, "could not remove file or directory \"%s\": %m",
00522 pathbuf);
00523 #else
00524 fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
00525 pathbuf, strerror(errno));
00526 #endif
00527 result = false;
00528 }
00529 }
00530 }
00531 }
00532
00533 if (rmtopdir)
00534 {
00535 if (rmdir(path) != 0)
00536 {
00537 #ifndef FRONTEND
00538 elog(WARNING, "could not remove file or directory \"%s\": %m",
00539 path);
00540 #else
00541 fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
00542 path, strerror(errno));
00543 #endif
00544 result = false;
00545 }
00546 }
00547
00548 pgfnames_cleanup(filenames);
00549
00550 return result;
00551 }
00552
00553
00554 #if defined(WIN32) && !defined(__CYGWIN__)
00555
00556 #undef stat
00557
00558
00559
00560
00561
00562
00563 int
00564 pgwin32_safestat(const char *path, struct stat * buf)
00565 {
00566 int r;
00567 WIN32_FILE_ATTRIBUTE_DATA attr;
00568
00569 r = stat(path, buf);
00570 if (r < 0)
00571 return r;
00572
00573 if (!GetFileAttributesEx(path, GetFileExInfoStandard, &attr))
00574 {
00575 _dosmaperr(GetLastError());
00576 return -1;
00577 }
00578
00579
00580
00581
00582
00583 buf->st_size = attr.nFileSizeLow;
00584
00585 return 0;
00586 }
00587
00588 #endif