ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Urlader/urlib.c
Revision: 1.4
Committed: Sat Jan 7 19:30:05 2012 UTC (12 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-0_2
Changes since 1.3: +9 -7 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "urlib.h"
2    
3     #include <fcntl.h>
4 root 1.2 #include <stdio.h>
5     #include <string.h>
6     #include <stdlib.h>
7 root 1.1
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 root 1.2 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 root 1.1 static void *
111     u_malloc (unsigned int size)
112     {
113     void *addr;
114    
115 root 1.3 if (!size)
116     return 0;
117    
118 root 1.1 #ifdef _WIN32
119 root 1.4 {
120     HANDLE handle = CreateFileMapping (0, 0, PAGE_READWRITE, 0, size, NULL);
121 root 1.1
122 root 1.4 addr = 0;
123     if (handle)
124     {
125     addr = MapViewOfFile (handle, FILE_MAP_WRITE, 0, 0, size);
126     CloseHandle (handle);
127     }
128     }
129 root 1.1 #elif defined (MAP_ANONYMOUS)
130     addr = mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
131    
132     if (addr == (void *)-1)
133     addr = 0;
134     #else
135     addr = malloc (size);
136     #endif
137    
138 root 1.3 if (!addr)
139     u_fatal ("memory allocation failure, aborting.");
140    
141 root 1.1 return addr;
142     }
143    
144     static void
145     u_free (void *addr, unsigned int size)
146     {
147 root 1.3 if (!addr)
148     return;
149    
150 root 1.1 #ifdef _WIN32
151     UnmapViewOfFile (addr);
152     #elif defined (MAP_ANONYMOUS)
153     munmap (addr, size);
154     #else
155     free (addr);
156     #endif
157     }
158    
159     static void *
160 root 1.3 u_realloc (void *addr, unsigned int old_size, unsigned int new_size)
161     {
162     void *addr2 = u_malloc (new_size);
163     memcpy (addr2, addr, (new_size < old_size ? new_size : old_size));
164     u_free (addr, old_size);
165    
166     return addr2;
167     }
168    
169     static void *
170 root 1.1 u_mmap (u_handle h, unsigned int size)
171     {
172     void *addr;
173    
174     #ifdef _WIN32
175     HANDLE handle = CreateFileMapping (h, 0, PAGE_READONLY, 0, size, NULL);
176    
177     if (!handle)
178     return 0;
179    
180     addr = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, size);
181    
182     CloseHandle (handle);
183     #else
184     addr = mmap (0, size, PROT_READ, MAP_SHARED, h, 0);
185    
186     if (addr == (void *)-1)
187     addr = 0;
188     #endif
189    
190     return addr;
191     }
192    
193     static void
194     u_munmap (void *addr, unsigned int len)
195     {
196     #ifdef _WIN32
197     UnmapViewOfFile (addr);
198     #else
199     munmap (addr, len);
200     #endif
201     }
202 root 1.2
203     /////////////////////////////////////////////////////////////////////////////
204    
205 root 1.3 typedef struct
206     {
207     char *addr;
208     unsigned int used;
209     unsigned int size;
210     } u_dynbuf;
211    
212     static void *
213     u_dynbuf_append (u_dynbuf *dynbuf, void *data, unsigned int len)
214     {
215     char *dest;
216    
217     if ((dynbuf->used += len) > dynbuf->size)
218     {
219     unsigned int new_size = dynbuf->size ? dynbuf->size * 2 : 4096;
220     dynbuf->addr = u_realloc (dynbuf->addr, dynbuf->size, new_size);
221     dynbuf->size = new_size;
222     }
223    
224     dest = dynbuf->addr + dynbuf->used - len;
225    
226     if (data)
227     memcpy (dest, data, len);
228    
229     return dest;
230     }
231    
232     /////////////////////////////////////////////////////////////////////////////
233    
234 root 1.2 static void
235     u_set_datadir (void)
236     {
237     #ifdef _WIN32
238     if (SHGetFolderPath (0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, datadir) != S_OK)
239     u_fatal ("unable to find application data directory");
240    
241     u_mkdir (datadir);
242     u_append (datadir, URLADER);
243    
244     #else
245     char *home = getenv ("HOME");
246    
247     if (!home)
248     {
249     struct passwd *pw;
250    
251     if ((pw = getpwuid (getuid ())))
252     home = pw->pw_dir;
253     else
254     home = "/tmp";
255     }
256    
257     u_mkdir (home);
258     //strcat (strcat (strcpy (datadir, home), "/."), URLADER);
259     sprintf (datadir, "%s/.%s", home, URLADER);
260     #endif
261    
262     u_setenv ("URLADER_DATADIR", datadir);
263     }
264    
265     static void
266     u_set_exe_info (void)
267     {
268     strcpy (exe_dir, datadir);
269     u_append (exe_dir, exe_id);
270     u_mkdir (exe_dir);
271    
272     strcpy (execdir, exe_dir);
273     u_append (execdir, "i-");
274     strcat (execdir, exe_ver);
275    
276     u_setenv ("URLADER_EXECDIR", execdir);
277     u_setenv ("URLADER_EXE_ID" , exe_id);
278     u_setenv ("URLADER_EXE_DIR", exe_dir);
279     u_setenv ("URLADER_EXE_VER", exe_ver);
280     }
281    
282     /////////////////////////////////////////////////////////////////////////////
283    
284 root 1.1 static u_handle
285     u_lock (const char *path, int excl, int dowait)
286     {
287     u_handle h;
288    
289     h = u_lockfile (path);
290     if (!u_valid (h))
291     return h;
292    
293     u_cloexec (h);
294    
295     for (;;)
296     {
297     int success;
298    
299     // acquire the lock
300     #ifdef _WIN32
301     OVERLAPPED ov = { 0 };
302    
303     success = LockFileEx (h,
304     (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0)
305     | (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY),
306     0,
307     1, 0,
308     &ov);
309     #else
310     struct flock lck = { 0 };
311    
312     lck.l_type = excl ? F_WRLCK : F_RDLCK;
313     lck.l_whence = SEEK_SET;
314     lck.l_len = 1;
315    
316     success = !fcntl (h, dowait ? F_SETLKW : F_SETLK, &lck);
317     #endif
318    
319     if (!success)
320     break;
321    
322     // we have the lock, now verify that the lockfile still exists
323    
324     #ifdef _WIN32
325     // apparently, we have to open the file to get its info :(
326 root 1.2 {
327     BY_HANDLE_FILE_INFORMATION s1, s2;
328     u_handle h2 = u_lockfile (path);
329     if (!u_valid (h))
330     break;
331    
332     success = GetFileInformationByHandle (h, &s1)
333     && GetFileInformationByHandle (h2, &s2);
334    
335     u_close (h2);
336    
337     if (!success)
338     break;
339    
340     success = s1.dwVolumeSerialNumber == s2.dwVolumeSerialNumber
341     && s1.nFileIndexHigh == s2.nFileIndexHigh
342     && s1.nFileIndexLow == s2.nFileIndexLow;
343     }
344 root 1.1 #else
345     struct stat s1, s2;
346    
347     if (fstat (h, &s1) || stat (path, &s2))
348     break;
349    
350     success = s1.st_dev == s2.st_dev
351     && s1.st_ino == s2.st_ino;
352     #endif
353    
354     if (success)
355     return h; // lock successfully acquired
356    
357     // files differ, close and retry - should be very rare
358     u_close (h);
359     }
360    
361     // failure
362     u_close (h);
363     return u_invalid_handle;
364     }
365