Include assert.h from qemu-common.h
[qemu] / block-raw-win32.c
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 #include "qemu-timer.h"
26 #include "block_int.h"
27 #include <windows.h>
28 #include <winioctl.h>
29
30 #define FTYPE_FILE 0
31 #define FTYPE_CD     1
32 #define FTYPE_HARDDISK 2
33
34 typedef struct BDRVRawState {
35     HANDLE hfile;
36     int type;
37     char drive_path[16]; /* format: "d:\" */
38 } BDRVRawState;
39
40 int qemu_ftruncate64(int fd, int64_t length)
41 {
42     LARGE_INTEGER li;
43     LONG high;
44     HANDLE h;
45     BOOL res;
46
47     if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
48         return -1;
49
50     h = (HANDLE)_get_osfhandle(fd);
51
52     /* get current position, ftruncate do not change position */
53     li.HighPart = 0;
54     li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
55     if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
56         return -1;
57
58     high = length >> 32;
59     if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
60         return -1;
61     res = SetEndOfFile(h);
62
63     /* back to old position */
64     SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
65     return res ? 0 : -1;
66 }
67
68 static int set_sparse(int fd)
69 {
70     DWORD returned;
71     return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
72                                  NULL, 0, NULL, 0, &returned, NULL);
73 }
74
75 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
76 {
77     BDRVRawState *s = bs->opaque;
78     int access_flags, create_flags;
79     DWORD overlapped;
80
81     s->type = FTYPE_FILE;
82
83     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
84         access_flags = GENERIC_READ | GENERIC_WRITE;
85     } else {
86         access_flags = GENERIC_READ;
87     }
88     if (flags & BDRV_O_CREAT) {
89         create_flags = CREATE_ALWAYS;
90     } else {
91         create_flags = OPEN_EXISTING;
92     }
93     overlapped = FILE_ATTRIBUTE_NORMAL;
94     if ((flags & BDRV_O_NOCACHE))
95         overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
96     else if (!(flags & BDRV_O_CACHE_WB))
97         overlapped |= FILE_FLAG_WRITE_THROUGH;
98     s->hfile = CreateFile(filename, access_flags,
99                           FILE_SHARE_READ, NULL,
100                           create_flags, overlapped, NULL);
101     if (s->hfile == INVALID_HANDLE_VALUE) {
102         int err = GetLastError();
103
104         if (err == ERROR_ACCESS_DENIED)
105             return -EACCES;
106         return -1;
107     }
108     return 0;
109 }
110
111 static int raw_read(BlockDriverState *bs, int64_t sector_num,
112                     uint8_t *buf, int nb_sectors)
113 {
114     BDRVRawState *s = bs->opaque;
115     OVERLAPPED ov;
116     DWORD ret_count;
117     int ret;
118     int64_t offset = sector_num * 512;
119     int count = nb_sectors * 512;
120
121     memset(&ov, 0, sizeof(ov));
122     ov.Offset = offset;
123     ov.OffsetHigh = offset >> 32;
124     ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
125     if (!ret)
126         return ret_count;
127     if (ret_count == count)
128         ret_count = 0;
129     return ret_count;
130 }
131
132 static int raw_write(BlockDriverState *bs, int64_t sector_num,
133                      const uint8_t *buf, int nb_sectors)
134 {
135     BDRVRawState *s = bs->opaque;
136     OVERLAPPED ov;
137     DWORD ret_count;
138     int ret;
139     int64_t offset = sector_num * 512;
140     int count = nb_sectors * 512;
141
142     memset(&ov, 0, sizeof(ov));
143     ov.Offset = offset;
144     ov.OffsetHigh = offset >> 32;
145     ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
146     if (!ret)
147         return ret_count;
148     if (ret_count == count)
149         ret_count = 0;
150     return ret_count;
151 }
152
153 static void raw_flush(BlockDriverState *bs)
154 {
155     BDRVRawState *s = bs->opaque;
156     FlushFileBuffers(s->hfile);
157 }
158
159 static void raw_close(BlockDriverState *bs)
160 {
161     BDRVRawState *s = bs->opaque;
162     CloseHandle(s->hfile);
163 }
164
165 static int raw_truncate(BlockDriverState *bs, int64_t offset)
166 {
167     BDRVRawState *s = bs->opaque;
168     LONG low, high;
169
170     low = offset;
171     high = offset >> 32;
172     if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
173         return -EIO;
174     if (!SetEndOfFile(s->hfile))
175         return -EIO;
176     return 0;
177 }
178
179 static int64_t raw_getlength(BlockDriverState *bs)
180 {
181     BDRVRawState *s = bs->opaque;
182     LARGE_INTEGER l;
183     ULARGE_INTEGER available, total, total_free;
184     DISK_GEOMETRY_EX dg;
185     DWORD count;
186     BOOL status;
187
188     switch(s->type) {
189     case FTYPE_FILE:
190         l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart);
191         if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
192             return -EIO;
193         break;
194     case FTYPE_CD:
195         if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
196             return -EIO;
197         l.QuadPart = total.QuadPart;
198         break;
199     case FTYPE_HARDDISK:
200         status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
201                                  NULL, 0, &dg, sizeof(dg), &count, NULL);
202         if (status != 0) {
203             l = dg.DiskSize;
204         }
205         break;
206     default:
207         return -EIO;
208     }
209     return l.QuadPart;
210 }
211
212 static int raw_create(const char *filename, int64_t total_size,
213                       const char *backing_file, int flags)
214 {
215     int fd;
216
217     if (flags || backing_file)
218         return -ENOTSUP;
219
220     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
221               0644);
222     if (fd < 0)
223         return -EIO;
224     set_sparse(fd);
225     ftruncate(fd, total_size * 512);
226     close(fd);
227     return 0;
228 }
229
230 BlockDriver bdrv_raw = {
231     .format_name        = "raw",
232     .instance_size      = sizeof(BDRVRawState),
233     .bdrv_open          = raw_open,
234     .bdrv_close         = raw_close,
235     .bdrv_create        = raw_create,
236     .bdrv_flush         = raw_flush,
237     .bdrv_read          = raw_read,
238     .bdrv_write         = raw_write,
239     .bdrv_truncate      = raw_truncate,
240     .bdrv_getlength     = raw_getlength,
241 };
242
243 /***********************************************/
244 /* host device */
245
246 static int find_cdrom(char *cdrom_name, int cdrom_name_size)
247 {
248     char drives[256], *pdrv = drives;
249     UINT type;
250
251     memset(drives, 0, sizeof(drives));
252     GetLogicalDriveStrings(sizeof(drives), drives);
253     while(pdrv[0] != '\0') {
254         type = GetDriveType(pdrv);
255         switch(type) {
256         case DRIVE_CDROM:
257             snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
258             return 0;
259             break;
260         }
261         pdrv += lstrlen(pdrv) + 1;
262     }
263     return -1;
264 }
265
266 static int find_device_type(BlockDriverState *bs, const char *filename)
267 {
268     BDRVRawState *s = bs->opaque;
269     UINT type;
270     const char *p;
271
272     if (strstart(filename, "\\\\.\\", &p) ||
273         strstart(filename, "//./", &p)) {
274         if (stristart(p, "PhysicalDrive", NULL))
275             return FTYPE_HARDDISK;
276         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
277         type = GetDriveType(s->drive_path);
278         switch (type) {
279         case DRIVE_REMOVABLE:
280         case DRIVE_FIXED:
281             return FTYPE_HARDDISK;
282         case DRIVE_CDROM:
283             return FTYPE_CD;
284         default:
285             return FTYPE_FILE;
286         }
287     } else {
288         return FTYPE_FILE;
289     }
290 }
291
292 static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
293 {
294     BDRVRawState *s = bs->opaque;
295     int access_flags, create_flags;
296     DWORD overlapped;
297     char device_name[64];
298
299     if (strstart(filename, "/dev/cdrom", NULL)) {
300         if (find_cdrom(device_name, sizeof(device_name)) < 0)
301             return -ENOENT;
302         filename = device_name;
303     } else {
304         /* transform drive letters into device name */
305         if (((filename[0] >= 'a' && filename[0] <= 'z') ||
306              (filename[0] >= 'A' && filename[0] <= 'Z')) &&
307             filename[1] == ':' && filename[2] == '\0') {
308             snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
309             filename = device_name;
310         }
311     }
312     s->type = find_device_type(bs, filename);
313
314     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
315         access_flags = GENERIC_READ | GENERIC_WRITE;
316     } else {
317         access_flags = GENERIC_READ;
318     }
319     create_flags = OPEN_EXISTING;
320
321     overlapped = FILE_ATTRIBUTE_NORMAL;
322     if ((flags & BDRV_O_NOCACHE))
323         overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
324     else if (!(flags & BDRV_O_CACHE_WB))
325         overlapped |= FILE_FLAG_WRITE_THROUGH;
326     s->hfile = CreateFile(filename, access_flags,
327                           FILE_SHARE_READ, NULL,
328                           create_flags, overlapped, NULL);
329     if (s->hfile == INVALID_HANDLE_VALUE) {
330         int err = GetLastError();
331
332         if (err == ERROR_ACCESS_DENIED)
333             return -EACCES;
334         return -1;
335     }
336     return 0;
337 }
338
339 #if 0
340 /***********************************************/
341 /* removable device additional commands */
342
343 static int raw_is_inserted(BlockDriverState *bs)
344 {
345     return 1;
346 }
347
348 static int raw_media_changed(BlockDriverState *bs)
349 {
350     return -ENOTSUP;
351 }
352
353 static int raw_eject(BlockDriverState *bs, int eject_flag)
354 {
355     DWORD ret_count;
356
357     if (s->type == FTYPE_FILE)
358         return -ENOTSUP;
359     if (eject_flag) {
360         DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
361                         NULL, 0, NULL, 0, &lpBytesReturned, NULL);
362     } else {
363         DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
364                         NULL, 0, NULL, 0, &lpBytesReturned, NULL);
365     }
366 }
367
368 static int raw_set_locked(BlockDriverState *bs, int locked)
369 {
370     return -ENOTSUP;
371 }
372 #endif
373
374 BlockDriver bdrv_host_device = {
375     .format_name        = "host_device",
376     .instance_size      = sizeof(BDRVRawState),
377     .bdrv_open          = hdev_open,
378     .bdrv_close         = raw_close,
379     .bdrv_flush         = raw_flush,
380
381     .bdrv_read          = raw_read,
382     .bdrv_write         = raw_write,
383     .bdrv_getlength     = raw_getlength,
384 };