MIMEタイプの定義

こんにちは、Habr!



最近、MIMEファイルタイプを正しく判別するために必要なバイト数を知りました。 まず第一に、彼はグーグルでした、彼は受け取った答えに満足しなかったので、この主題について少し自分で研究することを決めました。



次のタスクは、この問題を調査するように促しました。smbサーバーにあるファイルのMIMEタイプを判別します。 私が思いついた最善の方法は、ファイルの一部をローカルマシンにコピーし、この部分でそのMIMEタイプを認識しようとすることです。







まず、私がグーグルで検索したものと、なぜ気に入らなかったのかを説明します。







スタックオーバーフローは、2つのウィキペディアリンクを提供します。



  1. ファイル署名によると、ほとんどの場合、2〜4バイトで十分です。 ただし、残念ながら、たとえばpdfなどの一般的な形式の場合はそうではありません。
  2. 署名のリストは、さまざまな形式のファイルの署名のリストを提供しますが、完全にはほど遠い状態です。 それからファイル署名を見つけました、すべてがここにあるようです。

    ただし、同じPDFに戻ります。 このソースを信じている場合、ファイルがpdfであると判断するには4バイトで十分です(0x25 0x50 0x44 0x46)が、最初の4バイトに基づいてlibmagicはpdfファイルのMIMEタイプはテキスト/プレーンであり、5つのうちの1つが真実であると言いましたアプリケーション/ pdf。 これが何に関連しているのかを正確に答えることは難しいと思うので、ソースを調べる必要があります。




さて、実際に私がやったことに移りましょう。 1つのディレクトリからすべてのファイルを読み取り、最初のNバイトを別のディレクトリにコピーする非常に小さなプログラムを作成し、受信したファイルの部分的なコピーから実際の内容を判別しようとしました。 など、ファイルの一部のMIMEタイプが元のMIMEタイプと一致するまで。 作業の結果に基づいて、プログラムは、1つのタイプまたは別のタイプを判別するために必要なバイト数を報告しました。 彼女のコードは次のとおりです。



#include <stdio.h> #include <stdlib.h> #include <magic.h> #include <sys/types.h> #include <dirent.h> #include <errno.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #define TEST_DIR "test-dir/" #define TMP_DIR "tmp-dir/" magic_t cookie; // Detects how many bytes required for correct MIME-type of this file void detect_size(char *filename) { int bytes = 1; int infd, outfd; char strin[100], strout[100], type[100]; char buf[4096]; strcpy(strin, TEST_DIR); strcat(strin, filename); strcpy(strout, TMP_DIR); strcat(strout, filename); while(1) { // Make a copy of given file infd = open(strin, O_RDONLY); outfd = open(strout, O_RDWR | O_CREAT, 00666); read(infd, &buf, bytes); write(outfd, &buf, bytes); lseek(infd, 0, SEEK_SET); lseek(outfd, 0, SEEK_SET); // Detect mime types of old and new const char *mime_type = magic_descriptor(cookie, infd); strcpy(type, mime_type); mime_type = magic_descriptor(cookie, outfd); // Check if mime type detected correctly if (strcmp(mime_type, type) == 0) { printf("%s detected correctly in %d bytes\n", type, bytes); unlink(strout); return; } unlink(strout); bytes++; } } int main() { DIR *dirfd = opendir(TEST_DIR); struct dirent entry, *result = NULL; cookie = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR); magic_load(cookie, NULL); while(1) { readdir_r(dirfd, &entry, &result); if (result == NULL) break; // No more entries in this directory if (!strcmp(entry.d_name, ".") || !strcmp(entry.d_name, "..")) continue; // Ignore "." and ".." detect_size(entry.d_name); } magic_close(cookie); closedir(dirfd); exit(EXIT_SUCCESS); }
      
      







その後、さまざまなファイルをtest-dirフォルダーに入れて、実験を始めました。 もちろん、私がやったことは本格的で真剣な研究を引き付けるようには見えませんが、結果のいくつかはまだ興味深いものです。 彼らに簡単な要約を与える:



application / x-sharedlibは18バイトで正しく検出されました

1793バイトでアプリケーション/ mswordが正しく検出されました

4バイトで正しく検出された画像/ gif

アプリケーション/ zipは4バイトで正しく検出されました

application / x-dosexecが2バイトで正しく検出されました

application / vnd.oasis.opendocument.presentationは85バイトで正しく検出されました

14バイトで正しく検出されたテキスト/ html

画像/ jpegは2バイトで正しく検出されました

アプリケーション/ x-executableは18バイトで正しく検出されました

text / x-makefileは1594バイトで正しく検出されました

アプリケーション/ x-executableは18バイトで正しく検出されました

application / x-gzipが2バイトで正しく検出されました

オーディオ/ MPEGは2291バイトで正しく検出されました

text / xcは27バイトで正しく検出されました

オーディオ/ x-flacが4バイトで正しく検出されました

5バイトで正しく検出されたアプリケーション/ pdf



私にとって興味深いと思われるいくつかのことに注意してください。







まあ、これはおそらく私が今回お話ししたかったすべてです、私はたくさん書くのが好きではありません。 この記事が誰かにとって興味深いものになることを願っています。

ご清聴ありがとうございました。



All Articles