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