ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Urlader/urlib.c
Revision: 1.6
Committed: Tue Jan 17 18:38:37 2012 UTC (12 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_0, rel-1_01, HEAD
Changes since 1.5: +36 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * Copyright (c) 2012 Marc Alexander Lehmann <schmorp@schmorp.de>
3 *
4 * Redistribution and use in source and binary forms, with or without modifica-
5 * tion, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
16 * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
18 * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
22 * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
23 * OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * the GNU General Public License ("GPL") version 2 or any later version,
27 * in which case the provisions of the GPL are applicable instead of
28 * the above. If you wish to allow the use of your version of this file
29 * only under the terms of the GPL and not to allow others to use your
30 * version of this file under the BSD license, indicate your decision
31 * by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL. If you do not delete the
33 * provisions above, a recipient may use your version of this file under
34 * either the BSD or the GPL.
35 */
36
37 #include "urlib.h"
38
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43
44 #ifdef _WIN32
45
46 #include <windows.h>
47 //#include <winbase.h>
48 #include <shlobj.h>
49 #include <shlwapi.h>
50 #include <wininet.h>
51
52 static DWORD dword;
53
54 #define u_handle HANDLE
55 #define u_invalid_handle 0
56 #define u_valid(handle) (!!handle)
57
58 #define u_setenv(name,value) SetEnvironmentVariable (name, value)
59 #define u_mkdir(path) !CreateDirectory (path, NULL)
60 #define u_chdir(path) !SetCurrentDirectory (path)
61 #define u_rename(fr,to) !MoveFile (fr, to)
62 #define u_open(path) CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)
63 #define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)
64 #define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)
65 #define u_close(handle) CloseHandle (handle)
66 #define u_append(path,add) PathAppend (path, add)
67 #define u_write(handle,data,len) (WriteFile (handle, data, len, &dword, 0) ? dword : -1)
68
69 #define u_fsync(handle) FlushFileBuffers (handle)
70 #define u_sync()
71
72 #define u_lockfile(path) CreateFile (path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)
73 #define u_cloexec(handle)
74
75 #else
76
77 #define _GNU_SOURCE 1
78 #define _BSD_SOURCE 1
79 // the above increases our chances of getting MAP_ANONYMOUS
80
81 #include <sys/mman.h>
82 #include <sys/types.h>
83 #include <sys/stat.h>
84 #include <unistd.h>
85 #include <pwd.h>
86
87 #if defined (MAP_ANON) && !defined (MAP_ANONYMOUS)
88 #define MAP_ANONYMOUS MAP_ANON
89 #endif
90
91 #ifdef PATH_MAX
92 #define MAX_PATH (PATH_MAX < 4096 ? 4096 : PATH_MAX)
93 #else
94 #define MAX_PATH 4096
95 #endif
96
97 #define u_handle int
98 #define u_invalid_handle -1
99 #define u_valid(fd) ((fd) >= 0)
100
101 #define u_setenv(name,value) setenv (name, value, 1)
102 #define u_mkdir(path) mkdir (path, 0777)
103 #define u_chdir(path) chdir (path)
104 #define u_rename(fr,to) rename (fr, to)
105 #define u_open(path) open (path, O_RDONLY)
106 #define u_creat(path,exec) open (path, O_WRONLY | O_CREAT | O_TRUNC, (exec) ? 0777 : 0666)
107 #define u_close(handle) close (handle)
108 #define u_append(path,add) strcat (strcat (path, "/"), add)
109 #define u_write(handle,data,len) write (handle, data, len)
110
111 // on a mostly idle system, a sync at the end is certainly faster, hope for the best
112 #define u_fsync(handle)
113 #define u_sync() sync ()
114
115 #define u_lockfile(path) open (path, O_RDWR | O_CREAT, 0666)
116 #define u_cloexec(handle) fcntl (handle, F_SETFD, FD_CLOEXEC)
117
118 #endif
119
120 #define u_16(ptr) (((ptr)[0] << 8) | (ptr)[1])
121 #define u_32(ptr) (((ptr)[0] << 24) | ((ptr)[1] << 16) | ((ptr)[2] << 8) | (ptr)[3])
122
123 static char currdir[MAX_PATH];
124 static char datadir[MAX_PATH]; // %AppData%/urlader
125 static char exe_dir[MAX_PATH]; // %AppData%/urlader/EXE_ID
126 static char execdir[MAX_PATH]; // %AppData%/urlader/EXE_ID/EXE_VER
127 static char exe_id[MAX_PATH];
128 static char exe_ver[MAX_PATH];
129
130 /////////////////////////////////////////////////////////////////////////////
131
132 static void
133 u_fatal (const char *msg)
134 {
135 #ifdef _WIN32
136 MessageBox (0, msg, URLADER, 0);
137 #else
138 write (2, URLADER ": ", sizeof (URLADER ": ") - 1);
139 write (2, msg, strlen (msg));
140 write (2, "\n", 1);
141 #endif
142
143 _exit (1);
144 }
145
146 static void *
147 u_malloc (unsigned int size)
148 {
149 void *addr;
150
151 if (!size)
152 return 0;
153
154 #ifdef _WIN32
155 {
156 HANDLE handle = CreateFileMapping (0, 0, PAGE_READWRITE, 0, size, NULL);
157
158 addr = 0;
159 if (handle)
160 {
161 addr = MapViewOfFile (handle, FILE_MAP_WRITE, 0, 0, size);
162 CloseHandle (handle);
163 }
164 }
165 #elif defined (MAP_ANONYMOUS)
166 addr = mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
167
168 if (addr == (void *)-1)
169 addr = 0;
170 #else
171 addr = malloc (size);
172 #endif
173
174 if (!addr)
175 u_fatal ("memory allocation failure, aborting.");
176
177 return addr;
178 }
179
180 static void
181 u_free (void *addr, unsigned int size)
182 {
183 if (!addr)
184 return;
185
186 #ifdef _WIN32
187 UnmapViewOfFile (addr);
188 #elif defined (MAP_ANONYMOUS)
189 munmap (addr, size);
190 #else
191 free (addr);
192 #endif
193 }
194
195 static void *
196 u_realloc (void *addr, unsigned int old_size, unsigned int new_size)
197 {
198 void *addr2 = u_malloc (new_size);
199 memcpy (addr2, addr, (new_size < old_size ? new_size : old_size));
200 u_free (addr, old_size);
201
202 return addr2;
203 }
204
205 static void *
206 u_mmap (u_handle h, unsigned int size)
207 {
208 void *addr;
209
210 #ifdef _WIN32
211 HANDLE handle = CreateFileMapping (h, 0, PAGE_READONLY, 0, size, NULL);
212
213 if (!handle)
214 return 0;
215
216 addr = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, size);
217
218 CloseHandle (handle);
219 #else
220 addr = mmap (0, size, PROT_READ, MAP_SHARED, h, 0);
221
222 if (addr == (void *)-1)
223 addr = 0;
224 #endif
225
226 return addr;
227 }
228
229 static void
230 u_munmap (void *addr, unsigned int len)
231 {
232 #ifdef _WIN32
233 UnmapViewOfFile (addr);
234 #else
235 munmap (addr, len);
236 #endif
237 }
238
239 /////////////////////////////////////////////////////////////////////////////
240
241 typedef struct
242 {
243 char *addr;
244 unsigned int used;
245 unsigned int size;
246 } u_dynbuf;
247
248 static void *
249 u_dynbuf_append (u_dynbuf *dynbuf, void *data, unsigned int len)
250 {
251 char *dest;
252
253 if ((dynbuf->used += len) > dynbuf->size)
254 {
255 unsigned int new_size = dynbuf->size ? dynbuf->size * 2 : 4096;
256 dynbuf->addr = u_realloc (dynbuf->addr, dynbuf->size, new_size);
257 dynbuf->size = new_size;
258 }
259
260 dest = dynbuf->addr + dynbuf->used - len;
261
262 if (data)
263 memcpy (dest, data, len);
264
265 return dest;
266 }
267
268 /////////////////////////////////////////////////////////////////////////////
269
270 static void
271 u_set_datadir (void)
272 {
273 #ifdef _WIN32
274 if (SHGetFolderPath (0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, datadir) != S_OK)
275 u_fatal ("unable to find application data directory");
276
277 u_mkdir (datadir);
278 u_append (datadir, URLADER);
279
280 #else
281 char *home = getenv ("HOME");
282
283 if (!home)
284 {
285 struct passwd *pw;
286
287 if ((pw = getpwuid (getuid ())))
288 home = pw->pw_dir;
289 else
290 home = "/tmp";
291 }
292
293 u_mkdir (home);
294 //strcat (strcat (strcpy (datadir, home), "/."), URLADER);
295 sprintf (datadir, "%s/.%s", home, URLADER);
296 #endif
297
298 u_setenv ("URLADER_DATADIR", datadir);
299 }
300
301 static void
302 u_set_exe_info (void)
303 {
304 strcpy (exe_dir, datadir);
305 u_append (exe_dir, exe_id);
306 u_mkdir (exe_dir);
307
308 strcpy (execdir, exe_dir);
309 u_append (execdir, "i-");
310 strcat (execdir, exe_ver);
311
312 u_setenv ("URLADER_EXECDIR", execdir);
313 u_setenv ("URLADER_EXE_ID" , exe_id);
314 u_setenv ("URLADER_EXE_DIR", exe_dir);
315 u_setenv ("URLADER_EXE_VER", exe_ver);
316 }
317
318 /////////////////////////////////////////////////////////////////////////////
319
320 static u_handle
321 u_lock (const char *path, int excl, int dowait)
322 {
323 u_handle h;
324
325 h = u_lockfile (path);
326 if (!u_valid (h))
327 return h;
328
329 u_cloexec (h);
330
331 for (;;)
332 {
333 int success;
334
335 // acquire the lock
336 #ifdef _WIN32
337 OVERLAPPED ov = { 0 };
338
339 success = LockFileEx (h,
340 (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0)
341 | (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY),
342 0,
343 1, 0,
344 &ov);
345 #else
346 struct flock lck = { 0 };
347
348 lck.l_type = excl ? F_WRLCK : F_RDLCK;
349 lck.l_whence = SEEK_SET;
350 lck.l_len = 1;
351
352 success = !fcntl (h, dowait ? F_SETLKW : F_SETLK, &lck);
353 #endif
354
355 if (!success)
356 break;
357
358 // we have the lock, now verify that the lockfile still exists
359
360 #ifdef _WIN32
361 // apparently, we have to open the file to get its info :(
362 {
363 BY_HANDLE_FILE_INFORMATION s1, s2;
364 u_handle h2 = u_lockfile (path);
365 if (!u_valid (h))
366 break;
367
368 success = GetFileInformationByHandle (h, &s1)
369 && GetFileInformationByHandle (h2, &s2);
370
371 u_close (h2);
372
373 if (!success)
374 break;
375
376 success = s1.dwVolumeSerialNumber == s2.dwVolumeSerialNumber
377 && s1.nFileIndexHigh == s2.nFileIndexHigh
378 && s1.nFileIndexLow == s2.nFileIndexLow;
379 }
380 #else
381 struct stat s1, s2;
382
383 if (fstat (h, &s1) || stat (path, &s2))
384 break;
385
386 success = s1.st_dev == s2.st_dev
387 && s1.st_ino == s2.st_ino;
388 #endif
389
390 if (success)
391 return h; // lock successfully acquired
392
393 // files differ, close and retry - should be very rare
394 u_close (h);
395 }
396
397 // failure
398 u_close (h);
399 return u_invalid_handle;
400 }
401