1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
// (C) 2016 Intel Deutschland GmbH
// Author: Michael Soegtrop
// Released to the public under CC0
// See https://creativecommons.org/publicdomain/zero/1.0/
// Windows drop in repacement for Linux ln
// Supports command form "ln TARGET LINK_NAME"
// Supports -s and -f options
// Does not support hard links to folders (but symlinks are ok)
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
// Cygwin MinGW doesn't have this Vista++ function in windows.h
#ifdef UNICODE
WINBASEAPI BOOLEAN APIENTRY CreateSymbolicLinkW ( LPCWSTR, LPCWSTR, DWORD );
#define CreateSymbolicLink CreateSymbolicLinkW
#define CommandLineToArgv CommandLineToArgvW
#else
WINBASEAPI BOOLEAN APIENTRY CreateSymbolicLinkA ( LPCSTR, LPCSTR, DWORD );
#define CreateSymbolicLink CreateSymbolicLinkA
#define CommandLineToArgv CommandLineToArgvA
#endif
#define SYMBOLIC_LINK_FLAG_DIRECTORY 1
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLineA, int nShowCmd )
{
int iarg;
BOOL symbolic = FALSE;
BOOL force = FALSE;
BOOL folder;
const _TCHAR *target;
const _TCHAR *link;
LPTSTR lpCmdLine;
int argc;
LPTSTR *argv;
// Parse command line
// This is done explicitly here for two reasons
// 1.) MinGW doesn't seem to support _tmain, wWinMain and the like
// 2.) We want to make sure that CommandLineToArgv is used
lpCmdLine = GetCommandLine();
argv = CommandLineToArgv( lpCmdLine, &argc );
// Get target and link name
if( argc<3 )
{
_ftprintf( stderr, _T("Expecting at least 2 arguments, got %d\n"), argc-1 );
return 1;
}
target = argv[argc-2];
link = argv[argc-1];
// Parse options
// The last two arguments are interpreted as file names
// All other arguments must be -s or -f os multi letter options like -sf
for(iarg=1; iarg<argc-2; iarg++ )
{
const _TCHAR *pos = argv[iarg];
if( *pos != _T('-') )
{
_ftprintf( stderr, _T("Command line option expected in argument %d\n"), iarg );
return 1;
}
pos ++;
while( *pos )
{
switch( *pos )
{
case _T('s') : symbolic = TRUE; break;
case _T('f') : force = TRUE; break;
default :
_ftprintf( stderr, _T("Unknown option '%c'\n"), *pos );
return 1;
}
pos ++;
}
}
#ifdef IGNORE_SYMBOLIC
symbolic = FALSE;
#endif
// Check if link already exists - delete it if force is given or abort
{
if( GetFileAttributes(link) != INVALID_FILE_ATTRIBUTES )
{
if( force )
{
if( !DeleteFile( link ) )
{
_ftprintf( stderr, _T("Error deleting file '%s'\n"), link );
return 1;
}
}
else
{
_ftprintf( stderr, _T("File '%s' exists!\n"), link );
return 1;
}
}
}
// Check if target is a folder
folder = ( (GetFileAttributes(target) & FILE_ATTRIBUTE_DIRECTORY) ) != 0;
// Create link
if(symbolic)
{
if( !CreateSymbolicLink( link, target, folder ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0 ) )
{
_ftprintf( stderr, _T("Error creating symbolic link '%s' -> '%s'!\n"), link, target );
return 1;
}
}
else
{
if( folder )
{
_ftprintf( stderr, _T("Cannot create hard link to folder") );
return 1;
}
else
{
if( !CreateHardLink( link, target, NULL ) )
{
_ftprintf( stderr, _T("Error creating hard link '%s' -> '%s'!\n"), link, target );
return 1;
}
}
}
// Everything is fine
return 0;
}
|