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, &times);
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