diff options
author | Jakob Kaivo <jkk@ung.org> | 2019-03-13 21:26:44 -0400 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2019-03-13 21:26:44 -0400 |
commit | 0c77d8d0e691c446a6bdcb9fa3dcfe4736587fa4 (patch) | |
tree | 8e5fb9cd709a29a6d0fb9f143d865c556d3596b6 |
migrate to gitlab
-rw-r--r-- | Makefile | 24 | ||||
-rw-r--r-- | file.c | 126 | ||||
-rw-r--r-- | file.h | 23 | ||||
-rw-r--r-- | magic.c | 209 |
4 files changed, 382 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f8beb73 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.POSIX: + +.SUFFIXES: .cat .msg + +default: all + +CFLAGS=-g -Wall -Wextra -Wpedantic -Werror +UTILITY=file +SOURCES=file.c magic.c +HEADERS=file.h +OBJECTS=file.o magic.o +L10N= +all: $(UTILITY) $(L10N) + +$(UTILITY): $(OBJECTS) $(HEADERS) + +.msg.cat: + gencat $@ $< + +.c.cat: + sed -ne '/^\/\*\*cat/,/cat\*\*\//p;' $< | grep -v ^/ | grep -v ^\* | gencat $@ - + +clean: + rm -f *.o $(L10N) $(UTILITY) @@ -0,0 +1,126 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "file.h" +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +int file(const char *path, int domagic) +{ + printf("%s:", path); + struct stat st; + if (lstat(path, &st) == -1) { + printf(" cannot open (%s)\n", strerror(errno)); + return 1; + } + + if (S_ISLNK(st.st_mode)) { + char link[st.st_size]; + readlink(path, link, st.st_size); + printf(" symbolink link to %s\n", link); + return 0; + //stat(path, &st); + } + + if (domagic && S_ISREG(st.st_mode)) { + if (st.st_size == 0) { + printf(" empty"); + } + + if (access(path, X_OK) == 0) { + printf(" executable"); + } + + } + + + if (S_ISDIR(st.st_mode)) { + printf(" directory"); + } else if (S_ISFIFO(st.st_mode)) { + printf(" fifo"); + } else if (S_ISSOCK(st.st_mode)) { + printf(" socket"); + } else if (S_ISBLK(st.st_mode)) { + printf(" block special"); + } else if (S_ISCHR(st.st_mode)) { + printf(" character special"); + } else { + if (domagic) { + idmagic(path); + } else { + printf(" regular file"); + } + } + + putchar('\n'); + return 0; +} + +int main(int argc, char *argv[]) +{ + enum { NONE = 0, TODO, DONE } magic = TODO; + int c; + while ((c = getopt(argc, argv, "dhM:m:i")) != -1) { + switch (c) { + case 'd': /** include system default magic **/ + readmagic(NULL); + magic = DONE; + break; + + case 'h': /** identify symbolic links **/ + break; + + case 'i': /** perform no magic **/ + magic = NONE; + break; + + case 'M': /** specify magic file **/ + readmagic(optarg); + magic = DONE; + break; + + case 'm': /** specify magic file **/ + readmagic(optarg); + magic = DONE; + break; + + default: + return 1; + } + } + + if (magic == TODO) { + readmagic(NULL); + } + + if (optind >= argc) { + fprintf(stderr, "file: At least one file required\n"); + return 1; + } + + int r = 0; + while (optind < argc) { + r |= file(argv[optind++], magic); + } + + return r; +} @@ -0,0 +1,23 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#define _XOPEN_SOURCE 700 + +int readmagic(const char *path); +int idmagic(const char *path); @@ -0,0 +1,209 @@ +/* + * UNG's Not GNU + * + * Copyright (c) 2011-2017, Jakob Kaivo <jkk@ung.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "file.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <cpio.h> +#include <search.h> +#include <sys/types.h> +#include <tar.h> + +enum magic_type { + CHAR, + UCHAR, + SHORT, + USHORT, + INT, + UINT, + LONG, + ULONG, + STRING +}; + +size_t sizes[] = { + [CHAR] = sizeof(signed char), + [UCHAR] = sizeof(unsigned char), + [SHORT] = sizeof(short), + [USHORT] = sizeof(unsigned short), + [INT] = sizeof(int), + [UINT] = sizeof(unsigned int), + [LONG] = sizeof(long), + [ULONG] = sizeof(unsigned long), +}; + +union magic_value { + signed char schar; + unsigned char uchar; + short sshort; + unsigned short ushort; + int sint; + unsigned int uint; + long slong; + unsigned long ulong; + char *string; +}; + +struct magic { + struct magic *next; + struct magic *prev; + off_t offset; + enum magic_type type; + union magic_value value; + char *message; + struct magic *child; +}; + +static struct magic *head = NULL; +static struct magic *tail = NULL; +static int docontext = 0; + +static char *sh_strings[] = { "#!", 0 }; +static char *c_strings[] = { "/*", "#include ", "#define ", 0 }; +static char *fortran_strings[] = { "program ", "PROGRAM ", "c ", "C ", 0 }; +static struct { + char *identifier; + char **strings; +} context[] = { + { "commands text", sh_strings }, + { "c program text", c_strings }, + { "fortran program text", fortran_strings }, + { 0, 0 }, +}; + +static int addmagic(struct magic *parent, off_t o, enum magic_type t, + union magic_value v, char *m) +{ + struct magic *magic = calloc(1, sizeof(*magic)); + if (magic == NULL) { + fprintf(stderr, "file: out of memory\n"); + exit(1); + } + + magic->offset = o; + magic->type = t; + if (t == STRING) { + magic->value.string = strdup(v.string); + } else { + memcpy(&(magic->value), &v, sizeof(v)); + } + magic->message = strdup(m); + + if (parent) { + } + + insque(magic, tail); + if (tail == NULL) { + head = magic; + tail = magic; + } + + return 0; +} + +static int loadinternal(void) +{ + union magic_value cpio; + cpio.string = MAGIC; + addmagic(NULL, 0, STRING, cpio, "cpio archive"); + + union magic_value tar; + tar.string = TMAGIC; + addmagic(NULL, 0x101, STRING, tar, "tar archive"); + + union magic_value ar; + ar.string = "!<arch>"; + addmagic(NULL, 0, STRING, ar, "archive"); + + docontext = 1; + + return 0; +} + +int readmagic(const char *path) +{ + if (path == NULL) { + return loadinternal(); + } + + return 0; +} + +int idmagic(const char *path) +{ + int id = 0; + + FILE *f = fopen(path, "rb"); + if (f == NULL) { + printf(" regular file cannot open (%s)", strerror(errno)); + return 1; + } + + for (struct magic *cursor = head; cursor; cursor = cursor->next) { + size_t s = sizes[cursor->type]; + if (cursor->type == STRING) { + s = strlen(cursor->value.string) + 1; + } + char buf[s]; + + if (fseeko(f, cursor->offset, SEEK_SET) != 0) { + break; + } + + if (fread(buf, s, 1, f) == 0) { + break; + } + + if (cursor->type == STRING) { + buf[s-1] = '\0'; + } + + if ((cursor->type == STRING && !strcmp(buf, cursor->value.string)) + || memcmp(buf, &cursor->value, s) == 0) { + printf(" %s", cursor->message); + id = 1; + } + } + + if (docontext) { + fseeko(f, 0, SEEK_SET); + char *line = NULL; + size_t n = 0; + getline(&line, &n, f); + for (int i = 0; context[i].identifier; i++) { + for (int j = 0; context[i].strings[j]; j++) { + char *s = context[i].strings[j]; + if (!strncmp(line, s, strlen(s))) { + printf(" %s", context[i].identifier); + id = 1; + } + } + } + } + + if (id == 0) { + printf(" data"); + } + + fclose(f); + + return 0; +} |