summaryrefslogtreecommitdiff
path: root/fs/fat/fat_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat/fat_write.c')
-rw-r--r--fs/fat/fat_write.c227
1 files changed, 129 insertions, 98 deletions
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index 98b88ad..af828d0 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -30,6 +30,8 @@ static void uppercase(char *str, int len)
static int total_sector;
static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
{
+ ulong ret;
+
if (!cur_dev || !cur_dev->block_write)
return -1;
@@ -39,8 +41,13 @@ static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
return -1;
}
- return cur_dev->block_write(cur_dev->dev,
- cur_part_info.start + block, nr_blocks, buf);
+ ret = cur_dev->block_write(cur_dev->dev,
+ cur_part_info.start + block,
+ nr_blocks, buf);
+ if (nr_blocks && ret == 0)
+ return -1;
+
+ return ret;
}
/*
@@ -548,8 +555,9 @@ static int
set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
unsigned long size)
{
- int idx = 0;
+ __u32 idx = 0;
__u32 startsect;
+ int ret;
if (clustnum > 0)
startsect = mydata->data_begin +
@@ -559,26 +567,45 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
debug("clustnum: %d, startsect: %d\n", clustnum, startsect);
- if ((size / mydata->sect_size) > 0) {
- if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) {
- debug("Error writing data\n");
+ if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
+ ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
+
+ printf("FAT: Misaligned buffer address (%p)\n", buffer);
+
+ while (size >= mydata->sect_size) {
+ memcpy(tmpbuf, buffer, mydata->sect_size);
+ ret = disk_write(startsect++, 1, tmpbuf);
+ if (ret != 1) {
+ debug("Error writing data (got %d)\n", ret);
+ return -1;
+ }
+
+ buffer += mydata->sect_size;
+ size -= mydata->sect_size;
+ }
+ } else if (size >= mydata->sect_size) {
+ idx = size / mydata->sect_size;
+ ret = disk_write(startsect, idx, buffer);
+ if (ret != idx) {
+ debug("Error writing data (got %d)\n", ret);
return -1;
}
- }
- if (size % mydata->sect_size) {
- __u8 tmpbuf[mydata->sect_size];
+ startsect += idx;
+ idx *= mydata->sect_size;
+ buffer += idx;
+ size -= idx;
+ }
- idx = size / mydata->sect_size;
- buffer += idx * mydata->sect_size;
- memcpy(tmpbuf, buffer, size % mydata->sect_size);
+ if (size) {
+ ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
- if (disk_write(startsect + idx, 1, tmpbuf) < 0) {
- debug("Error writing data\n");
+ memcpy(tmpbuf, buffer, size);
+ ret = disk_write(startsect, 1, tmpbuf);
+ if (ret != 1) {
+ debug("Error writing data (got %d)\n", ret);
return -1;
}
-
- return 0;
}
return 0;
@@ -683,6 +710,14 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
debug("%llu bytes\n", filesize);
+ if (!curclust) {
+ if (filesize) {
+ debug("error: nonempty clusterless file!\n");
+ return -1;
+ }
+ return 0;
+ }
+
actsize = bytesperclust;
endclust = curclust;
do {
@@ -694,28 +729,17 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
goto getit;
if (CHECK_CLUST(newclust, mydata->fatsize)) {
- debug("curclust: 0x%x\n", newclust);
+ debug("newclust: 0x%x\n", newclust);
debug("Invalid FAT entry\n");
return 0;
}
endclust = newclust;
actsize += bytesperclust;
}
- /* actsize >= file size */
- actsize -= bytesperclust;
- /* set remaining clusters */
- if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
- debug("error: writing cluster\n");
- return -1;
- }
/* set remaining bytes */
- *gotsize += actsize;
- filesize -= actsize;
- buffer += actsize;
actsize = filesize;
-
- if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) {
+ if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
debug("error: writing cluster\n");
return -1;
}
@@ -738,8 +762,8 @@ getit:
filesize -= actsize;
buffer += actsize;
- if (CHECK_CLUST(curclust, mydata->fatsize)) {
- debug("curclust: 0x%x\n", curclust);
+ if (CHECK_CLUST(newclust, mydata->fatsize)) {
+ debug("newclust: 0x%x\n", newclust);
debug("Invalid FAT entry\n");
return 0;
}
@@ -749,15 +773,24 @@ getit:
}
/*
- * Fill dir_entry
+ * Set start cluster in directory entry
*/
-static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
- const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
+static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
+ __u32 start_cluster)
{
if (mydata->fatsize == 32)
dentptr->starthi =
cpu_to_le16((start_cluster & 0xffff0000) >> 16);
dentptr->start = cpu_to_le16(start_cluster & 0xffff);
+}
+
+/*
+ * Fill dir_entry
+ */
+static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
+ const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
+{
+ set_start_cluster(mydata, dentptr, start_cluster);
dentptr->size = cpu_to_le32(size);
dentptr->attr = attr;
@@ -1012,91 +1045,89 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,
if (retdent) {
/* Update file size and start_cluster in a directory entry */
retdent->size = cpu_to_le32(size);
- start_cluster = FAT2CPU16(retdent->start);
- if (mydata->fatsize == 32)
- start_cluster |=
- (FAT2CPU16(retdent->starthi) << 16);
-
- ret = check_overflow(mydata, start_cluster, size);
- if (ret) {
- printf("Error: %llu overflow\n", size);
- goto exit;
- }
+ start_cluster = START(retdent);
+
+ if (start_cluster) {
+ if (size) {
+ ret = check_overflow(mydata, start_cluster,
+ size);
+ if (ret) {
+ printf("Error: %llu overflow\n", size);
+ goto exit;
+ }
+ }
- ret = clear_fatent(mydata, start_cluster);
- if (ret) {
- printf("Error: clearing FAT entries\n");
- goto exit;
- }
+ ret = clear_fatent(mydata, start_cluster);
+ if (ret) {
+ printf("Error: clearing FAT entries\n");
+ goto exit;
+ }
- ret = set_contents(mydata, retdent, buffer, size, actwrite);
- if (ret < 0) {
- printf("Error: writing contents\n");
- goto exit;
- }
- debug("attempt to write 0x%llx bytes\n", *actwrite);
+ if (!size)
+ set_start_cluster(mydata, retdent, 0);
+ } else if (size) {
+ ret = start_cluster = find_empty_cluster(mydata);
+ if (ret < 0) {
+ printf("Error: finding empty cluster\n");
+ goto exit;
+ }
- /* Flush fat buffer */
- ret = flush_fat_buffer(mydata);
- if (ret) {
- printf("Error: flush fat buffer\n");
- goto exit;
- }
+ ret = check_overflow(mydata, start_cluster, size);
+ if (ret) {
+ printf("Error: %llu overflow\n", size);
+ goto exit;
+ }
- /* Write directory table to device */
- ret = set_cluster(mydata, dir_curclust,
- get_dentfromdir_block,
- mydata->clust_size * mydata->sect_size);
- if (ret) {
- printf("Error: writing directory entry\n");
- goto exit;
+ set_start_cluster(mydata, retdent, start_cluster);
}
} else {
/* Set short name to set alias checksum field in dir_slot */
set_name(empty_dentptr, filename);
fill_dir_slot(mydata, &empty_dentptr, filename);
- ret = start_cluster = find_empty_cluster(mydata);
- if (ret < 0) {
- printf("Error: finding empty cluster\n");
- goto exit;
- }
+ if (size) {
+ ret = start_cluster = find_empty_cluster(mydata);
+ if (ret < 0) {
+ printf("Error: finding empty cluster\n");
+ goto exit;
+ }
- ret = check_overflow(mydata, start_cluster, size);
- if (ret) {
- printf("Error: %llu overflow\n", size);
- goto exit;
+ ret = check_overflow(mydata, start_cluster, size);
+ if (ret) {
+ printf("Error: %llu overflow\n", size);
+ goto exit;
+ }
+ } else {
+ start_cluster = 0;
}
/* Set attribute as archieve for regular file */
fill_dentry(mydata, empty_dentptr, filename,
start_cluster, size, 0x20);
- ret = set_contents(mydata, empty_dentptr, buffer, size,
- actwrite);
- if (ret < 0) {
- printf("Error: writing contents\n");
- goto exit;
- }
- debug("attempt to write 0x%llx bytes\n", *actwrite);
+ retdent = empty_dentptr;
+ }
- /* Flush fat buffer */
- ret = flush_fat_buffer(mydata);
- if (ret) {
- printf("Error: flush fat buffer\n");
- goto exit;
- }
+ ret = set_contents(mydata, retdent, buffer, size, actwrite);
+ if (ret < 0) {
+ printf("Error: writing contents\n");
+ goto exit;
+ }
+ debug("attempt to write 0x%llx bytes\n", *actwrite);
- /* Write directory table to device */
- ret = set_cluster(mydata, dir_curclust,
- get_dentfromdir_block,
- mydata->clust_size * mydata->sect_size);
- if (ret) {
- printf("Error: writing directory entry\n");
- goto exit;
- }
+ /* Flush fat buffer */
+ ret = flush_fat_buffer(mydata);
+ if (ret) {
+ printf("Error: flush fat buffer\n");
+ goto exit;
}
+ /* Write directory table to device */
+ ret = set_cluster(mydata, dir_curclust, get_dentfromdir_block,
+ mydata->clust_size * mydata->sect_size);
+ if (ret)
+ printf("Error: writing directory entry\n");
+
exit:
free(mydata->fatbuf);
return ret;