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

# Content
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 if (!size)
116 return 0;
117
118 #ifdef _WIN32
119 {
120 HANDLE handle = CreateFileMapping (0, 0, PAGE_READWRITE, 0, size, NULL);
121
122 addr = 0;
123 if (handle)
124 {
125 addr = MapViewOfFile (handle, FILE_MAP_WRITE, 0, 0, size);
126 CloseHandle (handle);
127 }
128 }
129 #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 if (!addr)
139 u_fatal ("memory allocation failure, aborting.");
140
141 return addr;
142 }
143
144 static void
145 u_free (void *addr, unsigned int size)
146 {
147 if (!addr)
148 return;
149
150 #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 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 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
203 /////////////////////////////////////////////////////////////////////////////
204
205 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 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 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 {
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 #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