| /* | 
 |  * | 
 |  * Copyright (C) 2008, The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *     http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include <dirent.h> | 
 | #include <fcntl.h> | 
 | #include <sys/stat.h> | 
 |  | 
 | #include <diskusage/dirsize.h> | 
 |  | 
 | int64_t stat_size(struct stat *s) | 
 | { | 
 |     int64_t blksize = s->st_blksize; | 
 |     // count actual blocks used instead of nominal file size | 
 |     int64_t size = s->st_blocks * 512; | 
 |  | 
 |     if (blksize) { | 
 |         /* round up to filesystem block size */ | 
 |         size = (size + blksize - 1) & (~(blksize - 1)); | 
 |     } | 
 |  | 
 |     return size; | 
 | } | 
 |  | 
 | int64_t calculate_dir_size(int dfd) | 
 | { | 
 |     int64_t size = 0; | 
 |     struct stat s; | 
 |     DIR *d; | 
 |     struct dirent *de; | 
 |  | 
 |     d = fdopendir(dfd); | 
 |     if (d == NULL) { | 
 |         close(dfd); | 
 |         return 0; | 
 |     } | 
 |  | 
 |     while ((de = readdir(d))) { | 
 |         const char *name = de->d_name; | 
 |         if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { | 
 |             size += stat_size(&s); | 
 |         } | 
 |         if (de->d_type == DT_DIR) { | 
 |             int subfd; | 
 |  | 
 |             /* always skip "." and ".." */ | 
 |             if (name[0] == '.') { | 
 |                 if (name[1] == 0) | 
 |                     continue; | 
 |                 if ((name[1] == '.') && (name[2] == 0)) | 
 |                     continue; | 
 |             } | 
 |  | 
 |             subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); | 
 |             if (subfd >= 0) { | 
 |                 size += calculate_dir_size(subfd); | 
 |             } | 
 |         } | 
 |     } | 
 |     closedir(d); | 
 |     return size; | 
 | } |