Usermode - Renamed readdir() to SysReadDir()
[tpg/acess2.git] / Usermode / Applications / ls_src / main.c
1 /*
2  * Acess2 LS command
3  */
4 #include <acess/sys.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 #define BUF_SIZE        1024
10
11 // === CONSTANTS ===
12 enum eFileTypes {
13         FTYPE_NORMAL,
14         FTYPE_EXEC,
15         FTYPE_DIR,
16         FTYPE_SYMLINK
17 };
18
19 // === PROTOTYPES ===
20  int    main(int argc, char *argv[]);
21 void    ShowUsage(char *ProgName);
22 void    ParseArguments(int argc, char *argv[]);
23 void    SortFileList();
24 void    DisplayFile(char *Filename);
25
26 // === GLOBALS ===
27 // --- Flags ---
28  int    gbShowAll = 0;
29  int    gbShowImplicit = 0;
30  int    gbViewExtended = 0;
31  int    gbViewHumanReadable = 0;
32 // --- Parameters ---
33 char    *gsDirectory = NULL;
34 // --- Working Set ---
35 char    **gFileList;
36  int    giNumFiles = 0;
37
38 /**
39  * \fn int main(int argc, char *argv[])
40  * \brief Entrypoint
41  */
42 int main(int argc, char *argv[])
43 {
44          int    fd, tmp;
45          int    i;
46         char    buf[BUF_SIZE+1];
47         t_sysFInfo      info;
48          int    space = 0;
49
50         // Arguments Check
51         ParseArguments(argc, argv);
52
53         // Open Directory
54         fd = open(gsDirectory, OPENFLAG_READ|OPENFLAG_EXEC);
55         if(fd == -1) {
56                 printf("Unable to open '%s' for reading\n", gsDirectory);
57                 return EXIT_FAILURE;
58         }
59
60         // Check that it is a directory
61         finfo(fd, &info, 0);
62         if( !(info.flags & FILEFLAG_DIRECTORY) ) {
63                 fprintf(stderr, "'%s' is not a directory\n", gsDirectory);
64                 close(fd);
65                 return EXIT_FAILURE;
66         }
67
68         // Check if we should include the implicit . and ..
69         if(gbShowImplicit)
70         {
71                 space = 16;
72                 gFileList = malloc(space*sizeof(char*));
73                 gFileList[giNumFiles++] = ".";
74                 gFileList[giNumFiles++] = "..";
75         }
76
77         // Traverse Directory
78         while( (tmp = SysReadDir(fd, buf)) > 0 )
79         {
80                 // Error check
81                 if(tmp < 0) {
82                         close(fd);
83                         return EXIT_FAILURE;
84                 }
85                 
86                 // Allocate Space
87                 if(space == giNumFiles)
88                 {
89                         space += 16;
90                         gFileList = realloc(gFileList, space*sizeof(char*));
91                         if(gFileList == NULL) {
92                                 close(fd);
93                                 return EXIT_FAILURE;
94                         }
95                 }
96                 gFileList[giNumFiles++] = strdup(buf);
97         }
98
99         // Sort File List according to rules passed
100         SortFileList();
101
102         // Show the file list
103         for( i = 0; i < giNumFiles; i ++ )
104         {
105                 DisplayFile( gFileList[i] );
106         }
107
108         close(fd);
109         printf("\n");
110
111         return EXIT_SUCCESS;
112 }
113
114 /**
115  * \fn void ShowUsage(char *ProgName)
116  */
117 void ShowUsage(char *ProgName)
118 {
119         fprintf(stderr, "Usage: %s [options] [<directory>]\n", ProgName);
120         fprintf(stderr, "\n");
121 }
122
123 /**
124  * \fn void ParseArguments(int argc, char *argv[])
125  * \brief Parse the command line arguments
126  */
127 void ParseArguments(int argc, char *argv[])
128 {
129          int    i;
130         char    *str;
131         for( i = 1; i < argc; i ++ )
132         {
133                 str = argv[i];
134                 // Flags
135                 if(str[0] == '-')
136                 {
137                         if(str[1] == '-')
138                         {
139                                 continue;
140                         }
141                         str = &str[1];
142                         for( ; *str; str++ )
143                         {
144                                 switch(*str)
145                                 {
146                                 // Show All
147                                 case 'a':       gbShowAll = 1;  gbShowImplicit = 1;     continue;
148                                 // Almost All
149                                 case 'A':       gbShowAll = 1;  gbShowImplicit = 0;     continue;
150                                 // Extended List
151                                 case 'l':       gbViewExtended = 1;     continue;
152                                 // Human readable sizes
153                                 case 'h':       gbViewHumanReadable = 1;        continue;
154                                 default:
155                                         fprintf(stderr, "%s: Unknown option '%c'\n", argv[0], *str);
156                                         ShowUsage(argv[0]);
157                                         exit(EXIT_FAILURE);
158                                 }
159                         }
160                         continue;
161                 }
162                 
163                 if(gsDirectory == NULL) {
164                         gsDirectory = argv[i];
165                 }
166         }
167         
168         // Apply Defaults
169         if(!gsDirectory)        gsDirectory = ".";
170 }
171
172 /**
173  * \fn int strcmpp(void *p1, void *p2)
174  * \brief Compares two strings given pointers to their pointers
175  */
176 int strcmpp(const void *p1, const void *p2)
177 {
178         return strcmp( *(char **)p1, *(char **)p2 );
179 }
180
181 /**
182  * \fn void SortFileList()
183  * \brief Sorts the filled file list
184  */
185 void SortFileList()
186 {
187         qsort(gFileList, giNumFiles, sizeof(char*), strcmpp);
188 }
189
190 /**
191  * \fn void DisplayFile(char *Filename)
192  * \brief Prints out the information for a file
193  */
194 void DisplayFile(char *Filename)
195 {
196         t_sysFInfo      info;
197         t_sysACL        acl;
198         char    *path;
199          int    fd;
200          int    dirLen = strlen(gsDirectory);
201          int    type = FTYPE_NORMAL, perms = 0;
202         uint64_t        size = 0;
203          int    owner = 0, group = 0;
204         
205         // Check if we should skip this file
206         if(!gbShowAll && Filename[0] == '.')    return;
207         
208         // Allocate path
209         path = malloc(dirLen+1+strlen(Filename)+1);
210         if(!path) {
211                 fprintf(stderr, "heap exhausted\n");
212                 exit(EXIT_FAILURE);
213         }
214         
215         // Create path
216         strcpy(path, gsDirectory);
217         path[dirLen] = '/';
218         strcpy(&path[dirLen+1], Filename);
219         
220         // Get file type
221         fd = open(path, 0);
222         if(fd == -1) {
223                 fprintf(stderr, "Unable to open '%s'\n", path);
224         }
225         else {
226                 // Get Info
227                 finfo(fd, &info, 0);
228                 // Get Type
229                 if(info.flags & FILEFLAG_DIRECTORY) {
230                         type = FTYPE_DIR;
231                 }
232                 else if(info.flags & FILEFLAG_SYMLINK) {
233                         type = FTYPE_SYMLINK;
234                 }
235                 else {
236                         type = FTYPE_NORMAL;
237                 }
238                 // Get Size
239                 size = info.size;
240                 // Get Owner and Group
241                 owner = info.uid;
242                 group = info.gid;
243                 
244                 // Get Permissions
245                 // - Owner
246                 acl.object = info.uid;
247                 _SysGetACL(fd, &acl);
248                 if(acl.perms & 1)       perms |= 0400;  // R
249                 if(acl.perms & 2)       perms |= 0200;  // W
250                 if(acl.perms & 8)       perms |= 0100;  // X
251                 // - Group
252                 acl.object = info.gid | 0x80000000;
253                 _SysGetACL(fd, &acl);
254                 if(acl.perms & 1)       perms |= 0040;  // R
255                 if(acl.perms & 2)       perms |= 0020;  // W
256                 if(acl.perms & 8)       perms |= 0010;  // X
257                 // - World
258                 acl.object = 0xFFFFFFFF;
259                 _SysGetACL(fd, &acl);
260                 if(acl.perms & 1)       perms |= 0004;  // R
261                 if(acl.perms & 2)       perms |= 0002;  // W
262                 if(acl.perms & 8)       perms |= 0001;  // X
263                 
264                 // Close file
265                 close(fd);
266         }
267         free(path);     // We're finished with it
268         
269         // Extended view?
270         if(gbViewExtended)
271         {
272                 char    permStr[11] = " ---------";
273                 if(type == FTYPE_DIR)   permStr[0] = 'd';
274                 if(perms & 0400)        permStr[1] = 'r';
275                 if(perms & 0200)        permStr[2] = 'w';
276                 if(perms & 0100)        permStr[3] = 'x';
277                 if(perms & 0040)        permStr[4] = 'r';
278                 if(perms & 0020)        permStr[5] = 'w';
279                 if(perms & 0010)        permStr[6] = 'x';
280                 if(perms & 0004)        permStr[7] = 'r';
281                 if(perms & 0002)        permStr[8] = 'w';
282                 if(perms & 0001)        permStr[9] = 'x';
283                 printf("%s %4i %4i ", permStr, owner, group);
284                 if(gbViewHumanReadable && type != FTYPE_DIR) {
285                         if(size < 2048) {       // < 2 KiB
286                                 printf("%4lli B   ", size);
287                         }
288                         else if(size < 2048*1024) {     // < 2 MiB
289                                 printf("%4lli KiB ", size>>10);
290                         }
291                         else if(size < (uint64_t)2048*1024*1024) {      // < 2 GiB
292                                 printf("%4lli MiB ", size>>20);
293                         }
294                         else if(size < (uint64_t)2048*1024*1024*1024) { // < 2 TiB
295                                 printf("%4lli GiB ", size>>30);
296                         }
297                         else {  // Greater than 2 TiB (if your files are larger than this, you are Doing It Wrong [TM])
298                                 printf("%4lli TiB ", size>>40);
299                         }
300                 } else {
301                         printf("%8lli ", size);
302                 }
303         }
304         
305         switch(type)
306         {
307         case FTYPE_DIR:         printf("\x1B[32m");     break;  // Green
308         case FTYPE_SYMLINK:     printf("\x1B[34m");     break;  // Blue
309         case FTYPE_NORMAL:      break;
310         }
311         printf("%s%s\n", Filename, (type==FTYPE_DIR?"/":""));
312         printf("\x1B[00m");     // Reset
313 }

UCC git Repository :: git.ucc.asn.au