From patchwork Tue Sep 11 06:59:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 146408 Delivered-To: patch@linaro.org Received: by 2002:a2e:1648:0:0:0:0:0 with SMTP id 8-v6csp3315694ljw; Tue, 11 Sep 2018 00:05:33 -0700 (PDT) X-Google-Smtp-Source: ANB0VdbByShD6YWjRmQABW6Zv590kTtyWURiCdjBrK+MpAtfG/CP63TrxFvZGA2B7aQZ4mdbvKXf X-Received: by 2002:a50:b7db:: with SMTP id i27-v6mr27311984ede.284.1536649533405; Tue, 11 Sep 2018 00:05:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1536649533; cv=none; d=google.com; s=arc-20160816; b=yGiA4IWunYbwIHFYMDQWApDn/hTtQdCPzMTGZsf1lbqP1R6kGW9mBVmB4WRO1dxpjg d4ua0hch0Xx7YunwRQxTvTb2zLee46wuGHirCLgew0r8hZikesIy4gKv8+odmE6jRupN /8upKqaqDFC0yeqC0j+Sg6pA4l1FFxhxs1ytYe9rj/wSaF+WSCkgqCYIuUxIiqpeZ1cA V/UZJVR+CwVyBbn1RrzhVMOQ4hUBQNCimt+uNwuy6dZHYJhGESVYjWQdH9GhZnNF7R66 IP8WDeoGpnqQoIixpW0fygO7x6b39xJoxI8cfhdp6WJRL4U0LG0m3JMqIx04vzCvVAX5 rZDw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature; bh=KR3ol98ispkUpcCN5jE+NgBwqP8r9KSwJMjTj6yWW4I=; b=NOeIpcB3oy1ooKzPhRQW1CtJYTDvGAUDUKdrbzMAbRvU/4xMmIz9m9eCFQoRruYo4W 5Sdy164kFBNezO0jqBEBHixA8grc6oh8pRul7NZpnzBWFhI1zi2Ck8bL22xK/bOpjXnV 0JXlGNrMyoU275p/q20VqQnWuMwdMZ5Bvc9vQ6XKT3zKmr7sXKTqBNglZWC9NJ7BHfRI BZxRgRKnWK85nZ+rDFY//16for9uWFEoJAEceYbnIeiTrmw6KcKphQoEJim5BS3Y1GM5 +KEYaaHETbcV/4QNkb7AMP0wt1JvG567KEVVYPOV9bA7mxVfMPdKTyTUodaflgyh7H6C gAnQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=A6cYHgfk; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id m8-v6si557823edj.236.2018.09.11.00.05.33; Tue, 11 Sep 2018 00:05:33 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=A6cYHgfk; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: by lists.denx.de (Postfix, from userid 105) id D368CC21E13; Tue, 11 Sep 2018 07:03:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id DAD50C21EDE; Tue, 11 Sep 2018 07:00:11 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 92E75C21EFD; Tue, 11 Sep 2018 06:59:38 +0000 (UTC) Received: from mail-pf1-f195.google.com (mail-pf1-f195.google.com [209.85.210.195]) by lists.denx.de (Postfix) with ESMTPS id BFF94C21E4E for ; Tue, 11 Sep 2018 06:59:33 +0000 (UTC) Received: by mail-pf1-f195.google.com with SMTP id u24-v6so11726897pfn.13 for ; Mon, 10 Sep 2018 23:59:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=4PONucRGR9V0Hud3joGkF+3QgBqMV6Pco8o94a2cJDo=; b=A6cYHgfkSOeqeS1AEcxKKNUGJFpNkLzXjOq4uOmwrAAsGXBv12hUWXLY+3G+P+HcNq cFexAY4jpb+qHg3isxHTEr2Br3xNG8PuOkqT6SMHW9DpGPiLQCFnOt6T//njZV/C0yOU QRJb/eOQdKvI78Vr6Pwr23mCfd6RCVUFfDmjs= 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:in-reply-to :references; bh=4PONucRGR9V0Hud3joGkF+3QgBqMV6Pco8o94a2cJDo=; b=YZOr8+ywTfIkWFusJmDTWsn/iAHddTZTMtUeN7DPyBv3Ma+Jfletk3S+RvXnBuEHRA oxkbQqm5pHQ6R/RvauJtJJfGXAhdI4wApovapa9VG22J3t7tpKpTJNFuAiAC1bDyHgFa yrU73hzG+9wOSryeMubBVACn0l1FPCyAgG63oYWCpMP3vzC1IAcJAq7yCyCG9qOt9PyI sSUKRzyOa6o1ymNGn2O66QRoAS0UtwL9xptoMOlTMzpy+JuBtz7ss0ovKUmpp5wVBN8M FGFzRgLr8/qyyKEXz1bNP2RIXSwK4CXa7y5Gqg11n5+Geula7Zaqq2Y9g/2DL7IId9D3 aq6A== X-Gm-Message-State: APzg51CmoOWDZFjMWCxE+DLvde5/6XiWDTKt5jln0BQOz7n1XZDXpULC OnVKPRzBp55h9jWZr7Ioqy/ifA== X-Received: by 2002:a63:77ce:: with SMTP id s197-v6mr27032666pgc.172.1536649172151; Mon, 10 Sep 2018 23:59:32 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id j27-v6sm31485315pfj.91.2018.09.10.23.59.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 10 Sep 2018 23:59:31 -0700 (PDT) From: "Akashi, Takahiro" To: trini@konsulko.com Date: Tue, 11 Sep 2018 15:59:04 +0900 Message-Id: <20180911065922.19141-9-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180911065922.19141-1-takahiro.akashi@linaro.org> References: <20180911065922.19141-1-takahiro.akashi@linaro.org> Cc: u-boot@lists.denx.de, xypron.glpk@gmx.de, agraf@suse.de Subject: [U-Boot] [PATCH v3 08/26] fs: fat: support write with sub-directory path X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: AKASHI Takahiro In this patch, write implementation is overhauled and rewritten by making full use of directory iterator. The obvious bonus is that we are now able to write to a file with a directory path, like /A/B/C/FILE. Please note that, as there is no notion of "current directory" on u-boot, a file name specified must contain an absolute directory path. Otherwise, "/" (root directory) is assumed. Signed-off-by: AKASHI Takahiro --- fs/fat/fat.c | 9 - fs/fat/fat_write.c | 469 +++++++++++++++------------------------------ 2 files changed, 156 insertions(+), 322 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index afb8b3f9ef1a..5aa28656c7d5 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -464,15 +464,6 @@ static __u8 mkcksum(const char name[8], const char ext[3]) return ret; } -/* - * TODO these should go away once fat_write is reworked to use the - * directory iterator - */ -__u8 get_dentfromdir_block[MAX_CLUSTSIZE] - __aligned(ARCH_DMA_MINALIGN); -__u8 do_fat_read_at_block[MAX_CLUSTSIZE] - __aligned(ARCH_DMA_MINALIGN); - /* * Read boot sector and volume info from a FAT filesystem */ diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 1e4f5af9106d..37ef0564eb5e 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -99,7 +99,6 @@ static void set_name(dir_entry *dirent, const char *filename) debug("ext : %s\n", dirent->ext); } -static __u8 num_of_fats; /* * Write fat buffer into block device */ @@ -128,7 +127,7 @@ static int flush_dirty_fat_buffer(fsdata *mydata) return -1; } - if (num_of_fats == 2) { + if (mydata->fats == 2) { /* Update corresponding second FAT blocks */ startblock += mydata->fatlength; if (disk_write(startblock, getsize, bufptr) < 0) { @@ -210,15 +209,14 @@ name11_12: return 1; } -static int is_next_clust(fsdata *mydata, dir_entry *dentptr); -static void flush_dir_table(fsdata *mydata, dir_entry **dentptr); +static int flush_dir_table(fat_itr *itr); /* * Fill dir_slot entries with appropriate name, id, and attr - * The real directory entry is returned by 'dentptr' + * 'itr' will point to a next entry */ -static void -fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) +static int +fill_dir_slot(fat_itr *itr, const char *l_name) { __u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)]; dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer; @@ -226,7 +224,7 @@ fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) int idx = 0, ret; /* Get short file name checksum value */ - checksum = mkcksum((*dentptr)->name, (*dentptr)->ext); + checksum = mkcksum(itr->dent->name, itr->dent->ext); do { memset(slotptr, 0x00, sizeof(dir_slot)); @@ -241,120 +239,21 @@ fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name) slotptr->id |= LAST_LONG_ENTRY_MASK; while (counter >= 1) { - if (is_next_clust(mydata, *dentptr)) { - /* A new cluster is allocated for directory table */ - flush_dir_table(mydata, dentptr); - } - memcpy(*dentptr, slotptr, sizeof(dir_slot)); - (*dentptr)++; + memcpy(itr->dent, slotptr, sizeof(dir_slot)); slotptr--; counter--; - } - - if (is_next_clust(mydata, *dentptr)) { - /* A new cluster is allocated for directory table */ - flush_dir_table(mydata, dentptr); - } -} - -static __u32 dir_curclust; - -/* - * Extract the full long filename starting at 'retdent' (which is really - * a slot) into 'l_name'. If successful also copy the real directory entry - * into 'retdent' - * If additional adjacent cluster for directory entries is read into memory, - * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and - * the location of the real directory entry is returned by 'retdent' - * Return 0 on success, -1 otherwise. - */ -static int -get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster, - dir_entry **retdent, char *l_name) -{ - dir_entry *realdent; - dir_slot *slotptr = (dir_slot *)(*retdent); - dir_slot *slotptr2 = NULL; - __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? - PREFETCH_BLOCKS : - mydata->clust_size); - __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; - int idx = 0, cur_position = 0; - - if (counter > VFAT_MAXSEQ) { - debug("Error: VFAT name is too long\n"); - return -1; - } - - while ((__u8 *)slotptr < buflimit) { - if (counter == 0) - break; - if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) - return -1; - slotptr++; - counter--; - } - - if ((__u8 *)slotptr >= buflimit) { - if (curclust == 0) - return -1; - curclust = get_fatent(mydata, dir_curclust); - if (CHECK_CLUST(curclust, mydata->fatsize)) { - debug("curclust: 0x%x\n", curclust); - printf("Invalid FAT entry\n"); - return -1; - } - - dir_curclust = curclust; - - if (get_cluster(mydata, curclust, get_contents_vfatname_block, - mydata->clust_size * mydata->sect_size) != 0) { - debug("Error: reading directory block\n"); - return -1; - } - - slotptr2 = (dir_slot *)get_contents_vfatname_block; - while (counter > 0) { - if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) - & 0xff) != counter) + if (!fat_itr_next(itr)) + if (!itr->dent && !itr->is_root && flush_dir_table(itr)) return -1; - slotptr2++; - counter--; - } - - /* Save the real directory entry */ - realdent = (dir_entry *)slotptr2; - while ((__u8 *)slotptr2 > get_contents_vfatname_block) { - slotptr2--; - slot2str(slotptr2, l_name, &idx); - } - } else { - /* Save the real directory entry */ - realdent = (dir_entry *)slotptr; } - do { - slotptr--; - if (slot2str(slotptr, l_name, &idx)) - break; - } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); - - l_name[idx] = '\0'; - if (*l_name == DELETED_FLAG) - *l_name = '\0'; - else if (*l_name == aRING) - *l_name = DELETED_FLAG; - downcase(l_name, INT_MAX); - - /* Return the real directory entry */ - *retdent = realdent; - - if (slotptr2) { - memcpy(get_dentfromdir_block, get_contents_vfatname_block, - mydata->clust_size * mydata->sect_size); - cur_position = (__u8 *)realdent - get_contents_vfatname_block; - *retdent = (dir_entry *) &get_dentfromdir_block[cur_position]; - } + if (!itr->dent && !itr->is_root) + /* + * don't care return value here because we have already + * finished completing an entry with name, only ending up + * no more entry left + */ + flush_dir_table(itr); return 0; } @@ -569,20 +468,20 @@ static int find_empty_cluster(fsdata *mydata) } /* - * Write directory entries in 'get_dentfromdir_block' to block device + * Write directory entries in itr's buffer to block device */ -static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) +static int flush_dir_table(fat_itr *itr) { + fsdata *mydata = itr->fsdata; int dir_newclust = 0; + unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; - if (set_cluster(mydata, dir_curclust, - get_dentfromdir_block, - mydata->clust_size * mydata->sect_size) != 0) { - printf("error: wrinting directory entry\n"); - return; + if (set_cluster(mydata, itr->clust, itr->block, bytesperclust) != 0) { + printf("error: writing directory entry\n"); + return -1; } dir_newclust = find_empty_cluster(mydata); - set_fatent_value(mydata, dir_curclust, dir_newclust); + set_fatent_value(mydata, itr->clust, dir_newclust); if (mydata->fatsize == 32) set_fatent_value(mydata, dir_newclust, 0xffffff8); else if (mydata->fatsize == 16) @@ -590,15 +489,19 @@ static void flush_dir_table(fsdata *mydata, dir_entry **dentptr) else if (mydata->fatsize == 12) set_fatent_value(mydata, dir_newclust, 0xff8); - dir_curclust = dir_newclust; + itr->clust = dir_newclust; + itr->next_clust = dir_newclust; if (flush_dirty_fat_buffer(mydata) < 0) - return; + return -1; + + memset(itr->block, 0x00, bytesperclust); - memset(get_dentfromdir_block, 0x00, - mydata->clust_size * mydata->sect_size); + itr->dent = (dir_entry *)itr->block; + itr->last_cluster = 1; + itr->remaining = bytesperclust / sizeof(dir_entry) - 1; - *dentptr = (dir_entry *) get_dentfromdir_block; + return 0; } /* @@ -764,139 +667,83 @@ static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) return 0; } -/* - * Check if adding several entries exceed one cluster boundary - */ -static int is_next_clust(fsdata *mydata, dir_entry *dentptr) -{ - int cur_position; - - cur_position = (__u8 *)dentptr - get_dentfromdir_block; - - if (cur_position >= mydata->clust_size * mydata->sect_size) - return 1; - else - return 0; -} - -static dir_entry *empty_dentptr; /* * Find a directory entry based on filename or start cluster number * If the directory entry is not found, * the new position for writing a directory entry will be returned */ -static dir_entry *find_directory_entry(fsdata *mydata, int startsect, - char *filename, dir_entry *retdent, __u32 start) +static dir_entry *find_directory_entry(fat_itr *itr, char *filename) { - __u32 curclust = sect_to_clust(mydata, startsect); - - debug("get_dentfromdir: %s\n", filename); + int match = 0; - while (1) { - dir_entry *dentptr; + while (fat_itr_next(itr)) { + /* check both long and short name: */ + if (!strcasecmp(filename, itr->name)) + match = 1; + else if (itr->name != itr->s_name && + !strcasecmp(filename, itr->s_name)) + match = 1; - int i; + if (!match) + continue; - if (get_cluster(mydata, curclust, get_dentfromdir_block, - mydata->clust_size * mydata->sect_size) != 0) { - printf("Error: reading directory block\n"); + if (itr->dent->name[0] == '\0') return NULL; - } - - dentptr = (dir_entry *)get_dentfromdir_block; - - dir_curclust = curclust; - - for (i = 0; i < DIRENTSPERCLUST; i++) { - char s_name[14], l_name[VFAT_MAXLEN_BYTES]; - - l_name[0] = '\0'; - if (dentptr->name[0] == DELETED_FLAG) { - dentptr++; - if (is_next_clust(mydata, dentptr)) - break; - continue; - } - if ((dentptr->attr & ATTR_VOLUME)) { - if ((dentptr->attr & ATTR_VFAT) && - (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { - get_long_file_name(mydata, curclust, - get_dentfromdir_block, - &dentptr, l_name); - debug("vfatname: |%s|\n", l_name); - } else { - /* Volume label or VFAT entry */ - dentptr++; - if (is_next_clust(mydata, dentptr)) - break; - continue; - } - } - if (dentptr->name[0] == 0) { - debug("Dentname == NULL - %d\n", i); - empty_dentptr = dentptr; - return NULL; - } - - get_name(dentptr, s_name); - - if (strncasecmp(filename, s_name, sizeof(s_name)) && - strncasecmp(filename, l_name, sizeof(l_name))) { - debug("Mismatch: |%s|%s|\n", - s_name, l_name); - dentptr++; - if (is_next_clust(mydata, dentptr)) - break; - continue; - } + else + return itr->dent; + } - memcpy(retdent, dentptr, sizeof(dir_entry)); + if (!itr->dent && !itr->is_root && flush_dir_table(itr)) + /* indicate that allocating dent failed */ + itr->dent = NULL; - debug("DentName: %s", s_name); - debug(", start: 0x%x", START(dentptr)); - debug(", size: 0x%x %s\n", - FAT2CPU32(dentptr->size), - (dentptr->attr & ATTR_DIR) ? - "(DIR)" : ""); + return NULL; +} - return dentptr; +static int split_filename(char *filename, char **dirname, char **basename) +{ + char *p, *last_slash, *last_slash_cont; + +again: + p = filename; + last_slash = NULL; + last_slash_cont = NULL; + while (*p) { + if (ISDIRDELIM(*p)) { + last_slash = p; + last_slash_cont = p; + /* continuous slashes */ + while (ISDIRDELIM(*p)) + last_slash_cont = p++; + if (!*p) + break; } + p++; + } - /* - * In FAT16/12, the root dir is locate before data area, shows - * in following: - * ------------------------------------------------------------- - * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) | - * ------------------------------------------------------------- - * - * As a result if curclust is in Root dir, it is a negative - * number or 0, 1. - * - */ - if (mydata->fatsize != 32 && (int)curclust <= 1) { - /* Current clust is in root dir, set to next clust */ - curclust++; - if ((int)curclust <= 1) - continue; /* continue to find */ - - /* Reach the end of root dir */ - empty_dentptr = dentptr; - return NULL; + if (last_slash) { + if (last_slash_cont == (filename + strlen(filename) - 1)) { + /* remove trailing slashes */ + *last_slash = '\0'; + goto again; } - curclust = get_fatent(mydata, dir_curclust); - if (IS_LAST_CLUST(curclust, mydata->fatsize)) { - empty_dentptr = dentptr; - return NULL; - } - if (CHECK_CLUST(curclust, mydata->fatsize)) { - debug("curclust: 0x%x\n", curclust); - debug("Invalid FAT entry\n"); - return NULL; + if (last_slash == filename) { + /* avoid ""(null) directory */ + *dirname = "/"; + } else { + *last_slash = '\0'; + *dirname = filename; } + + *last_slash_cont = '\0'; + *basename = last_slash_cont + 1; + } else { + *dirname = "/"; /* root by default */ + *basename = filename; } - return NULL; + return 0; } static int normalize_longname(char *l_filename, const char *filename) @@ -940,86 +787,58 @@ static int normalize_longname(char *l_filename, const char *filename) static int do_fat_write(const char *filename, void *buffer, loff_t size, loff_t *actwrite) { - dir_entry *dentptr, *retdent; - __u32 startsect; + dir_entry *retdent; __u32 start_cluster; - boot_sector bs; - volume_info volinfo; - fsdata datablock; + fsdata datablock = { .fatbuf = NULL, }; fsdata *mydata = &datablock; - int cursect; + fat_itr *itr = NULL; int ret = -1; + char *filename_copy, *parent, *basename; char l_filename[VFAT_MAXLEN_BYTES]; - *actwrite = size; - dir_curclust = 0; + filename_copy = strdup(filename); + if (!filename_copy) + return -ENOMEM; - if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { - debug("error: reading boot sector\n"); - return -EIO; + split_filename(filename_copy, &parent, &basename); + if (!strlen(basename)) { + ret = -EINVAL; + goto exit; } - total_sector = bs.total_sect; - if (total_sector == 0) - total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ - - if (mydata->fatsize == 32) - mydata->fatlength = bs.fat32_length; - else - mydata->fatlength = bs.fat_length; - - mydata->fat_sect = bs.reserved; - - cursect = mydata->rootdir_sect - = mydata->fat_sect + mydata->fatlength * bs.fats; - num_of_fats = bs.fats; - - mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; - mydata->clust_size = bs.cluster_size; - - if (mydata->fatsize == 32) { - mydata->data_begin = mydata->rootdir_sect - - (mydata->clust_size * 2); - } else { - int rootdir_size; - - rootdir_size = ((bs.dir_entries[1] * (int)256 + - bs.dir_entries[0]) * - sizeof(dir_entry)) / - mydata->sect_size; - mydata->data_begin = mydata->rootdir_sect + - rootdir_size - - (mydata->clust_size * 2); + filename = basename; + if (normalize_longname(l_filename, filename)) { + printf("FAT: illegal filename (%s)\n", filename); + ret = -EINVAL; + goto exit; } - mydata->fatbufnum = -1; - mydata->fat_dirty = 0; - mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); - if (mydata->fatbuf == NULL) { - debug("Error: allocating memory\n"); - return -ENOMEM; + itr = malloc_cache_aligned(sizeof(fat_itr)); + if (!itr) { + ret = -ENOMEM; + goto exit; } - if (disk_read(cursect, - (mydata->fatsize == 32) ? - (mydata->clust_size) : - PREFETCH_BLOCKS, do_fat_read_at_block) < 0) { - debug("Error: reading rootdir block\n"); - ret = -EIO; + ret = fat_itr_root(itr, &datablock); + if (ret) goto exit; - } - dentptr = (dir_entry *) do_fat_read_at_block; - if (normalize_longname(l_filename, filename)) { - printf("FAT: illegal filename (%s)\n", filename); - ret = -EINVAL; + total_sector = datablock.total_sect; + + ret = fat_itr_resolve(itr, parent, TYPE_DIR); + if (ret) { + printf("%s: doesn't exist (%d)\n", parent, ret); goto exit; } - startsect = mydata->rootdir_sect; - retdent = find_directory_entry(mydata, startsect, - l_filename, dentptr, 0); + retdent = find_directory_entry(itr, l_filename); + if (retdent) { + if (fat_itr_isdir(itr)) { + ret = -EISDIR; + goto exit; + } + /* Update file size and start_cluster in a directory entry */ retdent->size = cpu_to_le32(size); start_cluster = START(retdent); @@ -1062,9 +881,31 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, set_start_cluster(mydata, retdent, start_cluster); } } else { + /* Create a new file */ + + if (itr->is_root) { + /* root dir cannot have "." or ".." */ + if (!strcmp(l_filename, ".") || + !strcmp(l_filename, "..")) { + ret = -EINVAL; + goto exit; + } + } + + if (!itr->dent) { + printf("Error: allocating new dir entry\n"); + ret = -EIO; + goto exit; + } + + memset(itr->dent, 0, sizeof(*itr->dent)); + /* Set short name to set alias checksum field in dir_slot */ - set_name(empty_dentptr, filename); - fill_dir_slot(mydata, &empty_dentptr, filename); + set_name(itr->dent, filename); + if (fill_dir_slot(itr, filename)) { + ret = -EIO; + goto exit; + } if (size) { ret = start_cluster = find_empty_cluster(mydata); @@ -1084,11 +925,11 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, start_cluster = 0; } - /* Set attribute as archieve for regular file */ - fill_dentry(mydata, empty_dentptr, filename, - start_cluster, size, 0x20); + /* Set attribute as archive for regular file */ + fill_dentry(itr->fsdata, itr->dent, filename, + start_cluster, size, 0x20); - retdent = empty_dentptr; + retdent = itr->dent; } ret = set_contents(mydata, retdent, buffer, size, actwrite); @@ -1108,15 +949,17 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, } /* Write directory table to device */ - ret = set_cluster(mydata, dir_curclust, get_dentfromdir_block, - mydata->clust_size * mydata->sect_size); + ret = set_cluster(mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size); if (ret) { printf("Error: writing directory entry\n"); ret = -EIO; } exit: + free(filename_copy); free(mydata->fatbuf); + free(itr); return ret; }