18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* vim:set shiftwidth=4 ts=8: */
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU Block driver for virtual VFAT (shadows a local directory)
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2004,2005 Johannes E. Schindelin
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Permission is hereby granted, free of charge, to any person obtaining a copy
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * of this software and associated documentation files (the "Software"), to deal
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * in the Software without restriction, including without limitation the rights
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * copies of the Software, and to permit persons to whom the Software is
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * furnished to do so, subject to the following conditions:
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The above copyright notice and this permission notice shall be included in
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * all copies or substantial portions of the Software.
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE.
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <sys/stat.h>
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <dirent.h>
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h"
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "block_int.h"
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "module.h"
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef S_IWGRP
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define S_IWGRP 0
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef S_IWOTH
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define S_IWOTH 0
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TODO: add ":bootsector=blabla.img:" */
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* LATER TODO: add automatic boot sector generation from
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BOOTEASY.ASM and Ranish Partition Manager
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    Note that DOS assumes the system files to be the first files in the
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    file system (test if the boot sector still relies on that fact)! */
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* MAYBE TODO: write block-visofs.c */
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TODO: call try_commit() only after a timeout */
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* #define DEBUG */
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define DLOG(a) a
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef stderr
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define stderr STDERR
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectFILE* stderr = NULL;
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void checkpoint(void);
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef __MINGW32__
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid nonono(const char* file, int line, const char* msg) {
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    exit(-5);
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef assert
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define DLOG(a)
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* dynamic array functions */
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct array_t {
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* pointer;
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int size,next,item_size;
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} array_t;
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void array_init(array_t* array,unsigned int item_size)
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    array->pointer = NULL;
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array->size=0;
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array->next=0;
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array->item_size=item_size;
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void array_free(array_t* array)
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(array->pointer)
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        free(array->pointer);
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array->size=array->next=0;
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* does not automatically grow */
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void* array_get(array_t* array,unsigned int index) {
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(index < array->next);
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return array->pointer + index * array->item_size;
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int array_ensure_allocated(array_t* array, int index)
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if((index + 1) * array->item_size > array->size) {
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int new_size = (index + 32) * array->item_size;
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array->pointer = qemu_realloc(array->pointer, new_size);
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (!array->pointer)
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -1;
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array->size = new_size;
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array->next = index + 1;
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void* array_get_next(array_t* array) {
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int next = array->next;
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    void* result;
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (array_ensure_allocated(array, next) < 0)
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return NULL;
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array->next = next + 1;
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    result = array_get(array, next);
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return result;
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if((array->next+count)*array->item_size>array->size) {
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int increment=count*array->item_size;
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array->pointer=qemu_realloc(array->pointer,array->size+increment);
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(!array->pointer)
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return NULL;
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array->size+=increment;
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memmove(array->pointer+(index+count)*array->item_size,
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		array->pointer+index*array->item_size,
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		(array->next-index)*array->item_size);
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array->next+=count;
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return array->pointer+index*array->item_size;
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* this performs a "roll", so that the element which was at index_from becomes
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * index_to, but the order of all other elements is preserved. */
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int array_roll(array_t* array,int index_to,int index_from,int count)
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* buf;
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* from;
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* to;
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int is;
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(!array ||
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    index_to<0 || index_to>=array->next ||
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    index_from<0 || index_from>=array->next)
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(index_to==index_from)
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    is=array->item_size;
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    from=array->pointer+index_from*is;
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    to=array->pointer+index_to*is;
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    buf=qemu_malloc(is*count);
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(buf,from,is*count);
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(index_to<index_from)
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	memmove(to+is*count,to,from-to);
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	memmove(from,from+is*count,to-from);
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(to,buf,is*count);
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    free(buf);
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int array_remove_slice(array_t* array,int index, int count)
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(index >=0);
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(count > 0);
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(index + count <= array->next);
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(array_roll(array,array->next-1,index,count))
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array->next -= count;
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int array_remove(array_t* array,int index)
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return array_remove_slice(array, index, 1);
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* return the index for a given member */
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int array_index(array_t* array, void* pointer)
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t offset = (char*)pointer - array->pointer;
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert((offset % array->item_size) == 0);
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(offset/array->item_size < array->next);
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return offset/array->item_size;
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* These structures are used to fake a disk and the VFAT filesystem.
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * For this reason we need to use __attribute__((packed)). */
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct bootsector_t {
2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t jump[3];
2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t name[8];
2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t sector_size;
2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t sectors_per_cluster;
2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t reserved_sectors;
2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t number_of_fats;
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t root_entries;
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t total_sectors16;
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t media_type;
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t sectors_per_fat;
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t sectors_per_track;
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t number_of_heads;
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t hidden_sectors;
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t total_sectors;
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    union {
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        struct {
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint8_t drive_number;
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint8_t current_head;
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint8_t signature;
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint32_t id;
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint8_t volume_label[11];
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} __attribute__((packed)) fat16;
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	struct {
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint32_t sectors_per_fat;
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint16_t flags;
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint8_t major,minor;
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint32_t first_cluster_of_root_directory;
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint16_t info_sector;
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint16_t backup_boot_sector;
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint16_t ignored;
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} __attribute__((packed)) fat32;
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } u;
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t fat_type[8];
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t ignored[0x1c0];
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t magic[2];
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} __attribute__((packed)) bootsector_t;
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct {
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t head;
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t sector;
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t cylinder;
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} mbr_chs_t;
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct partition_t {
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t attributes; /* 0x80 = bootable */
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mbr_chs_t start_CHS;
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mbr_chs_t end_CHS;
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t start_sector_long;
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t length_sector_long;
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} __attribute__((packed)) partition_t;
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct mbr_t {
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t ignored[0x1b8];
2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t nt_id;
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t ignored2[2];
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    partition_t partition[4];
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t magic[2];
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} __attribute__((packed)) mbr_t;
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct direntry_t {
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t name[8];
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t extension[3];
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t attributes;
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t reserved[2];
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t ctime;
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t cdate;
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t adate;
2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t begin_hi;
2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t mtime;
2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t mdate;
2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t begin;
2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t size;
2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} __attribute__((packed)) direntry_t;
2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* this structure are used to transparently access the files */
2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct mapping_t {
2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* begin is the first cluster, end is the last+1 */
2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t begin,end;
2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* as s->directory is growable, no pointer may be used here */
2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int dir_index;
2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* the clusters of a file may be in any order; this points to the first */
2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int first_mapping_index;
2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    union {
2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* offset is
2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * - the offset in the file (in clusters) for a file, or
2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * - the next cluster of the directory for a directory, and
2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * - the address of the buffer for a faked entry
2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 */
2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	struct {
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint32_t offset;
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} file;
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	struct {
3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int parent_mapping_index;
3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int first_dir_index;
3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} dir;
3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } info;
3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* path contains the full path, i.e. it always starts with s->path */
3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* path;
3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	MODE_DIRECTORY = 4, MODE_FAKED = 8,
3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int read_only;
3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} mapping_t;
3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void print_direntry(const struct direntry_t*);
3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void print_mapping(const struct mapping_t* mapping);
3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* here begins the real VVFAT driver */
3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct BDRVVVFATState {
3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BlockDriverState* bs; /* pointer to parent */
3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned char first_sectors[0x40*0x200];
3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int fat_type; /* 16 or 32 */
3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_t fat,directory,mapping;
3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int cluster_size;
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int sectors_per_cluster;
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int sectors_per_fat;
3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int sectors_of_root_directory;
3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t last_cluster_of_root_directory;
3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int faked_sectors; /* how many sectors are faked before file data */
3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t sector_count; /* total number of sectors of the partition */
3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t cluster_count; /* total number of clusters of this partition */
3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t max_fat_value;
3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int current_fd;
3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* current_mapping;
3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned char* cluster; /* points to current cluster */
3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int current_cluster;
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* write support */
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BlockDriverState* write_target;
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* qcow_filename;
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BlockDriverState* qcow;
3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    void* fat2;
3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* used_clusters;
3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_t commits;
3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char* path;
3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int downcase_short_names;
3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} BDRVVVFATState;
3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* take the sector position spos and convert it to Cylinder/Head/Sector position
3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * if the position is outside the specified geometry, fill maximum value for CHS
3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * and return 1 to signal overflow.
3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int head,sector;
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    sector   = spos % (bs->secs);  spos/= bs->secs;
3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    head     = spos % (bs->heads); spos/= bs->heads;
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(spos >= bs->cyls){
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Overflow,
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        it happens if 32bit sector positions are used, while CHS is only 24bit.
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        chs->head     = 0xFF;
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        chs->sector   = 0xFF;
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        chs->cylinder = 0xFF;
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    chs->head     = (uint8_t)head;
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
3748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    chs->cylinder = (uint8_t)spos;
3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void init_mbr(BDRVVVFATState* s)
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* TODO: if the files mbr.img and bootsect.img exist, use them */
3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mbr_t* real_mbr=(mbr_t*)s->first_sectors;
382a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    partition_t* partition = &(real_mbr->partition[0]);
3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int lba;
3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(s->first_sectors,0,512);
3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Win NT Disk Signature */
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    partition->attributes=0x80; /* bootable */
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* LBA is used when partition is outside the CHS geometry */
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    lba|= sector2CHS(s->bs, &partition->end_CHS,   s->sector_count);
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*LBA partitions are identified only by start/length_sector_long not by CHS*/
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* FAT12/FAT16/FAT32 */
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* DOS uses different types when partition is LBA,
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       probably to prevent older versions from using CHS on them */
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    partition->fs_type= s->fat_type==12 ? 0x1:
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        s->fat_type==16 ? (lba?0xe:0x06):
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                         /*fat_tyoe==32*/ (lba?0xc:0x0b);
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* direntry functions */
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int short2long_name(char* dest,const char* src)
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int len;
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i=0;i<129 && src[i];i++) {
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dest[2*i]=src[i];
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	dest[2*i+1]=0;
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    len=2*i;
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dest[2*i]=dest[2*i+1]=0;
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i=2*i+2;(i%26);i++)
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	dest[i]=0xff;
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return len;
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char buffer[258];
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int length=short2long_name(buffer,filename),
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        number_of_entries=(length+25)/26,i;
4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry_t* entry;
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i=0;i<number_of_entries;i++) {
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry=array_get_next(&(s->directory));
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry->attributes=0xf;
4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry->reserved[0]=0;
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry->begin=0;
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i=0;i<26*number_of_entries;i++) {
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int offset=(i%26);
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(offset<10) offset=1+offset;
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else if(offset<22) offset=14+offset-10;
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else offset=28+offset-22;
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry=array_get(&(s->directory),s->directory.next-1-(i/26));
4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry->name[offset]=buffer[i];
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return array_get(&(s->directory),s->directory.next-number_of_entries);
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic char is_free(const direntry_t* direntry)
4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic char is_volume_label(const direntry_t* direntry)
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return direntry->attributes == 0x28;
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic char is_long_name(const direntry_t* direntry)
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return direntry->attributes == 0xf;
4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic char is_short_name(const direntry_t* direntry)
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return !is_volume_label(direntry) && !is_long_name(direntry)
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	&& !is_free(direntry);
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic char is_directory(const direntry_t* direntry)
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline char is_dot(const direntry_t* direntry)
4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return is_short_name(direntry) && direntry->name[0] == '.';
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic char is_file(const direntry_t* direntry)
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return is_short_name(direntry) && !is_directory(direntry);
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline uint32_t begin_of_direntry(const direntry_t* direntry)
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline uint32_t filesize_of_direntry(const direntry_t* direntry)
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return le32_to_cpu(direntry->size);
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry->begin = cpu_to_le16(begin & 0xffff);
5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* fat functions */
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline uint8_t fat_chksum(const direntry_t* entry)
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t chksum=0;
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i=0;i<11;i++) {
5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        unsigned char c;
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
515cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        c = (i <= 8) ? entry->name[i] : entry->extension[i-8];
5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return chksum;
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* if return_time==0, this returns the fat_date, else the fat_time */
5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint16_t fat_datetime(time_t time,int return_time) {
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct tm* t;
5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef _WIN32
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    t=localtime(&time); /* this is not thread safe */
5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct tm t1;
529a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    t = &t1;
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    localtime_r(&time,t);
5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(return_time)
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(s->fat_type==32) {
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint32_t* entry=array_get(&(s->fat),cluster);
5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	*entry=cpu_to_le32(value);
5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if(s->fat_type==16) {
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint16_t* entry=array_get(&(s->fat),cluster);
5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	*entry=cpu_to_le16(value&0xffff);
5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int offset = (cluster*3/2);
5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	unsigned char* p = array_get(&(s->fat), offset);
5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        switch (cluster&1) {
5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	case 0:
5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		p[0] = value&0xff;
5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		break;
5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	case 1:
5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		p[0] = (p[0]&0xf) | ((value&0xf)<<4);
5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		p[1] = (value>>4);
5568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		break;
5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
5588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(s->fat_type==32) {
5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint32_t* entry=array_get(&(s->fat),cluster);
5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return le32_to_cpu(*entry);
5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if(s->fat_type==16) {
5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint16_t* entry=array_get(&(s->fat),cluster);
5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return le16_to_cpu(*entry);
5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(fat_entry>s->max_fat_value-8)
5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
5808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void init_fat(BDRVVVFATState* s)
5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->fat_type == 12) {
5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array_init(&(s->fat),1);
5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array_ensure_allocated(&(s->fat),
5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->sectors_per_fat * 0x200 * 3 / 2 - 1);
5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array_init(&(s->fat),(s->fat_type==32?4:2));
5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array_ensure_allocated(&(s->fat),
5918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(s->fat.pointer,0,s->fat.size);
5948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch(s->fat_type) {
5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	case 12: s->max_fat_value=0xfff; break;
5978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	case 16: s->max_fat_value=0xffff; break;
5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	case 32: s->max_fat_value=0x0fffffff; break;
5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	default: s->max_fat_value=0; /* error... */
6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	unsigned int directory_start, const char* filename, int is_dot)
6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i,j,long_index=s->directory.next;
6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    direntry_t* entry = NULL;
6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    direntry_t* entry_long = NULL;
6128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(is_dot) {
6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry=array_get_next(&(s->directory));
6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	memset(entry->name,0x20,11);
6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	memcpy(entry->name,filename,strlen(filename));
6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return entry;
6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    entry_long=create_long_filename(s,filename);
6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    i = strlen(filename);
6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(j = i - 1; j>0  && filename[j]!='.';j--);
6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (j > 0)
6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	i = (j > 8 ? 8 : j);
6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else if (i > 8)
6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	i = 8;
6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    entry=array_get_next(&(s->directory));
6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(entry->name,0x20,11);
6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memcpy(entry->name, filename, i);
6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(j > 0)
6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (i = 0; i < 3 && filename[j+1+i]; i++)
6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    entry->extension[i] = filename[j+1+i];
6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* upcase & remove unwanted characters */
6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i=10;i>=0;i--) {
6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(entry->name[i]<=' ' || entry->name[i]>0x7f
6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		|| strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    entry->name[i]='_';
6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else if(entry->name[i]>='a' && entry->name[i]<='z')
6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            entry->name[i]+='A'-'a';
6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* mangle duplicates */
6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(1) {
6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry_t* entry1=array_get(&(s->directory),directory_start);
6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int j;
6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for(;entry1<entry;entry1++)
6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		break; /* found dupe */
6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(entry1==entry) /* no dupe found */
6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    break;
6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* use all 8 characters of name */
6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(entry->name[7]==' ') {
6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int j;
6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    for(j=6;j>0 && entry->name[j]==' ';j--)
6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		entry->name[j]='~';
6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* increment number */
6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for(j=7;j>0 && entry->name[j]=='9';j--)
6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    entry->name[j]='0';
6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(j>0) {
6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(entry->name[j]<'0' || entry->name[j]>'9')
6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	        entry->name[j]='0';
6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    else
6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	        entry->name[j]++;
6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* calculate checksum; propagate to long name */
6778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(entry_long) {
6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint8_t chksum=fat_chksum(entry);
6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* calculate anew, because realloc could have taken place */
6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry_long=array_get(&(s->directory),long_index);
6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	while(entry_long<entry && is_long_name(entry_long)) {
6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    entry_long->reserved[1]=chksum;
6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    entry_long++;
6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return entry;
6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Read a directory. (the index of the corresponding mapping must be passed).
6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int read_directory(BDRVVVFATState* s, int mapping_index)
6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry_t* direntry;
6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char* dirname = mapping->path;
6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int first_cluster = mapping->begin;
7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int parent_index = mapping->info.dir.parent_mapping_index;
7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* parent_mapping = (mapping_t*)
7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DIR* dir=opendir(dirname);
7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dirent* entry;
7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping->mode & MODE_DIRECTORY);
7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(!dir) {
7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping->end = mapping->begin;
7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    i = mapping->info.dir.first_dir_index =
7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    first_cluster == 0 ? 0 : s->directory.next;
7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* actually read the directory, and allocate the mappings */
7208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while((entry=readdir(dir))) {
7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        char* buffer;
7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry_t* direntry;
7248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        struct stat st;
7258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int is_dot=!strcmp(entry->d_name,".");
7268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int is_dotdot=!strcmp(entry->d_name,"..");
7278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(first_cluster == 0 && (is_dotdot || is_dot))
7298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    continue;
7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	buffer=(char*)qemu_malloc(length);
7328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
7338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(stat(buffer,&st)<0) {
7358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    free(buffer);
7368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            continue;
7378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* create directory entry for this file */
7408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry=create_short_and_long_name(s, i, entry->d_name,
7418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		is_dot || is_dotdot);
7428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
7438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->reserved[0]=direntry->reserved[1]=0;
7448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->ctime=fat_datetime(st.st_ctime,1);
7458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->cdate=fat_datetime(st.st_ctime,0);
7468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->adate=fat_datetime(st.st_atime,0);
7478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->begin_hi=0;
7488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->mtime=fat_datetime(st.st_mtime,1);
7498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->mdate=fat_datetime(st.st_mtime,0);
7508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(is_dotdot)
7518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    set_begin_of_direntry(direntry, first_cluster_of_parent);
7528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else if(is_dot)
7538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    set_begin_of_direntry(direntry, first_cluster);
7548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else
7558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    direntry->begin=0; /* do that later */
7568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (st.st_size > 0x7fffffff) {
7578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fprintf(stderr, "File %s is larger than 2GB\n", buffer);
7588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    free(buffer);
7598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -2;
7608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
7628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* create mapping for this file */
7648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
7658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
7668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->current_mapping->begin=0;
7678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->current_mapping->end=st.st_size;
7688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /*
7698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	     * we get the direntry of the most recent direntry, which
7708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	     * contains the short name and all the relevant information.
7718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	     */
7728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->current_mapping->dir_index=s->directory.next-1;
7738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->current_mapping->first_mapping_index = -1;
7748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (S_ISDIR(st.st_mode)) {
7758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_mapping->mode = MODE_DIRECTORY;
7768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_mapping->info.dir.parent_mapping_index =
7778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    mapping_index;
7788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    } else {
7798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_mapping->mode = MODE_UNDEFINED;
7808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_mapping->info.file.offset = 0;
7818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
7828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->current_mapping->path=buffer;
7838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->current_mapping->read_only =
7848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
7858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
7868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    closedir(dir);
7888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* fill with zeroes up to the end of the cluster */
7908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(s->directory.next%(0x10*s->sectors_per_cluster)) {
7918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry_t* direntry=array_get_next(&(s->directory));
7928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	memset(direntry,0,sizeof(direntry_t));
7938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TODO: if there are more entries, bootsector has to be adjusted! */
7968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
7978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
7988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* root directory */
7998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int cur = s->directory.next;
8008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
8018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	memset(array_get(&(s->directory), cur), 0,
8028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		(ROOT_ENTRIES - cur) * sizeof(direntry_t));
8038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     /* reget the mapping, since s->mapping was possibly realloc()ed */
8068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
8078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
8088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	* 0x20 / s->cluster_size;
8098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->end = first_cluster;
8108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
8128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    set_begin_of_direntry(direntry, mapping->begin);
8138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
8158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
8188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
8208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
8238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return s->faked_sectors + s->sectors_per_cluster * cluster_num;
8258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
8288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
8308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DBG
8338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
8348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(mapping->mode==MODE_UNDEFINED)
8368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
8378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
8388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
8408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int init_directories(BDRVVVFATState* s,
8428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	const char* dirname)
8438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector_t* bootsector;
8458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping;
8468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int i;
8478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned int cluster;
8488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(&(s->first_sectors[0]),0,0x40*0x200);
8508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->cluster_size=s->sectors_per_cluster*0x200;
8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->cluster_buffer=qemu_malloc(s->cluster_size);
8538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*
8558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
8568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * where sc is sector_count,
8578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * spf is sectors_per_fat,
8588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * spc is sectors_per_clusters, and
8598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * fat_type = 12, 16 or 32.
8608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
8618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
8628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
8638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_init(&(s->mapping),sizeof(mapping_t));
8658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_init(&(s->directory),sizeof(direntry_t));
8668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* add volume label */
8688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    {
8698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry_t* entry=array_get_next(&(s->directory));
8708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	entry->attributes=0x28; /* archive | volume label */
871a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner	memcpy(entry->name,"QEMU VVF",8);
872a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner	memcpy(entry->extension,"AT ",3);
8738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Now build FAT, and write back information into directory */
8768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    init_fat(s);
8778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
8798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->cluster_count=sector2cluster(s, s->sector_count);
8808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping = array_get_next(&(s->mapping));
8828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->begin = 0;
8838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->dir_index = 0;
8848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->info.dir.parent_mapping_index = -1;
8858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->first_mapping_index = -1;
886a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    mapping->path = qemu_strdup(dirname);
8878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    i = strlen(mapping->path);
8888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (i > 0 && mapping->path[i - 1] == '/')
8898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping->path[i - 1] = '\0';
8908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->mode = MODE_DIRECTORY;
8918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->read_only = 0;
8928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->path = mapping->path;
8938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0, cluster = 0; i < s->mapping.next; i++) {
8958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* MS-DOS expects the FAT to be 0 for the root directory
8968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * (except for the media byte). */
8978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* LATER TODO: still true for FAT32? */
8988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int fix_fat = (i != 0);
8998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping = array_get(&(s->mapping), i);
9008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (mapping->mode & MODE_DIRECTORY) {
9028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->begin = cluster;
9038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(read_directory(s, i)) {
9048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fprintf(stderr, "Could not read directory %s\n",
9058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->path);
9068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return -1;
9078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
9088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping = array_get(&(s->mapping), i);
9098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else {
9108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping->mode == MODE_UNDEFINED);
9118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->mode=MODE_NORMAL;
9128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->begin = cluster;
9138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping->end > 0) {
9148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		direntry_t* direntry = array_get(&(s->directory),
9158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->dir_index);
9168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
9188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		set_begin_of_direntry(direntry, mapping->begin);
9198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    } else {
9208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping->end = cluster + 1;
9218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fix_fat = 0;
9228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
9238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
9248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping->begin < mapping->end);
9268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/* next free cluster */
9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	cluster = mapping->end;
9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if(cluster > s->cluster_count) {
9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		    s->fat_type,
9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		    s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner								: "2.88 MB"
9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				      : "504MB");
9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    return -EINVAL;
9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* fix fat for entry */
9408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (fix_fat) {
9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    int j;
9428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    for(j = mapping->begin; j < mapping->end - 1; j++)
9438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fat_set(s, j, j+1);
9448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fat_set(s, mapping->end - 1, s->max_fat_value);
9458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
9468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
9478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping = array_get(&(s->mapping), 0);
9498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
9508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->last_cluster_of_root_directory = mapping->end;
9518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* the FAT signature */
9538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    fat_set(s,0,s->max_fat_value);
9548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    fat_set(s,1,s->max_fat_value);
9558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->current_mapping = NULL;
9578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
9598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->jump[0]=0xeb;
9608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->jump[1]=0x3e;
9618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->jump[2]=0x90;
9628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(bootsector->name,"QEMU    ",8);
9638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->sector_size=cpu_to_le16(0x200);
9648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->sectors_per_cluster=s->sectors_per_cluster;
9658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->reserved_sectors=cpu_to_le16(1);
9668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->number_of_fats=0x2; /* number of FATs */
9678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
9688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
9698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
9708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->fat.pointer[0] = bootsector->media_type;
9718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
9728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
9738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
9748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
9758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
9768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* LATER TODO: if FAT32, this is wrong */
9788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
9798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->u.fat16.current_head=0;
9808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->u.fat16.signature=0x29;
9818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
9828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
9848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
9858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
9868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
9888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
9898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
9918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic BDRVVVFATState *vvv = NULL;
9928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
9938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int enable_write_target(BDRVVVFATState *s);
9958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int is_consistent(BDRVVVFATState *s);
9968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
9988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
9998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BDRVVVFATState *s = bs->opaque;
10008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int floppy = 0;
10018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
10028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
10048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vvv = s;
10058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
10068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(if (stderr == NULL) {
10088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    stderr = fopen("vvfat.log", "a");
10098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    setbuf(stderr, NULL);
10108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project})
10118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->bs = bs;
10138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->fat_type=16;
10158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* LATER TODO: if FAT32, adjust */
10168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->sectors_per_cluster=0x10;
10178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* 504MB disk*/
10188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bs->cyls=1024; bs->heads=16; bs->secs=63;
10198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->current_cluster=0xffffffff;
10218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->first_sectors_number=0x40;
10238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* read only is the default for safety */
10248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bs->read_only = 1;
10258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->qcow = s->write_target = NULL;
10268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->qcow_filename = NULL;
10278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->fat2 = NULL;
10288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->downcase_short_names = 1;
10298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!strstart(dirname, "fat:", NULL))
10318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
10328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (strstr(dirname, ":floppy:")) {
10348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	floppy = 1;
10358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->fat_type = 12;
10368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->first_sectors_number = 1;
10378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->sectors_per_cluster=2;
10388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	bs->cyls = 80; bs->heads = 2; bs->secs = 36;
10398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
10408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->sector_count=bs->cyls*bs->heads*bs->secs;
10428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (strstr(dirname, ":32:")) {
10448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
10458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->fat_type = 32;
10468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (strstr(dirname, ":16:")) {
10478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->fat_type = 16;
10488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (strstr(dirname, ":12:")) {
10498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->fat_type = 12;
10508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->sector_count=2880;
10518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
10528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (strstr(dirname, ":rw:")) {
10548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (enable_write_target(s))
10558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -1;
10568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	bs->read_only = 0;
10578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
10588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    i = strrchr(dirname, ':') - dirname;
10608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(i >= 3);
10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
10628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* workaround for DOS drive names */
10638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	dirname += i-1;
10648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
10658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	dirname += i+1;
10668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bs->total_sectors=bs->cyls*bs->heads*bs->secs;
10688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(init_directories(s, dirname))
10708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
10718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
10738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(s->first_sectors_number==0x40)
10758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	init_mbr(s);
10768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* for some reason or other, MS-DOS does not like to know about CHS... */
10788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (floppy)
10798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	bs->heads = bs->cyls = bs->secs = 0;
10808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    //    assert(is_consistent(s));
10828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
10838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
10848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void vvfat_close_current_file(BDRVVVFATState *s)
10868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
10878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(s->current_mapping) {
10888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->current_mapping = NULL;
10898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (s->current_fd) {
10908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		close(s->current_fd);
10918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_fd = 0;
10928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
10938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
10948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->current_cluster = -1;
10958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
10968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* mappings between index1 and index2-1 are supposed to be ordered
10988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * return value is the index of the last mapping for which end>cluster_num
10998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
11008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
11018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(1) {
1103a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        int index3;
11048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping_t* mapping;
11058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	index3=(index1+index2)/2;
11068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping=array_get(&(s->mapping),index3);
11078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping->begin < mapping->end);
11088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(mapping->begin>=cluster_num) {
11098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(index2!=index3 || index2==0);
11108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(index2==index3)
11118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return index1;
11128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    index2=index3;
11138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else {
11148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(index1==index3)
11158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return mapping->end<=cluster_num ? index2 : index1;
11168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    index1=index3;
11178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
11188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(index1<=index2);
11198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	DLOG(mapping=array_get(&(s->mapping),index1);
11208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping->begin<=cluster_num);
11218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(index2 >= s->mapping.next ||
11228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		((mapping = array_get(&(s->mapping),index2)) &&
11238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping->end>cluster_num)));
11248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
11288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
11308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping;
11318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(index>=s->mapping.next)
11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
11338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping=array_get(&(s->mapping),index);
11348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(mapping->begin>cluster_num)
11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
11368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
11378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return mapping;
11388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
11418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This function simply compares path == mapping->path. Since the mappings
11428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * are sorted by cluster, this is expensive: O(n).
11438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
11448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
11458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	const char* path)
11468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
11488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < s->mapping.next; i++) {
11508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping_t* mapping = array_get(&(s->mapping), i);
11518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (mapping->first_mapping_index < 0 &&
11528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		!strcmp(path, mapping->path))
11538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return mapping;
11548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return NULL;
11578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int open_file(BDRVVVFATState* s,mapping_t* mapping)
11608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(!mapping)
11628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
11638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(!s->current_mapping ||
11648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    strcmp(s->current_mapping->path,mapping->path)) {
11658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* open file */
11668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
11678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(fd<0)
11688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -1;
11698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	vvfat_close_current_file(s);
11708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->current_fd = fd;
11718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->current_mapping = mapping;
11728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
11748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int read_cluster(BDRVVVFATState *s,int cluster_num)
11778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(s->current_cluster != cluster_num) {
11798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int result=0;
11808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	off_t offset;
11818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
11828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(!s->current_mapping
11838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		|| s->current_mapping->begin>cluster_num
11848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		|| s->current_mapping->end<=cluster_num) {
11858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /* binary search of mappings for file */
11868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
11878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
11898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping && mapping->mode & MODE_DIRECTORY) {
11918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		vvfat_close_current_file(s);
11928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_mapping = mapping;
11938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectread_cluster_directory:
11948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
11958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->cluster = (unsigned char*)s->directory.pointer+offset
11968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			+ 0x20*s->current_mapping->info.dir.first_dir_index;
11978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
11988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
11998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_cluster = cluster_num;
12008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return 0;
12018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
12028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(open_file(s,mapping))
12048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return -2;
12058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else if (s->current_mapping->mode & MODE_DIRECTORY)
12068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    goto read_cluster_directory;
12078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(s->current_fd);
12098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
12118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
12128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -3;
12138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->cluster=s->cluster_buffer;
12148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	result=read(s->current_fd,s->cluster,s->cluster_size);
12158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(result<0) {
12168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->current_cluster = -1;
12178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -1;
12188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
12198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->current_cluster = cluster_num;
12208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
12228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
12258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void hexdump(const void* address, uint32_t len)
12268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const unsigned char* p = address;
12288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, j;
12298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < len; i += 16) {
12318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (j = 0; j < 16 && i + j < len; j++)
12328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fprintf(stderr, "%02x ", p[i + j]);
12338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (; j < 16; j++)
12348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fprintf(stderr, "   ");
12358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, " ");
12368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (j = 0; j < 16 && i + j < len; j++)
12378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
12388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "\n");
12398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void print_direntry(const direntry_t* direntry)
12438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int j = 0;
12458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char buffer[1024];
12468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1247a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    fprintf(stderr, "direntry %p: ", direntry);
12488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(!direntry)
12498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return;
12508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(is_long_name(direntry)) {
12518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	unsigned char* c=(unsigned char*)direntry;
12528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int i;
12538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
12558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    ADD_CHAR(c[i]);
12568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
12578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    ADD_CHAR(c[i]);
12588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
12598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    ADD_CHAR(c[i]);
12608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	buffer[j] = 0;
12618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "%s\n", buffer);
12628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
12638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int i;
12648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for(i=0;i<11;i++)
12658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    ADD_CHAR(direntry->name[i]);
12668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	buffer[j] = 0;
12678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
12688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		buffer,
12698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		direntry->attributes,
12708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		begin_of_direntry(direntry),le32_to_cpu(direntry->size));
12718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void print_mapping(const mapping_t* mapping)
12758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1276a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
1277a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
1278a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        mapping, mapping->begin, mapping->end, mapping->dir_index,
1279a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        mapping->first_mapping_index, mapping->path, mapping->mode);
1280a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner
12818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (mapping->mode & MODE_DIRECTORY)
12828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
12838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
12848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
12858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
12878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int vvfat_read(BlockDriverState *bs, int64_t sector_num,
12898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    uint8_t *buf, int nb_sectors)
12908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BDRVVVFATState *s = bs->opaque;
12928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
12938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i=0;i<nb_sectors;i++,sector_num++) {
12958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (sector_num >= s->sector_count)
12968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	   return -1;
12978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (s->qcow) {
12988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int n;
12998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (s->qcow->drv->bdrv_is_allocated(s->qcow,
13008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			sector_num, nb_sectors-i, &n)) {
13018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
13028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
13038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    return -1;
13048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		i += n - 1;
13058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		sector_num += n - 1;
13068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		continue;
13078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
13088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
13098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
13108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(sector_num<s->faked_sectors) {
13118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(sector_num<s->first_sectors_number)
13128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
13138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
13148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
13158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
13168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
13178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else {
13188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint32_t sector=sector_num-s->faked_sectors,
13198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    sector_offset_in_cluster=(sector%s->sectors_per_cluster),
13208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    cluster_num=sector/s->sectors_per_cluster;
13218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(read_cluster(s, cluster_num) != 0) {
13228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		/* LATER TODO: strict: return -1; */
13238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		memset(buf+i*0x200,0,0x200);
13248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		continue;
13258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
13268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
13278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
13288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
13298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
13308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
13318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* LATER TODO: statify all functions */
13338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
13358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Idea of the write support (use snapshot):
13368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
13378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 1. check if all data is consistent, recording renames, modifications,
13388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *    new files and directories (in s->commits).
13398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
13408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 2. if the data is not consistent, stop committing
13418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
13428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 3. handle renames, and create new files and directories (do not yet
13438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *    write their contents)
13448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
13458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 4. walk the directories, fixing the mapping and direntries, and marking
13468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *    the handled mappings as not deleted
13478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
13488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 5. commit the contents of the files
13498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
13508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 6. handle deleted files and directories
13518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
13528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
13538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct commit_t {
13558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* path;
13568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    union {
13578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	struct { uint32_t cluster; } rename;
13588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	struct { int dir_index; uint32_t modified_offset; } writeout;
13598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	struct { uint32_t first_cluster; } new_file;
13608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	struct { uint32_t cluster; } mkdir;
13618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } param;
13628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
13638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    enum {
13648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
13658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } action;
13668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} commit_t;
13678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void clear_commits(BDRVVVFATState* s)
13698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
13708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
13718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
13728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < s->commits.next; i++) {
13738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	commit_t* commit = array_get(&(s->commits), i);
13748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(commit->path || commit->action == ACTION_WRITEOUT);
13758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (commit->action != ACTION_WRITEOUT) {
13768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(commit->path);
13778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    free(commit->path);
13788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else
13798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(commit->path == NULL);
13808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
13818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->commits.next = 0;
13828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
13838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void schedule_rename(BDRVVVFATState* s,
13858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint32_t cluster, char* new_path)
13868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
13878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit_t* commit = array_get_next(&(s->commits));
13888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->path = new_path;
13898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->param.rename.cluster = cluster;
13908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->action = ACTION_RENAME;
13918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
13928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void schedule_writeout(BDRVVVFATState* s,
13948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int dir_index, uint32_t modified_offset)
13958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
13968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit_t* commit = array_get_next(&(s->commits));
13978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->path = NULL;
13988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->param.writeout.dir_index = dir_index;
13998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->param.writeout.modified_offset = modified_offset;
14008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->action = ACTION_WRITEOUT;
14018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
14028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void schedule_new_file(BDRVVVFATState* s,
14048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	char* path, uint32_t first_cluster)
14058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
14068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit_t* commit = array_get_next(&(s->commits));
14078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->path = path;
14088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->param.new_file.first_cluster = first_cluster;
14098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->action = ACTION_NEW_FILE;
14108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
14118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
14138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
14148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit_t* commit = array_get_next(&(s->commits));
14158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->path = path;
14168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->param.mkdir.cluster = cluster;
14178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    commit->action = ACTION_MKDIR;
14188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
14198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct {
14218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*
14228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * Since the sequence number is at most 0x3f, and the filename
14238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * length is at most 13 times the sequence number, the maximal
14248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * filename length is 0x3f * 13 bytes.
14258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
14268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned char name[0x3f * 13 + 1];
14278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int checksum, len;
14288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int sequence_number;
14298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} long_file_name;
14308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void lfn_init(long_file_name* lfn)
14328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
14338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   lfn->sequence_number = lfn->len = 0;
14348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   lfn->checksum = 0x100;
14358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
14368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
14388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int parse_long_name(long_file_name* lfn,
14398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	const direntry_t* direntry)
14408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
14418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, j, offset;
14428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const unsigned char* pointer = (const unsigned char*)direntry;
14438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!is_long_name(direntry))
14458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 1;
14468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (pointer[0] & 0x40) {
14488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	lfn->sequence_number = pointer[0] & 0x3f;
14498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	lfn->checksum = pointer[13];
14508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	lfn->name[0] = 0;
14518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	lfn->name[lfn->sequence_number * 13] = 0;
14528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
14538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
14548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else if (pointer[13] != lfn->checksum)
14558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -2;
14568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else if (pointer[12] || pointer[26] || pointer[27])
14578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -3;
14588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    offset = 13 * (lfn->sequence_number - 1);
14608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0, j = 1; i < 13; i++, j+=2) {
14618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (j == 11)
14628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    j = 14;
14638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else if (j == 26)
14648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    j = 28;
14658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (pointer[j+1] == 0)
14678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    lfn->name[offset + i] = pointer[j];
14688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
14698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -4;
14708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else
14718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    lfn->name[offset + i] = 0;
14728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
14738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (pointer[0] & 0x40)
14758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	lfn->len = offset + strlen((char*)lfn->name + offset);
14768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
14788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
14798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* returns 0 if successful, >0 if no short_name, and <0 on error */
14818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int parse_short_name(BDRVVVFATState* s,
14828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	long_file_name* lfn, direntry_t* direntry)
14838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
14848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, j;
14858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!is_short_name(direntry))
14878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 1;
14888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
14908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i <= j; i++) {
14918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
14928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -1;
14938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else if (s->downcase_short_names)
14945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    lfn->name[i] = qemu_tolower(direntry->name[i]);
14958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else
14968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    lfn->name[i] = direntry->name[i];
14978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
14988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
15008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (j >= 0) {
15018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	lfn->name[i++] = '.';
15028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	lfn->name[i + j + 1] = '\0';
15038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (;j >= 0; j--) {
15048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
15058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return -2;
15068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    else if (s->downcase_short_names)
15075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
15088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    else
15098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		lfn->name[i + j] = direntry->extension[j];
15108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
15118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else
15128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	lfn->name[i + j + 1] = '\0';
15138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    lfn->len = strlen((char*)lfn->name);
15158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
15178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
15188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline uint32_t modified_fat_get(BDRVVVFATState* s,
15208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	unsigned int cluster)
15218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (cluster < s->last_cluster_of_root_directory) {
15238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (cluster + 1 == s->last_cluster_of_root_directory)
15248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return s->max_fat_value;
15258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else
15268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return cluster + 1;
15278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
15288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->fat_type==32) {
15308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint32_t* entry=((uint32_t*)s->fat2)+cluster;
15318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return le32_to_cpu(*entry);
15328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (s->fat_type==16) {
15338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint16_t* entry=((uint16_t*)s->fat2)+cluster;
15348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return le16_to_cpu(*entry);
15358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
15368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        const uint8_t* x=s->fat2+cluster*3/2;
15378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
15388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
15398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
15408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
15428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int was_modified = 0;
15448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, dummy;
15458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->qcow == NULL)
15478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
15488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
15508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
15518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		cluster2sector(s, cluster_num) + i, 1, &dummy);
15528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return was_modified;
15548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
15558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic const char* get_basename(const char* path)
15578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char* basename = strrchr(path, '/');
15598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (basename == NULL)
15608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return path;
15618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
15628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return basename + 1; /* strip '/' */
15638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
15648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
15668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The array s->used_clusters holds the states of the clusters. If it is
15678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
15688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * was modified, bit 3 is set.
15698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * If any cluster is allocated, but not part of a file or directory, this
15708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * driver refuses to commit.
15718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
15728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef enum {
15738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
15748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} used_t;
15758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
15778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * get_cluster_count_for_direntry() not only determines how many clusters
15788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * are occupied by direntry, but also if it was renamed or modified.
15798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
15808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * A file is thought to be renamed *only* if there already was a file with
15818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * exactly the same first cluster, but a different name.
15828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
15838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Further, the files/directories handled by this function are
15848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * assumed to be *not* deleted (and *only* those).
15858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
15868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
15878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry_t* direntry, const char* path)
15888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*
15908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * This is a little bit tricky:
15918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * IF the guest OS just inserts a cluster into the file chain,
15928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * and leaves the rest alone, (i.e. the original file had clusters
15938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
15948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *
15958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - do_commit will write the cluster into the file at the given
15968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *   offset, but
15978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *
15988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - the cluster which is overwritten should be moved to a later
15998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *   position in the file.
16008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *
16018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * I am not aware that any OS does something as braindead, but this
16028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * situation could happen anyway when not committing for a long time.
16038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * Just to be sure that this does not bite us, detect it, and copy the
16048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * contents of the clusters to-be-overwritten into the qcow.
16058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
16068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int copy_it = 0;
16078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int was_modified = 0;
16088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int32_t ret = 0;
16098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t cluster_num = begin_of_direntry(direntry);
16118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t offset = 0;
16128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int first_mapping_index = -1;
16138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping = NULL;
16148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char* basename2 = NULL;
16158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vvfat_close_current_file(s);
16178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* the root directory */
16198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (cluster_num == 0)
16208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
16218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* write support */
16238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->qcow) {
16248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	basename2 = get_basename(path);
16258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping = find_mapping_for_cluster(s, cluster_num);
16278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (mapping) {
16298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    const char* basename;
16308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping->mode & MODE_DELETED);
16328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->mode &= ~MODE_DELETED;
16338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    basename = get_basename(mapping->path);
16358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping->mode & MODE_NORMAL);
16378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /* rename */
16398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (strcmp(basename, basename2))
1640a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner		schedule_rename(s, cluster_num, qemu_strdup(path));
16418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else if (is_file(direntry))
16428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /* new file */
1643a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner	    schedule_new_file(s, qemu_strdup(path), cluster_num);
16448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else {
1645a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner            abort();
16468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return 0;
16478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
16488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
16498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while(1) {
16518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (s->qcow) {
16528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (!copy_it && cluster_was_modified(s, cluster_num)) {
16538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (mapping == NULL ||
16548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->begin > cluster_num ||
16558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->end <= cluster_num)
16568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping = find_mapping_for_cluster(s, cluster_num);
16578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (mapping &&
16608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			(mapping->mode & MODE_DIRECTORY) == 0) {
16618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    /* was modified in qcow */
16638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    if (offset != mapping->info.file.offset + s->cluster_size
16648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    * (cluster_num - mapping->begin)) {
16658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			/* offset of this cluster in file chain has changed */
1666a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner                        abort();
16678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			copy_it = 1;
16688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    } else if (offset == 0) {
16698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			const char* basename = get_basename(mapping->path);
16708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (strcmp(basename, basename2))
16728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    copy_it = 1;
16738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			first_mapping_index = array_index(&(s->mapping), mapping);
16748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    }
16758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    if (mapping->first_mapping_index != first_mapping_index
16778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    && mapping->info.file.offset > 0) {
1678a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner                        abort();
16798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			copy_it = 1;
16808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    }
16818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    /* need to write out? */
16838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    if (!was_modified && is_file(direntry)) {
16848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			was_modified = 1;
16858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			schedule_writeout(s, mapping->dir_index, offset);
16868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    }
16878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
16888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
16898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (copy_it) {
16918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int i, dummy;
16928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		/*
16938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 * This is horribly inefficient, but that is okay, since
16948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 * it is rarely executed, if at all.
16958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 */
16968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int64_t offset = cluster2sector(s, cluster_num);
16978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		vvfat_close_current_file(s);
16998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		for (i = 0; i < s->sectors_per_cluster; i++)
17008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
17018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				offset + i, 1, &dummy)) {
17028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (vvfat_read(s->bs,
17038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    offset, s->cluster_buffer, 1))
17048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    return -1;
17058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (s->qcow->drv->bdrv_write(s->qcow,
17068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    offset, s->cluster_buffer, 1))
17078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    return -2;
17088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    }
17098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
17108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
17118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	ret++;
17138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (s->used_clusters[cluster_num] & USED_ANY)
17148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return 0;
17158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->used_clusters[cluster_num] = USED_FILE;
17168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	cluster_num = modified_fat_get(s, cluster_num);
17188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (fat_eof(s, cluster_num))
17208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return ret;
17218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
17228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -1;
17238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	offset += s->cluster_size;
17258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
17268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
17278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
17298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This function looks at the modified data (qcow).
17308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * It returns 0 upon inconsistency or error, and the number of clusters
17318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * used by the directory, its subdirectories and their files.
17328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
17338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int check_directory_consistency(BDRVVVFATState *s,
17348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int cluster_num, const char* path)
17358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
17368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret = 0;
17375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned char* cluster = qemu_malloc(s->cluster_size);
17388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry_t* direntries = (direntry_t*)cluster;
17398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
17408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    long_file_name lfn;
17428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int path_len = strlen(path);
17438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char path2[PATH_MAX];
17448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(path_len < PATH_MAX); /* len was tested before! */
17468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pstrcpy(path2, sizeof(path2), path);
17478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    path2[path_len] = '/';
17488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    path2[path_len + 1] = '\0';
17498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (mapping) {
17518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	const char* basename = get_basename(mapping->path);
17528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	const char* basename2 = get_basename(path);
17538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping->mode & MODE_DIRECTORY);
17558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping->mode & MODE_DELETED);
17578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping->mode &= ~MODE_DELETED;
17588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (strcmp(basename, basename2))
1760a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner	    schedule_rename(s, cluster_num, qemu_strdup(path));
17618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else
17628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* new directory */
1763a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner	schedule_mkdir(s, cluster_num, qemu_strdup(path));
17648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    lfn_init(&lfn);
17668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    do {
17678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int i;
17688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int subret = 0;
17698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	ret++;
17718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (s->used_clusters[cluster_num] & USED_ANY) {
17738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
17748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return 0;
17758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
17768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->used_clusters[cluster_num] = USED_DIRECTORY;
17778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
17798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
17808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->sectors_per_cluster);
17818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (subret) {
17828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fprintf(stderr, "Error fetching direntries\n");
17838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fail:
17848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    free(cluster);
17858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return 0;
17868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
17878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
17895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    int cluster_count = 0;
17908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
17928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
17938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    is_free(direntries + i))
17948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		continue;
17958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    subret = parse_long_name(&lfn, direntries + i);
17978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (subret < 0) {
17988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fprintf(stderr, "Error in long name\n");
17998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		goto fail;
18008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
18018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (subret == 0 || is_free(direntries + i))
18028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		continue;
18038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (fat_chksum(direntries+i) != lfn.checksum) {
18058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		subret = parse_short_name(s, &lfn, direntries + i);
18068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (subret < 0) {
18078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    fprintf(stderr, "Error in short name (%d)\n", subret);
18088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    goto fail;
18098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
18108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (subret > 0 || !strcmp((char*)lfn.name, ".")
18118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			|| !strcmp((char*)lfn.name, ".."))
18128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    continue;
18138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
18148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    lfn.checksum = 0x100; /* cannot use long name twice */
18158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (path_len + 1 + lfn.len >= PATH_MAX) {
18178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
18188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		goto fail;
18198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
18208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
18218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    (char*)lfn.name);
18228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (is_directory(direntries + i)) {
18248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (begin_of_direntry(direntries + i) == 0) {
18258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
18268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    goto fail;
18278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
18288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		cluster_count = check_directory_consistency(s,
18298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			begin_of_direntry(direntries + i), path2);
18308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (cluster_count == 0) {
18318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
18328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    goto fail;
18338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
18348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    } else if (is_file(direntries + i)) {
18358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		/* check file size with FAT */
18368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
18378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (cluster_count !=
18388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			(le32_to_cpu(direntries[i].size) + s->cluster_size
18398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			 - 1) / s->cluster_size) {
18408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
18418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    goto fail;
18428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
18438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    } else
1844a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner                abort(); /* cluster_count = 0; */
18458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    ret += cluster_count;
18478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
18488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	cluster_num = modified_fat_get(s, cluster_num);
18508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } while(!fat_eof(s, cluster_num));
18518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    free(cluster);
18538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ret;
18548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
18558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* returns 1 on success */
18578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int is_consistent(BDRVVVFATState* s)
18588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
18598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, check;
18608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int used_clusters_count = 0;
18618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(checkpoint());
18638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*
18648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - get modified FAT
18658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - compare the two FATs (TODO)
18668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - get buffer for marking used clusters
18678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - recurse direntries from root (using bs->bdrv_read to make
18688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *    sure to get the new data)
18698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *   - check that the FAT agrees with the size
18708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *   - count the number of clusters occupied by this directory and
18718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *     its files
18728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - check that the cumulative used cluster count agrees with the
18738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *   FAT
18748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - if all is fine, return number of used clusters
18758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
18768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->fat2 == NULL) {
18778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int size = 0x200 * s->sectors_per_fat;
18785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	s->fat2 = qemu_malloc(size);
18798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	memcpy(s->fat2, s->fat.pointer, size);
18808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
18818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    check = vvfat_read(s->bs,
18828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->first_sectors_number, s->fat2, s->sectors_per_fat);
18838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (check) {
18848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Could not copy fat\n");
18858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
18868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
18878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert (s->used_clusters);
18888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < sector2cluster(s, s->sector_count); i++)
18898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->used_clusters[i] &= ~USED_ANY;
18908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    clear_commits(s);
18928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* mark every mapped file/directory as deleted.
18948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * (check_directory_consistency() will unmark those still present). */
18958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->qcow)
18968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (i = 0; i < s->mapping.next; i++) {
18978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* mapping = array_get(&(s->mapping), i);
18988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping->first_mapping_index < 0)
18998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping->mode |= MODE_DELETED;
19008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
19018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    used_clusters_count = check_directory_consistency(s, 0, s->path);
19038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (used_clusters_count <= 0) {
19048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	DLOG(fprintf(stderr, "problem in directory\n"));
19058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
19068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
19078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    check = s->last_cluster_of_root_directory;
19098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = check; i < sector2cluster(s, s->sector_count); i++) {
19108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (modified_fat_get(s, i)) {
19118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if(!s->used_clusters[i]) {
19128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
19138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return 0;
19148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
19158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    check++;
19168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
19178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (s->used_clusters[i] == USED_ALLOCATED) {
19198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /* allocated, but not used... */
19208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
19218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return 0;
19228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
19238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
19248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (check != used_clusters_count)
19268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
19278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return used_clusters_count;
19298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
19308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void adjust_mapping_indices(BDRVVVFATState* s,
19328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int offset, int adjust)
19338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
19348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
19358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < s->mapping.next; i++) {
19378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping_t* mapping = array_get(&(s->mapping), i);
19388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ADJUST_MAPPING_INDEX(name) \
19408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (mapping->name >= offset) \
19418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->name += adjust
19428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	ADJUST_MAPPING_INDEX(first_mapping_index);
19448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (mapping->mode & MODE_DIRECTORY)
19458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
19468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
19478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
19488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* insert or update mapping */
19508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic mapping_t* insert_mapping(BDRVVVFATState* s,
19518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint32_t begin, uint32_t end)
19528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
19538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*
19548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - find mapping where mapping->begin >= begin,
19558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - if mapping->begin > begin: insert
19568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     *   - adjust all references to mappings!
19578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - else: adjust
19588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - replace name
19598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
19608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
19618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping = NULL;
19628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* first_mapping = array_get(&(s->mapping), 0);
19638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
19658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    && mapping->begin < begin) {
19668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping->end = begin;
19678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	index++;
19688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping = array_get(&(s->mapping), index);
19698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
19708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (index >= s->mapping.next || mapping->begin > begin) {
19718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping = array_insert(&(s->mapping), index, 1);
19728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping->path = NULL;
19738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	adjust_mapping_indices(s, index, +1);
19748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
19758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->begin = begin;
19778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->end = end;
19788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(mapping_t* next_mapping;
19808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectassert(index + 1 >= s->mapping.next ||
19818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project((next_mapping = array_get(&(s->mapping), index + 1)) &&
19828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project next_mapping->begin >= end)));
19838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
19858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->current_mapping = array_get(&(s->mapping),
19868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_mapping - first_mapping);
19878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return mapping;
19898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
19908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int remove_mapping(BDRVVVFATState* s, int mapping_index)
19928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
19938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
19948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* first_mapping = array_get(&(s->mapping), 0);
19958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* free mapping */
19978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (mapping->first_mapping_index < 0)
19988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	free(mapping->path);
19998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* remove from s->mapping */
20018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_remove(&(s->mapping), mapping_index);
20028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* adjust all references to mappings */
20048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    adjust_mapping_indices(s, mapping_index, -1);
20058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
20078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	s->current_mapping = array_get(&(s->mapping),
20088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->current_mapping - first_mapping);
20098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
20118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
20128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
20148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
20158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
20168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < s->mapping.next; i++) {
20178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping_t* mapping = array_get(&(s->mapping), i);
20188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (mapping->dir_index >= offset)
20198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->dir_index += adjust;
20208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if ((mapping->mode & MODE_DIRECTORY) &&
20218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping->info.dir.first_dir_index >= offset)
20228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->info.dir.first_dir_index += adjust;
20238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
20248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
20258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic direntry_t* insert_direntries(BDRVVVFATState* s,
20278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int dir_index, int count)
20288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
20298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*
20308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * make room in s->directory,
20318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * adjust_dirindices
20328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
20338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry_t* result = array_insert(&(s->directory), dir_index, count);
20348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (result == NULL)
20358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return NULL;
20368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    adjust_dirindices(s, dir_index, count);
20378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return result;
20388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
20398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
20418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
20428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret = array_remove_slice(&(s->directory), dir_index, count);
20438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret)
20448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return ret;
20458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    adjust_dirindices(s, dir_index, -count);
20468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
20478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
20488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
20508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Adapt the mappings of the cluster chain starting at first cluster
20518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * (i.e. if a file starts at first_cluster, the chain is followed according
20528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to the modified fat, and the corresponding entries in s->mapping are
20538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * adjusted)
20548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
20558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int commit_mappings(BDRVVVFATState* s,
20568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint32_t first_cluster, int dir_index)
20578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
20588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
20598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry_t* direntry = array_get(&(s->directory), dir_index);
20608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t cluster = first_cluster;
20618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vvfat_close_current_file(s);
20638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping);
20658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping->begin == first_cluster);
20668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->first_mapping_index = -1;
20678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->dir_index = dir_index;
20688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
20698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	MODE_DIRECTORY : MODE_NORMAL;
20708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (!fat_eof(s, cluster)) {
20728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint32_t c, c1;
20738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
20758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		c = c1, c1 = modified_fat_get(s, c1));
20768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	c++;
20788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (c > mapping->end) {
20798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int index = array_index(&(s->mapping), mapping);
20808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int i, max_i = s->mapping.next - index;
20818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    for (i = 1; i < max_i && mapping[i].begin < c; i++);
20828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    while (--i > 0)
20838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		remove_mapping(s, index + 1);
20848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
20858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
20868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		|| mapping[1].begin >= c);
20878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping->end = c;
20888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (!fat_eof(s, c1)) {
20908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
20918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* next_mapping = i >= s->mapping.next ? NULL :
20928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		array_get(&(s->mapping), i);
20938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (next_mapping == NULL || next_mapping->begin > c1) {
20958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int i1 = array_index(&(s->mapping), mapping);
20968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		next_mapping = insert_mapping(s, c1, c1+1);
20988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (c1 < c)
21008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    i1++;
21018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping = array_get(&(s->mapping), i1);
21028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
21038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    next_mapping->dir_index = mapping->dir_index;
21058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    next_mapping->first_mapping_index =
21068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping->first_mapping_index < 0 ?
21078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		array_index(&(s->mapping), mapping) :
21088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping->first_mapping_index;
21098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    next_mapping->path = mapping->path;
21108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    next_mapping->mode = mapping->mode;
21118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    next_mapping->read_only = mapping->read_only;
21128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping->mode & MODE_DIRECTORY) {
21138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		next_mapping->info.dir.parent_mapping_index =
21148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->info.dir.parent_mapping_index;
21158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		next_mapping->info.dir.first_dir_index =
21168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->info.dir.first_dir_index +
21178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			0x10 * s->sectors_per_cluster *
21188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			(mapping->end - mapping->begin);
21198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    } else
21208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		next_mapping->info.file.offset = mapping->info.file.offset +
21218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->end - mapping->begin;
21228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping = next_mapping;
21248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
21258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	cluster = c1;
21278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
21288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
21308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
21318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int commit_direntries(BDRVVVFATState* s,
21338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int dir_index, int parent_mapping_index)
21348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
21358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry_t* direntry = array_get(&(s->directory), dir_index);
21368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
21378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
21388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int factor = 0x10 * s->sectors_per_cluster;
21408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int old_cluster_count, new_cluster_count;
21418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int current_dir_index = mapping->info.dir.first_dir_index;
21428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int first_dir_index = current_dir_index;
21438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret, i;
21448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t c;
21458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
21478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(direntry);
21498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping);
21508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping->begin == first_cluster);
21518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping->info.dir.first_dir_index < s->directory.next);
21528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping->mode & MODE_DIRECTORY);
21538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(dir_index == 0 || is_directory(direntry));
21548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping->info.dir.parent_mapping_index = parent_mapping_index;
21568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (first_cluster == 0) {
21588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	old_cluster_count = new_cluster_count =
21598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->last_cluster_of_root_directory;
21608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
21618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
21628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		c = fat_get(s, c))
21638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    old_cluster_count++;
21648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
21668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		c = modified_fat_get(s, c))
21678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    new_cluster_count++;
21688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
21698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (new_cluster_count > old_cluster_count) {
21718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (insert_direntries(s,
21728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		current_dir_index + factor * old_cluster_count,
21738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		factor * (new_cluster_count - old_cluster_count)) == NULL)
21748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -1;
21758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (new_cluster_count < old_cluster_count)
21768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	remove_direntries(s,
21778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		current_dir_index + factor * new_cluster_count,
21788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		factor * (old_cluster_count - new_cluster_count));
21798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
21818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	void* direntry = array_get(&(s->directory), current_dir_index);
21828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
21838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->sectors_per_cluster);
21848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (ret)
21858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return ret;
21868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(!strncmp(s->directory.pointer, "QEMU", 4));
21878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	current_dir_index += factor;
21888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
21898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ret = commit_mappings(s, first_cluster, dir_index);
21918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret)
21928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return ret;
21938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* recurse */
21958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < factor * new_cluster_count; i++) {
21968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry = array_get(&(s->directory), first_dir_index + i);
21978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (is_directory(direntry) && !is_dot(direntry)) {
21988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping = find_mapping_for_cluster(s, first_cluster);
21998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping->mode & MODE_DIRECTORY);
22008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    ret = commit_direntries(s, first_dir_index + i,
22018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		array_index(&(s->mapping), mapping));
22028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (ret)
22038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return ret;
22048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
22058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
22068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
22088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
22098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* commit one file (adjust contents, adjust mapping),
22118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   return first_mapping_index */
22128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int commit_one_file(BDRVVVFATState* s,
22138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int dir_index, uint32_t offset)
22148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
22158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry_t* direntry = array_get(&(s->directory), dir_index);
22168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t c = begin_of_direntry(direntry);
22178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t first_cluster = c;
22188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping = find_mapping_for_cluster(s, c);
22198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t size = filesize_of_direntry(direntry);
22205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char* cluster = qemu_malloc(s->cluster_size);
22218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t i;
22228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int fd = 0;
22238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(offset < size);
22258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert((offset % s->cluster_size) == 0);
22268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = s->cluster_size; i < offset; i += s->cluster_size)
22288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	c = modified_fat_get(s, c);
22298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
22318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (fd < 0) {
22328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
22338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		strerror(errno), errno);
22348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return fd;
22358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
22368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (offset > 0)
22378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (lseek(fd, offset, SEEK_SET) != offset)
22388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -3;
22398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (offset < size) {
22418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	uint32_t c1;
22428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int rest_size = (size - offset > s->cluster_size ?
22438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		s->cluster_size : size - offset);
22448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int ret;
22458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	c1 = modified_fat_get(s, c);
22478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert((size - offset == 0 && fat_eof(s, c)) ||
22498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		(size > offset && c >=2 && !fat_eof(s, c)));
22508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	ret = vvfat_read(s->bs, cluster2sector(s, c),
22528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
22538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (ret < 0)
22558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return ret;
22568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (write(fd, cluster, rest_size) < 0)
22588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    return -2;
22598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	offset += rest_size;
22618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	c = c1;
22628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
22638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2264a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    if (ftruncate(fd, size)) {
2265a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        perror("ftruncate()");
2266a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        close(fd);
2267a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        return -4;
2268a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner    }
22698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    close(fd);
22708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return commit_mappings(s, first_cluster, dir_index);
22728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
22738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
22758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* test, if all mappings point to valid direntries */
22768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void check1(BDRVVVFATState* s)
22778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
22788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
22798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < s->mapping.next; i++) {
22808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping_t* mapping = array_get(&(s->mapping), i);
22818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (mapping->mode & MODE_DELETED) {
22828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fprintf(stderr, "deleted\n");
22838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    continue;
22848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
22858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping->dir_index >= 0);
22868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping->dir_index < s->directory.next);
22878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
22888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
22898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (mapping->mode & MODE_DIRECTORY) {
22908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
22918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
22928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
22938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
22948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
22958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* test, if all direntries have mappings */
22978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void check2(BDRVVVFATState* s)
22988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
22998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
23008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int first_mapping = -1;
23018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < s->directory.next; i++) {
23038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	direntry_t* direntry = array_get(&(s->directory), i);
23048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (is_short_name(direntry) && begin_of_direntry(direntry)) {
23068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
23078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping);
23088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping->dir_index == i || is_dot(direntry));
23098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
23108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
23118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
23138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /* cluster start */
23148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int j, count = 0;
23158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    for (j = 0; j < s->mapping.next; j++) {
23178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping_t* mapping = array_get(&(s->mapping), j);
23188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (mapping->mode & MODE_DELETED)
23198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    continue;
23208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (mapping->mode & MODE_DIRECTORY) {
23218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
23228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			assert(++count == 1);
23238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (mapping->first_mapping_index == -1)
23248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    first_mapping = array_index(&(s->mapping), mapping);
23258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			else
23268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    assert(first_mapping == mapping->first_mapping_index);
23278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (mapping->info.dir.parent_mapping_index < 0)
23288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    assert(j == 0);
23298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			else {
23308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
23318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    assert(parent->mode & MODE_DIRECTORY);
23328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
23338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			}
23348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    }
23358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
23368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
23378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (count == 0)
23388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		first_mapping = -1;
23398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
23408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
23418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
23428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
23438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int handle_renames_and_mkdirs(BDRVVVFATState* s)
23458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
23468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
23478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
23498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    fprintf(stderr, "handle_renames\n");
23508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < s->commits.next; i++) {
23518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	commit_t* commit = array_get(&(s->commits), i);
23528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
23538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
23548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
23558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < s->commits.next;) {
23578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	commit_t* commit = array_get(&(s->commits), i);
23588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (commit->action == ACTION_RENAME) {
23598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* mapping = find_mapping_for_cluster(s,
23608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    commit->param.rename.cluster);
23618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    char* old_path = mapping->path;
23628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(commit->path);
23648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->path = commit->path;
23658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (rename(old_path, mapping->path))
23668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return -2;
23678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping->mode & MODE_DIRECTORY) {
23698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int l1 = strlen(mapping->path);
23708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int l2 = strlen(old_path);
23718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int diff = l1 - l2;
23728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		direntry_t* direntry = array_get(&(s->directory),
23738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->info.dir.first_dir_index);
23748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		uint32_t c = mapping->begin;
23758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int i = 0;
23768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		/* recurse */
23788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		while (!fat_eof(s, c)) {
23798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    do {
23808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			direntry_t* d = direntry + i;
23818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (is_file(d) || (is_directory(d) && !is_dot(d))) {
23838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    mapping_t* m = find_mapping_for_cluster(s,
23848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    begin_of_direntry(d));
23858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    int l = strlen(m->path);
23865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			    char* new_path = qemu_malloc(l + diff + 1);
23878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    assert(!strncmp(m->path, mapping->path, l2));
23898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            pstrcpy(new_path, l + diff + 1, mapping->path);
23918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            pstrcpy(new_path + l1, l + diff + 1 - l1,
23928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                    m->path + l2);
23938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    schedule_rename(s, m->begin, new_path);
23958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			}
23968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			i++;
23978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
23988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    c = fat_get(s, c);
23998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
24008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
24018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    free(old_path);
24038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    array_remove(&(s->commits), i);
24048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    continue;
24058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else if (commit->action == ACTION_MKDIR) {
24068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* mapping;
24078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int j, parent_path_len;
24088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef __MINGW32__
24108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (mkdir(commit->path))
24118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                return -5;
24128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
24138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (mkdir(commit->path, 0755))
24148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                return -5;
24158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
24168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping = insert_mapping(s, commit->param.mkdir.cluster,
24188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    commit->param.mkdir.cluster + 1);
24198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping == NULL)
24208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return -6;
24218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->mode = MODE_DIRECTORY;
24238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->read_only = 0;
24248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->path = commit->path;
24258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    j = s->directory.next;
24268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(j);
24278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    insert_direntries(s, s->directory.next,
24288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    0x10 * s->sectors_per_cluster);
24298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->info.dir.first_dir_index = j;
24308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    parent_path_len = strlen(commit->path)
24328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		- strlen(get_basename(commit->path)) - 1;
24338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    for (j = 0; j < s->mapping.next; j++) {
24348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping_t* m = array_get(&(s->mapping), j);
24358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (m->first_mapping_index < 0 && m != mapping &&
24368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			!strncmp(m->path, mapping->path, parent_path_len) &&
24378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			strlen(m->path) == parent_path_len)
24388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    break;
24398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
24408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(j < s->mapping.next);
24418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->info.dir.parent_mapping_index = j;
24428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    array_remove(&(s->commits), i);
24448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    continue;
24458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
24468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	i++;
24488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
24498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
24508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
24518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
24538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * TODO: make sure that the short name is not matching *another* file
24548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
24558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int handle_commits(BDRVVVFATState* s)
24568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
24578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, fail = 0;
24588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vvfat_close_current_file(s);
24608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; !fail && i < s->commits.next; i++) {
24628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	commit_t* commit = array_get(&(s->commits), i);
24638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	switch(commit->action) {
24648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	case ACTION_RENAME: case ACTION_MKDIR:
2465a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner            abort();
24668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    fail = -2;
24678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    break;
24688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	case ACTION_WRITEOUT: {
2469a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner#ifndef NDEBUG
2470a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner            /* these variables are only used by assert() below */
24718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    direntry_t* entry = array_get(&(s->directory),
24728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    commit->param.writeout.dir_index);
24738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    uint32_t begin = begin_of_direntry(entry);
24748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* mapping = find_mapping_for_cluster(s, begin);
2475a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner#endif
24768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping);
24788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(mapping->begin == begin);
24798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(commit->path == NULL);
24808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (commit_one_file(s, commit->param.writeout.dir_index,
24828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			commit->param.writeout.modified_offset))
24838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fail = -3;
24848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    break;
24868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
24878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	case ACTION_NEW_FILE: {
24888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int begin = commit->param.new_file.first_cluster;
24898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* mapping = find_mapping_for_cluster(s, begin);
24908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    direntry_t* entry;
24918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    int i;
24928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
24938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /* find direntry */
24948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    for (i = 0; i < s->directory.next; i++) {
24958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		entry = array_get(&(s->directory), i);
24968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (is_file(entry) && begin_of_direntry(entry) == begin)
24978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    break;
24988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
24998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (i >= s->directory.next) {
25018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fail = -6;
25028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		continue;
25038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
25048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /* make sure there exists an initial mapping */
25068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping && mapping->begin != begin) {
25078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping->end = begin;
25088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping = NULL;
25098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
25108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping == NULL) {
25118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		mapping = insert_mapping(s, begin, begin+1);
25128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
25138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    /* most members will be fixed in commit_mappings() */
25148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    assert(commit->path);
25158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->path = commit->path;
25168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->read_only = 0;
25178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->mode = MODE_NORMAL;
25188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping->info.file.offset = 0;
25198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (commit_one_file(s, i, 0))
25218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fail = -7;
25228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    break;
25248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
25258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	default:
2526a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner            abort();
25278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
25288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
25298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
25308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
25318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return fail;
25328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
25338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int handle_deletes(BDRVVVFATState* s)
25358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
25368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, deferred = 1, deleted = 1;
25378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* delete files corresponding to mappings marked as deleted */
25398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
25408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (deferred && deleted) {
25418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	deferred = 0;
25428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	deleted = 0;
25438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	for (i = 1; i < s->mapping.next; i++) {
25458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    mapping_t* mapping = array_get(&(s->mapping), i);
25468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping->mode & MODE_DELETED) {
25478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		direntry_t* entry = array_get(&(s->directory),
25488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->dir_index);
25498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (is_free(entry)) {
25518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    /* remove file/directory */
25528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    if (mapping->mode & MODE_DIRECTORY) {
25538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			int j, next_dir_index = s->directory.next,
25548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			first_dir_index = mapping->info.dir.first_dir_index;
25558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (rmdir(mapping->path) < 0) {
25578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    if (errno == ENOTEMPTY) {
25588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				deferred++;
25598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				continue;
25608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    } else
25618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				return -5;
25628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			}
25638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			for (j = 1; j < s->mapping.next; j++) {
25658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    mapping_t* m = array_get(&(s->mapping), j);
25668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    if (m->mode & MODE_DIRECTORY &&
25678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    m->info.dir.first_dir_index >
25688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    first_dir_index &&
25698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    m->info.dir.first_dir_index <
25708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    next_dir_index)
25718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				next_dir_index =
25728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    m->info.dir.first_dir_index;
25738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			}
25748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			remove_direntries(s, first_dir_index,
25758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				next_dir_index - first_dir_index);
25768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			deleted++;
25788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    }
25798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		} else {
25808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    if (unlink(mapping->path))
25818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			return -4;
25828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    deleted++;
25838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
25848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
25858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		remove_mapping(s, i);
25868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
25878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
25888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
25898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
25918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
25928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
25938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
25948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * synchronize mapping with new state:
25958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
25968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * - copy FAT (with bdrv_read)
25978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * - mark all filenames corresponding to mappings as deleted
25988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * - recurse direntries from root (using bs->bdrv_read)
25998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * - delete files corresponding to mappings marked as deleted
26008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
26018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int do_commit(BDRVVVFATState* s)
26028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
26038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret = 0;
26048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* the real meat are the commits. Nothing to do? Move along! */
26068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->commits.next == 0)
26078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
26088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vvfat_close_current_file(s);
26108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ret = handle_renames_and_mkdirs(s);
26128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret) {
26138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Error handling renames (%d)\n", ret);
2614a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        abort();
26158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return ret;
26168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
26178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* copy FAT (with bdrv_read) */
26198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
26208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* recurse direntries from root (using bs->bdrv_read) */
26228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ret = commit_direntries(s, 0, -1);
26238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret) {
26248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
2625a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        abort();
26268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return ret;
26278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
26288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ret = handle_commits(s);
26308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret) {
26318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Error handling commits (%d)\n", ret);
2632a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        abort();
26338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return ret;
26348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
26358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ret = handle_deletes(s);
26378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret) {
26388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Error deleting\n");
2639a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner        abort();
26408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return ret;
26418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
26428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->qcow->drv->bdrv_make_empty(s->qcow);
26448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
26468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(checkpoint());
26488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
26498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
26508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int try_commit(BDRVVVFATState* s)
26528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
26538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vvfat_close_current_file(s);
26548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(checkpoint());
26558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(!is_consistent(s))
26568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
26578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return do_commit(s);
26588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
26598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int vvfat_write(BlockDriverState *bs, int64_t sector_num,
26618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    const uint8_t *buf, int nb_sectors)
26628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
26638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BDRVVVFATState *s = bs->opaque;
26648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, ret;
26658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(checkpoint());
26678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vvfat_close_current_file(s);
26698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*
26718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * Some sanity checks:
26728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - do not allow writing to the boot sector
26738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * - do not allow to write non-ASCII filenames
26748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
26758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (sector_num < s->first_sectors_number)
26778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
26788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = sector2cluster(s, sector_num);
26808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
26818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	mapping_t* mapping = find_mapping_for_cluster(s, i);
26828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (mapping) {
26838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping->read_only) {
26848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		fprintf(stderr, "Tried to write to write-protected file %s\n",
26858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			mapping->path);
26868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return -1;
26878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
26888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    if (mapping->mode & MODE_DIRECTORY) {
26908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int begin = cluster2sector(s, i);
26918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int end = begin + s->sectors_per_cluster, k;
26928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		int dir_index;
26938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		const direntry_t* direntries;
26948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		long_file_name lfn;
26958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		lfn_init(&lfn);
26978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
26988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (begin < sector_num)
26998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    begin = sector_num;
27008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (end > sector_num + nb_sectors)
27018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    end = sector_num + nb_sectors;
27028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		dir_index  = mapping->dir_index +
27038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
27048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
27058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		for (k = 0; k < (end - begin) * 0x10; k++) {
27078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    /* do not allow non-ASCII filenames */
27088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    if (parse_long_name(&lfn, direntries + k) < 0) {
27098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			fprintf(stderr, "Warning: non-ASCII filename\n");
27108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			return -1;
27118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    }
27128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    /* no access to the direntry of a read-only file */
27138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    else if (is_short_name(direntries+k) &&
27148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    (direntries[k].attributes & 1)) {
27158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (memcmp(direntries + k,
27168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    array_get(&(s->directory), dir_index + k),
27178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project				    sizeof(direntry_t))) {
27188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    fprintf(stderr, "Warning: tried to write to write-protected file\n");
27198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			    return -1;
27208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			}
27218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		    }
27228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
27238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    }
27248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    i = mapping->end;
27258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else
27268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    i++;
27278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
27288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /*
27308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * Use qcow backend. Commit later.
27318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
27328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
27338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
27348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret < 0) {
27358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Error writing to qcow backend\n");
27368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return ret;
27378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
27388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = sector2cluster(s, sector_num);
27408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
27418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (i >= 0)
27428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    s->used_clusters[i] |= USED_ALLOCATED;
27438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(checkpoint());
27458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* TODO: add timeout */
27468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    try_commit(s);
27478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDLOG(checkpoint());
27498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
27508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
27518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int vvfat_is_allocated(BlockDriverState *bs,
27538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int64_t sector_num, int nb_sectors, int* n)
27548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
27558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BDRVVVFATState* s = bs->opaque;
27568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    *n = s->sector_count - sector_num;
27578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (*n > nb_sectors)
27588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	*n = nb_sectors;
27598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else if (*n < 0)
27608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return 0;
27618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 1;
27628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
27638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int write_target_commit(BlockDriverState *bs, int64_t sector_num,
27658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	const uint8_t* buffer, int nb_sectors) {
27668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BDRVVVFATState* s = bs->opaque;
27678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return try_commit(s);
27688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
27698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void write_target_close(BlockDriverState *bs) {
27718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BDRVVVFATState* s = bs->opaque;
27728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bdrv_delete(s->qcow);
27738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    free(s->qcow_filename);
27748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
27758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic BlockDriver vvfat_write_target = {
27775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .format_name        = "vvfat_write_target",
27785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .bdrv_write         = write_target_commit,
27795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .bdrv_close         = write_target_close,
27808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
27818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int enable_write_target(BDRVVVFATState *s)
27838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
27845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BlockDriver *bdrv_qcow;
27855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUOptionParameter *options;
27868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int size = sector2cluster(s, s->sector_count);
27878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->used_clusters = calloc(size, 1);
27888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_init(&(s->commits), sizeof(commit_t));
27908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
27915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->qcow_filename = qemu_malloc(1024);
27928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    get_tmp_filename(s->qcow_filename, 1024);
27935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
27945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bdrv_qcow = bdrv_find_format("qcow");
27955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
27965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
27975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
27985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
27995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
28008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
28018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->qcow = bdrv_new("");
2802cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (s->qcow == NULL ||
2803cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        bdrv_open(s->qcow, s->qcow_filename, BDRV_O_RDWR, bdrv_qcow) < 0)
2804cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    {
28058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return -1;
2806cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
28078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
28088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef _WIN32
28098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unlink(s->qcow_filename);
28108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
28118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
28128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
28138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->bs->backing_hd->drv = &vvfat_write_target;
28148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->bs->backing_hd->opaque = s;
28158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
28168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
28178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
28188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
28198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void vvfat_close(BlockDriverState *bs)
28208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
28218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BDRVVVFATState *s = bs->opaque;
28228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
28238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vvfat_close_current_file(s);
28248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_free(&(s->fat));
28258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_free(&(s->directory));
28268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    array_free(&(s->mapping));
28278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if(s->cluster_buffer)
28288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        free(s->cluster_buffer);
28298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
28308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
28315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BlockDriver bdrv_vvfat = {
28325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .format_name	= "vvfat",
28335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .instance_size	= sizeof(BDRVVVFATState),
2834cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    .bdrv_file_open	= vvfat_open,
28355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .bdrv_read		= vvfat_read,
28365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .bdrv_write		= vvfat_write,
28375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .bdrv_close		= vvfat_close,
28385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .bdrv_is_allocated	= vvfat_is_allocated,
28395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    .protocol_name	= "fat",
28408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
28418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
28425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bdrv_vvfat_init(void)
28435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
28445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bdrv_register(&bdrv_vvfat);
28455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
28465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
28475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerblock_init(bdrv_vvfat_init);
28485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
28498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
28508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void checkpoint(void) {
28518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
28528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    check1(vvv);
28538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    check2(vvv);
28548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
28558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if 0
28568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
28578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	fprintf(stderr, "Nonono!\n");
28588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    mapping_t* mapping;
28598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry_t* direntry;
28608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
28618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
28628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vvv->mapping.next<47)
28638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	return;
28648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert((mapping = array_get(&(vvv->mapping), 47)));
28658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(mapping->dir_index < vvv->directory.next);
28668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    direntry = array_get(&(vvv->directory), mapping->dir_index);
28678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
28688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
28698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return;
28708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* avoid compiler warnings: */
28718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    hexdump(NULL, 100);
2872cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    remove_mapping(vvv, 0);
28738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    print_mapping(NULL);
28748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    print_direntry(NULL);
28758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
28768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
2877