Gtest code for mtp-responder
[platform/core/connectivity/mtp-responder.git] / src / util / mtp_support.c
1 /*
2  * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <glib.h>
18 #include <glib/gprintf.h>
19 #include <unistd.h>
20 #include <sys/wait.h>
21 #include "mtp_support.h"
22 #include "ptp_datacodes.h"
23 #include "mtp_util.h"
24
25 /*
26  * STATIC FUNCTIONS
27  */
28 static mtp_char *__util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str);
29
30 /*
31  * FUNCTIONS
32  */
33 /* LCOV_EXCL_START */
34 void _util_conv_byte_order(void *data, mtp_int32 size)
35 {
36         mtp_int32 idx;
37         mtp_uchar temp;
38         mtp_int32 h_size;
39         mtp_uchar *l_data = (mtp_uchar *)data;
40
41         ret_if(data == NULL);
42         retm_if(size <= 1, "size(%d) is invalid", size);
43
44         h_size = size / 2;
45         for (idx = 0; idx < h_size; idx++) {
46                 temp = l_data[idx];
47                 l_data[idx] = l_data[size - idx - 1];
48                 l_data[size - idx - 1] = temp;
49         }
50
51         return;
52 }
53
54 void _util_conv_byte_order_wstring(mtp_uint16 *wstr, mtp_int32 size)
55 {
56         _util_conv_byte_order_gen_str(wstr, size, sizeof(mtp_uint16));
57         return;
58 }
59
60 void _util_conv_byte_order_gen_str(void *str, mtp_int32 size, mtp_int32 elem_sz)
61 {
62         mtp_int32 idx;
63         mtp_int32 f_size = size * elem_sz;
64         mtp_uchar *l_str = (mtp_uchar *)str;
65
66         ret_if(str == NULL);
67         retm_if(elem_sz <= 1, "elem_sz(%d) is invalid", elem_sz);
68
69         for (idx = 0; idx < f_size; idx += elem_sz)
70                 _util_conv_byte_order(&(l_str[idx]), elem_sz);
71
72         return;
73 }
74 /* LCOV_EXCL_STOP */
75
76 /*
77  * If items_written is greater than or equal to dest_size,
78  * src is truncated when it is copied to dest.
79  */
80 mtp_int32 _util_utf16_to_utf8(char *dest, mtp_int32 dest_size,
81                 const mtp_wchar *src)
82 {
83         gchar *utf8 = NULL;
84         GError *error = NULL;
85         glong items_read = 0;
86         glong items_written = 0;
87         const gunichar2 *utf16 = (const gunichar2 *)src;
88
89         retv_if(src == NULL, 0);
90         retv_if(dest == NULL, 0);
91
92         utf8 = g_utf16_to_utf8(utf16, -1, &items_read, &items_written, &error);
93         if (utf8 == NULL) {
94                 /* LCOV_EXCL_START */
95                 ERR("%s\n", error->message);
96                 g_error_free(error);
97
98                 dest[0] = '\0';
99                 items_written = 0;
100                 /* LCOV_EXCL_STOP */
101         } else {
102                 g_strlcpy(dest, (char *)utf8, dest_size);
103                 g_free(utf8);
104         }
105
106         return (mtp_int32)items_written;
107 }
108
109 /*
110  * If items_written is greater than or equal to dest_items,
111  * src is truncated when it is copied to dest.
112  */
113 mtp_int32 _util_utf8_to_utf16(mtp_wchar *dest, mtp_int32 dest_items,
114                 const char *src)
115 {
116         GError *error = NULL;
117         glong items_read = 0;
118         gunichar2 *utf16 = NULL;
119         glong items_written = 0;
120
121         retv_if(src == NULL, 0);
122         retv_if(dest == NULL, 0);
123
124         utf16 = g_utf8_to_utf16(src, -1, &items_read, &items_written, &error);
125         if (utf16 == NULL) {
126                 /* LCOV_EXCL_START */
127                 ERR("%s\n", error->message);
128                 g_error_free(error);
129                 error = NULL;
130
131                 dest[0] = (mtp_wchar)'\0';
132                 items_written = 0;
133                 /* LCOV_EXCL_STOP */
134         } else {
135                 _util_wchar_ncpy(dest, utf16, dest_items);
136                 g_free(utf16);
137         }
138
139         return (mtp_int32)items_written;
140 }
141
142
143 /*
144  * Copies a unicode string.
145  * @param[in]   src     Null-terminated source string
146  * @param[out]  dest    Destination buffer
147  * @return      None
148  */
149 /* LCOV_EXCL_START */
150 void _util_wchar_cpy(mtp_wchar *dest, const mtp_wchar *src)
151 {
152         ret_if(src == NULL);
153         ret_if(dest == NULL);
154
155         if (!((int)dest & 0x1) && !((int)src & 0x1)) {
156                 /* 2-byte aligned */
157                 mtp_wchar *temp = dest;
158
159                 while ((*temp++ = *src++) != '\0')
160                         ;       /* DO NOTHING  */
161         } else {
162                 /* not-aligned, byte to byte approach - slow */
163                 mtp_char *pc1 = (mtp_char *)dest;
164                 mtp_char *pc2 = (mtp_char *)src;
165
166                 while (*pc2 || *(pc2 + 1)) {
167                         *pc1 = *pc2;
168                         *(pc1 + 1) = *(pc2 + 1);
169
170                         pc1 += 2;
171                         pc2 += 2;
172                 }
173         }
174
175         return;
176 }
177 /* LCOV_EXCL_STOP */
178
179 /*
180  * Copies a unicode string a given numbers of character.
181  * @param[in]   src     Null-terminated source string
182  * @param[out]  dest    Destination buffer
183  * @return      None
184  */
185 void _util_wchar_ncpy(mtp_wchar *dest, const mtp_wchar *src, unsigned long n)
186 {
187         char *pc1 = NULL;
188         char *pc2 = NULL;
189         mtp_wchar *temp = NULL;
190
191         ret_if(src == NULL);
192         ret_if(dest == NULL);
193
194         if (!((int)dest & 0x1) && !((int)src & 0x1)) {  /* 2-byte aligned */
195                 temp = dest;
196
197                 while (n && (*temp++ = *src++))
198                         n--;
199
200                 if (n) {
201                         while (--n)
202                                 *temp++ = 0;
203                 }
204         } else {                /* not-aligned, byte to byte approach - slow */
205
206                 pc1 = (char *)dest;
207                 pc2 = (char *)src;
208
209                 /* LCOV_EXCL_START */
210                 while (n && (*pc2 || *(pc2 + 1))) {
211                         --n;
212                         *pc1++ = *pc2++;
213                         *pc1++ = *pc2++;
214                 }
215
216                 if (n) {
217                         while (--n) {
218                                 *pc1++ = 0;
219                                 *pc1++ = 0;
220                         }
221                 }
222         }
223
224         return;
225 }
226
227 /*
228  * Returns the length of wide character string
229  * @param[in]   src     Wide char string
230  * @return      length
231  */
232 size_t _util_wchar_len(const mtp_wchar *s)
233 {
234         if (!((int)s & 0x1)) {  /* 2-byte aligned */
235                 mtp_wchar *temp = (mtp_wchar *)s;
236
237                 while (*temp++)
238                         /* DO NOTHING */ ;
239
240                 DBG("Length : %d\n", temp - s - 1);
241                 return ((size_t)(temp - s - 1));
242         } else {                /* not-aligned, byte to byte approach - slow */
243
244                 unsigned char *temp = (unsigned char *)s;
245
246                 while (*temp || *(temp + 1))
247                         temp += 2;
248
249                 DBG("Length : %d\n", (temp - (unsigned char *)s) / 2);
250                 return ((size_t) (temp - (unsigned char *)s) / 2);
251         }
252 }
253
254 static mtp_char* __util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str)
255 {
256         mtp_char *nstr = str;
257         mtp_int32 val = int_val;
258         mtp_char hex[] = { "0123456789ABCDEF" };
259
260         retv_if(str == NULL, NULL);
261
262         *nstr++ = '0';
263         *nstr++ = 'x';
264
265         for (val = int_val; val; val <<= 4)
266                 *nstr++ = hex[(val >> (sizeof(int) * 8 - 4)) & 0xF];
267
268         *nstr = '\0';
269         return str;
270 }
271
272 /*
273  * This is very minimal implementation.
274  * Be cautious using this function.
275  */
276 mtp_err_t _util_wchar_swprintf(mtp_wchar *mtp_wstr, mtp_int32 size,
277                 mtp_char *format, ...)
278 {
279         mtp_char *ptr;
280         mtp_wchar wsHex[24];
281         mtp_int32 count = 0;
282         mtp_wchar *wbuf = mtp_wstr;
283         mtp_char *bptr_val = NULL;
284         mtp_wchar *wstr_val = NULL;
285         mtp_int32 int_val = 0, len = 0;
286         mtp_char buf[MTP_MAX_PATHNAME_SIZE + 1];
287
288         va_list arg_list;
289         va_start(arg_list, format);
290         for (ptr = format; *ptr && count < (size - 1); ptr++) {
291                 if (*ptr == '%') {
292                         switch (*(ptr + 1)) {
293                         case 'd':
294                                 int_val = va_arg(arg_list, int);
295                                 wbuf[count++] = (mtp_wchar) (int_val + '0');
296                                 ptr++;
297                                 break;
298                         case 's':
299                                 bptr_val = va_arg(arg_list, char *);
300                                 wstr_val = (mtp_wchar *) bptr_val;
301                                 len = _util_wchar_len(wstr_val);
302                                 if (len + count > size - 1) {
303                                         len = size - 1 - count;
304                                         _util_wchar_ncpy(&wbuf[count], wstr_val,
305                                                         len);
306                                 } else {
307                                         _util_wchar_cpy(&wbuf[count], wstr_val);
308                                 }
309                                 count += len;
310                                 ptr++;
311                                 break;
312                         case 'x':
313                                 int_val = va_arg(arg_list, int);
314                                 __util_conv_int_to_hex_str(int_val, buf);
315                                 _util_utf8_to_utf16(wsHex,
316                                                 sizeof(wsHex) / WCHAR_SIZ, buf);
317                                 len = strlen(buf);
318                                 if (len + count > size - 1) {
319                                         len = size - 1 - count;
320                                         _util_wchar_ncpy(&wbuf[count], wsHex,
321                                                         len);
322                                 } else {
323                                         _util_wchar_cpy(&wbuf[count], wsHex);
324                                 }
325                                 count += len;
326                                 ptr++;
327                                 break;
328
329                         default:
330                                 DBG("swprintf not handling: %c", *(ptr + 1));
331                                 break;
332                         }
333                 } else {
334                         wbuf[count++] = (mtp_wchar)(*ptr);
335                 }
336         }
337
338         va_end(arg_list);
339         wbuf[count] = (mtp_wchar)'\0';
340         _util_utf16_to_utf8(buf, sizeof(buf), wbuf);
341
342         return MTP_ERROR_NONE;
343 }
344 /* LCOV_EXCL_STOP */
345
346 mtp_uint16 _util_get_fmtcode(const mtp_char *extn)
347 {
348         static fmt_code_t fmt_code_table[] = {
349                 {"ALB", MTP_FMT_ABSTRACT_AUDIO_ALBUM},
350                 {"MP3", PTP_FMT_MP3},
351                 {"WMA", MTP_FMT_WMA},
352                 {"WMV", MTP_FMT_WMV},
353                 {"JPG", PTP_FMT_IMG_EXIF},
354                 {"GIF", PTP_FMT_IMG_GIF},
355                 {"BMP", PTP_FMT_IMG_BMP},
356                 {"PNG", PTP_FMT_IMG_PNG},
357                 {"ASF", PTP_FMT_ASF},
358                 {"WAV", PTP_FMT_WAVE},
359                 {"AVI", PTP_FMT_AVI},
360                 {"MPG", PTP_FMT_MPEG},
361                 {"TXT", PTP_FMT_TEXT},
362                 {"3GP", MTP_FMT_3GP},
363                 {"ODF", MTP_FMT_3GP},
364                 {"O4A", MTP_FMT_3GP},
365                 {"O4V", MTP_FMT_3GP},
366                 {"MP4", MTP_FMT_MP4},
367                 {"FLAC", MTP_FMT_FLAC},
368                 {"", PTP_FMT_UNDEF}
369         };
370
371         fmt_code_t *p = NULL;
372         p = fmt_code_table;
373
374         while (p->fmt_code != PTP_FMT_UNDEF) {
375                 if (!strncasecmp(extn, p->extn, strlen(p->extn)))
376                         break;
377
378                 p++;
379         }
380
381         /* will return FormatCode or PTP_FORMATCODE_UNDEFINED
382          * if we hit end of list.
383          */
384         return p->fmt_code;
385 }
386
387 /*
388  * This function gets the file extension.
389  * @param[in]           fileName                Specifies the file name.
390  * @param[out]          file_extn               holds the extension of the file.
391  * @return              Returns TRUE on success and FALSE on failure.
392  */
393 mtp_bool _util_get_file_extn(const mtp_char *f_name, mtp_char *f_extn)
394 {
395         char *ptr;
396
397         retv_if(NULL == f_name, FALSE);
398         retv_if(NULL == f_extn, FALSE);
399
400         ptr = strrchr(f_name, '.');
401
402         if (ptr != NULL) {
403                 g_strlcpy(f_extn, ptr + 1, MTP_MAX_PATHNAME_SIZE);
404                 return TRUE;
405         }
406
407         return FALSE;
408 }
409
410 mtp_bool _util_get_file_name(const mtp_char *fullpath, mtp_char *f_name)
411 {
412         mtp_int32 i, j;
413
414         retv_if(f_name == NULL, FALSE);
415         retv_if(fullpath == NULL, FALSE);
416
417         i = strlen(fullpath);
418
419         for (j = 0; i >= 0; i--) {
420                 if (fullpath[i] == '/') {
421                         g_strlcpy(f_name, &fullpath[i + 1], j);
422                         return TRUE;
423                 }
424                 j++;
425         }
426         g_strlcpy(f_name, fullpath, j);
427
428         return TRUE;
429 }
430 /*
431  * This function gives file name without extension.
432  * @param[in]   fullpath        pointer to absolute file path
433  * @param[out]  f_name  gets filled with filename w/o extension
434  * @return      True or False based on success or failure
435  */
436 /* LCOV_EXCL_START */
437 mtp_bool _util_get_file_name_wo_extn(const mtp_char *fullpath, mtp_char *f_name)
438 {
439         mtp_char *fname_ptr;
440         mtp_uint32 fname_len;
441         mtp_char *extn_ptr = NULL;
442
443         retv_if(f_name == NULL, FALSE);
444         retv_if(fullpath == NULL, FALSE);
445
446         fname_ptr = strrchr(fullpath, '/');
447
448         if (fname_ptr == NULL) {
449                 ERR("Invalid File Name");
450                 return FALSE;
451         }
452
453         fname_ptr = fname_ptr + sizeof(char);
454         fname_len = strlen(fname_ptr);
455         extn_ptr = strrchr(fname_ptr, '.');
456
457         if (extn_ptr == NULL) {
458                 g_strlcpy(f_name, fname_ptr, fname_len + 1);
459                 return TRUE;
460         }
461
462         g_strlcpy(f_name, fname_ptr, ((mtp_uint32)(extn_ptr - fname_ptr) + 1));
463         return TRUE;
464 }
465 /* LCOV_EXCL_STOP */
466
467 mtp_bool _util_is_path_len_valid(const mtp_char *path)
468 {
469         mtp_uint32 limit = 0;
470         mtp_uint32 mtp_path_len = 0;
471         mtp_uint32 root_path_len = 0;
472
473         static mtp_uint32 max_store_len = 0;
474         static mtp_bool is_initialized = FALSE;
475         static mtp_uint32 internal_store_len = 0;
476         static mtp_uint32 external_store_len = 0;
477
478         char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
479         char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
480
481         retv_if(path == NULL, FALSE);
482
483         _util_get_external_path(ext_path);
484         _util_get_internal_path(inter_path);
485
486         if (!is_initialized) {
487                 is_initialized = TRUE;
488                 internal_store_len = strlen(inter_path);
489                 external_store_len = strlen(ext_path);
490
491                 max_store_len = internal_store_len > external_store_len ?
492                         internal_store_len : external_store_len;
493
494                 DBG("max store len : [%u]\n", max_store_len);
495         }
496
497         if (!strncmp(path, inter_path, internal_store_len)) {
498                 root_path_len = internal_store_len;
499         } else if (!strncmp(path, ext_path, external_store_len)) {
500                 root_path_len = external_store_len;
501         } else {
502                 ERR("Unknown store's path : %s\n", path);
503                 return FALSE;
504         }
505
506         /* Path len should be calculated except root path(eg. /opt/usr/media) */
507         mtp_path_len = strlen(path) - root_path_len;
508
509         /* MTP_MAX_PATHNAME_SIZE includes maximum length of root path */
510         limit = MTP_MAX_PATHNAME_SIZE - max_store_len;
511
512         if (mtp_path_len > limit) {
513                 ERR("Too long path : [%u] > [%u]\n", mtp_path_len, limit);
514                 return FALSE;
515         }
516
517         return TRUE;
518 }
519
520 mtp_bool _util_create_path(mtp_char *path, mtp_uint32 size, const mtp_char *dir,
521                 const mtp_char *filename)
522 {
523         mtp_int32 ret = 0;
524         mtp_uint32 len = 0;
525
526         retv_if(dir == NULL, FALSE);
527         retv_if(path == NULL, FALSE);
528         retv_if(filename == NULL, FALSE);
529
530         len = strlen(filename);
531         if (len > MTP_MAX_FILENAME_SIZE) {
532         /* LCOV_EXCL_START */
533                 ERR("filename is too long :[%u] > [%u]\n", len,
534                                 MTP_MAX_FILENAME_SIZE);
535                 return FALSE;
536         }
537
538         ret = g_snprintf(path, size, "%s/%s", dir, filename);
539         if (ret > size) {
540                 ERR("path is truncated");
541                 return FALSE;
542         }
543
544         if (_util_is_path_len_valid(path) == FALSE) {
545                 ERR("path length exceeds the limit");
546                 return FALSE;
547         }
548
549         return TRUE;
550 }
551
552 /*
553  * This function gets the parent path.
554  * @param[in]   fullpath        Pointer to a buffer containing full file path.
555  * @param[out]  p_path  Points the buffer to hold parent path.
556  * @return      None
557  */
558 void _util_get_parent_path(const mtp_char *fullpath, mtp_char *p_path)
559 {
560         mtp_char *ptr = NULL;
561
562         ret_if(NULL == p_path);
563         ret_if(NULL == fullpath);
564
565         ptr = strrchr(fullpath, '/');
566         if (!ptr) {
567                 ERR("Path does not have parent path");
568                 return;
569         }
570
571         g_strlcpy(p_path, fullpath, (mtp_uint32)(ptr - fullpath) + 1);
572         return;
573 }
574
575 void _util_conv_wstr_to_guid(mtp_wchar *wstr, mtp_uint64 *guid)
576 {
577         mtp_uint32 skip_idx;
578         mtp_uint32 cur_idx;
579         mtp_uint64 temp[2];
580         mtp_int32 count = 0;
581         mtp_int32 cpy_sz = 0;
582
583         ret_if(wstr == NULL);
584         ret_if(guid == NULL);
585
586         while (wstr[count] != 0)
587                 count++;
588
589         memset(guid, 0, sizeof(temp));
590         skip_idx = sizeof(temp) / sizeof(mtp_wchar);
591
592         for (cur_idx = 0; cur_idx < count; cur_idx += skip_idx) {
593
594                 memset(temp, 0, sizeof(temp));
595                 cpy_sz = (count - cur_idx) * sizeof(mtp_wchar);
596                 if (cpy_sz > sizeof(temp))
597                         cpy_sz = sizeof(temp);
598
599                 memcpy(temp, &(wstr[cur_idx]), cpy_sz);
600                 guid[0] += temp[0];
601                 guid[1] += temp[1];
602         }
603
604         return;
605 }
606
607 mtp_bool _util_get_unique_dir_path(const mtp_char *exist_path,
608                 mtp_char *new_path, mtp_uint32 new_path_buf_len)
609 {
610         mtp_uint32 num_bytes = 0;
611         mtp_uint32 max_value = 1;
612         mtp_uint32 count = 1;
613         mtp_uint32 val = 1;
614         mtp_char *buf = NULL;
615         mtp_uint32 len = strlen(exist_path);
616
617         retv_if(new_path == NULL, FALSE);
618         retv_if(exist_path == NULL, FALSE);
619
620         /* Excluding '_' */
621         num_bytes = new_path_buf_len - len - 1;
622         if (num_bytes <= 0) {
623                 ERR("No space to append data[%d]\n", num_bytes);
624                 return FALSE;
625         }
626
627         if (num_bytes >= MTP_BUF_SIZE_FOR_INT - 1) {
628                 max_value = UINT_MAX;
629         } else {
630                 while (count <= num_bytes) {
631                         max_value *= 10;
632                         count++;
633                 }
634                 DBG("max_value[%u]\n", max_value);
635         }
636
637         buf = (mtp_char *)g_malloc(new_path_buf_len);
638         if (buf == NULL) {
639                 ERR("g_malloc Fail");
640                 return FALSE;
641         }
642         g_strlcpy(buf, exist_path, new_path_buf_len);
643         while (val < max_value) {
644                 /* Including NUL and '_' */
645                 g_snprintf(&buf[len], num_bytes + 2, "_%u", val++);
646                 if (access(buf, F_OK) < 0)
647                         goto SUCCESS;
648         }
649
650         g_free(buf);
651         ERR("Unable to generate Unique Dir Name");
652         return FALSE;
653
654 SUCCESS:
655         g_strlcpy(new_path, buf, new_path_buf_len);
656         g_free(buf);
657         DBG_SECURE("Unique dir name[%s]\n", new_path);
658         return TRUE;
659 }
660
661 mtp_int32 _util_system_cmd_wait(const mtp_char *cmd)
662 {
663
664         int pid = 0;
665         int status = 0;
666
667         if (cmd == NULL)
668                 return -1;
669
670         pid = fork();
671
672         if (pid == -1)
673                 return -1;
674
675         if (pid == 0) {
676                 char *argv[4];
677                 argv[0] = "sh";
678                 argv[1] = "-c";
679                 argv[2] = (char*)cmd;
680                 argv[3] = 0;
681                 execv("/bin/sh", argv);
682                 exit(127);
683         }
684
685         do {
686                 if (waitpid(pid, &status, 0) == -1) {
687                         if (errno != EINTR)
688                                 return -1;
689                 } else {
690                         return status;
691                 }
692         } while (1);
693 }
694 /* LCOV_EXCL_STOP */