Annotation of qemu/block/vvfat.c, revision 1.1.1.3

1.1       root        1: /* vim:set shiftwidth=4 ts=8: */
                      2: /*
                      3:  * QEMU Block driver for virtual VFAT (shadows a local directory)
                      4:  *
                      5:  * Copyright (c) 2004,2005 Johannes E. Schindelin
                      6:  *
                      7:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      8:  * of this software and associated documentation files (the "Software"), to deal
                      9:  * in the Software without restriction, including without limitation the rights
                     10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     11:  * copies of the Software, and to permit persons to whom the Software is
                     12:  * furnished to do so, subject to the following conditions:
                     13:  *
                     14:  * The above copyright notice and this permission notice shall be included in
                     15:  * all copies or substantial portions of the Software.
                     16:  *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     22:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     23:  * THE SOFTWARE.
                     24:  */
                     25: #include <sys/stat.h>
                     26: #include <dirent.h>
                     27: #include "qemu-common.h"
                     28: #include "block_int.h"
                     29: #include "module.h"
                     30: 
                     31: #ifndef S_IWGRP
                     32: #define S_IWGRP 0
                     33: #endif
                     34: #ifndef S_IWOTH
                     35: #define S_IWOTH 0
                     36: #endif
                     37: 
                     38: /* TODO: add ":bootsector=blabla.img:" */
                     39: /* LATER TODO: add automatic boot sector generation from
                     40:     BOOTEASY.ASM and Ranish Partition Manager
                     41:     Note that DOS assumes the system files to be the first files in the
                     42:     file system (test if the boot sector still relies on that fact)! */
                     43: /* MAYBE TODO: write block-visofs.c */
                     44: /* TODO: call try_commit() only after a timeout */
                     45: 
                     46: /* #define DEBUG */
                     47: 
                     48: #ifdef DEBUG
                     49: 
                     50: #define DLOG(a) a
                     51: 
                     52: #undef stderr
                     53: #define stderr STDERR
                     54: FILE* stderr = NULL;
                     55: 
                     56: static void checkpoint(void);
                     57: 
                     58: #ifdef __MINGW32__
                     59: void nonono(const char* file, int line, const char* msg) {
                     60:     fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
                     61:     exit(-5);
                     62: }
                     63: #undef assert
                     64: #define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
                     65: #endif
                     66: 
                     67: #else
                     68: 
                     69: #define DLOG(a)
                     70: 
                     71: #endif
                     72: 
                     73: /* dynamic array functions */
                     74: typedef struct array_t {
                     75:     char* pointer;
                     76:     unsigned int size,next,item_size;
                     77: } array_t;
                     78: 
                     79: static inline void array_init(array_t* array,unsigned int item_size)
                     80: {
                     81:     array->pointer = NULL;
                     82:     array->size=0;
                     83:     array->next=0;
                     84:     array->item_size=item_size;
                     85: }
                     86: 
                     87: static inline void array_free(array_t* array)
                     88: {
                     89:     if(array->pointer)
                     90:         free(array->pointer);
                     91:     array->size=array->next=0;
                     92: }
                     93: 
                     94: /* does not automatically grow */
                     95: static inline void* array_get(array_t* array,unsigned int index) {
                     96:     assert(index < array->next);
                     97:     return array->pointer + index * array->item_size;
                     98: }
                     99: 
                    100: static inline int array_ensure_allocated(array_t* array, int index)
                    101: {
                    102:     if((index + 1) * array->item_size > array->size) {
                    103:        int new_size = (index + 32) * array->item_size;
                    104:        array->pointer = qemu_realloc(array->pointer, new_size);
                    105:        if (!array->pointer)
                    106:            return -1;
                    107:        array->size = new_size;
                    108:        array->next = index + 1;
                    109:     }
                    110: 
                    111:     return 0;
                    112: }
                    113: 
                    114: static inline void* array_get_next(array_t* array) {
                    115:     unsigned int next = array->next;
                    116:     void* result;
                    117: 
                    118:     if (array_ensure_allocated(array, next) < 0)
                    119:        return NULL;
                    120: 
                    121:     array->next = next + 1;
                    122:     result = array_get(array, next);
                    123: 
                    124:     return result;
                    125: }
                    126: 
                    127: static inline void* array_insert(array_t* array,unsigned int index,unsigned int count) {
                    128:     if((array->next+count)*array->item_size>array->size) {
                    129:        int increment=count*array->item_size;
                    130:        array->pointer=qemu_realloc(array->pointer,array->size+increment);
                    131:        if(!array->pointer)
                    132:             return NULL;
                    133:        array->size+=increment;
                    134:     }
                    135:     memmove(array->pointer+(index+count)*array->item_size,
                    136:                array->pointer+index*array->item_size,
                    137:                (array->next-index)*array->item_size);
                    138:     array->next+=count;
                    139:     return array->pointer+index*array->item_size;
                    140: }
                    141: 
                    142: /* this performs a "roll", so that the element which was at index_from becomes
                    143:  * index_to, but the order of all other elements is preserved. */
                    144: static inline int array_roll(array_t* array,int index_to,int index_from,int count)
                    145: {
                    146:     char* buf;
                    147:     char* from;
                    148:     char* to;
                    149:     int is;
                    150: 
                    151:     if(!array ||
                    152:            index_to<0 || index_to>=array->next ||
                    153:            index_from<0 || index_from>=array->next)
                    154:        return -1;
                    155: 
                    156:     if(index_to==index_from)
                    157:        return 0;
                    158: 
                    159:     is=array->item_size;
                    160:     from=array->pointer+index_from*is;
                    161:     to=array->pointer+index_to*is;
                    162:     buf=qemu_malloc(is*count);
                    163:     memcpy(buf,from,is*count);
                    164: 
                    165:     if(index_to<index_from)
                    166:        memmove(to+is*count,to,from-to);
                    167:     else
                    168:        memmove(from,from+is*count,to-from);
                    169: 
                    170:     memcpy(to,buf,is*count);
                    171: 
                    172:     free(buf);
                    173: 
                    174:     return 0;
                    175: }
                    176: 
                    177: static inline int array_remove_slice(array_t* array,int index, int count)
                    178: {
                    179:     assert(index >=0);
                    180:     assert(count > 0);
                    181:     assert(index + count <= array->next);
                    182:     if(array_roll(array,array->next-1,index,count))
                    183:        return -1;
                    184:     array->next -= count;
                    185:     return 0;
                    186: }
                    187: 
                    188: static int array_remove(array_t* array,int index)
                    189: {
                    190:     return array_remove_slice(array, index, 1);
                    191: }
                    192: 
                    193: /* return the index for a given member */
                    194: static int array_index(array_t* array, void* pointer)
                    195: {
                    196:     size_t offset = (char*)pointer - array->pointer;
                    197:     assert((offset % array->item_size) == 0);
                    198:     assert(offset/array->item_size < array->next);
                    199:     return offset/array->item_size;
                    200: }
                    201: 
                    202: /* These structures are used to fake a disk and the VFAT filesystem.
                    203:  * For this reason we need to use __attribute__((packed)). */
                    204: 
                    205: typedef struct bootsector_t {
                    206:     uint8_t jump[3];
                    207:     uint8_t name[8];
                    208:     uint16_t sector_size;
                    209:     uint8_t sectors_per_cluster;
                    210:     uint16_t reserved_sectors;
                    211:     uint8_t number_of_fats;
                    212:     uint16_t root_entries;
                    213:     uint16_t total_sectors16;
                    214:     uint8_t media_type;
                    215:     uint16_t sectors_per_fat;
                    216:     uint16_t sectors_per_track;
                    217:     uint16_t number_of_heads;
                    218:     uint32_t hidden_sectors;
                    219:     uint32_t total_sectors;
                    220:     union {
                    221:         struct {
                    222:            uint8_t drive_number;
                    223:            uint8_t current_head;
                    224:            uint8_t signature;
                    225:            uint32_t id;
                    226:            uint8_t volume_label[11];
                    227:        } __attribute__((packed)) fat16;
                    228:        struct {
                    229:            uint32_t sectors_per_fat;
                    230:            uint16_t flags;
                    231:            uint8_t major,minor;
                    232:            uint32_t first_cluster_of_root_directory;
                    233:            uint16_t info_sector;
                    234:            uint16_t backup_boot_sector;
                    235:            uint16_t ignored;
                    236:        } __attribute__((packed)) fat32;
                    237:     } u;
                    238:     uint8_t fat_type[8];
                    239:     uint8_t ignored[0x1c0];
                    240:     uint8_t magic[2];
                    241: } __attribute__((packed)) bootsector_t;
                    242: 
                    243: typedef struct {
                    244:     uint8_t head;
                    245:     uint8_t sector;
                    246:     uint8_t cylinder;
                    247: } mbr_chs_t;
                    248: 
                    249: typedef struct partition_t {
                    250:     uint8_t attributes; /* 0x80 = bootable */
                    251:     mbr_chs_t start_CHS;
                    252:     uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
                    253:     mbr_chs_t end_CHS;
                    254:     uint32_t start_sector_long;
                    255:     uint32_t length_sector_long;
                    256: } __attribute__((packed)) partition_t;
                    257: 
                    258: typedef struct mbr_t {
                    259:     uint8_t ignored[0x1b8];
                    260:     uint32_t nt_id;
                    261:     uint8_t ignored2[2];
                    262:     partition_t partition[4];
                    263:     uint8_t magic[2];
                    264: } __attribute__((packed)) mbr_t;
                    265: 
                    266: typedef struct direntry_t {
                    267:     uint8_t name[8];
                    268:     uint8_t extension[3];
                    269:     uint8_t attributes;
                    270:     uint8_t reserved[2];
                    271:     uint16_t ctime;
                    272:     uint16_t cdate;
                    273:     uint16_t adate;
                    274:     uint16_t begin_hi;
                    275:     uint16_t mtime;
                    276:     uint16_t mdate;
                    277:     uint16_t begin;
                    278:     uint32_t size;
                    279: } __attribute__((packed)) direntry_t;
                    280: 
                    281: /* this structure are used to transparently access the files */
                    282: 
                    283: typedef struct mapping_t {
                    284:     /* begin is the first cluster, end is the last+1 */
                    285:     uint32_t begin,end;
                    286:     /* as s->directory is growable, no pointer may be used here */
                    287:     unsigned int dir_index;
                    288:     /* the clusters of a file may be in any order; this points to the first */
                    289:     int first_mapping_index;
                    290:     union {
                    291:        /* offset is
                    292:         * - the offset in the file (in clusters) for a file, or
                    293:         * - the next cluster of the directory for a directory, and
                    294:         * - the address of the buffer for a faked entry
                    295:         */
                    296:        struct {
                    297:            uint32_t offset;
                    298:        } file;
                    299:        struct {
                    300:            int parent_mapping_index;
                    301:            int first_dir_index;
                    302:        } dir;
                    303:     } info;
                    304:     /* path contains the full path, i.e. it always starts with s->path */
                    305:     char* path;
                    306: 
                    307:     enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
                    308:        MODE_DIRECTORY = 4, MODE_FAKED = 8,
                    309:        MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
                    310:     int read_only;
                    311: } mapping_t;
                    312: 
                    313: #ifdef DEBUG
                    314: static void print_direntry(const struct direntry_t*);
                    315: static void print_mapping(const struct mapping_t* mapping);
                    316: #endif
                    317: 
                    318: /* here begins the real VVFAT driver */
                    319: 
                    320: typedef struct BDRVVVFATState {
                    321:     BlockDriverState* bs; /* pointer to parent */
                    322:     unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
                    323:     unsigned char first_sectors[0x40*0x200];
                    324: 
                    325:     int fat_type; /* 16 or 32 */
                    326:     array_t fat,directory,mapping;
                    327: 
                    328:     unsigned int cluster_size;
                    329:     unsigned int sectors_per_cluster;
                    330:     unsigned int sectors_per_fat;
                    331:     unsigned int sectors_of_root_directory;
                    332:     uint32_t last_cluster_of_root_directory;
                    333:     unsigned int faked_sectors; /* how many sectors are faked before file data */
                    334:     uint32_t sector_count; /* total number of sectors of the partition */
                    335:     uint32_t cluster_count; /* total number of clusters of this partition */
                    336:     uint32_t max_fat_value;
                    337: 
                    338:     int current_fd;
                    339:     mapping_t* current_mapping;
                    340:     unsigned char* cluster; /* points to current cluster */
                    341:     unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
                    342:     unsigned int current_cluster;
                    343: 
                    344:     /* write support */
                    345:     BlockDriverState* write_target;
                    346:     char* qcow_filename;
                    347:     BlockDriverState* qcow;
                    348:     void* fat2;
                    349:     char* used_clusters;
                    350:     array_t commits;
                    351:     const char* path;
                    352:     int downcase_short_names;
                    353: } BDRVVVFATState;
                    354: 
                    355: /* take the sector position spos and convert it to Cylinder/Head/Sector position
                    356:  * if the position is outside the specified geometry, fill maximum value for CHS
                    357:  * and return 1 to signal overflow.
                    358:  */
                    359: static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
                    360:     int head,sector;
                    361:     sector   = spos % (bs->secs);  spos/= bs->secs;
                    362:     head     = spos % (bs->heads); spos/= bs->heads;
                    363:     if(spos >= bs->cyls){
                    364:         /* Overflow,
                    365:         it happens if 32bit sector positions are used, while CHS is only 24bit.
                    366:         Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
                    367:         chs->head     = 0xFF;
                    368:         chs->sector   = 0xFF;
                    369:         chs->cylinder = 0xFF;
                    370:         return 1;
                    371:     }
                    372:     chs->head     = (uint8_t)head;
                    373:     chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
                    374:     chs->cylinder = (uint8_t)spos;
                    375:     return 0;
                    376: }
                    377: 
                    378: static void init_mbr(BDRVVVFATState* s)
                    379: {
                    380:     /* TODO: if the files mbr.img and bootsect.img exist, use them */
                    381:     mbr_t* real_mbr=(mbr_t*)s->first_sectors;
1.1.1.2   root      382:     partition_t* partition = &(real_mbr->partition[0]);
1.1       root      383:     int lba;
                    384: 
                    385:     memset(s->first_sectors,0,512);
                    386: 
                    387:     /* Win NT Disk Signature */
                    388:     real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
                    389: 
                    390:     partition->attributes=0x80; /* bootable */
                    391: 
                    392:     /* LBA is used when partition is outside the CHS geometry */
                    393:     lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
                    394:     lba|= sector2CHS(s->bs, &partition->end_CHS,   s->sector_count);
                    395: 
                    396:     /*LBA partitions are identified only by start/length_sector_long not by CHS*/
                    397:     partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
                    398:     partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
                    399: 
                    400:     /* FAT12/FAT16/FAT32 */
                    401:     /* DOS uses different types when partition is LBA,
                    402:        probably to prevent older versions from using CHS on them */
                    403:     partition->fs_type= s->fat_type==12 ? 0x1:
                    404:                         s->fat_type==16 ? (lba?0xe:0x06):
                    405:                          /*fat_tyoe==32*/ (lba?0xc:0x0b);
                    406: 
                    407:     real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
                    408: }
                    409: 
                    410: /* direntry functions */
                    411: 
                    412: /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
                    413: static inline int short2long_name(char* dest,const char* src)
                    414: {
                    415:     int i;
                    416:     int len;
                    417:     for(i=0;i<129 && src[i];i++) {
                    418:         dest[2*i]=src[i];
                    419:        dest[2*i+1]=0;
                    420:     }
                    421:     len=2*i;
                    422:     dest[2*i]=dest[2*i+1]=0;
                    423:     for(i=2*i+2;(i%26);i++)
                    424:        dest[i]=0xff;
                    425:     return len;
                    426: }
                    427: 
                    428: static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* filename)
                    429: {
                    430:     char buffer[258];
                    431:     int length=short2long_name(buffer,filename),
                    432:         number_of_entries=(length+25)/26,i;
                    433:     direntry_t* entry;
                    434: 
                    435:     for(i=0;i<number_of_entries;i++) {
                    436:        entry=array_get_next(&(s->directory));
                    437:        entry->attributes=0xf;
                    438:        entry->reserved[0]=0;
                    439:        entry->begin=0;
                    440:        entry->name[0]=(number_of_entries-i)|(i==0?0x40:0);
                    441:     }
                    442:     for(i=0;i<26*number_of_entries;i++) {
                    443:        int offset=(i%26);
                    444:        if(offset<10) offset=1+offset;
                    445:        else if(offset<22) offset=14+offset-10;
                    446:        else offset=28+offset-22;
                    447:        entry=array_get(&(s->directory),s->directory.next-1-(i/26));
                    448:        entry->name[offset]=buffer[i];
                    449:     }
                    450:     return array_get(&(s->directory),s->directory.next-number_of_entries);
                    451: }
                    452: 
                    453: static char is_free(const direntry_t* direntry)
                    454: {
                    455:     return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
                    456: }
                    457: 
                    458: static char is_volume_label(const direntry_t* direntry)
                    459: {
                    460:     return direntry->attributes == 0x28;
                    461: }
                    462: 
                    463: static char is_long_name(const direntry_t* direntry)
                    464: {
                    465:     return direntry->attributes == 0xf;
                    466: }
                    467: 
                    468: static char is_short_name(const direntry_t* direntry)
                    469: {
                    470:     return !is_volume_label(direntry) && !is_long_name(direntry)
                    471:        && !is_free(direntry);
                    472: }
                    473: 
                    474: static char is_directory(const direntry_t* direntry)
                    475: {
                    476:     return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
                    477: }
                    478: 
                    479: static inline char is_dot(const direntry_t* direntry)
                    480: {
                    481:     return is_short_name(direntry) && direntry->name[0] == '.';
                    482: }
                    483: 
                    484: static char is_file(const direntry_t* direntry)
                    485: {
                    486:     return is_short_name(direntry) && !is_directory(direntry);
                    487: }
                    488: 
                    489: static inline uint32_t begin_of_direntry(const direntry_t* direntry)
                    490: {
                    491:     return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
                    492: }
                    493: 
                    494: static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
                    495: {
                    496:     return le32_to_cpu(direntry->size);
                    497: }
                    498: 
                    499: static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
                    500: {
                    501:     direntry->begin = cpu_to_le16(begin & 0xffff);
                    502:     direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
                    503: }
                    504: 
                    505: /* fat functions */
                    506: 
                    507: static inline uint8_t fat_chksum(const direntry_t* entry)
                    508: {
                    509:     uint8_t chksum=0;
                    510:     int i;
                    511: 
                    512:     for(i=0;i<11;i++) {
                    513:         unsigned char c;
                    514: 
                    515:         c = (i <= 8) ? entry->name[i] : entry->extension[i-8];
                    516:         chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
                    517:     }
                    518: 
                    519:     return chksum;
                    520: }
                    521: 
                    522: /* if return_time==0, this returns the fat_date, else the fat_time */
                    523: static uint16_t fat_datetime(time_t time,int return_time) {
                    524:     struct tm* t;
                    525: #ifdef _WIN32
                    526:     t=localtime(&time); /* this is not thread safe */
                    527: #else
                    528:     struct tm t1;
1.1.1.2   root      529:     t = &t1;
1.1       root      530:     localtime_r(&time,t);
                    531: #endif
                    532:     if(return_time)
                    533:        return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11));
                    534:     return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9));
                    535: }
                    536: 
                    537: static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
                    538: {
                    539:     if(s->fat_type==32) {
                    540:        uint32_t* entry=array_get(&(s->fat),cluster);
                    541:        *entry=cpu_to_le32(value);
                    542:     } else if(s->fat_type==16) {
                    543:        uint16_t* entry=array_get(&(s->fat),cluster);
                    544:        *entry=cpu_to_le16(value&0xffff);
                    545:     } else {
                    546:        int offset = (cluster*3/2);
                    547:        unsigned char* p = array_get(&(s->fat), offset);
                    548:         switch (cluster&1) {
                    549:        case 0:
                    550:                p[0] = value&0xff;
                    551:                p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
                    552:                break;
                    553:        case 1:
                    554:                p[0] = (p[0]&0xf) | ((value&0xf)<<4);
                    555:                p[1] = (value>>4);
                    556:                break;
                    557:        }
                    558:     }
                    559: }
                    560: 
                    561: static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
                    562: {
                    563:     if(s->fat_type==32) {
                    564:        uint32_t* entry=array_get(&(s->fat),cluster);
                    565:        return le32_to_cpu(*entry);
                    566:     } else if(s->fat_type==16) {
                    567:        uint16_t* entry=array_get(&(s->fat),cluster);
                    568:        return le16_to_cpu(*entry);
                    569:     } else {
                    570:        const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2;
                    571:        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
                    572:     }
                    573: }
                    574: 
                    575: static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
                    576: {
                    577:     if(fat_entry>s->max_fat_value-8)
                    578:        return -1;
                    579:     return 0;
                    580: }
                    581: 
                    582: static inline void init_fat(BDRVVVFATState* s)
                    583: {
                    584:     if (s->fat_type == 12) {
                    585:        array_init(&(s->fat),1);
                    586:        array_ensure_allocated(&(s->fat),
                    587:                s->sectors_per_fat * 0x200 * 3 / 2 - 1);
                    588:     } else {
                    589:        array_init(&(s->fat),(s->fat_type==32?4:2));
                    590:        array_ensure_allocated(&(s->fat),
                    591:                s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
                    592:     }
                    593:     memset(s->fat.pointer,0,s->fat.size);
                    594: 
                    595:     switch(s->fat_type) {
                    596:        case 12: s->max_fat_value=0xfff; break;
                    597:        case 16: s->max_fat_value=0xffff; break;
                    598:        case 32: s->max_fat_value=0x0fffffff; break;
                    599:        default: s->max_fat_value=0; /* error... */
                    600:     }
                    601: 
                    602: }
                    603: 
                    604: /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
                    605: /* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
                    606: static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
                    607:        unsigned int directory_start, const char* filename, int is_dot)
                    608: {
                    609:     int i,j,long_index=s->directory.next;
                    610:     direntry_t* entry = NULL;
                    611:     direntry_t* entry_long = NULL;
                    612: 
                    613:     if(is_dot) {
                    614:        entry=array_get_next(&(s->directory));
                    615:        memset(entry->name,0x20,11);
                    616:        memcpy(entry->name,filename,strlen(filename));
                    617:        return entry;
                    618:     }
                    619: 
                    620:     entry_long=create_long_filename(s,filename);
                    621: 
                    622:     i = strlen(filename);
                    623:     for(j = i - 1; j>0  && filename[j]!='.';j--);
                    624:     if (j > 0)
                    625:        i = (j > 8 ? 8 : j);
                    626:     else if (i > 8)
                    627:        i = 8;
                    628: 
                    629:     entry=array_get_next(&(s->directory));
                    630:     memset(entry->name,0x20,11);
                    631:     memcpy(entry->name, filename, i);
                    632: 
                    633:     if(j > 0)
                    634:        for (i = 0; i < 3 && filename[j+1+i]; i++)
                    635:            entry->extension[i] = filename[j+1+i];
                    636: 
                    637:     /* upcase & remove unwanted characters */
                    638:     for(i=10;i>=0;i--) {
                    639:        if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
                    640:        if(entry->name[i]<=' ' || entry->name[i]>0x7f
                    641:                || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
                    642:            entry->name[i]='_';
                    643:         else if(entry->name[i]>='a' && entry->name[i]<='z')
                    644:             entry->name[i]+='A'-'a';
                    645:     }
                    646: 
                    647:     /* mangle duplicates */
                    648:     while(1) {
                    649:        direntry_t* entry1=array_get(&(s->directory),directory_start);
                    650:        int j;
                    651: 
                    652:        for(;entry1<entry;entry1++)
                    653:            if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
                    654:                break; /* found dupe */
                    655:        if(entry1==entry) /* no dupe found */
                    656:            break;
                    657: 
                    658:        /* use all 8 characters of name */
                    659:        if(entry->name[7]==' ') {
                    660:            int j;
                    661:            for(j=6;j>0 && entry->name[j]==' ';j--)
                    662:                entry->name[j]='~';
                    663:        }
                    664: 
                    665:        /* increment number */
                    666:        for(j=7;j>0 && entry->name[j]=='9';j--)
                    667:            entry->name[j]='0';
                    668:        if(j>0) {
                    669:            if(entry->name[j]<'0' || entry->name[j]>'9')
                    670:                entry->name[j]='0';
                    671:            else
                    672:                entry->name[j]++;
                    673:        }
                    674:     }
                    675: 
                    676:     /* calculate checksum; propagate to long name */
                    677:     if(entry_long) {
                    678:         uint8_t chksum=fat_chksum(entry);
                    679: 
                    680:        /* calculate anew, because realloc could have taken place */
                    681:        entry_long=array_get(&(s->directory),long_index);
                    682:        while(entry_long<entry && is_long_name(entry_long)) {
                    683:            entry_long->reserved[1]=chksum;
                    684:            entry_long++;
                    685:        }
                    686:     }
                    687: 
                    688:     return entry;
                    689: }
                    690: 
                    691: /*
                    692:  * Read a directory. (the index of the corresponding mapping must be passed).
                    693:  */
                    694: static int read_directory(BDRVVVFATState* s, int mapping_index)
                    695: {
                    696:     mapping_t* mapping = array_get(&(s->mapping), mapping_index);
                    697:     direntry_t* direntry;
                    698:     const char* dirname = mapping->path;
                    699:     int first_cluster = mapping->begin;
                    700:     int parent_index = mapping->info.dir.parent_mapping_index;
                    701:     mapping_t* parent_mapping = (mapping_t*)
                    702:         (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
                    703:     int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
                    704: 
                    705:     DIR* dir=opendir(dirname);
                    706:     struct dirent* entry;
                    707:     int i;
                    708: 
                    709:     assert(mapping->mode & MODE_DIRECTORY);
                    710: 
                    711:     if(!dir) {
                    712:        mapping->end = mapping->begin;
                    713:        return -1;
                    714:     }
                    715: 
                    716:     i = mapping->info.dir.first_dir_index =
                    717:            first_cluster == 0 ? 0 : s->directory.next;
                    718: 
                    719:     /* actually read the directory, and allocate the mappings */
                    720:     while((entry=readdir(dir))) {
                    721:        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
                    722:         char* buffer;
                    723:        direntry_t* direntry;
                    724:         struct stat st;
                    725:        int is_dot=!strcmp(entry->d_name,".");
                    726:        int is_dotdot=!strcmp(entry->d_name,"..");
                    727: 
                    728:        if(first_cluster == 0 && (is_dotdot || is_dot))
                    729:            continue;
                    730: 
                    731:        buffer=(char*)qemu_malloc(length);
                    732:        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
                    733: 
                    734:        if(stat(buffer,&st)<0) {
                    735:            free(buffer);
                    736:             continue;
                    737:        }
                    738: 
                    739:        /* create directory entry for this file */
                    740:        direntry=create_short_and_long_name(s, i, entry->d_name,
                    741:                is_dot || is_dotdot);
                    742:        direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
                    743:        direntry->reserved[0]=direntry->reserved[1]=0;
                    744:        direntry->ctime=fat_datetime(st.st_ctime,1);
                    745:        direntry->cdate=fat_datetime(st.st_ctime,0);
                    746:        direntry->adate=fat_datetime(st.st_atime,0);
                    747:        direntry->begin_hi=0;
                    748:        direntry->mtime=fat_datetime(st.st_mtime,1);
                    749:        direntry->mdate=fat_datetime(st.st_mtime,0);
                    750:        if(is_dotdot)
                    751:            set_begin_of_direntry(direntry, first_cluster_of_parent);
                    752:        else if(is_dot)
                    753:            set_begin_of_direntry(direntry, first_cluster);
                    754:        else
                    755:            direntry->begin=0; /* do that later */
                    756:         if (st.st_size > 0x7fffffff) {
                    757:            fprintf(stderr, "File %s is larger than 2GB\n", buffer);
                    758:            free(buffer);
                    759:            return -2;
                    760:         }
                    761:        direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
                    762: 
                    763:        /* create mapping for this file */
                    764:        if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
                    765:            s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
                    766:            s->current_mapping->begin=0;
                    767:            s->current_mapping->end=st.st_size;
                    768:            /*
                    769:             * we get the direntry of the most recent direntry, which
                    770:             * contains the short name and all the relevant information.
                    771:             */
                    772:            s->current_mapping->dir_index=s->directory.next-1;
                    773:            s->current_mapping->first_mapping_index = -1;
                    774:            if (S_ISDIR(st.st_mode)) {
                    775:                s->current_mapping->mode = MODE_DIRECTORY;
                    776:                s->current_mapping->info.dir.parent_mapping_index =
                    777:                    mapping_index;
                    778:            } else {
                    779:                s->current_mapping->mode = MODE_UNDEFINED;
                    780:                s->current_mapping->info.file.offset = 0;
                    781:            }
                    782:            s->current_mapping->path=buffer;
                    783:            s->current_mapping->read_only =
                    784:                (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
                    785:        }
                    786:     }
                    787:     closedir(dir);
                    788: 
                    789:     /* fill with zeroes up to the end of the cluster */
                    790:     while(s->directory.next%(0x10*s->sectors_per_cluster)) {
                    791:        direntry_t* direntry=array_get_next(&(s->directory));
                    792:        memset(direntry,0,sizeof(direntry_t));
                    793:     }
                    794: 
                    795: /* TODO: if there are more entries, bootsector has to be adjusted! */
                    796: #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
                    797:     if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
                    798:        /* root directory */
                    799:        int cur = s->directory.next;
                    800:        array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
                    801:        memset(array_get(&(s->directory), cur), 0,
                    802:                (ROOT_ENTRIES - cur) * sizeof(direntry_t));
                    803:     }
                    804: 
                    805:      /* reget the mapping, since s->mapping was possibly realloc()ed */
                    806:     mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
                    807:     first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
                    808:        * 0x20 / s->cluster_size;
                    809:     mapping->end = first_cluster;
                    810: 
                    811:     direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
                    812:     set_begin_of_direntry(direntry, mapping->begin);
                    813: 
                    814:     return 0;
                    815: }
                    816: 
                    817: static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
                    818: {
                    819:     return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
                    820: }
                    821: 
                    822: static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
                    823: {
                    824:     return s->faked_sectors + s->sectors_per_cluster * cluster_num;
                    825: }
                    826: 
                    827: static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
                    828: {
                    829:     return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
                    830: }
                    831: 
                    832: #ifdef DBG
                    833: static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
                    834: {
                    835:     if(mapping->mode==MODE_UNDEFINED)
                    836:        return 0;
                    837:     return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
                    838: }
                    839: #endif
                    840: 
                    841: static int init_directories(BDRVVVFATState* s,
                    842:        const char* dirname)
                    843: {
                    844:     bootsector_t* bootsector;
                    845:     mapping_t* mapping;
                    846:     unsigned int i;
                    847:     unsigned int cluster;
                    848: 
                    849:     memset(&(s->first_sectors[0]),0,0x40*0x200);
                    850: 
                    851:     s->cluster_size=s->sectors_per_cluster*0x200;
                    852:     s->cluster_buffer=qemu_malloc(s->cluster_size);
                    853: 
                    854:     /*
                    855:      * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
                    856:      * where sc is sector_count,
                    857:      * spf is sectors_per_fat,
                    858:      * spc is sectors_per_clusters, and
                    859:      * fat_type = 12, 16 or 32.
                    860:      */
                    861:     i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
                    862:     s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
                    863: 
                    864:     array_init(&(s->mapping),sizeof(mapping_t));
                    865:     array_init(&(s->directory),sizeof(direntry_t));
                    866: 
                    867:     /* add volume label */
                    868:     {
                    869:        direntry_t* entry=array_get_next(&(s->directory));
                    870:        entry->attributes=0x28; /* archive | volume label */
                    871:        snprintf((char*)entry->name,11,"QEMU VVFAT");
                    872:     }
                    873: 
                    874:     /* Now build FAT, and write back information into directory */
                    875:     init_fat(s);
                    876: 
                    877:     s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
                    878:     s->cluster_count=sector2cluster(s, s->sector_count);
                    879: 
                    880:     mapping = array_get_next(&(s->mapping));
                    881:     mapping->begin = 0;
                    882:     mapping->dir_index = 0;
                    883:     mapping->info.dir.parent_mapping_index = -1;
                    884:     mapping->first_mapping_index = -1;
1.1.1.3 ! root      885:     mapping->path = qemu_strdup(dirname);
1.1       root      886:     i = strlen(mapping->path);
                    887:     if (i > 0 && mapping->path[i - 1] == '/')
                    888:        mapping->path[i - 1] = '\0';
                    889:     mapping->mode = MODE_DIRECTORY;
                    890:     mapping->read_only = 0;
                    891:     s->path = mapping->path;
                    892: 
                    893:     for (i = 0, cluster = 0; i < s->mapping.next; i++) {
                    894:        /* MS-DOS expects the FAT to be 0 for the root directory
                    895:         * (except for the media byte). */
                    896:        /* LATER TODO: still true for FAT32? */
                    897:        int fix_fat = (i != 0);
                    898:        mapping = array_get(&(s->mapping), i);
                    899: 
                    900:         if (mapping->mode & MODE_DIRECTORY) {
                    901:            mapping->begin = cluster;
                    902:            if(read_directory(s, i)) {
                    903:                fprintf(stderr, "Could not read directory %s\n",
                    904:                        mapping->path);
                    905:                return -1;
                    906:            }
                    907:            mapping = array_get(&(s->mapping), i);
                    908:        } else {
                    909:            assert(mapping->mode == MODE_UNDEFINED);
                    910:            mapping->mode=MODE_NORMAL;
                    911:            mapping->begin = cluster;
                    912:            if (mapping->end > 0) {
                    913:                direntry_t* direntry = array_get(&(s->directory),
                    914:                        mapping->dir_index);
                    915: 
                    916:                mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
                    917:                set_begin_of_direntry(direntry, mapping->begin);
                    918:            } else {
                    919:                mapping->end = cluster + 1;
                    920:                fix_fat = 0;
                    921:            }
                    922:        }
                    923: 
                    924:        assert(mapping->begin < mapping->end);
                    925: 
                    926:        /* next free cluster */
                    927:        cluster = mapping->end;
                    928: 
                    929:        if(cluster > s->cluster_count) {
                    930:            fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
                    931:                    s->fat_type,
                    932:                    s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
                    933:                                                                : "2.88 MB"
                    934:                                      : "504MB");
                    935:            return -EINVAL;
                    936:        }
                    937: 
                    938:        /* fix fat for entry */
                    939:        if (fix_fat) {
                    940:            int j;
                    941:            for(j = mapping->begin; j < mapping->end - 1; j++)
                    942:                fat_set(s, j, j+1);
                    943:            fat_set(s, mapping->end - 1, s->max_fat_value);
                    944:        }
                    945:     }
                    946: 
                    947:     mapping = array_get(&(s->mapping), 0);
                    948:     s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
                    949:     s->last_cluster_of_root_directory = mapping->end;
                    950: 
                    951:     /* the FAT signature */
                    952:     fat_set(s,0,s->max_fat_value);
                    953:     fat_set(s,1,s->max_fat_value);
                    954: 
                    955:     s->current_mapping = NULL;
                    956: 
                    957:     bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
                    958:     bootsector->jump[0]=0xeb;
                    959:     bootsector->jump[1]=0x3e;
                    960:     bootsector->jump[2]=0x90;
                    961:     memcpy(bootsector->name,"QEMU    ",8);
                    962:     bootsector->sector_size=cpu_to_le16(0x200);
                    963:     bootsector->sectors_per_cluster=s->sectors_per_cluster;
                    964:     bootsector->reserved_sectors=cpu_to_le16(1);
                    965:     bootsector->number_of_fats=0x2; /* number of FATs */
                    966:     bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
                    967:     bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
                    968:     bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
                    969:     s->fat.pointer[0] = bootsector->media_type;
                    970:     bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
                    971:     bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
                    972:     bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
                    973:     bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
                    974:     bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
                    975: 
                    976:     /* LATER TODO: if FAT32, this is wrong */
                    977:     bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
                    978:     bootsector->u.fat16.current_head=0;
                    979:     bootsector->u.fat16.signature=0x29;
                    980:     bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
                    981: 
                    982:     memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
                    983:     memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
                    984:     bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
                    985: 
                    986:     return 0;
                    987: }
                    988: 
                    989: #ifdef DEBUG
                    990: static BDRVVVFATState *vvv = NULL;
                    991: #endif
                    992: 
                    993: static int enable_write_target(BDRVVVFATState *s);
                    994: static int is_consistent(BDRVVVFATState *s);
                    995: 
                    996: static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
                    997: {
                    998:     BDRVVVFATState *s = bs->opaque;
                    999:     int floppy = 0;
                   1000:     int i;
                   1001: 
                   1002: #ifdef DEBUG
                   1003:     vvv = s;
                   1004: #endif
                   1005: 
                   1006: DLOG(if (stderr == NULL) {
                   1007:     stderr = fopen("vvfat.log", "a");
                   1008:     setbuf(stderr, NULL);
                   1009: })
                   1010: 
                   1011:     s->bs = bs;
                   1012: 
                   1013:     s->fat_type=16;
                   1014:     /* LATER TODO: if FAT32, adjust */
                   1015:     s->sectors_per_cluster=0x10;
                   1016:     /* 504MB disk*/
                   1017:     bs->cyls=1024; bs->heads=16; bs->secs=63;
                   1018: 
                   1019:     s->current_cluster=0xffffffff;
                   1020: 
                   1021:     s->first_sectors_number=0x40;
                   1022:     /* read only is the default for safety */
                   1023:     bs->read_only = 1;
                   1024:     s->qcow = s->write_target = NULL;
                   1025:     s->qcow_filename = NULL;
                   1026:     s->fat2 = NULL;
                   1027:     s->downcase_short_names = 1;
                   1028: 
                   1029:     if (!strstart(dirname, "fat:", NULL))
                   1030:        return -1;
                   1031: 
                   1032:     if (strstr(dirname, ":floppy:")) {
                   1033:        floppy = 1;
                   1034:        s->fat_type = 12;
                   1035:        s->first_sectors_number = 1;
                   1036:        s->sectors_per_cluster=2;
                   1037:        bs->cyls = 80; bs->heads = 2; bs->secs = 36;
                   1038:     }
                   1039: 
                   1040:     s->sector_count=bs->cyls*bs->heads*bs->secs;
                   1041: 
                   1042:     if (strstr(dirname, ":32:")) {
                   1043:        fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
                   1044:        s->fat_type = 32;
                   1045:     } else if (strstr(dirname, ":16:")) {
                   1046:        s->fat_type = 16;
                   1047:     } else if (strstr(dirname, ":12:")) {
                   1048:        s->fat_type = 12;
                   1049:        s->sector_count=2880;
                   1050:     }
                   1051: 
                   1052:     if (strstr(dirname, ":rw:")) {
                   1053:        if (enable_write_target(s))
                   1054:            return -1;
                   1055:        bs->read_only = 0;
                   1056:     }
                   1057: 
                   1058:     i = strrchr(dirname, ':') - dirname;
                   1059:     assert(i >= 3);
                   1060:     if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
                   1061:        /* workaround for DOS drive names */
                   1062:        dirname += i-1;
                   1063:     else
                   1064:        dirname += i+1;
                   1065: 
                   1066:     bs->total_sectors=bs->cyls*bs->heads*bs->secs;
                   1067: 
                   1068:     if(init_directories(s, dirname))
                   1069:        return -1;
                   1070: 
                   1071:     s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
                   1072: 
                   1073:     if(s->first_sectors_number==0x40)
                   1074:        init_mbr(s);
                   1075: 
                   1076:     /* for some reason or other, MS-DOS does not like to know about CHS... */
                   1077:     if (floppy)
                   1078:        bs->heads = bs->cyls = bs->secs = 0;
                   1079: 
                   1080:     //    assert(is_consistent(s));
                   1081:     return 0;
                   1082: }
                   1083: 
                   1084: static inline void vvfat_close_current_file(BDRVVVFATState *s)
                   1085: {
                   1086:     if(s->current_mapping) {
                   1087:        s->current_mapping = NULL;
                   1088:        if (s->current_fd) {
                   1089:                close(s->current_fd);
                   1090:                s->current_fd = 0;
                   1091:        }
                   1092:     }
                   1093:     s->current_cluster = -1;
                   1094: }
                   1095: 
                   1096: /* mappings between index1 and index2-1 are supposed to be ordered
                   1097:  * return value is the index of the last mapping for which end>cluster_num
                   1098:  */
                   1099: static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
                   1100: {
                   1101:     int index3=index1+1;
                   1102:     while(1) {
                   1103:        mapping_t* mapping;
                   1104:        index3=(index1+index2)/2;
                   1105:        mapping=array_get(&(s->mapping),index3);
                   1106:        assert(mapping->begin < mapping->end);
                   1107:        if(mapping->begin>=cluster_num) {
                   1108:            assert(index2!=index3 || index2==0);
                   1109:            if(index2==index3)
                   1110:                return index1;
                   1111:            index2=index3;
                   1112:        } else {
                   1113:            if(index1==index3)
                   1114:                return mapping->end<=cluster_num ? index2 : index1;
                   1115:            index1=index3;
                   1116:        }
                   1117:        assert(index1<=index2);
                   1118:        DLOG(mapping=array_get(&(s->mapping),index1);
                   1119:        assert(mapping->begin<=cluster_num);
                   1120:        assert(index2 >= s->mapping.next ||
                   1121:                ((mapping = array_get(&(s->mapping),index2)) &&
                   1122:                mapping->end>cluster_num)));
                   1123:     }
                   1124: }
                   1125: 
                   1126: static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
                   1127: {
                   1128:     int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
                   1129:     mapping_t* mapping;
                   1130:     if(index>=s->mapping.next)
                   1131:         return NULL;
                   1132:     mapping=array_get(&(s->mapping),index);
                   1133:     if(mapping->begin>cluster_num)
                   1134:         return NULL;
                   1135:     assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
                   1136:     return mapping;
                   1137: }
                   1138: 
                   1139: /*
                   1140:  * This function simply compares path == mapping->path. Since the mappings
                   1141:  * are sorted by cluster, this is expensive: O(n).
                   1142:  */
                   1143: static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
                   1144:        const char* path)
                   1145: {
                   1146:     int i;
                   1147: 
                   1148:     for (i = 0; i < s->mapping.next; i++) {
                   1149:        mapping_t* mapping = array_get(&(s->mapping), i);
                   1150:        if (mapping->first_mapping_index < 0 &&
                   1151:                !strcmp(path, mapping->path))
                   1152:            return mapping;
                   1153:     }
                   1154: 
                   1155:     return NULL;
                   1156: }
                   1157: 
                   1158: static int open_file(BDRVVVFATState* s,mapping_t* mapping)
                   1159: {
                   1160:     if(!mapping)
                   1161:        return -1;
                   1162:     if(!s->current_mapping ||
                   1163:            strcmp(s->current_mapping->path,mapping->path)) {
                   1164:        /* open file */
                   1165:        int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
                   1166:        if(fd<0)
                   1167:            return -1;
                   1168:        vvfat_close_current_file(s);
                   1169:        s->current_fd = fd;
                   1170:        s->current_mapping = mapping;
                   1171:     }
                   1172:     return 0;
                   1173: }
                   1174: 
                   1175: static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
                   1176: {
                   1177:     if(s->current_cluster != cluster_num) {
                   1178:        int result=0;
                   1179:        off_t offset;
                   1180:        assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
                   1181:        if(!s->current_mapping
                   1182:                || s->current_mapping->begin>cluster_num
                   1183:                || s->current_mapping->end<=cluster_num) {
                   1184:            /* binary search of mappings for file */
                   1185:            mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
                   1186: 
                   1187:            assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
                   1188: 
                   1189:            if (mapping && mapping->mode & MODE_DIRECTORY) {
                   1190:                vvfat_close_current_file(s);
                   1191:                s->current_mapping = mapping;
                   1192: read_cluster_directory:
                   1193:                offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
                   1194:                s->cluster = (unsigned char*)s->directory.pointer+offset
                   1195:                        + 0x20*s->current_mapping->info.dir.first_dir_index;
                   1196:                assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
                   1197:                assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
                   1198:                s->current_cluster = cluster_num;
                   1199:                return 0;
                   1200:            }
                   1201: 
                   1202:            if(open_file(s,mapping))
                   1203:                return -2;
                   1204:        } else if (s->current_mapping->mode & MODE_DIRECTORY)
                   1205:            goto read_cluster_directory;
                   1206: 
                   1207:        assert(s->current_fd);
                   1208: 
                   1209:        offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
                   1210:        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
                   1211:            return -3;
                   1212:        s->cluster=s->cluster_buffer;
                   1213:        result=read(s->current_fd,s->cluster,s->cluster_size);
                   1214:        if(result<0) {
                   1215:            s->current_cluster = -1;
                   1216:            return -1;
                   1217:        }
                   1218:        s->current_cluster = cluster_num;
                   1219:     }
                   1220:     return 0;
                   1221: }
                   1222: 
                   1223: #ifdef DEBUG
                   1224: static void hexdump(const void* address, uint32_t len)
                   1225: {
                   1226:     const unsigned char* p = address;
                   1227:     int i, j;
                   1228: 
                   1229:     for (i = 0; i < len; i += 16) {
                   1230:        for (j = 0; j < 16 && i + j < len; j++)
                   1231:            fprintf(stderr, "%02x ", p[i + j]);
                   1232:        for (; j < 16; j++)
                   1233:            fprintf(stderr, "   ");
                   1234:        fprintf(stderr, " ");
                   1235:        for (j = 0; j < 16 && i + j < len; j++)
                   1236:            fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
                   1237:        fprintf(stderr, "\n");
                   1238:     }
                   1239: }
                   1240: 
                   1241: static void print_direntry(const direntry_t* direntry)
                   1242: {
                   1243:     int j = 0;
                   1244:     char buffer[1024];
                   1245: 
                   1246:     fprintf(stderr, "direntry 0x%x: ", (int)direntry);
                   1247:     if(!direntry)
                   1248:        return;
                   1249:     if(is_long_name(direntry)) {
                   1250:        unsigned char* c=(unsigned char*)direntry;
                   1251:        int i;
                   1252:        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
                   1253: #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
                   1254:            ADD_CHAR(c[i]);
                   1255:        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
                   1256:            ADD_CHAR(c[i]);
                   1257:        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
                   1258:            ADD_CHAR(c[i]);
                   1259:        buffer[j] = 0;
                   1260:        fprintf(stderr, "%s\n", buffer);
                   1261:     } else {
                   1262:        int i;
                   1263:        for(i=0;i<11;i++)
                   1264:            ADD_CHAR(direntry->name[i]);
                   1265:        buffer[j] = 0;
                   1266:        fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
                   1267:                buffer,
                   1268:                direntry->attributes,
                   1269:                begin_of_direntry(direntry),le32_to_cpu(direntry->size));
                   1270:     }
                   1271: }
                   1272: 
                   1273: static void print_mapping(const mapping_t* mapping)
                   1274: {
                   1275:     fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
                   1276:     if (mapping->mode & MODE_DIRECTORY)
                   1277:        fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
                   1278:     else
                   1279:        fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
                   1280: }
                   1281: #endif
                   1282: 
                   1283: static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
                   1284:                     uint8_t *buf, int nb_sectors)
                   1285: {
                   1286:     BDRVVVFATState *s = bs->opaque;
                   1287:     int i;
                   1288: 
                   1289:     for(i=0;i<nb_sectors;i++,sector_num++) {
                   1290:        if (sector_num >= s->sector_count)
                   1291:           return -1;
                   1292:        if (s->qcow) {
                   1293:            int n;
                   1294:            if (s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1295:                        sector_num, nb_sectors-i, &n)) {
                   1296: DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
                   1297:                if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
                   1298:                    return -1;
                   1299:                i += n - 1;
                   1300:                sector_num += n - 1;
                   1301:                continue;
                   1302:            }
                   1303: DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
                   1304:        }
                   1305:        if(sector_num<s->faked_sectors) {
                   1306:            if(sector_num<s->first_sectors_number)
                   1307:                memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
                   1308:            else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
                   1309:                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
                   1310:            else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
                   1311:                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
                   1312:        } else {
                   1313:            uint32_t sector=sector_num-s->faked_sectors,
                   1314:            sector_offset_in_cluster=(sector%s->sectors_per_cluster),
                   1315:            cluster_num=sector/s->sectors_per_cluster;
                   1316:            if(read_cluster(s, cluster_num) != 0) {
                   1317:                /* LATER TODO: strict: return -1; */
                   1318:                memset(buf+i*0x200,0,0x200);
                   1319:                continue;
                   1320:            }
                   1321:            memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
                   1322:        }
                   1323:     }
                   1324:     return 0;
                   1325: }
                   1326: 
                   1327: /* LATER TODO: statify all functions */
                   1328: 
                   1329: /*
                   1330:  * Idea of the write support (use snapshot):
                   1331:  *
                   1332:  * 1. check if all data is consistent, recording renames, modifications,
                   1333:  *    new files and directories (in s->commits).
                   1334:  *
                   1335:  * 2. if the data is not consistent, stop committing
                   1336:  *
                   1337:  * 3. handle renames, and create new files and directories (do not yet
                   1338:  *    write their contents)
                   1339:  *
                   1340:  * 4. walk the directories, fixing the mapping and direntries, and marking
                   1341:  *    the handled mappings as not deleted
                   1342:  *
                   1343:  * 5. commit the contents of the files
                   1344:  *
                   1345:  * 6. handle deleted files and directories
                   1346:  *
                   1347:  */
                   1348: 
                   1349: typedef struct commit_t {
                   1350:     char* path;
                   1351:     union {
                   1352:        struct { uint32_t cluster; } rename;
                   1353:        struct { int dir_index; uint32_t modified_offset; } writeout;
                   1354:        struct { uint32_t first_cluster; } new_file;
                   1355:        struct { uint32_t cluster; } mkdir;
                   1356:     } param;
                   1357:     /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
                   1358:     enum {
                   1359:        ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
                   1360:     } action;
                   1361: } commit_t;
                   1362: 
                   1363: static void clear_commits(BDRVVVFATState* s)
                   1364: {
                   1365:     int i;
                   1366: DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
                   1367:     for (i = 0; i < s->commits.next; i++) {
                   1368:        commit_t* commit = array_get(&(s->commits), i);
                   1369:        assert(commit->path || commit->action == ACTION_WRITEOUT);
                   1370:        if (commit->action != ACTION_WRITEOUT) {
                   1371:            assert(commit->path);
                   1372:            free(commit->path);
                   1373:        } else
                   1374:            assert(commit->path == NULL);
                   1375:     }
                   1376:     s->commits.next = 0;
                   1377: }
                   1378: 
                   1379: static void schedule_rename(BDRVVVFATState* s,
                   1380:        uint32_t cluster, char* new_path)
                   1381: {
                   1382:     commit_t* commit = array_get_next(&(s->commits));
                   1383:     commit->path = new_path;
                   1384:     commit->param.rename.cluster = cluster;
                   1385:     commit->action = ACTION_RENAME;
                   1386: }
                   1387: 
                   1388: static void schedule_writeout(BDRVVVFATState* s,
                   1389:        int dir_index, uint32_t modified_offset)
                   1390: {
                   1391:     commit_t* commit = array_get_next(&(s->commits));
                   1392:     commit->path = NULL;
                   1393:     commit->param.writeout.dir_index = dir_index;
                   1394:     commit->param.writeout.modified_offset = modified_offset;
                   1395:     commit->action = ACTION_WRITEOUT;
                   1396: }
                   1397: 
                   1398: static void schedule_new_file(BDRVVVFATState* s,
                   1399:        char* path, uint32_t first_cluster)
                   1400: {
                   1401:     commit_t* commit = array_get_next(&(s->commits));
                   1402:     commit->path = path;
                   1403:     commit->param.new_file.first_cluster = first_cluster;
                   1404:     commit->action = ACTION_NEW_FILE;
                   1405: }
                   1406: 
                   1407: static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
                   1408: {
                   1409:     commit_t* commit = array_get_next(&(s->commits));
                   1410:     commit->path = path;
                   1411:     commit->param.mkdir.cluster = cluster;
                   1412:     commit->action = ACTION_MKDIR;
                   1413: }
                   1414: 
                   1415: typedef struct {
                   1416:     /*
                   1417:      * Since the sequence number is at most 0x3f, and the filename
                   1418:      * length is at most 13 times the sequence number, the maximal
                   1419:      * filename length is 0x3f * 13 bytes.
                   1420:      */
                   1421:     unsigned char name[0x3f * 13 + 1];
                   1422:     int checksum, len;
                   1423:     int sequence_number;
                   1424: } long_file_name;
                   1425: 
                   1426: static void lfn_init(long_file_name* lfn)
                   1427: {
                   1428:    lfn->sequence_number = lfn->len = 0;
                   1429:    lfn->checksum = 0x100;
                   1430: }
                   1431: 
                   1432: /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
                   1433: static int parse_long_name(long_file_name* lfn,
                   1434:        const direntry_t* direntry)
                   1435: {
                   1436:     int i, j, offset;
                   1437:     const unsigned char* pointer = (const unsigned char*)direntry;
                   1438: 
                   1439:     if (!is_long_name(direntry))
                   1440:        return 1;
                   1441: 
                   1442:     if (pointer[0] & 0x40) {
                   1443:        lfn->sequence_number = pointer[0] & 0x3f;
                   1444:        lfn->checksum = pointer[13];
                   1445:        lfn->name[0] = 0;
                   1446:        lfn->name[lfn->sequence_number * 13] = 0;
                   1447:     } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
                   1448:        return -1;
                   1449:     else if (pointer[13] != lfn->checksum)
                   1450:        return -2;
                   1451:     else if (pointer[12] || pointer[26] || pointer[27])
                   1452:        return -3;
                   1453: 
                   1454:     offset = 13 * (lfn->sequence_number - 1);
                   1455:     for (i = 0, j = 1; i < 13; i++, j+=2) {
                   1456:        if (j == 11)
                   1457:            j = 14;
                   1458:        else if (j == 26)
                   1459:            j = 28;
                   1460: 
                   1461:        if (pointer[j+1] == 0)
                   1462:            lfn->name[offset + i] = pointer[j];
                   1463:        else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
                   1464:            return -4;
                   1465:        else
                   1466:            lfn->name[offset + i] = 0;
                   1467:     }
                   1468: 
                   1469:     if (pointer[0] & 0x40)
                   1470:        lfn->len = offset + strlen((char*)lfn->name + offset);
                   1471: 
                   1472:     return 0;
                   1473: }
                   1474: 
                   1475: /* returns 0 if successful, >0 if no short_name, and <0 on error */
                   1476: static int parse_short_name(BDRVVVFATState* s,
                   1477:        long_file_name* lfn, direntry_t* direntry)
                   1478: {
                   1479:     int i, j;
                   1480: 
                   1481:     if (!is_short_name(direntry))
                   1482:        return 1;
                   1483: 
                   1484:     for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
                   1485:     for (i = 0; i <= j; i++) {
                   1486:        if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
                   1487:            return -1;
                   1488:        else if (s->downcase_short_names)
                   1489:            lfn->name[i] = qemu_tolower(direntry->name[i]);
                   1490:        else
                   1491:            lfn->name[i] = direntry->name[i];
                   1492:     }
                   1493: 
                   1494:     for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
                   1495:     if (j >= 0) {
                   1496:        lfn->name[i++] = '.';
                   1497:        lfn->name[i + j + 1] = '\0';
                   1498:        for (;j >= 0; j--) {
                   1499:            if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
                   1500:                return -2;
                   1501:            else if (s->downcase_short_names)
                   1502:                lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
                   1503:            else
                   1504:                lfn->name[i + j] = direntry->extension[j];
                   1505:        }
                   1506:     } else
                   1507:        lfn->name[i + j + 1] = '\0';
                   1508: 
                   1509:     lfn->len = strlen((char*)lfn->name);
                   1510: 
                   1511:     return 0;
                   1512: }
                   1513: 
                   1514: static inline uint32_t modified_fat_get(BDRVVVFATState* s,
                   1515:        unsigned int cluster)
                   1516: {
                   1517:     if (cluster < s->last_cluster_of_root_directory) {
                   1518:        if (cluster + 1 == s->last_cluster_of_root_directory)
                   1519:            return s->max_fat_value;
                   1520:        else
                   1521:            return cluster + 1;
                   1522:     }
                   1523: 
                   1524:     if (s->fat_type==32) {
                   1525:         uint32_t* entry=((uint32_t*)s->fat2)+cluster;
                   1526:         return le32_to_cpu(*entry);
                   1527:     } else if (s->fat_type==16) {
                   1528:         uint16_t* entry=((uint16_t*)s->fat2)+cluster;
                   1529:         return le16_to_cpu(*entry);
                   1530:     } else {
                   1531:         const uint8_t* x=s->fat2+cluster*3/2;
                   1532:         return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
                   1533:     }
                   1534: }
                   1535: 
                   1536: static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
                   1537: {
                   1538:     int was_modified = 0;
                   1539:     int i, dummy;
                   1540: 
                   1541:     if (s->qcow == NULL)
                   1542:        return 0;
                   1543: 
                   1544:     for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
                   1545:        was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1546:                cluster2sector(s, cluster_num) + i, 1, &dummy);
                   1547: 
                   1548:     return was_modified;
                   1549: }
                   1550: 
                   1551: static const char* get_basename(const char* path)
                   1552: {
                   1553:     char* basename = strrchr(path, '/');
                   1554:     if (basename == NULL)
                   1555:        return path;
                   1556:     else
                   1557:        return basename + 1; /* strip '/' */
                   1558: }
                   1559: 
                   1560: /*
                   1561:  * The array s->used_clusters holds the states of the clusters. If it is
                   1562:  * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
                   1563:  * was modified, bit 3 is set.
                   1564:  * If any cluster is allocated, but not part of a file or directory, this
                   1565:  * driver refuses to commit.
                   1566:  */
                   1567: typedef enum {
                   1568:      USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
                   1569: } used_t;
                   1570: 
                   1571: /*
                   1572:  * get_cluster_count_for_direntry() not only determines how many clusters
                   1573:  * are occupied by direntry, but also if it was renamed or modified.
                   1574:  *
                   1575:  * A file is thought to be renamed *only* if there already was a file with
                   1576:  * exactly the same first cluster, but a different name.
                   1577:  *
                   1578:  * Further, the files/directories handled by this function are
                   1579:  * assumed to be *not* deleted (and *only* those).
                   1580:  */
                   1581: static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
                   1582:        direntry_t* direntry, const char* path)
                   1583: {
                   1584:     /*
                   1585:      * This is a little bit tricky:
                   1586:      * IF the guest OS just inserts a cluster into the file chain,
                   1587:      * and leaves the rest alone, (i.e. the original file had clusters
                   1588:      * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
                   1589:      *
                   1590:      * - do_commit will write the cluster into the file at the given
                   1591:      *   offset, but
                   1592:      *
                   1593:      * - the cluster which is overwritten should be moved to a later
                   1594:      *   position in the file.
                   1595:      *
                   1596:      * I am not aware that any OS does something as braindead, but this
                   1597:      * situation could happen anyway when not committing for a long time.
                   1598:      * Just to be sure that this does not bite us, detect it, and copy the
                   1599:      * contents of the clusters to-be-overwritten into the qcow.
                   1600:      */
                   1601:     int copy_it = 0;
                   1602:     int was_modified = 0;
                   1603:     int32_t ret = 0;
                   1604: 
                   1605:     uint32_t cluster_num = begin_of_direntry(direntry);
                   1606:     uint32_t offset = 0;
                   1607:     int first_mapping_index = -1;
                   1608:     mapping_t* mapping = NULL;
                   1609:     const char* basename2 = NULL;
                   1610: 
                   1611:     vvfat_close_current_file(s);
                   1612: 
                   1613:     /* the root directory */
                   1614:     if (cluster_num == 0)
                   1615:        return 0;
                   1616: 
                   1617:     /* write support */
                   1618:     if (s->qcow) {
                   1619:        basename2 = get_basename(path);
                   1620: 
                   1621:        mapping = find_mapping_for_cluster(s, cluster_num);
                   1622: 
                   1623:        if (mapping) {
                   1624:            const char* basename;
                   1625: 
                   1626:            assert(mapping->mode & MODE_DELETED);
                   1627:            mapping->mode &= ~MODE_DELETED;
                   1628: 
                   1629:            basename = get_basename(mapping->path);
                   1630: 
                   1631:            assert(mapping->mode & MODE_NORMAL);
                   1632: 
                   1633:            /* rename */
                   1634:            if (strcmp(basename, basename2))
1.1.1.3 ! root     1635:                schedule_rename(s, cluster_num, qemu_strdup(path));
1.1       root     1636:        } else if (is_file(direntry))
                   1637:            /* new file */
1.1.1.3 ! root     1638:            schedule_new_file(s, qemu_strdup(path), cluster_num);
1.1       root     1639:        else {
                   1640:            assert(0);
                   1641:            return 0;
                   1642:        }
                   1643:     }
                   1644: 
                   1645:     while(1) {
                   1646:        if (s->qcow) {
                   1647:            if (!copy_it && cluster_was_modified(s, cluster_num)) {
                   1648:                if (mapping == NULL ||
                   1649:                        mapping->begin > cluster_num ||
                   1650:                        mapping->end <= cluster_num)
                   1651:                mapping = find_mapping_for_cluster(s, cluster_num);
                   1652: 
                   1653: 
                   1654:                if (mapping &&
                   1655:                        (mapping->mode & MODE_DIRECTORY) == 0) {
                   1656: 
                   1657:                    /* was modified in qcow */
                   1658:                    if (offset != mapping->info.file.offset + s->cluster_size
                   1659:                            * (cluster_num - mapping->begin)) {
                   1660:                        /* offset of this cluster in file chain has changed */
                   1661:                        assert(0);
                   1662:                        copy_it = 1;
                   1663:                    } else if (offset == 0) {
                   1664:                        const char* basename = get_basename(mapping->path);
                   1665: 
                   1666:                        if (strcmp(basename, basename2))
                   1667:                            copy_it = 1;
                   1668:                        first_mapping_index = array_index(&(s->mapping), mapping);
                   1669:                    }
                   1670: 
                   1671:                    if (mapping->first_mapping_index != first_mapping_index
                   1672:                            && mapping->info.file.offset > 0) {
                   1673:                        assert(0);
                   1674:                        copy_it = 1;
                   1675:                    }
                   1676: 
                   1677:                    /* need to write out? */
                   1678:                    if (!was_modified && is_file(direntry)) {
                   1679:                        was_modified = 1;
                   1680:                        schedule_writeout(s, mapping->dir_index, offset);
                   1681:                    }
                   1682:                }
                   1683:            }
                   1684: 
                   1685:            if (copy_it) {
                   1686:                int i, dummy;
                   1687:                /*
                   1688:                 * This is horribly inefficient, but that is okay, since
                   1689:                 * it is rarely executed, if at all.
                   1690:                 */
                   1691:                int64_t offset = cluster2sector(s, cluster_num);
                   1692: 
                   1693:                vvfat_close_current_file(s);
                   1694:                for (i = 0; i < s->sectors_per_cluster; i++)
                   1695:                    if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1696:                                offset + i, 1, &dummy)) {
                   1697:                        if (vvfat_read(s->bs,
                   1698:                                    offset, s->cluster_buffer, 1))
                   1699:                            return -1;
                   1700:                        if (s->qcow->drv->bdrv_write(s->qcow,
                   1701:                                    offset, s->cluster_buffer, 1))
                   1702:                            return -2;
                   1703:                    }
                   1704:            }
                   1705:        }
                   1706: 
                   1707:        ret++;
                   1708:        if (s->used_clusters[cluster_num] & USED_ANY)
                   1709:            return 0;
                   1710:        s->used_clusters[cluster_num] = USED_FILE;
                   1711: 
                   1712:        cluster_num = modified_fat_get(s, cluster_num);
                   1713: 
                   1714:        if (fat_eof(s, cluster_num))
                   1715:            return ret;
                   1716:        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
                   1717:            return -1;
                   1718: 
                   1719:        offset += s->cluster_size;
                   1720:     }
                   1721: }
                   1722: 
                   1723: /*
                   1724:  * This function looks at the modified data (qcow).
                   1725:  * It returns 0 upon inconsistency or error, and the number of clusters
                   1726:  * used by the directory, its subdirectories and their files.
                   1727:  */
                   1728: static int check_directory_consistency(BDRVVVFATState *s,
                   1729:        int cluster_num, const char* path)
                   1730: {
                   1731:     int ret = 0;
                   1732:     unsigned char* cluster = qemu_malloc(s->cluster_size);
                   1733:     direntry_t* direntries = (direntry_t*)cluster;
                   1734:     mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
                   1735: 
                   1736:     long_file_name lfn;
                   1737:     int path_len = strlen(path);
                   1738:     char path2[PATH_MAX];
                   1739: 
                   1740:     assert(path_len < PATH_MAX); /* len was tested before! */
                   1741:     pstrcpy(path2, sizeof(path2), path);
                   1742:     path2[path_len] = '/';
                   1743:     path2[path_len + 1] = '\0';
                   1744: 
                   1745:     if (mapping) {
                   1746:        const char* basename = get_basename(mapping->path);
                   1747:        const char* basename2 = get_basename(path);
                   1748: 
                   1749:        assert(mapping->mode & MODE_DIRECTORY);
                   1750: 
                   1751:        assert(mapping->mode & MODE_DELETED);
                   1752:        mapping->mode &= ~MODE_DELETED;
                   1753: 
                   1754:        if (strcmp(basename, basename2))
1.1.1.3 ! root     1755:            schedule_rename(s, cluster_num, qemu_strdup(path));
1.1       root     1756:     } else
                   1757:        /* new directory */
1.1.1.3 ! root     1758:        schedule_mkdir(s, cluster_num, qemu_strdup(path));
1.1       root     1759: 
                   1760:     lfn_init(&lfn);
                   1761:     do {
                   1762:        int i;
                   1763:        int subret = 0;
                   1764: 
                   1765:        ret++;
                   1766: 
                   1767:        if (s->used_clusters[cluster_num] & USED_ANY) {
                   1768:            fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
                   1769:            return 0;
                   1770:        }
                   1771:        s->used_clusters[cluster_num] = USED_DIRECTORY;
                   1772: 
                   1773: DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
                   1774:        subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
                   1775:                s->sectors_per_cluster);
                   1776:        if (subret) {
                   1777:            fprintf(stderr, "Error fetching direntries\n");
                   1778:        fail:
                   1779:            free(cluster);
                   1780:            return 0;
                   1781:        }
                   1782: 
                   1783:        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
                   1784:            int cluster_count = 0;
                   1785: 
                   1786: DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
                   1787:            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
                   1788:                    is_free(direntries + i))
                   1789:                continue;
                   1790: 
                   1791:            subret = parse_long_name(&lfn, direntries + i);
                   1792:            if (subret < 0) {
                   1793:                fprintf(stderr, "Error in long name\n");
                   1794:                goto fail;
                   1795:            }
                   1796:            if (subret == 0 || is_free(direntries + i))
                   1797:                continue;
                   1798: 
                   1799:            if (fat_chksum(direntries+i) != lfn.checksum) {
                   1800:                subret = parse_short_name(s, &lfn, direntries + i);
                   1801:                if (subret < 0) {
                   1802:                    fprintf(stderr, "Error in short name (%d)\n", subret);
                   1803:                    goto fail;
                   1804:                }
                   1805:                if (subret > 0 || !strcmp((char*)lfn.name, ".")
                   1806:                        || !strcmp((char*)lfn.name, ".."))
                   1807:                    continue;
                   1808:            }
                   1809:            lfn.checksum = 0x100; /* cannot use long name twice */
                   1810: 
                   1811:            if (path_len + 1 + lfn.len >= PATH_MAX) {
                   1812:                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
                   1813:                goto fail;
                   1814:            }
                   1815:             pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
                   1816:                     (char*)lfn.name);
                   1817: 
                   1818:            if (is_directory(direntries + i)) {
                   1819:                if (begin_of_direntry(direntries + i) == 0) {
                   1820:                    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
                   1821:                    goto fail;
                   1822:                }
                   1823:                cluster_count = check_directory_consistency(s,
                   1824:                        begin_of_direntry(direntries + i), path2);
                   1825:                if (cluster_count == 0) {
                   1826:                    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
                   1827:                    goto fail;
                   1828:                }
                   1829:            } else if (is_file(direntries + i)) {
                   1830:                /* check file size with FAT */
                   1831:                cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
                   1832:                if (cluster_count !=
                   1833:                        (le32_to_cpu(direntries[i].size) + s->cluster_size
                   1834:                         - 1) / s->cluster_size) {
                   1835:                    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
                   1836:                    goto fail;
                   1837:                }
                   1838:            } else
                   1839:                assert(0); /* cluster_count = 0; */
                   1840: 
                   1841:            ret += cluster_count;
                   1842:        }
                   1843: 
                   1844:        cluster_num = modified_fat_get(s, cluster_num);
                   1845:     } while(!fat_eof(s, cluster_num));
                   1846: 
                   1847:     free(cluster);
                   1848:     return ret;
                   1849: }
                   1850: 
                   1851: /* returns 1 on success */
                   1852: static int is_consistent(BDRVVVFATState* s)
                   1853: {
                   1854:     int i, check;
                   1855:     int used_clusters_count = 0;
                   1856: 
                   1857: DLOG(checkpoint());
                   1858:     /*
                   1859:      * - get modified FAT
                   1860:      * - compare the two FATs (TODO)
                   1861:      * - get buffer for marking used clusters
                   1862:      * - recurse direntries from root (using bs->bdrv_read to make
                   1863:      *    sure to get the new data)
                   1864:      *   - check that the FAT agrees with the size
                   1865:      *   - count the number of clusters occupied by this directory and
                   1866:      *     its files
                   1867:      * - check that the cumulative used cluster count agrees with the
                   1868:      *   FAT
                   1869:      * - if all is fine, return number of used clusters
                   1870:      */
                   1871:     if (s->fat2 == NULL) {
                   1872:        int size = 0x200 * s->sectors_per_fat;
                   1873:        s->fat2 = qemu_malloc(size);
                   1874:        memcpy(s->fat2, s->fat.pointer, size);
                   1875:     }
                   1876:     check = vvfat_read(s->bs,
                   1877:            s->first_sectors_number, s->fat2, s->sectors_per_fat);
                   1878:     if (check) {
                   1879:        fprintf(stderr, "Could not copy fat\n");
                   1880:        return 0;
                   1881:     }
                   1882:     assert (s->used_clusters);
                   1883:     for (i = 0; i < sector2cluster(s, s->sector_count); i++)
                   1884:        s->used_clusters[i] &= ~USED_ANY;
                   1885: 
                   1886:     clear_commits(s);
                   1887: 
                   1888:     /* mark every mapped file/directory as deleted.
                   1889:      * (check_directory_consistency() will unmark those still present). */
                   1890:     if (s->qcow)
                   1891:        for (i = 0; i < s->mapping.next; i++) {
                   1892:            mapping_t* mapping = array_get(&(s->mapping), i);
                   1893:            if (mapping->first_mapping_index < 0)
                   1894:                mapping->mode |= MODE_DELETED;
                   1895:        }
                   1896: 
                   1897:     used_clusters_count = check_directory_consistency(s, 0, s->path);
                   1898:     if (used_clusters_count <= 0) {
                   1899:        DLOG(fprintf(stderr, "problem in directory\n"));
                   1900:        return 0;
                   1901:     }
                   1902: 
                   1903:     check = s->last_cluster_of_root_directory;
                   1904:     for (i = check; i < sector2cluster(s, s->sector_count); i++) {
                   1905:        if (modified_fat_get(s, i)) {
                   1906:            if(!s->used_clusters[i]) {
                   1907:                DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
                   1908:                return 0;
                   1909:            }
                   1910:            check++;
                   1911:        }
                   1912: 
                   1913:        if (s->used_clusters[i] == USED_ALLOCATED) {
                   1914:            /* allocated, but not used... */
                   1915:            DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
                   1916:            return 0;
                   1917:        }
                   1918:     }
                   1919: 
                   1920:     if (check != used_clusters_count)
                   1921:        return 0;
                   1922: 
                   1923:     return used_clusters_count;
                   1924: }
                   1925: 
                   1926: static inline void adjust_mapping_indices(BDRVVVFATState* s,
                   1927:        int offset, int adjust)
                   1928: {
                   1929:     int i;
                   1930: 
                   1931:     for (i = 0; i < s->mapping.next; i++) {
                   1932:        mapping_t* mapping = array_get(&(s->mapping), i);
                   1933: 
                   1934: #define ADJUST_MAPPING_INDEX(name) \
                   1935:        if (mapping->name >= offset) \
                   1936:            mapping->name += adjust
                   1937: 
                   1938:        ADJUST_MAPPING_INDEX(first_mapping_index);
                   1939:        if (mapping->mode & MODE_DIRECTORY)
                   1940:            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
                   1941:     }
                   1942: }
                   1943: 
                   1944: /* insert or update mapping */
                   1945: static mapping_t* insert_mapping(BDRVVVFATState* s,
                   1946:        uint32_t begin, uint32_t end)
                   1947: {
                   1948:     /*
                   1949:      * - find mapping where mapping->begin >= begin,
                   1950:      * - if mapping->begin > begin: insert
                   1951:      *   - adjust all references to mappings!
                   1952:      * - else: adjust
                   1953:      * - replace name
                   1954:      */
                   1955:     int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
                   1956:     mapping_t* mapping = NULL;
                   1957:     mapping_t* first_mapping = array_get(&(s->mapping), 0);
                   1958: 
                   1959:     if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
                   1960:            && mapping->begin < begin) {
                   1961:        mapping->end = begin;
                   1962:        index++;
                   1963:        mapping = array_get(&(s->mapping), index);
                   1964:     }
                   1965:     if (index >= s->mapping.next || mapping->begin > begin) {
                   1966:        mapping = array_insert(&(s->mapping), index, 1);
                   1967:        mapping->path = NULL;
                   1968:        adjust_mapping_indices(s, index, +1);
                   1969:     }
                   1970: 
                   1971:     mapping->begin = begin;
                   1972:     mapping->end = end;
                   1973: 
                   1974: DLOG(mapping_t* next_mapping;
                   1975: assert(index + 1 >= s->mapping.next ||
                   1976: ((next_mapping = array_get(&(s->mapping), index + 1)) &&
                   1977:  next_mapping->begin >= end)));
                   1978: 
                   1979:     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
                   1980:        s->current_mapping = array_get(&(s->mapping),
                   1981:                s->current_mapping - first_mapping);
                   1982: 
                   1983:     return mapping;
                   1984: }
                   1985: 
                   1986: static int remove_mapping(BDRVVVFATState* s, int mapping_index)
                   1987: {
                   1988:     mapping_t* mapping = array_get(&(s->mapping), mapping_index);
                   1989:     mapping_t* first_mapping = array_get(&(s->mapping), 0);
                   1990: 
                   1991:     /* free mapping */
                   1992:     if (mapping->first_mapping_index < 0)
                   1993:        free(mapping->path);
                   1994: 
                   1995:     /* remove from s->mapping */
                   1996:     array_remove(&(s->mapping), mapping_index);
                   1997: 
                   1998:     /* adjust all references to mappings */
                   1999:     adjust_mapping_indices(s, mapping_index, -1);
                   2000: 
                   2001:     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
                   2002:        s->current_mapping = array_get(&(s->mapping),
                   2003:                s->current_mapping - first_mapping);
                   2004: 
                   2005:     return 0;
                   2006: }
                   2007: 
                   2008: static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
                   2009: {
                   2010:     int i;
                   2011:     for (i = 0; i < s->mapping.next; i++) {
                   2012:        mapping_t* mapping = array_get(&(s->mapping), i);
                   2013:        if (mapping->dir_index >= offset)
                   2014:            mapping->dir_index += adjust;
                   2015:        if ((mapping->mode & MODE_DIRECTORY) &&
                   2016:                mapping->info.dir.first_dir_index >= offset)
                   2017:            mapping->info.dir.first_dir_index += adjust;
                   2018:     }
                   2019: }
                   2020: 
                   2021: static direntry_t* insert_direntries(BDRVVVFATState* s,
                   2022:        int dir_index, int count)
                   2023: {
                   2024:     /*
                   2025:      * make room in s->directory,
                   2026:      * adjust_dirindices
                   2027:      */
                   2028:     direntry_t* result = array_insert(&(s->directory), dir_index, count);
                   2029:     if (result == NULL)
                   2030:        return NULL;
                   2031:     adjust_dirindices(s, dir_index, count);
                   2032:     return result;
                   2033: }
                   2034: 
                   2035: static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
                   2036: {
                   2037:     int ret = array_remove_slice(&(s->directory), dir_index, count);
                   2038:     if (ret)
                   2039:        return ret;
                   2040:     adjust_dirindices(s, dir_index, -count);
                   2041:     return 0;
                   2042: }
                   2043: 
                   2044: /*
                   2045:  * Adapt the mappings of the cluster chain starting at first cluster
                   2046:  * (i.e. if a file starts at first_cluster, the chain is followed according
                   2047:  * to the modified fat, and the corresponding entries in s->mapping are
                   2048:  * adjusted)
                   2049:  */
                   2050: static int commit_mappings(BDRVVVFATState* s,
                   2051:        uint32_t first_cluster, int dir_index)
                   2052: {
                   2053:     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
                   2054:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2055:     uint32_t cluster = first_cluster;
                   2056: 
                   2057:     vvfat_close_current_file(s);
                   2058: 
                   2059:     assert(mapping);
                   2060:     assert(mapping->begin == first_cluster);
                   2061:     mapping->first_mapping_index = -1;
                   2062:     mapping->dir_index = dir_index;
                   2063:     mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
                   2064:        MODE_DIRECTORY : MODE_NORMAL;
                   2065: 
                   2066:     while (!fat_eof(s, cluster)) {
                   2067:        uint32_t c, c1;
                   2068: 
                   2069:        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
                   2070:                c = c1, c1 = modified_fat_get(s, c1));
                   2071: 
                   2072:        c++;
                   2073:        if (c > mapping->end) {
                   2074:            int index = array_index(&(s->mapping), mapping);
                   2075:            int i, max_i = s->mapping.next - index;
                   2076:            for (i = 1; i < max_i && mapping[i].begin < c; i++);
                   2077:            while (--i > 0)
                   2078:                remove_mapping(s, index + 1);
                   2079:        }
                   2080:        assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
                   2081:                || mapping[1].begin >= c);
                   2082:        mapping->end = c;
                   2083: 
                   2084:        if (!fat_eof(s, c1)) {
                   2085:            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
                   2086:            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
                   2087:                array_get(&(s->mapping), i);
                   2088: 
                   2089:            if (next_mapping == NULL || next_mapping->begin > c1) {
                   2090:                int i1 = array_index(&(s->mapping), mapping);
                   2091: 
                   2092:                next_mapping = insert_mapping(s, c1, c1+1);
                   2093: 
                   2094:                if (c1 < c)
                   2095:                    i1++;
                   2096:                mapping = array_get(&(s->mapping), i1);
                   2097:            }
                   2098: 
                   2099:            next_mapping->dir_index = mapping->dir_index;
                   2100:            next_mapping->first_mapping_index =
                   2101:                mapping->first_mapping_index < 0 ?
                   2102:                array_index(&(s->mapping), mapping) :
                   2103:                mapping->first_mapping_index;
                   2104:            next_mapping->path = mapping->path;
                   2105:            next_mapping->mode = mapping->mode;
                   2106:            next_mapping->read_only = mapping->read_only;
                   2107:            if (mapping->mode & MODE_DIRECTORY) {
                   2108:                next_mapping->info.dir.parent_mapping_index =
                   2109:                        mapping->info.dir.parent_mapping_index;
                   2110:                next_mapping->info.dir.first_dir_index =
                   2111:                        mapping->info.dir.first_dir_index +
                   2112:                        0x10 * s->sectors_per_cluster *
                   2113:                        (mapping->end - mapping->begin);
                   2114:            } else
                   2115:                next_mapping->info.file.offset = mapping->info.file.offset +
                   2116:                        mapping->end - mapping->begin;
                   2117: 
                   2118:            mapping = next_mapping;
                   2119:        }
                   2120: 
                   2121:        cluster = c1;
                   2122:     }
                   2123: 
                   2124:     return 0;
                   2125: }
                   2126: 
                   2127: static int commit_direntries(BDRVVVFATState* s,
                   2128:        int dir_index, int parent_mapping_index)
                   2129: {
                   2130:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2131:     uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
                   2132:     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
                   2133: 
                   2134:     int factor = 0x10 * s->sectors_per_cluster;
                   2135:     int old_cluster_count, new_cluster_count;
                   2136:     int current_dir_index = mapping->info.dir.first_dir_index;
                   2137:     int first_dir_index = current_dir_index;
                   2138:     int ret, i;
                   2139:     uint32_t c;
                   2140: 
                   2141: DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
                   2142: 
                   2143:     assert(direntry);
                   2144:     assert(mapping);
                   2145:     assert(mapping->begin == first_cluster);
                   2146:     assert(mapping->info.dir.first_dir_index < s->directory.next);
                   2147:     assert(mapping->mode & MODE_DIRECTORY);
                   2148:     assert(dir_index == 0 || is_directory(direntry));
                   2149: 
                   2150:     mapping->info.dir.parent_mapping_index = parent_mapping_index;
                   2151: 
                   2152:     if (first_cluster == 0) {
                   2153:        old_cluster_count = new_cluster_count =
                   2154:            s->last_cluster_of_root_directory;
                   2155:     } else {
                   2156:        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
                   2157:                c = fat_get(s, c))
                   2158:            old_cluster_count++;
                   2159: 
                   2160:        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
                   2161:                c = modified_fat_get(s, c))
                   2162:            new_cluster_count++;
                   2163:     }
                   2164: 
                   2165:     if (new_cluster_count > old_cluster_count) {
                   2166:        if (insert_direntries(s,
                   2167:                current_dir_index + factor * old_cluster_count,
                   2168:                factor * (new_cluster_count - old_cluster_count)) == NULL)
                   2169:            return -1;
                   2170:     } else if (new_cluster_count < old_cluster_count)
                   2171:        remove_direntries(s,
                   2172:                current_dir_index + factor * new_cluster_count,
                   2173:                factor * (old_cluster_count - new_cluster_count));
                   2174: 
                   2175:     for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
                   2176:        void* direntry = array_get(&(s->directory), current_dir_index);
                   2177:        int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
                   2178:                s->sectors_per_cluster);
                   2179:        if (ret)
                   2180:            return ret;
                   2181:        assert(!strncmp(s->directory.pointer, "QEMU", 4));
                   2182:        current_dir_index += factor;
                   2183:     }
                   2184: 
                   2185:     ret = commit_mappings(s, first_cluster, dir_index);
                   2186:     if (ret)
                   2187:        return ret;
                   2188: 
                   2189:     /* recurse */
                   2190:     for (i = 0; i < factor * new_cluster_count; i++) {
                   2191:        direntry = array_get(&(s->directory), first_dir_index + i);
                   2192:        if (is_directory(direntry) && !is_dot(direntry)) {
                   2193:            mapping = find_mapping_for_cluster(s, first_cluster);
                   2194:            assert(mapping->mode & MODE_DIRECTORY);
                   2195:            ret = commit_direntries(s, first_dir_index + i,
                   2196:                array_index(&(s->mapping), mapping));
                   2197:            if (ret)
                   2198:                return ret;
                   2199:        }
                   2200:     }
                   2201: 
                   2202:     return 0;
                   2203: }
                   2204: 
                   2205: /* commit one file (adjust contents, adjust mapping),
                   2206:    return first_mapping_index */
                   2207: static int commit_one_file(BDRVVVFATState* s,
                   2208:        int dir_index, uint32_t offset)
                   2209: {
                   2210:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2211:     uint32_t c = begin_of_direntry(direntry);
                   2212:     uint32_t first_cluster = c;
                   2213:     mapping_t* mapping = find_mapping_for_cluster(s, c);
                   2214:     uint32_t size = filesize_of_direntry(direntry);
                   2215:     char* cluster = qemu_malloc(s->cluster_size);
                   2216:     uint32_t i;
                   2217:     int fd = 0;
                   2218: 
                   2219:     assert(offset < size);
                   2220:     assert((offset % s->cluster_size) == 0);
                   2221: 
                   2222:     for (i = s->cluster_size; i < offset; i += s->cluster_size)
                   2223:        c = modified_fat_get(s, c);
                   2224: 
                   2225:     fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
                   2226:     if (fd < 0) {
                   2227:        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
                   2228:                strerror(errno), errno);
                   2229:        return fd;
                   2230:     }
                   2231:     if (offset > 0)
                   2232:        if (lseek(fd, offset, SEEK_SET) != offset)
                   2233:            return -3;
                   2234: 
                   2235:     while (offset < size) {
                   2236:        uint32_t c1;
                   2237:        int rest_size = (size - offset > s->cluster_size ?
                   2238:                s->cluster_size : size - offset);
                   2239:        int ret;
                   2240: 
                   2241:        c1 = modified_fat_get(s, c);
                   2242: 
                   2243:        assert((size - offset == 0 && fat_eof(s, c)) ||
                   2244:                (size > offset && c >=2 && !fat_eof(s, c)));
                   2245: 
                   2246:        ret = vvfat_read(s->bs, cluster2sector(s, c),
                   2247:            (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
                   2248: 
                   2249:        if (ret < 0)
                   2250:            return ret;
                   2251: 
                   2252:        if (write(fd, cluster, rest_size) < 0)
                   2253:            return -2;
                   2254: 
                   2255:        offset += rest_size;
                   2256:        c = c1;
                   2257:     }
                   2258: 
                   2259:     ftruncate(fd, size);
                   2260:     close(fd);
                   2261: 
                   2262:     return commit_mappings(s, first_cluster, dir_index);
                   2263: }
                   2264: 
                   2265: #ifdef DEBUG
                   2266: /* test, if all mappings point to valid direntries */
                   2267: static void check1(BDRVVVFATState* s)
                   2268: {
                   2269:     int i;
                   2270:     for (i = 0; i < s->mapping.next; i++) {
                   2271:        mapping_t* mapping = array_get(&(s->mapping), i);
                   2272:        if (mapping->mode & MODE_DELETED) {
                   2273:            fprintf(stderr, "deleted\n");
                   2274:            continue;
                   2275:        }
                   2276:        assert(mapping->dir_index >= 0);
                   2277:        assert(mapping->dir_index < s->directory.next);
                   2278:        direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
                   2279:        assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
                   2280:        if (mapping->mode & MODE_DIRECTORY) {
                   2281:            assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
                   2282:            assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
                   2283:        }
                   2284:     }
                   2285: }
                   2286: 
                   2287: /* test, if all direntries have mappings */
                   2288: static void check2(BDRVVVFATState* s)
                   2289: {
                   2290:     int i;
                   2291:     int first_mapping = -1;
                   2292: 
                   2293:     for (i = 0; i < s->directory.next; i++) {
                   2294:        direntry_t* direntry = array_get(&(s->directory), i);
                   2295: 
                   2296:        if (is_short_name(direntry) && begin_of_direntry(direntry)) {
                   2297:            mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
                   2298:            assert(mapping);
                   2299:            assert(mapping->dir_index == i || is_dot(direntry));
                   2300:            assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
                   2301:        }
                   2302: 
                   2303:        if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
                   2304:            /* cluster start */
                   2305:            int j, count = 0;
                   2306: 
                   2307:            for (j = 0; j < s->mapping.next; j++) {
                   2308:                mapping_t* mapping = array_get(&(s->mapping), j);
                   2309:                if (mapping->mode & MODE_DELETED)
                   2310:                    continue;
                   2311:                if (mapping->mode & MODE_DIRECTORY) {
                   2312:                    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
                   2313:                        assert(++count == 1);
                   2314:                        if (mapping->first_mapping_index == -1)
                   2315:                            first_mapping = array_index(&(s->mapping), mapping);
                   2316:                        else
                   2317:                            assert(first_mapping == mapping->first_mapping_index);
                   2318:                        if (mapping->info.dir.parent_mapping_index < 0)
                   2319:                            assert(j == 0);
                   2320:                        else {
                   2321:                            mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
                   2322:                            assert(parent->mode & MODE_DIRECTORY);
                   2323:                            assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
                   2324:                        }
                   2325:                    }
                   2326:                }
                   2327:            }
                   2328:            if (count == 0)
                   2329:                first_mapping = -1;
                   2330:        }
                   2331:     }
                   2332: }
                   2333: #endif
                   2334: 
                   2335: static int handle_renames_and_mkdirs(BDRVVVFATState* s)
                   2336: {
                   2337:     int i;
                   2338: 
                   2339: #ifdef DEBUG
                   2340:     fprintf(stderr, "handle_renames\n");
                   2341:     for (i = 0; i < s->commits.next; i++) {
                   2342:        commit_t* commit = array_get(&(s->commits), i);
                   2343:        fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
                   2344:     }
                   2345: #endif
                   2346: 
                   2347:     for (i = 0; i < s->commits.next;) {
                   2348:        commit_t* commit = array_get(&(s->commits), i);
                   2349:        if (commit->action == ACTION_RENAME) {
                   2350:            mapping_t* mapping = find_mapping_for_cluster(s,
                   2351:                    commit->param.rename.cluster);
                   2352:            char* old_path = mapping->path;
                   2353: 
                   2354:            assert(commit->path);
                   2355:            mapping->path = commit->path;
                   2356:            if (rename(old_path, mapping->path))
                   2357:                return -2;
                   2358: 
                   2359:            if (mapping->mode & MODE_DIRECTORY) {
                   2360:                int l1 = strlen(mapping->path);
                   2361:                int l2 = strlen(old_path);
                   2362:                int diff = l1 - l2;
                   2363:                direntry_t* direntry = array_get(&(s->directory),
                   2364:                        mapping->info.dir.first_dir_index);
                   2365:                uint32_t c = mapping->begin;
                   2366:                int i = 0;
                   2367: 
                   2368:                /* recurse */
                   2369:                while (!fat_eof(s, c)) {
                   2370:                    do {
                   2371:                        direntry_t* d = direntry + i;
                   2372: 
                   2373:                        if (is_file(d) || (is_directory(d) && !is_dot(d))) {
                   2374:                            mapping_t* m = find_mapping_for_cluster(s,
                   2375:                                    begin_of_direntry(d));
                   2376:                            int l = strlen(m->path);
                   2377:                            char* new_path = qemu_malloc(l + diff + 1);
                   2378: 
                   2379:                            assert(!strncmp(m->path, mapping->path, l2));
                   2380: 
                   2381:                             pstrcpy(new_path, l + diff + 1, mapping->path);
                   2382:                             pstrcpy(new_path + l1, l + diff + 1 - l1,
                   2383:                                     m->path + l2);
                   2384: 
                   2385:                            schedule_rename(s, m->begin, new_path);
                   2386:                        }
                   2387:                        i++;
                   2388:                    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
                   2389:                    c = fat_get(s, c);
                   2390:                }
                   2391:            }
                   2392: 
                   2393:            free(old_path);
                   2394:            array_remove(&(s->commits), i);
                   2395:            continue;
                   2396:        } else if (commit->action == ACTION_MKDIR) {
                   2397:            mapping_t* mapping;
                   2398:            int j, parent_path_len;
                   2399: 
                   2400: #ifdef __MINGW32__
                   2401:             if (mkdir(commit->path))
                   2402:                 return -5;
                   2403: #else
                   2404:             if (mkdir(commit->path, 0755))
                   2405:                 return -5;
                   2406: #endif
                   2407: 
                   2408:            mapping = insert_mapping(s, commit->param.mkdir.cluster,
                   2409:                    commit->param.mkdir.cluster + 1);
                   2410:            if (mapping == NULL)
                   2411:                return -6;
                   2412: 
                   2413:            mapping->mode = MODE_DIRECTORY;
                   2414:            mapping->read_only = 0;
                   2415:            mapping->path = commit->path;
                   2416:            j = s->directory.next;
                   2417:            assert(j);
                   2418:            insert_direntries(s, s->directory.next,
                   2419:                    0x10 * s->sectors_per_cluster);
                   2420:            mapping->info.dir.first_dir_index = j;
                   2421: 
                   2422:            parent_path_len = strlen(commit->path)
                   2423:                - strlen(get_basename(commit->path)) - 1;
                   2424:            for (j = 0; j < s->mapping.next; j++) {
                   2425:                mapping_t* m = array_get(&(s->mapping), j);
                   2426:                if (m->first_mapping_index < 0 && m != mapping &&
                   2427:                        !strncmp(m->path, mapping->path, parent_path_len) &&
                   2428:                        strlen(m->path) == parent_path_len)
                   2429:                    break;
                   2430:            }
                   2431:            assert(j < s->mapping.next);
                   2432:            mapping->info.dir.parent_mapping_index = j;
                   2433: 
                   2434:            array_remove(&(s->commits), i);
                   2435:            continue;
                   2436:        }
                   2437: 
                   2438:        i++;
                   2439:     }
                   2440:     return 0;
                   2441: }
                   2442: 
                   2443: /*
                   2444:  * TODO: make sure that the short name is not matching *another* file
                   2445:  */
                   2446: static int handle_commits(BDRVVVFATState* s)
                   2447: {
                   2448:     int i, fail = 0;
                   2449: 
                   2450:     vvfat_close_current_file(s);
                   2451: 
                   2452:     for (i = 0; !fail && i < s->commits.next; i++) {
                   2453:        commit_t* commit = array_get(&(s->commits), i);
                   2454:        switch(commit->action) {
                   2455:        case ACTION_RENAME: case ACTION_MKDIR:
                   2456:            assert(0);
                   2457:            fail = -2;
                   2458:            break;
                   2459:        case ACTION_WRITEOUT: {
                   2460:            direntry_t* entry = array_get(&(s->directory),
                   2461:                    commit->param.writeout.dir_index);
                   2462:            uint32_t begin = begin_of_direntry(entry);
                   2463:            mapping_t* mapping = find_mapping_for_cluster(s, begin);
                   2464: 
                   2465:            assert(mapping);
                   2466:            assert(mapping->begin == begin);
                   2467:            assert(commit->path == NULL);
                   2468: 
                   2469:            if (commit_one_file(s, commit->param.writeout.dir_index,
                   2470:                        commit->param.writeout.modified_offset))
                   2471:                fail = -3;
                   2472: 
                   2473:            break;
                   2474:        }
                   2475:        case ACTION_NEW_FILE: {
                   2476:            int begin = commit->param.new_file.first_cluster;
                   2477:            mapping_t* mapping = find_mapping_for_cluster(s, begin);
                   2478:            direntry_t* entry;
                   2479:            int i;
                   2480: 
                   2481:            /* find direntry */
                   2482:            for (i = 0; i < s->directory.next; i++) {
                   2483:                entry = array_get(&(s->directory), i);
                   2484:                if (is_file(entry) && begin_of_direntry(entry) == begin)
                   2485:                    break;
                   2486:            }
                   2487: 
                   2488:            if (i >= s->directory.next) {
                   2489:                fail = -6;
                   2490:                continue;
                   2491:            }
                   2492: 
                   2493:            /* make sure there exists an initial mapping */
                   2494:            if (mapping && mapping->begin != begin) {
                   2495:                mapping->end = begin;
                   2496:                mapping = NULL;
                   2497:            }
                   2498:            if (mapping == NULL) {
                   2499:                mapping = insert_mapping(s, begin, begin+1);
                   2500:            }
                   2501:            /* most members will be fixed in commit_mappings() */
                   2502:            assert(commit->path);
                   2503:            mapping->path = commit->path;
                   2504:            mapping->read_only = 0;
                   2505:            mapping->mode = MODE_NORMAL;
                   2506:            mapping->info.file.offset = 0;
                   2507: 
                   2508:            if (commit_one_file(s, i, 0))
                   2509:                fail = -7;
                   2510: 
                   2511:            break;
                   2512:        }
                   2513:        default:
                   2514:            assert(0);
                   2515:        }
                   2516:     }
                   2517:     if (i > 0 && array_remove_slice(&(s->commits), 0, i))
                   2518:        return -1;
                   2519:     return fail;
                   2520: }
                   2521: 
                   2522: static int handle_deletes(BDRVVVFATState* s)
                   2523: {
                   2524:     int i, deferred = 1, deleted = 1;
                   2525: 
                   2526:     /* delete files corresponding to mappings marked as deleted */
                   2527:     /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
                   2528:     while (deferred && deleted) {
                   2529:        deferred = 0;
                   2530:        deleted = 0;
                   2531: 
                   2532:        for (i = 1; i < s->mapping.next; i++) {
                   2533:            mapping_t* mapping = array_get(&(s->mapping), i);
                   2534:            if (mapping->mode & MODE_DELETED) {
                   2535:                direntry_t* entry = array_get(&(s->directory),
                   2536:                        mapping->dir_index);
                   2537: 
                   2538:                if (is_free(entry)) {
                   2539:                    /* remove file/directory */
                   2540:                    if (mapping->mode & MODE_DIRECTORY) {
                   2541:                        int j, next_dir_index = s->directory.next,
                   2542:                        first_dir_index = mapping->info.dir.first_dir_index;
                   2543: 
                   2544:                        if (rmdir(mapping->path) < 0) {
                   2545:                            if (errno == ENOTEMPTY) {
                   2546:                                deferred++;
                   2547:                                continue;
                   2548:                            } else
                   2549:                                return -5;
                   2550:                        }
                   2551: 
                   2552:                        for (j = 1; j < s->mapping.next; j++) {
                   2553:                            mapping_t* m = array_get(&(s->mapping), j);
                   2554:                            if (m->mode & MODE_DIRECTORY &&
                   2555:                                    m->info.dir.first_dir_index >
                   2556:                                    first_dir_index &&
                   2557:                                    m->info.dir.first_dir_index <
                   2558:                                    next_dir_index)
                   2559:                                next_dir_index =
                   2560:                                    m->info.dir.first_dir_index;
                   2561:                        }
                   2562:                        remove_direntries(s, first_dir_index,
                   2563:                                next_dir_index - first_dir_index);
                   2564: 
                   2565:                        deleted++;
                   2566:                    }
                   2567:                } else {
                   2568:                    if (unlink(mapping->path))
                   2569:                        return -4;
                   2570:                    deleted++;
                   2571:                }
                   2572:                DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
                   2573:                remove_mapping(s, i);
                   2574:            }
                   2575:        }
                   2576:     }
                   2577: 
                   2578:     return 0;
                   2579: }
                   2580: 
                   2581: /*
                   2582:  * synchronize mapping with new state:
                   2583:  *
                   2584:  * - copy FAT (with bdrv_read)
                   2585:  * - mark all filenames corresponding to mappings as deleted
                   2586:  * - recurse direntries from root (using bs->bdrv_read)
                   2587:  * - delete files corresponding to mappings marked as deleted
                   2588:  */
                   2589: static int do_commit(BDRVVVFATState* s)
                   2590: {
                   2591:     int ret = 0;
                   2592: 
                   2593:     /* the real meat are the commits. Nothing to do? Move along! */
                   2594:     if (s->commits.next == 0)
                   2595:        return 0;
                   2596: 
                   2597:     vvfat_close_current_file(s);
                   2598: 
                   2599:     ret = handle_renames_and_mkdirs(s);
                   2600:     if (ret) {
                   2601:        fprintf(stderr, "Error handling renames (%d)\n", ret);
                   2602:        assert(0);
                   2603:        return ret;
                   2604:     }
                   2605: 
                   2606:     /* copy FAT (with bdrv_read) */
                   2607:     memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
                   2608: 
                   2609:     /* recurse direntries from root (using bs->bdrv_read) */
                   2610:     ret = commit_direntries(s, 0, -1);
                   2611:     if (ret) {
                   2612:        fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
                   2613:        assert(0);
                   2614:        return ret;
                   2615:     }
                   2616: 
                   2617:     ret = handle_commits(s);
                   2618:     if (ret) {
                   2619:        fprintf(stderr, "Error handling commits (%d)\n", ret);
                   2620:        assert(0);
                   2621:        return ret;
                   2622:     }
                   2623: 
                   2624:     ret = handle_deletes(s);
                   2625:     if (ret) {
                   2626:        fprintf(stderr, "Error deleting\n");
                   2627:         assert(0);
                   2628:        return ret;
                   2629:     }
                   2630: 
                   2631:     s->qcow->drv->bdrv_make_empty(s->qcow);
                   2632: 
                   2633:     memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
                   2634: 
                   2635: DLOG(checkpoint());
                   2636:     return 0;
                   2637: }
                   2638: 
                   2639: static int try_commit(BDRVVVFATState* s)
                   2640: {
                   2641:     vvfat_close_current_file(s);
                   2642: DLOG(checkpoint());
                   2643:     if(!is_consistent(s))
                   2644:        return -1;
                   2645:     return do_commit(s);
                   2646: }
                   2647: 
                   2648: static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
                   2649:                     const uint8_t *buf, int nb_sectors)
                   2650: {
                   2651:     BDRVVVFATState *s = bs->opaque;
                   2652:     int i, ret;
                   2653: 
                   2654: DLOG(checkpoint());
                   2655: 
                   2656:     vvfat_close_current_file(s);
                   2657: 
                   2658:     /*
                   2659:      * Some sanity checks:
                   2660:      * - do not allow writing to the boot sector
                   2661:      * - do not allow to write non-ASCII filenames
                   2662:      */
                   2663: 
                   2664:     if (sector_num < s->first_sectors_number)
                   2665:        return -1;
                   2666: 
                   2667:     for (i = sector2cluster(s, sector_num);
                   2668:            i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
                   2669:        mapping_t* mapping = find_mapping_for_cluster(s, i);
                   2670:        if (mapping) {
                   2671:            if (mapping->read_only) {
                   2672:                fprintf(stderr, "Tried to write to write-protected file %s\n",
                   2673:                        mapping->path);
                   2674:                return -1;
                   2675:            }
                   2676: 
                   2677:            if (mapping->mode & MODE_DIRECTORY) {
                   2678:                int begin = cluster2sector(s, i);
                   2679:                int end = begin + s->sectors_per_cluster, k;
                   2680:                int dir_index;
                   2681:                const direntry_t* direntries;
                   2682:                long_file_name lfn;
                   2683: 
                   2684:                lfn_init(&lfn);
                   2685: 
                   2686:                if (begin < sector_num)
                   2687:                    begin = sector_num;
                   2688:                if (end > sector_num + nb_sectors)
                   2689:                    end = sector_num + nb_sectors;
                   2690:                dir_index  = mapping->dir_index +
                   2691:                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
                   2692:                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
                   2693: 
                   2694:                for (k = 0; k < (end - begin) * 0x10; k++) {
                   2695:                    /* do not allow non-ASCII filenames */
                   2696:                    if (parse_long_name(&lfn, direntries + k) < 0) {
                   2697:                        fprintf(stderr, "Warning: non-ASCII filename\n");
                   2698:                        return -1;
                   2699:                    }
                   2700:                    /* no access to the direntry of a read-only file */
                   2701:                    else if (is_short_name(direntries+k) &&
                   2702:                            (direntries[k].attributes & 1)) {
                   2703:                        if (memcmp(direntries + k,
                   2704:                                    array_get(&(s->directory), dir_index + k),
                   2705:                                    sizeof(direntry_t))) {
                   2706:                            fprintf(stderr, "Warning: tried to write to write-protected file\n");
                   2707:                            return -1;
                   2708:                        }
                   2709:                    }
                   2710:                }
                   2711:            }
                   2712:            i = mapping->end;
                   2713:        } else
                   2714:            i++;
                   2715:     }
                   2716: 
                   2717:     /*
                   2718:      * Use qcow backend. Commit later.
                   2719:      */
                   2720: DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
                   2721:     ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
                   2722:     if (ret < 0) {
                   2723:        fprintf(stderr, "Error writing to qcow backend\n");
                   2724:        return ret;
                   2725:     }
                   2726: 
                   2727:     for (i = sector2cluster(s, sector_num);
                   2728:            i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
                   2729:        if (i >= 0)
                   2730:            s->used_clusters[i] |= USED_ALLOCATED;
                   2731: 
                   2732: DLOG(checkpoint());
                   2733:     /* TODO: add timeout */
                   2734:     try_commit(s);
                   2735: 
                   2736: DLOG(checkpoint());
                   2737:     return 0;
                   2738: }
                   2739: 
                   2740: static int vvfat_is_allocated(BlockDriverState *bs,
                   2741:        int64_t sector_num, int nb_sectors, int* n)
                   2742: {
                   2743:     BDRVVVFATState* s = bs->opaque;
                   2744:     *n = s->sector_count - sector_num;
                   2745:     if (*n > nb_sectors)
                   2746:        *n = nb_sectors;
                   2747:     else if (*n < 0)
                   2748:        return 0;
                   2749:     return 1;
                   2750: }
                   2751: 
                   2752: static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
                   2753:        const uint8_t* buffer, int nb_sectors) {
                   2754:     BDRVVVFATState* s = bs->opaque;
                   2755:     return try_commit(s);
                   2756: }
                   2757: 
                   2758: static void write_target_close(BlockDriverState *bs) {
                   2759:     BDRVVVFATState* s = bs->opaque;
                   2760:     bdrv_delete(s->qcow);
                   2761:     free(s->qcow_filename);
                   2762: }
                   2763: 
                   2764: static BlockDriver vvfat_write_target = {
                   2765:     .format_name        = "vvfat_write_target",
                   2766:     .bdrv_write         = write_target_commit,
                   2767:     .bdrv_close         = write_target_close,
                   2768: };
                   2769: 
                   2770: static int enable_write_target(BDRVVVFATState *s)
                   2771: {
                   2772:     BlockDriver *bdrv_qcow;
                   2773:     QEMUOptionParameter *options;
                   2774:     int size = sector2cluster(s, s->sector_count);
                   2775:     s->used_clusters = calloc(size, 1);
                   2776: 
                   2777:     array_init(&(s->commits), sizeof(commit_t));
                   2778: 
                   2779:     s->qcow_filename = qemu_malloc(1024);
                   2780:     get_tmp_filename(s->qcow_filename, 1024);
                   2781: 
                   2782:     bdrv_qcow = bdrv_find_format("qcow");
                   2783:     options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
                   2784:     set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
                   2785:     set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
                   2786: 
                   2787:     if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
                   2788:        return -1;
                   2789:     s->qcow = bdrv_new("");
                   2790:     if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
                   2791:        return -1;
                   2792: 
                   2793: #ifndef _WIN32
                   2794:     unlink(s->qcow_filename);
                   2795: #endif
                   2796: 
                   2797:     s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
                   2798:     s->bs->backing_hd->drv = &vvfat_write_target;
                   2799:     s->bs->backing_hd->opaque = s;
                   2800: 
                   2801:     return 0;
                   2802: }
                   2803: 
                   2804: static void vvfat_close(BlockDriverState *bs)
                   2805: {
                   2806:     BDRVVVFATState *s = bs->opaque;
                   2807: 
                   2808:     vvfat_close_current_file(s);
                   2809:     array_free(&(s->fat));
                   2810:     array_free(&(s->directory));
                   2811:     array_free(&(s->mapping));
                   2812:     if(s->cluster_buffer)
                   2813:         free(s->cluster_buffer);
                   2814: }
                   2815: 
                   2816: static BlockDriver bdrv_vvfat = {
                   2817:     .format_name       = "vvfat",
                   2818:     .instance_size     = sizeof(BDRVVVFATState),
                   2819:     .bdrv_open         = vvfat_open,
                   2820:     .bdrv_read         = vvfat_read,
                   2821:     .bdrv_write                = vvfat_write,
                   2822:     .bdrv_close                = vvfat_close,
                   2823:     .bdrv_is_allocated = vvfat_is_allocated,
                   2824:     .protocol_name     = "fat",
                   2825: };
                   2826: 
                   2827: static void bdrv_vvfat_init(void)
                   2828: {
                   2829:     bdrv_register(&bdrv_vvfat);
                   2830: }
                   2831: 
                   2832: block_init(bdrv_vvfat_init);
                   2833: 
                   2834: #ifdef DEBUG
                   2835: static void checkpoint(void) {
                   2836:     assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
                   2837:     check1(vvv);
                   2838:     check2(vvv);
                   2839:     assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
                   2840: #if 0
                   2841:     if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
                   2842:        fprintf(stderr, "Nonono!\n");
                   2843:     mapping_t* mapping;
                   2844:     direntry_t* direntry;
                   2845:     assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
                   2846:     assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
                   2847:     if (vvv->mapping.next<47)
                   2848:        return;
                   2849:     assert((mapping = array_get(&(vvv->mapping), 47)));
                   2850:     assert(mapping->dir_index < vvv->directory.next);
                   2851:     direntry = array_get(&(vvv->directory), mapping->dir_index);
                   2852:     assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
                   2853: #endif
                   2854:     return;
                   2855:     /* avoid compiler warnings: */
                   2856:     hexdump(NULL, 100);
                   2857:     remove_mapping(vvv, NULL);
                   2858:     print_mapping(NULL);
                   2859:     print_direntry(NULL);
                   2860: }
                   2861: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.