#include "raw-clone.h"
#include "resize-fs.h"
#include "signal-util.h"
+#include "sparse-endian.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-table.h"
return false;
}
+int probe_sector_size(int fd, uint32_t *ret) {
+
+ struct gpt_header {
+ char signature[8];
+ le32_t revision;
+ le32_t header_size;
+ le32_t crc32;
+ le32_t reserved;
+ le64_t my_lba;
+ le64_t alternate_lba;
+ le64_t first_usable_lba;
+ le64_t last_usable_lba;
+ sd_id128_t disk_guid;
+ le64_t partition_entry_lba;
+ le32_t number_of_partition_entries;
+ le32_t size_of_partition_entry;
+ le32_t partition_entry_array_crc32;
+ } _packed_;
+
+ /* Disk images might be for 512B or for 4096 sector sizes, let's try to auto-detect that by searching
+ * for the GPT headers at the relevant byte offsets */
+
+ assert_cc(sizeof(struct gpt_header) == 92);
+
+ /* We expect a sector size in the range 512…4096. The GPT header is located in the second
+ * sector. Hence it could be at byte 512 at the earliest, and at byte 4096 at the latest. And we must
+ * read with granularity of the largest sector size we care about. Which means 8K. */
+ uint8_t sectors[2 * 4096];
+ uint32_t found = 0;
+ ssize_t n;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ n = pread(fd, sectors, sizeof(sectors), 0);
+ if (n < 0)
+ return -errno;
+ if (n != sizeof(sectors)) /* too short? */
+ goto not_found;
+
+ /* Let's see if we find the GPT partition header with various expected sector sizes */
+ for (uint32_t sz = 512; sz <= 4096; sz <<= 1) {
+ struct gpt_header *p;
+
+ assert(sizeof(sectors) >= sz * 2);
+ p = (struct gpt_header*) (sectors + sz);
+
+ if (memcmp(p->signature, (const char[8]) { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }, 8) != 0)
+ continue;
+
+ if (le32toh(p->revision) != UINT32_C(0x00010000)) /* the only known revision of the spec: 1.0 */
+ continue;
+
+ if (le32toh(p->header_size) < sizeof(struct gpt_header))
+ continue;
+
+ if (le32toh(p->header_size) > 4096) /* larger than a sector? something is off… */
+ continue;
+
+ if (le64toh(p->my_lba) != 1) /* this sector must claim to be at sector offset 1 */
+ continue;
+
+ if (found != 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
+ "Detected valid partition table at offsets matching multiple sector sizes, refusing.");
+
+ found = sz;
+ }
+
+ if (found != 0) {
+ log_debug("Determined sector size %" PRIu32 " based on discovered partition table.", found);
+ *ret = found;
+ return 1; /* indicate we *did* find it */
+ }
+
+not_found:
+ log_debug("Couldn't find any partition table to derive sector size of.");
+ *ret = 512; /* pick the traditional default */
+ return 0; /* indicate we didn't find it */
+}
+
int probe_filesystem_full(
int fd,
const char *path,