Я создаю клон git и работаю над командой hash-file. В настоящее время я пытаюсь вычислить хеш SHA1 известной строки и имею этот код и следующую проблему:
#include <openssl/sha.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int hashFile(char *file_name, int ww) {
int i, ret;
size_t size_len;
unsigned long file_size;
char path[56];
unsigned char hash[SHA_DIGEST_LENGTH];
char *token, *type, *blob_content, *content;
FILE *src = fopen(file_name, "r");
if (ferror(src)) {
perror("Unable to read file");
return 1;
}
fseek(src, 0L, SEEK_END);
file_size = ftell(src);
rewind(src);
size_len = snprintf(NULL, 0, "%lu", file_size);
char *buffer = (char *)malloc((size_t)file_size + 1);
fread(buffer, sizeof(char), file_size, src);
buffer[file_size] = '\0';
blob_content = (char *)malloc((7 + sizeof(unsigned long) + file_size + 1) *
sizeof(char));
snprintf(blob_content, 7 + size_len + 1, "blob %lu\\0", file_size);
strcat(blob_content, buffer);
SHA1((unsigned char *)blob_content, strlen(blob_content), hash);
printf("%s\n", hash);
free(blob_content);
free(buffer);
return 0;
}
void printHashHelp() {
printf("usage: twat hash-file [options] <file_name>\n");
printf("\n");
printf("options:\n");
printf("\t-w: write contents to objects store\n");
}
$ clang --std=c17 -fmodules -fprebuilt-module-path=. -I/opt/homebrew/opt/openssl/include cmd.c comp.c init.c cat.c hash.c -o twat -v
...
Undefined symbols for architecture arm64:
"_SHA1", referenced from:
_hashFile in hash-fc3ff3.o
ld: symbol(s) not found for architecture arm64
Как мне связать и включить SHA1 для работы на M2 Max? Какую команду clang
мне следует использовать, если это неверно?
Я пробовал разные методы связывания openssl/sha.h
и полагал, что у меня это получилось, но в настоящее время эта функция не работает.
Далее: Как использовать хеширование SHA1 в программировании на C Я попытался использовать связанную библиотеку, но компилятор не смог связать ее.
Примечание. Если в вашем файле есть какие-либо двоичные данные, ваша уверенность в том, что strcat и snprintf сделают правильные действия, приведет к непредсказуемым результатам.
@AndrewHenle Спасибо, что указали на это - получать размер файла таким образом было немного глупо - я получил информацию об ужасе на странице руководства zlib, поэтому я просто воспользовался этим.
@selbie Я думаю, это будет использоваться только для текстовых данных - что бы вы порекомендовали для их обобщения?
@ h5law - Я обновил свой ответ, добавив еще несколько советов по улучшению после того, как вы приняли его. Надеюсь это поможет.
@ h5law - если вы используете «rb» в Windows с fopen, это поможет обеспечить совместимость, поскольку \r\n
не будет переводиться по-другому. Смотрите мой обновленный ответ ниже.
Добавить
-L/opt/homebrew/lib -lcrypto
в вашу командную строку.
Кроме того, ваши malloc и snprintf выглядят странно. Все +1 и +7 выглядят подверженными ошибкам.
Это было бы лучше:
char header[100] = {0}; // 100 is big enough for the entire "blob 12345" thing regardless of how big the file is
SHA1_CTX ctx = {0};
SHA1_Init(&ctx);
sprintf(header, "blob %lu", file_size);
SHA1_Update(&ctx, header, strlen(header));
SHA1_Update(&ctx, buffer, file_size);
SHA1_Final(hash, &ctx);
И затем, если вы действительно хотите быть педантическим, убедитесь, что вы открываете файл как двоичный в не-Unix:
#ifdef _WIN32
char* flags = "rb";
#else
char* flags = "r";
#endif
FILE *src = fopen(file_name, flags);
убедитесь, что вы открываете файл как двоичный файл на платформах, отличных от Unix. Думаю, было бы проще просто открыть его в двоичном виде с помощью "rb"
на всех платформах.
Начиная с [email protected], команды Init Update и Final устарели в соответствии с их документацией в пользу команды SHA1. Странный malloc заключается в том, что blob_content должен хранить весь файл. Я думаю, что запись на диск может быть лучшим вариантом по сравнению с сохранением строки в памяти, а не во временном файле.
@AndrewHenle - у меня не было возможности посмотреть это, но я думал, что некоторые платформы не распознают «b» как флаг для fopen, даже если это было неактивно. Возможно, это уже не так.
@selbie Возможно, хотя это, вероятно, уже устарело. C99, похоже, требует поддержки флага b . И неизвестно, как это вообще будет работать на z/OS...
Во-первых,
FILE *src = fopen(file_name, "r"); if (ferror(src))
?? Почему вы используетеferror()
, чтобы проверить, удалось лиfopen()
?fopen()
возвращаетNULL
в случае неудачи, аferror(NULL)
вызывает неопределенное поведение. Во-вторых, вы открываете файл в текстовом режиме, а это значит, чтоftell()
не дает вам подсчета байтов. На самом деле, использованиеfseek()
/ftell()
для получения размера файла в корне неверно. См. stackoverflow.com/questions/8236/…. Вам необходимо хешировать содержимое файла, каким бы оно ни было. А как ты собираешься хешировать файл размером 382 ГБ?