open
+ lseek
を使用してデバイスのサイズを照会すると、すべてが正常であることに気付きましたが、stat
デバイスを使用すると、実際のデバイスの代わりにゼロが表示されますサイズ。デバイスはファイルシステムなしでクリーンであり、デバイスの最初のバイトは「1234567890ABC」のようなテキストで始まります。なにが問題ですか?
コード:
#include <sys/stat.h>
#include <dirent.h>
bool
GetFileSize(const char* pPath, uint64_t& Size)
{
pPath = "/home/sw/.bashrc";
pPath = "/dev/sda";
struct stat buffer;
if (stat(pPath, &buffer))
{
printf("Failed to stat file. Error: %s. FilePath: %s\n", strerror(errno), pPath);
return false;
}
printf("File size by stat: %" PRIu64 " WTF?\n", buffer.st_size);
//
// Note: It's strange, but stat::st_size from the stat call is zero for devices
//
int File = open(pPath, O_RDONLY);
if (File < 0)
{
printf("Failed to open file. Error: %s. FilePath: %s\n", strerror(errno), pPath);
return false;
}
long off = lseek(File, 0, SEEK_END);
if (off == (off_t)-1)
{
printf("Failed to get file size. Error: %s. FilePath: %s\n", strerror(errno), pPath);
close(File);
return false;
}
close(File);
printf("File size by lseek: %" PRIu64 "\n", off);
fflush(stdout);
Size = off;
return true;
}
出力:
File size by stat: 0 Huh?
File size by lseek: 34359738368
通常のファイルにstatを使用すると、すべて問題ありません(「/ dev/sda」で行をコメントアウトします)。
File size by stat: 4019 Huh?
File size by lseek: 4019
悪魔は詳細にあります...まず第一に、Unixデザインの基本原則があります:すべてがファイルです、うまく 説明ここ 。
2つ目は、stat(2)呼び出しにより、inodeがファイルシステムに保存されているdevice-サイズがゼロの特殊ファイル(lstat(2)
と考える)。ファイルシステムが存在するブロックデバイスがある場合、statfs(2)
またはgetfsstat(2)
またはstatvfs(2)
をファイルシステム/デバイスに依存しない方法で使用して、その情報を取得します。
特殊ファイル(通常は/ devにある)の処理は常にシステム固有であり、マニュアルページはセクション4にあります。したがって、デバイスを直接操作する場合は、そこで詳細を読む必要があります。たとえば、Linuxでは、man 4 hd
はプログラムでIDEブロックデバイスを操作する方法を示します。一方、man 4 sd
はscsiディスクなどを操作する方法を示します。
3番目に、システムコールの機能に矛盾がないこと[〜#〜] nor [〜#〜]の制限は想定されていません。
これがお役に立てば幸いです。
これから nix Stack Exchange 質問:
デバイスファイル自体はファイルではありません。これらは、Unixライクなオペレーティングシステムでデバイスを使用するためのI/Oインターフェイスです。これらはディスク上のスペースを使用しませんが、statコマンドによって報告されるように、iノードを使用します。
$ stat /dev/sda
File: /dev/sda
Size: 0 Blocks: 0 IO Block: 4096 block special file
Device: 6h/6d Inode: 14628 Links: 1 Device type: 8,0
これでstat
部分が解決されます。
この「ファイル」でシークできるという事実は関係ありません。これは実際にはファイルではありませんが、open
してファイルから読み取ることができます。あなたもそれを求めることができます。最下位レベルでディスクを読み取ることができるため、シークが必要です(それが機能する理由であり、「実際の」ファイルのように新しい位置を返さないのはなぜですか?)。
この他のUnixSEの回答 によると、これを読んでデバイスのサイズを取得できます/dev/sda/size
ファイル。
_/dev/sda
_などの「デバイス」の長さは POSIX _struct stat
_ で指定されていません。
_off_t st_size For regular files, the file size in bytes.
For symbolic links, the length in bytes of the
pathname contained in the symbolic link.
For a shared memory object, the length in bytes.
For a typed memory object, the length in bytes.
For other file types, the use of this field is
unspecified.
_
したがって、POSIXにはディスクデバイスの「サイズ」の要件はありません。
Linuxも同様に stat()
がディスクデバイスのサイズを返すことを指定しません:
_
st_size
_このフィールドは、ファイルのサイズ(通常のファイルまたはシンボリックリンクの場合)をバイト単位で示します。シンボリックリンクのサイズは、終端のnullバイトを含まない、リンクに含まれるパス名の長さです。
Linuxでは、文書化された、オープン可能なrawディスクデバイスのサイズを取得する方法は、BLKGETSIZE
ioctlを使用することです。 sd(4)
のマンページを参照してください。
これは、デバイスのサイズをsectorsで返すことに注意してください。バイト単位のサイズの場合、BLKSSZGET
ioctlによって返された値を乗算する必要があると思うかもしれませんが、 ソースコードを正しく読んでいる場合 は、実際にBLKSSZGET
が何を返しても、512を掛けます。