94 |
105 |
95 int sys_lstat(const char *path, SYS_STAT *s) { |
106 int sys_lstat(const char *path, SYS_STAT *s) { |
96 return lstat(path, s); |
107 return lstat(path, s); |
97 } |
108 } |
98 |
109 |
|
110 int sys_islink(const char *path) { |
|
111 struct stat s; |
|
112 if(!lstat(path, &s)) { |
|
113 return S_ISLNK(s.st_mode); |
|
114 } |
|
115 } return 0; |
|
116 |
99 int sys_rename(const char *oldpath, const char *newpath) { |
117 int sys_rename(const char *oldpath, const char *newpath) { |
100 return rename(oldpath, newpath); |
118 return rename(oldpath, newpath); |
101 } |
119 } |
102 |
120 |
103 int sys_unlink(const char *path) { |
121 int sys_unlink(const char *path) { |
106 |
124 |
107 int sys_mkdir(const char *path) { |
125 int sys_mkdir(const char *path) { |
108 return mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); |
126 return mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); |
109 } |
127 } |
110 |
128 |
111 ssize_t sys_readlink(const char *path, char *buffer, size_t size) { |
129 char* sys_readlink(const char *path, SYS_STAT *s) { |
112 return readlink(path, buffer, size); |
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 // we try to read the link at most 4 times |
|
139 // only repeat if the buffer is too small |
|
140 len = readlink(path, lnkbuf, lnksize); |
|
141 if(len < lnksize) { |
|
142 ret = lnkbuf; // success |
|
143 lnkbuf[len] = 0; // terminate buffer |
|
144 break; |
|
145 } |
|
146 lnksize *= 2; // retry with bigger buffer |
|
147 lnkbuf = realloc(lnkbuf, lnksize); |
|
148 } |
|
149 |
|
150 if(!ret) { |
|
151 free(lnkbuf); |
|
152 } |
|
153 return ret; |
113 } |
154 } |
114 |
155 |
115 int sys_symlink(const char *target, const char *linkpath) { |
156 int sys_symlink(const char *target, const char *linkpath) { |
116 int err = symlink(target, linkpath); |
157 int err = symlink(target, linkpath); |
117 if(err && errno == EEXIST) { |
158 if(err && errno == EEXIST) { |
123 return err; |
164 return err; |
124 } |
165 } |
125 |
166 |
126 #else |
167 #else |
127 /* ---------- Windows implementation ---------- */ |
168 /* ---------- Windows implementation ---------- */ |
|
169 |
|
170 #include <windows.h> |
|
171 #include <winnls.h> |
|
172 #include <shobjidl.h> |
|
173 #include <objbase.h> |
|
174 #include <objidl.h> |
|
175 |
|
176 #include <direct.h> |
|
177 #include <wchar.h> |
|
178 |
|
179 void sys_init(void) { |
|
180 HRESULT res = CoInitialize(NULL); |
|
181 if(res != S_OK) { |
|
182 fprintf(stderr, "Error: CoInitialize failed\n"); |
|
183 } |
|
184 } |
|
185 |
|
186 void sys_uninit(void) { |
|
187 CoUninitialize(); |
|
188 } |
128 |
189 |
129 static wchar_t* path2winpath(const char *path, int dir, int *newlen) { |
190 static wchar_t* path2winpath(const char *path, int dir, int *newlen) { |
130 size_t len = strlen(path); |
191 size_t len = strlen(path); |
131 size_t lenadd = dir ? 2 : 0; |
192 size_t lenadd = dir ? 2 : 0; |
132 |
193 |
245 free(fpath); |
324 free(fpath); |
246 return ret; |
325 return ret; |
247 } |
326 } |
248 |
327 |
249 int sys_lstat(const char *path, SYS_STAT *s) { |
328 int sys_lstat(const char *path, SYS_STAT *s) { |
250 return sys_stat(path, s); // unsupported on windows |
329 return sys_stat(path, s); // unsupported on windows |
|
330 } |
|
331 |
|
332 int sys_islink(const char *path) { |
|
333 // don't use symlinks on windows, because it is not really useful |
|
334 // however, we interpret .lnk files as symlinks |
|
335 int ret = 0; |
|
336 |
|
337 scstr_t path_s = scstr(path); |
|
338 if(scstrsuffix(path_s, SC(".lnk"))) { |
|
339 // looks like a .lnk file |
|
340 // check content |
|
341 IShellLink *sl; |
|
342 HRESULT hres; |
|
343 hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); |
|
344 if(SUCCEEDED(hres)) { |
|
345 IPersistFile *file; |
|
346 hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (void**)&file); |
|
347 if(!SUCCEEDED(hres)) { |
|
348 sl->lpVtbl->Release(sl); |
|
349 return ret; |
|
350 } |
|
351 |
|
352 int newlen = 0; |
|
353 wchar_t *wpath = path2winpath(path, 0, &newlen); |
|
354 |
|
355 hres = file->lpVtbl->Load(file, wpath, STGM_READ); |
|
356 if(SUCCEEDED(hres)) { |
|
357 ret = 1; |
|
358 file->lpVtbl->Release(file); |
|
359 } |
|
360 free(wpath); |
|
361 |
|
362 sl->lpVtbl->Release(sl); |
|
363 } |
|
364 } |
|
365 return ret; |
251 } |
366 } |
252 |
367 |
253 int sys_rename(const char *oldpath, const char *newpath) { |
368 int sys_rename(const char *oldpath, const char *newpath) { |
254 wchar_t *o = path2winpath(oldpath, FALSE, NULL); |
369 wchar_t *o = path2winpath(oldpath, FALSE, NULL); |
255 wchar_t *n = path2winpath(newpath, FALSE, NULL); |
370 wchar_t *n = path2winpath(newpath, FALSE, NULL); |
290 int ret = _wmkdir(wpath); |
405 int ret = _wmkdir(wpath); |
291 free(wpath); |
406 free(wpath); |
292 return ret; |
407 return ret; |
293 } |
408 } |
294 |
409 |
295 ssize_t sys_readlink(const char *path, char *buffer, size_t size) { |
410 char* sys_readlink(const char *path, SYS_STAT *s) { |
296 // TODO |
411 char *ret_link = NULL; |
297 fprintf(stderr, "sys_readlink: implement me\n"); |
412 |
298 return 1; |
413 // create COM object for using the ShellLink interface |
|
414 IShellLinkW *sl; |
|
415 HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); |
|
416 if(!SUCCEEDED(hres)) { |
|
417 return NULL; |
|
418 } |
|
419 |
|
420 IPersistFile *file; |
|
421 hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (void**)&file); |
|
422 if(!SUCCEEDED(hres)) { |
|
423 sl->lpVtbl->Release(sl); |
|
424 return NULL; |
|
425 } |
|
426 |
|
427 // load .lnk file |
|
428 int newlen = 0; |
|
429 wchar_t *wpath = path2winpath(path, 0, &newlen); |
|
430 hres = file->lpVtbl->Load(file, wpath, STGM_READ); |
|
431 if(SUCCEEDED(hres)) { |
|
432 WCHAR link_path[MAX_PATH]; |
|
433 memset(link_path, 0, MAX_PATH); |
|
434 |
|
435 hres = sl->lpVtbl->Resolve(sl, 0, SLR_NO_UI); |
|
436 if(SUCCEEDED(hres)) { |
|
437 hres = sl->lpVtbl->GetPath(sl, link_path, MAX_PATH, NULL, SLGP_SHORTPATH); |
|
438 if(SUCCEEDED(hres)) { |
|
439 ret_link = winpath2multibyte(link_path, wcslen(link_path)); |
|
440 } |
|
441 } |
|
442 } |
|
443 // cleanup |
|
444 free(wpath); |
|
445 file->lpVtbl->Release(file); |
|
446 sl->lpVtbl->Release(sl); |
|
447 |
|
448 return ret_link; |
299 } |
449 } |
300 |
450 |
301 int sys_symlink(const char *target, const char *linkpath) { |
451 int sys_symlink(const char *target, const char *linkpath) { |
302 // TODO |
452 // convert relative target to absolut path |
303 fprintf(stderr, "sys_symlink: implement me\n"); |
453 char *link_parent = util_parent_path(linkpath); |
304 return 1; |
454 char *target_unnormalized = util_concat_path(link_parent, target); |
|
455 char *target_normalized = util_path_normalize(target_unnormalized); |
|
456 |
|
457 free(link_parent); |
|
458 free(target_unnormalized); |
|
459 |
|
460 // convert to wchar_t* |
|
461 int wtargetlen = 0; |
|
462 wchar_t *wtarget = path2winpath(target_normalized, FALSE, &wtargetlen); |
|
463 free(target_normalized); |
|
464 if(!wtarget) { |
|
465 return 1; |
|
466 } |
|
467 |
|
468 int wlinkpathlen = 0; |
|
469 wchar_t *wlinkpath = path2winpath(linkpath, FALSE, &wlinkpathlen); |
|
470 if(!wlinkpath) { |
|
471 free(wtarget); |
|
472 return 1; |
|
473 } |
|
474 |
|
475 int ret = 1; |
|
476 |
|
477 // create COM object for using the ShellLink interface |
|
478 IShellLinkW *sl; |
|
479 HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); |
|
480 if(SUCCEEDED(hres)) { |
|
481 IPersistFile *file; |
|
482 hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (void**)&file); |
|
483 if(SUCCEEDED(hres)) { |
|
484 // try to load the shortcut |
|
485 file->lpVtbl->Load(file, wlinkpath, STGM_READ); // ignore error |
|
486 |
|
487 // set path |
|
488 hres = sl->lpVtbl->SetPath(sl, wtarget); |
|
489 if(SUCCEEDED(hres)) { |
|
490 hres = file->lpVtbl->Save(file, wlinkpath, TRUE); |
|
491 if(SUCCEEDED(hres)) { |
|
492 // successfully created/modified shortcut |
|
493 ret = 0; // ok |
|
494 } |
|
495 } |
|
496 |
|
497 file->lpVtbl->Release(file); |
|
498 } |
|
499 |
|
500 sl->lpVtbl->Release(sl); |
|
501 } |
|
502 |
|
503 free(wtarget); |
|
504 free(wlinkpath); |
|
505 |
|
506 return ret; |
305 } |
507 } |
306 |
508 |
307 #endif |
509 #endif |