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

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 */
1.1.1.4 ! root      871:        memcpy(entry->name,"QEMU VVF",8);
        !           872:        memcpy(entry->extension,"AT ",3);
1.1       root      873:     }
                    874: 
                    875:     /* Now build FAT, and write back information into directory */
                    876:     init_fat(s);
                    877: 
                    878:     s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
                    879:     s->cluster_count=sector2cluster(s, s->sector_count);
                    880: 
                    881:     mapping = array_get_next(&(s->mapping));
                    882:     mapping->begin = 0;
                    883:     mapping->dir_index = 0;
                    884:     mapping->info.dir.parent_mapping_index = -1;
                    885:     mapping->first_mapping_index = -1;
1.1.1.3   root      886:     mapping->path = qemu_strdup(dirname);
1.1       root      887:     i = strlen(mapping->path);
                    888:     if (i > 0 && mapping->path[i - 1] == '/')
                    889:        mapping->path[i - 1] = '\0';
                    890:     mapping->mode = MODE_DIRECTORY;
                    891:     mapping->read_only = 0;
                    892:     s->path = mapping->path;
                    893: 
                    894:     for (i = 0, cluster = 0; i < s->mapping.next; i++) {
                    895:        /* MS-DOS expects the FAT to be 0 for the root directory
                    896:         * (except for the media byte). */
                    897:        /* LATER TODO: still true for FAT32? */
                    898:        int fix_fat = (i != 0);
                    899:        mapping = array_get(&(s->mapping), i);
                    900: 
                    901:         if (mapping->mode & MODE_DIRECTORY) {
                    902:            mapping->begin = cluster;
                    903:            if(read_directory(s, i)) {
                    904:                fprintf(stderr, "Could not read directory %s\n",
                    905:                        mapping->path);
                    906:                return -1;
                    907:            }
                    908:            mapping = array_get(&(s->mapping), i);
                    909:        } else {
                    910:            assert(mapping->mode == MODE_UNDEFINED);
                    911:            mapping->mode=MODE_NORMAL;
                    912:            mapping->begin = cluster;
                    913:            if (mapping->end > 0) {
                    914:                direntry_t* direntry = array_get(&(s->directory),
                    915:                        mapping->dir_index);
                    916: 
                    917:                mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
                    918:                set_begin_of_direntry(direntry, mapping->begin);
                    919:            } else {
                    920:                mapping->end = cluster + 1;
                    921:                fix_fat = 0;
                    922:            }
                    923:        }
                    924: 
                    925:        assert(mapping->begin < mapping->end);
                    926: 
                    927:        /* next free cluster */
                    928:        cluster = mapping->end;
                    929: 
                    930:        if(cluster > s->cluster_count) {
                    931:            fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
                    932:                    s->fat_type,
                    933:                    s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
                    934:                                                                : "2.88 MB"
                    935:                                      : "504MB");
                    936:            return -EINVAL;
                    937:        }
                    938: 
                    939:        /* fix fat for entry */
                    940:        if (fix_fat) {
                    941:            int j;
                    942:            for(j = mapping->begin; j < mapping->end - 1; j++)
                    943:                fat_set(s, j, j+1);
                    944:            fat_set(s, mapping->end - 1, s->max_fat_value);
                    945:        }
                    946:     }
                    947: 
                    948:     mapping = array_get(&(s->mapping), 0);
                    949:     s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
                    950:     s->last_cluster_of_root_directory = mapping->end;
                    951: 
                    952:     /* the FAT signature */
                    953:     fat_set(s,0,s->max_fat_value);
                    954:     fat_set(s,1,s->max_fat_value);
                    955: 
                    956:     s->current_mapping = NULL;
                    957: 
                    958:     bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
                    959:     bootsector->jump[0]=0xeb;
                    960:     bootsector->jump[1]=0x3e;
                    961:     bootsector->jump[2]=0x90;
                    962:     memcpy(bootsector->name,"QEMU    ",8);
                    963:     bootsector->sector_size=cpu_to_le16(0x200);
                    964:     bootsector->sectors_per_cluster=s->sectors_per_cluster;
                    965:     bootsector->reserved_sectors=cpu_to_le16(1);
                    966:     bootsector->number_of_fats=0x2; /* number of FATs */
                    967:     bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
                    968:     bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
                    969:     bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
                    970:     s->fat.pointer[0] = bootsector->media_type;
                    971:     bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
                    972:     bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
                    973:     bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
                    974:     bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
                    975:     bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
                    976: 
                    977:     /* LATER TODO: if FAT32, this is wrong */
                    978:     bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
                    979:     bootsector->u.fat16.current_head=0;
                    980:     bootsector->u.fat16.signature=0x29;
                    981:     bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
                    982: 
                    983:     memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
                    984:     memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
                    985:     bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
                    986: 
                    987:     return 0;
                    988: }
                    989: 
                    990: #ifdef DEBUG
                    991: static BDRVVVFATState *vvv = NULL;
                    992: #endif
                    993: 
                    994: static int enable_write_target(BDRVVVFATState *s);
                    995: static int is_consistent(BDRVVVFATState *s);
                    996: 
                    997: static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
                    998: {
                    999:     BDRVVVFATState *s = bs->opaque;
                   1000:     int floppy = 0;
                   1001:     int i;
                   1002: 
                   1003: #ifdef DEBUG
                   1004:     vvv = s;
                   1005: #endif
                   1006: 
                   1007: DLOG(if (stderr == NULL) {
                   1008:     stderr = fopen("vvfat.log", "a");
                   1009:     setbuf(stderr, NULL);
                   1010: })
                   1011: 
                   1012:     s->bs = bs;
                   1013: 
                   1014:     s->fat_type=16;
                   1015:     /* LATER TODO: if FAT32, adjust */
                   1016:     s->sectors_per_cluster=0x10;
                   1017:     /* 504MB disk*/
                   1018:     bs->cyls=1024; bs->heads=16; bs->secs=63;
                   1019: 
                   1020:     s->current_cluster=0xffffffff;
                   1021: 
                   1022:     s->first_sectors_number=0x40;
                   1023:     /* read only is the default for safety */
                   1024:     bs->read_only = 1;
                   1025:     s->qcow = s->write_target = NULL;
                   1026:     s->qcow_filename = NULL;
                   1027:     s->fat2 = NULL;
                   1028:     s->downcase_short_names = 1;
                   1029: 
                   1030:     if (!strstart(dirname, "fat:", NULL))
                   1031:        return -1;
                   1032: 
                   1033:     if (strstr(dirname, ":floppy:")) {
                   1034:        floppy = 1;
                   1035:        s->fat_type = 12;
                   1036:        s->first_sectors_number = 1;
                   1037:        s->sectors_per_cluster=2;
                   1038:        bs->cyls = 80; bs->heads = 2; bs->secs = 36;
                   1039:     }
                   1040: 
                   1041:     s->sector_count=bs->cyls*bs->heads*bs->secs;
                   1042: 
                   1043:     if (strstr(dirname, ":32:")) {
                   1044:        fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
                   1045:        s->fat_type = 32;
                   1046:     } else if (strstr(dirname, ":16:")) {
                   1047:        s->fat_type = 16;
                   1048:     } else if (strstr(dirname, ":12:")) {
                   1049:        s->fat_type = 12;
                   1050:        s->sector_count=2880;
                   1051:     }
                   1052: 
                   1053:     if (strstr(dirname, ":rw:")) {
                   1054:        if (enable_write_target(s))
                   1055:            return -1;
                   1056:        bs->read_only = 0;
                   1057:     }
                   1058: 
                   1059:     i = strrchr(dirname, ':') - dirname;
                   1060:     assert(i >= 3);
                   1061:     if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
                   1062:        /* workaround for DOS drive names */
                   1063:        dirname += i-1;
                   1064:     else
                   1065:        dirname += i+1;
                   1066: 
                   1067:     bs->total_sectors=bs->cyls*bs->heads*bs->secs;
                   1068: 
                   1069:     if(init_directories(s, dirname))
                   1070:        return -1;
                   1071: 
                   1072:     s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
                   1073: 
                   1074:     if(s->first_sectors_number==0x40)
                   1075:        init_mbr(s);
                   1076: 
                   1077:     /* for some reason or other, MS-DOS does not like to know about CHS... */
                   1078:     if (floppy)
                   1079:        bs->heads = bs->cyls = bs->secs = 0;
                   1080: 
                   1081:     //    assert(is_consistent(s));
                   1082:     return 0;
                   1083: }
                   1084: 
                   1085: static inline void vvfat_close_current_file(BDRVVVFATState *s)
                   1086: {
                   1087:     if(s->current_mapping) {
                   1088:        s->current_mapping = NULL;
                   1089:        if (s->current_fd) {
                   1090:                close(s->current_fd);
                   1091:                s->current_fd = 0;
                   1092:        }
                   1093:     }
                   1094:     s->current_cluster = -1;
                   1095: }
                   1096: 
                   1097: /* mappings between index1 and index2-1 are supposed to be ordered
                   1098:  * return value is the index of the last mapping for which end>cluster_num
                   1099:  */
                   1100: static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
                   1101: {
                   1102:     int index3=index1+1;
                   1103:     while(1) {
                   1104:        mapping_t* mapping;
                   1105:        index3=(index1+index2)/2;
                   1106:        mapping=array_get(&(s->mapping),index3);
                   1107:        assert(mapping->begin < mapping->end);
                   1108:        if(mapping->begin>=cluster_num) {
                   1109:            assert(index2!=index3 || index2==0);
                   1110:            if(index2==index3)
                   1111:                return index1;
                   1112:            index2=index3;
                   1113:        } else {
                   1114:            if(index1==index3)
                   1115:                return mapping->end<=cluster_num ? index2 : index1;
                   1116:            index1=index3;
                   1117:        }
                   1118:        assert(index1<=index2);
                   1119:        DLOG(mapping=array_get(&(s->mapping),index1);
                   1120:        assert(mapping->begin<=cluster_num);
                   1121:        assert(index2 >= s->mapping.next ||
                   1122:                ((mapping = array_get(&(s->mapping),index2)) &&
                   1123:                mapping->end>cluster_num)));
                   1124:     }
                   1125: }
                   1126: 
                   1127: static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
                   1128: {
                   1129:     int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
                   1130:     mapping_t* mapping;
                   1131:     if(index>=s->mapping.next)
                   1132:         return NULL;
                   1133:     mapping=array_get(&(s->mapping),index);
                   1134:     if(mapping->begin>cluster_num)
                   1135:         return NULL;
                   1136:     assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
                   1137:     return mapping;
                   1138: }
                   1139: 
                   1140: /*
                   1141:  * This function simply compares path == mapping->path. Since the mappings
                   1142:  * are sorted by cluster, this is expensive: O(n).
                   1143:  */
                   1144: static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
                   1145:        const char* path)
                   1146: {
                   1147:     int i;
                   1148: 
                   1149:     for (i = 0; i < s->mapping.next; i++) {
                   1150:        mapping_t* mapping = array_get(&(s->mapping), i);
                   1151:        if (mapping->first_mapping_index < 0 &&
                   1152:                !strcmp(path, mapping->path))
                   1153:            return mapping;
                   1154:     }
                   1155: 
                   1156:     return NULL;
                   1157: }
                   1158: 
                   1159: static int open_file(BDRVVVFATState* s,mapping_t* mapping)
                   1160: {
                   1161:     if(!mapping)
                   1162:        return -1;
                   1163:     if(!s->current_mapping ||
                   1164:            strcmp(s->current_mapping->path,mapping->path)) {
                   1165:        /* open file */
                   1166:        int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
                   1167:        if(fd<0)
                   1168:            return -1;
                   1169:        vvfat_close_current_file(s);
                   1170:        s->current_fd = fd;
                   1171:        s->current_mapping = mapping;
                   1172:     }
                   1173:     return 0;
                   1174: }
                   1175: 
                   1176: static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
                   1177: {
                   1178:     if(s->current_cluster != cluster_num) {
                   1179:        int result=0;
                   1180:        off_t offset;
                   1181:        assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
                   1182:        if(!s->current_mapping
                   1183:                || s->current_mapping->begin>cluster_num
                   1184:                || s->current_mapping->end<=cluster_num) {
                   1185:            /* binary search of mappings for file */
                   1186:            mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
                   1187: 
                   1188:            assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
                   1189: 
                   1190:            if (mapping && mapping->mode & MODE_DIRECTORY) {
                   1191:                vvfat_close_current_file(s);
                   1192:                s->current_mapping = mapping;
                   1193: read_cluster_directory:
                   1194:                offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
                   1195:                s->cluster = (unsigned char*)s->directory.pointer+offset
                   1196:                        + 0x20*s->current_mapping->info.dir.first_dir_index;
                   1197:                assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
                   1198:                assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
                   1199:                s->current_cluster = cluster_num;
                   1200:                return 0;
                   1201:            }
                   1202: 
                   1203:            if(open_file(s,mapping))
                   1204:                return -2;
                   1205:        } else if (s->current_mapping->mode & MODE_DIRECTORY)
                   1206:            goto read_cluster_directory;
                   1207: 
                   1208:        assert(s->current_fd);
                   1209: 
                   1210:        offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
                   1211:        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
                   1212:            return -3;
                   1213:        s->cluster=s->cluster_buffer;
                   1214:        result=read(s->current_fd,s->cluster,s->cluster_size);
                   1215:        if(result<0) {
                   1216:            s->current_cluster = -1;
                   1217:            return -1;
                   1218:        }
                   1219:        s->current_cluster = cluster_num;
                   1220:     }
                   1221:     return 0;
                   1222: }
                   1223: 
                   1224: #ifdef DEBUG
                   1225: static void hexdump(const void* address, uint32_t len)
                   1226: {
                   1227:     const unsigned char* p = address;
                   1228:     int i, j;
                   1229: 
                   1230:     for (i = 0; i < len; i += 16) {
                   1231:        for (j = 0; j < 16 && i + j < len; j++)
                   1232:            fprintf(stderr, "%02x ", p[i + j]);
                   1233:        for (; j < 16; j++)
                   1234:            fprintf(stderr, "   ");
                   1235:        fprintf(stderr, " ");
                   1236:        for (j = 0; j < 16 && i + j < len; j++)
                   1237:            fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
                   1238:        fprintf(stderr, "\n");
                   1239:     }
                   1240: }
                   1241: 
                   1242: static void print_direntry(const direntry_t* direntry)
                   1243: {
                   1244:     int j = 0;
                   1245:     char buffer[1024];
                   1246: 
                   1247:     fprintf(stderr, "direntry 0x%x: ", (int)direntry);
                   1248:     if(!direntry)
                   1249:        return;
                   1250:     if(is_long_name(direntry)) {
                   1251:        unsigned char* c=(unsigned char*)direntry;
                   1252:        int i;
                   1253:        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
                   1254: #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
                   1255:            ADD_CHAR(c[i]);
                   1256:        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
                   1257:            ADD_CHAR(c[i]);
                   1258:        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
                   1259:            ADD_CHAR(c[i]);
                   1260:        buffer[j] = 0;
                   1261:        fprintf(stderr, "%s\n", buffer);
                   1262:     } else {
                   1263:        int i;
                   1264:        for(i=0;i<11;i++)
                   1265:            ADD_CHAR(direntry->name[i]);
                   1266:        buffer[j] = 0;
                   1267:        fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
                   1268:                buffer,
                   1269:                direntry->attributes,
                   1270:                begin_of_direntry(direntry),le32_to_cpu(direntry->size));
                   1271:     }
                   1272: }
                   1273: 
                   1274: static void print_mapping(const mapping_t* mapping)
                   1275: {
                   1276:     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);
                   1277:     if (mapping->mode & MODE_DIRECTORY)
                   1278:        fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
                   1279:     else
                   1280:        fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
                   1281: }
                   1282: #endif
                   1283: 
                   1284: static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
                   1285:                     uint8_t *buf, int nb_sectors)
                   1286: {
                   1287:     BDRVVVFATState *s = bs->opaque;
                   1288:     int i;
                   1289: 
                   1290:     for(i=0;i<nb_sectors;i++,sector_num++) {
                   1291:        if (sector_num >= s->sector_count)
                   1292:           return -1;
                   1293:        if (s->qcow) {
                   1294:            int n;
                   1295:            if (s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1296:                        sector_num, nb_sectors-i, &n)) {
                   1297: DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
                   1298:                if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
                   1299:                    return -1;
                   1300:                i += n - 1;
                   1301:                sector_num += n - 1;
                   1302:                continue;
                   1303:            }
                   1304: DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
                   1305:        }
                   1306:        if(sector_num<s->faked_sectors) {
                   1307:            if(sector_num<s->first_sectors_number)
                   1308:                memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
                   1309:            else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
                   1310:                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
                   1311:            else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
                   1312:                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
                   1313:        } else {
                   1314:            uint32_t sector=sector_num-s->faked_sectors,
                   1315:            sector_offset_in_cluster=(sector%s->sectors_per_cluster),
                   1316:            cluster_num=sector/s->sectors_per_cluster;
                   1317:            if(read_cluster(s, cluster_num) != 0) {
                   1318:                /* LATER TODO: strict: return -1; */
                   1319:                memset(buf+i*0x200,0,0x200);
                   1320:                continue;
                   1321:            }
                   1322:            memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
                   1323:        }
                   1324:     }
                   1325:     return 0;
                   1326: }
                   1327: 
                   1328: /* LATER TODO: statify all functions */
                   1329: 
                   1330: /*
                   1331:  * Idea of the write support (use snapshot):
                   1332:  *
                   1333:  * 1. check if all data is consistent, recording renames, modifications,
                   1334:  *    new files and directories (in s->commits).
                   1335:  *
                   1336:  * 2. if the data is not consistent, stop committing
                   1337:  *
                   1338:  * 3. handle renames, and create new files and directories (do not yet
                   1339:  *    write their contents)
                   1340:  *
                   1341:  * 4. walk the directories, fixing the mapping and direntries, and marking
                   1342:  *    the handled mappings as not deleted
                   1343:  *
                   1344:  * 5. commit the contents of the files
                   1345:  *
                   1346:  * 6. handle deleted files and directories
                   1347:  *
                   1348:  */
                   1349: 
                   1350: typedef struct commit_t {
                   1351:     char* path;
                   1352:     union {
                   1353:        struct { uint32_t cluster; } rename;
                   1354:        struct { int dir_index; uint32_t modified_offset; } writeout;
                   1355:        struct { uint32_t first_cluster; } new_file;
                   1356:        struct { uint32_t cluster; } mkdir;
                   1357:     } param;
                   1358:     /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
                   1359:     enum {
                   1360:        ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
                   1361:     } action;
                   1362: } commit_t;
                   1363: 
                   1364: static void clear_commits(BDRVVVFATState* s)
                   1365: {
                   1366:     int i;
                   1367: DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
                   1368:     for (i = 0; i < s->commits.next; i++) {
                   1369:        commit_t* commit = array_get(&(s->commits), i);
                   1370:        assert(commit->path || commit->action == ACTION_WRITEOUT);
                   1371:        if (commit->action != ACTION_WRITEOUT) {
                   1372:            assert(commit->path);
                   1373:            free(commit->path);
                   1374:        } else
                   1375:            assert(commit->path == NULL);
                   1376:     }
                   1377:     s->commits.next = 0;
                   1378: }
                   1379: 
                   1380: static void schedule_rename(BDRVVVFATState* s,
                   1381:        uint32_t cluster, char* new_path)
                   1382: {
                   1383:     commit_t* commit = array_get_next(&(s->commits));
                   1384:     commit->path = new_path;
                   1385:     commit->param.rename.cluster = cluster;
                   1386:     commit->action = ACTION_RENAME;
                   1387: }
                   1388: 
                   1389: static void schedule_writeout(BDRVVVFATState* s,
                   1390:        int dir_index, uint32_t modified_offset)
                   1391: {
                   1392:     commit_t* commit = array_get_next(&(s->commits));
                   1393:     commit->path = NULL;
                   1394:     commit->param.writeout.dir_index = dir_index;
                   1395:     commit->param.writeout.modified_offset = modified_offset;
                   1396:     commit->action = ACTION_WRITEOUT;
                   1397: }
                   1398: 
                   1399: static void schedule_new_file(BDRVVVFATState* s,
                   1400:        char* path, uint32_t first_cluster)
                   1401: {
                   1402:     commit_t* commit = array_get_next(&(s->commits));
                   1403:     commit->path = path;
                   1404:     commit->param.new_file.first_cluster = first_cluster;
                   1405:     commit->action = ACTION_NEW_FILE;
                   1406: }
                   1407: 
                   1408: static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
                   1409: {
                   1410:     commit_t* commit = array_get_next(&(s->commits));
                   1411:     commit->path = path;
                   1412:     commit->param.mkdir.cluster = cluster;
                   1413:     commit->action = ACTION_MKDIR;
                   1414: }
                   1415: 
                   1416: typedef struct {
                   1417:     /*
                   1418:      * Since the sequence number is at most 0x3f, and the filename
                   1419:      * length is at most 13 times the sequence number, the maximal
                   1420:      * filename length is 0x3f * 13 bytes.
                   1421:      */
                   1422:     unsigned char name[0x3f * 13 + 1];
                   1423:     int checksum, len;
                   1424:     int sequence_number;
                   1425: } long_file_name;
                   1426: 
                   1427: static void lfn_init(long_file_name* lfn)
                   1428: {
                   1429:    lfn->sequence_number = lfn->len = 0;
                   1430:    lfn->checksum = 0x100;
                   1431: }
                   1432: 
                   1433: /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
                   1434: static int parse_long_name(long_file_name* lfn,
                   1435:        const direntry_t* direntry)
                   1436: {
                   1437:     int i, j, offset;
                   1438:     const unsigned char* pointer = (const unsigned char*)direntry;
                   1439: 
                   1440:     if (!is_long_name(direntry))
                   1441:        return 1;
                   1442: 
                   1443:     if (pointer[0] & 0x40) {
                   1444:        lfn->sequence_number = pointer[0] & 0x3f;
                   1445:        lfn->checksum = pointer[13];
                   1446:        lfn->name[0] = 0;
                   1447:        lfn->name[lfn->sequence_number * 13] = 0;
                   1448:     } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
                   1449:        return -1;
                   1450:     else if (pointer[13] != lfn->checksum)
                   1451:        return -2;
                   1452:     else if (pointer[12] || pointer[26] || pointer[27])
                   1453:        return -3;
                   1454: 
                   1455:     offset = 13 * (lfn->sequence_number - 1);
                   1456:     for (i = 0, j = 1; i < 13; i++, j+=2) {
                   1457:        if (j == 11)
                   1458:            j = 14;
                   1459:        else if (j == 26)
                   1460:            j = 28;
                   1461: 
                   1462:        if (pointer[j+1] == 0)
                   1463:            lfn->name[offset + i] = pointer[j];
                   1464:        else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
                   1465:            return -4;
                   1466:        else
                   1467:            lfn->name[offset + i] = 0;
                   1468:     }
                   1469: 
                   1470:     if (pointer[0] & 0x40)
                   1471:        lfn->len = offset + strlen((char*)lfn->name + offset);
                   1472: 
                   1473:     return 0;
                   1474: }
                   1475: 
                   1476: /* returns 0 if successful, >0 if no short_name, and <0 on error */
                   1477: static int parse_short_name(BDRVVVFATState* s,
                   1478:        long_file_name* lfn, direntry_t* direntry)
                   1479: {
                   1480:     int i, j;
                   1481: 
                   1482:     if (!is_short_name(direntry))
                   1483:        return 1;
                   1484: 
                   1485:     for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
                   1486:     for (i = 0; i <= j; i++) {
                   1487:        if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
                   1488:            return -1;
                   1489:        else if (s->downcase_short_names)
                   1490:            lfn->name[i] = qemu_tolower(direntry->name[i]);
                   1491:        else
                   1492:            lfn->name[i] = direntry->name[i];
                   1493:     }
                   1494: 
                   1495:     for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
                   1496:     if (j >= 0) {
                   1497:        lfn->name[i++] = '.';
                   1498:        lfn->name[i + j + 1] = '\0';
                   1499:        for (;j >= 0; j--) {
                   1500:            if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
                   1501:                return -2;
                   1502:            else if (s->downcase_short_names)
                   1503:                lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
                   1504:            else
                   1505:                lfn->name[i + j] = direntry->extension[j];
                   1506:        }
                   1507:     } else
                   1508:        lfn->name[i + j + 1] = '\0';
                   1509: 
                   1510:     lfn->len = strlen((char*)lfn->name);
                   1511: 
                   1512:     return 0;
                   1513: }
                   1514: 
                   1515: static inline uint32_t modified_fat_get(BDRVVVFATState* s,
                   1516:        unsigned int cluster)
                   1517: {
                   1518:     if (cluster < s->last_cluster_of_root_directory) {
                   1519:        if (cluster + 1 == s->last_cluster_of_root_directory)
                   1520:            return s->max_fat_value;
                   1521:        else
                   1522:            return cluster + 1;
                   1523:     }
                   1524: 
                   1525:     if (s->fat_type==32) {
                   1526:         uint32_t* entry=((uint32_t*)s->fat2)+cluster;
                   1527:         return le32_to_cpu(*entry);
                   1528:     } else if (s->fat_type==16) {
                   1529:         uint16_t* entry=((uint16_t*)s->fat2)+cluster;
                   1530:         return le16_to_cpu(*entry);
                   1531:     } else {
                   1532:         const uint8_t* x=s->fat2+cluster*3/2;
                   1533:         return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
                   1534:     }
                   1535: }
                   1536: 
                   1537: static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
                   1538: {
                   1539:     int was_modified = 0;
                   1540:     int i, dummy;
                   1541: 
                   1542:     if (s->qcow == NULL)
                   1543:        return 0;
                   1544: 
                   1545:     for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
                   1546:        was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1547:                cluster2sector(s, cluster_num) + i, 1, &dummy);
                   1548: 
                   1549:     return was_modified;
                   1550: }
                   1551: 
                   1552: static const char* get_basename(const char* path)
                   1553: {
                   1554:     char* basename = strrchr(path, '/');
                   1555:     if (basename == NULL)
                   1556:        return path;
                   1557:     else
                   1558:        return basename + 1; /* strip '/' */
                   1559: }
                   1560: 
                   1561: /*
                   1562:  * The array s->used_clusters holds the states of the clusters. If it is
                   1563:  * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
                   1564:  * was modified, bit 3 is set.
                   1565:  * If any cluster is allocated, but not part of a file or directory, this
                   1566:  * driver refuses to commit.
                   1567:  */
                   1568: typedef enum {
                   1569:      USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
                   1570: } used_t;
                   1571: 
                   1572: /*
                   1573:  * get_cluster_count_for_direntry() not only determines how many clusters
                   1574:  * are occupied by direntry, but also if it was renamed or modified.
                   1575:  *
                   1576:  * A file is thought to be renamed *only* if there already was a file with
                   1577:  * exactly the same first cluster, but a different name.
                   1578:  *
                   1579:  * Further, the files/directories handled by this function are
                   1580:  * assumed to be *not* deleted (and *only* those).
                   1581:  */
                   1582: static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
                   1583:        direntry_t* direntry, const char* path)
                   1584: {
                   1585:     /*
                   1586:      * This is a little bit tricky:
                   1587:      * IF the guest OS just inserts a cluster into the file chain,
                   1588:      * and leaves the rest alone, (i.e. the original file had clusters
                   1589:      * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
                   1590:      *
                   1591:      * - do_commit will write the cluster into the file at the given
                   1592:      *   offset, but
                   1593:      *
                   1594:      * - the cluster which is overwritten should be moved to a later
                   1595:      *   position in the file.
                   1596:      *
                   1597:      * I am not aware that any OS does something as braindead, but this
                   1598:      * situation could happen anyway when not committing for a long time.
                   1599:      * Just to be sure that this does not bite us, detect it, and copy the
                   1600:      * contents of the clusters to-be-overwritten into the qcow.
                   1601:      */
                   1602:     int copy_it = 0;
                   1603:     int was_modified = 0;
                   1604:     int32_t ret = 0;
                   1605: 
                   1606:     uint32_t cluster_num = begin_of_direntry(direntry);
                   1607:     uint32_t offset = 0;
                   1608:     int first_mapping_index = -1;
                   1609:     mapping_t* mapping = NULL;
                   1610:     const char* basename2 = NULL;
                   1611: 
                   1612:     vvfat_close_current_file(s);
                   1613: 
                   1614:     /* the root directory */
                   1615:     if (cluster_num == 0)
                   1616:        return 0;
                   1617: 
                   1618:     /* write support */
                   1619:     if (s->qcow) {
                   1620:        basename2 = get_basename(path);
                   1621: 
                   1622:        mapping = find_mapping_for_cluster(s, cluster_num);
                   1623: 
                   1624:        if (mapping) {
                   1625:            const char* basename;
                   1626: 
                   1627:            assert(mapping->mode & MODE_DELETED);
                   1628:            mapping->mode &= ~MODE_DELETED;
                   1629: 
                   1630:            basename = get_basename(mapping->path);
                   1631: 
                   1632:            assert(mapping->mode & MODE_NORMAL);
                   1633: 
                   1634:            /* rename */
                   1635:            if (strcmp(basename, basename2))
1.1.1.3   root     1636:                schedule_rename(s, cluster_num, qemu_strdup(path));
1.1       root     1637:        } else if (is_file(direntry))
                   1638:            /* new file */
1.1.1.3   root     1639:            schedule_new_file(s, qemu_strdup(path), cluster_num);
1.1       root     1640:        else {
                   1641:            assert(0);
                   1642:            return 0;
                   1643:        }
                   1644:     }
                   1645: 
                   1646:     while(1) {
                   1647:        if (s->qcow) {
                   1648:            if (!copy_it && cluster_was_modified(s, cluster_num)) {
                   1649:                if (mapping == NULL ||
                   1650:                        mapping->begin > cluster_num ||
                   1651:                        mapping->end <= cluster_num)
                   1652:                mapping = find_mapping_for_cluster(s, cluster_num);
                   1653: 
                   1654: 
                   1655:                if (mapping &&
                   1656:                        (mapping->mode & MODE_DIRECTORY) == 0) {
                   1657: 
                   1658:                    /* was modified in qcow */
                   1659:                    if (offset != mapping->info.file.offset + s->cluster_size
                   1660:                            * (cluster_num - mapping->begin)) {
                   1661:                        /* offset of this cluster in file chain has changed */
                   1662:                        assert(0);
                   1663:                        copy_it = 1;
                   1664:                    } else if (offset == 0) {
                   1665:                        const char* basename = get_basename(mapping->path);
                   1666: 
                   1667:                        if (strcmp(basename, basename2))
                   1668:                            copy_it = 1;
                   1669:                        first_mapping_index = array_index(&(s->mapping), mapping);
                   1670:                    }
                   1671: 
                   1672:                    if (mapping->first_mapping_index != first_mapping_index
                   1673:                            && mapping->info.file.offset > 0) {
                   1674:                        assert(0);
                   1675:                        copy_it = 1;
                   1676:                    }
                   1677: 
                   1678:                    /* need to write out? */
                   1679:                    if (!was_modified && is_file(direntry)) {
                   1680:                        was_modified = 1;
                   1681:                        schedule_writeout(s, mapping->dir_index, offset);
                   1682:                    }
                   1683:                }
                   1684:            }
                   1685: 
                   1686:            if (copy_it) {
                   1687:                int i, dummy;
                   1688:                /*
                   1689:                 * This is horribly inefficient, but that is okay, since
                   1690:                 * it is rarely executed, if at all.
                   1691:                 */
                   1692:                int64_t offset = cluster2sector(s, cluster_num);
                   1693: 
                   1694:                vvfat_close_current_file(s);
                   1695:                for (i = 0; i < s->sectors_per_cluster; i++)
                   1696:                    if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1697:                                offset + i, 1, &dummy)) {
                   1698:                        if (vvfat_read(s->bs,
                   1699:                                    offset, s->cluster_buffer, 1))
                   1700:                            return -1;
                   1701:                        if (s->qcow->drv->bdrv_write(s->qcow,
                   1702:                                    offset, s->cluster_buffer, 1))
                   1703:                            return -2;
                   1704:                    }
                   1705:            }
                   1706:        }
                   1707: 
                   1708:        ret++;
                   1709:        if (s->used_clusters[cluster_num] & USED_ANY)
                   1710:            return 0;
                   1711:        s->used_clusters[cluster_num] = USED_FILE;
                   1712: 
                   1713:        cluster_num = modified_fat_get(s, cluster_num);
                   1714: 
                   1715:        if (fat_eof(s, cluster_num))
                   1716:            return ret;
                   1717:        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
                   1718:            return -1;
                   1719: 
                   1720:        offset += s->cluster_size;
                   1721:     }
                   1722: }
                   1723: 
                   1724: /*
                   1725:  * This function looks at the modified data (qcow).
                   1726:  * It returns 0 upon inconsistency or error, and the number of clusters
                   1727:  * used by the directory, its subdirectories and their files.
                   1728:  */
                   1729: static int check_directory_consistency(BDRVVVFATState *s,
                   1730:        int cluster_num, const char* path)
                   1731: {
                   1732:     int ret = 0;
                   1733:     unsigned char* cluster = qemu_malloc(s->cluster_size);
                   1734:     direntry_t* direntries = (direntry_t*)cluster;
                   1735:     mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
                   1736: 
                   1737:     long_file_name lfn;
                   1738:     int path_len = strlen(path);
                   1739:     char path2[PATH_MAX];
                   1740: 
                   1741:     assert(path_len < PATH_MAX); /* len was tested before! */
                   1742:     pstrcpy(path2, sizeof(path2), path);
                   1743:     path2[path_len] = '/';
                   1744:     path2[path_len + 1] = '\0';
                   1745: 
                   1746:     if (mapping) {
                   1747:        const char* basename = get_basename(mapping->path);
                   1748:        const char* basename2 = get_basename(path);
                   1749: 
                   1750:        assert(mapping->mode & MODE_DIRECTORY);
                   1751: 
                   1752:        assert(mapping->mode & MODE_DELETED);
                   1753:        mapping->mode &= ~MODE_DELETED;
                   1754: 
                   1755:        if (strcmp(basename, basename2))
1.1.1.3   root     1756:            schedule_rename(s, cluster_num, qemu_strdup(path));
1.1       root     1757:     } else
                   1758:        /* new directory */
1.1.1.3   root     1759:        schedule_mkdir(s, cluster_num, qemu_strdup(path));
1.1       root     1760: 
                   1761:     lfn_init(&lfn);
                   1762:     do {
                   1763:        int i;
                   1764:        int subret = 0;
                   1765: 
                   1766:        ret++;
                   1767: 
                   1768:        if (s->used_clusters[cluster_num] & USED_ANY) {
                   1769:            fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
                   1770:            return 0;
                   1771:        }
                   1772:        s->used_clusters[cluster_num] = USED_DIRECTORY;
                   1773: 
                   1774: DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
                   1775:        subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
                   1776:                s->sectors_per_cluster);
                   1777:        if (subret) {
                   1778:            fprintf(stderr, "Error fetching direntries\n");
                   1779:        fail:
                   1780:            free(cluster);
                   1781:            return 0;
                   1782:        }
                   1783: 
                   1784:        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
                   1785:            int cluster_count = 0;
                   1786: 
                   1787: DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
                   1788:            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
                   1789:                    is_free(direntries + i))
                   1790:                continue;
                   1791: 
                   1792:            subret = parse_long_name(&lfn, direntries + i);
                   1793:            if (subret < 0) {
                   1794:                fprintf(stderr, "Error in long name\n");
                   1795:                goto fail;
                   1796:            }
                   1797:            if (subret == 0 || is_free(direntries + i))
                   1798:                continue;
                   1799: 
                   1800:            if (fat_chksum(direntries+i) != lfn.checksum) {
                   1801:                subret = parse_short_name(s, &lfn, direntries + i);
                   1802:                if (subret < 0) {
                   1803:                    fprintf(stderr, "Error in short name (%d)\n", subret);
                   1804:                    goto fail;
                   1805:                }
                   1806:                if (subret > 0 || !strcmp((char*)lfn.name, ".")
                   1807:                        || !strcmp((char*)lfn.name, ".."))
                   1808:                    continue;
                   1809:            }
                   1810:            lfn.checksum = 0x100; /* cannot use long name twice */
                   1811: 
                   1812:            if (path_len + 1 + lfn.len >= PATH_MAX) {
                   1813:                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
                   1814:                goto fail;
                   1815:            }
                   1816:             pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
                   1817:                     (char*)lfn.name);
                   1818: 
                   1819:            if (is_directory(direntries + i)) {
                   1820:                if (begin_of_direntry(direntries + i) == 0) {
                   1821:                    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
                   1822:                    goto fail;
                   1823:                }
                   1824:                cluster_count = check_directory_consistency(s,
                   1825:                        begin_of_direntry(direntries + i), path2);
                   1826:                if (cluster_count == 0) {
                   1827:                    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
                   1828:                    goto fail;
                   1829:                }
                   1830:            } else if (is_file(direntries + i)) {
                   1831:                /* check file size with FAT */
                   1832:                cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
                   1833:                if (cluster_count !=
                   1834:                        (le32_to_cpu(direntries[i].size) + s->cluster_size
                   1835:                         - 1) / s->cluster_size) {
                   1836:                    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
                   1837:                    goto fail;
                   1838:                }
                   1839:            } else
                   1840:                assert(0); /* cluster_count = 0; */
                   1841: 
                   1842:            ret += cluster_count;
                   1843:        }
                   1844: 
                   1845:        cluster_num = modified_fat_get(s, cluster_num);
                   1846:     } while(!fat_eof(s, cluster_num));
                   1847: 
                   1848:     free(cluster);
                   1849:     return ret;
                   1850: }
                   1851: 
                   1852: /* returns 1 on success */
                   1853: static int is_consistent(BDRVVVFATState* s)
                   1854: {
                   1855:     int i, check;
                   1856:     int used_clusters_count = 0;
                   1857: 
                   1858: DLOG(checkpoint());
                   1859:     /*
                   1860:      * - get modified FAT
                   1861:      * - compare the two FATs (TODO)
                   1862:      * - get buffer for marking used clusters
                   1863:      * - recurse direntries from root (using bs->bdrv_read to make
                   1864:      *    sure to get the new data)
                   1865:      *   - check that the FAT agrees with the size
                   1866:      *   - count the number of clusters occupied by this directory and
                   1867:      *     its files
                   1868:      * - check that the cumulative used cluster count agrees with the
                   1869:      *   FAT
                   1870:      * - if all is fine, return number of used clusters
                   1871:      */
                   1872:     if (s->fat2 == NULL) {
                   1873:        int size = 0x200 * s->sectors_per_fat;
                   1874:        s->fat2 = qemu_malloc(size);
                   1875:        memcpy(s->fat2, s->fat.pointer, size);
                   1876:     }
                   1877:     check = vvfat_read(s->bs,
                   1878:            s->first_sectors_number, s->fat2, s->sectors_per_fat);
                   1879:     if (check) {
                   1880:        fprintf(stderr, "Could not copy fat\n");
                   1881:        return 0;
                   1882:     }
                   1883:     assert (s->used_clusters);
                   1884:     for (i = 0; i < sector2cluster(s, s->sector_count); i++)
                   1885:        s->used_clusters[i] &= ~USED_ANY;
                   1886: 
                   1887:     clear_commits(s);
                   1888: 
                   1889:     /* mark every mapped file/directory as deleted.
                   1890:      * (check_directory_consistency() will unmark those still present). */
                   1891:     if (s->qcow)
                   1892:        for (i = 0; i < s->mapping.next; i++) {
                   1893:            mapping_t* mapping = array_get(&(s->mapping), i);
                   1894:            if (mapping->first_mapping_index < 0)
                   1895:                mapping->mode |= MODE_DELETED;
                   1896:        }
                   1897: 
                   1898:     used_clusters_count = check_directory_consistency(s, 0, s->path);
                   1899:     if (used_clusters_count <= 0) {
                   1900:        DLOG(fprintf(stderr, "problem in directory\n"));
                   1901:        return 0;
                   1902:     }
                   1903: 
                   1904:     check = s->last_cluster_of_root_directory;
                   1905:     for (i = check; i < sector2cluster(s, s->sector_count); i++) {
                   1906:        if (modified_fat_get(s, i)) {
                   1907:            if(!s->used_clusters[i]) {
                   1908:                DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
                   1909:                return 0;
                   1910:            }
                   1911:            check++;
                   1912:        }
                   1913: 
                   1914:        if (s->used_clusters[i] == USED_ALLOCATED) {
                   1915:            /* allocated, but not used... */
                   1916:            DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
                   1917:            return 0;
                   1918:        }
                   1919:     }
                   1920: 
                   1921:     if (check != used_clusters_count)
                   1922:        return 0;
                   1923: 
                   1924:     return used_clusters_count;
                   1925: }
                   1926: 
                   1927: static inline void adjust_mapping_indices(BDRVVVFATState* s,
                   1928:        int offset, int adjust)
                   1929: {
                   1930:     int i;
                   1931: 
                   1932:     for (i = 0; i < s->mapping.next; i++) {
                   1933:        mapping_t* mapping = array_get(&(s->mapping), i);
                   1934: 
                   1935: #define ADJUST_MAPPING_INDEX(name) \
                   1936:        if (mapping->name >= offset) \
                   1937:            mapping->name += adjust
                   1938: 
                   1939:        ADJUST_MAPPING_INDEX(first_mapping_index);
                   1940:        if (mapping->mode & MODE_DIRECTORY)
                   1941:            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
                   1942:     }
                   1943: }
                   1944: 
                   1945: /* insert or update mapping */
                   1946: static mapping_t* insert_mapping(BDRVVVFATState* s,
                   1947:        uint32_t begin, uint32_t end)
                   1948: {
                   1949:     /*
                   1950:      * - find mapping where mapping->begin >= begin,
                   1951:      * - if mapping->begin > begin: insert
                   1952:      *   - adjust all references to mappings!
                   1953:      * - else: adjust
                   1954:      * - replace name
                   1955:      */
                   1956:     int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
                   1957:     mapping_t* mapping = NULL;
                   1958:     mapping_t* first_mapping = array_get(&(s->mapping), 0);
                   1959: 
                   1960:     if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
                   1961:            && mapping->begin < begin) {
                   1962:        mapping->end = begin;
                   1963:        index++;
                   1964:        mapping = array_get(&(s->mapping), index);
                   1965:     }
                   1966:     if (index >= s->mapping.next || mapping->begin > begin) {
                   1967:        mapping = array_insert(&(s->mapping), index, 1);
                   1968:        mapping->path = NULL;
                   1969:        adjust_mapping_indices(s, index, +1);
                   1970:     }
                   1971: 
                   1972:     mapping->begin = begin;
                   1973:     mapping->end = end;
                   1974: 
                   1975: DLOG(mapping_t* next_mapping;
                   1976: assert(index + 1 >= s->mapping.next ||
                   1977: ((next_mapping = array_get(&(s->mapping), index + 1)) &&
                   1978:  next_mapping->begin >= end)));
                   1979: 
                   1980:     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
                   1981:        s->current_mapping = array_get(&(s->mapping),
                   1982:                s->current_mapping - first_mapping);
                   1983: 
                   1984:     return mapping;
                   1985: }
                   1986: 
                   1987: static int remove_mapping(BDRVVVFATState* s, int mapping_index)
                   1988: {
                   1989:     mapping_t* mapping = array_get(&(s->mapping), mapping_index);
                   1990:     mapping_t* first_mapping = array_get(&(s->mapping), 0);
                   1991: 
                   1992:     /* free mapping */
                   1993:     if (mapping->first_mapping_index < 0)
                   1994:        free(mapping->path);
                   1995: 
                   1996:     /* remove from s->mapping */
                   1997:     array_remove(&(s->mapping), mapping_index);
                   1998: 
                   1999:     /* adjust all references to mappings */
                   2000:     adjust_mapping_indices(s, mapping_index, -1);
                   2001: 
                   2002:     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
                   2003:        s->current_mapping = array_get(&(s->mapping),
                   2004:                s->current_mapping - first_mapping);
                   2005: 
                   2006:     return 0;
                   2007: }
                   2008: 
                   2009: static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
                   2010: {
                   2011:     int i;
                   2012:     for (i = 0; i < s->mapping.next; i++) {
                   2013:        mapping_t* mapping = array_get(&(s->mapping), i);
                   2014:        if (mapping->dir_index >= offset)
                   2015:            mapping->dir_index += adjust;
                   2016:        if ((mapping->mode & MODE_DIRECTORY) &&
                   2017:                mapping->info.dir.first_dir_index >= offset)
                   2018:            mapping->info.dir.first_dir_index += adjust;
                   2019:     }
                   2020: }
                   2021: 
                   2022: static direntry_t* insert_direntries(BDRVVVFATState* s,
                   2023:        int dir_index, int count)
                   2024: {
                   2025:     /*
                   2026:      * make room in s->directory,
                   2027:      * adjust_dirindices
                   2028:      */
                   2029:     direntry_t* result = array_insert(&(s->directory), dir_index, count);
                   2030:     if (result == NULL)
                   2031:        return NULL;
                   2032:     adjust_dirindices(s, dir_index, count);
                   2033:     return result;
                   2034: }
                   2035: 
                   2036: static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
                   2037: {
                   2038:     int ret = array_remove_slice(&(s->directory), dir_index, count);
                   2039:     if (ret)
                   2040:        return ret;
                   2041:     adjust_dirindices(s, dir_index, -count);
                   2042:     return 0;
                   2043: }
                   2044: 
                   2045: /*
                   2046:  * Adapt the mappings of the cluster chain starting at first cluster
                   2047:  * (i.e. if a file starts at first_cluster, the chain is followed according
                   2048:  * to the modified fat, and the corresponding entries in s->mapping are
                   2049:  * adjusted)
                   2050:  */
                   2051: static int commit_mappings(BDRVVVFATState* s,
                   2052:        uint32_t first_cluster, int dir_index)
                   2053: {
                   2054:     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
                   2055:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2056:     uint32_t cluster = first_cluster;
                   2057: 
                   2058:     vvfat_close_current_file(s);
                   2059: 
                   2060:     assert(mapping);
                   2061:     assert(mapping->begin == first_cluster);
                   2062:     mapping->first_mapping_index = -1;
                   2063:     mapping->dir_index = dir_index;
                   2064:     mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
                   2065:        MODE_DIRECTORY : MODE_NORMAL;
                   2066: 
                   2067:     while (!fat_eof(s, cluster)) {
                   2068:        uint32_t c, c1;
                   2069: 
                   2070:        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
                   2071:                c = c1, c1 = modified_fat_get(s, c1));
                   2072: 
                   2073:        c++;
                   2074:        if (c > mapping->end) {
                   2075:            int index = array_index(&(s->mapping), mapping);
                   2076:            int i, max_i = s->mapping.next - index;
                   2077:            for (i = 1; i < max_i && mapping[i].begin < c; i++);
                   2078:            while (--i > 0)
                   2079:                remove_mapping(s, index + 1);
                   2080:        }
                   2081:        assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
                   2082:                || mapping[1].begin >= c);
                   2083:        mapping->end = c;
                   2084: 
                   2085:        if (!fat_eof(s, c1)) {
                   2086:            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
                   2087:            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
                   2088:                array_get(&(s->mapping), i);
                   2089: 
                   2090:            if (next_mapping == NULL || next_mapping->begin > c1) {
                   2091:                int i1 = array_index(&(s->mapping), mapping);
                   2092: 
                   2093:                next_mapping = insert_mapping(s, c1, c1+1);
                   2094: 
                   2095:                if (c1 < c)
                   2096:                    i1++;
                   2097:                mapping = array_get(&(s->mapping), i1);
                   2098:            }
                   2099: 
                   2100:            next_mapping->dir_index = mapping->dir_index;
                   2101:            next_mapping->first_mapping_index =
                   2102:                mapping->first_mapping_index < 0 ?
                   2103:                array_index(&(s->mapping), mapping) :
                   2104:                mapping->first_mapping_index;
                   2105:            next_mapping->path = mapping->path;
                   2106:            next_mapping->mode = mapping->mode;
                   2107:            next_mapping->read_only = mapping->read_only;
                   2108:            if (mapping->mode & MODE_DIRECTORY) {
                   2109:                next_mapping->info.dir.parent_mapping_index =
                   2110:                        mapping->info.dir.parent_mapping_index;
                   2111:                next_mapping->info.dir.first_dir_index =
                   2112:                        mapping->info.dir.first_dir_index +
                   2113:                        0x10 * s->sectors_per_cluster *
                   2114:                        (mapping->end - mapping->begin);
                   2115:            } else
                   2116:                next_mapping->info.file.offset = mapping->info.file.offset +
                   2117:                        mapping->end - mapping->begin;
                   2118: 
                   2119:            mapping = next_mapping;
                   2120:        }
                   2121: 
                   2122:        cluster = c1;
                   2123:     }
                   2124: 
                   2125:     return 0;
                   2126: }
                   2127: 
                   2128: static int commit_direntries(BDRVVVFATState* s,
                   2129:        int dir_index, int parent_mapping_index)
                   2130: {
                   2131:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2132:     uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
                   2133:     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
                   2134: 
                   2135:     int factor = 0x10 * s->sectors_per_cluster;
                   2136:     int old_cluster_count, new_cluster_count;
                   2137:     int current_dir_index = mapping->info.dir.first_dir_index;
                   2138:     int first_dir_index = current_dir_index;
                   2139:     int ret, i;
                   2140:     uint32_t c;
                   2141: 
                   2142: DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
                   2143: 
                   2144:     assert(direntry);
                   2145:     assert(mapping);
                   2146:     assert(mapping->begin == first_cluster);
                   2147:     assert(mapping->info.dir.first_dir_index < s->directory.next);
                   2148:     assert(mapping->mode & MODE_DIRECTORY);
                   2149:     assert(dir_index == 0 || is_directory(direntry));
                   2150: 
                   2151:     mapping->info.dir.parent_mapping_index = parent_mapping_index;
                   2152: 
                   2153:     if (first_cluster == 0) {
                   2154:        old_cluster_count = new_cluster_count =
                   2155:            s->last_cluster_of_root_directory;
                   2156:     } else {
                   2157:        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
                   2158:                c = fat_get(s, c))
                   2159:            old_cluster_count++;
                   2160: 
                   2161:        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
                   2162:                c = modified_fat_get(s, c))
                   2163:            new_cluster_count++;
                   2164:     }
                   2165: 
                   2166:     if (new_cluster_count > old_cluster_count) {
                   2167:        if (insert_direntries(s,
                   2168:                current_dir_index + factor * old_cluster_count,
                   2169:                factor * (new_cluster_count - old_cluster_count)) == NULL)
                   2170:            return -1;
                   2171:     } else if (new_cluster_count < old_cluster_count)
                   2172:        remove_direntries(s,
                   2173:                current_dir_index + factor * new_cluster_count,
                   2174:                factor * (old_cluster_count - new_cluster_count));
                   2175: 
                   2176:     for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
                   2177:        void* direntry = array_get(&(s->directory), current_dir_index);
                   2178:        int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
                   2179:                s->sectors_per_cluster);
                   2180:        if (ret)
                   2181:            return ret;
                   2182:        assert(!strncmp(s->directory.pointer, "QEMU", 4));
                   2183:        current_dir_index += factor;
                   2184:     }
                   2185: 
                   2186:     ret = commit_mappings(s, first_cluster, dir_index);
                   2187:     if (ret)
                   2188:        return ret;
                   2189: 
                   2190:     /* recurse */
                   2191:     for (i = 0; i < factor * new_cluster_count; i++) {
                   2192:        direntry = array_get(&(s->directory), first_dir_index + i);
                   2193:        if (is_directory(direntry) && !is_dot(direntry)) {
                   2194:            mapping = find_mapping_for_cluster(s, first_cluster);
                   2195:            assert(mapping->mode & MODE_DIRECTORY);
                   2196:            ret = commit_direntries(s, first_dir_index + i,
                   2197:                array_index(&(s->mapping), mapping));
                   2198:            if (ret)
                   2199:                return ret;
                   2200:        }
                   2201:     }
                   2202: 
                   2203:     return 0;
                   2204: }
                   2205: 
                   2206: /* commit one file (adjust contents, adjust mapping),
                   2207:    return first_mapping_index */
                   2208: static int commit_one_file(BDRVVVFATState* s,
                   2209:        int dir_index, uint32_t offset)
                   2210: {
                   2211:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2212:     uint32_t c = begin_of_direntry(direntry);
                   2213:     uint32_t first_cluster = c;
                   2214:     mapping_t* mapping = find_mapping_for_cluster(s, c);
                   2215:     uint32_t size = filesize_of_direntry(direntry);
                   2216:     char* cluster = qemu_malloc(s->cluster_size);
                   2217:     uint32_t i;
                   2218:     int fd = 0;
                   2219: 
                   2220:     assert(offset < size);
                   2221:     assert((offset % s->cluster_size) == 0);
                   2222: 
                   2223:     for (i = s->cluster_size; i < offset; i += s->cluster_size)
                   2224:        c = modified_fat_get(s, c);
                   2225: 
                   2226:     fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
                   2227:     if (fd < 0) {
                   2228:        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
                   2229:                strerror(errno), errno);
                   2230:        return fd;
                   2231:     }
                   2232:     if (offset > 0)
                   2233:        if (lseek(fd, offset, SEEK_SET) != offset)
                   2234:            return -3;
                   2235: 
                   2236:     while (offset < size) {
                   2237:        uint32_t c1;
                   2238:        int rest_size = (size - offset > s->cluster_size ?
                   2239:                s->cluster_size : size - offset);
                   2240:        int ret;
                   2241: 
                   2242:        c1 = modified_fat_get(s, c);
                   2243: 
                   2244:        assert((size - offset == 0 && fat_eof(s, c)) ||
                   2245:                (size > offset && c >=2 && !fat_eof(s, c)));
                   2246: 
                   2247:        ret = vvfat_read(s->bs, cluster2sector(s, c),
                   2248:            (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
                   2249: 
                   2250:        if (ret < 0)
                   2251:            return ret;
                   2252: 
                   2253:        if (write(fd, cluster, rest_size) < 0)
                   2254:            return -2;
                   2255: 
                   2256:        offset += rest_size;
                   2257:        c = c1;
                   2258:     }
                   2259: 
1.1.1.4 ! root     2260:     if (ftruncate(fd, size)) {
        !          2261:         perror("ftruncate()");
        !          2262:         close(fd);
        !          2263:         return -4;
        !          2264:     }
1.1       root     2265:     close(fd);
                   2266: 
                   2267:     return commit_mappings(s, first_cluster, dir_index);
                   2268: }
                   2269: 
                   2270: #ifdef DEBUG
                   2271: /* test, if all mappings point to valid direntries */
                   2272: static void check1(BDRVVVFATState* s)
                   2273: {
                   2274:     int i;
                   2275:     for (i = 0; i < s->mapping.next; i++) {
                   2276:        mapping_t* mapping = array_get(&(s->mapping), i);
                   2277:        if (mapping->mode & MODE_DELETED) {
                   2278:            fprintf(stderr, "deleted\n");
                   2279:            continue;
                   2280:        }
                   2281:        assert(mapping->dir_index >= 0);
                   2282:        assert(mapping->dir_index < s->directory.next);
                   2283:        direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
                   2284:        assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
                   2285:        if (mapping->mode & MODE_DIRECTORY) {
                   2286:            assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
                   2287:            assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
                   2288:        }
                   2289:     }
                   2290: }
                   2291: 
                   2292: /* test, if all direntries have mappings */
                   2293: static void check2(BDRVVVFATState* s)
                   2294: {
                   2295:     int i;
                   2296:     int first_mapping = -1;
                   2297: 
                   2298:     for (i = 0; i < s->directory.next; i++) {
                   2299:        direntry_t* direntry = array_get(&(s->directory), i);
                   2300: 
                   2301:        if (is_short_name(direntry) && begin_of_direntry(direntry)) {
                   2302:            mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
                   2303:            assert(mapping);
                   2304:            assert(mapping->dir_index == i || is_dot(direntry));
                   2305:            assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
                   2306:        }
                   2307: 
                   2308:        if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
                   2309:            /* cluster start */
                   2310:            int j, count = 0;
                   2311: 
                   2312:            for (j = 0; j < s->mapping.next; j++) {
                   2313:                mapping_t* mapping = array_get(&(s->mapping), j);
                   2314:                if (mapping->mode & MODE_DELETED)
                   2315:                    continue;
                   2316:                if (mapping->mode & MODE_DIRECTORY) {
                   2317:                    if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
                   2318:                        assert(++count == 1);
                   2319:                        if (mapping->first_mapping_index == -1)
                   2320:                            first_mapping = array_index(&(s->mapping), mapping);
                   2321:                        else
                   2322:                            assert(first_mapping == mapping->first_mapping_index);
                   2323:                        if (mapping->info.dir.parent_mapping_index < 0)
                   2324:                            assert(j == 0);
                   2325:                        else {
                   2326:                            mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
                   2327:                            assert(parent->mode & MODE_DIRECTORY);
                   2328:                            assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
                   2329:                        }
                   2330:                    }
                   2331:                }
                   2332:            }
                   2333:            if (count == 0)
                   2334:                first_mapping = -1;
                   2335:        }
                   2336:     }
                   2337: }
                   2338: #endif
                   2339: 
                   2340: static int handle_renames_and_mkdirs(BDRVVVFATState* s)
                   2341: {
                   2342:     int i;
                   2343: 
                   2344: #ifdef DEBUG
                   2345:     fprintf(stderr, "handle_renames\n");
                   2346:     for (i = 0; i < s->commits.next; i++) {
                   2347:        commit_t* commit = array_get(&(s->commits), i);
                   2348:        fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
                   2349:     }
                   2350: #endif
                   2351: 
                   2352:     for (i = 0; i < s->commits.next;) {
                   2353:        commit_t* commit = array_get(&(s->commits), i);
                   2354:        if (commit->action == ACTION_RENAME) {
                   2355:            mapping_t* mapping = find_mapping_for_cluster(s,
                   2356:                    commit->param.rename.cluster);
                   2357:            char* old_path = mapping->path;
                   2358: 
                   2359:            assert(commit->path);
                   2360:            mapping->path = commit->path;
                   2361:            if (rename(old_path, mapping->path))
                   2362:                return -2;
                   2363: 
                   2364:            if (mapping->mode & MODE_DIRECTORY) {
                   2365:                int l1 = strlen(mapping->path);
                   2366:                int l2 = strlen(old_path);
                   2367:                int diff = l1 - l2;
                   2368:                direntry_t* direntry = array_get(&(s->directory),
                   2369:                        mapping->info.dir.first_dir_index);
                   2370:                uint32_t c = mapping->begin;
                   2371:                int i = 0;
                   2372: 
                   2373:                /* recurse */
                   2374:                while (!fat_eof(s, c)) {
                   2375:                    do {
                   2376:                        direntry_t* d = direntry + i;
                   2377: 
                   2378:                        if (is_file(d) || (is_directory(d) && !is_dot(d))) {
                   2379:                            mapping_t* m = find_mapping_for_cluster(s,
                   2380:                                    begin_of_direntry(d));
                   2381:                            int l = strlen(m->path);
                   2382:                            char* new_path = qemu_malloc(l + diff + 1);
                   2383: 
                   2384:                            assert(!strncmp(m->path, mapping->path, l2));
                   2385: 
                   2386:                             pstrcpy(new_path, l + diff + 1, mapping->path);
                   2387:                             pstrcpy(new_path + l1, l + diff + 1 - l1,
                   2388:                                     m->path + l2);
                   2389: 
                   2390:                            schedule_rename(s, m->begin, new_path);
                   2391:                        }
                   2392:                        i++;
                   2393:                    } while((i % (0x10 * s->sectors_per_cluster)) != 0);
                   2394:                    c = fat_get(s, c);
                   2395:                }
                   2396:            }
                   2397: 
                   2398:            free(old_path);
                   2399:            array_remove(&(s->commits), i);
                   2400:            continue;
                   2401:        } else if (commit->action == ACTION_MKDIR) {
                   2402:            mapping_t* mapping;
                   2403:            int j, parent_path_len;
                   2404: 
                   2405: #ifdef __MINGW32__
                   2406:             if (mkdir(commit->path))
                   2407:                 return -5;
                   2408: #else
                   2409:             if (mkdir(commit->path, 0755))
                   2410:                 return -5;
                   2411: #endif
                   2412: 
                   2413:            mapping = insert_mapping(s, commit->param.mkdir.cluster,
                   2414:                    commit->param.mkdir.cluster + 1);
                   2415:            if (mapping == NULL)
                   2416:                return -6;
                   2417: 
                   2418:            mapping->mode = MODE_DIRECTORY;
                   2419:            mapping->read_only = 0;
                   2420:            mapping->path = commit->path;
                   2421:            j = s->directory.next;
                   2422:            assert(j);
                   2423:            insert_direntries(s, s->directory.next,
                   2424:                    0x10 * s->sectors_per_cluster);
                   2425:            mapping->info.dir.first_dir_index = j;
                   2426: 
                   2427:            parent_path_len = strlen(commit->path)
                   2428:                - strlen(get_basename(commit->path)) - 1;
                   2429:            for (j = 0; j < s->mapping.next; j++) {
                   2430:                mapping_t* m = array_get(&(s->mapping), j);
                   2431:                if (m->first_mapping_index < 0 && m != mapping &&
                   2432:                        !strncmp(m->path, mapping->path, parent_path_len) &&
                   2433:                        strlen(m->path) == parent_path_len)
                   2434:                    break;
                   2435:            }
                   2436:            assert(j < s->mapping.next);
                   2437:            mapping->info.dir.parent_mapping_index = j;
                   2438: 
                   2439:            array_remove(&(s->commits), i);
                   2440:            continue;
                   2441:        }
                   2442: 
                   2443:        i++;
                   2444:     }
                   2445:     return 0;
                   2446: }
                   2447: 
                   2448: /*
                   2449:  * TODO: make sure that the short name is not matching *another* file
                   2450:  */
                   2451: static int handle_commits(BDRVVVFATState* s)
                   2452: {
                   2453:     int i, fail = 0;
                   2454: 
                   2455:     vvfat_close_current_file(s);
                   2456: 
                   2457:     for (i = 0; !fail && i < s->commits.next; i++) {
                   2458:        commit_t* commit = array_get(&(s->commits), i);
                   2459:        switch(commit->action) {
                   2460:        case ACTION_RENAME: case ACTION_MKDIR:
                   2461:            assert(0);
                   2462:            fail = -2;
                   2463:            break;
                   2464:        case ACTION_WRITEOUT: {
                   2465:            direntry_t* entry = array_get(&(s->directory),
                   2466:                    commit->param.writeout.dir_index);
                   2467:            uint32_t begin = begin_of_direntry(entry);
                   2468:            mapping_t* mapping = find_mapping_for_cluster(s, begin);
                   2469: 
                   2470:            assert(mapping);
                   2471:            assert(mapping->begin == begin);
                   2472:            assert(commit->path == NULL);
                   2473: 
                   2474:            if (commit_one_file(s, commit->param.writeout.dir_index,
                   2475:                        commit->param.writeout.modified_offset))
                   2476:                fail = -3;
                   2477: 
                   2478:            break;
                   2479:        }
                   2480:        case ACTION_NEW_FILE: {
                   2481:            int begin = commit->param.new_file.first_cluster;
                   2482:            mapping_t* mapping = find_mapping_for_cluster(s, begin);
                   2483:            direntry_t* entry;
                   2484:            int i;
                   2485: 
                   2486:            /* find direntry */
                   2487:            for (i = 0; i < s->directory.next; i++) {
                   2488:                entry = array_get(&(s->directory), i);
                   2489:                if (is_file(entry) && begin_of_direntry(entry) == begin)
                   2490:                    break;
                   2491:            }
                   2492: 
                   2493:            if (i >= s->directory.next) {
                   2494:                fail = -6;
                   2495:                continue;
                   2496:            }
                   2497: 
                   2498:            /* make sure there exists an initial mapping */
                   2499:            if (mapping && mapping->begin != begin) {
                   2500:                mapping->end = begin;
                   2501:                mapping = NULL;
                   2502:            }
                   2503:            if (mapping == NULL) {
                   2504:                mapping = insert_mapping(s, begin, begin+1);
                   2505:            }
                   2506:            /* most members will be fixed in commit_mappings() */
                   2507:            assert(commit->path);
                   2508:            mapping->path = commit->path;
                   2509:            mapping->read_only = 0;
                   2510:            mapping->mode = MODE_NORMAL;
                   2511:            mapping->info.file.offset = 0;
                   2512: 
                   2513:            if (commit_one_file(s, i, 0))
                   2514:                fail = -7;
                   2515: 
                   2516:            break;
                   2517:        }
                   2518:        default:
                   2519:            assert(0);
                   2520:        }
                   2521:     }
                   2522:     if (i > 0 && array_remove_slice(&(s->commits), 0, i))
                   2523:        return -1;
                   2524:     return fail;
                   2525: }
                   2526: 
                   2527: static int handle_deletes(BDRVVVFATState* s)
                   2528: {
                   2529:     int i, deferred = 1, deleted = 1;
                   2530: 
                   2531:     /* delete files corresponding to mappings marked as deleted */
                   2532:     /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
                   2533:     while (deferred && deleted) {
                   2534:        deferred = 0;
                   2535:        deleted = 0;
                   2536: 
                   2537:        for (i = 1; i < s->mapping.next; i++) {
                   2538:            mapping_t* mapping = array_get(&(s->mapping), i);
                   2539:            if (mapping->mode & MODE_DELETED) {
                   2540:                direntry_t* entry = array_get(&(s->directory),
                   2541:                        mapping->dir_index);
                   2542: 
                   2543:                if (is_free(entry)) {
                   2544:                    /* remove file/directory */
                   2545:                    if (mapping->mode & MODE_DIRECTORY) {
                   2546:                        int j, next_dir_index = s->directory.next,
                   2547:                        first_dir_index = mapping->info.dir.first_dir_index;
                   2548: 
                   2549:                        if (rmdir(mapping->path) < 0) {
                   2550:                            if (errno == ENOTEMPTY) {
                   2551:                                deferred++;
                   2552:                                continue;
                   2553:                            } else
                   2554:                                return -5;
                   2555:                        }
                   2556: 
                   2557:                        for (j = 1; j < s->mapping.next; j++) {
                   2558:                            mapping_t* m = array_get(&(s->mapping), j);
                   2559:                            if (m->mode & MODE_DIRECTORY &&
                   2560:                                    m->info.dir.first_dir_index >
                   2561:                                    first_dir_index &&
                   2562:                                    m->info.dir.first_dir_index <
                   2563:                                    next_dir_index)
                   2564:                                next_dir_index =
                   2565:                                    m->info.dir.first_dir_index;
                   2566:                        }
                   2567:                        remove_direntries(s, first_dir_index,
                   2568:                                next_dir_index - first_dir_index);
                   2569: 
                   2570:                        deleted++;
                   2571:                    }
                   2572:                } else {
                   2573:                    if (unlink(mapping->path))
                   2574:                        return -4;
                   2575:                    deleted++;
                   2576:                }
                   2577:                DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
                   2578:                remove_mapping(s, i);
                   2579:            }
                   2580:        }
                   2581:     }
                   2582: 
                   2583:     return 0;
                   2584: }
                   2585: 
                   2586: /*
                   2587:  * synchronize mapping with new state:
                   2588:  *
                   2589:  * - copy FAT (with bdrv_read)
                   2590:  * - mark all filenames corresponding to mappings as deleted
                   2591:  * - recurse direntries from root (using bs->bdrv_read)
                   2592:  * - delete files corresponding to mappings marked as deleted
                   2593:  */
                   2594: static int do_commit(BDRVVVFATState* s)
                   2595: {
                   2596:     int ret = 0;
                   2597: 
                   2598:     /* the real meat are the commits. Nothing to do? Move along! */
                   2599:     if (s->commits.next == 0)
                   2600:        return 0;
                   2601: 
                   2602:     vvfat_close_current_file(s);
                   2603: 
                   2604:     ret = handle_renames_and_mkdirs(s);
                   2605:     if (ret) {
                   2606:        fprintf(stderr, "Error handling renames (%d)\n", ret);
                   2607:        assert(0);
                   2608:        return ret;
                   2609:     }
                   2610: 
                   2611:     /* copy FAT (with bdrv_read) */
                   2612:     memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
                   2613: 
                   2614:     /* recurse direntries from root (using bs->bdrv_read) */
                   2615:     ret = commit_direntries(s, 0, -1);
                   2616:     if (ret) {
                   2617:        fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
                   2618:        assert(0);
                   2619:        return ret;
                   2620:     }
                   2621: 
                   2622:     ret = handle_commits(s);
                   2623:     if (ret) {
                   2624:        fprintf(stderr, "Error handling commits (%d)\n", ret);
                   2625:        assert(0);
                   2626:        return ret;
                   2627:     }
                   2628: 
                   2629:     ret = handle_deletes(s);
                   2630:     if (ret) {
                   2631:        fprintf(stderr, "Error deleting\n");
                   2632:         assert(0);
                   2633:        return ret;
                   2634:     }
                   2635: 
                   2636:     s->qcow->drv->bdrv_make_empty(s->qcow);
                   2637: 
                   2638:     memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
                   2639: 
                   2640: DLOG(checkpoint());
                   2641:     return 0;
                   2642: }
                   2643: 
                   2644: static int try_commit(BDRVVVFATState* s)
                   2645: {
                   2646:     vvfat_close_current_file(s);
                   2647: DLOG(checkpoint());
                   2648:     if(!is_consistent(s))
                   2649:        return -1;
                   2650:     return do_commit(s);
                   2651: }
                   2652: 
                   2653: static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
                   2654:                     const uint8_t *buf, int nb_sectors)
                   2655: {
                   2656:     BDRVVVFATState *s = bs->opaque;
                   2657:     int i, ret;
                   2658: 
                   2659: DLOG(checkpoint());
                   2660: 
                   2661:     vvfat_close_current_file(s);
                   2662: 
                   2663:     /*
                   2664:      * Some sanity checks:
                   2665:      * - do not allow writing to the boot sector
                   2666:      * - do not allow to write non-ASCII filenames
                   2667:      */
                   2668: 
                   2669:     if (sector_num < s->first_sectors_number)
                   2670:        return -1;
                   2671: 
                   2672:     for (i = sector2cluster(s, sector_num);
                   2673:            i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
                   2674:        mapping_t* mapping = find_mapping_for_cluster(s, i);
                   2675:        if (mapping) {
                   2676:            if (mapping->read_only) {
                   2677:                fprintf(stderr, "Tried to write to write-protected file %s\n",
                   2678:                        mapping->path);
                   2679:                return -1;
                   2680:            }
                   2681: 
                   2682:            if (mapping->mode & MODE_DIRECTORY) {
                   2683:                int begin = cluster2sector(s, i);
                   2684:                int end = begin + s->sectors_per_cluster, k;
                   2685:                int dir_index;
                   2686:                const direntry_t* direntries;
                   2687:                long_file_name lfn;
                   2688: 
                   2689:                lfn_init(&lfn);
                   2690: 
                   2691:                if (begin < sector_num)
                   2692:                    begin = sector_num;
                   2693:                if (end > sector_num + nb_sectors)
                   2694:                    end = sector_num + nb_sectors;
                   2695:                dir_index  = mapping->dir_index +
                   2696:                    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
                   2697:                direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
                   2698: 
                   2699:                for (k = 0; k < (end - begin) * 0x10; k++) {
                   2700:                    /* do not allow non-ASCII filenames */
                   2701:                    if (parse_long_name(&lfn, direntries + k) < 0) {
                   2702:                        fprintf(stderr, "Warning: non-ASCII filename\n");
                   2703:                        return -1;
                   2704:                    }
                   2705:                    /* no access to the direntry of a read-only file */
                   2706:                    else if (is_short_name(direntries+k) &&
                   2707:                            (direntries[k].attributes & 1)) {
                   2708:                        if (memcmp(direntries + k,
                   2709:                                    array_get(&(s->directory), dir_index + k),
                   2710:                                    sizeof(direntry_t))) {
                   2711:                            fprintf(stderr, "Warning: tried to write to write-protected file\n");
                   2712:                            return -1;
                   2713:                        }
                   2714:                    }
                   2715:                }
                   2716:            }
                   2717:            i = mapping->end;
                   2718:        } else
                   2719:            i++;
                   2720:     }
                   2721: 
                   2722:     /*
                   2723:      * Use qcow backend. Commit later.
                   2724:      */
                   2725: DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
                   2726:     ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
                   2727:     if (ret < 0) {
                   2728:        fprintf(stderr, "Error writing to qcow backend\n");
                   2729:        return ret;
                   2730:     }
                   2731: 
                   2732:     for (i = sector2cluster(s, sector_num);
                   2733:            i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
                   2734:        if (i >= 0)
                   2735:            s->used_clusters[i] |= USED_ALLOCATED;
                   2736: 
                   2737: DLOG(checkpoint());
                   2738:     /* TODO: add timeout */
                   2739:     try_commit(s);
                   2740: 
                   2741: DLOG(checkpoint());
                   2742:     return 0;
                   2743: }
                   2744: 
                   2745: static int vvfat_is_allocated(BlockDriverState *bs,
                   2746:        int64_t sector_num, int nb_sectors, int* n)
                   2747: {
                   2748:     BDRVVVFATState* s = bs->opaque;
                   2749:     *n = s->sector_count - sector_num;
                   2750:     if (*n > nb_sectors)
                   2751:        *n = nb_sectors;
                   2752:     else if (*n < 0)
                   2753:        return 0;
                   2754:     return 1;
                   2755: }
                   2756: 
                   2757: static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
                   2758:        const uint8_t* buffer, int nb_sectors) {
                   2759:     BDRVVVFATState* s = bs->opaque;
                   2760:     return try_commit(s);
                   2761: }
                   2762: 
                   2763: static void write_target_close(BlockDriverState *bs) {
                   2764:     BDRVVVFATState* s = bs->opaque;
                   2765:     bdrv_delete(s->qcow);
                   2766:     free(s->qcow_filename);
                   2767: }
                   2768: 
                   2769: static BlockDriver vvfat_write_target = {
                   2770:     .format_name        = "vvfat_write_target",
                   2771:     .bdrv_write         = write_target_commit,
                   2772:     .bdrv_close         = write_target_close,
                   2773: };
                   2774: 
                   2775: static int enable_write_target(BDRVVVFATState *s)
                   2776: {
                   2777:     BlockDriver *bdrv_qcow;
                   2778:     QEMUOptionParameter *options;
                   2779:     int size = sector2cluster(s, s->sector_count);
                   2780:     s->used_clusters = calloc(size, 1);
                   2781: 
                   2782:     array_init(&(s->commits), sizeof(commit_t));
                   2783: 
                   2784:     s->qcow_filename = qemu_malloc(1024);
                   2785:     get_tmp_filename(s->qcow_filename, 1024);
                   2786: 
                   2787:     bdrv_qcow = bdrv_find_format("qcow");
                   2788:     options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
                   2789:     set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
                   2790:     set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
                   2791: 
                   2792:     if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
                   2793:        return -1;
                   2794:     s->qcow = bdrv_new("");
                   2795:     if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
                   2796:        return -1;
                   2797: 
                   2798: #ifndef _WIN32
                   2799:     unlink(s->qcow_filename);
                   2800: #endif
                   2801: 
                   2802:     s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
                   2803:     s->bs->backing_hd->drv = &vvfat_write_target;
                   2804:     s->bs->backing_hd->opaque = s;
                   2805: 
                   2806:     return 0;
                   2807: }
                   2808: 
                   2809: static void vvfat_close(BlockDriverState *bs)
                   2810: {
                   2811:     BDRVVVFATState *s = bs->opaque;
                   2812: 
                   2813:     vvfat_close_current_file(s);
                   2814:     array_free(&(s->fat));
                   2815:     array_free(&(s->directory));
                   2816:     array_free(&(s->mapping));
                   2817:     if(s->cluster_buffer)
                   2818:         free(s->cluster_buffer);
                   2819: }
                   2820: 
                   2821: static BlockDriver bdrv_vvfat = {
                   2822:     .format_name       = "vvfat",
                   2823:     .instance_size     = sizeof(BDRVVVFATState),
                   2824:     .bdrv_open         = vvfat_open,
                   2825:     .bdrv_read         = vvfat_read,
                   2826:     .bdrv_write                = vvfat_write,
                   2827:     .bdrv_close                = vvfat_close,
                   2828:     .bdrv_is_allocated = vvfat_is_allocated,
                   2829:     .protocol_name     = "fat",
                   2830: };
                   2831: 
                   2832: static void bdrv_vvfat_init(void)
                   2833: {
                   2834:     bdrv_register(&bdrv_vvfat);
                   2835: }
                   2836: 
                   2837: block_init(bdrv_vvfat_init);
                   2838: 
                   2839: #ifdef DEBUG
                   2840: static void checkpoint(void) {
                   2841:     assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
                   2842:     check1(vvv);
                   2843:     check2(vvv);
                   2844:     assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
                   2845: #if 0
                   2846:     if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
                   2847:        fprintf(stderr, "Nonono!\n");
                   2848:     mapping_t* mapping;
                   2849:     direntry_t* direntry;
                   2850:     assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
                   2851:     assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
                   2852:     if (vvv->mapping.next<47)
                   2853:        return;
                   2854:     assert((mapping = array_get(&(vvv->mapping), 47)));
                   2855:     assert(mapping->dir_index < vvv->directory.next);
                   2856:     direntry = array_get(&(vvv->directory), mapping->dir_index);
                   2857:     assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
                   2858: #endif
                   2859:     return;
                   2860:     /* avoid compiler warnings: */
                   2861:     hexdump(NULL, 100);
                   2862:     remove_mapping(vvv, NULL);
                   2863:     print_mapping(NULL);
                   2864:     print_direntry(NULL);
                   2865: }
                   2866: #endif

unix.superglobalmegacorp.com

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