1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <libidav/utils.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <errno.h>
37
38 #include <cx/string.h>
39
40 #ifndef _WIN32
41 #include <unistd.h>
42 #endif
43
44 #include "system.h"
45
46 void sys_freedirent(SysDirEnt *ent) {
47 free(ent->name);
48 free(ent);
49 }
50
51 #ifndef _WIN32
52
53
54 void sys_init(
void) {
55
56 }
57 void sys_uninit(
void) {
58
59 }
60
61 SYS_DIR sys_opendir(
const char *path) {
62 DIR *dir = opendir(path);
63 if(!dir) {
64 return NULL;
65 }
66 SysDir *d = malloc(
sizeof(SysDir));
67 d->dir = dir;
68 d->ent =
NULL;
69 return d;
70 }
71
72 SysDirEnt* sys_readdir(
SYS_DIR dir) {
73 if(dir->ent) {
74 free(dir->ent->name);
75 free(dir->ent);
76 dir->ent =
NULL;
77 }
78 struct dirent *ent = readdir(dir->dir);
79 if(ent) {
80 SysDirEnt *e = malloc(
sizeof(SysDirEnt));
81 e->name = strdup(ent->d_name);
82 dir->ent = e;
83 return e;
84 }
85 return NULL;
86 }
87
88 void sys_closedir(
SYS_DIR dir) {
89 closedir(dir->dir);
90 if(dir->ent) {
91 free(dir->ent->name);
92 free(dir->ent);
93 }
94 free(dir);
95 }
96
97 FILE* sys_fopen(
const char *path,
const char *mode) {
98 return fopen(path, mode);
99 }
100
101 int sys_stat(
const char *path,
SYS_STAT *s) {
102 return stat(path, s);
103 }
104
105 int sys_lstat(
const char *path,
SYS_STAT *s) {
106 return lstat(path, s);
107 }
108
109 int sys_islink(
const char *path) {
110 struct stat s;
111 if(!lstat(path, &s)) {
112 return S_ISLNK(s.st_mode);
113 }
114 return 0;
115 }
116
117 int sys_rename(
const char *oldpath,
const char *newpath) {
118 return rename(oldpath, newpath);
119 }
120
121 int sys_unlink(
const char *path) {
122 return unlink(path);
123 }
124
125 int sys_mkdir(
const char *path) {
126 return mkdir(path,
S_IRWXU |
S_IRGRP |
S_IXGRP |
S_IROTH |
S_IXOTH);
127 }
128
129 char* sys_readlink(
const char *path,
SYS_STAT *s) {
130 char *ret =
NULL;
131
132 off_t l_sz = s->st_size +
16;
133 size_t lnksize = l_sz >
256 ? l_sz :
256;
134 char *lnkbuf = malloc(lnksize);
135
136 ssize_t len =
0;
137 for(
int i=
0;i<
4;i++) {
138
139
140 len = readlink(path, lnkbuf, lnksize);
141 if(len < lnksize) {
142 ret = lnkbuf;
143 lnkbuf[len] =
0;
144 break;
145 }
146 lnksize *=
2;
147 lnkbuf = realloc(lnkbuf, lnksize);
148 }
149
150 if(!ret) {
151 free(lnkbuf);
152 }
153 return ret;
154 }
155
156 int sys_symlink(
const char *target,
const char *linkpath) {
157 int err = symlink(target, linkpath);
158 if(err && errno ==
EEXIST) {
159 if(unlink(linkpath)) {
160 return 1;
161 }
162 return sys_symlink(target, linkpath);
163 }
164 return err;
165 }
166
167 int sys_truncate(
const char* path,
off_t length) {
168 return truncate(path, length);
169 }
170
171 #else
172
173
174 #include <windows.h>
175 #include <winnls.h>
176 #include <shobjidl.h>
177 #include <objbase.h>
178 #include <objidl.h>
179
180 #include <direct.h>
181 #include <wchar.h>
182
183 void sys_init(
void) {
184 HRESULT res = CoInitialize(
NULL);
185 if(res !=
S_OK) {
186 fprintf(stderr,
"Error: CoInitialize failed\n");
187 }
188 }
189
190 void sys_uninit(
void) {
191 CoUninitialize();
192 }
193
194 static wchar_t* path2winpath(
const char *path,
int dir,
int *newlen) {
195 size_t len = strlen(path);
196 size_t lenadd = dir ?
2 :
0;
197
198
199 wchar_t *wpath = calloc(len+lenadd+
1,
sizeof(
wchar_t));
200 int wlen = MultiByteToWideChar(
201 CP_UTF8,
202 0,
203 path,
204 len,
205 wpath,
206 len+
1
207 );
208 if(newlen) {
209 *newlen = wlen;
210 }
211 for(
int i=
0;i<wlen;i++) {
212 if(wpath[i] ==
'/'L) {
213 wpath[i] =
'\\'L;
214 }
215 }
216
217 if(dir) {
218 if(wpath[wlen-
1] !=
'\\'L) {
219 wpath[wlen++] =
'\\'L;
220 }
221 wpath[wlen++] =
'*'L;
222 }
223 wpath[wlen] =
0;
224
225 return wpath;
226 }
227
228 static char* winpath2multibyte(
const wchar_t *wpath,
size_t wlen) {
229 size_t maxlen = wlen *
4;
230 char *ret = malloc(maxlen +
1);
231 int ret_len = WideCharToMultiByte(
232 CP_UTF8,
233 0,
234 wpath,
235 wlen,
236 ret,
237 maxlen,
238 NULL,
239 NULL);
240 ret[ret_len] =
0;
241 return ret;
242 }
243
244
245
246 SYS_DIR sys_opendir(
const char *path) {
247 struct WinDir *dir = malloc(
sizeof(
struct WinDir));
248 wchar_t *dirpath = path2winpath(path,
TRUE,
NULL);
249 if(!dirpath) {
250 fprintf(stderr,
"Cannot convert path \"%s\" to UTF16\n", path);
251 free(dir);
252 return NULL;
253 }
254 dir->first =
1;
255 dir->handle = FindFirstFileW(dirpath, &dir->finddata);
256 free(dirpath);
257 if(dir->handle ==
INVALID_HANDLE_VALUE) {
258 free(dir);
259 return NULL;
260 }
261 dir->ent =
NULL;
262 return dir;
263 }
264
265 SysDirEnt* sys_readdir(
SYS_DIR dir) {
266 if(dir->ent) {
267 free(dir->ent->name);
268 free(dir->ent);
269 dir->ent =
NULL;
270 }
271 if(dir->first) {
272 dir->first =
0;
273 }
else {
274 if(FindNextFileW(dir->handle, &dir->finddata) ==
0) {
275 return NULL;
276 }
277 }
278
279 size_t namelen = wcslen(dir->finddata.cFileName);
280
281 char *name = malloc((namelen+
1)*
4);
282 int nlen = WideCharToMultiByte(
283 CP_UTF8,
284 0,
285 dir->finddata.cFileName,
286 -
1,
287 name,
288 256,
289 NULL,
290 NULL);
291 if(nlen >
0) {
292 name[nlen] =
0;
293 SysDirEnt *ent = malloc(
sizeof(SysDirEnt));
294 ent->name = name;
295 dir->ent = ent;
296 return ent;
297 }
else {
298 return NULL;
299 }
300 }
301
302 void sys_closedir(
SYS_DIR dir) {
303 if(dir->ent) {
304 free(dir->ent->name);
305 free(dir->ent);
306 }
307 FindClose(dir->handle);
308 free(dir);
309 }
310
311 FILE* sys_fopen(
const char *path,
const char *mode) {
312 wchar_t *fpath = path2winpath(path,
FALSE,
NULL);
313 wchar_t *fmode = path2winpath(mode,
FALSE,
NULL);
314
315 FILE *file = (fpath && fmode) ? _wfopen(fpath, fmode) :
NULL;
316 free(fpath);
317 free(fmode);
318 return file;
319 }
320
321 int sys_stat(
const char *path,
SYS_STAT *s) {
322 wchar_t *fpath = path2winpath(path,
FALSE,
NULL);
323 if(!fpath) {
324 fprintf(stderr,
"Cannot convert path \"%s\" to UTF16\n", path);
325 return -
1;
326 }
327 int ret = _wstat64(fpath, s);
328 free(fpath);
329 return ret;
330 }
331
332 int sys_lstat(
const char *path,
SYS_STAT *s) {
333 return sys_stat(path, s);
334 }
335
336 int sys_islink(
const char *path) {
337
338
339 int ret =
0;
340
341 cxstring path_s = cx_str(path);
342 if(cx_strsuffix(path_s,
CX_STR(
".lnk"))) {
343
344
345 IShellLink *sl;
346 HRESULT hres;
347 hres = CoCreateInstance(&CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (
LPVOID*)&sl);
348 if(
SUCCEEDED(hres)) {
349 IPersistFile *file;
350 hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (
void**)&file);
351 if(!
SUCCEEDED(hres)) {
352 sl->lpVtbl->Release(sl);
353 return ret;
354 }
355
356 int newlen =
0;
357 wchar_t *wpath = path2winpath(path,
0, &newlen);
358
359 hres = file->lpVtbl->Load(file, wpath,
STGM_READ);
360 if(
SUCCEEDED(hres)) {
361 ret =
1;
362 file->lpVtbl->Release(file);
363 }
364 free(wpath);
365
366 sl->lpVtbl->Release(sl);
367 }
368 }
369 return ret;
370 }
371
372 int sys_rename(
const char *oldpath,
const char *newpath) {
373 wchar_t *o = path2winpath(oldpath,
FALSE,
NULL);
374 wchar_t *n = path2winpath(newpath,
FALSE,
NULL);
375 if(!o || !n) {
376 return -
1;
377 }
378
379 struct __stat64 s;
380 if(!_wstat64(n, &s)) {
381 if(_wunlink(n)) {
382 fprintf(stderr,
"sys_rename: cannot delete existing file: %ls\n", n);
383 }
384 }
385
386 int ret = _wrename(o, n);
387 free(o);
388 free(n);
389 return ret;
390 }
391
392 int sys_unlink(
const char *path) {
393 wchar_t *wpath = path2winpath(path,
FALSE,
NULL);
394 if(!wpath) {
395 fprintf(stderr,
"sys_unlink: cannot convert path\n");
396 return -
1;
397 }
398 int ret = _wunlink(wpath);
399 free(wpath);
400 return ret;
401 }
402
403 int sys_mkdir(
const char *path) {
404 wchar_t *wpath = path2winpath(path,
FALSE,
NULL);
405 if(!wpath) {
406 fprintf(stderr,
"sys_mkdir: cannot convert path\n");
407 return -
1;
408 }
409 int ret = _wmkdir(wpath);
410 free(wpath);
411 return ret;
412 }
413
414 char* sys_readlink(
const char *path,
SYS_STAT *s) {
415 char *ret_link =
NULL;
416
417
418 IShellLinkW *sl;
419 HRESULT hres = CoCreateInstance(&CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (
LPVOID*)&sl);
420 if(!
SUCCEEDED(hres)) {
421 return NULL;
422 }
423
424 IPersistFile *file;
425 hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (
void**)&file);
426 if(!
SUCCEEDED(hres)) {
427 sl->lpVtbl->Release(sl);
428 return NULL;
429 }
430
431
432 int newlen =
0;
433 wchar_t *wpath = path2winpath(path,
0, &newlen);
434 hres = file->lpVtbl->Load(file, wpath,
STGM_READ);
435 if(
SUCCEEDED(hres)) {
436 WCHAR link_path[
MAX_PATH];
437 memset(link_path,
0,
MAX_PATH);
438
439 hres = sl->lpVtbl->Resolve(sl,
0,
SLR_NO_UI);
440 if(
SUCCEEDED(hres)) {
441 hres = sl->lpVtbl->GetPath(sl, link_path,
MAX_PATH,
NULL,
SLGP_SHORTPATH);
442 if(
SUCCEEDED(hres)) {
443 ret_link = winpath2multibyte(link_path, wcslen(link_path));
444 }
445 }
446 }
447
448 free(wpath);
449 file->lpVtbl->Release(file);
450 sl->lpVtbl->Release(sl);
451
452 return ret_link;
453 }
454
455 int sys_symlink(
const char *target,
const char *linkpath) {
456
457 char *link_parent = util_parent_path(linkpath);
458 char *target_unnormalized = util_concat_path(link_parent, target);
459 char *target_normalized = util_path_normalize(target_unnormalized);
460
461 free(link_parent);
462 free(target_unnormalized);
463
464
465 int wtargetlen =
0;
466 wchar_t *wtarget = path2winpath(target_normalized,
FALSE, &wtargetlen);
467 free(target_normalized);
468 if(!wtarget) {
469 return 1;
470 }
471
472 int wlinkpathlen =
0;
473 wchar_t *wlinkpath = path2winpath(linkpath,
FALSE, &wlinkpathlen);
474 if(!wlinkpath) {
475 free(wtarget);
476 return 1;
477 }
478
479 int ret =
1;
480
481
482 IShellLinkW *sl;
483 HRESULT hres = CoCreateInstance(&CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (
LPVOID*)&sl);
484 if(
SUCCEEDED(hres)) {
485 IPersistFile *file;
486 hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (
void**)&file);
487 if(
SUCCEEDED(hres)) {
488
489 file->lpVtbl->Load(file, wlinkpath,
STGM_READ);
490
491
492 hres = sl->lpVtbl->SetPath(sl, wtarget);
493 if(
SUCCEEDED(hres)) {
494 hres = file->lpVtbl->Save(file, wlinkpath,
TRUE);
495 if(
SUCCEEDED(hres)) {
496
497 ret =
0;
498 }
499 }
500
501 file->lpVtbl->Release(file);
502 }
503
504 sl->lpVtbl->Release(sl);
505 }
506
507 free(wtarget);
508 free(wlinkpath);
509
510 return ret;
511 }
512
513 int sys_truncate(
const char* path,
off_t length) {
514 wchar_t* wpath = path2winpath(path,
FALSE,
NULL);
515 if (!wpath) {
516 fprintf(stderr,
"sys_truncate: cannot convert path\n");
517 return -
1;
518 }
519
520 FILE* file = _wfopen(wpath,
"wb"L);
521 int ret =
1;
522 if (file) {
523 ret = _chsize(fileno(file), length);
524 fclose(file);
525 }
526
527 free(wpath);
528 return ret;
529 }
530
531 #endif
532