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, 8 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

# User Rev Content
1 root 1.6 /*
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 root 1.1 #include "urlib.h"
38    
39     #include <fcntl.h>
40 root 1.2 #include <stdio.h>
41     #include <string.h>
42     #include <stdlib.h>
43 root 1.1
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 root 1.5 #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 root 1.1 #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 root 1.5 #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 root 1.1 #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 root 1.2 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 root 1.1 static void *
147     u_malloc (unsigned int size)
148     {
149     void *addr;
150    
151 root 1.3 if (!size)
152     return 0;
153    
154 root 1.1 #ifdef _WIN32
155 root 1.4 {
156     HANDLE handle = CreateFileMapping (0, 0, PAGE_READWRITE, 0, size, NULL);
157 root 1.1
158 root 1.4 addr = 0;
159     if (handle)
160     {
161     addr = MapViewOfFile (handle, FILE_MAP_WRITE, 0, 0, size);
162     CloseHandle (handle);
163     }
164     }
165 root 1.1 #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 root 1.3 if (!addr)
175     u_fatal ("memory allocation failure, aborting.");
176    
177 root 1.1 return addr;
178     }
179    
180     static void
181     u_free (void *addr, unsigned int size)
182     {
183 root 1.3 if (!addr)
184     return;
185    
186 root 1.1 #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 root 1.3 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 root 1.1 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 root 1.2
239     /////////////////////////////////////////////////////////////////////////////
240    
241 root 1.3 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 root 1.2 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 root 1.1 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 root 1.2 {
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 root 1.1 #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