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

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);
                    759:            return -2;
                    760:         }
                    761:        direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
                    762: 
                    763:        /* create mapping for this file */
                    764:        if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
                    765:            s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
                    766:            s->current_mapping->begin=0;
                    767:            s->current_mapping->end=st.st_size;
                    768:            /*
                    769:             * we get the direntry of the most recent direntry, which
                    770:             * contains the short name and all the relevant information.
                    771:             */
                    772:            s->current_mapping->dir_index=s->directory.next-1;
                    773:            s->current_mapping->first_mapping_index = -1;
                    774:            if (S_ISDIR(st.st_mode)) {
                    775:                s->current_mapping->mode = MODE_DIRECTORY;
                    776:                s->current_mapping->info.dir.parent_mapping_index =
                    777:                    mapping_index;
                    778:            } else {
                    779:                s->current_mapping->mode = MODE_UNDEFINED;
                    780:                s->current_mapping->info.file.offset = 0;
                    781:            }
                    782:            s->current_mapping->path=buffer;
                    783:            s->current_mapping->read_only =
                    784:                (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
                    785:        }
                    786:     }
                    787:     closedir(dir);
                    788: 
                    789:     /* fill with zeroes up to the end of the cluster */
                    790:     while(s->directory.next%(0x10*s->sectors_per_cluster)) {
                    791:        direntry_t* direntry=array_get_next(&(s->directory));
                    792:        memset(direntry,0,sizeof(direntry_t));
                    793:     }
                    794: 
                    795: /* TODO: if there are more entries, bootsector has to be adjusted! */
                    796: #define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
                    797:     if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
                    798:        /* root directory */
                    799:        int cur = s->directory.next;
                    800:        array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
                    801:        memset(array_get(&(s->directory), cur), 0,
                    802:                (ROOT_ENTRIES - cur) * sizeof(direntry_t));
                    803:     }
                    804: 
                    805:      /* reget the mapping, since s->mapping was possibly realloc()ed */
                    806:     mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
                    807:     first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
                    808:        * 0x20 / s->cluster_size;
                    809:     mapping->end = first_cluster;
                    810: 
                    811:     direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
                    812:     set_begin_of_direntry(direntry, mapping->begin);
                    813: 
                    814:     return 0;
                    815: }
                    816: 
                    817: static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
                    818: {
                    819:     return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
                    820: }
                    821: 
                    822: static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
                    823: {
                    824:     return s->faked_sectors + s->sectors_per_cluster * cluster_num;
                    825: }
                    826: 
                    827: static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
                    828: {
                    829:     return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
                    830: }
                    831: 
                    832: #ifdef DBG
                    833: static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
                    834: {
                    835:     if(mapping->mode==MODE_UNDEFINED)
                    836:        return 0;
                    837:     return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
                    838: }
                    839: #endif
                    840: 
                    841: static int init_directories(BDRVVVFATState* s,
                    842:        const char* dirname)
                    843: {
                    844:     bootsector_t* bootsector;
                    845:     mapping_t* mapping;
                    846:     unsigned int i;
                    847:     unsigned int cluster;
                    848: 
                    849:     memset(&(s->first_sectors[0]),0,0x40*0x200);
                    850: 
                    851:     s->cluster_size=s->sectors_per_cluster*0x200;
                    852:     s->cluster_buffer=qemu_malloc(s->cluster_size);
                    853: 
                    854:     /*
                    855:      * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
                    856:      * where sc is sector_count,
                    857:      * spf is sectors_per_fat,
                    858:      * spc is sectors_per_clusters, and
                    859:      * fat_type = 12, 16 or 32.
                    860:      */
                    861:     i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
                    862:     s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
                    863: 
                    864:     array_init(&(s->mapping),sizeof(mapping_t));
                    865:     array_init(&(s->directory),sizeof(direntry_t));
                    866: 
                    867:     /* add volume label */
                    868:     {
                    869:        direntry_t* entry=array_get_next(&(s->directory));
                    870:        entry->attributes=0x28; /* archive | volume label */
1.1.1.4   root      871:        memcpy(entry->name,"QEMU VVF",8);
                    872:        memcpy(entry->extension,"AT ",3);
1.1       root      873:     }
                    874: 
                    875:     /* Now build FAT, and write back information into directory */
                    876:     init_fat(s);
                    877: 
                    878:     s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
                    879:     s->cluster_count=sector2cluster(s, s->sector_count);
                    880: 
                    881:     mapping = array_get_next(&(s->mapping));
                    882:     mapping->begin = 0;
                    883:     mapping->dir_index = 0;
                    884:     mapping->info.dir.parent_mapping_index = -1;
                    885:     mapping->first_mapping_index = -1;
1.1.1.3   root      886:     mapping->path = qemu_strdup(dirname);
1.1       root      887:     i = strlen(mapping->path);
                    888:     if (i > 0 && mapping->path[i - 1] == '/')
                    889:        mapping->path[i - 1] = '\0';
                    890:     mapping->mode = MODE_DIRECTORY;
                    891:     mapping->read_only = 0;
                    892:     s->path = mapping->path;
                    893: 
                    894:     for (i = 0, cluster = 0; i < s->mapping.next; i++) {
                    895:        /* MS-DOS expects the FAT to be 0 for the root directory
                    896:         * (except for the media byte). */
                    897:        /* LATER TODO: still true for FAT32? */
                    898:        int fix_fat = (i != 0);
                    899:        mapping = array_get(&(s->mapping), i);
                    900: 
                    901:         if (mapping->mode & MODE_DIRECTORY) {
                    902:            mapping->begin = cluster;
                    903:            if(read_directory(s, i)) {
                    904:                fprintf(stderr, "Could not read directory %s\n",
                    905:                        mapping->path);
                    906:                return -1;
                    907:            }
                    908:            mapping = array_get(&(s->mapping), i);
                    909:        } else {
                    910:            assert(mapping->mode == MODE_UNDEFINED);
                    911:            mapping->mode=MODE_NORMAL;
                    912:            mapping->begin = cluster;
                    913:            if (mapping->end > 0) {
                    914:                direntry_t* direntry = array_get(&(s->directory),
                    915:                        mapping->dir_index);
                    916: 
                    917:                mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
                    918:                set_begin_of_direntry(direntry, mapping->begin);
                    919:            } else {
                    920:                mapping->end = cluster + 1;
                    921:                fix_fat = 0;
                    922:            }
                    923:        }
                    924: 
                    925:        assert(mapping->begin < mapping->end);
                    926: 
                    927:        /* next free cluster */
                    928:        cluster = mapping->end;
                    929: 
                    930:        if(cluster > s->cluster_count) {
                    931:            fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
                    932:                    s->fat_type,
                    933:                    s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
                    934:                                                                : "2.88 MB"
                    935:                                      : "504MB");
                    936:            return -EINVAL;
                    937:        }
                    938: 
                    939:        /* fix fat for entry */
                    940:        if (fix_fat) {
                    941:            int j;
                    942:            for(j = mapping->begin; j < mapping->end - 1; j++)
                    943:                fat_set(s, j, j+1);
                    944:            fat_set(s, mapping->end - 1, s->max_fat_value);
                    945:        }
                    946:     }
                    947: 
                    948:     mapping = array_get(&(s->mapping), 0);
                    949:     s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
                    950:     s->last_cluster_of_root_directory = mapping->end;
                    951: 
                    952:     /* the FAT signature */
                    953:     fat_set(s,0,s->max_fat_value);
                    954:     fat_set(s,1,s->max_fat_value);
                    955: 
                    956:     s->current_mapping = NULL;
                    957: 
                    958:     bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
                    959:     bootsector->jump[0]=0xeb;
                    960:     bootsector->jump[1]=0x3e;
                    961:     bootsector->jump[2]=0x90;
                    962:     memcpy(bootsector->name,"QEMU    ",8);
                    963:     bootsector->sector_size=cpu_to_le16(0x200);
                    964:     bootsector->sectors_per_cluster=s->sectors_per_cluster;
                    965:     bootsector->reserved_sectors=cpu_to_le16(1);
                    966:     bootsector->number_of_fats=0x2; /* number of FATs */
                    967:     bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
                    968:     bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
                    969:     bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
                    970:     s->fat.pointer[0] = bootsector->media_type;
                    971:     bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
                    972:     bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
                    973:     bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
                    974:     bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
                    975:     bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
                    976: 
                    977:     /* LATER TODO: if FAT32, this is wrong */
                    978:     bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
                    979:     bootsector->u.fat16.current_head=0;
                    980:     bootsector->u.fat16.signature=0x29;
                    981:     bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
                    982: 
                    983:     memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
                    984:     memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12   ":s->fat_type==16?"FAT16   ":"FAT32   "),8);
                    985:     bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
                    986: 
                    987:     return 0;
                    988: }
                    989: 
                    990: #ifdef DEBUG
                    991: static BDRVVVFATState *vvv = NULL;
                    992: #endif
                    993: 
                    994: static int enable_write_target(BDRVVVFATState *s);
                    995: static int is_consistent(BDRVVVFATState *s);
                    996: 
                    997: static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
                    998: {
                    999:     BDRVVVFATState *s = bs->opaque;
                   1000:     int floppy = 0;
                   1001:     int i;
                   1002: 
                   1003: #ifdef DEBUG
                   1004:     vvv = s;
                   1005: #endif
                   1006: 
                   1007: DLOG(if (stderr == NULL) {
                   1008:     stderr = fopen("vvfat.log", "a");
                   1009:     setbuf(stderr, NULL);
                   1010: })
                   1011: 
                   1012:     s->bs = bs;
                   1013: 
                   1014:     s->fat_type=16;
                   1015:     /* LATER TODO: if FAT32, adjust */
                   1016:     s->sectors_per_cluster=0x10;
                   1017:     /* 504MB disk*/
                   1018:     bs->cyls=1024; bs->heads=16; bs->secs=63;
                   1019: 
                   1020:     s->current_cluster=0xffffffff;
                   1021: 
                   1022:     s->first_sectors_number=0x40;
                   1023:     /* read only is the default for safety */
                   1024:     bs->read_only = 1;
                   1025:     s->qcow = s->write_target = NULL;
                   1026:     s->qcow_filename = NULL;
                   1027:     s->fat2 = NULL;
                   1028:     s->downcase_short_names = 1;
                   1029: 
                   1030:     if (!strstart(dirname, "fat:", NULL))
                   1031:        return -1;
                   1032: 
                   1033:     if (strstr(dirname, ":floppy:")) {
                   1034:        floppy = 1;
                   1035:        s->fat_type = 12;
                   1036:        s->first_sectors_number = 1;
                   1037:        s->sectors_per_cluster=2;
                   1038:        bs->cyls = 80; bs->heads = 2; bs->secs = 36;
                   1039:     }
                   1040: 
                   1041:     s->sector_count=bs->cyls*bs->heads*bs->secs;
                   1042: 
                   1043:     if (strstr(dirname, ":32:")) {
                   1044:        fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
                   1045:        s->fat_type = 32;
                   1046:     } else if (strstr(dirname, ":16:")) {
                   1047:        s->fat_type = 16;
                   1048:     } else if (strstr(dirname, ":12:")) {
                   1049:        s->fat_type = 12;
                   1050:        s->sector_count=2880;
                   1051:     }
                   1052: 
                   1053:     if (strstr(dirname, ":rw:")) {
                   1054:        if (enable_write_target(s))
                   1055:            return -1;
                   1056:        bs->read_only = 0;
                   1057:     }
                   1058: 
                   1059:     i = strrchr(dirname, ':') - dirname;
                   1060:     assert(i >= 3);
                   1061:     if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
                   1062:        /* workaround for DOS drive names */
                   1063:        dirname += i-1;
                   1064:     else
                   1065:        dirname += i+1;
                   1066: 
                   1067:     bs->total_sectors=bs->cyls*bs->heads*bs->secs;
                   1068: 
                   1069:     if(init_directories(s, dirname))
                   1070:        return -1;
                   1071: 
                   1072:     s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
                   1073: 
                   1074:     if(s->first_sectors_number==0x40)
                   1075:        init_mbr(s);
                   1076: 
                   1077:     /* for some reason or other, MS-DOS does not like to know about CHS... */
                   1078:     if (floppy)
                   1079:        bs->heads = bs->cyls = bs->secs = 0;
                   1080: 
                   1081:     //    assert(is_consistent(s));
                   1082:     return 0;
                   1083: }
                   1084: 
                   1085: static inline void vvfat_close_current_file(BDRVVVFATState *s)
                   1086: {
                   1087:     if(s->current_mapping) {
                   1088:        s->current_mapping = NULL;
                   1089:        if (s->current_fd) {
                   1090:                close(s->current_fd);
                   1091:                s->current_fd = 0;
                   1092:        }
                   1093:     }
                   1094:     s->current_cluster = -1;
                   1095: }
                   1096: 
                   1097: /* mappings between index1 and index2-1 are supposed to be ordered
                   1098:  * return value is the index of the last mapping for which end>cluster_num
                   1099:  */
                   1100: static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
                   1101: {
                   1102:     while(1) {
1.1.1.5 ! root     1103:         int index3;
1.1       root     1104:        mapping_t* mapping;
                   1105:        index3=(index1+index2)/2;
                   1106:        mapping=array_get(&(s->mapping),index3);
                   1107:        assert(mapping->begin < mapping->end);
                   1108:        if(mapping->begin>=cluster_num) {
                   1109:            assert(index2!=index3 || index2==0);
                   1110:            if(index2==index3)
                   1111:                return index1;
                   1112:            index2=index3;
                   1113:        } else {
                   1114:            if(index1==index3)
                   1115:                return mapping->end<=cluster_num ? index2 : index1;
                   1116:            index1=index3;
                   1117:        }
                   1118:        assert(index1<=index2);
                   1119:        DLOG(mapping=array_get(&(s->mapping),index1);
                   1120:        assert(mapping->begin<=cluster_num);
                   1121:        assert(index2 >= s->mapping.next ||
                   1122:                ((mapping = array_get(&(s->mapping),index2)) &&
                   1123:                mapping->end>cluster_num)));
                   1124:     }
                   1125: }
                   1126: 
                   1127: static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_num)
                   1128: {
                   1129:     int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
                   1130:     mapping_t* mapping;
                   1131:     if(index>=s->mapping.next)
                   1132:         return NULL;
                   1133:     mapping=array_get(&(s->mapping),index);
                   1134:     if(mapping->begin>cluster_num)
                   1135:         return NULL;
                   1136:     assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
                   1137:     return mapping;
                   1138: }
                   1139: 
                   1140: /*
                   1141:  * This function simply compares path == mapping->path. Since the mappings
                   1142:  * are sorted by cluster, this is expensive: O(n).
                   1143:  */
                   1144: static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
                   1145:        const char* path)
                   1146: {
                   1147:     int i;
                   1148: 
                   1149:     for (i = 0; i < s->mapping.next; i++) {
                   1150:        mapping_t* mapping = array_get(&(s->mapping), i);
                   1151:        if (mapping->first_mapping_index < 0 &&
                   1152:                !strcmp(path, mapping->path))
                   1153:            return mapping;
                   1154:     }
                   1155: 
                   1156:     return NULL;
                   1157: }
                   1158: 
                   1159: static int open_file(BDRVVVFATState* s,mapping_t* mapping)
                   1160: {
                   1161:     if(!mapping)
                   1162:        return -1;
                   1163:     if(!s->current_mapping ||
                   1164:            strcmp(s->current_mapping->path,mapping->path)) {
                   1165:        /* open file */
                   1166:        int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
                   1167:        if(fd<0)
                   1168:            return -1;
                   1169:        vvfat_close_current_file(s);
                   1170:        s->current_fd = fd;
                   1171:        s->current_mapping = mapping;
                   1172:     }
                   1173:     return 0;
                   1174: }
                   1175: 
                   1176: static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
                   1177: {
                   1178:     if(s->current_cluster != cluster_num) {
                   1179:        int result=0;
                   1180:        off_t offset;
                   1181:        assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
                   1182:        if(!s->current_mapping
                   1183:                || s->current_mapping->begin>cluster_num
                   1184:                || s->current_mapping->end<=cluster_num) {
                   1185:            /* binary search of mappings for file */
                   1186:            mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
                   1187: 
                   1188:            assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
                   1189: 
                   1190:            if (mapping && mapping->mode & MODE_DIRECTORY) {
                   1191:                vvfat_close_current_file(s);
                   1192:                s->current_mapping = mapping;
                   1193: read_cluster_directory:
                   1194:                offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
                   1195:                s->cluster = (unsigned char*)s->directory.pointer+offset
                   1196:                        + 0x20*s->current_mapping->info.dir.first_dir_index;
                   1197:                assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
                   1198:                assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
                   1199:                s->current_cluster = cluster_num;
                   1200:                return 0;
                   1201:            }
                   1202: 
                   1203:            if(open_file(s,mapping))
                   1204:                return -2;
                   1205:        } else if (s->current_mapping->mode & MODE_DIRECTORY)
                   1206:            goto read_cluster_directory;
                   1207: 
                   1208:        assert(s->current_fd);
                   1209: 
                   1210:        offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
                   1211:        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
                   1212:            return -3;
                   1213:        s->cluster=s->cluster_buffer;
                   1214:        result=read(s->current_fd,s->cluster,s->cluster_size);
                   1215:        if(result<0) {
                   1216:            s->current_cluster = -1;
                   1217:            return -1;
                   1218:        }
                   1219:        s->current_cluster = cluster_num;
                   1220:     }
                   1221:     return 0;
                   1222: }
                   1223: 
                   1224: #ifdef DEBUG
                   1225: static void hexdump(const void* address, uint32_t len)
                   1226: {
                   1227:     const unsigned char* p = address;
                   1228:     int i, j;
                   1229: 
                   1230:     for (i = 0; i < len; i += 16) {
                   1231:        for (j = 0; j < 16 && i + j < len; j++)
                   1232:            fprintf(stderr, "%02x ", p[i + j]);
                   1233:        for (; j < 16; j++)
                   1234:            fprintf(stderr, "   ");
                   1235:        fprintf(stderr, " ");
                   1236:        for (j = 0; j < 16 && i + j < len; j++)
                   1237:            fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
                   1238:        fprintf(stderr, "\n");
                   1239:     }
                   1240: }
                   1241: 
                   1242: static void print_direntry(const direntry_t* direntry)
                   1243: {
                   1244:     int j = 0;
                   1245:     char buffer[1024];
                   1246: 
1.1.1.5 ! root     1247:     fprintf(stderr, "direntry %p: ", direntry);
1.1       root     1248:     if(!direntry)
                   1249:        return;
                   1250:     if(is_long_name(direntry)) {
                   1251:        unsigned char* c=(unsigned char*)direntry;
                   1252:        int i;
                   1253:        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
                   1254: #define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
                   1255:            ADD_CHAR(c[i]);
                   1256:        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
                   1257:            ADD_CHAR(c[i]);
                   1258:        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
                   1259:            ADD_CHAR(c[i]);
                   1260:        buffer[j] = 0;
                   1261:        fprintf(stderr, "%s\n", buffer);
                   1262:     } else {
                   1263:        int i;
                   1264:        for(i=0;i<11;i++)
                   1265:            ADD_CHAR(direntry->name[i]);
                   1266:        buffer[j] = 0;
                   1267:        fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
                   1268:                buffer,
                   1269:                direntry->attributes,
                   1270:                begin_of_direntry(direntry),le32_to_cpu(direntry->size));
                   1271:     }
                   1272: }
                   1273: 
                   1274: static void print_mapping(const mapping_t* mapping)
                   1275: {
1.1.1.5 ! root     1276:     fprintf(stderr, "mapping (%p): begin, end = %d, %d, dir_index = %d, "
        !          1277:         "first_mapping_index = %d, name = %s, mode = 0x%x, " ,
        !          1278:         mapping, mapping->begin, mapping->end, mapping->dir_index,
        !          1279:         mapping->first_mapping_index, mapping->path, mapping->mode);
        !          1280: 
1.1       root     1281:     if (mapping->mode & MODE_DIRECTORY)
                   1282:        fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
                   1283:     else
                   1284:        fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
                   1285: }
                   1286: #endif
                   1287: 
                   1288: static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
                   1289:                     uint8_t *buf, int nb_sectors)
                   1290: {
                   1291:     BDRVVVFATState *s = bs->opaque;
                   1292:     int i;
                   1293: 
                   1294:     for(i=0;i<nb_sectors;i++,sector_num++) {
                   1295:        if (sector_num >= s->sector_count)
                   1296:           return -1;
                   1297:        if (s->qcow) {
                   1298:            int n;
                   1299:            if (s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1300:                        sector_num, nb_sectors-i, &n)) {
                   1301: DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
                   1302:                if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
                   1303:                    return -1;
                   1304:                i += n - 1;
                   1305:                sector_num += n - 1;
                   1306:                continue;
                   1307:            }
                   1308: DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
                   1309:        }
                   1310:        if(sector_num<s->faked_sectors) {
                   1311:            if(sector_num<s->first_sectors_number)
                   1312:                memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
                   1313:            else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
                   1314:                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
                   1315:            else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
                   1316:                memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
                   1317:        } else {
                   1318:            uint32_t sector=sector_num-s->faked_sectors,
                   1319:            sector_offset_in_cluster=(sector%s->sectors_per_cluster),
                   1320:            cluster_num=sector/s->sectors_per_cluster;
                   1321:            if(read_cluster(s, cluster_num) != 0) {
                   1322:                /* LATER TODO: strict: return -1; */
                   1323:                memset(buf+i*0x200,0,0x200);
                   1324:                continue;
                   1325:            }
                   1326:            memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
                   1327:        }
                   1328:     }
                   1329:     return 0;
                   1330: }
                   1331: 
                   1332: /* LATER TODO: statify all functions */
                   1333: 
                   1334: /*
                   1335:  * Idea of the write support (use snapshot):
                   1336:  *
                   1337:  * 1. check if all data is consistent, recording renames, modifications,
                   1338:  *    new files and directories (in s->commits).
                   1339:  *
                   1340:  * 2. if the data is not consistent, stop committing
                   1341:  *
                   1342:  * 3. handle renames, and create new files and directories (do not yet
                   1343:  *    write their contents)
                   1344:  *
                   1345:  * 4. walk the directories, fixing the mapping and direntries, and marking
                   1346:  *    the handled mappings as not deleted
                   1347:  *
                   1348:  * 5. commit the contents of the files
                   1349:  *
                   1350:  * 6. handle deleted files and directories
                   1351:  *
                   1352:  */
                   1353: 
                   1354: typedef struct commit_t {
                   1355:     char* path;
                   1356:     union {
                   1357:        struct { uint32_t cluster; } rename;
                   1358:        struct { int dir_index; uint32_t modified_offset; } writeout;
                   1359:        struct { uint32_t first_cluster; } new_file;
                   1360:        struct { uint32_t cluster; } mkdir;
                   1361:     } param;
                   1362:     /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
                   1363:     enum {
                   1364:        ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
                   1365:     } action;
                   1366: } commit_t;
                   1367: 
                   1368: static void clear_commits(BDRVVVFATState* s)
                   1369: {
                   1370:     int i;
                   1371: DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
                   1372:     for (i = 0; i < s->commits.next; i++) {
                   1373:        commit_t* commit = array_get(&(s->commits), i);
                   1374:        assert(commit->path || commit->action == ACTION_WRITEOUT);
                   1375:        if (commit->action != ACTION_WRITEOUT) {
                   1376:            assert(commit->path);
                   1377:            free(commit->path);
                   1378:        } else
                   1379:            assert(commit->path == NULL);
                   1380:     }
                   1381:     s->commits.next = 0;
                   1382: }
                   1383: 
                   1384: static void schedule_rename(BDRVVVFATState* s,
                   1385:        uint32_t cluster, char* new_path)
                   1386: {
                   1387:     commit_t* commit = array_get_next(&(s->commits));
                   1388:     commit->path = new_path;
                   1389:     commit->param.rename.cluster = cluster;
                   1390:     commit->action = ACTION_RENAME;
                   1391: }
                   1392: 
                   1393: static void schedule_writeout(BDRVVVFATState* s,
                   1394:        int dir_index, uint32_t modified_offset)
                   1395: {
                   1396:     commit_t* commit = array_get_next(&(s->commits));
                   1397:     commit->path = NULL;
                   1398:     commit->param.writeout.dir_index = dir_index;
                   1399:     commit->param.writeout.modified_offset = modified_offset;
                   1400:     commit->action = ACTION_WRITEOUT;
                   1401: }
                   1402: 
                   1403: static void schedule_new_file(BDRVVVFATState* s,
                   1404:        char* path, uint32_t first_cluster)
                   1405: {
                   1406:     commit_t* commit = array_get_next(&(s->commits));
                   1407:     commit->path = path;
                   1408:     commit->param.new_file.first_cluster = first_cluster;
                   1409:     commit->action = ACTION_NEW_FILE;
                   1410: }
                   1411: 
                   1412: static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
                   1413: {
                   1414:     commit_t* commit = array_get_next(&(s->commits));
                   1415:     commit->path = path;
                   1416:     commit->param.mkdir.cluster = cluster;
                   1417:     commit->action = ACTION_MKDIR;
                   1418: }
                   1419: 
                   1420: typedef struct {
                   1421:     /*
                   1422:      * Since the sequence number is at most 0x3f, and the filename
                   1423:      * length is at most 13 times the sequence number, the maximal
                   1424:      * filename length is 0x3f * 13 bytes.
                   1425:      */
                   1426:     unsigned char name[0x3f * 13 + 1];
                   1427:     int checksum, len;
                   1428:     int sequence_number;
                   1429: } long_file_name;
                   1430: 
                   1431: static void lfn_init(long_file_name* lfn)
                   1432: {
                   1433:    lfn->sequence_number = lfn->len = 0;
                   1434:    lfn->checksum = 0x100;
                   1435: }
                   1436: 
                   1437: /* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
                   1438: static int parse_long_name(long_file_name* lfn,
                   1439:        const direntry_t* direntry)
                   1440: {
                   1441:     int i, j, offset;
                   1442:     const unsigned char* pointer = (const unsigned char*)direntry;
                   1443: 
                   1444:     if (!is_long_name(direntry))
                   1445:        return 1;
                   1446: 
                   1447:     if (pointer[0] & 0x40) {
                   1448:        lfn->sequence_number = pointer[0] & 0x3f;
                   1449:        lfn->checksum = pointer[13];
                   1450:        lfn->name[0] = 0;
                   1451:        lfn->name[lfn->sequence_number * 13] = 0;
                   1452:     } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
                   1453:        return -1;
                   1454:     else if (pointer[13] != lfn->checksum)
                   1455:        return -2;
                   1456:     else if (pointer[12] || pointer[26] || pointer[27])
                   1457:        return -3;
                   1458: 
                   1459:     offset = 13 * (lfn->sequence_number - 1);
                   1460:     for (i = 0, j = 1; i < 13; i++, j+=2) {
                   1461:        if (j == 11)
                   1462:            j = 14;
                   1463:        else if (j == 26)
                   1464:            j = 28;
                   1465: 
                   1466:        if (pointer[j+1] == 0)
                   1467:            lfn->name[offset + i] = pointer[j];
                   1468:        else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
                   1469:            return -4;
                   1470:        else
                   1471:            lfn->name[offset + i] = 0;
                   1472:     }
                   1473: 
                   1474:     if (pointer[0] & 0x40)
                   1475:        lfn->len = offset + strlen((char*)lfn->name + offset);
                   1476: 
                   1477:     return 0;
                   1478: }
                   1479: 
                   1480: /* returns 0 if successful, >0 if no short_name, and <0 on error */
                   1481: static int parse_short_name(BDRVVVFATState* s,
                   1482:        long_file_name* lfn, direntry_t* direntry)
                   1483: {
                   1484:     int i, j;
                   1485: 
                   1486:     if (!is_short_name(direntry))
                   1487:        return 1;
                   1488: 
                   1489:     for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
                   1490:     for (i = 0; i <= j; i++) {
                   1491:        if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
                   1492:            return -1;
                   1493:        else if (s->downcase_short_names)
                   1494:            lfn->name[i] = qemu_tolower(direntry->name[i]);
                   1495:        else
                   1496:            lfn->name[i] = direntry->name[i];
                   1497:     }
                   1498: 
                   1499:     for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
                   1500:     if (j >= 0) {
                   1501:        lfn->name[i++] = '.';
                   1502:        lfn->name[i + j + 1] = '\0';
                   1503:        for (;j >= 0; j--) {
                   1504:            if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
                   1505:                return -2;
                   1506:            else if (s->downcase_short_names)
                   1507:                lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
                   1508:            else
                   1509:                lfn->name[i + j] = direntry->extension[j];
                   1510:        }
                   1511:     } else
                   1512:        lfn->name[i + j + 1] = '\0';
                   1513: 
                   1514:     lfn->len = strlen((char*)lfn->name);
                   1515: 
                   1516:     return 0;
                   1517: }
                   1518: 
                   1519: static inline uint32_t modified_fat_get(BDRVVVFATState* s,
                   1520:        unsigned int cluster)
                   1521: {
                   1522:     if (cluster < s->last_cluster_of_root_directory) {
                   1523:        if (cluster + 1 == s->last_cluster_of_root_directory)
                   1524:            return s->max_fat_value;
                   1525:        else
                   1526:            return cluster + 1;
                   1527:     }
                   1528: 
                   1529:     if (s->fat_type==32) {
                   1530:         uint32_t* entry=((uint32_t*)s->fat2)+cluster;
                   1531:         return le32_to_cpu(*entry);
                   1532:     } else if (s->fat_type==16) {
                   1533:         uint16_t* entry=((uint16_t*)s->fat2)+cluster;
                   1534:         return le16_to_cpu(*entry);
                   1535:     } else {
                   1536:         const uint8_t* x=s->fat2+cluster*3/2;
                   1537:         return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
                   1538:     }
                   1539: }
                   1540: 
                   1541: static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
                   1542: {
                   1543:     int was_modified = 0;
                   1544:     int i, dummy;
                   1545: 
                   1546:     if (s->qcow == NULL)
                   1547:        return 0;
                   1548: 
                   1549:     for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
                   1550:        was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1551:                cluster2sector(s, cluster_num) + i, 1, &dummy);
                   1552: 
                   1553:     return was_modified;
                   1554: }
                   1555: 
                   1556: static const char* get_basename(const char* path)
                   1557: {
                   1558:     char* basename = strrchr(path, '/');
                   1559:     if (basename == NULL)
                   1560:        return path;
                   1561:     else
                   1562:        return basename + 1; /* strip '/' */
                   1563: }
                   1564: 
                   1565: /*
                   1566:  * The array s->used_clusters holds the states of the clusters. If it is
                   1567:  * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
                   1568:  * was modified, bit 3 is set.
                   1569:  * If any cluster is allocated, but not part of a file or directory, this
                   1570:  * driver refuses to commit.
                   1571:  */
                   1572: typedef enum {
                   1573:      USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
                   1574: } used_t;
                   1575: 
                   1576: /*
                   1577:  * get_cluster_count_for_direntry() not only determines how many clusters
                   1578:  * are occupied by direntry, but also if it was renamed or modified.
                   1579:  *
                   1580:  * A file is thought to be renamed *only* if there already was a file with
                   1581:  * exactly the same first cluster, but a different name.
                   1582:  *
                   1583:  * Further, the files/directories handled by this function are
                   1584:  * assumed to be *not* deleted (and *only* those).
                   1585:  */
                   1586: static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
                   1587:        direntry_t* direntry, const char* path)
                   1588: {
                   1589:     /*
                   1590:      * This is a little bit tricky:
                   1591:      * IF the guest OS just inserts a cluster into the file chain,
                   1592:      * and leaves the rest alone, (i.e. the original file had clusters
                   1593:      * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
                   1594:      *
                   1595:      * - do_commit will write the cluster into the file at the given
                   1596:      *   offset, but
                   1597:      *
                   1598:      * - the cluster which is overwritten should be moved to a later
                   1599:      *   position in the file.
                   1600:      *
                   1601:      * I am not aware that any OS does something as braindead, but this
                   1602:      * situation could happen anyway when not committing for a long time.
                   1603:      * Just to be sure that this does not bite us, detect it, and copy the
                   1604:      * contents of the clusters to-be-overwritten into the qcow.
                   1605:      */
                   1606:     int copy_it = 0;
                   1607:     int was_modified = 0;
                   1608:     int32_t ret = 0;
                   1609: 
                   1610:     uint32_t cluster_num = begin_of_direntry(direntry);
                   1611:     uint32_t offset = 0;
                   1612:     int first_mapping_index = -1;
                   1613:     mapping_t* mapping = NULL;
                   1614:     const char* basename2 = NULL;
                   1615: 
                   1616:     vvfat_close_current_file(s);
                   1617: 
                   1618:     /* the root directory */
                   1619:     if (cluster_num == 0)
                   1620:        return 0;
                   1621: 
                   1622:     /* write support */
                   1623:     if (s->qcow) {
                   1624:        basename2 = get_basename(path);
                   1625: 
                   1626:        mapping = find_mapping_for_cluster(s, cluster_num);
                   1627: 
                   1628:        if (mapping) {
                   1629:            const char* basename;
                   1630: 
                   1631:            assert(mapping->mode & MODE_DELETED);
                   1632:            mapping->mode &= ~MODE_DELETED;
                   1633: 
                   1634:            basename = get_basename(mapping->path);
                   1635: 
                   1636:            assert(mapping->mode & MODE_NORMAL);
                   1637: 
                   1638:            /* rename */
                   1639:            if (strcmp(basename, basename2))
1.1.1.3   root     1640:                schedule_rename(s, cluster_num, qemu_strdup(path));
1.1       root     1641:        } else if (is_file(direntry))
                   1642:            /* new file */
1.1.1.3   root     1643:            schedule_new_file(s, qemu_strdup(path), cluster_num);
1.1       root     1644:        else {
1.1.1.5 ! root     1645:             abort();
1.1       root     1646:            return 0;
                   1647:        }
                   1648:     }
                   1649: 
                   1650:     while(1) {
                   1651:        if (s->qcow) {
                   1652:            if (!copy_it && cluster_was_modified(s, cluster_num)) {
                   1653:                if (mapping == NULL ||
                   1654:                        mapping->begin > cluster_num ||
                   1655:                        mapping->end <= cluster_num)
                   1656:                mapping = find_mapping_for_cluster(s, cluster_num);
                   1657: 
                   1658: 
                   1659:                if (mapping &&
                   1660:                        (mapping->mode & MODE_DIRECTORY) == 0) {
                   1661: 
                   1662:                    /* was modified in qcow */
                   1663:                    if (offset != mapping->info.file.offset + s->cluster_size
                   1664:                            * (cluster_num - mapping->begin)) {
                   1665:                        /* offset of this cluster in file chain has changed */
1.1.1.5 ! root     1666:                         abort();
1.1       root     1667:                        copy_it = 1;
                   1668:                    } else if (offset == 0) {
                   1669:                        const char* basename = get_basename(mapping->path);
                   1670: 
                   1671:                        if (strcmp(basename, basename2))
                   1672:                            copy_it = 1;
                   1673:                        first_mapping_index = array_index(&(s->mapping), mapping);
                   1674:                    }
                   1675: 
                   1676:                    if (mapping->first_mapping_index != first_mapping_index
                   1677:                            && mapping->info.file.offset > 0) {
1.1.1.5 ! root     1678:                         abort();
1.1       root     1679:                        copy_it = 1;
                   1680:                    }
                   1681: 
                   1682:                    /* need to write out? */
                   1683:                    if (!was_modified && is_file(direntry)) {
                   1684:                        was_modified = 1;
                   1685:                        schedule_writeout(s, mapping->dir_index, offset);
                   1686:                    }
                   1687:                }
                   1688:            }
                   1689: 
                   1690:            if (copy_it) {
                   1691:                int i, dummy;
                   1692:                /*
                   1693:                 * This is horribly inefficient, but that is okay, since
                   1694:                 * it is rarely executed, if at all.
                   1695:                 */
                   1696:                int64_t offset = cluster2sector(s, cluster_num);
                   1697: 
                   1698:                vvfat_close_current_file(s);
                   1699:                for (i = 0; i < s->sectors_per_cluster; i++)
                   1700:                    if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
                   1701:                                offset + i, 1, &dummy)) {
                   1702:                        if (vvfat_read(s->bs,
                   1703:                                    offset, s->cluster_buffer, 1))
                   1704:                            return -1;
                   1705:                        if (s->qcow->drv->bdrv_write(s->qcow,
                   1706:                                    offset, s->cluster_buffer, 1))
                   1707:                            return -2;
                   1708:                    }
                   1709:            }
                   1710:        }
                   1711: 
                   1712:        ret++;
                   1713:        if (s->used_clusters[cluster_num] & USED_ANY)
                   1714:            return 0;
                   1715:        s->used_clusters[cluster_num] = USED_FILE;
                   1716: 
                   1717:        cluster_num = modified_fat_get(s, cluster_num);
                   1718: 
                   1719:        if (fat_eof(s, cluster_num))
                   1720:            return ret;
                   1721:        else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
                   1722:            return -1;
                   1723: 
                   1724:        offset += s->cluster_size;
                   1725:     }
                   1726: }
                   1727: 
                   1728: /*
                   1729:  * This function looks at the modified data (qcow).
                   1730:  * It returns 0 upon inconsistency or error, and the number of clusters
                   1731:  * used by the directory, its subdirectories and their files.
                   1732:  */
                   1733: static int check_directory_consistency(BDRVVVFATState *s,
                   1734:        int cluster_num, const char* path)
                   1735: {
                   1736:     int ret = 0;
                   1737:     unsigned char* cluster = qemu_malloc(s->cluster_size);
                   1738:     direntry_t* direntries = (direntry_t*)cluster;
                   1739:     mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
                   1740: 
                   1741:     long_file_name lfn;
                   1742:     int path_len = strlen(path);
                   1743:     char path2[PATH_MAX];
                   1744: 
                   1745:     assert(path_len < PATH_MAX); /* len was tested before! */
                   1746:     pstrcpy(path2, sizeof(path2), path);
                   1747:     path2[path_len] = '/';
                   1748:     path2[path_len + 1] = '\0';
                   1749: 
                   1750:     if (mapping) {
                   1751:        const char* basename = get_basename(mapping->path);
                   1752:        const char* basename2 = get_basename(path);
                   1753: 
                   1754:        assert(mapping->mode & MODE_DIRECTORY);
                   1755: 
                   1756:        assert(mapping->mode & MODE_DELETED);
                   1757:        mapping->mode &= ~MODE_DELETED;
                   1758: 
                   1759:        if (strcmp(basename, basename2))
1.1.1.3   root     1760:            schedule_rename(s, cluster_num, qemu_strdup(path));
1.1       root     1761:     } else
                   1762:        /* new directory */
1.1.1.3   root     1763:        schedule_mkdir(s, cluster_num, qemu_strdup(path));
1.1       root     1764: 
                   1765:     lfn_init(&lfn);
                   1766:     do {
                   1767:        int i;
                   1768:        int subret = 0;
                   1769: 
                   1770:        ret++;
                   1771: 
                   1772:        if (s->used_clusters[cluster_num] & USED_ANY) {
                   1773:            fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
                   1774:            return 0;
                   1775:        }
                   1776:        s->used_clusters[cluster_num] = USED_DIRECTORY;
                   1777: 
                   1778: DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
                   1779:        subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
                   1780:                s->sectors_per_cluster);
                   1781:        if (subret) {
                   1782:            fprintf(stderr, "Error fetching direntries\n");
                   1783:        fail:
                   1784:            free(cluster);
                   1785:            return 0;
                   1786:        }
                   1787: 
                   1788:        for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
                   1789:            int cluster_count = 0;
                   1790: 
                   1791: DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
                   1792:            if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
                   1793:                    is_free(direntries + i))
                   1794:                continue;
                   1795: 
                   1796:            subret = parse_long_name(&lfn, direntries + i);
                   1797:            if (subret < 0) {
                   1798:                fprintf(stderr, "Error in long name\n");
                   1799:                goto fail;
                   1800:            }
                   1801:            if (subret == 0 || is_free(direntries + i))
                   1802:                continue;
                   1803: 
                   1804:            if (fat_chksum(direntries+i) != lfn.checksum) {
                   1805:                subret = parse_short_name(s, &lfn, direntries + i);
                   1806:                if (subret < 0) {
                   1807:                    fprintf(stderr, "Error in short name (%d)\n", subret);
                   1808:                    goto fail;
                   1809:                }
                   1810:                if (subret > 0 || !strcmp((char*)lfn.name, ".")
                   1811:                        || !strcmp((char*)lfn.name, ".."))
                   1812:                    continue;
                   1813:            }
                   1814:            lfn.checksum = 0x100; /* cannot use long name twice */
                   1815: 
                   1816:            if (path_len + 1 + lfn.len >= PATH_MAX) {
                   1817:                fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
                   1818:                goto fail;
                   1819:            }
                   1820:             pstrcpy(path2 + path_len + 1, sizeof(path2) - path_len - 1,
                   1821:                     (char*)lfn.name);
                   1822: 
                   1823:            if (is_directory(direntries + i)) {
                   1824:                if (begin_of_direntry(direntries + i) == 0) {
                   1825:                    DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
                   1826:                    goto fail;
                   1827:                }
                   1828:                cluster_count = check_directory_consistency(s,
                   1829:                        begin_of_direntry(direntries + i), path2);
                   1830:                if (cluster_count == 0) {
                   1831:                    DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
                   1832:                    goto fail;
                   1833:                }
                   1834:            } else if (is_file(direntries + i)) {
                   1835:                /* check file size with FAT */
                   1836:                cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
                   1837:                if (cluster_count !=
                   1838:                        (le32_to_cpu(direntries[i].size) + s->cluster_size
                   1839:                         - 1) / s->cluster_size) {
                   1840:                    DLOG(fprintf(stderr, "Cluster count mismatch\n"));
                   1841:                    goto fail;
                   1842:                }
                   1843:            } else
1.1.1.5 ! root     1844:                 abort(); /* cluster_count = 0; */
1.1       root     1845: 
                   1846:            ret += cluster_count;
                   1847:        }
                   1848: 
                   1849:        cluster_num = modified_fat_get(s, cluster_num);
                   1850:     } while(!fat_eof(s, cluster_num));
                   1851: 
                   1852:     free(cluster);
                   1853:     return ret;
                   1854: }
                   1855: 
                   1856: /* returns 1 on success */
                   1857: static int is_consistent(BDRVVVFATState* s)
                   1858: {
                   1859:     int i, check;
                   1860:     int used_clusters_count = 0;
                   1861: 
                   1862: DLOG(checkpoint());
                   1863:     /*
                   1864:      * - get modified FAT
                   1865:      * - compare the two FATs (TODO)
                   1866:      * - get buffer for marking used clusters
                   1867:      * - recurse direntries from root (using bs->bdrv_read to make
                   1868:      *    sure to get the new data)
                   1869:      *   - check that the FAT agrees with the size
                   1870:      *   - count the number of clusters occupied by this directory and
                   1871:      *     its files
                   1872:      * - check that the cumulative used cluster count agrees with the
                   1873:      *   FAT
                   1874:      * - if all is fine, return number of used clusters
                   1875:      */
                   1876:     if (s->fat2 == NULL) {
                   1877:        int size = 0x200 * s->sectors_per_fat;
                   1878:        s->fat2 = qemu_malloc(size);
                   1879:        memcpy(s->fat2, s->fat.pointer, size);
                   1880:     }
                   1881:     check = vvfat_read(s->bs,
                   1882:            s->first_sectors_number, s->fat2, s->sectors_per_fat);
                   1883:     if (check) {
                   1884:        fprintf(stderr, "Could not copy fat\n");
                   1885:        return 0;
                   1886:     }
                   1887:     assert (s->used_clusters);
                   1888:     for (i = 0; i < sector2cluster(s, s->sector_count); i++)
                   1889:        s->used_clusters[i] &= ~USED_ANY;
                   1890: 
                   1891:     clear_commits(s);
                   1892: 
                   1893:     /* mark every mapped file/directory as deleted.
                   1894:      * (check_directory_consistency() will unmark those still present). */
                   1895:     if (s->qcow)
                   1896:        for (i = 0; i < s->mapping.next; i++) {
                   1897:            mapping_t* mapping = array_get(&(s->mapping), i);
                   1898:            if (mapping->first_mapping_index < 0)
                   1899:                mapping->mode |= MODE_DELETED;
                   1900:        }
                   1901: 
                   1902:     used_clusters_count = check_directory_consistency(s, 0, s->path);
                   1903:     if (used_clusters_count <= 0) {
                   1904:        DLOG(fprintf(stderr, "problem in directory\n"));
                   1905:        return 0;
                   1906:     }
                   1907: 
                   1908:     check = s->last_cluster_of_root_directory;
                   1909:     for (i = check; i < sector2cluster(s, s->sector_count); i++) {
                   1910:        if (modified_fat_get(s, i)) {
                   1911:            if(!s->used_clusters[i]) {
                   1912:                DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
                   1913:                return 0;
                   1914:            }
                   1915:            check++;
                   1916:        }
                   1917: 
                   1918:        if (s->used_clusters[i] == USED_ALLOCATED) {
                   1919:            /* allocated, but not used... */
                   1920:            DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
                   1921:            return 0;
                   1922:        }
                   1923:     }
                   1924: 
                   1925:     if (check != used_clusters_count)
                   1926:        return 0;
                   1927: 
                   1928:     return used_clusters_count;
                   1929: }
                   1930: 
                   1931: static inline void adjust_mapping_indices(BDRVVVFATState* s,
                   1932:        int offset, int adjust)
                   1933: {
                   1934:     int i;
                   1935: 
                   1936:     for (i = 0; i < s->mapping.next; i++) {
                   1937:        mapping_t* mapping = array_get(&(s->mapping), i);
                   1938: 
                   1939: #define ADJUST_MAPPING_INDEX(name) \
                   1940:        if (mapping->name >= offset) \
                   1941:            mapping->name += adjust
                   1942: 
                   1943:        ADJUST_MAPPING_INDEX(first_mapping_index);
                   1944:        if (mapping->mode & MODE_DIRECTORY)
                   1945:            ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
                   1946:     }
                   1947: }
                   1948: 
                   1949: /* insert or update mapping */
                   1950: static mapping_t* insert_mapping(BDRVVVFATState* s,
                   1951:        uint32_t begin, uint32_t end)
                   1952: {
                   1953:     /*
                   1954:      * - find mapping where mapping->begin >= begin,
                   1955:      * - if mapping->begin > begin: insert
                   1956:      *   - adjust all references to mappings!
                   1957:      * - else: adjust
                   1958:      * - replace name
                   1959:      */
                   1960:     int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
                   1961:     mapping_t* mapping = NULL;
                   1962:     mapping_t* first_mapping = array_get(&(s->mapping), 0);
                   1963: 
                   1964:     if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
                   1965:            && mapping->begin < begin) {
                   1966:        mapping->end = begin;
                   1967:        index++;
                   1968:        mapping = array_get(&(s->mapping), index);
                   1969:     }
                   1970:     if (index >= s->mapping.next || mapping->begin > begin) {
                   1971:        mapping = array_insert(&(s->mapping), index, 1);
                   1972:        mapping->path = NULL;
                   1973:        adjust_mapping_indices(s, index, +1);
                   1974:     }
                   1975: 
                   1976:     mapping->begin = begin;
                   1977:     mapping->end = end;
                   1978: 
                   1979: DLOG(mapping_t* next_mapping;
                   1980: assert(index + 1 >= s->mapping.next ||
                   1981: ((next_mapping = array_get(&(s->mapping), index + 1)) &&
                   1982:  next_mapping->begin >= end)));
                   1983: 
                   1984:     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
                   1985:        s->current_mapping = array_get(&(s->mapping),
                   1986:                s->current_mapping - first_mapping);
                   1987: 
                   1988:     return mapping;
                   1989: }
                   1990: 
                   1991: static int remove_mapping(BDRVVVFATState* s, int mapping_index)
                   1992: {
                   1993:     mapping_t* mapping = array_get(&(s->mapping), mapping_index);
                   1994:     mapping_t* first_mapping = array_get(&(s->mapping), 0);
                   1995: 
                   1996:     /* free mapping */
                   1997:     if (mapping->first_mapping_index < 0)
                   1998:        free(mapping->path);
                   1999: 
                   2000:     /* remove from s->mapping */
                   2001:     array_remove(&(s->mapping), mapping_index);
                   2002: 
                   2003:     /* adjust all references to mappings */
                   2004:     adjust_mapping_indices(s, mapping_index, -1);
                   2005: 
                   2006:     if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
                   2007:        s->current_mapping = array_get(&(s->mapping),
                   2008:                s->current_mapping - first_mapping);
                   2009: 
                   2010:     return 0;
                   2011: }
                   2012: 
                   2013: static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
                   2014: {
                   2015:     int i;
                   2016:     for (i = 0; i < s->mapping.next; i++) {
                   2017:        mapping_t* mapping = array_get(&(s->mapping), i);
                   2018:        if (mapping->dir_index >= offset)
                   2019:            mapping->dir_index += adjust;
                   2020:        if ((mapping->mode & MODE_DIRECTORY) &&
                   2021:                mapping->info.dir.first_dir_index >= offset)
                   2022:            mapping->info.dir.first_dir_index += adjust;
                   2023:     }
                   2024: }
                   2025: 
                   2026: static direntry_t* insert_direntries(BDRVVVFATState* s,
                   2027:        int dir_index, int count)
                   2028: {
                   2029:     /*
                   2030:      * make room in s->directory,
                   2031:      * adjust_dirindices
                   2032:      */
                   2033:     direntry_t* result = array_insert(&(s->directory), dir_index, count);
                   2034:     if (result == NULL)
                   2035:        return NULL;
                   2036:     adjust_dirindices(s, dir_index, count);
                   2037:     return result;
                   2038: }
                   2039: 
                   2040: static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
                   2041: {
                   2042:     int ret = array_remove_slice(&(s->directory), dir_index, count);
                   2043:     if (ret)
                   2044:        return ret;
                   2045:     adjust_dirindices(s, dir_index, -count);
                   2046:     return 0;
                   2047: }
                   2048: 
                   2049: /*
                   2050:  * Adapt the mappings of the cluster chain starting at first cluster
                   2051:  * (i.e. if a file starts at first_cluster, the chain is followed according
                   2052:  * to the modified fat, and the corresponding entries in s->mapping are
                   2053:  * adjusted)
                   2054:  */
                   2055: static int commit_mappings(BDRVVVFATState* s,
                   2056:        uint32_t first_cluster, int dir_index)
                   2057: {
                   2058:     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
                   2059:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2060:     uint32_t cluster = first_cluster;
                   2061: 
                   2062:     vvfat_close_current_file(s);
                   2063: 
                   2064:     assert(mapping);
                   2065:     assert(mapping->begin == first_cluster);
                   2066:     mapping->first_mapping_index = -1;
                   2067:     mapping->dir_index = dir_index;
                   2068:     mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
                   2069:        MODE_DIRECTORY : MODE_NORMAL;
                   2070: 
                   2071:     while (!fat_eof(s, cluster)) {
                   2072:        uint32_t c, c1;
                   2073: 
                   2074:        for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
                   2075:                c = c1, c1 = modified_fat_get(s, c1));
                   2076: 
                   2077:        c++;
                   2078:        if (c > mapping->end) {
                   2079:            int index = array_index(&(s->mapping), mapping);
                   2080:            int i, max_i = s->mapping.next - index;
                   2081:            for (i = 1; i < max_i && mapping[i].begin < c; i++);
                   2082:            while (--i > 0)
                   2083:                remove_mapping(s, index + 1);
                   2084:        }
                   2085:        assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
                   2086:                || mapping[1].begin >= c);
                   2087:        mapping->end = c;
                   2088: 
                   2089:        if (!fat_eof(s, c1)) {
                   2090:            int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
                   2091:            mapping_t* next_mapping = i >= s->mapping.next ? NULL :
                   2092:                array_get(&(s->mapping), i);
                   2093: 
                   2094:            if (next_mapping == NULL || next_mapping->begin > c1) {
                   2095:                int i1 = array_index(&(s->mapping), mapping);
                   2096: 
                   2097:                next_mapping = insert_mapping(s, c1, c1+1);
                   2098: 
                   2099:                if (c1 < c)
                   2100:                    i1++;
                   2101:                mapping = array_get(&(s->mapping), i1);
                   2102:            }
                   2103: 
                   2104:            next_mapping->dir_index = mapping->dir_index;
                   2105:            next_mapping->first_mapping_index =
                   2106:                mapping->first_mapping_index < 0 ?
                   2107:                array_index(&(s->mapping), mapping) :
                   2108:                mapping->first_mapping_index;
                   2109:            next_mapping->path = mapping->path;
                   2110:            next_mapping->mode = mapping->mode;
                   2111:            next_mapping->read_only = mapping->read_only;
                   2112:            if (mapping->mode & MODE_DIRECTORY) {
                   2113:                next_mapping->info.dir.parent_mapping_index =
                   2114:                        mapping->info.dir.parent_mapping_index;
                   2115:                next_mapping->info.dir.first_dir_index =
                   2116:                        mapping->info.dir.first_dir_index +
                   2117:                        0x10 * s->sectors_per_cluster *
                   2118:                        (mapping->end - mapping->begin);
                   2119:            } else
                   2120:                next_mapping->info.file.offset = mapping->info.file.offset +
                   2121:                        mapping->end - mapping->begin;
                   2122: 
                   2123:            mapping = next_mapping;
                   2124:        }
                   2125: 
                   2126:        cluster = c1;
                   2127:     }
                   2128: 
                   2129:     return 0;
                   2130: }
                   2131: 
                   2132: static int commit_direntries(BDRVVVFATState* s,
                   2133:        int dir_index, int parent_mapping_index)
                   2134: {
                   2135:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2136:     uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
                   2137:     mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
                   2138: 
                   2139:     int factor = 0x10 * s->sectors_per_cluster;
                   2140:     int old_cluster_count, new_cluster_count;
                   2141:     int current_dir_index = mapping->info.dir.first_dir_index;
                   2142:     int first_dir_index = current_dir_index;
                   2143:     int ret, i;
                   2144:     uint32_t c;
                   2145: 
                   2146: DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
                   2147: 
                   2148:     assert(direntry);
                   2149:     assert(mapping);
                   2150:     assert(mapping->begin == first_cluster);
                   2151:     assert(mapping->info.dir.first_dir_index < s->directory.next);
                   2152:     assert(mapping->mode & MODE_DIRECTORY);
                   2153:     assert(dir_index == 0 || is_directory(direntry));
                   2154: 
                   2155:     mapping->info.dir.parent_mapping_index = parent_mapping_index;
                   2156: 
                   2157:     if (first_cluster == 0) {
                   2158:        old_cluster_count = new_cluster_count =
                   2159:            s->last_cluster_of_root_directory;
                   2160:     } else {
                   2161:        for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
                   2162:                c = fat_get(s, c))
                   2163:            old_cluster_count++;
                   2164: 
                   2165:        for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
                   2166:                c = modified_fat_get(s, c))
                   2167:            new_cluster_count++;
                   2168:     }
                   2169: 
                   2170:     if (new_cluster_count > old_cluster_count) {
                   2171:        if (insert_direntries(s,
                   2172:                current_dir_index + factor * old_cluster_count,
                   2173:                factor * (new_cluster_count - old_cluster_count)) == NULL)
                   2174:            return -1;
                   2175:     } else if (new_cluster_count < old_cluster_count)
                   2176:        remove_direntries(s,
                   2177:                current_dir_index + factor * new_cluster_count,
                   2178:                factor * (old_cluster_count - new_cluster_count));
                   2179: 
                   2180:     for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
                   2181:        void* direntry = array_get(&(s->directory), current_dir_index);
                   2182:        int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
                   2183:                s->sectors_per_cluster);
                   2184:        if (ret)
                   2185:            return ret;
                   2186:        assert(!strncmp(s->directory.pointer, "QEMU", 4));
                   2187:        current_dir_index += factor;
                   2188:     }
                   2189: 
                   2190:     ret = commit_mappings(s, first_cluster, dir_index);
                   2191:     if (ret)
                   2192:        return ret;
                   2193: 
                   2194:     /* recurse */
                   2195:     for (i = 0; i < factor * new_cluster_count; i++) {
                   2196:        direntry = array_get(&(s->directory), first_dir_index + i);
                   2197:        if (is_directory(direntry) && !is_dot(direntry)) {
                   2198:            mapping = find_mapping_for_cluster(s, first_cluster);
                   2199:            assert(mapping->mode & MODE_DIRECTORY);
                   2200:            ret = commit_direntries(s, first_dir_index + i,
                   2201:                array_index(&(s->mapping), mapping));
                   2202:            if (ret)
                   2203:                return ret;
                   2204:        }
                   2205:     }
                   2206: 
                   2207:     return 0;
                   2208: }
                   2209: 
                   2210: /* commit one file (adjust contents, adjust mapping),
                   2211:    return first_mapping_index */
                   2212: static int commit_one_file(BDRVVVFATState* s,
                   2213:        int dir_index, uint32_t offset)
                   2214: {
                   2215:     direntry_t* direntry = array_get(&(s->directory), dir_index);
                   2216:     uint32_t c = begin_of_direntry(direntry);
                   2217:     uint32_t first_cluster = c;
                   2218:     mapping_t* mapping = find_mapping_for_cluster(s, c);
                   2219:     uint32_t size = filesize_of_direntry(direntry);
                   2220:     char* cluster = qemu_malloc(s->cluster_size);
                   2221:     uint32_t i;
                   2222:     int fd = 0;
                   2223: 
                   2224:     assert(offset < size);
                   2225:     assert((offset % s->cluster_size) == 0);
                   2226: 
                   2227:     for (i = s->cluster_size; i < offset; i += s->cluster_size)
                   2228:        c = modified_fat_get(s, c);
                   2229: 
                   2230:     fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
                   2231:     if (fd < 0) {
                   2232:        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
                   2233:                strerror(errno), errno);
                   2234:        return fd;
                   2235:     }
                   2236:     if (offset > 0)
                   2237:        if (lseek(fd, offset, SEEK_SET) != offset)
                   2238:            return -3;
                   2239: 
                   2240:     while (offset < size) {
                   2241:        uint32_t c1;
                   2242:        int rest_size = (size - offset > s->cluster_size ?
                   2243:                s->cluster_size : size - offset);
                   2244:        int ret;
                   2245: 
                   2246:        c1 = modified_fat_get(s, c);
                   2247: 
                   2248:        assert((size - offset == 0 && fat_eof(s, c)) ||
                   2249:                (size > offset && c >=2 && !fat_eof(s, c)));
                   2250: 
                   2251:        ret = vvfat_read(s->bs, cluster2sector(s, c),
                   2252:            (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
                   2253: 
                   2254:        if (ret < 0)
                   2255:            return ret;
                   2256: 
                   2257:        if (write(fd, cluster, rest_size) < 0)
                   2258:            return -2;
                   2259: 
                   2260:        offset += rest_size;
                   2261:        c = c1;
                   2262:     }
                   2263: 
1.1.1.4   root     2264:     if (ftruncate(fd, size)) {
                   2265:         perror("ftruncate()");
                   2266:         close(fd);
                   2267:         return -4;
                   2268:     }
1.1       root     2269:     close(fd);
                   2270: 
                   2271:     return commit_mappings(s, first_cluster, dir_index);
                   2272: }
                   2273: 
                   2274: #ifdef DEBUG
                   2275: /* test, if all mappings point to valid direntries */
                   2276: static void check1(BDRVVVFATState* s)
                   2277: {
                   2278:     int i;
                   2279:     for (i = 0; i < s->mapping.next; i++) {
                   2280:        mapping_t* mapping = array_get(&(s->mapping), i);
                   2281:        if (mapping->mode & MODE_DELETED) {
                   2282:            fprintf(stderr, "deleted\n");
                   2283:            continue;
                   2284:        }
                   2285:        assert(mapping->dir_index >= 0);
                   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.