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