From patchwork Thu Aug 23 13:37:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?0LDRgNC60LDQtNC40Lkg0LjQstCw0L3QvtCy?= X-Patchwork-Id: 961382 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Iskar15v"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41x61r6G0Hz9s4v for ; Fri, 24 Aug 2018 00:17:36 +1000 (AEST) Received: from localhost ([::1]:36753 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fsqQX-0003et-E5 for incoming@patchwork.ozlabs.org; Thu, 23 Aug 2018 10:17:33 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46634) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fspoM-0006rl-7J for qemu-devel@nongnu.org; Thu, 23 Aug 2018 09:38:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fspoI-0001tr-5e for qemu-devel@nongnu.org; Thu, 23 Aug 2018 09:38:06 -0400 Received: from mail-lj1-x22e.google.com ([2a00:1450:4864:20::22e]:38527) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fspoH-0001tN-Uf for qemu-devel@nongnu.org; Thu, 23 Aug 2018 09:38:02 -0400 Received: by mail-lj1-x22e.google.com with SMTP id p6-v6so4191487ljc.5 for ; Thu, 23 Aug 2018 06:38:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=F+w+aL2Dul1r+OT/QfuGoblcytuTUbjldSKk6+RF80E=; b=Iskar15vaSIel9Kr8U1wt8Jt05zGmuY37jAJYuXylqb/YxwcIZLmYgGZFp5mfAz13q /7qXMcylMiauiYwX/70IuK66nwym8TtDn41EWp/lhDD6/y6pyt6n58DRLPXd+QV6eorT bVjghligFV0+CFjn7nsuShYEbMwhEvSleWpvSDq3kNytNLoTv7o8NI9khgH/upzNC6BT wKBrkUFuTBn3sQRmjBaopt2MROFeNDOqfyhzqMS4L0uKgd8n76DkE910xpVYjVpgnIcL DU7xiDnxJ+eFPU2m9OF1pOH8BM4et/rgcoILujfx0mdKtW0dj7wulw30HMrSQ8u/q9y3 +Hhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=F+w+aL2Dul1r+OT/QfuGoblcytuTUbjldSKk6+RF80E=; b=qWb5N+vaL4vCJmj+egz5B1SH9AZob7GBemderIwnEcwsL3mSuAZoCyZcTOoIATlaob e6UZS9c86oKS8xhgSsNyDU/n8iy79gM0EMFD59+QP0zSmd6GitWYwuyIrHHVaevjVOQi Fk1kGcWpt0+GhNofywYKnOSGU0E/juYik4EwKSVqC1y26gkGmhGlPqz0SWNTawQB4Vy+ w4Vq1iuUQUnVOKFRzMgXDp4ALZcil4DTilC6lgeVV947LU36gxNlbNOHVybUk7K00D4d xI6Rrqp87sUL8mayBkyvEuIZy7nkGG+RfFyJfnxFA3mxH0pZykXFj3l97B/4+XJ56kf3 FIvg== X-Gm-Message-State: AOUpUlEGRAUVuOQRSH0rqb2gMzTRt5yOYAi0tFy5/oEvsiHcAdwWO8mw 40ZpYz3hFLezCvHx2mBNCrEKR7Xa X-Google-Smtp-Source: AA+uWPz2xhfK6T3Jjs3v0LIXEN2n1vUJiV4gvkkoAHwuGNRDGAYky1RPX9woxRNjKS0j1RKrC8GDVQ== X-Received: by 2002:a2e:8147:: with SMTP id t7-v6mr16154253ljg.32.1535031480159; Thu, 23 Aug 2018 06:38:00 -0700 (PDT) Received: from localhost.localdomain ([178.57.116.92]) by smtp.gmail.com with ESMTPSA id t25-v6sm764371ljb.89.2018.08.23.06.37.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 23 Aug 2018 06:37:59 -0700 (PDT) From: Arkasha To: qemu-devel@nongnu.org Date: Thu, 23 Aug 2018 16:37:42 +0300 Message-Id: <1535031462-15030-1-git-send-email-ivanovrkasha@gmail.com> X-Mailer: git-send-email 2.7.4 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::22e Subject: [Qemu-devel] [PATCH V2] block: increased maximum size of vvfat devices X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, Arkasha , pavel.dovgaluk@ispras.ru, mreitz@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This fixes the problem of the impossibility to create FAT16 disks larger than 504 mb: The change CHS made it possible to obtain a larger disk. Also, auto-detection of disk parameters was added depending on the volume of the connected files: The size of all folders and files on the created disk is calculated and the size of the FAT table is added. This size allows to choose the future size of the FAT drive from the standard limitations. Signed-off-by: Arkasha --- block/vvfat.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 10 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index fc41841..4409233 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -77,6 +77,47 @@ static void checkpoint(void); #define DIR_KANJI_FAKE 0x05 #define DIR_FREE 0x00 +static bool check_size(uint32_t offset_to_bootsector, int cyls, int heads, + int secs, uint8_t sectors_per_cluster, int fat_type, + long int sum, long int size_disk) +{ + uint32_t sector_count = cyls * heads * secs - offset_to_bootsector; + int i = 1 + sectors_per_cluster * 0x200 * 8 / fat_type; + uint16_t sectors_per_fat = (sector_count + i) / i; + /*size + FAT1 and FAT2 table size*/ + if ((sum + sectors_per_fat * 512 * 2) < size_disk) { + return true; + } + return false; +} + +static long int find_size(const char *dirname, unsigned int cluster) +{ + long int sum = 0; + DIR *dir = opendir(dirname); + struct dirent *entry; + while ((entry = readdir(dir))) { + unsigned int length = strlen(dirname) + 2 + strlen(entry->d_name); + char *buffer; + struct stat st; + buffer = g_malloc(length); + snprintf(buffer, length, "%s/%s", dirname, entry->d_name); + if (stat(buffer, &st) < 0) { + g_free(buffer); + continue; + } + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..") + && S_ISDIR(st.st_mode)) { + sum += find_size(buffer, cluster); + } + g_free(buffer); + sum += (st.st_size + cluster - 1) / (cluster) * (cluster); + } + closedir(dir); + return sum; +} + + /* dynamic array functions */ typedef struct array_t { char* pointer; @@ -948,8 +988,6 @@ static int init_directories(BDRVVVFATState* s, /* Now build FAT, and write back information into directory */ init_fat(s); - /* TODO: if there are more entries, bootsector has to be adjusted! */ - s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster; s->cluster_count=sector2cluster(s, s->sector_count); mapping = array_get_next(&(s->mapping)); @@ -1154,12 +1192,12 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, { BDRVVVFATState *s = bs->opaque; int cyls, heads, secs; + long int size_disk; bool floppy; const char *dirname, *label; QemuOpts *opts; Error *local_err = NULL; int ret; - #ifdef DEBUG vvv = s; #endif @@ -1181,6 +1219,29 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, s->fat_type = qemu_opt_get_number(opts, "fat-type", 0); floppy = qemu_opt_get_bool(opts, "floppy", false); + unsigned int cluster; + long int sum = 0; + if (floppy) { + if (!s->fat_type) { + s->sectors_per_cluster = 2; + } else { + s->sectors_per_cluster = 1; + } + } else if (s->fat_type == 12) { + s->offset_to_bootsector = 0x3f; + s->sectors_per_cluster = 0x10; + } else { + s->offset_to_bootsector = 0x3f; + /* LATER TODO: if FAT32, adjust */ + s->sectors_per_cluster = 0x80; + } + + cluster = s->sectors_per_cluster * 0x200; + sum += find_size(dirname, cluster); + /* TODO: if there are more entries, bootsector has to be adjusted! */ + s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster; + /*File size + boot sector size + root directory size*/ + sum += 512 + s->root_entries * 32; memset(s->volume_label, ' ', sizeof(s->volume_label)); label = qemu_opt_get(opts, "label"); @@ -1201,24 +1262,41 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, if (!s->fat_type) { s->fat_type = 12; secs = 36; - s->sectors_per_cluster = 2; } else { secs = s->fat_type == 12 ? 18 : 36; - s->sectors_per_cluster = 1; } cyls = 80; heads = 2; } else { - /* 32MB or 504MB disk*/ if (!s->fat_type) { s->fat_type = 16; } - s->offset_to_bootsector = 0x3f; + size_disk = 528482304; cyls = s->fat_type == 12 ? 64 : 1024; heads = 16; secs = 63; - } + if (!check_size(s->offset_to_bootsector, cyls, heads, + secs, s->sectors_per_cluster, + s->fat_type, sum, size_disk)) { + if (s->fat_type > 12) { + size_disk = 4294950912; + cyls = 8322; + heads = 16; + secs = 63; + } else { + fprintf(stderr, "Requires Fat16 or Fat32\n"); + return -2; + } + if (!check_size(s->offset_to_bootsector, cyls, heads, + secs, s->sectors_per_cluster, + s->fat_type, sum, size_disk)) { + fprintf(stderr, "Folder is larger than %f GB\n", + (float)size_disk / 1073741824); + return -2; + } + } + } switch (s->fat_type) { case 32: warn_report("FAT32 has not been tested. You are welcome to do so!"); @@ -1235,8 +1313,6 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, s->bs = bs; - /* LATER TODO: if FAT32, adjust */ - s->sectors_per_cluster=0x10; s->current_cluster=0xffffffff;