Added an embryo of the main routine to print the result.
[dus.git] / dus.c
1
2 /*
3  *  dus is a simple utility designed to display the list of files and
4  *  directories with disk occupancy, sorted according to it.
5  *
6  *  Copyright (c) 2009 Francois Fleuret
7  *  Written by Francois Fleuret <francois@fleuret.org>
8  *
9  *  This file is part of dus.
10  *
11  *  dus is free software: you can redistribute it and/or modify it
12  *  under the terms of the GNU General Public License version 3 as
13  *  published by the Free Software Foundation.
14  *
15  *  dus is distributed in the hope that it will be useful, but WITHOUT
16  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18  *  License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with dus.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #define _BSD_SOURCE
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <dirent.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <string.h>
35
36 size_t file_or_dir_size(char *name) {
37   DIR *dir;
38   struct dirent *dir_e;
39   struct stat dummy;
40   size_t result;
41   char subname[1024];
42
43   result = 0;
44
45   if(lstat(name, &dummy) != 0) {
46     printf("Can not stat %s (%s).\n", name, strerror(errno));
47     exit (1);
48   }
49
50   if(S_ISLNK(dummy.st_mode)) {
51     return 0;
52   }
53
54   dir = opendir(name);
55
56   if(dir) {
57     while((dir_e = readdir(dir))) {
58       if(strcmp(dir_e->d_name, ".") &&
59          strcmp(dir_e->d_name, "..")) {
60         sprintf(subname, "%s/%s", name, dir_e->d_name);
61         result += file_or_dir_size(subname);
62       }
63     }
64     closedir(dir);
65   } else {
66     if(S_ISREG(dummy.st_mode)) {
67       result += dummy.st_size;
68     }
69   }
70
71   return result;
72 }
73
74 /**********************************************************************/
75
76 struct file_with_size {
77   char *filename;
78   size_t size;
79   struct file_with_size *next;
80 };
81
82 struct file_with_size *create(char *name, struct file_with_size *current) {
83   struct file_with_size *result;
84   result = malloc(sizeof(struct file_with_size));
85   result->filename = strdup(name);
86   result->size = file_or_dir_size(name);
87   result->next = current;
88   return result;
89 }
90
91 void destroy(struct file_with_size *node) {
92   struct file_with_size *next;
93   while(node) {
94     next = node->next;
95     free(node->filename);
96     free(node);
97     node = next;
98   }
99 }
100
101 /**********************************************************************/
102
103 void print_sorted(struct file_with_size *root) {
104   struct file_with_size *node;
105   struct file_with_size **nodes;
106   int nb, n;
107
108   nb = 0;
109   for(node = root; node; node = node->next) {
110     nb++;
111   }
112
113   nodes = malloc(nb * sizeof(struct file_with_size *));
114
115   n = 0;
116   for(node = root; node; node = node->next) {
117     nodes[n++] = node;
118   }
119
120   for(n = 0; n < nb; n++) {
121     printf("%u %s\n", nodes[n]->size, nodes[n]->filename);
122   }
123
124   free(nodes);
125 }
126
127 /**********************************************************************/
128
129 int main(int argc, char **argv) {
130   int k;
131   struct file_with_size *root;
132
133   root = 0;
134   for(k = 1; k < argc; k++) {
135     root = create(argv[k], root);
136   }
137
138   print_sorted(root);
139
140   destroy(root);
141
142   exit(0);
143 }