#include <command.h>
#include <config.h>
#include <fat.h>
+#include <log.h>
+#include <malloc.h>
#include <asm/byteorder.h>
#include <part.h>
+#include <asm/cache.h>
#include <linux/ctype.h>
#include <div64.h>
#include <linux/math64.h>
return ret;
}
-/*
- * Set short name in directory entry
+/**
+ * set_name() - set short name in directory entry
+ *
+ * @dirent: directory entry
+ * @filename: long file name
*/
static void set_name(dir_entry *dirent, const char *filename)
{
if (len == 0)
return;
- strcpy(s_name, filename);
+ strncpy(s_name, filename, VFAT_MAXLEN_BYTES - 1);
+ s_name[VFAT_MAXLEN_BYTES - 1] = '\0';
uppercase(s_name, len);
period = strchr(s_name, '.');
memcpy(dirent->name, s_name, period_location);
} else {
memcpy(dirent->name, s_name, 6);
+ /*
+ * TODO: Translating two long names with the same first six
+ * characters to the same short name is utterly wrong.
+ * Short names must be unique.
+ */
dirent->name[6] = '~';
dirent->name[7] = '1';
}
return 1;
}
-static int flush_dir_table(fat_itr *itr);
+static int new_dir_table(fat_itr *itr);
+static int flush_dir(fat_itr *itr);
/*
* Fill dir_slot entries with appropriate name, id, and attr
memcpy(itr->dent, slotptr, sizeof(dir_slot));
slotptr--;
counter--;
+
+ if (itr->remaining == 0)
+ flush_dir(itr);
+
+ /* allocate a cluster for more entries */
if (!fat_itr_next(itr))
- if (!itr->dent && !itr->is_root && flush_dir_table(itr))
+ if (!itr->dent &&
+ (!itr->is_root || itr->fsdata->fatsize == 32) &&
+ new_dir_table(itr))
return -1;
}
- 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;
}
}
/*
- * Write directory entries in itr's buffer to block device
+ * Allocate a cluster for additional directory entries
*/
-static int flush_dir_table(fat_itr *itr)
+static int new_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, itr->clust, itr->block, bytesperclust) != 0) {
- printf("error: writing directory entry\n");
- return -1;
- }
dir_newclust = find_empty_cluster(mydata);
set_fatent_value(mydata, itr->clust, dir_newclust);
if (mydata->fatsize == 32)
newclust = get_fatent(mydata, endclust);
+ if (newclust != endclust + 1)
+ break;
if (IS_LAST_CLUST(newclust, mydata->fatsize))
break;
if (CHECK_CLUST(newclust, mydata->fatsize)) {
offset = 0;
else
offset = pos - cur_pos;
- wsize = min(cur_pos + actsize, filesize) - pos;
+ wsize = min_t(unsigned long long, actsize, filesize - cur_pos);
+ wsize -= offset;
+
if (get_set_cluster(mydata, curclust, offset,
buffer, wsize, &actsize)) {
printf("Error get-and-setting cluster\n");
if (filesize <= cur_pos)
break;
- /* CHECK: newclust = get_fatent(mydata, endclust); */
-
if (IS_LAST_CLUST(newclust, mydata->fatsize))
/* no more clusters */
break;
return itr->dent;
}
- if (!itr->dent && !itr->is_root && flush_dir_table(itr))
+ /* allocate a cluster for more entries */
+ if (!itr->dent &&
+ (!itr->is_root || itr->fsdata->fatsize == 32) &&
+ new_dir_table(itr))
/* indicate that allocating dent failed */
itr->dent = NULL;
memset(itr->dent, 0, sizeof(*itr->dent));
- /* Set short name to set alias checksum field in dir_slot */
+ /* Calculate checksum for short name */
set_name(itr->dent, filename);
+
+ /* Set long name entries */
if (fill_dir_slot(itr, filename)) {
ret = -EIO;
goto exit;
}
- /* Set attribute as archive for regular file */
+ /* Set short name entry */
fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20);
retdent = itr->dent;