Tizen 2.1 base
[apps/home/myfiles.git] / src / common / file-operation / mf-fo-internal.c
1 /*
2  * Copyright 2013         Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.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://floralicense.org/license/
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
18
19
20 #include <stdio.h>
21 #include <errno.h>
22 #include <sys/stat.h>
23 #include <sys/statfs.h>
24 #include <sys/types.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/syscall.h>        /*__NR_gettid*/
28 #include <unistd.h>
29 #include <ftw.h>
30
31 #include "mf-fo-internal.h"
32 #include "mf-fo-common.h"
33 #include "mf-fo-debug.h"
34
35 GSList *dir_list = NULL;
36 #ifndef SAFE_FREE
37 #define SAFE_FREE(x) do { \
38                                 if ((x) != NULL) {\
39                                         free(x); \
40                                         x = NULL;\
41                                 } \
42                         } while (0)
43 #endif
44
45 #ifndef NAME_MAX
46 #define NAME_MAX 255
47 #endif
48
49 #ifndef FILENAME_MAX
50 #define FILENAME_MAX 4096
51 #endif
52
53 static inline long __mf_fo_get_name_max(void)
54 {
55         long max = 0;
56
57 #ifdef _PC_NAME_MAX
58         max = pathconf("/", _PC_NAME_MAX);
59 #endif
60
61         if (max < 1) {
62                 max = NAME_MAX + 1;
63         }
64
65         return max;
66 }
67
68 static inline long __mf_fo_get_path_max(void)
69 {
70         long max = 0;
71
72 #ifdef _PC_PATH_MAX
73         max = pathconf("/", _PC_PATH_MAX);
74 #endif
75
76         if (max < 1) {
77                 max = FILENAME_MAX;
78         }
79
80         return max;
81 }
82
83 static const char *__mf_fo_get_base_name(const char *path)
84 {
85         const char *base = NULL;
86
87
88         if (path && (path[0] != '\0')) {
89                 char *tmp = NULL;
90                 tmp = strrchr(path, '/');
91                 if (tmp[1] == '\0') {
92                         if (tmp == path) {
93                                 mf_fo_loge("path is ROOT - %s", path);
94                         } else {
95                                 mf_fo_loge("invaild arg - %s", path);
96                         }
97                 } else {
98                         base = tmp + 1;
99                 }
100         }
101         return base;
102 }
103
104 static int __get_directory_hierarchies( const char *pathname, const struct stat *statptr, int type)
105 {
106         mf_fo_dir_list_info *info = NULL;
107         mf_debug("pathname is [%s]\t type is [%d]\t size is [%ld]",
108                 pathname, type, statptr->st_size);
109
110         switch (type) {
111
112         case FTW_F:
113                 info = calloc(sizeof(mf_fo_dir_list_info), 1);
114                 info->ftw_path = g_strdup(pathname);
115                 info->size = statptr->st_size;
116                 info->type = type;
117                 dir_list = g_slist_append(dir_list, info);
118                 mf_debug("File pathname is [%s]", pathname);
119                 break;
120         case FTW_D:
121                 info = calloc(sizeof(mf_fo_dir_list_info), 1);
122                 info->ftw_path = g_strdup(pathname);
123                 info->size = statptr->st_size;
124                 info->type = type;
125                 dir_list = g_slist_append(dir_list, info);
126                 mf_debug("Directory pathname is [%s]", pathname);
127                 //process file
128                 break;
129         default:
130                 mf_debug("Default pathname is [%s]", pathname);
131         }
132
133         return 0;
134 }
135
136 static int __mf_fo_get_total_dir_size(const char *dir, unsigned long long *size)
137 {
138         int ret = -1;
139         if (!dir) {
140                 return -EINVAL;
141         }
142         ret = ftw(dir, __get_directory_hierarchies, 16);
143         if (ret == 0) {
144                 mf_debug();
145                 mf_fo_dir_list_info *ent = NULL;
146                 GSList *list = NULL;
147                 list = dir_list;
148                 while (list) {
149                         ent = (mf_fo_dir_list_info *)list->data;
150                         if (ent->type == FTW_D) {
151                                 *size += MF_VISUAL_FOLDER_SIZE;
152                         } else if (ent->type == FTW_F) {
153                                 *size += ent->size;
154                         }
155                         list = g_slist_next(list);
156                 }
157         } else {
158                 _mf_fo_free_directory_hierarchies(&dir_list);
159                 return -(errno);
160         }
161         _mf_fo_free_directory_hierarchies(&dir_list);
162
163         return 0;
164 }
165
166
167 #if 0
168 static char *_get_unique_dirname(const char *name)
169 {
170         char *new_name = NULL;
171         long max = 0;
172         unsigned int i = 0;
173         char *num_area = NULL;
174         gboolean has_num = FALSE;
175         int next_num = 1;
176
177         if ((num_area = strrchr(name, NEW_NAME_SEPARATOR)) != NULL) {
178                 num_area += 1;
179                 has_num = TRUE;
180                 for (i = (num_area - name); name[i] != '\0'; i++) {
181                         if (!isdigit(name[i])) {
182                                 has_num = FALSE;
183                                 break;
184                         }
185                 }
186         }
187         max = __mf_fo_get_path_max();
188         new_name = malloc(sizeof(char) * max);
189         if (new_name) {
190                 int write_len = 0;
191                 int prefix_len = (int)(num_area - name - 1);
192                 if (has_num) {
193                         next_num = atoi(num_area) + 1;
194                         write_len = snprintf(new_name, max, "%.*s_%d", (int)(num_area - name - 1), name, next_num);
195                         if (write_len > max) {
196                                 snprintf(new_name, max, "%.*s_%d", (int)(num_area - name - 1), name, next_num);
197                         }
198                         while (_mf_fo_check_exist(new_name)) {
199                                 next_num++;
200                                 snprintf(new_name, max, "%.*s_%d", (int)(num_area - name - 1), name, next_num);
201                         }
202                 } else {
203                         snprintf(new_name, max, "%s_%d", name, next_num);
204                         while (_mf_fo_check_exist(new_name)) {
205                                 next_num++;
206                                 snprintf(new_name, max, "%s_%d", name, next_num);
207                         }
208                 }
209         }
210         return new_name;
211 }
212 #else
213 char *_mf_fo_get_next_unique_dirname(const char *name, int *errcode)
214 {
215         char *new_name = NULL;
216         char *tmp_name = NULL;
217         int name_len = 0;
218         long p_max = 0;
219
220         if (!name) {
221                 *errcode = EINVAL;
222                 return NULL;
223         }
224
225         name_len = strlen(name);
226         if (name_len <= 1) {
227                 *errcode = EINVAL;
228                 return NULL;
229         }
230
231         p_max = __mf_fo_get_path_max();
232
233         if (name[name_len - 1] == '/') {
234                 tmp_name = strndup(name, name_len - 1);
235                 if (!tmp_name) {
236                         *errcode = ENOMEM;
237                         return NULL;
238                 }
239         }
240
241         new_name = malloc(sizeof(char) * p_max);
242
243         if (new_name) {
244                 int next_num = 0;
245                 long n_max = 0;
246
247                 n_max = __mf_fo_get_name_max();
248
249                 do {
250                         int write_len = 0;
251                         next_num++;
252                         write_len = snprintf(new_name, p_max, "%s_%d", tmp_name ? tmp_name : name, next_num);
253                         if (write_len > p_max) {
254                                 mf_fo_loge("write_len[%u] is greater than max[%ld]", write_len, p_max);
255                                 *errcode = ENAMETOOLONG;
256                                 goto ERROR_FREE_RETURN;
257                         } else {
258                                 const char *b_name = 0;
259                                 b_name = __mf_fo_get_base_name(new_name);
260                                 if (b_name && (mf_util_character_count_get(b_name) > n_max)) {
261                                         mf_fo_loge("b_name length[%u] is greater than name max[%ld]", strlen(b_name), n_max);
262                                         *errcode = ENAMETOOLONG;
263                                         goto ERROR_FREE_RETURN;
264                                 }
265                         }
266                 } while (_mf_fo_check_exist(new_name));
267         } else {
268                 *errcode = ENOMEM;
269         }
270
271         SAFE_FREE(tmp_name);
272         return new_name;
273
274 ERROR_FREE_RETURN:
275         SAFE_FREE(tmp_name);
276         SAFE_FREE(new_name);
277
278         return NULL;
279 }
280 #endif
281
282 char *_mf_fo_get_next_unique_filename(const char *name, int *errcode)
283 {
284         char *new_name = NULL;
285         int name_len = 0;
286         long p_max = 0;
287         const char *base = NULL;
288
289         if (!name) {
290                 *errcode = EINVAL;
291                 return NULL;
292         }
293
294         name_len = strlen(name);
295         if (name_len <= 1) {
296                 *errcode = EINVAL;
297                 return NULL;
298         }
299
300         base = __mf_fo_get_base_name(name);
301         if (!base) {
302                 *errcode = EINVAL;
303                 return NULL;
304         }
305
306         p_max = __mf_fo_get_path_max();
307
308         new_name = malloc(sizeof(char) * p_max);
309
310         if (new_name) {
311                 int next_num = 0;
312                 long n_max = 0;
313                 int dir_len = 0;
314                 int base_len = 0;
315                 const char *ext = NULL;
316
317                 n_max = __mf_fo_get_name_max();
318                 dir_len = (int)(base - name);
319
320                 if ((ext = strrchr(name, '.')) != NULL) {
321                         base_len = (int)(ext - base);
322                 } else {
323                         base_len = strlen(base);
324                 }
325
326                 do {
327                         int write_len = 0;
328                         next_num++;
329                         if (ext) {
330                                 write_len = snprintf(new_name, p_max, "%.*s%.*s_%d%s", dir_len, name, base_len, base, next_num, ext);
331                         } else {
332                                 write_len = snprintf(new_name, p_max, "%.*s%.*s_%d", dir_len, name, base_len, base, next_num);
333                         }
334
335                         if (write_len > p_max) {
336                                 mf_fo_loge("write_len[%u] is greater than max[%ld]", write_len, p_max);
337                                 *errcode = ENAMETOOLONG;
338                                 goto ERROR_FREE_RETURN;
339                         } else {
340                                 const char *b_name = NULL;
341                                 b_name = __mf_fo_get_base_name(new_name);
342                                 if (b_name && (strlen(b_name) > n_max)) {
343                                         mf_fo_loge("b_name length[%u] is greater than name max[%ld]", strlen(b_name), n_max);
344                                         *errcode = ENAMETOOLONG;
345                                         goto ERROR_FREE_RETURN;
346                                 }
347                         }
348                 } while (_mf_fo_check_exist(new_name));
349         } else {
350                 *errcode = ENOMEM;
351         }
352
353         return new_name;
354
355 ERROR_FREE_RETURN:
356         SAFE_FREE(new_name);
357
358         return NULL;
359 }
360
361 int _mf_fo_get_total_item_size(const char *item, unsigned long long *size)
362 {
363         struct stat info;
364         if (!item || !size) {
365                 return -EINVAL;
366         }
367         if (stat(item, &info)) {
368                 mf_fo_loge("Fail to stat item : %s", item);
369                 return -(errno);
370         }
371
372         if (S_ISREG(info.st_mode)) {
373                 *size = (unsigned long long)info.st_size;
374         } else if (S_ISDIR(info.st_mode)) {
375                 int ret = __mf_fo_get_total_dir_size(item, size);
376                 if (ret < 0) {
377                         mf_fo_loge("Fail to get size of directory(%s)", item);
378                         *size = 0;
379                         return ret;
380                 }
381         } else {
382                 mf_fo_loge("item(%s) is not file or directory", item);
383                 *size = (unsigned long long)info.st_size;
384                 return -EINVAL;
385         }
386         return 0;
387 }
388
389 int _mf_fo_get_remain_space(const char *path, unsigned long long *size)
390 {
391         FO_TRACE_BEGIN;
392         struct statfs dst_fs;
393
394         if (!path || !size) {
395                 FO_TRACE_END;
396                 return -EINVAL;
397         }
398
399         if (statfs(path, &dst_fs) == 0) {
400                 *size = ((unsigned long long)(dst_fs.f_bsize) * (unsigned long long)(dst_fs.f_bavail));
401         } else {
402                 FO_TRACE_END;
403                 return -errno;
404         }
405         FO_TRACE_END;
406
407         return 0;
408 }
409
410 inline bool _mf_fo_check_exist(const char *path)
411 {
412         if (path && (access(path, F_OK) == 0)) {
413                 return true;
414         }
415         return false;
416 }
417
418 int _mf_fo_errno_to_mferr(int err_no)
419 {
420         int err = MF_FO_ERR_SET(MF_FO_ERR_UNKNOWN);
421         switch (err_no) {
422 #ifdef EINVAL
423         case EINVAL:
424                 err = MF_FO_ERR_SET(MF_FO_ERR_ARGUMENT);
425                 break;
426 #endif
427 #ifdef EACCES                   /*The requested access to the file is not allowed*/
428         case EACCES:            /*report*/
429                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_PERMISSION);
430                 break;
431 #endif
432 #ifdef EFAULT                   /* pathname points outside your accessible address space*/
433         case EFAULT:
434                 err = MF_FO_ERR_SET(MF_FO_ERR_FAULT);
435                 break;
436 #endif
437 #ifdef EISDIR                   /*pathname refers to a directory and the access requested involved writing*/
438         case EISDIR:            /*report*/
439                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_TYPE);
440                 break;
441 #endif
442 #ifdef EMFILE                   /*The process already has the maximum number of files open.*/
443         case EMFILE:
444                 err = MF_FO_ERR_SET(MF_FO_ERR_MAX_OPEN);
445                 break;
446 #endif
447 #ifdef ENOSPC                   /*pathname was to be created but the device containing pathname has no room for the new file*/
448         case ENOSPC:            /*report*/
449                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_SPACE);
450                 break;
451 #endif
452 #ifdef ENOTDIR                  /* A component used as a directory in pathname is not*/
453         case ENOTDIR:           /*report*/
454                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_TYPE);
455                 break;
456 #endif
457 #ifdef EROFS                    /*pathname refers to a file on a read-only filesystem and write access was requested*/
458         case EROFS:             /*report*/
459                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_RO);
460                 break;
461 #endif
462 #ifdef ELOOP                    /* Too many symbolic links were encountered in resolving pathname */
463         case ELOOP:
464                 err = MF_FO_ERR_SET(MF_FO_ERR_LOOP);
465                 break;
466 #endif
467 #ifdef ENOMEM                   /* Insufficient kernel memory was available */
468         case ENOMEM:            /*report*/
469                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_MEM);
470                 break;
471 #endif
472 #ifdef ENOENT                   /* O_CREAT is not set and the named file does not exist*/
473         case ENOENT:            /*report*/
474                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_NOT_EXIST);
475                 break;
476 #endif
477 #ifdef ENAMETOOLONG             /*pathname was too long.*/
478         case ENAMETOOLONG:      /*report*/
479                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_LONG_NAME);
480                 break;
481 #endif
482 #ifdef EFBIG                    /* An attempt was made to write a file that exceeds the implementation-defined maximum
483                                 file size or the process file size limit*/
484         case EFBIG:             /*report*/
485                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_BIG_SIZE);
486                 break;
487 #endif
488 #ifdef EIO                      /* I/O error */
489         case EIO:
490                 err = MF_FO_ERR_SET(MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_IO);
491                 break;
492 #endif
493         default:
494                 break;
495         }
496
497         return err;
498 }
499
500 void _mf_fo_free_directory_hierarchies(GSList **glist)
501 {
502         if (*glist == NULL)
503                 return;
504         GSList *list = *glist;
505         while (list) {
506                 mf_fo_dir_list_info *info = NULL;
507                 info = (mf_fo_dir_list_info *)list->data;
508                 g_free(info->ftw_path);
509                 g_free(info);
510                 list = g_slist_next(list);
511         }
512         g_slist_free(*glist);
513         *glist = NULL;
514 }
515