1 |
#include "urlib.h" |
2 |
|
3 |
#include <fcntl.h> |
4 |
#include <stdio.h> |
5 |
#include <string.h> |
6 |
#include <stdlib.h> |
7 |
|
8 |
#ifdef _WIN32 |
9 |
|
10 |
#include <windows.h> |
11 |
//#include <winbase.h> |
12 |
#include <shlobj.h> |
13 |
#include <shlwapi.h> |
14 |
#include <wininet.h> |
15 |
|
16 |
static DWORD dword; |
17 |
|
18 |
#define u_handle HANDLE |
19 |
#define u_invalid_handle 0 |
20 |
#define u_valid(handle) (!!handle) |
21 |
|
22 |
#define u_setenv(name,value) SetEnvironmentVariable (name, value) |
23 |
#define u_mkdir(path) !CreateDirectory (path, NULL) |
24 |
#define u_chdir(path) !SetCurrentDirectory (path) |
25 |
#define u_rename(fr,to) !MoveFile (fr, to) |
26 |
#define u_open(path) CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) |
27 |
#define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) |
28 |
#define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) |
29 |
#define u_close(handle) CloseHandle (handle) |
30 |
#define u_append(path,add) PathAppend (path, add) |
31 |
#define u_write(handle,data,len) (WriteFile (handle, data, len, &dword, 0) ? dword : -1) |
32 |
|
33 |
#define u_fsync(handle) FlushFileBuffers (handle) |
34 |
#define u_sync() |
35 |
|
36 |
#define u_lockfile(path) CreateFile (path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) |
37 |
#define u_cloexec(handle) |
38 |
|
39 |
#else |
40 |
|
41 |
#define _GNU_SOURCE 1 |
42 |
#define _BSD_SOURCE 1 |
43 |
// the above increases our chances of getting MAP_ANONYMOUS |
44 |
|
45 |
#include <sys/mman.h> |
46 |
#include <sys/types.h> |
47 |
#include <sys/stat.h> |
48 |
#include <unistd.h> |
49 |
#include <pwd.h> |
50 |
|
51 |
#if defined (MAP_ANON) && !defined (MAP_ANONYMOUS) |
52 |
#define MAP_ANONYMOUS MAP_ANON |
53 |
#endif |
54 |
|
55 |
#ifdef PATH_MAX |
56 |
#define MAX_PATH (PATH_MAX < 4096 ? 4096 : PATH_MAX) |
57 |
#else |
58 |
#define MAX_PATH 4096 |
59 |
#endif |
60 |
|
61 |
#define u_handle int |
62 |
#define u_invalid_handle -1 |
63 |
#define u_valid(fd) ((fd) >= 0) |
64 |
|
65 |
#define u_setenv(name,value) setenv (name, value, 1) |
66 |
#define u_mkdir(path) mkdir (path, 0777) |
67 |
#define u_chdir(path) chdir (path) |
68 |
#define u_rename(fr,to) rename (fr, to) |
69 |
#define u_open(path) open (path, O_RDONLY) |
70 |
#define u_creat(path,exec) open (path, O_WRONLY | O_CREAT | O_TRUNC, (exec) ? 0777 : 0666) |
71 |
#define u_close(handle) close (handle) |
72 |
#define u_append(path,add) strcat (strcat (path, "/"), add) |
73 |
#define u_write(handle,data,len) write (handle, data, len) |
74 |
|
75 |
// on a mostly idle system, a sync at the end is certainly faster, hope for the best |
76 |
#define u_fsync(handle) |
77 |
#define u_sync() sync () |
78 |
|
79 |
#define u_lockfile(path) open (path, O_RDWR | O_CREAT, 0666) |
80 |
#define u_cloexec(handle) fcntl (handle, F_SETFD, FD_CLOEXEC) |
81 |
|
82 |
#endif |
83 |
|
84 |
#define u_16(ptr) (((ptr)[0] << 8) | (ptr)[1]) |
85 |
#define u_32(ptr) (((ptr)[0] << 24) | ((ptr)[1] << 16) | ((ptr)[2] << 8) | (ptr)[3]) |
86 |
|
87 |
static char currdir[MAX_PATH]; |
88 |
static char datadir[MAX_PATH]; // %AppData%/urlader |
89 |
static char exe_dir[MAX_PATH]; // %AppData%/urlader/EXE_ID |
90 |
static char execdir[MAX_PATH]; // %AppData%/urlader/EXE_ID/EXE_VER |
91 |
static char exe_id[MAX_PATH]; |
92 |
static char exe_ver[MAX_PATH]; |
93 |
|
94 |
///////////////////////////////////////////////////////////////////////////// |
95 |
|
96 |
static void |
97 |
u_fatal (const char *msg) |
98 |
{ |
99 |
#ifdef _WIN32 |
100 |
MessageBox (0, msg, URLADER, 0); |
101 |
#else |
102 |
write (2, URLADER ": ", sizeof (URLADER ": ") - 1); |
103 |
write (2, msg, strlen (msg)); |
104 |
write (2, "\n", 1); |
105 |
#endif |
106 |
|
107 |
_exit (1); |
108 |
} |
109 |
|
110 |
static void * |
111 |
u_malloc (unsigned int size) |
112 |
{ |
113 |
void *addr; |
114 |
|
115 |
#ifdef _WIN32 |
116 |
HANDLE handle = CreateFileMapping (0, 0, PAGE_READWRITE, 0, size, NULL); |
117 |
|
118 |
if (!handle) |
119 |
return 0; |
120 |
|
121 |
addr = MapViewOfFile (handle, FILE_MAP_WRITE, 0, 0, size); |
122 |
|
123 |
CloseHandle (handle); |
124 |
#elif defined (MAP_ANONYMOUS) |
125 |
addr = mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); |
126 |
|
127 |
if (addr == (void *)-1) |
128 |
addr = 0; |
129 |
#else |
130 |
addr = malloc (size); |
131 |
#endif |
132 |
|
133 |
return addr; |
134 |
} |
135 |
|
136 |
static void |
137 |
u_free (void *addr, unsigned int size) |
138 |
{ |
139 |
#ifdef _WIN32 |
140 |
UnmapViewOfFile (addr); |
141 |
#elif defined (MAP_ANONYMOUS) |
142 |
munmap (addr, size); |
143 |
#else |
144 |
free (addr); |
145 |
#endif |
146 |
} |
147 |
|
148 |
static void * |
149 |
u_mmap (u_handle h, unsigned int size) |
150 |
{ |
151 |
void *addr; |
152 |
|
153 |
#ifdef _WIN32 |
154 |
HANDLE handle = CreateFileMapping (h, 0, PAGE_READONLY, 0, size, NULL); |
155 |
|
156 |
if (!handle) |
157 |
return 0; |
158 |
|
159 |
addr = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, size); |
160 |
|
161 |
CloseHandle (handle); |
162 |
#else |
163 |
addr = mmap (0, size, PROT_READ, MAP_SHARED, h, 0); |
164 |
|
165 |
if (addr == (void *)-1) |
166 |
addr = 0; |
167 |
#endif |
168 |
|
169 |
return addr; |
170 |
} |
171 |
|
172 |
static void |
173 |
u_munmap (void *addr, unsigned int len) |
174 |
{ |
175 |
#ifdef _WIN32 |
176 |
UnmapViewOfFile (addr); |
177 |
#else |
178 |
munmap (addr, len); |
179 |
#endif |
180 |
} |
181 |
|
182 |
///////////////////////////////////////////////////////////////////////////// |
183 |
|
184 |
static void |
185 |
u_set_datadir (void) |
186 |
{ |
187 |
#ifdef _WIN32 |
188 |
if (SHGetFolderPath (0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, datadir) != S_OK) |
189 |
u_fatal ("unable to find application data directory"); |
190 |
|
191 |
u_mkdir (datadir); |
192 |
u_append (datadir, URLADER); |
193 |
|
194 |
#else |
195 |
char *home = getenv ("HOME"); |
196 |
|
197 |
if (!home) |
198 |
{ |
199 |
struct passwd *pw; |
200 |
|
201 |
if ((pw = getpwuid (getuid ()))) |
202 |
home = pw->pw_dir; |
203 |
else |
204 |
home = "/tmp"; |
205 |
} |
206 |
|
207 |
u_mkdir (home); |
208 |
//strcat (strcat (strcpy (datadir, home), "/."), URLADER); |
209 |
sprintf (datadir, "%s/.%s", home, URLADER); |
210 |
#endif |
211 |
|
212 |
u_setenv ("URLADER_DATADIR", datadir); |
213 |
} |
214 |
|
215 |
static void |
216 |
u_set_exe_info (void) |
217 |
{ |
218 |
strcpy (exe_dir, datadir); |
219 |
u_append (exe_dir, exe_id); |
220 |
u_mkdir (exe_dir); |
221 |
|
222 |
strcpy (execdir, exe_dir); |
223 |
u_append (execdir, "i-"); |
224 |
strcat (execdir, exe_ver); |
225 |
|
226 |
u_setenv ("URLADER_EXECDIR", execdir); |
227 |
u_setenv ("URLADER_EXE_ID" , exe_id); |
228 |
u_setenv ("URLADER_EXE_DIR", exe_dir); |
229 |
u_setenv ("URLADER_EXE_VER", exe_ver); |
230 |
} |
231 |
|
232 |
///////////////////////////////////////////////////////////////////////////// |
233 |
|
234 |
static u_handle |
235 |
u_lock (const char *path, int excl, int dowait) |
236 |
{ |
237 |
u_handle h; |
238 |
|
239 |
h = u_lockfile (path); |
240 |
if (!u_valid (h)) |
241 |
return h; |
242 |
|
243 |
u_cloexec (h); |
244 |
|
245 |
for (;;) |
246 |
{ |
247 |
int success; |
248 |
|
249 |
// acquire the lock |
250 |
#ifdef _WIN32 |
251 |
OVERLAPPED ov = { 0 }; |
252 |
|
253 |
success = LockFileEx (h, |
254 |
(excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) |
255 |
| (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), |
256 |
0, |
257 |
1, 0, |
258 |
&ov); |
259 |
#else |
260 |
struct flock lck = { 0 }; |
261 |
|
262 |
lck.l_type = excl ? F_WRLCK : F_RDLCK; |
263 |
lck.l_whence = SEEK_SET; |
264 |
lck.l_len = 1; |
265 |
|
266 |
success = !fcntl (h, dowait ? F_SETLKW : F_SETLK, &lck); |
267 |
#endif |
268 |
|
269 |
if (!success) |
270 |
break; |
271 |
|
272 |
// we have the lock, now verify that the lockfile still exists |
273 |
|
274 |
#ifdef _WIN32 |
275 |
// apparently, we have to open the file to get its info :( |
276 |
{ |
277 |
BY_HANDLE_FILE_INFORMATION s1, s2; |
278 |
u_handle h2 = u_lockfile (path); |
279 |
if (!u_valid (h)) |
280 |
break; |
281 |
|
282 |
success = GetFileInformationByHandle (h, &s1) |
283 |
&& GetFileInformationByHandle (h2, &s2); |
284 |
|
285 |
u_close (h2); |
286 |
|
287 |
if (!success) |
288 |
break; |
289 |
|
290 |
success = s1.dwVolumeSerialNumber == s2.dwVolumeSerialNumber |
291 |
&& s1.nFileIndexHigh == s2.nFileIndexHigh |
292 |
&& s1.nFileIndexLow == s2.nFileIndexLow; |
293 |
} |
294 |
#else |
295 |
struct stat s1, s2; |
296 |
|
297 |
if (fstat (h, &s1) || stat (path, &s2)) |
298 |
break; |
299 |
|
300 |
success = s1.st_dev == s2.st_dev |
301 |
&& s1.st_ino == s2.st_ino; |
302 |
#endif |
303 |
|
304 |
if (success) |
305 |
return h; // lock successfully acquired |
306 |
|
307 |
// files differ, close and retry - should be very rare |
308 |
u_close (h); |
309 |
} |
310 |
|
311 |
// failure |
312 |
u_close (h); |
313 |
return u_invalid_handle; |
314 |
} |
315 |
|