ec3f2c75128323ec4e84cd56828a100ff472763c
[platform/core/connectivity/mtp-responder.git] / src / util / mtp_fs.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 #define __USE_STDIO__
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <sys/vfs.h>
23 #include <sys/sendfile.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <dirent.h>
27 #include <glib.h>
28 #include <glib/gprintf.h>
29 #include <storage.h>
30 #include "mtp_fs.h"
31 #include "mtp_util.h"
32 #include "mtp_support.h"
33 #include "ptp_datacodes.h"
34 #include "mtp_device.h"
35
36 /*
37  * FUNCTIONS
38  */
39
40 /*
41  * mtp_uint32 _util_file_open(const mtp_char *filename,
42  *      file_mode_t mode, mtp_int32 *error)
43  * This function opens the file in specific mode.
44  *
45  * @param[in]   filename        Specifies the name of file to open.
46  * @param[in]   mode            Specifies the mode of file to open.
47  * @param[out]  error           Specifies the type of error
48  * @return      This function returns the file handle  on success,
49  or INVALID_FILE on failure
50  */
51 FILE* _util_file_open(const mtp_char *filename, file_mode_t mode,
52                 mtp_int32 *error)
53 {
54 #ifdef __USE_STDIO__
55         FILE *fhandle = NULL;
56         char *fmode = NULL;
57
58         switch ((int)mode) {
59         case MTP_FILE_READ:
60                 fmode = "rm";
61                 break;
62
63         case MTP_FILE_WRITE:
64 /* LCOV_EXCL_START */
65                 fmode = "w";
66                 break;
67
68         case MTP_FILE_APPEND:
69                 fmode = "a";
70                 break;
71
72         case MTP_FILE_READ | MTP_FILE_WRITE:
73                 fmode = "r+";
74                 break;
75
76         case MTP_FILE_READ | MTP_FILE_WRITE | MTP_FILE_APPEND:
77                 fmode = "a+";
78                 break;
79
80         default:
81                 ERR("Invalid mode : %d\n", mode);
82                 *error = EINVAL;
83                 return NULL;
84         }
85 /* LCOV_EXCL_STOP */
86
87         fhandle = fopen(filename, fmode);
88         if (fhandle == NULL) {
89                 ERR("File open Fail:mode[0x%x], errno [%d]\n", mode, errno);
90                 ERR_SECURE("filename[%s]\n", filename);
91                 *error = errno;
92                 return NULL;
93         }
94
95         /* LCOV_EXCL_START*/
96         fcntl(fileno(fhandle), F_SETFL, O_NOATIME);
97
98         return fhandle;
99
100 #else /* __USE_STDIO__ */
101
102         mtp_int32 fhandle = 0;
103         mtp_int32 flags = 0;
104         mode_t perm = 0;
105
106         switch ((int)mode) {
107         case MTP_FILE_READ:
108                 flags = O_RDONLY;
109                 break;
110
111         case MTP_FILE_WRITE:
112                 flags = O_WRONLY | O_CREAT | O_TRUNC;
113                 perm = 0644;
114                 break;
115
116         case MTP_FILE_APPEND:
117                 flags = O_WRONLY | O_APPEND | O_CREAT;
118                 perm = 0644;
119                 break;
120
121         case MTP_FILE_READ | MTP_FILE_WRITE:
122                 flags = O_RDWR;
123                 break;
124
125         case MTP_FILE_READ | MTP_FILE_WRITE | MTP_FILE_APPEND:
126                 flags = O_RDWR | O_APPEND | O_CREAT;
127                 perm = 0644;
128                 break;
129
130         default:
131                 ERR("Invalid mode : %d\n", mode);
132                 *error = EINVAL;
133                 return NULL;
134         }
135
136         if (perm)
137                 fhandle = open(filename, flags, perm);
138         else
139                 fhandle = open(filename, flags);
140
141         if (fhandle < 0) {
142                 ERR("File open Fail:mode[0x%x], errno [%d]\n", mode, errno);
143                 ERR_SECURE("filename[%s]\n", filename);
144                 *error = errno;
145                 return NULL;
146         }
147
148         return fhandle;
149 #endif /* __USE_STDIO__ */
150 }
151
152 /*
153  * void _util_file_read(mtp_uint32 handle, void *bufptr, mtp_uint32 size,
154  *      mtp_uint32 *preadcount)
155  *
156  * This function reads data from the file handle into the data buffer.
157  *
158  * @param[in]   handle          Specifies the handle of file to read.
159  * @param[out]  bufptr          Points to buff where data is to be read.
160  * @param[in]   size            Specifies the num bytes to be read.
161  * @param[out]  preadcount      Will store the actual num bytes read.
162  * @return      None
163  */
164 void _util_file_read(FILE* fhandle, void *bufptr, mtp_uint32 size,
165                 mtp_uint32 *read_count)
166 {
167         mtp_uint32 bytes_read = 0;
168
169 #ifdef __USE_STDIO__
170         bytes_read = fread_unlocked(bufptr, sizeof(mtp_char), size, fhandle);
171 #else /* __USE_STDIO__ */
172         bytes_read = read(fhandle, bufptr, size);
173 #endif /* __USE_STDIO__ */
174
175         *read_count = bytes_read;
176 }
177 /**
178  * mtp_uint32 _util_file_write(mtp_uint32 fhandle, void *bufptr, mtp_uint32 size)
179  *
180  * This function writes data to the file using the data buffer passed.
181  *
182  * @param[in]   handle  Specifies the handle of file to write.
183  * @param[in]   bufptr  Points the buffer which holds the data.
184  * @param[in]   size    Specifies num bytes to be written.
185  * @return      This function returns num bytes written.
186  */
187
188 mtp_uint32 _util_file_write(FILE* fhandle, void *bufptr, mtp_uint32 size)
189 {
190         mtp_uint32 bytes_written = 0;
191
192 #ifdef __USE_STDIO__
193         bytes_written = fwrite_unlocked(bufptr, sizeof(mtp_char), size, fhandle);
194 #else /* __USE_STDIO__ */
195         mtp_int32 ret = 0;
196
197         ret = write(fhandle, bufptr, size);
198         if (ret < 0)
199                 ret = 0;
200
201         bytes_written = ret;
202 #endif /* __USE_STDIO__ */
203
204         return bytes_written;
205 }
206
207 /**
208  * mtp_int32 _util_file_close(mtp_uint32 fhandle)
209  * This function closes the file.
210  *
211  * @param[in]   handle  Specifies the handle of file to close.
212  * @return      0 in case of success or EOF on failure.
213  */
214 mtp_int32 _util_file_close(FILE* fhandle)
215 {
216 #ifdef __USE_STDIO__
217         return fclose(fhandle);
218 #else /* __USE_STDIO__ */
219         return close(fhandle);
220 #endif /* __USE_STDIO__ */
221 }
222
223 /*
224  * This function seeks to a particular location in a file.
225  *
226  * @param[in]   handle          Specifies the handle of file to seek.
227  * @param[in]   offset          Specifies the starting point.
228  * @param[in]   whence          Specifies the setting value
229  * @return      Returns TRUE in case of success or FALSE on Failure.
230  */
231 mtp_bool _util_file_seek(FILE* handle, off_t offset, mtp_int32 whence)
232 {
233         mtp_int64 ret_val = 0;
234
235 #ifdef __USE_STDIO__
236         ret_val = fseek(handle, offset, whence);
237 #else /* __USE_STDIO__ */
238         ret_val = lseek(handle, offset, whence);
239         if (ret_val > 0)
240                 ret_val = 0;
241 #endif /* __USE_STDIO__ */
242         if (ret_val < 0) {
243                 ERR(" _util_file_seek error errno [%d]\n", errno);
244                 return FALSE;
245         }
246
247         return TRUE;
248 }
249
250 mtp_bool _util_file_copy(const mtp_char *origpath, const mtp_char *newpath,
251                 mtp_int32 *error)
252 {
253 #ifdef __USE_STDIO__
254         FILE *fold = NULL;
255         FILE *fnew = NULL;
256         size_t nmemb = 0;
257         mtp_int32 ret = 0;
258         mtp_char buf[BUFSIZ] = { 0 };
259
260         if ((fold = fopen(origpath, "rb")) == NULL) {
261                 ERR("In-file open Fail errno [%d]\n", errno);
262                 *error = errno;
263                 return FALSE;
264         }
265
266         if ((fnew = fopen(newpath, "wb")) == NULL) {
267                 ERR("Out-file open Fail errno [%d]\n", errno);
268                 *error = errno;
269                 fclose(fold);
270                 return FALSE;
271         }
272
273         do {
274                 nmemb = fread(buf, sizeof(mtp_char), BUFSIZ, fold);
275                 if (nmemb < BUFSIZ && ferror(fold)) {
276                         ERR("fread Fail errno [%d] \n", errno);
277                         *error = errno;
278                         fclose(fnew);
279                         fclose(fold);
280                         if (remove(newpath) < 0)
281                                 ERR("Remove Fail");
282                         return FALSE;
283                 }
284
285                 ret = fwrite(buf, sizeof(mtp_char), nmemb, fnew);
286                 if (ret < nmemb && ferror(fnew)) {
287                         ERR("fwrite Fail errno [%d]\n", errno);
288                         *error = errno;
289                         fclose(fnew);
290                         fclose(fold);
291                         if (remove(newpath) < 0)
292                                 ERR("Remove Fail");
293                         return FALSE;
294                 }
295         } while (!feof(fold));
296
297         fclose(fnew);
298         fclose(fold);
299 #else /* __USE_STDIO__ */
300         mtp_int32 in_fd = 0;
301         mtp_int32 out_fd = 0;
302         mtp_int32 ret = 0;
303         off_t offset = 0;
304
305         if ((in_fd = open(origpath, O_RDONLY)) < 0) {
306                 ERR("In-file open Fail, errno [%d]\n", errno);
307                 *error = errno;
308                 return FALSE;
309         }
310
311         if ((out_fd = open(newpath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) {
312                 ERR("Out-file open Fail errno [%d] \n", errno);
313                 *error = errno;
314                 close(in_fd);
315                 return FALSE;
316         }
317
318         do {
319                 ret = sendfile(out_fd, in_fd, &offset, BUFSIZ);
320                 if (ret < 0) {
321                         ERR("sendfile Fail errno [%d]\n", errno);
322                         *error = errno;
323                         close(out_fd);
324                         close(in_fd);
325                         if (remove(newpath) < 0)
326                                 ERR("Remove Fail");
327                         return FALSE;
328                 }
329         } while (ret == BUFSIZ);
330
331         close(out_fd);
332         close(in_fd);
333 #endif /* __USE_STDIO__ */
334
335         return TRUE;
336 }
337
338 mtp_bool _util_copy_dir_children_recursive(const mtp_char *origpath,
339                 const mtp_char *newpath, mtp_uint32 store_id, mtp_int32 *error)
340 {
341         DIR *dir = NULL;
342         struct dirent entry = { 0 };
343         struct dirent *entryptr = NULL;
344         mtp_int32 retval = 0;
345         mtp_char old_pathname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
346         mtp_char new_pathname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
347         struct stat entryinfo;
348
349         retv_if(origpath == NULL, FALSE);
350         retv_if(newpath == NULL, FALSE);
351
352         /* Open the given directory */
353         dir = opendir(origpath);
354         if (dir == NULL) {
355                 ERR("opendir(%s) Fail", origpath);
356                 _util_print_error();
357                 return FALSE;
358         }
359
360         retval = readdir_r(dir, &entry, &entryptr);
361
362         while (retval == 0 && entryptr != NULL) {
363                 /* Skip the names "." and ".." as we don't want to recurse on them. */
364                 if (!g_strcmp0(entry.d_name, ".") ||
365                                 !g_strcmp0(entry.d_name, "..")) {
366                         retval = readdir_r(dir, &entry, &entryptr);
367                         continue;
368                 }
369                 g_snprintf(old_pathname, MTP_MAX_PATHNAME_SIZE + 1,
370                                 "%s/%s", origpath, entry.d_name);
371                 g_snprintf(new_pathname, MTP_MAX_PATHNAME_SIZE + 1,
372                                 "%s/%s", newpath, entry.d_name);
373
374                 if (stat(old_pathname, &entryinfo) != 0) {
375                         ERR("Error statting [%s] errno [%d]\n", old_pathname, errno);
376                         closedir(dir);
377                         return FALSE;
378                 }
379
380                 /* Create new mtp object */
381                 mtp_store_t *store = _device_get_store(store_id);
382                 if (store == NULL) {
383                         ERR("store is NULL");
384                         closedir(dir);
385                         return FALSE;
386                 }
387
388                 mtp_obj_t *orig_obj = _entity_get_object_from_store_by_path(store, old_pathname);
389                 if (orig_obj == NULL) {
390                         ERR("orig_obj is NULL");
391                         closedir(dir);
392                         return FALSE;
393                 }
394
395                 mtp_obj_t *parent_obj = _entity_get_object_from_store_by_path(store, newpath);
396                 if (parent_obj == NULL) {
397                         ERR("orig_obj is NULL");
398                         closedir(dir);
399                         return FALSE;
400                 }
401
402                 mtp_obj_t *new_obj = _entity_alloc_mtp_object();
403                 if (new_obj == NULL) {
404                         ERR("_entity_alloc_mtp_object Fail");
405                         closedir(dir);
406                         return FALSE;
407                 }
408
409                 memset(new_obj, 0, sizeof(mtp_obj_t));
410
411                 new_obj->child_array.type = UINT32_TYPE;
412                 _entity_copy_mtp_object(new_obj, orig_obj);
413                 if (new_obj->obj_info == NULL) {
414                         _entity_dealloc_mtp_obj(new_obj);
415                         closedir(dir);
416                         return FALSE;
417                 }
418
419                 _entity_set_object_file_path(new_obj, new_pathname, CHAR_TYPE);
420                 new_obj->obj_handle = _entity_generate_next_obj_handle();
421                 new_obj->obj_info->h_parent = parent_obj->obj_handle;
422
423                 if (S_ISDIR(entryinfo.st_mode)) {
424                         if (FALSE == _util_dir_create(new_pathname, error)) {
425                                 /* dir already exists
426                                    merge the contents */
427                                 if (EEXIST != *error) {
428                                         ERR("directory[%s] create Fail errno [%d]\n", new_pathname, errno);
429                                         _entity_dealloc_mtp_obj(new_obj);
430                                         closedir(dir);
431                                         return FALSE;
432                                 }
433                         }
434
435                         /* The directory is created. Add object to mtp store */
436                         _entity_add_object_to_store(store, new_obj);
437
438                         if (FALSE == _util_copy_dir_children_recursive(old_pathname,
439                                                 new_pathname, store_id, error)) {
440                                 ERR("Recursive Copy of Children Fail\
441                                                 [%s]->[%s], errno [%d]\n", old_pathname, new_pathname, errno);
442                                 closedir(dir);
443                                 return FALSE;
444                         }
445                 } else {
446                         if (FALSE == _util_file_copy(old_pathname, new_pathname, error)) {
447                                 ERR("file copy fail [%s]->[%s]\n",
448                                                 old_pathname, new_pathname);
449                                 /* Cannot overwrite a read-only file,
450                                    Skip copy and retain the read-only file
451                                    on destination */
452                                 if (EACCES == *error)
453                                         goto DONE;
454                                 _entity_dealloc_mtp_obj(new_obj);
455                                 closedir(dir);
456                                 return FALSE;
457                         }
458 #ifdef MTP_SUPPORT_SET_PROTECTION
459                         mtp_bool ret = FALSE;
460
461                         if (!((S_IWUSR & entryInfo.st_mode) ||
462                                                 (S_IWGRP & entryInfo.st_mode) ||
463                                                 (S_IWOTH & entryInfo.st_mode))) {
464                                 ret = _util_set_file_attrs(newPathName,
465                                                 MTP_FILE_ATTR_MODE_REG |
466                                                 MTP_FILE_ATTR_MODE_READ_ONLY);
467                                 if (!ret) {
468                                         ERR("Failed to set directory attributes errno [%d]\n", errno);
469                                         _entity_dealloc_mtp_obj(new_obj);
470                                         closedir(dir);
471                                         return FALSE;
472                                 }
473                         }
474 #endif /* MTP_SUPPORT_SET_PROTECTION */
475                         /* The file is created. Add object to mtp store */
476                         _entity_add_object_to_store(store, new_obj);
477                 }
478 DONE:
479                 retval = readdir_r(dir, &entry, &entryptr);
480         }
481
482         closedir(dir);
483         return (retval == 0) ? TRUE : FALSE;
484 }
485
486 mtp_bool _util_file_move(const mtp_char *origpath, const mtp_char *newpath,
487                 mtp_int32 *error)
488 {
489         mtp_int32 ret = 0;
490
491         ret = rename(origpath, newpath);
492         if (ret < 0) {
493                 if (errno == EXDEV) {
494                         DBG("oldpath  and  newpath  are not on the same\
495                                         mounted file system.");
496                         if (_util_file_copy(origpath, newpath, error) == FALSE) {
497                                 ERR("_util_file_copy Fail errno [%d]\n", errno);
498                                 return FALSE;
499                         }
500                         if (remove(origpath) < 0) {
501                                 ERR("remove Fail : %d\n", errno);
502                                 return FALSE;
503                         }
504                 } else {
505                         ERR("rename Fail : %d\n", errno);
506                         *error = errno;
507                         return FALSE;
508                 }
509         }
510
511         return TRUE;
512 }
513
514 mtp_bool _util_is_file_opened(const mtp_char *fullpath)
515 {
516         mtp_int32 ret = 0;
517
518         ret = rename(fullpath, fullpath);
519         return (ret != 0);
520 }
521
522 mtp_bool _util_dir_create(const mtp_char *dirname, mtp_int32 *error)
523 {
524
525         if (mkdir(dirname, S_IRWXU | S_IRGRP |
526                                 S_IXGRP | S_IROTH | S_IXOTH) < 0) {
527                 *error = errno;
528                 return FALSE;
529         }
530         return TRUE;
531 }
532
533 mtp_int32 _util_remove_dir_children_recursive(const mtp_char *dirname,
534                 mtp_uint32 *num_of_deleted_file, mtp_uint32 *num_of_file, mtp_bool breadonly)
535 {
536         retv_if(dirname == NULL, FALSE);
537
538         DIR *dir = NULL;
539         struct dirent entry = { 0 };
540         struct dirent *entryptr = NULL;
541         mtp_int32 retval = 0;
542         mtp_char pathname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
543         struct stat entryinfo;
544         mtp_int32 ret = MTP_ERROR_NONE;
545
546         /* Open the given directory */
547         dir = opendir(dirname);
548         if (dir == NULL) {
549                 ERR("Open directory Fail[%s], errno [%d]", dirname, errno);
550                 return MTP_ERROR_GENERAL;
551         }
552
553         retval = readdir_r(dir, &entry, &entryptr);
554
555         while (retval == 0 && entryptr != NULL) {
556                 /* Skip the names "." and ".."
557                    as we don't want to recurse on them. */
558                 if (!g_strcmp0(entry.d_name, ".") ||
559                                 !g_strcmp0(entry.d_name, "..")) {
560                         retval = readdir_r(dir, &entry, &entryptr);
561                         continue;
562                 }
563                 g_snprintf(pathname, MTP_MAX_PATHNAME_SIZE + 1,
564                                 "%s/%s", dirname, entry.d_name);
565                 if (stat(pathname, &entryinfo) != 0) {
566                         ERR("Error statting %s errno [%d]\n", pathname, errno);
567                         closedir(dir);
568                         return MTP_ERROR_GENERAL;
569                 }
570                 *num_of_file += 1;
571                 if (S_ISDIR(entryinfo.st_mode)) {
572                         ret = _util_remove_dir_children_recursive(pathname,
573                                         num_of_deleted_file, num_of_file, breadonly);
574                         if (MTP_ERROR_GENERAL == ret || MTP_ERROR_ACCESS_DENIED == ret) {
575                                 ERR("deletion fail [%s]\n", pathname);
576                                 closedir(dir);
577                                 return ret;
578                         }
579                         if (MTP_ERROR_OBJECT_WRITE_PROTECTED == ret) {
580                                 DBG("Folder[%s] contains read-only files,hence\
581                                                 folder is not deleted\n", pathname);
582                                 /* Read the next entry */
583                                 goto DONE;
584                         }
585                         if (rmdir(pathname) < 0) {
586                                 ERR("deletion fail [%s], errno [%d]\n", pathname, errno);
587                                 closedir(dir);
588                                 if (EACCES == errno)
589                                         return MTP_ERROR_ACCESS_DENIED;
590                                 return MTP_ERROR_GENERAL;
591                         }
592                         *num_of_deleted_file += 1;
593                 } else {
594                         /* Only during Deleteobject, bReadOnly(TRUE)
595                            do not delete read-only files */
596 #ifdef MTP_SUPPORT_SET_PROTECTION
597                         if (breadonly) {
598                                 /* check for file attributes */
599                                 if (!((S_IWUSR & entryinfo.st_mode) ||
600                                                         (S_IWGRP & entryinfo.st_mode) ||
601                                                         (S_IWOTH & entryinfo.st_mode))) {
602                                         ret = MTP_ERROR_OBJECT_WRITE_PROTECTED;
603                                         DBG("File [%s] is readOnly:Deletion Fail\n", pathname);
604                                         goto DONE;
605                                 }
606                         }
607 #endif /* MTP_SUPPORT_SET_PROTECTION */
608                         if (unlink(pathname) < 0) {
609                                 ERR("deletion fail [%s], errno [%d]\n", pathname, errno);
610                                 closedir(dir);
611                                 if (EACCES == errno)
612                                         return MTP_ERROR_ACCESS_DENIED;
613                                 return MTP_ERROR_GENERAL;
614                         }
615                         *num_of_deleted_file += 1;
616                 }
617 DONE:
618                 retval = readdir_r(dir, &entry, &entryptr);
619                 if (retval != 0) {
620                         closedir(dir);
621                         return MTP_ERROR_GENERAL;
622                 }
623         }
624
625         closedir(dir);
626         return ret;
627 }
628 /* LCOV_EXCL_STOP */
629
630 /*
631  * mtp_bool _util_get_file_attrs(const mtp_char *filename, file_attr_t *attrs)
632  * This function gets the file attributes.
633  *
634  * @param[in]           filename        Specifies the name of file to find.
635  * @param[out]          attrs           Points the file Attributes.
636  * @return              This function returns TRUE if gets the attributes
637  *                      successfully, otherwise FALSE.
638  */
639 mtp_bool _util_get_file_attrs(const mtp_char *filename, file_attr_t *attrs)
640 {
641         struct stat fileinfo = { 0 };
642
643         if (stat(filename, &fileinfo) < 0) {
644                 ERR_SECURE("%s : stat Fail errno [%d]\n", filename, errno);
645                 return FALSE;
646         }
647
648         memset(attrs, 0, sizeof(file_attr_t));
649         attrs->fsize = (mtp_uint64)fileinfo.st_size;
650         attrs->ctime = fileinfo.st_ctime;
651         attrs->mtime = fileinfo.st_mtime;
652
653         /*Reset attribute mode */
654         attrs->attribute = MTP_FILE_ATTR_MODE_NONE;
655         if (S_ISREG(fileinfo.st_mode)) {
656                 /* LCOV_EXCL_START */
657                 attrs->attribute |= MTP_FILE_ATTR_MODE_REG;
658                 if (!((S_IWUSR & fileinfo.st_mode) ||
659                                         (S_IWGRP & fileinfo.st_mode) ||
660                                         (S_IWOTH & fileinfo.st_mode))) {
661                         attrs->attribute |= MTP_FILE_ATTR_MODE_READ_ONLY;
662                 }
663         } else if (S_ISDIR(fileinfo.st_mode)) {
664                 attrs->attribute |= MTP_FILE_ATTR_MODE_DIR;
665         } else if (S_ISBLK(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
666                         S_ISLNK(fileinfo.st_mode) || S_ISSOCK(fileinfo.st_mode)) {
667                 attrs->attribute |= MTP_FILE_ATTR_MODE_SYSTEM;
668         }
669         return TRUE;
670 }
671
672 mtp_bool _util_set_file_attrs(const mtp_char *filename, mtp_dword attrib)
673 {
674         mtp_dword attrs = 0;
675
676         if (MTP_FILE_ATTR_MODE_REG & attrib) {
677                 /*Reqular file */
678                 if (MTP_FILE_ATTR_MODE_READ_ONLY & attrib)
679                         attrs |= (S_IRUSR | S_IRGRP | S_IROTH);
680                 else
681                         attrs |= (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
682         } else {
683                 /* do nothing for files other than File/Folder */
684                 DBG("entered here nothing");
685                 return FALSE;
686         }
687
688         if (0 != chmod(filename, attrs)) {
689                 if (EPERM == errno)
690                         return TRUE;
691                 ERR_SECURE("Change mode of [File : %s] Fail\n", filename);
692                 _util_print_error();
693                 return FALSE;
694         }
695         return TRUE;
696 }
697 /* LCOV_EXCL_STOP */
698
699 /*
700  * mtp_bool _util_ifind_first(mtp_char *dirname, DIR **dirp,
701  *      dir_entry_t *dir_info)
702  * This function finds the first file in the directory stream.
703  *
704  * @param[in]           dirname         specifies the name of directory.
705  * @param[out]          dirp            pointer to the directory stream.
706  * @param[in]           dir_info        pointer to the file information.
707  * @return              This function returns TRUE on success, otherwise FALSE.
708  */
709 mtp_bool _util_ifind_first(mtp_char *dirname, DIR **dirp, dir_entry_t *dir_info)
710 {
711         DIR *dir;
712
713         retv_if(dirp == NULL, FALSE);
714         retv_if(dirname == NULL, FALSE);
715         retv_if(dir_info == NULL, FALSE);
716
717         dir = opendir(dirname);
718         if (NULL == dir) {
719                 /* LCOV_EXCL_START */
720                 ERR("opendir(%s) Fail", dirname);
721                 _util_print_error();
722
723                 return FALSE;
724         }
725
726         if (_util_ifind_next(dirname, dir, dir_info) == FALSE) {
727                 DBG("Stop enumeration");
728                 _util_print_error();
729                 closedir(dir);
730                 return FALSE;
731                 /* LCOV_EXCL_STOP */
732         }
733
734         *dirp = dir;
735
736         return TRUE;
737 }
738
739 /*
740  * mtp_bool _util_ifind_next(mtp_char *dirname, DIR *dirp, dir_entry_t *dir_info)
741  * This function finds the next successive file in the directory stream.
742  *
743  * @param[in]           dirname         name of the directory.
744  * @param[in]           dirp            pointer to the directory stream.
745  * @param[out]          dir_info        Points the file information.
746  * @return              This function returns TRUE on success, otherwise FALSE.
747  */
748 mtp_bool _util_ifind_next(mtp_char *dir_name, DIR *dirp, dir_entry_t *dir_info)
749 {
750         mtp_int32 ret = 0;
751         struct dirent entry = {0};
752         struct stat stat_buf = {0};
753         struct dirent *result = NULL;
754         mtp_char path_name[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
755
756         retv_if(dir_name == NULL, FALSE);
757         retv_if(dir_info == NULL, FALSE);
758
759         do {
760                 ret = readdir_r(dirp, &entry, &result);
761                 if (ret != 0) {
762                         ERR("readdir_r Fail : %d\n", ret);
763                         return FALSE;
764                 } else if (result == NULL) {
765                         DBG("There is no more entry");
766                         return FALSE;
767                 }
768
769                 if (_util_create_path(path_name, sizeof(path_name),
770                                         dir_name, entry.d_name) == FALSE) {
771                         continue;
772                 }
773
774                 if (stat(path_name, &stat_buf) < 0) {
775                         ERR_SECURE("stat Fail, skip [%s]\n", path_name);
776                         continue;
777                 }
778                 break;
779         } while (1);
780
781         g_strlcpy(dir_info->filename, path_name, sizeof(dir_info->filename));
782         dir_info->attrs.attribute = MTP_FILE_ATTR_MODE_NONE;
783
784         switch (stat_buf.st_mode & S_IFMT) {
785         case S_IFREG:
786                 dir_info->type = MTP_FILE_TYPE;
787                 if (!(stat_buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
788                         dir_info->attrs.attribute |= MTP_FILE_ATTR_MODE_READ_ONLY;
789                 break;
790
791         case S_IFDIR:
792                 dir_info->type = MTP_DIR_TYPE;
793                 dir_info->attrs.attribute = MTP_FILE_ATTR_MODE_DIR;
794                 break;
795
796         case S_IFBLK:
797         case S_IFCHR:
798         case S_IFIFO:
799         case S_IFLNK:
800         case S_IFSOCK:
801         /* LCOV_EXCL_START */
802                 dir_info->attrs.attribute |= MTP_FILE_ATTR_MODE_SYSTEM;
803                 break;
804
805         default:
806                 dir_info->attrs.attribute |= MTP_FILE_ATTR_MODE_SYSTEM;
807                 ERR_SECURE("%s has unknown type. mode[0x%x]\n",
808                                 dir_info->filename, stat_buf.st_mode);
809                 break;
810                 /* LCOV_EXCL_STOP */
811         }
812
813         /* Directory Information */
814         dir_info->attrs.mtime = stat_buf.st_mtime;
815         dir_info->attrs.fsize = (mtp_uint64)stat_buf.st_size;
816
817         return TRUE;
818 }
819
820 /* LCOV_EXCL_START */
821 mtp_bool _util_get_filesystem_info_ext(mtp_char *storepath,
822         fs_info_t *fs_info)
823 {
824         struct statfs buf = { 0 };
825         mtp_uint64 avail_size = 0;
826         mtp_uint64 capacity = 0;
827         mtp_uint64 used_size = 0;
828
829         if (statfs(storepath, &buf) != 0) {
830                 ERR("statfs is failed\n");
831                 return FALSE;
832         }
833
834         capacity = used_size = avail_size = (mtp_uint64)buf.f_bsize;
835         DBG("Block size : %lu\n", (unsigned long)buf.f_bsize);
836         capacity *= buf.f_blocks;
837         used_size *= (buf.f_blocks - buf.f_bavail);
838         avail_size *= buf.f_bavail;
839
840         fs_info->disk_size = capacity;
841         fs_info->reserved_size = used_size;
842         fs_info->avail_size = avail_size;
843
844         return TRUE;
845 }
846 /* LCOV_EXCL_STOP */
847
848 mtp_bool _util_get_filesystem_info_int(mtp_char *storepath, fs_info_t *fs_info)
849 {
850         struct statvfs s;
851         int ret;
852
853         mtp_uint64 avail_size = 0;
854         mtp_uint64 capacity = 0;
855         mtp_uint64 used_size = 0;
856
857         ret = storage_get_internal_memory_size(&s);
858         if (ret < 0) {
859                 ERR("storage_get_internal_memory_size : ret = %d", ret);
860                 return FALSE;
861         }
862
863         capacity = (mtp_uint64)s.f_frsize*s.f_blocks;
864         avail_size = (mtp_uint64)s.f_bsize*s.f_bavail;
865         used_size = (capacity - avail_size);
866
867         DBG("total : %llu , avail %llu , used %llu", capacity, avail_size, used_size);
868
869         fs_info->disk_size = capacity;
870         fs_info->reserved_size = used_size;
871         fs_info->avail_size = avail_size;
872
873         return TRUE;
874 }
875
876 mtp_bool _util_get_filesystem_info(mtp_char *storepath,
877         fs_info_t *fs_info)
878 {
879         if (!g_strcmp0(storepath, MTP_EXTERNAL_PATH_CHAR))
880                 return _util_get_filesystem_info_ext(storepath, fs_info);
881         else
882                 return _util_get_filesystem_info_int(storepath, fs_info);
883
884         return FALSE;
885 }
886
887 /* LCOV_EXCL_START */
888 void _util_count_num_lines(FILE* fhandle, mtp_uint32 *num_lines)
889 {
890         if (fhandle == NULL)
891                 return;
892
893         mtp_uint32 line_count = 0;
894         mtp_char *buffer = NULL;
895         mtp_int32 read_bytes;
896         mtp_uint32 line_max_length;
897
898         line_max_length = LINUX_MAX_PATHNAME_LENGTH + 2;
899         buffer = (mtp_char *)g_malloc(line_max_length);
900         if (buffer == NULL) {
901                 ERR("Malloc Fail");
902                 return;
903         }
904
905 #ifdef __USE_STDIO__
906         while ((read_bytes = getline(&buffer,
907                                         (size_t *)&line_max_length, fhandle)) != -1) {
908                 if (read_bytes > MTP_MAX_PATHNAME_SIZE + 1)
909                         continue;
910                 line_count++;
911         }
912 #else /* __USE_STDIO__ */
913
914         mtp_uint16 ii = 0;
915         mtp_uint32 prev_pos = -1;
916         mtp_uint32 new_pos;
917         mtp_uint32 filename_len = 0;
918         while ((read_bytes = read(fhandle, buffer, LINUX_MAX_PATHNAME_LENGTH)) > 0) {
919                 for (ii = 0; ii < read_bytes; ii++) {
920                         if (buffer[ii] != '\n')
921                                 continue;
922                         new_pos = ii;
923                         filename_len = new_pos - prev_pos -1;
924                         prev_pos = new_pos;
925                         if (filename_len > MTP_MAX_PATHNAME_SIZE)
926                                 continue;
927                         line_count++;
928                 }
929                 if (buffer[read_bytes - 1] != '\n')
930                         _util_file_seek(fhandle, prev_pos + 1 - read_bytes, SEEK_CUR);
931
932                 prev_pos = -1;
933         }
934 #endif /* __USE_STDIO__ */
935
936         *num_lines = line_count;
937         g_free(buffer);
938         return;
939 }
940
941 void _util_fill_guid_array(void *guidarray, mtp_uint32 start_index,
942                 FILE* fhandle, mtp_uint32 size)
943 {
944         ptp_array_t *pguidarray = NULL;
945         mtp_uint32 *guidptr = NULL;
946         mtp_uint32 num_lines = 0;
947         mtp_wchar objfullpath[MTP_MAX_PATHNAME_SIZE * 2 + 1] = { 0 };
948         mtp_char guid[16] = { 0 };
949         mtp_char *buffer = NULL;
950         mtp_uint32 line_max_length;
951         mtp_uint32 len = 0;
952
953         line_max_length = LINUX_MAX_PATHNAME_LENGTH + 2;
954         pguidarray = (ptp_array_t *)guidarray;
955         guidptr = (mtp_uint32 *)(pguidarray->array_entry);
956
957         buffer = (mtp_char *)g_malloc(line_max_length);
958         if (buffer == NULL) {
959                 ERR("Malloc Fail");
960                 return;
961         }
962
963 #ifdef __USE_STDIO__
964         while ((len = getline(&buffer, (size_t *)&line_max_length, fhandle)) != -1 &&
965                         (num_lines - start_index) <= size) {
966                 if (len > MTP_MAX_PATHNAME_SIZE + 1)
967                         continue;
968                 num_lines++;
969                 if (num_lines < start_index)
970                         continue;
971                 buffer[len - 1] = '\0';
972                 _util_utf8_to_utf16(objfullpath,
973                                 sizeof(objfullpath) / WCHAR_SIZ, buffer);
974                 _util_conv_wstr_to_guid(objfullpath, (mtp_uint64 *)guid);
975                 memcpy(&(guidptr[pguidarray->num_ele]),
976                                 guid, sizeof(guid));
977                 pguidarray->num_ele += sizeof(mtp_uint32);
978         }
979 #else /* __USE_STDIO__ */
980         mtp_uint16 ii = 0;
981         mtp_uint32 prev_pos = -1;
982         mtp_uint32 new_pos;
983         mtp_char file_name[MTP_MAX_PATHNAME_SIZE + 1];
984         mtp_int32 read_bytes;
985
986         while ((read_bytes = read(fhandle, buffer,
987                                         LINUX_MAX_PATHNAME_LENGTH)) > 0 &&
988                         (num_lines - start_index) <= size) {
989
990                 for (ii = 0; ii < read_bytes; ii++) {
991                         if (buffer[ii] != '\n')
992                                 continue;
993                         new_pos = ii;
994                         len = new_pos - prev_pos - 1;
995                         prev_pos = new_pos;
996                         if (len > MTP_MAX_PATHNAME_SIZE)
997                                 continue;
998                         num_lines++;
999                         if (num_lines < start_index)
1000                                 continue;
1001                         strncpy(file_name, &buffer[new_pos - len], len);
1002                         file_name[len] = '\0';
1003                         _util_utf8_to_utf16(objfullpath,
1004                                         sizeof(objfullpath) / WCHAR_SIZ, file_name);
1005                         _util_conv_wstr_to_guid(objfullpath, (mtp_uint64 *)guid);
1006                         memcpy(&(guidptr[pguidarray->num_elements]),
1007                                         guid, sizeof(guid));
1008                         pguidarray->num_elements += sizeof(mtp_uint32);
1009                 }
1010
1011                 if (buffer[read_bytes - 1] != '\n')
1012                         _util_file_seek(fhandle, prev_pos + 1 - read_bytes, SEEK_CUR);
1013
1014                 prev_pos = -1;
1015         }
1016 #endif /* __USE_STDIO__ */
1017
1018         g_free(buffer);
1019
1020         return;
1021 }
1022
1023 /*
1024  * void FLOGD(const char *fmt, ...)
1025  * This function writes MTP debug message to MTP log file
1026  *
1027  * @param[in]           fmt Formatted debug message.
1028  * @param[out]          None.
1029  * @return              None.
1030  */
1031 void FLOGD(const char *fmt, ...)
1032 {
1033         static mtp_int64 written_bytes = 0;
1034         FILE *fp = NULL;
1035         va_list ap;
1036
1037         if (written_bytes == 0 || written_bytes > MTP_LOG_MAX_SIZE) {
1038                 fp = fopen(MTP_LOG_FILE, "w");
1039                 written_bytes = 0;
1040         } else {
1041                 fp = fopen(MTP_LOG_FILE, "a+");
1042         }
1043
1044         if (fp == NULL)
1045                 return;
1046
1047         written_bytes += fprintf(fp, "%s ", __FILE__);
1048         va_start(ap, fmt);
1049         written_bytes += vfprintf(fp, fmt, ap);
1050         va_end(ap);
1051
1052         fclose(fp);
1053         return;
1054 }
1055 /* LCOV_EXCL_STOP */