-
Notifications
You must be signed in to change notification settings - Fork 0
/
ls.c
285 lines (224 loc) · 7.28 KB
/
ls.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
//DESARROLLADO POR: CESAR AUGUSTO MENDEZ VARGAS - 20130262 - ISC
#define _XOPEN_SOURCE //Se necesita para que sys/stat declare algunas constantes necesarias
#include <unistd.h>
#include <stdio.h>
#include <dirent.h> //Contiene la estructura dirent
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
//Este arreglo contiene los atributos a ser ejecutados
int commands[ 11 ];
/*
!0: -A : lists all entries including those starting with periods (.), but excluding any . or .. entries.
!1: -h : displays file sizes using more human-friendly units.
!2: -i : displays inode numbers along with file names (only on systems that support inode numbers, such as POSIX-compliant and UNIX systems).
!3: -l : displays permissions, links, owner, group, size, time, name; see Long Output Format.
!4: -n : displays user ID and group IDs as numbers instead of names.
!5: -o : displays only the user ID of owner (POSIX-compliant and UNIX systems only).
!6: -p : puts / after directory names.
!7: -a : lists all entries including those starting with periods (.)
*/
char units[ 7 ] = {
'B',
'K',
'M',
'G',
'T',
'P',
'E'
};
//Funciones auxiliares
char *file_size_human( int ); //Convierte un tamano de archivo a formato facil de entender
char *mode_human( int ); //Representa los permisos de los archivos en formato facil de entender
char *date_human( time_t fecha ); //Convierte la fecha de entero a string
int main( int argc, char * argv[ ] ) {
int ch;
//Marco todos los comandos como deshabilitados al principio
for( int i = 0; i < 11; i++ ){
commands[ i ] = 0;
}
//Si es root implementar -A automaticamente
if ( !getuid( ) ){
commands[ 0 ] = 1;
}
//Con getopt puedo procesar los parametros de tipo - y --, muy facilmente
while ( ( ch = getopt(argc, argv, "1ARahilnop" ) ) != -1 ) {
switch( ch ){
case 'A': //Con este argumento se listan los archivos ocultos
commands[ 0 ] = 1;
break;
case 'h': //Mostrar los tamanos de archivos en formato humano/entendible
commands[ 1 ] = 1;
break;
case 'i': //Mostrar el nodo i del elemento
commands[ 2 ] = 1;
break;
case 'l': //Mostrar informacion larga/detallada
commands[ 3 ] = 1;
break;
case 'n': //Con esto muestro solo los ids en vez de los nombres en owner y group
commands[ 4 ] = 1;
break;
case 'o': //Solo mostrar solo id del usuario owner
commands[ 5 ] = 1;
break;
case 'p': //Si el elemento es un directorio se le agrega '/' al final
commands[ 6 ] = 1;
break;
case 'a': //Muestro las entradas . y ..
commands[ 7 ] = 1;
break;
}
}
//Directorio donde me encuentro
char Directory[ 1024 ];
DIR *dir; //Estructura directorio que representa un flujo de directorio
struct dirent *ent; //Esta estructura contiene el nombre del directorio/fichero
//Con esta funcion me sitio en la carpeta desde donde estoy llamando al script
if ( getcwd( Directory, sizeof( Directory ) ) == NULL ){
printf( "Error obteniendo el directorio base..." );
return 0;
}
//Abro el directorio actual
if ( ( dir = opendir ( Directory ) ) != NULL) {
//Mientras tenga archivos
while ( ( ent = readdir ( dir ) ) != NULL ) {
struct stat st; //Esta es la estructura que contiene la informacion del elemento
//Si no esta definido el comando -a, saltar estos directorios
if( ( !strcmp( ent->d_name, "." ) && !commands[ 7 ] ) || ( !strcmp( ent->d_name, ".." ) && !commands[ 7 ] ) ) continue; //Si
//Si no esta definido el comando -A, saltar los elementos ocultos
if( ent->d_name[ 0 ] == '.' && !commands[ 0 ] ) continue;
//Esta funcion es la cual alimente struct stat st, en base al archivo que quiero saber.
stat( ent->d_name, &st );
//Si se quiere mostrar la informacion del nodo i
if( commands[ 2 ] ){
printf("%8d ", st.st_ino );
}
//Mostrar comando l
if( commands[ 3 ] ){
printf( "%10s %2d ", mode_human( st.st_mode ), st.st_nlink );
//Si este comando esta activo, solo se muestra el user id
if( commands[ 5 ] ){
printf( "%4d ", st.st_uid );
}
else {
//Mostrar los ID's en vez de los nombres de los owners
if( commands[ 4 ] ){
printf( "%4d %4d ", st.st_uid, st.st_gid );
}
else {
struct passwd *pw = getpwuid( st.st_uid ); //Obtengo el nombre del owner
struct group *gr = getgrgid( st.st_gid ); //Obtengo el nombre del grupo
printf( "%s %s ", pw->pw_name, gr->gr_name );
}
}
//Si se quiere en formato entendible
if( commands[ 1 ] ){
printf( "%s ", file_size_human( st.st_size ) );
}
else {
printf("%6d ", st.st_size );
}
printf( "%11s ", date_human( st.st_mtime ) ); //Imprimo la fecha
}
//En caso de que se quiera el size, y no se uso -l
if( commands[ 1 ] && !commands[ 3 ] ){
printf( " %s ", file_size_human( st.st_size ) );
}
//Por ultimo imprimo el nombre
printf( "%s ", ent->d_name );
//Si es un directorio y esta activo -p, poner / luego del nombre
if( commands[ 6 ] ){
if( st.st_mode & S_IFDIR ) printf( "/" );
}
if( !commands[ 9 ] ){
printf("\n");
}
}
closedir ( dir );
}
else {
printf( "No se pudo abrir el directorio!\n" );
}
return 0;
}
//MOstrar el tamano del archivo en formato humano
char *file_size_human( int n ){
char *r;
r = (char *) malloc( 6 ); //Le asigno memoria para poder retornarlo y que no desaparezca
int unit = 0; //Unit es el indice de la unidad que se va a representar( B, K, M, ... )
double nd = n; //Truco para realizar las operaciones en flotante y dar un tamanio mas preciso.
while( nd >= 1024 ){ //Mientras se pueda reducir la unidad
unit++; //Cambio de unidad
nd /= 1024; //Redusco el tamano de la unidad
if( unit == 6 ){
break; //Solo se soportan 7 unidades ( y mucho es ).
}
}
//Uso sprintf para agregar un string de forma facil con el formato que quiero
sprintf( r, "%.2f%c", nd, units[ unit ] );
return r;
}
char *mode_human( int mask ){
char *r;
//En esta funcion simplemente se devuelve un string con el [tipo de archivo][y los permisos de: owner, grupo, otros ]
/*
Simplemente se realiza un & logico con la mascara especifica
para ver si dicho usuario dispone de tal permiso
Si no se tiene el permiso se muestra -
EL primer caracter muestra el tipo del archivo '-' indica que es un fichero normal
*/
r = (char *) malloc( 10 );
strcpy( r, "----------" );
if( S_IFDIR & mask ){ //Si es un directorio el primer caracter se muestra con d
r[ 0 ] = 'd';
}
else if( S_IFLNK & mask ){ //Si es un syslink se muestra una l
r[ 0 ] = 'l';
}
else {
//Just in case
}
//PERMISOS OWNER
if( S_IRUSR & mask ){
r[ 1 ] = 'r';
}
if( S_IWUSR & mask ){
r[ 2 ] = 'w';
}
if( S_IXUSR & mask ){
r[ 3 ] = 'x';
}
//PERMISOS GROUP
if( S_IRGRP & mask ){
r[ 4 ] = 'r';
}
if( S_IWGRP & mask ){
r[ 5 ] = 'w';
}
if( S_IXGRP & mask ){
r[ 6 ] = 'x';
}
//PERMISOS OTROS
if( S_IROTH & mask ){
r[ 7 ] = 'r';
}
if( S_IWOTH & mask ){
r[ 8 ] = 'w';
}
if( S_IXOTH & mask ){
r[ 9 ] = 'x';
}
return r;
}
char *date_human( time_t fecha ){
char *r;
r = ( char * )malloc ( 12 );
//strftime copia en un texto con el formato indicado de fecha
//localtime devuelve una estructura con la informacion de fecha a la configuracion horaria actual del sistema
strftime( r, 11, "%b %d %Y", localtime( &fecha ) );
return r;
}