~vcs-imports/qemu/git

« back to all changes in this revision

Viewing changes to block-raw-win32.c

  • Committer: Blue Swirl
  • Date: 2009-08-31 15:14:40 UTC
  • Revision ID: git-v1:528e93a9787ccfc59582a44035f5f342caf5b84f
Fix breakage due to __thread

Thread-local storage is not supported on all hosts.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Block driver for RAW files (win32)
3
 
 *
4
 
 * Copyright (c) 2006 Fabrice Bellard
5
 
 *
6
 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 
 * of this software and associated documentation files (the "Software"), to deal
8
 
 * in the Software without restriction, including without limitation the rights
9
 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 
 * copies of the Software, and to permit persons to whom the Software is
11
 
 * furnished to do so, subject to the following conditions:
12
 
 *
13
 
 * The above copyright notice and this permission notice shall be included in
14
 
 * all copies or substantial portions of the Software.
15
 
 *
16
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 
 * THE SOFTWARE.
23
 
 */
24
 
#include "qemu-common.h"
25
 
#ifndef QEMU_IMG
26
 
#include "qemu-timer.h"
27
 
#include "exec-all.h"
28
 
#endif
29
 
#include "block_int.h"
30
 
#include <assert.h>
31
 
#include <winioctl.h>
32
 
 
33
 
#define FTYPE_FILE 0
34
 
#define FTYPE_CD     1
35
 
#define FTYPE_HARDDISK 2
36
 
 
37
 
typedef struct BDRVRawState {
38
 
    HANDLE hfile;
39
 
    int type;
40
 
    char drive_path[16]; /* format: "d:\" */
41
 
} BDRVRawState;
42
 
 
43
 
typedef struct RawAIOCB {
44
 
    BlockDriverAIOCB common;
45
 
    HANDLE hEvent;
46
 
    OVERLAPPED ov;
47
 
    int count;
48
 
} RawAIOCB;
49
 
 
50
 
int qemu_ftruncate64(int fd, int64_t length)
51
 
{
52
 
    LARGE_INTEGER li;
53
 
    LONG high;
54
 
    HANDLE h;
55
 
    BOOL res;
56
 
 
57
 
    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
58
 
        return -1;
59
 
 
60
 
    h = (HANDLE)_get_osfhandle(fd);
61
 
 
62
 
    /* get current position, ftruncate do not change position */
63
 
    li.HighPart = 0;
64
 
    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
65
 
    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
66
 
        return -1;
67
 
 
68
 
    high = length >> 32;
69
 
    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
70
 
        return -1;
71
 
    res = SetEndOfFile(h);
72
 
 
73
 
    /* back to old position */
74
 
    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
75
 
    return res ? 0 : -1;
76
 
}
77
 
 
78
 
static int set_sparse(int fd)
79
 
{
80
 
    DWORD returned;
81
 
    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
82
 
                                 NULL, 0, NULL, 0, &returned, NULL);
83
 
}
84
 
 
85
 
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
86
 
{
87
 
    BDRVRawState *s = bs->opaque;
88
 
    int access_flags, create_flags;
89
 
    DWORD overlapped;
90
 
 
91
 
    s->type = FTYPE_FILE;
92
 
 
93
 
    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
94
 
        access_flags = GENERIC_READ | GENERIC_WRITE;
95
 
    } else {
96
 
        access_flags = GENERIC_READ;
97
 
    }
98
 
    if (flags & BDRV_O_CREAT) {
99
 
        create_flags = CREATE_ALWAYS;
100
 
    } else {
101
 
        create_flags = OPEN_EXISTING;
102
 
    }
103
 
#ifdef QEMU_IMG
104
 
    overlapped = FILE_ATTRIBUTE_NORMAL;
105
 
#else
106
 
    overlapped = FILE_FLAG_OVERLAPPED;
107
 
#endif
108
 
    if (flags & BDRV_O_DIRECT)
109
 
        overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
110
 
    s->hfile = CreateFile(filename, access_flags,
111
 
                          FILE_SHARE_READ, NULL,
112
 
                          create_flags, overlapped, NULL);
113
 
    if (s->hfile == INVALID_HANDLE_VALUE) {
114
 
        int err = GetLastError();
115
 
 
116
 
        if (err == ERROR_ACCESS_DENIED)
117
 
            return -EACCES;
118
 
        return -1;
119
 
    }
120
 
    return 0;
121
 
}
122
 
 
123
 
static int raw_pread(BlockDriverState *bs, int64_t offset,
124
 
                     uint8_t *buf, int count)
125
 
{
126
 
    BDRVRawState *s = bs->opaque;
127
 
    OVERLAPPED ov;
128
 
    DWORD ret_count;
129
 
    int ret;
130
 
 
131
 
    memset(&ov, 0, sizeof(ov));
132
 
    ov.Offset = offset;
133
 
    ov.OffsetHigh = offset >> 32;
134
 
    ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
135
 
    if (!ret) {
136
 
        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
137
 
        if (!ret)
138
 
            return -EIO;
139
 
        else
140
 
            return ret_count;
141
 
    }
142
 
    return ret_count;
143
 
}
144
 
 
145
 
static int raw_pwrite(BlockDriverState *bs, int64_t offset,
146
 
                      const uint8_t *buf, int count)
147
 
{
148
 
    BDRVRawState *s = bs->opaque;
149
 
    OVERLAPPED ov;
150
 
    DWORD ret_count;
151
 
    int ret;
152
 
 
153
 
    memset(&ov, 0, sizeof(ov));
154
 
    ov.Offset = offset;
155
 
    ov.OffsetHigh = offset >> 32;
156
 
    ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
157
 
    if (!ret) {
158
 
        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
159
 
        if (!ret)
160
 
            return -EIO;
161
 
        else
162
 
            return ret_count;
163
 
    }
164
 
    return ret_count;
165
 
}
166
 
 
167
 
#if 0
168
 
#ifndef QEMU_IMG
169
 
static void raw_aio_cb(void *opaque)
170
 
{
171
 
    RawAIOCB *acb = opaque;
172
 
    BlockDriverState *bs = acb->common.bs;
173
 
    BDRVRawState *s = bs->opaque;
174
 
    DWORD ret_count;
175
 
    int ret;
176
 
 
177
 
    ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
178
 
    if (!ret || ret_count != acb->count) {
179
 
        acb->common.cb(acb->common.opaque, -EIO);
180
 
    } else {
181
 
        acb->common.cb(acb->common.opaque, 0);
182
 
    }
183
 
}
184
 
#endif
185
 
 
186
 
static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
187
 
        int64_t sector_num, uint8_t *buf, int nb_sectors,
188
 
        BlockDriverCompletionFunc *cb, void *opaque)
189
 
{
190
 
    RawAIOCB *acb;
191
 
    int64_t offset;
192
 
 
193
 
    acb = qemu_aio_get(bs, cb, opaque);
194
 
    if (acb->hEvent) {
195
 
        acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
196
 
        if (!acb->hEvent) {
197
 
            qemu_aio_release(acb);
198
 
            return NULL;
199
 
        }
200
 
    }
201
 
    memset(&acb->ov, 0, sizeof(acb->ov));
202
 
    offset = sector_num * 512;
203
 
    acb->ov.Offset = offset;
204
 
    acb->ov.OffsetHigh = offset >> 32;
205
 
    acb->ov.hEvent = acb->hEvent;
206
 
    acb->count = nb_sectors * 512;
207
 
#ifndef QEMU_IMG
208
 
    qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
209
 
#endif
210
 
    return acb;
211
 
}
212
 
 
213
 
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
214
 
        int64_t sector_num, uint8_t *buf, int nb_sectors,
215
 
        BlockDriverCompletionFunc *cb, void *opaque)
216
 
{
217
 
    BDRVRawState *s = bs->opaque;
218
 
    RawAIOCB *acb;
219
 
    int ret;
220
 
 
221
 
    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
222
 
    if (!acb)
223
 
        return NULL;
224
 
    ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
225
 
    if (!ret) {
226
 
        qemu_aio_release(acb);
227
 
        return NULL;
228
 
    }
229
 
#ifdef QEMU_IMG
230
 
    qemu_aio_release(acb);
231
 
#endif
232
 
    return (BlockDriverAIOCB *)acb;
233
 
}
234
 
 
235
 
static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
236
 
        int64_t sector_num, uint8_t *buf, int nb_sectors,
237
 
        BlockDriverCompletionFunc *cb, void *opaque)
238
 
{
239
 
    BDRVRawState *s = bs->opaque;
240
 
    RawAIOCB *acb;
241
 
    int ret;
242
 
 
243
 
    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
244
 
    if (!acb)
245
 
        return NULL;
246
 
    ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
247
 
    if (!ret) {
248
 
        qemu_aio_release(acb);
249
 
        return NULL;
250
 
    }
251
 
#ifdef QEMU_IMG
252
 
    qemu_aio_release(acb);
253
 
#endif
254
 
    return (BlockDriverAIOCB *)acb;
255
 
}
256
 
 
257
 
static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
258
 
{
259
 
#ifndef QEMU_IMG
260
 
    RawAIOCB *acb = (RawAIOCB *)blockacb;
261
 
    BlockDriverState *bs = acb->common.bs;
262
 
    BDRVRawState *s = bs->opaque;
263
 
 
264
 
    qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
265
 
    /* XXX: if more than one async I/O it is not correct */
266
 
    CancelIo(s->hfile);
267
 
    qemu_aio_release(acb);
268
 
#endif
269
 
}
270
 
#endif /* #if 0 */
271
 
 
272
 
static void raw_flush(BlockDriverState *bs)
273
 
{
274
 
    BDRVRawState *s = bs->opaque;
275
 
    FlushFileBuffers(s->hfile);
276
 
}
277
 
 
278
 
static void raw_close(BlockDriverState *bs)
279
 
{
280
 
    BDRVRawState *s = bs->opaque;
281
 
    CloseHandle(s->hfile);
282
 
}
283
 
 
284
 
static int raw_truncate(BlockDriverState *bs, int64_t offset)
285
 
{
286
 
    BDRVRawState *s = bs->opaque;
287
 
    DWORD low, high;
288
 
 
289
 
    low = offset;
290
 
    high = offset >> 32;
291
 
    if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
292
 
        return -EIO;
293
 
    if (!SetEndOfFile(s->hfile))
294
 
        return -EIO;
295
 
    return 0;
296
 
}
297
 
 
298
 
static int64_t raw_getlength(BlockDriverState *bs)
299
 
{
300
 
    BDRVRawState *s = bs->opaque;
301
 
    LARGE_INTEGER l;
302
 
    ULARGE_INTEGER available, total, total_free;
303
 
    DISK_GEOMETRY_EX dg;
304
 
    DWORD count;
305
 
    BOOL status;
306
 
 
307
 
    switch(s->type) {
308
 
    case FTYPE_FILE:
309
 
        l.LowPart = GetFileSize(s->hfile, &l.HighPart);
310
 
        if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
311
 
            return -EIO;
312
 
        break;
313
 
    case FTYPE_CD:
314
 
        if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
315
 
            return -EIO;
316
 
        l.QuadPart = total.QuadPart;
317
 
        break;
318
 
    case FTYPE_HARDDISK:
319
 
        status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
320
 
                                 NULL, 0, &dg, sizeof(dg), &count, NULL);
321
 
        if (status != 0) {
322
 
            l = dg.DiskSize;
323
 
        }
324
 
        break;
325
 
    default:
326
 
        return -EIO;
327
 
    }
328
 
    return l.QuadPart;
329
 
}
330
 
 
331
 
static int raw_create(const char *filename, int64_t total_size,
332
 
                      const char *backing_file, int flags)
333
 
{
334
 
    int fd;
335
 
 
336
 
    if (flags || backing_file)
337
 
        return -ENOTSUP;
338
 
 
339
 
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
340
 
              0644);
341
 
    if (fd < 0)
342
 
        return -EIO;
343
 
    set_sparse(fd);
344
 
    ftruncate(fd, total_size * 512);
345
 
    close(fd);
346
 
    return 0;
347
 
}
348
 
 
349
 
void qemu_aio_init(void)
350
 
{
351
 
}
352
 
 
353
 
void qemu_aio_poll(void)
354
 
{
355
 
}
356
 
 
357
 
void qemu_aio_flush(void)
358
 
{
359
 
}
360
 
 
361
 
void qemu_aio_wait_start(void)
362
 
{
363
 
}
364
 
 
365
 
void qemu_aio_wait(void)
366
 
{
367
 
#ifndef QEMU_IMG
368
 
    qemu_bh_poll();
369
 
#endif
370
 
}
371
 
 
372
 
void qemu_aio_wait_end(void)
373
 
{
374
 
}
375
 
 
376
 
BlockDriver bdrv_raw = {
377
 
    "raw",
378
 
    sizeof(BDRVRawState),
379
 
    NULL, /* no probe for protocols */
380
 
    raw_open,
381
 
    NULL,
382
 
    NULL,
383
 
    raw_close,
384
 
    raw_create,
385
 
    raw_flush,
386
 
 
387
 
#if 0
388
 
    .bdrv_aio_read = raw_aio_read,
389
 
    .bdrv_aio_write = raw_aio_write,
390
 
    .bdrv_aio_cancel = raw_aio_cancel,
391
 
    .aiocb_size = sizeof(RawAIOCB);
392
 
#endif
393
 
    .protocol_name = "file",
394
 
    .bdrv_pread = raw_pread,
395
 
    .bdrv_pwrite = raw_pwrite,
396
 
    .bdrv_truncate = raw_truncate,
397
 
    .bdrv_getlength = raw_getlength,
398
 
};
399
 
 
400
 
/***********************************************/
401
 
/* host device */
402
 
 
403
 
static int find_cdrom(char *cdrom_name, int cdrom_name_size)
404
 
{
405
 
    char drives[256], *pdrv = drives;
406
 
    UINT type;
407
 
 
408
 
    memset(drives, 0, sizeof(drives));
409
 
    GetLogicalDriveStrings(sizeof(drives), drives);
410
 
    while(pdrv[0] != '\0') {
411
 
        type = GetDriveType(pdrv);
412
 
        switch(type) {
413
 
        case DRIVE_CDROM:
414
 
            snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
415
 
            return 0;
416
 
            break;
417
 
        }
418
 
        pdrv += lstrlen(pdrv) + 1;
419
 
    }
420
 
    return -1;
421
 
}
422
 
 
423
 
static int find_device_type(BlockDriverState *bs, const char *filename)
424
 
{
425
 
    BDRVRawState *s = bs->opaque;
426
 
    UINT type;
427
 
    const char *p;
428
 
 
429
 
    if (strstart(filename, "\\\\.\\", &p) ||
430
 
        strstart(filename, "//./", &p)) {
431
 
        if (stristart(p, "PhysicalDrive", NULL))
432
 
            return FTYPE_HARDDISK;
433
 
        snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
434
 
        type = GetDriveType(s->drive_path);
435
 
        if (type == DRIVE_CDROM)
436
 
            return FTYPE_CD;
437
 
        else
438
 
            return FTYPE_FILE;
439
 
    } else {
440
 
        return FTYPE_FILE;
441
 
    }
442
 
}
443
 
 
444
 
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
445
 
{
446
 
    BDRVRawState *s = bs->opaque;
447
 
    int access_flags, create_flags;
448
 
    DWORD overlapped;
449
 
    char device_name[64];
450
 
 
451
 
    if (strstart(filename, "/dev/cdrom", NULL)) {
452
 
        if (find_cdrom(device_name, sizeof(device_name)) < 0)
453
 
            return -ENOENT;
454
 
        filename = device_name;
455
 
    } else {
456
 
        /* transform drive letters into device name */
457
 
        if (((filename[0] >= 'a' && filename[0] <= 'z') ||
458
 
             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
459
 
            filename[1] == ':' && filename[2] == '\0') {
460
 
            snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
461
 
            filename = device_name;
462
 
        }
463
 
    }
464
 
    s->type = find_device_type(bs, filename);
465
 
 
466
 
    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
467
 
        access_flags = GENERIC_READ | GENERIC_WRITE;
468
 
    } else {
469
 
        access_flags = GENERIC_READ;
470
 
    }
471
 
    create_flags = OPEN_EXISTING;
472
 
 
473
 
#ifdef QEMU_IMG
474
 
    overlapped = FILE_ATTRIBUTE_NORMAL;
475
 
#else
476
 
    overlapped = FILE_FLAG_OVERLAPPED;
477
 
#endif
478
 
    if (flags & BDRV_O_DIRECT)
479
 
        overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
480
 
    s->hfile = CreateFile(filename, access_flags,
481
 
                          FILE_SHARE_READ, NULL,
482
 
                          create_flags, overlapped, NULL);
483
 
    if (s->hfile == INVALID_HANDLE_VALUE) {
484
 
        int err = GetLastError();
485
 
 
486
 
        if (err == ERROR_ACCESS_DENIED)
487
 
            return -EACCES;
488
 
        return -1;
489
 
    }
490
 
    return 0;
491
 
}
492
 
 
493
 
#if 0
494
 
/***********************************************/
495
 
/* removable device additional commands */
496
 
 
497
 
static int raw_is_inserted(BlockDriverState *bs)
498
 
{
499
 
    return 1;
500
 
}
501
 
 
502
 
static int raw_media_changed(BlockDriverState *bs)
503
 
{
504
 
    return -ENOTSUP;
505
 
}
506
 
 
507
 
static int raw_eject(BlockDriverState *bs, int eject_flag)
508
 
{
509
 
    DWORD ret_count;
510
 
 
511
 
    if (s->type == FTYPE_FILE)
512
 
        return -ENOTSUP;
513
 
    if (eject_flag) {
514
 
        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
515
 
                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
516
 
    } else {
517
 
        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
518
 
                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
519
 
    }
520
 
}
521
 
 
522
 
static int raw_set_locked(BlockDriverState *bs, int locked)
523
 
{
524
 
    return -ENOTSUP;
525
 
}
526
 
#endif
527
 
 
528
 
BlockDriver bdrv_host_device = {
529
 
    "host_device",
530
 
    sizeof(BDRVRawState),
531
 
    NULL, /* no probe for protocols */
532
 
    hdev_open,
533
 
    NULL,
534
 
    NULL,
535
 
    raw_close,
536
 
    NULL,
537
 
    raw_flush,
538
 
 
539
 
#if 0
540
 
    .bdrv_aio_read = raw_aio_read,
541
 
    .bdrv_aio_write = raw_aio_write,
542
 
    .bdrv_aio_cancel = raw_aio_cancel,
543
 
    .aiocb_size = sizeof(RawAIOCB);
544
 
#endif
545
 
    .bdrv_pread = raw_pread,
546
 
    .bdrv_pwrite = raw_pwrite,
547
 
    .bdrv_getlength = raw_getlength,
548
 
};