알려진 크기의 파일을 저장하기 위해 FAT 형식의 디스크 이미지를 만드는 중입니다. 이 경우 1GiB 파일입니다.
예를 들어:
# Create a file that's 1 GiB in size.
dd if=/dev/zero iflag=count_bytes of=./large-file bs=1M count=1G
# Measure file size in KiB.
LARGE_FILE_SIZE_KIB="$(du --summarize --block-size=1024 large-file | cut --fields 1)"
# Create a FAT-formatted disk image.
mkfs.vfat -vv -C ./disk.img "${LARGE_FILE_SIZE_KIB}"
# Mount disk image using a loopback device.
mount -o loop ./disk.img /mnt
# Copy the large file to the disk image.
cp --archive ./large-file /mnt
다음 출력과 함께 스크립트가 실패합니다.
++ dd if=/dev/zero iflag=count_bytes of=./large-file bs=1M count=1G
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 39.6962 s, 27.0 MB/s
+++ du --summarize --block-size=1024 large-file
+++ cut --fields 1
++ LARGE_FILE_SIZE_KIB=1048580
++ mkfs.vfat -vv -C ./disk.img 1048580
mkfs.fat 4.2 (2021-01-31)
Auto-selecting FAT32 for large filesystem
Boot jump code is eb 58
Using 32 reserved sectors
Trying with 8 sectors/cluster:
Trying FAT32: #clu=261627, fatlen=2048, maxclu=262144, limit=65525/268435446
Using sector 6 as backup boot sector (0 = none)
./disk.img has 64 heads and 63 sectors per track,
hidden sectors 0x0000;
logical sector size is 512,
using 0xf8 media descriptor, with 2097144 sectors;
drive number 0x80;
filesystem has 2 32-bit FATs and 8 sectors per cluster.
FAT size is 2048 sectors, and provides 261627 clusters.
There are 32 reserved sectors.
Volume ID is f0de10c3, no volume label.
++ mount -o loop ./disk.img /mnt
++ cp --archive ./large-file /mnt
cp: error writing '/mnt/large-file': No space left on device
알려진 크기의 파일을 저장할 수 있을 만큼 큰 FAT 형식의 디스크 이미지를 만드는 방법은 무엇입니까?
자원:
- https://linux.die.net/man/1/dd
- https://linux.die.net/man/8/mkfs.vfat
- https://linux.die.net/man/8/mount
- https://linux.die.net/man/1/cp
- https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Size_limits
편집 1
내 가정은 이것이 KiB의 여유 공간을 가진 이미지를 mkfs.vfat -C ./disk.img N
생성할 것이라는 것이 N
었지만, 그렇지 않은 것 같습니다.
답변1
공간이 충분하지 않은 파일 시스템에 파일을 넣으려는 것 같습니다. 이는 의도적으로 설계된 것입니다! 기본적으로 "N kB가 필요한 파일의 경우 디스크 이미지 크기를 정확히 N kB로 만듭니다"라고 말하는 것입니다. FAT는 파일 메타데이터, 디렉터리 테이블 및 볼륨 설명자를 정확히 어디에 저장합니까?
FAT32, 표준 반복 슈퍼블록, 일반적인 디렉터리 테이블 + 긴 파일 이름 테이블, 그리고 디스크 어딘가에 32개의 예약된 섹터를 사용하면 내 생각에는 약 4MB 정도의 추가 공간이 필요할 것 같습니다. 대용량 파일 시스템.
또한 1980년대와 1990년대 초반에 구축된 PC에 적합한 구성인 기본 mkfs.vfat를 사용하고 있습니다. 이는 더 작은 섹터를 의미하므로 추적할 섹터가 더 많기 때문에 FAT가 저장되면 파일을 하나 더 소비합니다. 파일 시스템에서 섹터 크기를 최대화합니다.1GB 이상의 여유 공간(그래서 디스크 이미지는 1GB보다 훨씬 큽니다!), 16kB~해야 한다작동합니다(최소 "FAT32-legal" 클러스터 수는 65525이며, 4kB 섹터를 1GB로 나눈 것으로 가정 -S 4096
하고 클러스터 크기를 16섹터로 최대화하므로 -s 16
).
또한 참고: 1GB를 사용하면 이미 FAT32의 최대 파일 크기인 2GB에 매우 가깝습니다. 따라서 백업이나 파일 시스템 이미지 등의 저장 용도로 사용하려는 경우 FAT32로는 충분하지 않다는 것을 금방 알 수 있습니다. 그것은매우오래된 파일 시스템.
부록: 이미지가 콘텐츠보다 얼마나 큰지 계산하는 방법
위에서 언급한 것처럼 FAT는 섹터 수에 대한 임의의(놀랍게도 낮은!) 제한이 있어 얼마나 많은 오버헤드가 발생할지 예측하기가 약간 어렵기 때문에 약간 성가십니다.
하지만, 이점은 Linux 지원입니다.부족한이는 저장 공간을 "소모"하지 않는 "빈" 이미지를 만들 수 있음을 의미합니다. 이미지가 필요한 것보다 클 수 있습니다!
그런 다음 필요한 데이터로 채우고 원하는 크기로 축소할 수 있습니다.
일반적으로 귀하의 질문에 있는 스크립트는 문제의 일부 작업을 수행하며 동일한 작업을 수행하는 더 합리적인 방법이 있습니다. 코드에서 내 명령에 해당하는 내용을 설명하겠습니다. 아이디어는 간단합니다. 필요한 것보다 훨씬 크지만 저장 공간 측면에서 "무료"인 이미지 파일을 만들고 먼저 필요한 파일로 채운 다음 남은 여유 공간이 얼마나 되는지 확인합니다. 이미지 크기에서 해당 공간을 빼고 새 이미지를 만들면 완료됩니다.
# File(s) we want to store
files=( *.data ) # whatever you want to store.
imgfile="fat32.img"
# First, figure out how much size we'll need
# use `stat` to get the size in bytes instead of parsing `du`'s output
# Replace the new line after each file size with a "+" and add the initial overhead.
initial_overhead=$(( 5 * 2**20 )) # 5 MiB
# Then use your shell's arithmetic evaluation $(( … )) to execute that sum
totalsize=$(( $(stat -c '%s' -- "${files[@]}" | tr '\n' '+') initial_overhead ))
# give an extra 20% (no floating point math in bash…), then round to 1 kiB blocks
img_size=$(( ( totalsize * 120 / 100 + 1023 ) / 1024 * 1024 ))
# Create a file of that size
fallocate -l ${img_size} -- "${img_file}"
mkfs.vfat -vv -- "${img_file}"
# set up loopback device as regular user, and extract loopback
# device name from result
loopback=$(udisksctl loop-setup - "${img_file}" | sed 's/.* \([^ ]*\)\.$/\1/')
# mount loopback device as regular user, and get mount path
mounted=$(udisksctl mount -b "${loopback}" | sed 's/^.* \([^ ]*\)$/\1/')
# make sure we're good so far
[[ -d "${mounted}" ]] || (echo "couldn't get mount"; exit -1)
# copy over files…
cp -- "${files[@]}" "${mounted}"
# … and unmount our file system image
udisksctl unmount -b "${loopback}"
udisksctl loop-delete -b "${loopback}"
# use df to directly get the amount of free space in kilobyte blocks
free_space=$(df --direct --block-size=1K --output=avail -- "${img_file}" | tail -n1)
# We no longer need our temporary image
rm -- "${img_file}"
# subtract 2 kB just to be on the safe side when making new image
new_img_size=$(( free_space - 2 ))
# Make a new image, copy over files
fallocate -l ${new_img_size} -- "${img_file}"
mkfs.vfat -vv -- "${img_file}"
loopback=$(udisksctl loop-setup - "${img_file}" | sed 's/.* \([^ ]*\)\.$/\1/')
mounted=$(udisksctl mount -b "${loopback}" | sed 's/^.* \([^ ]*\)$/\1/')
[[ -d "${mounted}" ]] || (echo "final copy: couldn't get mount"; exit -1)
cp -- "${files[@]}" "${mounted}"
udisksctl unmount -b "${loopback}"
udisksctl loop-delete -b "${loopback}"
# Done!
1: FAT32가 도입되었을 때 1GB 하드 드라이브는 여전히 그렇게 작지 않았습니다. 파일 시스템 구조는 1981년 FAT12에서 파생되었으며 1GB 하드 드라이브에 필요한 블록 수인 360kB 크기의 플로피 디스크용으로 설계되었습니다. 유지하는 것은 약 15년 후에만 증가할 것입니다. 실제로 FAT32로 포맷된 SD 카드가 장착된 스마트폰에는 1997년경에 발명된 파일 시스템의 타임캡슐이 들어 있습니다. 이 파일 시스템 자체는 1980년에 발명된 파일 시스템의 비교적 사소한 수정이므로 현대의 저장 문제가 해결되었습니다. 44년 전의 타협 솔루션을 사용합니다.
답변2
귀하의 코드를 수정하고 몇 가지 추가 설명을 추가했습니다.
작동 방식은 다음과 같습니다.
# Create a file that's 1 GiB in size.
dd if=/dev/zero iflag=count_bytes of=./large-file bs=1M count=1G
# Measure file size in KiB. BUT TWICE THE SIZE!
# Double parentheses are needed for arithmetic
LARGE_FILE_SIZE_KIB=$(($(du --summarize --block-size=1024 large-file | cut --fields 1) * 2))
# Create a FAT-formatted disk image.
sudo mkfs.vfat -vv -C ./disk.img "${LARGE_FILE_SIZE_KIB}"
# Create mount directory
sudo mkdir /mnt/test
# Mount disk image using a loopback device.
sudo mount -o loop -t vfat ./disk.img /mnt/test
# Copy the large file to the disk image.
# BUT do not use --archive option
sudo cp ./large-file /mnt/test
편집하다:
부인 성명.
가상 디스크의 최소 크기가 복사되는 파일 크기의 두 배여야 하는 이유를 조사하지 않았습니다.
그러나 나는 이것이 1GB 파일을 수용하기에는 너무 낮거나 너무 높은 블록 크기와 관련이 있다고 생각합니다.