provide thumbnail path in contact and person views
[platform/core/pim/contacts-service.git] / server / db / ctsvc_db_utils.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 #include <ctype.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <dirent.h>
24 #include <sys/stat.h>
25 #include <sys/vfs.h>
26 #include <image_util.h>
27 #include <unicode/ulocdata.h>
28 #include <unicode/uset.h>
29 #include <unicode/ustring.h>
30 #include <libexif/exif-data.h>
31
32 #include "contacts.h"
33 #include "ctsvc_internal.h"
34 #include "ctsvc_db_utils.h"
35 #include "ctsvc_mutex.h"
36 #include "ctsvc_db_sqlite.h"
37 #include "ctsvc_db_schema.h"
38 #include "ctsvc_notification.h"
39 #include "ctsvc_struct.h"
40 #include "ctsvc_normalize.h"
41 #include "ctsvc_localize.h"
42 #include "ctsvc_localize_utils.h"
43 #include "ctsvc_server_setting.h"
44 #include "ctsvc_notify.h"
45 #include "ctsvc_image_util.h"
46
47 #ifdef _CONTACTS_IPC_SERVER
48 #include "ctsvc_server_change_subject.h"
49 #endif
50
51 static __thread int transaction_count = 0;
52 static __thread int transaction_ver = 0;
53 static __thread bool version_up = false;
54
55 #define CTS_SECURITY_IMAGE_PERMISSION 0440
56 #define CTS_COMMIT_TRY_MAX 500000 /* For 3second */
57
58 int ctsvc_begin_trans(void)
59 {
60         int ret = -1, progress;
61
62         if (transaction_count <= 0) {
63                 ret = ctsvc_query_exec("BEGIN IMMEDIATE TRANSACTION");
64                 progress = 100000;
65                 while (CONTACTS_ERROR_DB == ret && progress < CTS_COMMIT_TRY_MAX) {
66                         usleep(progress);
67                         ret = ctsvc_query_exec("BEGIN IMMEDIATE TRANSACTION");
68                         progress *= 2;
69                 }
70                 if (CONTACTS_ERROR_NONE != ret) {
71                         ERR("ctsvc_query_exec() Fail(%d)", ret);
72                         return ret;
73                 }
74
75                 transaction_count = 0;
76
77                 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
78                 ret = ctsvc_query_get_first_int_result(query, &transaction_ver);
79                 version_up = false;
80         }
81         transaction_count++;
82         INFO("transaction_count : %d.", transaction_count);
83         return CONTACTS_ERROR_NONE;
84 }
85
86 int ctsvc_end_trans(bool is_success)
87 {
88         int ret = -1, progress;
89         char query[CTS_SQL_MIN_LEN] = {0};
90
91         transaction_count--;
92         INFO("%s, transaction_count : %d", is_success ? "True" : "False",  transaction_count);
93
94         if (0 != transaction_count) {
95                 DBG("contact transaction_count : %d.", transaction_count);
96                 return CONTACTS_ERROR_NONE;
97         }
98
99         if (false == is_success) {
100                 ctsvc_nofitication_cancel();
101                 ctsvc_change_subject_clear_changed_info();
102                 ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
103
104                 return CONTACTS_ERROR_NONE;
105         }
106
107         if (version_up) {
108                 transaction_ver++;
109                 snprintf(query, sizeof(query), "UPDATE %s SET ver = %d",
110                                 CTS_TABLE_VERSION, transaction_ver);
111                 ret = ctsvc_query_exec(query);
112                 if (CONTACTS_ERROR_NONE != ret)
113                         ERR("ctsvc_query_exec(version up) Fail(%d)", ret);
114         }
115
116         INFO("start commit");
117         progress = 100000;
118         ret = ctsvc_query_exec("COMMIT TRANSACTION");
119         while (CONTACTS_ERROR_DB == ret && progress < CTS_COMMIT_TRY_MAX) {
120                 usleep(progress);
121                 ret = ctsvc_query_exec("COMMIT TRANSACTION");
122                 progress *= 2;
123         }
124         INFO("%s", (CONTACTS_ERROR_NONE == ret) ? "commit" : "rollback");
125
126         if (CONTACTS_ERROR_NONE != ret) {
127                 int tmp_ret;
128                 ERR("ctsvc_query_exec() Fail(%d)", ret);
129                 ctsvc_nofitication_cancel();
130                 ctsvc_change_subject_clear_changed_info();
131
132                 tmp_ret = ctsvc_query_exec("ROLLBACK TRANSACTION");
133                 if (CONTACTS_ERROR_NONE != tmp_ret)
134                         ERR("ctsvc_query_exec(ROLLBACK) Fail(%d)", tmp_ret);
135
136                 return ret;
137         }
138
139         ctsvc_notification_send();
140         ctsvc_change_subject_publish_changed_info();
141
142         DBG("Transaction shut down! : (%d)\n", transaction_ver);
143
144         return CONTACTS_ERROR_NONE;
145 }
146
147 const char* ctsvc_get_display_column(void)
148 {
149         contacts_name_display_order_e order;
150
151         ctsvc_setting_get_name_display_order(&order);
152         if (CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST == order)
153                 return "display_name";
154         else
155                 return "reverse_display_name";
156 }
157
158 const char* ctsvc_get_sort_name_column(void)
159 {
160         contacts_name_sorting_order_e order;
161
162         ctsvc_setting_get_name_sorting_order(&order);
163         if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
164                 return "sort_name, display_name_language";
165         else
166                 return "reverse_sort_name, reverse_display_name_language";
167 }
168
169 const char* ctsvc_get_sort_column(void)
170 {
171         contacts_name_sorting_order_e order;
172
173         ctsvc_setting_get_name_sorting_order(&order);
174         if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
175                 return "display_name_language, sortkey";
176         else
177                 return "reverse_display_name_language, reverse_sortkey";
178 }
179
180 void ctsvc_utils_make_image_file_name(int parent_id, int id, char *src_img, char *dest,
181                 int dest_size)
182 {
183         char *ext;
184         char *temp;
185         char *lower_ext;
186
187         ext = strrchr(src_img, '.');
188         if (NULL == ext || strchr(ext, '/'))
189                 ext = "";
190
191         lower_ext = strdup(ext);
192         if (NULL == lower_ext) {
193                 ERR("strdup() Fail");
194                 return;
195         }
196         temp = lower_ext;
197         while (*temp) {
198                 *temp = tolower(*temp);
199                 temp++;
200         }
201
202         if (0 < parent_id)
203                 snprintf(dest, dest_size, "%d_%d%s", parent_id, id, lower_ext);
204         else
205                 snprintf(dest, dest_size, "%d%s", id, ext);
206         free(lower_ext);
207 }
208
209 static inline bool _ctsvc_check_available_image_space(int need_size)
210 {
211         int ret;
212         struct statfs buf;
213         long long size;
214
215         ret = statfs(CTSVC_NOTI_IMG_REPERTORY, &buf);
216         RETVM_IF(ret != 0, false, "statfs() Fail(%d)", ret);
217
218         size = (long long)buf.f_bavail * (buf.f_bsize);
219
220         if (need_size < size)  /* if available space to copy a image is larger than need_size */
221                 return true;
222         return false;
223 }
224
225 static image_util_rotation_e _ctsvc_image_get_rotation_info(const char *path)
226 {
227         ExifData *ed = NULL;
228         ExifEntry *entry;
229         image_util_rotation_e rotation = IMAGE_UTIL_ROTATION_NONE;
230         int orientation = 0;
231
232         ed = exif_data_new_from_file(path);
233         if (NULL == ed) {
234                 ERR("exif_data_new_from_file() Fail");
235                 return IMAGE_UTIL_ROTATION_NONE;
236         }
237
238         entry = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
239         if (entry) {
240                 ExifByteOrder mByteOrder = exif_data_get_byte_order(ed);
241                 orientation = (int)exif_get_short(entry->data, mByteOrder);
242                 if (orientation < 0 || 8 < orientation)
243                         orientation = 0;
244         }
245
246         if (ed)
247                 exif_data_unref(ed);
248
249         switch (orientation) {
250         case 1: /* Top-left */
251                 rotation = IMAGE_UTIL_ROTATION_NONE;
252                 break;
253         case 2: /* Top-right */
254                 rotation = IMAGE_UTIL_ROTATION_FLIP_HORZ;
255                 break;
256         case 3: /* Bottom-right */
257                 rotation = IMAGE_UTIL_ROTATION_180;
258                 break;
259         case 4: /* Bottom-left */
260                 rotation = IMAGE_UTIL_ROTATION_FLIP_VERT;
261                 break;
262         case 6: /* Right-top */
263                 rotation = IMAGE_UTIL_ROTATION_90;
264                 break;
265         case 8: /* Left-bottom */
266                 rotation = IMAGE_UTIL_ROTATION_270;
267                 break;
268         case 5: /* Left-top */
269         case 7: /* Right-bottom */
270         case 0:
271         default:
272                 break;
273         };
274
275         return rotation;
276 }
277
278
279 typedef struct {
280         const char *src;
281         const char *dest;
282         int max_size;
283         int ret;
284 } image_info;
285
286 static bool _ctsvc_image_util_supported_jpeg_colorspace_cb(
287                 image_util_colorspace_e colorspace, void *user_data)
288 {
289         int width = 0;
290         int height = 0;
291         int dest_fd = 0;
292         int mimetype = 0;
293         uint64_t size = 0;
294         void *buffer = NULL;
295         void *buffer_temp = NULL;
296         int ret;
297         image_util_rotation_e rotation;
298         image_info *info = user_data;
299
300         ret = ctsvc_image_util_get_mimetype(colorspace, &mimetype);
301         if (CONTACTS_ERROR_NONE != ret) {
302                 info->ret = CONTACTS_ERROR_SYSTEM;
303                 return true;
304         }
305
306         ret = image_util_decode_jpeg(info->src, colorspace, (unsigned char **)&buffer,
307                         &width, &height, (unsigned int *)&size);
308         if (IMAGE_UTIL_ERROR_NONE != ret) {
309                 info->ret = CONTACTS_ERROR_SYSTEM;
310                 return true;
311         }
312
313         rotation = _ctsvc_image_get_rotation_info(info->src);
314         if (IMAGE_UTIL_ROTATION_NONE != rotation) { /* need rotate */
315                 media_format_h fmt;
316                 media_packet_h packet;
317
318                 fmt = ctsvc_image_util_create_media_format(mimetype, width, height);
319                 if (NULL == fmt) {
320                         ERR("ctsvc_image_util_create_media_format() Fail");
321                         info->ret = CONTACTS_ERROR_SYSTEM;
322                         free(buffer);
323                         return false;
324                 }
325
326                 packet = ctsvc_image_util_create_media_packet(fmt, buffer, (unsigned int)size);
327                 if (NULL == packet) {
328                         ERR("ctsvc_image_util_create_media_packet() Fail");
329                         media_format_unref(fmt);
330                         info->ret = CONTACTS_ERROR_SYSTEM;
331                         free(buffer);
332                         return false;
333                 }
334
335                 ret = ctsvc_image_util_rotate(packet, rotation, &buffer_temp, &size);
336
337                 media_packet_destroy(packet);
338                 media_format_unref(fmt);
339
340                 if (CONTACTS_ERROR_NONE != ret) {
341                         free(buffer);
342                         info->ret = CONTACTS_ERROR_SYSTEM;
343                         return false;
344                 }
345
346                 if (rotation == IMAGE_UTIL_ROTATION_90 || rotation == IMAGE_UTIL_ROTATION_270) {
347                         int temp = width;
348                         width = height;
349                         height = temp;
350                 }
351                 free(buffer);
352                 buffer = buffer_temp;
353         }
354
355         if (info->max_size < width || info->max_size < height) { /* need resize */
356                 int resized_width;
357                 int resized_height;
358                 media_format_h fmt;
359                 media_packet_h packet;
360
361                 /* set resize */
362                 if (width > height) {
363                         resized_width = info->max_size;
364                         resized_height = height * info->max_size / width;
365                 } else {
366                         resized_height = info->max_size;
367                         resized_width = width * info->max_size / height;
368                 }
369
370                 if (resized_height % 8)
371                         resized_height += (8 - (resized_height % 8));
372
373                 if (resized_width % 8)
374                         resized_width += (8 - (resized_width % 8));
375
376                 fmt = ctsvc_image_util_create_media_format(mimetype, width, height);
377                 if (NULL == fmt) {
378                         ERR("ctsvc_image_util_create_media_format() Fail");
379                         info->ret = CONTACTS_ERROR_SYSTEM;
380                         free(buffer);
381                         return false;
382                 }
383
384                 packet = ctsvc_image_util_create_media_packet(fmt, buffer, (unsigned int)size);
385                 if (NULL == packet) {
386                         ERR("ctsvc_image_util_create_media_packet() Fail");
387                         media_format_unref(fmt);
388                         info->ret = CONTACTS_ERROR_SYSTEM;
389                         free(buffer);
390                         return false;
391                 }
392
393                 ret = ctsvc_image_util_resize(packet, resized_width, resized_height, &buffer_temp,
394                                 &size);
395
396                 media_packet_destroy(packet);
397                 media_format_unref(fmt);
398
399                 if (CONTACTS_ERROR_NONE != ret) {
400                         free(buffer);
401                         info->ret = -1;
402                         return false;
403                 }
404                 free(buffer);
405                 buffer = buffer_temp;
406
407                 width = resized_width;
408                 height = resized_height;
409         }
410
411         ret = image_util_encode_jpeg(buffer, width, height, colorspace,
412                         CTSVC_IMAGE_ENCODE_QUALITY, info->dest);
413         free(buffer);
414         if (IMAGE_UTIL_ERROR_NONE != ret) {
415                 ERR("image_util_encode_jpeg Fail(%d)", ret);
416                 info->ret = CONTACTS_ERROR_SYSTEM;
417                 return false;
418         }
419
420         dest_fd = open(info->dest, O_RDONLY);
421         if (dest_fd < 0) {
422                 ERR("System : Open Fail(%d)", errno);
423                 info->ret = CONTACTS_ERROR_SYSTEM;
424                 return false;
425         }
426
427         ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
428         if (0 != ret) {
429                 ERR("fchmod Fail(%d)", errno);
430                 info->ret = CONTACTS_ERROR_SYSTEM;
431                 close(dest_fd);
432                 return false;
433         }
434         close(dest_fd);
435
436         info->ret = CONTACTS_ERROR_NONE;
437         return false;
438 }
439
440 static int _ctsvc_image_encode(const char *src, const char *dest, int max_size)
441 {
442         int ret;
443         image_info info = {src, dest, max_size, CONTACTS_ERROR_SYSTEM};
444
445         ret = image_util_foreach_supported_jpeg_colorspace(
446                         _ctsvc_image_util_supported_jpeg_colorspace_cb, &info);
447
448         if (IMAGE_UTIL_ERROR_NONE != ret)
449                 return CONTACTS_ERROR_SYSTEM;
450
451         return info.ret;
452 }
453
454 #define CTSVC_COPY_SIZE_MAX 4096
455 int ctsvc_utils_copy_image(const char *dir, const char *src, const char *file)
456 {
457         int ret;
458         int size;
459         int src_fd, dest_fd;
460         char buf[CTSVC_COPY_SIZE_MAX] = {0};
461
462         if (NULL == file || *file == '\0')
463                 return CONTACTS_ERROR_INVALID_PARAMETER;
464
465         char dest[strlen(dir) + strlen(file) + 2];
466         snprintf(dest, sizeof(dest), "%s/%s", dir, file);
467
468         if (false == _ctsvc_check_available_image_space(1204 * 1204)) /*need larger than 1M*/
469                 return CONTACTS_ERROR_FILE_NO_SPACE;
470
471         ret = _ctsvc_image_encode(src, dest, CTSVC_IMAGE_MAX_SIZE);
472         if (CONTACTS_ERROR_NONE == ret)
473                 return ret;
474         else
475                 ERR("_ctsvc_image_encode Fail(%d)", ret);
476
477         src_fd = open(src, O_RDONLY);
478         if (src_fd < 0) {
479                 ERR("System : Open(%s) Fail(%d)", src, errno);
480                 return CONTACTS_ERROR_SYSTEM;
481         }
482
483         dest_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0660);
484         if (dest_fd < 0) {
485                 ERR("Open Fail(%d)", errno);
486                 close(src_fd);
487                 return CONTACTS_ERROR_SYSTEM;
488         }
489
490         while (0 < (size = read(src_fd, buf, CTSVC_COPY_SIZE_MAX))) {
491                 ret = write(dest_fd, buf, size);
492                 if (ret <= 0) {
493                         if (EINTR == errno) {
494                                 continue;
495                         } else {
496                                 ERR("write() Fail(%d)", errno);
497                                 if (ENOSPC == errno)
498                                         ret = CONTACTS_ERROR_FILE_NO_SPACE; /* No space */
499                                 else
500                                         ret = CONTACTS_ERROR_SYSTEM; /* IO error */
501                                 close(src_fd);
502                                 close(dest_fd);
503                                 unlink(dest);
504                                 return ret;
505                         }
506                 }
507         }
508
509         ret = fchmod(dest_fd, CTS_SECURITY_IMAGE_PERMISSION);
510         if (0 != ret)
511                 ERR("fchmod() Fail(%d)", ret);
512
513         close(src_fd);
514         close(dest_fd);
515
516         return CONTACTS_ERROR_NONE;
517 }
518
519 char* ctsvc_utils_get_thumbnail_path(const char *image_path)
520 {
521         int name_len = 0;
522         int full_len = 0;
523         char *thumbnail_path = NULL;
524         char *ext = NULL;
525
526         RETV_IF(NULL == image_path, NULL);
527         RETV_IF(NULL != strstr(image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
528
529         full_len = strlen(image_path) + strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX) + 1;
530         thumbnail_path = calloc(1, full_len);
531         if (NULL == thumbnail_path) {
532                 ERR("calloc() Fail");
533                 return NULL;
534         }
535
536         ext = strrchr(image_path, '.');
537         if (ext) {
538                 name_len = ext -image_path;
539                 strncpy(thumbnail_path, image_path, name_len);
540                 snprintf(thumbnail_path+name_len, full_len-name_len, "%s%s", CTSVC_IMAGE_THUMBNAIL_SUFFIX, ext);
541         } else {
542                 snprintf(thumbnail_path, full_len, "%s%s", image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX);
543         }
544
545         return thumbnail_path;
546 }
547
548 char* ctsvc_utils_get_image_path(const char *thumbnail_path)
549 {
550         int name_len = 0;
551         int full_len = 0;
552         char *image_path = NULL;
553         char *ext = NULL;
554
555         RETV_IF(NULL == thumbnail_path, NULL);
556         RETV_IF(NULL == strstr(thumbnail_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
557
558         full_len = strlen(thumbnail_path) - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX) + 1;
559         image_path = calloc(1, full_len);
560         if (NULL == image_path) {
561            ERR("calloc() Fail");
562            return NULL;
563         }
564
565         ext = strrchr(thumbnail_path, '.');
566         if (ext) {
567                 name_len = ext -thumbnail_path - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX);
568                 strncpy(image_path, thumbnail_path, name_len);
569                 snprintf(image_path + name_len, full_len -name_len, "%s", ext);
570         } else {
571                 name_len = strlen(thumbnail_path) - strlen(CTSVC_IMAGE_THUMBNAIL_SUFFIX);
572                 strncpy(image_path, thumbnail_path, name_len);
573         }
574         return image_path;
575 }
576
577 char* ctsvc_utils_make_thumbnail(const char *image_path)
578 {
579         int ret;
580         char src[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
581         char dest[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
582         char *thumbnail_path = NULL;
583
584         RETV_IF(NULL == image_path, NULL);
585         RETV_IF(NULL != strstr(image_path, CTSVC_IMAGE_THUMBNAIL_SUFFIX), NULL);
586
587         if (false == _ctsvc_check_available_image_space(
588                         CTSVC_IMAGE_THUMBNAIL_SIZE * CTSVC_IMAGE_THUMBNAIL_SIZE)) {
589                         ERR("No space to make thumbnail");
590                         return NULL;
591         }
592
593         thumbnail_path = ctsvc_utils_get_thumbnail_path(image_path);
594         if (NULL == thumbnail_path) {
595                 ERR("ctsvc_image_util_get_thumbnail_path() Fail");
596                 return NULL;
597         }
598
599         if (0 == access(dest, F_OK)) {
600                 DBG("already exist");
601                 return thumbnail_path;
602         }
603
604         snprintf(src, sizeof(src), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, image_path);
605         snprintf(dest, sizeof(dest), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, thumbnail_path);
606
607         ret = _ctsvc_image_encode(src, dest, CTSVC_IMAGE_THUMBNAIL_SIZE);
608         if (CONTACTS_ERROR_NONE != ret) {
609                 ERR("_ctsvc_image_encode() Fail(%d)", ret);
610                 free(thumbnail_path);
611                 return NULL;
612         }
613
614         return strdup(thumbnail_path);
615 }
616
617 int ctsvc_get_next_ver(void)
618 {
619         const char *query;
620         int version;
621         int ret;
622
623         if (0 < transaction_count) {
624                 version_up = true;
625                 return transaction_ver + 1;
626         }
627
628         query = "SELECT ver FROM "CTS_TABLE_VERSION;
629         ret = ctsvc_query_get_first_int_result(query, &version);
630
631         /* In this case, contacts-service already works abnormally. */
632         if (CONTACTS_ERROR_NONE != ret)
633                 ERR("ctsvc_query_get_first_int_result : get version error(%d)", ret);
634
635         return (1 + version);
636 }
637
638 int ctsvc_get_current_version(int *out_current_version)
639 {
640         if (transaction_count <= 0) {
641                 int ret;
642                 int version = 0;
643                 const char *query = "SELECT ver FROM "CTS_TABLE_VERSION;
644
645                 ret = ctsvc_query_get_first_int_result(query, &version);
646                 if (CONTACTS_ERROR_NONE != ret) {
647                         ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
648                         return ret;
649                 }
650
651                 *out_current_version = version;
652         } else {
653                 *out_current_version = transaction_ver;
654         }
655         return CONTACTS_ERROR_NONE;
656 }
657
658 int ctsvc_get_transaction_ver(void)
659 {
660         return transaction_ver;
661 }
662
663 int SAFE_SNPRINTF(char **buf, int *buf_size, int len, const char *src)
664 {
665         int remain;
666         int temp_len;
667
668         if (len < 0)
669                 return -1;
670
671         remain = *buf_size - len;
672         if (strlen(src) + 1 < remain) {
673                 temp_len = snprintf((*buf)+len, remain, "%s", src);
674                 return temp_len;
675         } else {
676                 char *temp;
677                 while (1) {
678                         temp = realloc(*buf, *buf_size*2);
679                         if (NULL == temp)
680                                 return -1;
681                         *buf = temp;
682                         *buf_size = *buf_size * 2;
683                         remain = *buf_size - len;
684                         if (strlen(src) + 1 < remain)
685                                 break;
686                 }
687                 temp_len = snprintf((*buf)+len, remain, "%s", src);
688                 return temp_len;
689         }
690 }
691