Index: tools/build/v2/engine/builtins.c =================================================================== --- tools/build/v2/engine/builtins.c (revision 78335) +++ tools/build/v2/engine/builtins.c (working copy) @@ -28,6 +28,10 @@ #include "constants.h" #include +#ifdef NT +#include +#endif + #if defined(USE_EXECUNIX) # include # include @@ -405,6 +409,11 @@ bind_builtin( "MAKEDIR", builtin_makedir, 0, args ); } + { + const char * args [] = { "path", 0 }; + bind_builtin( "READLINK", builtin_readlink, 0, args ); + } + /* Initialize builtin modules. */ init_set(); init_path(); @@ -1794,6 +1803,93 @@ } } +LIST *builtin_readlink( FRAME * frame, int flags ) +{ + const char * path = object_str( list_front( lol_get( frame->args, 0 ) ) ); +#ifdef NT + + /* This struct is declared in ntifs.h which is + * part of the Windows Driver Kit. + */ + typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[ 1 ]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[ 1 ]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[ 1 ]; + } GenericReparseBuffer; + }; + } REPARSE_DATA_BUFFER; + + HANDLE hLink = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL ); + DWORD n; + union { + REPARSE_DATA_BUFFER reparse; + char data[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + } buf; + int okay = DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, &buf, sizeof(buf), &n, NULL); + CloseHandle( hLink ); + + if (okay && buf.reparse.ReparseTag == IO_REPARSE_TAG_SYMLINK ) + { + int index = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameOffset / 2; + int length = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameLength / 2; + char cbuf[MAX_PATH + 1]; + int numchars = WideCharToMultiByte( CP_ACP, 0, buf.reparse.SymbolicLinkReparseBuffer.PathBuffer + index, length, cbuf, sizeof(cbuf), NULL, NULL ); + if( numchars >= sizeof(cbuf) ) + { + return 0; + } + cbuf[numchars] = '\0'; + return list_new( object_new( cbuf ) ); + } + return 0; +#else + char static_buf[256]; + char * buf = static_buf; + size_t bufsize = 256; + LIST * result = 0; + while (1) { + ssize_t len = readlink( path, buf, bufsize ); + if ( len < 0 ) + { + break; + } + else if ( len < bufsize ) + { + buf[ len ] = '\0'; + result = list_new( object_new( buf ) ); + break; + } + if ( buf != static_buf ) + BJAM_FREE( buf ); + bufsize *= 2; + buf = BJAM_MALLOC( bufsize ); + } + + if ( buf != static_buf ) + BJAM_FREE( buf ); + + return result; +#endif +} + #ifdef HAVE_PYTHON LIST * builtin_python_import_rule( FRAME * frame, int flags ) Index: tools/build/v2/engine/builtins.h =================================================================== --- tools/build/v2/engine/builtins.h (revision 78335) +++ tools/build/v2/engine/builtins.h (working copy) @@ -61,6 +61,7 @@ LIST *builtin_precious( FRAME * frame, int flags ); LIST *builtin_self_path( FRAME * frame, int flags ); LIST *builtin_makedir( FRAME * frame, int flags ); +LIST *builtin_readlink( FRAME * frame, int flags ); void backtrace( FRAME *frame ); extern int last_update_now_status; Index: tools/build/v2/build/virtual-target.jam =================================================================== --- tools/build/v2/build/virtual-target.jam (revision 78335) +++ tools/build/v2/build/virtual-target.jam (working copy) @@ -1302,8 +1302,9 @@ for local t in $(self.created-targets) { # Skip targets of the wrong type. + local type = [ $(t).type ] ; if ! $(target-type) || - [ type.is-derived [ $(t).type ] $(target-type) ] + ( $(type) && [ type.is-derived $(type) $(target-type) ] ) { result = [ sequence.merge $(result) : [ $(t).path ] ] ; }