1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 #include <config.h>
4
5 #include "common.h"
6
7 #ifdef WIN32
8 #ifndef _WIN32_WINNT
9 #define _WIN32_WINNT 0x500
10 #endif
11 #endif
12
13 #include "utils.h"
14
15 #ifdef WIN32
16
17 #include <windows.h>
18 #include <winsock2.h>
19 #include <ws2tcpip.h>
20 #include <Rpc.h>
21 #include <shlobj.h>
22 #include <psapi.h>
23
24 #else
25 #include <arpa/inet.h>
26 #endif
27
28 #ifndef WIN32
29 #include <pwd.h>
30 #include <uuid/uuid.h>
31 #endif
32
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <sys/stat.h>
37 #include <dirent.h>
38 #include <errno.h>
39 #include <limits.h>
40 #include <stdarg.h>
41
42 #include <string.h>
43 #include <openssl/sha.h>
44 #include <openssl/hmac.h>
45 #include <openssl/evp.h>
46 #include <openssl/bio.h>
47 #include <openssl/buffer.h>
48
49 #include <glib.h>
50 #include <glib/gstdio.h>
51 #include <searpc-utils.h>
52
53 #include <jansson.h>
54
55 #include <utime.h>
56
57 #include <zlib.h>
58
59 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
60 #include <netinet/in.h>
61 #include <stdlib.h>
62 #include <kvm.h>
63 #include <paths.h>
64 #include <sys/param.h>
65 #include <sys/sysctl.h>
66 #include <sys/user.h>
67 #endif
68
69 extern int inet_pton(int af, const char *src, void *dst);
70
71
72 struct timeval
timeval_from_msec(uint64_t milliseconds)73 timeval_from_msec (uint64_t milliseconds)
74 {
75 struct timeval ret;
76 const uint64_t microseconds = milliseconds * 1000;
77 ret.tv_sec = microseconds / 1000000;
78 ret.tv_usec = microseconds % 1000000;
79 return ret;
80 }
81
82 void
rawdata_to_hex(const unsigned char * rawdata,char * hex_str,int n_bytes)83 rawdata_to_hex (const unsigned char *rawdata, char *hex_str, int n_bytes)
84 {
85 static const char hex[] = "0123456789abcdef";
86 int i;
87
88 for (i = 0; i < n_bytes; i++) {
89 unsigned int val = *rawdata++;
90 *hex_str++ = hex[val >> 4];
91 *hex_str++ = hex[val & 0xf];
92 }
93 *hex_str = '\0';
94 }
95
hexval(char c)96 static unsigned hexval(char c)
97 {
98 if (c >= '0' && c <= '9')
99 return c - '0';
100 if (c >= 'a' && c <= 'f')
101 return c - 'a' + 10;
102 if (c >= 'A' && c <= 'F')
103 return c - 'A' + 10;
104 return ~0;
105 }
106
107 int
hex_to_rawdata(const char * hex_str,unsigned char * rawdata,int n_bytes)108 hex_to_rawdata (const char *hex_str, unsigned char *rawdata, int n_bytes)
109 {
110 int i;
111 for (i = 0; i < n_bytes; i++) {
112 unsigned int val = (hexval(hex_str[0]) << 4) | hexval(hex_str[1]);
113 if (val & ~0xff)
114 return -1;
115 *rawdata++ = val;
116 hex_str += 2;
117 }
118 return 0;
119 }
120
121 size_t
ccnet_strlcpy(char * dest,const char * src,size_t size)122 ccnet_strlcpy (char *dest, const char *src, size_t size)
123 {
124 size_t ret = strlen(src);
125
126 if (size) {
127 size_t len = (ret >= size) ? size - 1 : ret;
128 memcpy(dest, src, len);
129 dest[len] = '\0';
130 }
131 return ret;
132 }
133
134
135 int
checkdir(const char * dir)136 checkdir (const char *dir)
137 {
138 SeafStat st;
139
140 #ifdef WIN32
141 /* remove trailing '\\' */
142 char *path = g_strdup(dir);
143 char *p = (char *)path + strlen(path) - 1;
144 while (*p == '\\' || *p == '/') *p-- = '\0';
145 if ((seaf_stat(dir, &st) < 0) || !S_ISDIR(st.st_mode)) {
146 g_free (path);
147 return -1;
148 }
149 g_free (path);
150 return 0;
151 #else
152 if ((seaf_stat(dir, &st) < 0) || !S_ISDIR(st.st_mode))
153 return -1;
154 return 0;
155 #endif
156 }
157
158 int
checkdir_with_mkdir(const char * dir)159 checkdir_with_mkdir (const char *dir)
160 {
161 #ifdef WIN32
162 int ret;
163 char *path = g_strdup(dir);
164 char *p = (char *)path + strlen(path) - 1;
165 while (*p == '\\' || *p == '/') *p-- = '\0';
166 ret = g_mkdir_with_parents(path, 0755);
167 g_free (path);
168 return ret;
169 #else
170 return g_mkdir_with_parents(dir, 0755);
171 #endif
172 }
173
174 int
objstore_mkdir(const char * base)175 objstore_mkdir (const char *base)
176 {
177 int ret;
178 int i, j, len;
179 static const char hex[] = "0123456789abcdef";
180 char subdir[SEAF_PATH_MAX];
181
182 if ( (ret = checkdir_with_mkdir(base)) < 0)
183 return ret;
184
185 len = strlen(base);
186 memcpy(subdir, base, len);
187 subdir[len] = G_DIR_SEPARATOR;
188 subdir[len+3] = '\0';
189
190 for (i = 0; i < 16; i++) {
191 subdir[len+1] = hex[i];
192 for (j = 0; j < 16; j++) {
193 subdir[len+2] = hex[j];
194 if ( (ret = checkdir_with_mkdir(subdir)) < 0)
195 return ret;
196 }
197 }
198 return 0;
199 }
200
201 void
objstore_get_path(char * path,const char * base,const char * obj_id)202 objstore_get_path (char *path, const char *base, const char *obj_id)
203 {
204 int len;
205
206 len = strlen(base);
207 memcpy(path, base, len);
208 path[len] = G_DIR_SEPARATOR;
209 path[len+1] = obj_id[0];
210 path[len+2] = obj_id[1];
211 path[len+3] = G_DIR_SEPARATOR;
212 strcpy(path+len+4, obj_id+2);
213 }
214
215 #ifdef WIN32
216
217 /* UNIX epoch expressed in Windows time, the unit is 100 nanoseconds.
218 * See http://msdn.microsoft.com/en-us/library/ms724228
219 */
220 #define UNIX_EPOCH 116444736000000000ULL
221
222 __time64_t
file_time_to_unix_time(FILETIME * ftime)223 file_time_to_unix_time (FILETIME *ftime)
224 {
225 guint64 win_time, unix_time;
226
227 win_time = (guint64)ftime->dwLowDateTime + (((guint64)ftime->dwHighDateTime)<<32);
228 unix_time = (win_time - UNIX_EPOCH)/10000000;
229
230 return (__time64_t)unix_time;
231 }
232
233 static int
get_utc_file_time_fd(int fd,__time64_t * mtime,__time64_t * ctime)234 get_utc_file_time_fd (int fd, __time64_t *mtime, __time64_t *ctime)
235 {
236 HANDLE handle;
237 FILETIME write_time, create_time;
238
239 handle = (HANDLE)_get_osfhandle (fd);
240 if (handle == INVALID_HANDLE_VALUE) {
241 g_warning ("Failed to get handle from fd: %lu.\n", GetLastError());
242 return -1;
243 }
244
245 if (!GetFileTime (handle, &create_time, NULL, &write_time)) {
246 g_warning ("Failed to get file time: %lu.\n", GetLastError());
247 return -1;
248 }
249
250 *mtime = file_time_to_unix_time (&write_time);
251 *ctime = file_time_to_unix_time (&create_time);
252
253 return 0;
254 }
255
256 #define EPOCH_DIFF 11644473600ULL
257
258 inline static void
unix_time_to_file_time(guint64 unix_time,FILETIME * ftime)259 unix_time_to_file_time (guint64 unix_time, FILETIME *ftime)
260 {
261 guint64 win_time;
262
263 win_time = (unix_time + EPOCH_DIFF) * 10000000;
264 ftime->dwLowDateTime = win_time & 0xFFFFFFFF;
265 ftime->dwHighDateTime = (win_time >> 32) & 0xFFFFFFFF;
266 }
267
268 static int
set_utc_file_time(const char * path,const wchar_t * wpath,guint64 mtime)269 set_utc_file_time (const char *path, const wchar_t *wpath, guint64 mtime)
270 {
271 HANDLE handle;
272 FILETIME write_time;
273
274 handle = CreateFileW (wpath,
275 GENERIC_WRITE,
276 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
277 NULL,
278 OPEN_EXISTING,
279 FILE_FLAG_BACKUP_SEMANTICS,
280 NULL);
281 if (handle == INVALID_HANDLE_VALUE) {
282 g_warning ("Failed to open %s: %lu.\n", path, GetLastError());
283 return -1;
284 }
285
286 unix_time_to_file_time (mtime, &write_time);
287
288 if (!SetFileTime (handle, NULL, NULL, &write_time)) {
289 g_warning ("Failed to set file time for %s: %lu.\n", path, GetLastError());
290 CloseHandle (handle);
291 return -1;
292 }
293 CloseHandle (handle);
294
295 return 0;
296 }
297
298 wchar_t *
win32_long_path(const char * path)299 win32_long_path (const char *path)
300 {
301 char *long_path, *p;
302 wchar_t *long_path_w;
303
304 if (strncmp(path, "//", 2) == 0)
305 long_path = g_strconcat ("\\\\?\\UNC\\", path + 2, NULL);
306 else
307 long_path = g_strconcat ("\\\\?\\", path, NULL);
308 for (p = long_path; *p != 0; ++p)
309 if (*p == '/')
310 *p = '\\';
311
312 long_path_w = g_utf8_to_utf16 (long_path, -1, NULL, NULL, NULL);
313
314 g_free (long_path);
315 return long_path_w;
316 }
317
318 /* Convert a (possible) 8.3 format path to long path */
319 wchar_t *
win32_83_path_to_long_path(const char * worktree,const wchar_t * path,int path_len)320 win32_83_path_to_long_path (const char *worktree, const wchar_t *path, int path_len)
321 {
322 wchar_t *worktree_w = g_utf8_to_utf16 (worktree, -1, NULL, NULL, NULL);
323 int wt_len;
324 wchar_t *p;
325 wchar_t *fullpath_w = NULL;
326 wchar_t *fullpath_long = NULL;
327 wchar_t *ret = NULL;
328 char *fullpath;
329
330 for (p = worktree_w; *p != L'\0'; ++p)
331 if (*p == L'/')
332 *p = L'\\';
333
334 wt_len = wcslen(worktree_w);
335
336 fullpath_w = g_new0 (wchar_t, wt_len + path_len + 6);
337 wcscpy (fullpath_w, L"\\\\?\\");
338 wcscat (fullpath_w, worktree_w);
339 wcscat (fullpath_w, L"\\");
340 wcsncat (fullpath_w, path, path_len);
341
342 fullpath_long = g_new0 (wchar_t, SEAF_PATH_MAX);
343
344 DWORD n = GetLongPathNameW (fullpath_w, fullpath_long, SEAF_PATH_MAX);
345 if (n == 0) {
346 /* Failed. */
347 fullpath = g_utf16_to_utf8 (fullpath_w, -1, NULL, NULL, NULL);
348 g_free (fullpath);
349
350 goto out;
351 } else if (n > SEAF_PATH_MAX) {
352 /* In this case n is the necessary length for the buf. */
353 g_free (fullpath_long);
354 fullpath_long = g_new0 (wchar_t, n);
355
356 if (GetLongPathNameW (fullpath_w, fullpath_long, n) != (n - 1)) {
357 fullpath = g_utf16_to_utf8 (fullpath_w, -1, NULL, NULL, NULL);
358 g_free (fullpath);
359
360 goto out;
361 }
362 }
363
364 /* Remove "\\?\worktree\" from the beginning. */
365 ret = wcsdup (fullpath_long + wt_len + 5);
366
367 out:
368 g_free (worktree_w);
369 g_free (fullpath_w);
370 g_free (fullpath_long);
371
372 return ret;
373 }
374
375 static int
windows_error_to_errno(DWORD error)376 windows_error_to_errno (DWORD error)
377 {
378 switch (error) {
379 case ERROR_FILE_NOT_FOUND:
380 case ERROR_PATH_NOT_FOUND:
381 return ENOENT;
382 case ERROR_ALREADY_EXISTS:
383 return EEXIST;
384 case ERROR_ACCESS_DENIED:
385 case ERROR_SHARING_VIOLATION:
386 return EACCES;
387 case ERROR_DIR_NOT_EMPTY:
388 return ENOTEMPTY;
389 default:
390 return 0;
391 }
392 }
393
394 #endif
395
396 int
seaf_stat(const char * path,SeafStat * st)397 seaf_stat (const char *path, SeafStat *st)
398 {
399 #ifdef WIN32
400 wchar_t *wpath = win32_long_path (path);
401 WIN32_FILE_ATTRIBUTE_DATA attrs;
402 int ret = 0;
403
404 if (!GetFileAttributesExW (wpath, GetFileExInfoStandard, &attrs)) {
405 ret = -1;
406 errno = windows_error_to_errno (GetLastError());
407 goto out;
408 }
409
410 memset (st, 0, sizeof(SeafStat));
411
412 if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
413 st->st_mode = (S_IFDIR | S_IRWXU);
414 else
415 st->st_mode = (S_IFREG | S_IRUSR | S_IWUSR);
416
417 st->st_atime = file_time_to_unix_time (&attrs.ftLastAccessTime);
418 st->st_ctime = file_time_to_unix_time (&attrs.ftCreationTime);
419 st->st_mtime = file_time_to_unix_time (&attrs.ftLastWriteTime);
420
421 st->st_size = ((((__int64)attrs.nFileSizeHigh)<<32) + attrs.nFileSizeLow);
422
423 out:
424 g_free (wpath);
425
426 return ret;
427 #else
428 return stat (path, st);
429 #endif
430 }
431
432 int
seaf_fstat(int fd,SeafStat * st)433 seaf_fstat (int fd, SeafStat *st)
434 {
435 #ifdef WIN32
436 if (_fstat64 (fd, st) < 0)
437 return -1;
438
439 if (get_utc_file_time_fd (fd, &st->st_mtime, &st->st_ctime) < 0)
440 return -1;
441
442 return 0;
443 #else
444 return fstat (fd, st);
445 #endif
446 }
447
448 #ifdef WIN32
449
450 void
seaf_stat_from_find_data(WIN32_FIND_DATAW * fdata,SeafStat * st)451 seaf_stat_from_find_data (WIN32_FIND_DATAW *fdata, SeafStat *st)
452 {
453 memset (st, 0, sizeof(SeafStat));
454
455 if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
456 st->st_mode = (S_IFDIR | S_IRWXU);
457 else
458 st->st_mode = (S_IFREG | S_IRUSR | S_IWUSR);
459
460 st->st_atime = file_time_to_unix_time (&fdata->ftLastAccessTime);
461 st->st_ctime = file_time_to_unix_time (&fdata->ftCreationTime);
462 st->st_mtime = file_time_to_unix_time (&fdata->ftLastWriteTime);
463
464 st->st_size = ((((__int64)fdata->nFileSizeHigh)<<32) + fdata->nFileSizeLow);
465 }
466
467 #endif
468
469 int
seaf_set_file_time(const char * path,guint64 mtime)470 seaf_set_file_time (const char *path, guint64 mtime)
471 {
472 #ifndef WIN32
473 struct stat st;
474 struct utimbuf times;
475
476 if (stat (path, &st) < 0) {
477 g_warning ("Failed to stat %s: %s.\n", path, strerror(errno));
478 return -1;
479 }
480
481 times.actime = st.st_atime;
482 times.modtime = (time_t)mtime;
483
484 return utime (path, ×);
485 #else
486 wchar_t *wpath = win32_long_path (path);
487 int ret = 0;
488
489 if (set_utc_file_time (path, wpath, mtime) < 0)
490 ret = -1;
491
492 g_free (wpath);
493 return ret;
494 #endif
495 }
496
497 int
seaf_util_unlink(const char * path)498 seaf_util_unlink (const char *path)
499 {
500 #ifdef WIN32
501 wchar_t *wpath = win32_long_path (path);
502 int ret = 0;
503
504 if (!DeleteFileW (wpath)) {
505 ret = -1;
506 errno = windows_error_to_errno (GetLastError());
507 }
508
509 g_free (wpath);
510 return ret;
511 #else
512 return unlink (path);
513 #endif
514 }
515
516 int
seaf_util_rmdir(const char * path)517 seaf_util_rmdir (const char *path)
518 {
519 #ifdef WIN32
520 wchar_t *wpath = win32_long_path (path);
521 int ret = 0;
522
523 if (!RemoveDirectoryW (wpath)) {
524 ret = -1;
525 errno = windows_error_to_errno (GetLastError());
526 }
527
528 g_free (wpath);
529 return ret;
530 #else
531 return rmdir (path);
532 #endif
533 }
534
535 int
seaf_util_mkdir(const char * path,mode_t mode)536 seaf_util_mkdir (const char *path, mode_t mode)
537 {
538 #ifdef WIN32
539 wchar_t *wpath = win32_long_path (path);
540 int ret = 0;
541
542 if (!CreateDirectoryW (wpath, NULL)) {
543 ret = -1;
544 errno = windows_error_to_errno (GetLastError());
545 }
546
547 g_free (wpath);
548 return ret;
549 #else
550 return mkdir (path, mode);
551 #endif
552 }
553
554 int
seaf_util_open(const char * path,int flags)555 seaf_util_open (const char *path, int flags)
556 {
557 #ifdef WIN32
558 wchar_t *wpath;
559 DWORD access = 0;
560 HANDLE handle;
561 int fd;
562
563 access |= GENERIC_READ;
564 if (flags & (O_WRONLY | O_RDWR))
565 access |= GENERIC_WRITE;
566
567 wpath = win32_long_path (path);
568
569 handle = CreateFileW (wpath,
570 access,
571 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
572 NULL,
573 OPEN_EXISTING,
574 0,
575 NULL);
576 if (handle == INVALID_HANDLE_VALUE) {
577 errno = windows_error_to_errno (GetLastError());
578 g_free (wpath);
579 return -1;
580 }
581
582 fd = _open_osfhandle ((intptr_t)handle, 0);
583
584 g_free (wpath);
585 return fd;
586 #else
587 return open (path, flags);
588 #endif
589 }
590
591 int
seaf_util_create(const char * path,int flags,mode_t mode)592 seaf_util_create (const char *path, int flags, mode_t mode)
593 {
594 #ifdef WIN32
595 wchar_t *wpath;
596 DWORD access = 0;
597 HANDLE handle;
598 int fd;
599
600 access |= GENERIC_READ;
601 if (flags & (O_WRONLY | O_RDWR))
602 access |= GENERIC_WRITE;
603
604 wpath = win32_long_path (path);
605
606 handle = CreateFileW (wpath,
607 access,
608 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
609 NULL,
610 CREATE_ALWAYS,
611 0,
612 NULL);
613 if (handle == INVALID_HANDLE_VALUE) {
614 errno = windows_error_to_errno (GetLastError());
615 g_free (wpath);
616 return -1;
617 }
618
619 fd = _open_osfhandle ((intptr_t)handle, 0);
620
621 g_free (wpath);
622 return fd;
623 #else
624 return open (path, flags, mode);
625 #endif
626 }
627
628 int
seaf_util_rename(const char * oldpath,const char * newpath)629 seaf_util_rename (const char *oldpath, const char *newpath)
630 {
631 #ifdef WIN32
632 wchar_t *oldpathw = win32_long_path (oldpath);
633 wchar_t *newpathw = win32_long_path (newpath);
634 int ret = 0;
635
636 if (!MoveFileExW (oldpathw, newpathw, MOVEFILE_REPLACE_EXISTING)) {
637 ret = -1;
638 errno = windows_error_to_errno (GetLastError());
639 }
640
641 g_free (oldpathw);
642 g_free (newpathw);
643 return ret;
644 #else
645 return rename (oldpath, newpath);
646 #endif
647 }
648
649 gboolean
seaf_util_exists(const char * path)650 seaf_util_exists (const char *path)
651 {
652 #ifdef WIN32
653 wchar_t *wpath = win32_long_path (path);
654 DWORD attrs;
655 gboolean ret;
656
657 attrs = GetFileAttributesW (wpath);
658 ret = (attrs != INVALID_FILE_ATTRIBUTES);
659
660 g_free (wpath);
661 return ret;
662 #else
663 return (access (path, F_OK) == 0);
664 #endif
665 }
666
667 gint64
seaf_util_lseek(int fd,gint64 offset,int whence)668 seaf_util_lseek (int fd, gint64 offset, int whence)
669 {
670 #ifdef WIN32
671 return _lseeki64 (fd, offset, whence);
672 #else
673 return lseek (fd, offset, whence);
674 #endif
675 }
676
677 #ifdef WIN32
678
679 int
traverse_directory_win32(wchar_t * path_w,DirentCallback callback,void * user_data)680 traverse_directory_win32 (wchar_t *path_w,
681 DirentCallback callback,
682 void *user_data)
683 {
684 WIN32_FIND_DATAW fdata;
685 HANDLE handle;
686 wchar_t *pattern;
687 char *path;
688 int path_len_w;
689 DWORD error;
690 gboolean stop;
691 int ret = 0;
692
693 path = g_utf16_to_utf8 (path_w, -1, NULL, NULL, NULL);
694
695 path_len_w = wcslen(path_w);
696
697 pattern = g_new0 (wchar_t, (path_len_w + 3));
698 wcscpy (pattern, path_w);
699 wcscat (pattern, L"\\*");
700
701 handle = FindFirstFileW (pattern, &fdata);
702 if (handle == INVALID_HANDLE_VALUE) {
703 g_warning ("FindFirstFile failed %s: %lu.\n",
704 path, GetLastError());
705 ret = -1;
706 goto out;
707 }
708
709 do {
710 if (wcscmp (fdata.cFileName, L".") == 0 ||
711 wcscmp (fdata.cFileName, L"..") == 0)
712 continue;
713
714 ++ret;
715
716 stop = FALSE;
717 if (callback (path_w, &fdata, user_data, &stop) < 0) {
718 ret = -1;
719 FindClose (handle);
720 goto out;
721 }
722 if (stop) {
723 FindClose (handle);
724 goto out;
725 }
726 } while (FindNextFileW (handle, &fdata) != 0);
727
728 error = GetLastError();
729 if (error != ERROR_NO_MORE_FILES) {
730 g_warning ("FindNextFile failed %s: %lu.\n",
731 path, error);
732 ret = -1;
733 }
734
735 FindClose (handle);
736
737 out:
738 g_free (path);
739 g_free (pattern);
740 return ret;
741 }
742
743 #endif
744
745 ssize_t
readn(int fd,void * buf,size_t n)746 readn (int fd, void *buf, size_t n)
747 {
748 size_t n_left;
749 ssize_t n_read;
750 char *ptr;
751
752 ptr = buf;
753 n_left = n;
754 while (n_left > 0) {
755 n_read = read(fd, ptr, n_left);
756 if (n_read < 0) {
757 if (errno == EINTR)
758 n_read = 0;
759 else
760 return -1;
761 } else if (n_read == 0)
762 break;
763
764 n_left -= n_read;
765 ptr += n_read;
766 }
767 return (n - n_left);
768 }
769
770 ssize_t
writen(int fd,const void * buf,size_t n)771 writen (int fd, const void *buf, size_t n)
772 {
773 size_t n_left;
774 ssize_t n_written;
775 const char *ptr;
776
777 ptr = buf;
778 n_left = n;
779 while (n_left > 0) {
780 n_written = write(fd, ptr, n_left);
781 if (n_written <= 0) {
782 if (n_written < 0 && errno == EINTR)
783 n_written = 0;
784 else
785 return -1;
786 }
787
788 n_left -= n_written;
789 ptr += n_written;
790 }
791 return n;
792 }
793
794
795 ssize_t
recvn(evutil_socket_t fd,void * buf,size_t n)796 recvn (evutil_socket_t fd, void *buf, size_t n)
797 {
798 size_t n_left;
799 ssize_t n_read;
800 char *ptr;
801
802 ptr = buf;
803 n_left = n;
804 while (n_left > 0) {
805 #ifndef WIN32
806 if ((n_read = read(fd, ptr, n_left)) < 0)
807 #else
808 if ((n_read = recv(fd, ptr, n_left, 0)) < 0)
809 #endif
810 {
811 if (errno == EINTR)
812 n_read = 0;
813 else
814 return -1;
815 } else if (n_read == 0)
816 break;
817
818 n_left -= n_read;
819 ptr += n_read;
820 }
821 return (n - n_left);
822 }
823
824 ssize_t
sendn(evutil_socket_t fd,const void * buf,size_t n)825 sendn (evutil_socket_t fd, const void *buf, size_t n)
826 {
827 size_t n_left;
828 ssize_t n_written;
829 const char *ptr;
830
831 ptr = buf;
832 n_left = n;
833 while (n_left > 0) {
834 #ifndef WIN32
835 if ( (n_written = write(fd, ptr, n_left)) <= 0)
836 #else
837 if ( (n_written = send(fd, ptr, n_left, 0)) <= 0)
838 #endif
839 {
840 if (n_written < 0 && errno == EINTR)
841 n_written = 0;
842 else
843 return -1;
844 }
845
846 n_left -= n_written;
847 ptr += n_written;
848 }
849 return n;
850 }
851
copy_fd(int ifd,int ofd)852 int copy_fd (int ifd, int ofd)
853 {
854 while (1) {
855 char buffer[8192];
856 ssize_t len = readn (ifd, buffer, sizeof(buffer));
857 if (!len)
858 break;
859 if (len < 0) {
860 close (ifd);
861 return -1;
862 }
863 if (writen (ofd, buffer, len) < 0) {
864 close (ofd);
865 return -1;
866 }
867 }
868 close(ifd);
869 return 0;
870 }
871
copy_file(const char * dst,const char * src,int mode)872 int copy_file (const char *dst, const char *src, int mode)
873 {
874 int fdi, fdo, status;
875
876 if ((fdi = g_open (src, O_RDONLY | O_BINARY, 0)) < 0)
877 return fdi;
878
879 fdo = g_open (dst, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, mode);
880 if (fdo < 0 && errno == EEXIST) {
881 close (fdi);
882 return 0;
883 } else if (fdo < 0){
884 close (fdi);
885 return -1;
886 }
887
888 status = copy_fd (fdi, fdo);
889 if (close (fdo) != 0)
890 return -1;
891
892 return status;
893 }
894
895 char*
ccnet_expand_path(const char * src)896 ccnet_expand_path (const char *src)
897 {
898 #ifdef WIN32
899 char new_path[SEAF_PATH_MAX + 1];
900 char *p = new_path;
901 const char *q = src;
902
903 memset(new_path, 0, sizeof(new_path));
904 if (*src == '~') {
905 const char *home = g_get_home_dir();
906 memcpy(new_path, home, strlen(home));
907 p += strlen(new_path);
908 q++;
909 }
910 memcpy(p, q, strlen(q));
911
912 /* delete the charactor '\' or '/' at the end of the path
913 * because the function stat faied to deal with directory names
914 * with '\' or '/' in the end */
915 p = new_path + strlen(new_path) - 1;
916 while(*p == '\\' || *p == '/') *p-- = '\0';
917
918 return strdup (new_path);
919 #else
920 const char *next_in, *ntoken;
921 char new_path[SEAF_PATH_MAX + 1];
922 char *next_out;
923 int len;
924
925 /* special cases */
926 if (!src || *src == '\0')
927 return NULL;
928 if (strlen(src) > SEAF_PATH_MAX)
929 return NULL;
930
931 next_in = src;
932 next_out = new_path;
933 *next_out = '\0';
934
935 if (*src == '~') {
936 /* handle src start with '~' or '~<user>' like '~plt' */
937 struct passwd *pw = NULL;
938
939 for ( ; *next_in != '/' && *next_in != '\0'; next_in++) ;
940
941 len = next_in - src;
942 if (len == 1) {
943 pw = getpwuid (geteuid());
944 } else {
945 /* copy '~<user>' to new_path */
946 memcpy (new_path, src, len);
947 new_path[len] = '\0';
948 pw = getpwnam (new_path + 1);
949 }
950 if (pw == NULL)
951 return NULL;
952
953 len = strlen (pw->pw_dir);
954 memcpy (new_path, pw->pw_dir, len);
955 next_out = new_path + len;
956 *next_out = '\0';
957
958 if (*next_in == '\0')
959 return strdup (new_path);
960 } else if (*src != '/') {
961 getcwd (new_path, SEAF_PATH_MAX);
962 for ( ; *next_out; next_out++) ; /* to '\0' */
963 }
964
965 while (*next_in != '\0') {
966 /* move ntoken to the next not '/' char */
967 for (ntoken = next_in; *ntoken == '/'; ntoken++) ;
968
969 for (next_in = ntoken; *next_in != '/'
970 && *next_in != '\0'; next_in++) ;
971
972 len = next_in - ntoken;
973
974 if (len == 0) {
975 /* the path ends with '/', keep it */
976 *next_out++ = '/';
977 *next_out = '\0';
978 break;
979 }
980
981 if (len == 2 && ntoken[0] == '.' && ntoken[1] == '.')
982 {
983 /* '..' */
984 for (; next_out > new_path && *next_out != '/'; next_out--)
985 ;
986 *next_out = '\0';
987 } else if (ntoken[0] != '.' || len != 1) {
988 /* not '.' */
989 *next_out++ = '/';
990 memcpy (next_out, ntoken, len);
991 next_out += len;
992 *next_out = '\0';
993 }
994 }
995
996 /* the final special case */
997 if (new_path[0] == '\0') {
998 new_path[0] = '/';
999 new_path[1] = '\0';
1000 }
1001 return strdup (new_path);
1002 #endif
1003 }
1004
1005
1006 int
calculate_sha1(unsigned char * sha1,const char * msg,int len)1007 calculate_sha1 (unsigned char *sha1, const char *msg, int len)
1008 {
1009 SHA_CTX c;
1010
1011 if (len < 0)
1012 len = strlen(msg);
1013
1014 SHA1_Init(&c);
1015 SHA1_Update(&c, msg, len);
1016 SHA1_Final(sha1, &c);
1017 return 0;
1018 }
1019
1020 uint32_t
ccnet_sha1_hash(const void * v)1021 ccnet_sha1_hash (const void *v)
1022 {
1023 /* 31 bit hash function */
1024 const unsigned char *p = v;
1025 uint32_t h = 0;
1026 int i;
1027
1028 for (i = 0; i < 20; i++)
1029 h = (h << 5) - h + p[i];
1030
1031 return h;
1032 }
1033
1034 int
ccnet_sha1_equal(const void * v1,const void * v2)1035 ccnet_sha1_equal (const void *v1,
1036 const void *v2)
1037 {
1038 const unsigned char *p1 = v1;
1039 const unsigned char *p2 = v2;
1040 int i;
1041
1042 for (i = 0; i < 20; i++)
1043 if (p1[i] != p2[i])
1044 return 0;
1045
1046 return 1;
1047 }
1048
1049 #ifndef WIN32
gen_uuid()1050 char* gen_uuid ()
1051 {
1052 char *uuid_str = g_malloc (37);
1053 uuid_t uuid;
1054
1055 uuid_generate (uuid);
1056 uuid_unparse_lower (uuid, uuid_str);
1057
1058 return uuid_str;
1059 }
1060
gen_uuid_inplace(char * buf)1061 void gen_uuid_inplace (char *buf)
1062 {
1063 uuid_t uuid;
1064
1065 uuid_generate (uuid);
1066 uuid_unparse_lower (uuid, buf);
1067 }
1068
1069 gboolean
is_uuid_valid(const char * uuid_str)1070 is_uuid_valid (const char *uuid_str)
1071 {
1072 uuid_t uuid;
1073
1074 if (!uuid_str)
1075 return FALSE;
1076
1077 if (uuid_parse (uuid_str, uuid) < 0)
1078 return FALSE;
1079 return TRUE;
1080 }
1081
1082 #else
gen_uuid()1083 char* gen_uuid ()
1084 {
1085 char *uuid_str = g_malloc (37);
1086 unsigned char *str = NULL;
1087 UUID uuid;
1088
1089 UuidCreate(&uuid);
1090 UuidToString(&uuid, &str);
1091 memcpy(uuid_str, str, 37);
1092 RpcStringFree(&str);
1093 return uuid_str;
1094 }
1095
gen_uuid_inplace(char * buf)1096 void gen_uuid_inplace (char *buf)
1097 {
1098 unsigned char *str = NULL;
1099 UUID uuid;
1100
1101 UuidCreate(&uuid);
1102 UuidToString(&uuid, &str);
1103 memcpy(buf, str, 37);
1104 RpcStringFree(&str);
1105 }
1106
1107 gboolean
is_uuid_valid(const char * uuid_str)1108 is_uuid_valid (const char *uuid_str)
1109 {
1110 if (!uuid_str)
1111 return FALSE;
1112
1113 UUID uuid;
1114 if (UuidFromString((unsigned char *)uuid_str, &uuid) != RPC_S_OK)
1115 return FALSE;
1116 return TRUE;
1117 }
1118
1119 #endif
1120
1121 gboolean
is_object_id_valid(const char * obj_id)1122 is_object_id_valid (const char *obj_id)
1123 {
1124 if (!obj_id)
1125 return FALSE;
1126
1127 int len = strlen(obj_id);
1128 int i;
1129 char c;
1130
1131 if (len != 40)
1132 return FALSE;
1133
1134 for (i = 0; i < len; ++i) {
1135 c = obj_id[i];
1136 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
1137 continue;
1138 return FALSE;
1139 }
1140
1141 return TRUE;
1142 }
1143
strjoin_n(const char * seperator,int argc,char ** argv)1144 char* strjoin_n (const char *seperator, int argc, char **argv)
1145 {
1146 GString *buf;
1147 int i;
1148 char *str;
1149
1150 if (argc == 0)
1151 return NULL;
1152
1153 buf = g_string_new (argv[0]);
1154 for (i = 1; i < argc; ++i) {
1155 g_string_append (buf, seperator);
1156 g_string_append (buf, argv[i]);
1157 }
1158
1159 str = buf->str;
1160 g_string_free (buf, FALSE);
1161 return str;
1162 }
1163
1164
is_ipaddr_valid(const char * ip)1165 gboolean is_ipaddr_valid (const char *ip)
1166 {
1167 unsigned char buf[sizeof(struct in6_addr)];
1168
1169 if (evutil_inet_pton(AF_INET, ip, buf) == 1)
1170 return TRUE;
1171
1172 if (evutil_inet_pton(AF_INET6, ip, buf) == 1)
1173 return TRUE;
1174
1175 return FALSE;
1176 }
1177
parse_key_value_pairs(char * string,KeyValueFunc func,void * data)1178 void parse_key_value_pairs (char *string, KeyValueFunc func, void *data)
1179 {
1180 char *line = string, *next, *space;
1181 char *key, *value;
1182
1183 while (*line) {
1184 /* handle empty line */
1185 if (*line == '\n') {
1186 ++line;
1187 continue;
1188 }
1189
1190 for (next = line; *next != '\n' && *next; ++next) ;
1191 *next = '\0';
1192
1193 for (space = line; space < next && *space != ' '; ++space) ;
1194 if (*space != ' ') {
1195 g_warning ("Bad key value format: %s\n", line);
1196 return;
1197 }
1198 *space = '\0';
1199 key = line;
1200 value = space + 1;
1201
1202 func (data, key, value);
1203
1204 line = next + 1;
1205 }
1206 }
1207
parse_key_value_pairs2(char * string,KeyValueFunc2 func,void * data)1208 void parse_key_value_pairs2 (char *string, KeyValueFunc2 func, void *data)
1209 {
1210 char *line = string, *next, *space;
1211 char *key, *value;
1212
1213 while (*line) {
1214 /* handle empty line */
1215 if (*line == '\n') {
1216 ++line;
1217 continue;
1218 }
1219
1220 for (next = line; *next != '\n' && *next; ++next) ;
1221 *next = '\0';
1222
1223 for (space = line; space < next && *space != ' '; ++space) ;
1224 if (*space != ' ') {
1225 g_warning ("Bad key value format: %s\n", line);
1226 return;
1227 }
1228 *space = '\0';
1229 key = line;
1230 value = space + 1;
1231
1232 if (func(data, key, value) == FALSE)
1233 break;
1234
1235 line = next + 1;
1236 }
1237 }
1238
1239 /**
1240 * string_list_is_exists:
1241 * @str_list:
1242 * @string: a C string or %NULL
1243 *
1244 * Check whether @string is in @str_list.
1245 *
1246 * returns: %TRUE if @string is in str_list, %FALSE otherwise
1247 */
1248 gboolean
string_list_is_exists(GList * str_list,const char * string)1249 string_list_is_exists (GList *str_list, const char *string)
1250 {
1251 GList *ptr;
1252 for (ptr = str_list; ptr; ptr = ptr->next) {
1253 if (g_strcmp0(string, ptr->data) == 0)
1254 return TRUE;
1255 }
1256 return FALSE;
1257 }
1258
1259 /**
1260 * string_list_append:
1261 * @str_list:
1262 * @string: a C string (can't be %NULL
1263 *
1264 * Append @string to @str_list if it is in the list.
1265 *
1266 * returns: the new start of the list
1267 */
1268 GList*
string_list_append(GList * str_list,const char * string)1269 string_list_append (GList *str_list, const char *string)
1270 {
1271 g_return_val_if_fail (string != NULL, str_list);
1272
1273 if (string_list_is_exists(str_list, string))
1274 return str_list;
1275
1276 str_list = g_list_append (str_list, g_strdup(string));
1277 return str_list;
1278 }
1279
1280 GList *
string_list_append_sorted(GList * str_list,const char * string)1281 string_list_append_sorted (GList *str_list, const char *string)
1282 {
1283 g_return_val_if_fail (string != NULL, str_list);
1284
1285 if (string_list_is_exists(str_list, string))
1286 return str_list;
1287
1288 str_list = g_list_insert_sorted_with_data (str_list, g_strdup(string),
1289 (GCompareDataFunc)g_strcmp0, NULL);
1290 return str_list;
1291 }
1292
1293
1294 GList *
string_list_remove(GList * str_list,const char * string)1295 string_list_remove (GList *str_list, const char *string)
1296 {
1297 g_return_val_if_fail (string != NULL, str_list);
1298
1299 GList *ptr;
1300
1301 for (ptr = str_list; ptr; ptr = ptr->next) {
1302 if (strcmp((char *)ptr->data, string) == 0) {
1303 g_free (ptr->data);
1304 return g_list_delete_link (str_list, ptr);
1305 }
1306 }
1307 return str_list;
1308 }
1309
1310
1311 void
string_list_free(GList * str_list)1312 string_list_free (GList *str_list)
1313 {
1314 GList *ptr = str_list;
1315
1316 while (ptr) {
1317 g_free (ptr->data);
1318 ptr = ptr->next;
1319 }
1320
1321 g_list_free (str_list);
1322 }
1323
1324
1325 void
string_list_join(GList * str_list,GString * str,const char * seperator)1326 string_list_join (GList *str_list, GString *str, const char *seperator)
1327 {
1328 GList *ptr;
1329 if (!str_list)
1330 return;
1331
1332 ptr = str_list;
1333 g_string_append (str, ptr->data);
1334
1335 for (ptr = ptr->next; ptr; ptr = ptr->next) {
1336 g_string_append (str, seperator);
1337 g_string_append (str, (char *)ptr->data);
1338 }
1339 }
1340
1341 GList *
string_list_parse(const char * list_in_str,const char * seperator)1342 string_list_parse (const char *list_in_str, const char *seperator)
1343 {
1344 if (!list_in_str)
1345 return NULL;
1346
1347 GList *list = NULL;
1348 char **array = g_strsplit (list_in_str, seperator, 0);
1349 char **ptr;
1350
1351 for (ptr = array; *ptr; ptr++) {
1352 list = g_list_prepend (list, g_strdup(*ptr));
1353 }
1354 list = g_list_reverse (list);
1355
1356 g_strfreev (array);
1357 return list;
1358 }
1359
1360 GList *
string_list_parse_sorted(const char * list_in_str,const char * seperator)1361 string_list_parse_sorted (const char *list_in_str, const char *seperator)
1362 {
1363 GList *list = string_list_parse (list_in_str, seperator);
1364
1365 return g_list_sort (list, (GCompareFunc)g_strcmp0);
1366 }
1367
1368 gboolean
string_list_sorted_is_equal(GList * list1,GList * list2)1369 string_list_sorted_is_equal (GList *list1, GList *list2)
1370 {
1371 GList *ptr1 = list1, *ptr2 = list2;
1372
1373 while (ptr1 && ptr2) {
1374 if (g_strcmp0(ptr1->data, ptr2->data) != 0)
1375 break;
1376
1377 ptr1 = ptr1->next;
1378 ptr2 = ptr2->next;
1379 }
1380
1381 if (!ptr1 && !ptr2)
1382 return TRUE;
1383 return FALSE;
1384 }
1385
1386 char **
ncopy_string_array(char ** orig,int n)1387 ncopy_string_array (char **orig, int n)
1388 {
1389 char **ret = g_malloc (sizeof(char *) * n);
1390 int i = 0;
1391
1392 for (; i < n; i++)
1393 ret[i] = g_strdup(orig[i]);
1394 return ret;
1395 }
1396
1397 void
nfree_string_array(char ** array,int n)1398 nfree_string_array (char **array, int n)
1399 {
1400 int i = 0;
1401
1402 for (; i < n; i++)
1403 g_free (array[i]);
1404 g_free (array);
1405 }
1406
1407 gint64
get_current_time()1408 get_current_time()
1409 {
1410 return g_get_real_time();
1411 }
1412
1413 #ifdef WIN32
1414 static SOCKET pg_serv_sock = INVALID_SOCKET;
1415 static struct sockaddr_in pg_serv_addr;
1416
1417 /* pgpipe() should only be called in the main loop,
1418 * since it accesses the static global socket.
1419 */
1420 int
pgpipe(ccnet_pipe_t handles[2])1421 pgpipe (ccnet_pipe_t handles[2])
1422 {
1423 int len = sizeof( pg_serv_addr );
1424
1425 handles[0] = handles[1] = INVALID_SOCKET;
1426
1427 if (pg_serv_sock == INVALID_SOCKET) {
1428 if ((pg_serv_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
1429 g_warning("pgpipe failed to create socket: %d\n", WSAGetLastError());
1430 return -1;
1431 }
1432
1433 memset(&pg_serv_addr, 0, sizeof(pg_serv_addr));
1434 pg_serv_addr.sin_family = AF_INET;
1435 pg_serv_addr.sin_port = htons(0);
1436 pg_serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1437
1438 if (bind(pg_serv_sock, (SOCKADDR *)&pg_serv_addr, len) == SOCKET_ERROR) {
1439 g_warning("pgpipe failed to bind: %d\n", WSAGetLastError());
1440 closesocket(pg_serv_sock);
1441 pg_serv_sock = INVALID_SOCKET;
1442 return -1;
1443 }
1444
1445 if (listen(pg_serv_sock, SOMAXCONN) == SOCKET_ERROR) {
1446 g_warning("pgpipe failed to listen: %d\n", WSAGetLastError());
1447 closesocket(pg_serv_sock);
1448 pg_serv_sock = INVALID_SOCKET;
1449 return -1;
1450 }
1451
1452 struct sockaddr_in tmp_addr;
1453 int tmp_len = sizeof(tmp_addr);
1454 if (getsockname(pg_serv_sock, (SOCKADDR *)&tmp_addr, &tmp_len) == SOCKET_ERROR) {
1455 g_warning("pgpipe failed to getsockname: %d\n", WSAGetLastError());
1456 closesocket(pg_serv_sock);
1457 pg_serv_sock = INVALID_SOCKET;
1458 return -1;
1459 }
1460 pg_serv_addr.sin_port = tmp_addr.sin_port;
1461 }
1462
1463 if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
1464 {
1465 g_warning("pgpipe failed to create socket 2: %d\n", WSAGetLastError());
1466 closesocket(pg_serv_sock);
1467 pg_serv_sock = INVALID_SOCKET;
1468 return -1;
1469 }
1470
1471 if (connect(handles[1], (SOCKADDR *)&pg_serv_addr, len) == SOCKET_ERROR)
1472 {
1473 g_warning("pgpipe failed to connect socket: %d\n", WSAGetLastError());
1474 closesocket(handles[1]);
1475 handles[1] = INVALID_SOCKET;
1476 closesocket(pg_serv_sock);
1477 pg_serv_sock = INVALID_SOCKET;
1478 return -1;
1479 }
1480
1481 struct sockaddr_in client_addr;
1482 int client_len = sizeof(client_addr);
1483 if ((handles[0] = accept(pg_serv_sock, (SOCKADDR *)&client_addr, &client_len)) == INVALID_SOCKET)
1484 {
1485 g_warning("pgpipe failed to accept socket: %d\n", WSAGetLastError());
1486 closesocket(handles[1]);
1487 handles[1] = INVALID_SOCKET;
1488 closesocket(pg_serv_sock);
1489 pg_serv_sock = INVALID_SOCKET;
1490 return -1;
1491 }
1492
1493 return 0;
1494 }
1495 #endif
1496
1497 /*
1498 The EVP_EncryptXXX and EVP_DecryptXXX series of functions have a
1499 weird choice of returned value.
1500 */
1501 #define ENC_SUCCESS 1
1502 #define ENC_FAILURE 0
1503 #define DEC_SUCCESS 1
1504 #define DEC_FAILURE 0
1505
1506
1507 #include <openssl/aes.h>
1508 #include <openssl/evp.h>
1509
1510 /* Block size, in bytes. For AES it can only be 16 bytes. */
1511 #define BLK_SIZE 16
1512 #define ENCRYPT_BLK_SIZE BLK_SIZE
1513
1514
1515 int
ccnet_encrypt(char ** data_out,int * out_len,const char * data_in,const int in_len,const char * code,const int code_len)1516 ccnet_encrypt (char **data_out,
1517 int *out_len,
1518 const char *data_in,
1519 const int in_len,
1520 const char *code,
1521 const int code_len)
1522 {
1523 *data_out = NULL;
1524 *out_len = -1;
1525
1526 /* check validation */
1527 if ( data_in == NULL || in_len <= 0 ||
1528 code == NULL || code_len <= 0) {
1529
1530 g_warning ("Invalid params.\n");
1531 return -1;
1532 }
1533
1534 EVP_CIPHER_CTX *ctx;
1535 int ret, key_len;
1536 unsigned char key[16], iv[16];
1537 int blks;
1538
1539
1540 /* Generate the derived key. We use AES 128 bits key,
1541 Electroic-Code-Book cipher mode, and SHA1 as the message digest
1542 when generating the key. IV is not used in ecb mode,
1543 actually. */
1544 key_len = EVP_BytesToKey (EVP_aes_128_ecb(), /* cipher mode */
1545 EVP_sha1(), /* message digest */
1546 NULL, /* salt */
1547 (unsigned char*)code, /* passwd */
1548 code_len,
1549 3, /* iteration times */
1550 key, /* the derived key */
1551 iv); /* IV, initial vector */
1552
1553 /* The key should be 16 bytes long for our 128 bit key. */
1554 if (key_len != 16) {
1555 g_warning ("failed to init EVP_CIPHER_CTX.\n");
1556 return -1;
1557 }
1558
1559 /* Prepare CTX for encryption. */
1560 ctx = EVP_CIPHER_CTX_new ();
1561
1562 ret = EVP_EncryptInit_ex (ctx,
1563 EVP_aes_128_ecb(), /* cipher mode */
1564 NULL, /* engine, NULL for default */
1565 key, /* derived key */
1566 iv); /* initial vector */
1567
1568 if (ret == ENC_FAILURE){
1569 EVP_CIPHER_CTX_free (ctx);
1570 return -1;
1571 }
1572 /* Allocating output buffer. */
1573
1574 /*
1575 For EVP symmetric encryption, padding is always used __even if__
1576 data size is a multiple of block size, in which case the padding
1577 length is the block size. so we have the following:
1578 */
1579
1580 blks = (in_len / BLK_SIZE) + 1;
1581
1582 *data_out = (char *)g_malloc (blks * BLK_SIZE);
1583
1584 if (*data_out == NULL) {
1585 g_warning ("failed to allocate the output buffer.\n");
1586 goto enc_error;
1587 }
1588
1589 int update_len, final_len;
1590
1591 /* Do the encryption. */
1592 ret = EVP_EncryptUpdate (ctx,
1593 (unsigned char*)*data_out,
1594 &update_len,
1595 (unsigned char*)data_in,
1596 in_len);
1597
1598 if (ret == ENC_FAILURE)
1599 goto enc_error;
1600
1601 /* Finish the possible partial block. */
1602 ret = EVP_EncryptFinal_ex (ctx,
1603 (unsigned char*)*data_out + update_len,
1604 &final_len);
1605
1606 *out_len = update_len + final_len;
1607
1608 /* out_len should be equal to the allocated buffer size. */
1609 if (ret == ENC_FAILURE || *out_len != (blks * BLK_SIZE))
1610 goto enc_error;
1611
1612 EVP_CIPHER_CTX_free (ctx);
1613
1614 return 0;
1615
1616 enc_error:
1617
1618 EVP_CIPHER_CTX_free (ctx);
1619
1620 *out_len = -1;
1621
1622 if (*data_out != NULL)
1623 g_free (*data_out);
1624
1625 *data_out = NULL;
1626
1627 return -1;
1628 }
1629
1630 int
ccnet_decrypt(char ** data_out,int * out_len,const char * data_in,const int in_len,const char * code,const int code_len)1631 ccnet_decrypt (char **data_out,
1632 int *out_len,
1633 const char *data_in,
1634 const int in_len,
1635 const char *code,
1636 const int code_len)
1637 {
1638 *data_out = NULL;
1639 *out_len = -1;
1640
1641 /* Check validation. Because padding is always used, in_len must
1642 * be a multiple of BLK_SIZE */
1643 if ( data_in == NULL || in_len <= 0 || in_len % BLK_SIZE != 0 ||
1644 code == NULL || code_len <= 0) {
1645
1646 g_warning ("Invalid param(s).\n");
1647 return -1;
1648 }
1649
1650 EVP_CIPHER_CTX *ctx;
1651 int ret, key_len;
1652 unsigned char key[16], iv[16];
1653
1654
1655 /* Generate the derived key. We use AES 128 bits key,
1656 Electroic-Code-Book cipher mode, and SHA1 as the message digest
1657 when generating the key. IV is not used in ecb mode,
1658 actually. */
1659 key_len = EVP_BytesToKey (EVP_aes_128_ecb(), /* cipher mode */
1660 EVP_sha1(), /* message digest */
1661 NULL, /* salt */
1662 (unsigned char*)code, /* passwd */
1663 code_len,
1664 3, /* iteration times */
1665 key, /* the derived key */
1666 iv); /* IV, initial vector */
1667
1668 /* The key should be 16 bytes long for our 128 bit key. */
1669 if (key_len != 16) {
1670 g_warning ("failed to init EVP_CIPHER_CTX.\n");
1671 return -1;
1672 }
1673
1674
1675 /* Prepare CTX for decryption. */
1676 ctx = EVP_CIPHER_CTX_new ();
1677
1678 ret = EVP_DecryptInit_ex (ctx,
1679 EVP_aes_128_ecb(), /* cipher mode */
1680 NULL, /* engine, NULL for default */
1681 key, /* derived key */
1682 iv); /* initial vector */
1683
1684 if (ret == DEC_FAILURE)
1685 return -1;
1686
1687 /* Allocating output buffer. */
1688
1689 *data_out = (char *)g_malloc (in_len);
1690
1691 if (*data_out == NULL) {
1692 g_warning ("failed to allocate the output buffer.\n");
1693 goto dec_error;
1694 }
1695
1696 int update_len, final_len;
1697
1698 /* Do the decryption. */
1699 ret = EVP_DecryptUpdate (ctx,
1700 (unsigned char*)*data_out,
1701 &update_len,
1702 (unsigned char*)data_in,
1703 in_len);
1704
1705 if (ret == DEC_FAILURE)
1706 goto dec_error;
1707
1708
1709 /* Finish the possible partial block. */
1710 ret = EVP_DecryptFinal_ex (ctx,
1711 (unsigned char*)*data_out + update_len,
1712 &final_len);
1713
1714 *out_len = update_len + final_len;
1715
1716 /* out_len should be smaller than in_len. */
1717 if (ret == DEC_FAILURE || *out_len > in_len)
1718 goto dec_error;
1719
1720 EVP_CIPHER_CTX_free (ctx);
1721
1722 return 0;
1723
1724 dec_error:
1725
1726 EVP_CIPHER_CTX_free (ctx);
1727
1728 *out_len = -1;
1729 if (*data_out != NULL)
1730 g_free (*data_out);
1731
1732 *data_out = NULL;
1733
1734 return -1;
1735
1736 }
1737
1738 /* convert locale specific input to utf8 encoded string */
ccnet_locale_to_utf8(const gchar * src)1739 char *ccnet_locale_to_utf8 (const gchar *src)
1740 {
1741 if (!src)
1742 return NULL;
1743
1744 gsize bytes_read = 0;
1745 gsize bytes_written = 0;
1746 GError *error = NULL;
1747 gchar *dst = NULL;
1748
1749 dst = g_locale_to_utf8
1750 (src, /* locale specific string */
1751 strlen(src), /* len of src */
1752 &bytes_read, /* length processed */
1753 &bytes_written, /* output length */
1754 &error);
1755
1756 if (error) {
1757 return NULL;
1758 }
1759
1760 return dst;
1761 }
1762
1763 /* convert utf8 input to locale specific string */
ccnet_locale_from_utf8(const gchar * src)1764 char *ccnet_locale_from_utf8 (const gchar *src)
1765 {
1766 if (!src)
1767 return NULL;
1768
1769 gsize bytes_read = 0;
1770 gsize bytes_written = 0;
1771 GError *error = NULL;
1772 gchar *dst = NULL;
1773
1774 dst = g_locale_from_utf8
1775 (src, /* locale specific string */
1776 strlen(src), /* len of src */
1777 &bytes_read, /* length processed */
1778 &bytes_written, /* output length */
1779 &error);
1780
1781 if (error) {
1782 return NULL;
1783 }
1784
1785 return dst;
1786 }
1787
1788 #ifdef WIN32
1789
1790 static HANDLE
get_process_handle(const char * process_name_in)1791 get_process_handle (const char *process_name_in)
1792 {
1793 char name[256];
1794 if (strstr(process_name_in, ".exe")) {
1795 snprintf (name, sizeof(name), "%s", process_name_in);
1796 } else {
1797 snprintf (name, sizeof(name), "%s.exe", process_name_in);
1798 }
1799
1800 DWORD aProcesses[1024], cbNeeded, cProcesses;
1801
1802 if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
1803 return NULL;
1804
1805 /* Calculate how many process identifiers were returned. */
1806 cProcesses = cbNeeded / sizeof(DWORD);
1807
1808 HANDLE hProcess;
1809 HMODULE hMod;
1810 char process_name[SEAF_PATH_MAX];
1811 unsigned int i;
1812
1813 for (i = 0; i < cProcesses; i++) {
1814 if(aProcesses[i] == 0)
1815 continue;
1816 hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, aProcesses[i]);
1817 if (!hProcess)
1818 continue;
1819
1820 if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
1821 GetModuleBaseName(hProcess, hMod, process_name,
1822 sizeof(process_name)/sizeof(char));
1823 }
1824
1825 if (strcasecmp(process_name, name) == 0)
1826 return hProcess;
1827 else {
1828 CloseHandle(hProcess);
1829 }
1830 }
1831 /* Not found */
1832 return NULL;
1833 }
1834
count_process(const char * process_name_in)1835 int count_process (const char *process_name_in)
1836 {
1837 char name[SEAF_PATH_MAX];
1838 char process_name[SEAF_PATH_MAX];
1839 DWORD aProcesses[1024], cbNeeded, cProcesses;
1840 HANDLE hProcess;
1841 HMODULE hMods[1024];
1842 int count = 0;
1843 int i, j;
1844
1845 if (strstr(process_name_in, ".exe")) {
1846 snprintf (name, sizeof(name), "%s", process_name_in);
1847 } else {
1848 snprintf (name, sizeof(name), "%s.exe", process_name_in);
1849 }
1850
1851 if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
1852 return 0;
1853 }
1854
1855 /* Calculate how many process identifiers were returned. */
1856 cProcesses = cbNeeded / sizeof(DWORD);
1857
1858 for (i = 0; i < cProcesses; i++) {
1859 if(aProcesses[i] == 0)
1860 continue;
1861 hProcess = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
1862 if (!hProcess) {
1863 continue;
1864 }
1865
1866 if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
1867 for (j = 0; j < cbNeeded / sizeof(HMODULE); j++) {
1868 if (GetModuleBaseName(hProcess, hMods[j], process_name,
1869 sizeof(process_name))) {
1870 if (strcasecmp(process_name, name) == 0)
1871 count++;
1872 }
1873 }
1874 }
1875
1876 CloseHandle(hProcess);
1877 }
1878
1879 return count;
1880 }
1881
1882 gboolean
process_is_running(const char * process_name)1883 process_is_running (const char *process_name)
1884 {
1885 HANDLE proc_handle = get_process_handle(process_name);
1886
1887 if (proc_handle) {
1888 CloseHandle(proc_handle);
1889 return TRUE;
1890 } else {
1891 return FALSE;
1892 }
1893 }
1894
1895 int
win32_kill_process(const char * process_name)1896 win32_kill_process (const char *process_name)
1897 {
1898 HANDLE proc_handle = get_process_handle(process_name);
1899
1900 if (proc_handle) {
1901 TerminateProcess(proc_handle, 0);
1902 CloseHandle(proc_handle);
1903 return 0;
1904 } else {
1905 return -1;
1906 }
1907 }
1908
1909 int
win32_spawn_process(char * cmdline_in,char * working_directory_in)1910 win32_spawn_process (char *cmdline_in, char *working_directory_in)
1911 {
1912 if (!cmdline_in)
1913 return -1;
1914
1915 wchar_t *cmdline_w = NULL;
1916 wchar_t *working_directory_w = NULL;
1917
1918 cmdline_w = wchar_from_utf8 (cmdline_in);
1919 if (!cmdline_in) {
1920 g_warning ("failed to convert cmdline_in");
1921 return -1;
1922 }
1923
1924 if (working_directory_in) {
1925 working_directory_w = wchar_from_utf8 (working_directory_in);
1926 if (!working_directory_w) {
1927 g_warning ("failed to convert working_directory_in");
1928 return -1;
1929 }
1930 }
1931
1932 STARTUPINFOW si;
1933 PROCESS_INFORMATION pi;
1934 unsigned flags;
1935 BOOL success;
1936
1937 /* we want to execute seafile without crreating a console window */
1938 flags = CREATE_NO_WINDOW;
1939
1940 memset(&si, 0, sizeof(si));
1941 si.cb = sizeof(si);
1942 si.dwFlags = STARTF_USESTDHANDLES | STARTF_FORCEOFFFEEDBACK;
1943 si.hStdInput = (HANDLE) _get_osfhandle(0);
1944 si.hStdOutput = (HANDLE) _get_osfhandle(1);
1945 si.hStdError = (HANDLE) _get_osfhandle(2);
1946
1947 memset(&pi, 0, sizeof(pi));
1948
1949 success = CreateProcessW (NULL, cmdline_w, NULL, NULL, TRUE, flags,
1950 NULL, working_directory_w, &si, &pi);
1951 free (cmdline_w);
1952 if (working_directory_w) free (working_directory_w);
1953
1954 if (!success) {
1955 g_warning ("failed to fork_process: GLE=%lu\n", GetLastError());
1956 return -1;
1957 }
1958
1959 /* close the handle of thread so that the process object can be freed by
1960 * system
1961 */
1962 CloseHandle(pi.hThread);
1963 CloseHandle(pi.hProcess);
1964 return 0;
1965 }
1966
1967 char *
wchar_to_utf8(const wchar_t * wch)1968 wchar_to_utf8 (const wchar_t *wch)
1969 {
1970 if (wch == NULL) {
1971 return NULL;
1972 }
1973
1974 char *utf8 = NULL;
1975 int bufsize, len;
1976
1977 bufsize = WideCharToMultiByte
1978 (CP_UTF8, /* multibyte code page */
1979 0, /* flags */
1980 wch, /* src */
1981 -1, /* src len, -1 for all includes \0 */
1982 utf8, /* dst */
1983 0, /* dst buf len */
1984 NULL, /* default char */
1985 NULL); /* BOOL flag indicates default char is used */
1986
1987 if (bufsize <= 0) {
1988 g_warning ("failed to convert a string from wchar to utf8 0");
1989 return NULL;
1990 }
1991
1992 utf8 = g_malloc(bufsize);
1993 len = WideCharToMultiByte
1994 (CP_UTF8, /* multibyte code page */
1995 0, /* flags */
1996 wch, /* src */
1997 -1, /* src len, -1 for all includes \0 */
1998 utf8, /* dst */
1999 bufsize, /* dst buf len */
2000 NULL, /* default char */
2001 NULL); /* BOOL flag indicates default char is used */
2002
2003 if (len != bufsize) {
2004 g_free (utf8);
2005 g_warning ("failed to convert a string from wchar to utf8");
2006 return NULL;
2007 }
2008
2009 return utf8;
2010 }
2011
2012 wchar_t *
wchar_from_utf8(const char * utf8)2013 wchar_from_utf8 (const char *utf8)
2014 {
2015 if (utf8 == NULL) {
2016 return NULL;
2017 }
2018
2019 wchar_t *wch = NULL;
2020 int bufsize, len;
2021
2022 bufsize = MultiByteToWideChar
2023 (CP_UTF8, /* multibyte code page */
2024 0, /* flags */
2025 utf8, /* src */
2026 -1, /* src len, -1 for all includes \0 */
2027 wch, /* dst */
2028 0); /* dst buf len */
2029
2030 if (bufsize <= 0) {
2031 g_warning ("failed to convert a string from wchar to utf8 0");
2032 return NULL;
2033 }
2034
2035 wch = g_malloc (bufsize * sizeof(wchar_t));
2036 len = MultiByteToWideChar
2037 (CP_UTF8, /* multibyte code page */
2038 0, /* flags */
2039 utf8, /* src */
2040 -1, /* src len, -1 for all includes \0 */
2041 wch, /* dst */
2042 bufsize); /* dst buf len */
2043
2044 if (len != bufsize) {
2045 g_free (wch);
2046 g_warning ("failed to convert a string from utf8 to wchar");
2047 return NULL;
2048 }
2049
2050 return wch;
2051 }
2052
2053 #endif /* ifdef WIN32 */
2054
2055 /* read the link of /proc/123/exe and compare with `process_name' */
2056 static int
find_process_in_dirent(struct dirent * dir,const char * process_name)2057 find_process_in_dirent(struct dirent *dir, const char *process_name)
2058 {
2059 char path[512];
2060 /* fisrst construct a path like /proc/123/exe */
2061 #if defined(__linux__)
2062 if (sprintf (path, "/proc/%s/exe", dir->d_name) < 0) {
2063 #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
2064 if (sprintf (path, "/proc/%s/file", dir->d_name) < 0) {
2065 #else
2066 if (1) {
2067 #endif
2068 return -1;
2069 }
2070
2071 char buf[SEAF_PATH_MAX];
2072 /* get the full path of exe */
2073 ssize_t l = readlink(path, buf, SEAF_PATH_MAX);
2074
2075 if (l < 0)
2076 return -1;
2077 buf[l] = '\0';
2078
2079 /* get the base name of exe */
2080 char *base = g_path_get_basename(buf);
2081 int ret = strcmp(base, process_name);
2082 g_free(base);
2083
2084 if (ret == 0)
2085 return atoi(dir->d_name);
2086 else
2087 return -1;
2088 }
2089
2090 /* read the /proc fs to determine whether some process is running */
2091 static gboolean
2092 process_is_running_procfs (const char *process_name)
2093 {
2094 DIR *proc_dir = opendir("/proc");
2095 if (!proc_dir) {
2096 fprintf (stderr, "failed to open /proc/ dir\n");
2097 return FALSE;
2098 }
2099
2100 struct dirent *subdir = NULL;
2101 while ((subdir = readdir(proc_dir))) {
2102 char first = subdir->d_name[0];
2103 /* /proc/[1-9][0-9]* */
2104 if (first > '9' || first < '1')
2105 continue;
2106 int pid = find_process_in_dirent(subdir, process_name);
2107 if (pid > 0) {
2108 closedir(proc_dir);
2109 return TRUE;
2110 }
2111 }
2112
2113 closedir(proc_dir);
2114 return FALSE;
2115 }
2116
2117 static int
2118 count_process_procfs(const char *process_name)
2119 {
2120 int count = 0;
2121 DIR *proc_dir = opendir("/proc");
2122 if (!proc_dir) {
2123 g_warning ("failed to open /proc/ :%s\n", strerror(errno));
2124 return FALSE;
2125 }
2126
2127 struct dirent *subdir = NULL;
2128 while ((subdir = readdir(proc_dir))) {
2129 char first = subdir->d_name[0];
2130 /* /proc/[1-9][0-9]* */
2131 if (first > '9' || first < '1')
2132 continue;
2133 if (find_process_in_dirent(subdir, process_name) > 0) {
2134 count++;
2135 }
2136 }
2137
2138 closedir (proc_dir);
2139 return count;
2140 }
2141
2142 #ifdef __linux__
2143 gboolean process_is_running(const char *process_name) {
2144 return process_is_running_procfs(process_name);
2145 }
2146
2147 int count_process(const char *process_name) {
2148 return count_process_procfs(process_name);
2149 }
2150 #endif
2151
2152 #ifdef __APPLE__
2153 gboolean process_is_running (const char *process_name)
2154 {
2155 //TODO
2156 return FALSE;
2157 }
2158 #endif
2159
2160 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
2161 #if defined(__FreeBSD__)
2162 #define PSKIP(kp) ((kp)->ki_pid == mypid || \
2163 (!kthreads && ((kp)->ki_flag & P_KPROC) != 0))
2164 #define KVM_OPENFILES(exec, coref, buf) \
2165 kvm_openfiles(exec, coref, NULL, O_RDONLY, buf)
2166 #define KVM_GETPROCS(kd, plist, nproc) \
2167 kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc)
2168
2169 #elif defined(__DragonFly__)
2170 #define PSKIP(kp) ((kp)->kp_pid == mypid || \
2171 (!kthreads && ((kp)->kp_flags & P_SYSTEM) != 0))
2172 #define KVM_OPENFILES(exec, coref, buf) \
2173 kvm_openfiles(exec, coref, NULL, O_RDONLY, buf)
2174 #define KVM_GETPROCS(kd, plist, nproc) \
2175 kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc)
2176
2177 #elif defined(__NetBSD__)
2178 #define PSKIP(kp) ((kp)->kp_pid == mypid || \
2179 ((kp)->p_flag & P_SYSTEM) != 0)
2180 #define KVM_OPENFILES(exec, coref, buf) \
2181 kvm_openfiles(exec, coref, NULL, KVM_NO_FILES, buf)
2182 #define KVM_GETPROCS(kd, plist, nproc) \
2183 kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc)
2184
2185 #elif defined(__OpenBSD__)
2186 #define PSKIP(kp) ((kp)->kp_pid == mypid || \
2187 ((kp)->p_flag & (P_SYSTEM | P_THREAD)) != 0)
2188 #define KVM_OPENFILES(exec, coref, buf) \
2189 kvm_openfiles(exec, coref, NULL, KVM_NO_FILES, buf)
2190 #define KVM_GETPROCS(kd, plist, nproc) \
2191 kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*plist), &nproc)
2192
2193 #else
2194 #define PSKIP(kp) 0
2195 #define KVM_OPENFILES(exec, coref, buf) 0
2196 #define KVM_GETPROCS(kd, plist, nproc) 0
2197 #endif
2198
2199 #ifndef WITH_PROC_FS
2200 #define WITH_PROC_FS g_file_test("/proc/curproc", G_FILE_TEST_EXISTS)
2201 #endif
2202
2203 static int
2204 count_running_process_kvm(const char *process_name) {
2205
2206
2207 static kvm_t *kd;
2208 static struct kinfo_proc *plist;
2209 static int nproc;
2210 static pid_t mypid;
2211 static int kthreads;
2212
2213 char buf[_POSIX2_LINE_MAX];
2214 const char * execf, *coref;
2215 char **pargv;
2216 int i, selected_nproc;
2217 struct kinfo_proc *kp;
2218
2219 selected_nproc = 0;
2220 execf = NULL;
2221 coref = _PATH_DEVNULL;
2222
2223 mypid = getpid();
2224 kd = KVM_OPENFILES(execf, coref, buf);
2225 if (kd == NULL) {
2226 fprintf(stderr, "Error: Cannot open kernel files (%s)", buf);
2227 exit(1);
2228 }
2229
2230 plist = KVM_GETPROCS(kd, plist, nproc);
2231 if (plist == NULL) {
2232 fprintf(stderr, "Error: Cannot get process list (%s)", kvm_geterr(kd));
2233 exit(1);
2234 }
2235
2236 for(i = 0, kp = plist; i < nproc; i++, kp++) {
2237 if (PSKIP(kp)) {
2238 continue;
2239 }
2240 if ((pargv = kvm_getargv(kd, kp, 0)) != NULL) {
2241 if (strstr(pargv[0], process_name) != NULL) {
2242 selected_nproc += 1;
2243 }
2244 }
2245 }
2246 kvm_close(kd);
2247 kvm_close(kd);
2248
2249 return selected_nproc;
2250 }
2251
2252 gboolean
2253 process_is_running(const char * process_name) {
2254 if (WITH_PROC_FS) {
2255 return process_is_running_procfs(process_name);
2256 }
2257 if (count_running_process_kvm(process_name) > 0) {
2258 return TRUE;
2259 } else {
2260 return FALSE;
2261 }
2262 }
2263
2264 int
2265 count_process(const char * process_name) {
2266 if (WITH_PROC_FS) {
2267 return count_process_procfs(process_name);
2268 }
2269 return count_running_process_kvm(process_name);
2270 }
2271 #endif
2272
2273 char*
2274 ccnet_object_type_from_id (const char *object_id)
2275 {
2276 char *ptr;
2277
2278 if ( !(ptr = strchr(object_id, '/')) )
2279 return NULL;
2280
2281 return g_strndup(object_id, ptr - object_id);
2282 }
2283
2284
2285 #ifdef WIN32
2286 /**
2287 * In Win32 we need to use _stat64 for files larger than 2GB. _stat64 needs
2288 * the `path' argument in gbk encoding.
2289 */
2290 #define STAT_STRUCT struct __stat64
2291 #define STAT_FUNC win_stat64_utf8
2292
2293 static inline int
2294 win_stat64_utf8 (char *path_utf8, STAT_STRUCT *sb)
2295 {
2296 wchar_t *path_w = wchar_from_utf8 (path_utf8);
2297 int result = _wstat64 (path_w, sb);
2298 free (path_w);
2299 return result;
2300 }
2301
2302 #else
2303 #define STAT_STRUCT struct stat
2304 #define STAT_FUNC stat
2305 #endif
2306
2307 static gint64
2308 calc_recursively (const char *path, GError **calc_error)
2309 {
2310 gint64 sum = 0;
2311
2312 GError *error = NULL;
2313 GDir *folder = g_dir_open(path, 0, &error);
2314 if (!folder) {
2315 g_set_error (calc_error, CCNET_DOMAIN, 0,
2316 "g_open() dir %s failed:%s\n", path, error->message);
2317 return -1;
2318 }
2319
2320 const char *name = NULL;
2321 while ((name = g_dir_read_name(folder)) != NULL) {
2322 STAT_STRUCT sb;
2323 char *full_path= g_build_filename (path, name, NULL);
2324 if (STAT_FUNC(full_path, &sb) < 0) {
2325 g_set_error (calc_error, CCNET_DOMAIN, 0, "failed to stat on %s: %s\n",
2326 full_path, strerror(errno));
2327 g_free(full_path);
2328 g_dir_close(folder);
2329 return -1;
2330 }
2331
2332 if (S_ISDIR(sb.st_mode)) {
2333 gint64 size = calc_recursively(full_path, calc_error);
2334 if (size < 0) {
2335 g_free (full_path);
2336 g_dir_close (folder);
2337 return -1;
2338 }
2339 sum += size;
2340 g_free(full_path);
2341 } else if (S_ISREG(sb.st_mode)) {
2342 sum += sb.st_size;
2343 g_free(full_path);
2344 }
2345 }
2346
2347 g_dir_close (folder);
2348 return sum;
2349 }
2350
2351 gint64
2352 ccnet_calc_directory_size (const char *path, GError **error)
2353 {
2354 return calc_recursively (path, error);
2355 }
2356
2357 #ifdef WIN32
2358 /*
2359 * strtok_r code directly from glibc.git /string/strtok_r.c since windows
2360 * doesn't have it.
2361 */
2362 char *
2363 strtok_r(char *s, const char *delim, char **save_ptr)
2364 {
2365 char *token;
2366
2367 if(s == NULL)
2368 s = *save_ptr;
2369
2370 /* Scan leading delimiters. */
2371 s += strspn(s, delim);
2372 if(*s == '\0') {
2373 *save_ptr = s;
2374 return NULL;
2375 }
2376
2377 /* Find the end of the token. */
2378 token = s;
2379 s = strpbrk(token, delim);
2380
2381 if(s == NULL) {
2382 /* This token finishes the string. */
2383 *save_ptr = strchr(token, '\0');
2384 } else {
2385 /* Terminate the token and make *SAVE_PTR point past it. */
2386 *s = '\0';
2387 *save_ptr = s + 1;
2388 }
2389
2390 return token;
2391 }
2392 #endif
2393
2394 /* JSON related utils. For compatibility with json-glib. */
2395
2396 const char *
2397 json_object_get_string_member (json_t *object, const char *key)
2398 {
2399 json_t *string = json_object_get (object, key);
2400 if (!string)
2401 return NULL;
2402 return json_string_value (string);
2403 }
2404
2405 gboolean
2406 json_object_has_member (json_t *object, const char *key)
2407 {
2408 return (json_object_get (object, key) != NULL);
2409 }
2410
2411 gint64
2412 json_object_get_int_member (json_t *object, const char *key)
2413 {
2414 json_t *integer = json_object_get (object, key);
2415 return json_integer_value (integer);
2416 }
2417
2418 void
2419 json_object_set_string_member (json_t *object, const char *key, const char *value)
2420 {
2421 json_object_set_new (object, key, json_string (value));
2422 }
2423
2424 void
2425 json_object_set_int_member (json_t *object, const char *key, gint64 value)
2426 {
2427 json_object_set_new (object, key, json_integer (value));
2428 }
2429
2430 void
2431 clean_utf8_data (char *data, int len)
2432 {
2433 const char *s, *e;
2434 char *p;
2435 gboolean is_valid;
2436
2437 s = data;
2438 p = data;
2439
2440 while ((s - data) != len) {
2441 is_valid = g_utf8_validate (s, len - (s - data), &e);
2442 if (is_valid)
2443 break;
2444
2445 if (s != e)
2446 p += (e - s);
2447 *p = '?';
2448 ++p;
2449 s = e + 1;
2450 }
2451 }
2452
2453 char *
2454 normalize_utf8_path (const char *path)
2455 {
2456 if (!g_utf8_validate (path, -1, NULL))
2457 return NULL;
2458 return g_utf8_normalize (path, -1, G_NORMALIZE_NFC);
2459 }
2460
2461 /* zlib related wrapper functions. */
2462
2463 #define ZLIB_BUF_SIZE 16384
2464
2465 int
2466 seaf_compress (guint8 *input, int inlen, guint8 **output, int *outlen)
2467 {
2468 int ret;
2469 unsigned have;
2470 z_stream strm;
2471 guint8 out[ZLIB_BUF_SIZE];
2472 GByteArray *barray;
2473
2474 if (inlen == 0)
2475 return -1;
2476
2477 /* allocate deflate state */
2478 strm.zalloc = Z_NULL;
2479 strm.zfree = Z_NULL;
2480 strm.opaque = Z_NULL;
2481 ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
2482 if (ret != Z_OK) {
2483 g_warning ("deflateInit failed.\n");
2484 return -1;
2485 }
2486
2487 strm.avail_in = inlen;
2488 strm.next_in = input;
2489 barray = g_byte_array_new ();
2490
2491 do {
2492 strm.avail_out = ZLIB_BUF_SIZE;
2493 strm.next_out = out;
2494 ret = deflate(&strm, Z_FINISH); /* no bad return value */
2495 have = ZLIB_BUF_SIZE - strm.avail_out;
2496 g_byte_array_append (barray, out, have);
2497 } while (ret != Z_STREAM_END);
2498
2499 *outlen = barray->len;
2500 *output = g_byte_array_free (barray, FALSE);
2501
2502 /* clean up and return */
2503 (void)deflateEnd(&strm);
2504 return 0;
2505 }
2506
2507 int
2508 seaf_decompress (guint8 *input, int inlen, guint8 **output, int *outlen)
2509 {
2510 int ret;
2511 unsigned have;
2512 z_stream strm;
2513 unsigned char out[ZLIB_BUF_SIZE];
2514 GByteArray *barray;
2515
2516 if (inlen == 0) {
2517 g_warning ("Empty input for zlib, invalid.\n");
2518 return -1;
2519 }
2520
2521 /* allocate inflate state */
2522 strm.zalloc = Z_NULL;
2523 strm.zfree = Z_NULL;
2524 strm.opaque = Z_NULL;
2525 strm.avail_in = 0;
2526 strm.next_in = Z_NULL;
2527 ret = inflateInit(&strm);
2528 if (ret != Z_OK) {
2529 g_warning ("inflateInit failed.\n");
2530 return -1;
2531 }
2532
2533 strm.avail_in = inlen;
2534 strm.next_in = input;
2535 barray = g_byte_array_new ();
2536
2537 do {
2538 strm.avail_out = ZLIB_BUF_SIZE;
2539 strm.next_out = out;
2540 ret = inflate(&strm, Z_NO_FLUSH);
2541 if (ret < 0) {
2542 g_warning ("Failed to inflate.\n");
2543 goto out;
2544 }
2545 have = ZLIB_BUF_SIZE - strm.avail_out;
2546 g_byte_array_append (barray, out, have);
2547 } while (ret != Z_STREAM_END);
2548
2549 out:
2550 /* clean up and return */
2551 (void)inflateEnd(&strm);
2552
2553 if (ret == Z_STREAM_END) {
2554 *outlen = barray->len;
2555 *output = g_byte_array_free (barray, FALSE);
2556 return 0;
2557 } else {
2558 g_byte_array_free (barray, TRUE);
2559 return -1;
2560 }
2561 }
2562
2563 char*
2564 format_dir_path (const char *path)
2565 {
2566 int path_len = strlen (path);
2567 char *rpath;
2568 if (path[0] != '/') {
2569 rpath = g_strconcat ("/", path, NULL);
2570 path_len++;
2571 } else {
2572 rpath = g_strdup (path);
2573 }
2574 while (path_len > 1 && rpath[path_len-1] == '/') {
2575 rpath[path_len-1] = '\0';
2576 path_len--;
2577 }
2578
2579 return rpath;
2580 }
2581
2582 gboolean
2583 is_empty_string (const char *str)
2584 {
2585 return !str || strcmp (str, "") == 0;
2586 }
2587
2588 gboolean
2589 is_permission_valid (const char *perm)
2590 {
2591 if (is_empty_string (perm)) {
2592 return FALSE;
2593 }
2594
2595 return strcmp (perm, "r") == 0 || strcmp (perm, "rw") == 0;
2596 }
2597
2598 char *
2599 seaf_key_file_get_string (GKeyFile *key_file,
2600 const char *group,
2601 const char *key,
2602 GError **error)
2603 {
2604 char *v;
2605
2606 v = g_key_file_get_string (key_file, group, key, error);
2607 if (!v || v[0] == '\0') {
2608 g_free (v);
2609 return NULL;
2610 }
2611
2612 return g_strchomp(v);
2613 }
2614
2615 gchar*
2616 ccnet_key_file_get_string (GKeyFile *keyf,
2617 const char *category,
2618 const char *key)
2619 {
2620 gchar *v;
2621
2622 if (!g_key_file_has_key (keyf, category, key, NULL))
2623 return NULL;
2624
2625 v = g_key_file_get_string (keyf, category, key, NULL);
2626 if (v != NULL && v[0] == '\0') {
2627 g_free(v);
2628 return NULL;
2629 }
2630
2631 return g_strchomp(v);
2632 }
2633