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

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

unix.superglobalmegacorp.com

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