forked from facebook/watchman
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrealpath.c
122 lines (104 loc) · 3.2 KB
/
realpath.c
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
/* Copyright 2014-present Facebook, Inc.
* Licensed under the Apache License, Version 2.0 */
#include "watchman.h"
char *realpath(const char *filename, char *target) {
#if 1 /* Requires Vista or later */
WCHAR final_buf[WATCHMAN_NAME_MAX];
WCHAR *final_bufptr = final_buf;
DWORD err, len;
char *utf8;
char *func_name;
if (target) {
// The only sane way is to set target = NULL
w_log(W_LOG_FATAL, "realpath called with target!=NULL");
}
int filename_len = (int)strlen(filename);
if (filename_len == 0) {
// Special case for "" -> cwd
func_name = "GetCurrentDirectoryW";
len = GetCurrentDirectoryW(sizeof(final_buf)/sizeof(final_buf[0]),
final_buf);
err = GetLastError();
} else {
WCHAR *wfilename;
wfilename = w_utf8_to_win_unc(filename, filename_len);
if (!wfilename) {
w_log(W_LOG_ERR, "failed to convert %s to WCHAR\n", filename);
return NULL;
}
func_name = "CreateFileW";
HANDLE h = CreateFileW(wfilename, 0 /* query metadata */,
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
err = GetLastError();
if (h != INVALID_HANDLE_VALUE) {
func_name = "GetFinalPathNameByHandleW";
len = GetFinalPathNameByHandleW(h, final_buf,
sizeof(final_buf)/sizeof(WCHAR),
FILE_NAME_NORMALIZED|VOLUME_NAME_DOS);
err = GetLastError();
if (len >= sizeof(final_buf)/sizeof(WCHAR)) {
// Repeat with a heap buffer
final_bufptr = malloc((len + 1) * sizeof(WCHAR));
if (final_bufptr == NULL) {
len = 0;
} else {
len = GetFinalPathNameByHandleW(h, final_buf, len,
FILE_NAME_NORMALIZED|VOLUME_NAME_DOS);
err = GetLastError();
}
}
CloseHandle(h);
} else {
len = 0;
}
free(wfilename);
}
if (len == 0) {
if (final_bufptr != final_buf) {
free(final_bufptr);
}
w_log(W_LOG_ERR, "(realpath) %s: %s %s\n", func_name,
filename, win32_strerror(err));
errno = map_win32_err(err);
return NULL;
}
utf8 = w_win_unc_to_utf8(final_bufptr, len, NULL);
if (final_bufptr != final_buf) {
free(final_bufptr);
}
return utf8;
#else
char full_buf[WATCHMAN_NAME_MAX];
char long_buf[WATCHMAN_NAME_MAX];
char *base = NULL;
DWORD full_len, long_len;
printf("realpath called with '%s'\n", filename);
if (!strlen(filename)) {
// Special case for "" -> cwd
full_len = GetCurrentDirectory(sizeof(full_buf), full_buf);
} else {
full_len = GetFullPathName(filename, sizeof(full_buf), full_buf, &base);
}
if (full_len > sizeof(full_buf)-1) {
w_log(W_LOG_FATAL, "GetFullPathName needs %lu chars\n", full_len);
}
full_buf[full_len] = 0;
printf("full: %s\n", full_buf);
long_len = GetLongPathName(full_buf, long_buf, sizeof(long_buf));
if (long_len > sizeof(long_buf)-1) {
w_log(W_LOG_FATAL, "GetLongPathName needs %lu chars\n", long_len);
}
long_buf[long_len] = 0;
printf("long: %s\n", long_buf);
if (target) {
// Pray they passed in a big enough buffer
strcpy(target, long_buf);
return target;
}
return strdup(long_buf);
#endif
}
/* vim:ts=2:sw=2:et:
*/