@@ -297,6 +297,124 @@ pgsymlink(const char *oldpath, const char *newpath)
297297
298298 return 0 ;
299299}
300+
301+ /*
302+ * pgreadlink - uses Win32 junction points
303+ */
304+ int
305+ pgreadlink (const char * path , char * buf , size_t size )
306+ {
307+ DWORD attr ;
308+ HANDLE h ;
309+ char buffer [MAX_PATH * sizeof (WCHAR ) + sizeof (REPARSE_JUNCTION_DATA_BUFFER )];
310+ REPARSE_JUNCTION_DATA_BUFFER * reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER * ) buffer ;
311+ DWORD len ;
312+ int r ;
313+
314+ attr = GetFileAttributes (path );
315+ if (attr == INVALID_FILE_ATTRIBUTES )
316+ {
317+ _dosmaperr (GetLastError ());
318+ return -1 ;
319+ }
320+ if ((attr & FILE_ATTRIBUTE_REPARSE_POINT ) == 0 )
321+ {
322+ errno = EINVAL ;
323+ return -1 ;
324+ }
325+
326+ h = CreateFile (path ,
327+ GENERIC_READ ,
328+ FILE_SHARE_READ | FILE_SHARE_WRITE ,
329+ NULL ,
330+ OPEN_EXISTING ,
331+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS ,
332+ 0 );
333+ if (h == INVALID_HANDLE_VALUE )
334+ {
335+ _dosmaperr (GetLastError ());
336+ return -1 ;
337+ }
338+
339+ if (!DeviceIoControl (h ,
340+ FSCTL_GET_REPARSE_POINT ,
341+ NULL ,
342+ 0 ,
343+ (LPVOID ) reparseBuf ,
344+ sizeof (buffer ),
345+ & len ,
346+ NULL ))
347+ {
348+ LPSTR msg ;
349+
350+ errno = 0 ;
351+ FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM ,
352+ NULL , GetLastError (),
353+ MAKELANGID (LANG_ENGLISH , SUBLANG_DEFAULT ),
354+ (LPSTR ) & msg , 0 , NULL );
355+ #ifndef FRONTEND
356+ ereport (ERROR ,
357+ (errcode_for_file_access (),
358+ errmsg ("could not get junction for \"%s\": %s" ,
359+ path , msg )));
360+ #else
361+ fprintf (stderr , _ ("could not get junction for \"%s\": %s\n" ),
362+ path , msg );
363+ #endif
364+ LocalFree (msg );
365+ CloseHandle (h );
366+ errno = EINVAL ;
367+ return -1 ;
368+ }
369+ CloseHandle (h );
370+
371+ /* Got it, let's get some results from this */
372+ if (reparseBuf -> ReparseTag != IO_REPARSE_TAG_MOUNT_POINT )
373+ {
374+ errno = EINVAL ;
375+ return -1 ;
376+ }
377+
378+ r = WideCharToMultiByte (CP_ACP , 0 ,
379+ reparseBuf -> PathBuffer , -1 ,
380+ buf ,
381+ size ,
382+ NULL , NULL );
383+
384+ if (r <= 0 )
385+ {
386+ errno = EINVAL ;
387+ return -1 ;
388+ }
389+
390+ /*
391+ * If the path starts with "\??\", which it will do in most (all?) cases,
392+ * strip those out.
393+ */
394+ if (r > 4 && strncmp (buf , "\\??\\" , 4 ) == 0 )
395+ {
396+ memmove (buf , buf + 4 , strlen (buf + 4 ) + 1 );
397+ r -= 4 ;
398+ }
399+ return r ;
400+ }
401+
402+ /*
403+ * Assumes the file exists, so will return false if it doesn't
404+ * (since a nonexistant file is not a junction)
405+ */
406+ bool
407+ pgwin32_is_junction (char * path )
408+ {
409+ DWORD attr = GetFileAttributes (path );
410+
411+ if (attr == INVALID_FILE_ATTRIBUTES )
412+ {
413+ _dosmaperr (GetLastError ());
414+ return false;
415+ }
416+ return ((attr & FILE_ATTRIBUTE_REPARSE_POINT ) == FILE_ATTRIBUTE_REPARSE_POINT );
417+ }
300418#endif /* defined(WIN32) && !defined(__CYGWIN__) */
301419
302420
0 commit comments