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