Estoy tratando de escribir un pequeño programa en C que emula el comando de unix ls -l
. Para hacerlo, estoy usando el syscall stat(2)
y me he encontrado con un pequeño inconveniente al escribir los permisos. Tengo una variable mode_t
que contiene los permisos de archivo de st_mode
, y no sería difícil analizar ese valor en s representación de cadena, pero me preguntaba si hay una mejor manera de hacerlo que eso.Impresión de permisos de archivo como 'ls -l' usando stat (2) en C
Respuesta
ejemplo de Google
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
if(argc != 2)
return 1;
struct stat fileStat;
if(stat(argv[1],&fileStat) < 0)
return 1;
printf("Information for %s\n",argv[1]);
printf("---------------------------\n");
printf("File Size: \t\t%d bytes\n",fileStat.st_size);
printf("Number of Links: \t%d\n",fileStat.st_nlink);
printf("File inode: \t\t%d\n",fileStat.st_ino);
printf("File Permissions: \t");
printf((S_ISDIR(fileStat.st_mode)) ? "d" : "-");
printf((fileStat.st_mode & S_IRUSR) ? "r" : "-");
printf((fileStat.st_mode & S_IWUSR) ? "w" : "-");
printf((fileStat.st_mode & S_IXUSR) ? "x" : "-");
printf((fileStat.st_mode & S_IRGRP) ? "r" : "-");
printf((fileStat.st_mode & S_IWGRP) ? "w" : "-");
printf((fileStat.st_mode & S_IXGRP) ? "x" : "-");
printf((fileStat.st_mode & S_IROTH) ? "r" : "-");
printf((fileStat.st_mode & S_IWOTH) ? "w" : "-");
printf((fileStat.st_mode & S_IXOTH) ? "x" : "-");
printf("\n\n");
printf("The file %s a symbolic link\n", (S_ISLNK(fileStat.st_mode)) ? "is" : "is not");
return 0;
}
resultado:
Information for 2.c --------------------------- File Size: 1223 bytes Number of Links: 1 File inode: 39977236 File Permissions: -rw-r--r-- The file is not a symbolic link
Los fundamentos son bastante simple; los bits difíciles son los bits SUID y SGID y el bit adhesivo, que modifican los bits 'x'. Considere dividir los permisos en 3 dígitos octales para usuario, grupo, propietario y usarlos para indexar en una matriz de cadenas de 3 caracteres como rwx
y ---
. Luego ajuste los bits apropiados x
basados en los otros bits de modo. El tipo de archivo tendrá que tratarse por separado, pero podría usar un desplazamiento a la derecha de 12 bits (posiblemente con enmascaramiento) y una tabla de entrada de 16 para tratar los 16 valores posibles (no todos son válidos en un sistema dado) . O puede tratar con tipos conocidos como se muestra en el siguiente código.
+----+---+---+---+---+
|type|SSS|USR|GRP|OTH|
+----+---+---+---+---+
los 4 tipos bits, en los tres bits S (setuid, setgid, pegajosas) y el usuario, grupo y otros bits.
Este es el código que uso para convertir mode_t
en una cadena. Fue escrito para un programa muy bien sin hilos, por lo que utiliza datos estáticos; sería trivial modificarla para tomar la cadena de salida como parámetro de entrada:
/* Convert a mode field into "ls -l" type perms field. */
static char *lsperms(int mode)
{
static const char *rwx[] = {"---", "--x", "-w-", "-wx",
"r--", "r-x", "rw-", "rwx"};
static char bits[11];
bits[0] = filetypeletter(mode);
strcpy(&bits[1], rwx[(mode >> 6)& 7]);
strcpy(&bits[4], rwx[(mode >> 3)& 7]);
strcpy(&bits[7], rwx[(mode & 7)]);
if (mode & S_ISUID)
bits[3] = (mode & S_IXUSR) ? 's' : 'S';
if (mode & S_ISGID)
bits[6] = (mode & S_IXGRP) ? 's' : 'l';
if (mode & S_ISVTX)
bits[9] = (mode & S_IXOTH) ? 't' : 'T';
bits[10] = '\0';
return(bits);
}
static int filetypeletter(int mode)
{
char c;
if (S_ISREG(mode))
c = '-';
else if (S_ISDIR(mode))
c = 'd';
else if (S_ISBLK(mode))
c = 'b';
else if (S_ISCHR(mode))
c = 'c';
#ifdef S_ISFIFO
else if (S_ISFIFO(mode))
c = 'p';
#endif /* S_ISFIFO */
#ifdef S_ISLNK
else if (S_ISLNK(mode))
c = 'l';
#endif /* S_ISLNK */
#ifdef S_ISSOCK
else if (S_ISSOCK(mode))
c = 's';
#endif /* S_ISSOCK */
#ifdef S_ISDOOR
/* Solaris 2.6, etc. */
else if (S_ISDOOR(mode))
c = 'D';
#endif /* S_ISDOOR */
else
{
/* Unknown type -- possibly a regular file? */
c = '?';
}
return(c);
}
¡Aprecie la profundidad proporcionada por su respuesta! ¡Aprenda algo nuevo cada día! – cheezone
sonido metálico '' -Weverything'' quejó con razón :) –
@ ArranCudbard-Bell: He estado limpiando un corpus de comandos con algo análogo a 'sonido metálico -Weverything' y puede ser un poco doloroso a veces. En realidad, no he intentado 'clang -Weverything' directamente; podría ser menos oneroso que las opciones que estoy usando (alrededor de 18 '-W *' flags; '-Wconversion' es la mayor causa de problemas para mi código). –
no me gusta la sintaxis if/ else if
.
prefiero utilizar la instrucción switch
. Después de luchar un poco encontré la manera en que podemos hacerlo utilizando diferentes macros, por ejemplo:
S_ISCHR (mode)
es equivalente a:
((mode & S_IFMT) == S_IFCHR)
Esto nos permite construir una sentencia switch como esto:
char f_type(mode_t mode)
{
char c;
switch (mode & S_IFMT)
{
case S_IFBLK:
c = 'b';
break;
case S_IFCHR:
c = 'c';
break;
case S_IFDIR:
c = 'd';
break;
case S_IFIFO:
c = 'p';
break;
case S_IFLNK:
c = 'l';
break;
case S_IFREG:
c = '-';
break;
case S_IFSOCK:
c = 's';
break;
default:
c = '?';
break;
}
return (c);
}
Que en mi opinión es un poco más elegante que el enfoque if/else if
.
¿Ha descartado el código de ensamblado para determinar cuál es más eficiente? (por ejemplo, 'gcc -S-masm = intel -O2 -o filemode.asm filemode.c') –
- 1. Opción ilegal stat Binutils -c
- 2. awk '{print $ 9}' la última columna ls -l incluyendo espacios en el nombre de archivo
- 3. Lua = operador como impresión
- 4. usando stat para detectar si existe un archivo (¿lento?)
- 5. El uso correcto de Stat en C
- 6. c lea los permisos de un archivo
- 7. Comprobando permisos de ntfs de carpeta/archivo usando python
- 8. Uso de Struct Stat()
- 9. Establecer permisos en un archivo comprimido en python
- 10. C# impresión en red
- 11. impresión en LPT1 en C#
- 12. ¿Cómo buscar un entorno usando ls() dentro de una función?
- 13. Búsqueda de archivos ejecutables usando ls y grep
- 14. git ls-files con fecha?
- 15. Prefijo L para cadenas en C++
- 16. UNIX stat time format
- 17. Preservar ls colorear después grep'ing
- 18. escritura de permisos de archivo en Android
- 19. ¿Cómo calcula el comando stat los bloques de un archivo?
- 20. Los permisos de archivo no heredan los permisos de directorio
- 21. Usando Moustache como lengua de plantillas en Symfony 2
- 22. Impresión con matriz de puntos en C#?
- 23. ¿Cómo solicitas permisos de administrador usando NSIS?
- 24. Unix stat()/lstat() para Java
- 25. valores negativos de impresión como hexagonal en Python
- 26. ¿Por qué open() crea mi archivo con los permisos incorrectos?
- 27. Cómo bloquear Windows (como "Windows + L") desde .NET?
- 28. Alimentación de formulario en impresión C#
- 29. impresión NSData usando NSLog
- 30. Incrementos de impresión de 0.1 en C#
Gracias por la respuesta. Esto ha ayudado mucho. – cheezone
Tenga en cuenta que debido a que el código usa 'stat()' en lugar de 'lstat()', la única vez que informará 'symlink' es cuando se rompe el enlace simbólico. De lo contrario, informará sobre el archivo al final del enlace simbólico. –