-
Notifications
You must be signed in to change notification settings - Fork 0
/
realpath.c
executable file
·134 lines (115 loc) · 3.15 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
123
124
125
126
127
128
129
130
131
132
133
134
/*
realpath() Win32 implementation
By Nach M. S.
Copyright (C) September 8, 2005
I am placing this in the public domain for anyone to use or modify
*/
#include <windows.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <sys/stat.h>
inline char *realpath(const char *path, char resolved_path[PATH_MAX])
{
char *return_path = 0;
if (path) //Else EINVAL
{
if (resolved_path)
{
return_path = resolved_path;
}
else
{
//Non standard extension that glibc uses
return_path = malloc(PATH_MAX);
}
if (return_path) //Else EINVAL
{
//This is a Win32 API function similar to what realpath() is supposed to do
size_t size = GetFullPathNameA(path, PATH_MAX, return_path, 0);
//GetFullPathNameA() returns a size larger than buffer if buffer is too small
if (size > PATH_MAX)
{
if (return_path != resolved_path) //Malloc'd buffer - Unstandard extension retry
{
size_t new_size;
free(return_path);
return_path = malloc(size);
if (return_path)
{
new_size = GetFullPathNameA(path, size, return_path, 0); //Try again
if (new_size > size) //If it's still too large, we have a problem, don't try again
{
free(return_path);
return_path = 0;
errno = ENAMETOOLONG;
}
else
{
size = new_size;
}
}
else
{
//I wasn't sure what to return here, but the standard does say to return EINVAL
//if resolved_path is null, and in this case we couldn't malloc large enough buffer
errno = EINVAL;
}
}
else //resolved_path buffer isn't big enough
{
return_path = 0;
errno = ENAMETOOLONG;
}
}
//GetFullPathNameA() returns 0 if some path resolve problem occured
if (!size)
{
if (return_path != resolved_path) //Malloc'd buffer
{
free(return_path);
}
return_path = 0;
//Convert MS errors into standard errors
switch (GetLastError())
{
case ERROR_FILE_NOT_FOUND:
errno = ENOENT;
break;
case ERROR_PATH_NOT_FOUND: case ERROR_INVALID_DRIVE:
errno = ENOTDIR;
break;
case ERROR_ACCESS_DENIED:
errno = EACCES;
break;
default: //Unknown Error
errno = EIO;
break;
}
}
//If we get to here with a valid return_path, we're still doing good
if (return_path)
{
struct stat stat_buffer;
//Make sure path exists, stat() returns 0 on success
if (stat(return_path, &stat_buffer))
{
if (return_path != resolved_path)
{
free(return_path);
}
return_path = 0;
//stat() will set the correct errno for us
}
//else we succeeded!
}
}
else
{
errno = EINVAL;
}
}
else
{
errno = EINVAL;
}