Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F102997903
readlink.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, Feb 26, 07:27
Size
5 KB
Mime Type
text/x-c
Expires
Fri, Feb 28, 07:27 (2 d)
Engine
blob
Format
Raw Data
Handle
24472722
Attached To
R3704 elastic-yarn
readlink.c
View Options
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
#include "winutils.h"
//----------------------------------------------------------------------------
// The Windows SDK does not include the definition of REPARSE_DATA_BUFFER. To
// avoid adding a dependency on the WDK we define the structure here.
// Reference: http://msdn.microsoft.com/en-us/library/ff552012.aspx
//
#pragma warning(push)
#pragma warning(disable: 4201)
// nonstandard extension: nameless struct/union
#pragma pack(push, 1)
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
,
*
PREPARSE_DATA_BUFFER
;
#pragma pack(pop)
#pragma warning(pop)
//----------------------------------------------------------------------------
// Function: Readlink
//
// Description:
// Prints the target of a symbolic link to stdout.
//
// The return codes and output are modeled after the UNIX readlink command.
// Hence no error messages are printed. Unlike the UNIX readlink, no options
// are accepted.
//
// Returns:
// 0: on success
// 1: on all errors
//
// Notes:
//
int
Readlink
(
__in
int
argc
,
__in_ecount
(
argc
)
wchar_t
*
argv
[])
{
DWORD
bytesReturned
;
DWORD
bufferSize
=
1024
;
// Start off with a 1KB buffer.
HANDLE
hFile
=
INVALID_HANDLE_VALUE
;
PWSTR
longLinkName
=
NULL
;
PWCHAR
printName
=
NULL
;
PREPARSE_DATA_BUFFER
pReparseData
=
NULL
;
USHORT
printNameLength
;
USHORT
printNameOffset
;
DWORD
result
;
BOOLEAN
succeeded
=
FALSE
;
if
(
argc
!=
2
)
{
ReadlinkUsage
();
goto
Cleanup
;
}
if
(
ConvertToLongPath
(
argv
[
1
],
&
longLinkName
)
!=
ERROR_SUCCESS
)
{
goto
Cleanup
;
}
// Get a handle to the link to issue the FSCTL.
// FILE_FLAG_BACKUP_SEMANTICS is needed to open directories.
// FILE_FLAG_OPEN_REPARSE_POINT disables normal reparse point processing
// so we can query the symlink.
//
hFile
=
CreateFileW
(
longLinkName
,
0
,
// no rights needed to issue the FSCTL.
FILE_SHARE_READ
|
FILE_SHARE_WRITE
|
FILE_SHARE_DELETE
,
NULL
,
OPEN_EXISTING
,
FILE_FLAG_BACKUP_SEMANTICS
|
FILE_FLAG_OPEN_REPARSE_POINT
,
NULL
);
if
(
hFile
==
INVALID_HANDLE_VALUE
)
{
goto
Cleanup
;
}
for
(;;)
{
pReparseData
=
(
PREPARSE_DATA_BUFFER
)
LocalAlloc
(
LMEM_FIXED
,
bufferSize
);
if
(
pReparseData
==
NULL
)
{
goto
Cleanup
;
}
// Issue the FSCTL to query the link information.
//
result
=
DeviceIoControl
(
hFile
,
FSCTL_GET_REPARSE_POINT
,
NULL
,
0
,
pReparseData
,
bufferSize
,
&
bytesReturned
,
NULL
);
if
(
result
!=
0
)
{
// Success!
//
break
;
}
else
if
((
GetLastError
()
==
ERROR_INSUFFICIENT_BUFFER
)
||
(
GetLastError
()
==
ERROR_MORE_DATA
))
{
// Retry with a larger buffer.
//
LocalFree
(
pReparseData
);
bufferSize
*=
2
;
}
else
{
// Unrecoverable error.
//
goto
Cleanup
;
}
}
if
(
pReparseData
->
ReparseTag
!=
IO_REPARSE_TAG_SYMLINK
)
{
// Doesn't look like a symlink.
//
goto
Cleanup
;
}
// MSDN does not guarantee that the embedded paths in REPARSE_DATA_BUFFER
// will be NULL terminated. So we copy the string to a separate buffer and
// NULL terminate it before printing.
//
printNameLength
=
pReparseData
->
SymbolicLinkReparseBuffer
.
PrintNameLength
;
printNameOffset
=
pReparseData
->
SymbolicLinkReparseBuffer
.
PrintNameOffset
;
printName
=
(
PWCHAR
)
LocalAlloc
(
LMEM_FIXED
,
printNameLength
+
1
);
if
(
printName
==
NULL
)
{
goto
Cleanup
;
}
memcpy
(
printName
,
pReparseData
->
SymbolicLinkReparseBuffer
.
PathBuffer
+
printNameOffset
,
printNameLength
);
printName
[
printNameLength
/
sizeof
(
WCHAR
)]
=
L'\0'
;
fwprintf
(
stdout
,
L"%ls"
,
printName
);
succeeded
=
TRUE
;
Cleanup:
if
(
hFile
!=
INVALID_HANDLE_VALUE
)
{
CloseHandle
(
hFile
);
}
if
(
printName
!=
NULL
)
{
LocalFree
(
printName
);
}
if
(
pReparseData
!=
NULL
)
{
LocalFree
(
pReparseData
);
}
if
(
longLinkName
!=
NULL
)
{
LocalFree
(
longLinkName
);
}
return
(
succeeded
?
EXIT_SUCCESS
:
EXIT_FAILURE
);
}
void
ReadlinkUsage
()
{
fwprintf
(
stdout
,
L"\
Usage: readlink [LINKNAME]
\n
\
Prints the target of a symbolic link
\n
\
The output and returned error codes are similar to the UNIX
\n
\
readlink command. However no options are accepted.
\n
\
\n
\
0 is returned on success.
\n
\
1 is returned for all errors.
\n
\
\n
"
);
}
Event Timeline
Log In to Comment