| /* |
| * |
| * 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; |
| int64_t size = s->st_size; |
| |
| 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 (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); |
| } |
| } else { |
| if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { |
| size += stat_size(&s); |
| } |
| } |
| } |
| closedir(d); |
| return size; |
| } |