/* Note: for compatibility, we open disk image files as RDWR, and
RDONLY as fallback */
if (!(flags & BDRV_O_FILE))
- open_flags = BDRV_O_RDWR | (flags & BDRV_O_CACHE_MASK);
+ open_flags = (flags & BDRV_O_ACCESS) | (flags & BDRV_O_CACHE_MASK);
else
open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
ret = drv->bdrv_open(bs, filename, open_flags);
case WIN_WRITE_ONCE:
case CFA_WRITE_SECT_WO_ERASE:
case WIN_WRITE_VERIFY:
+ if (bdrv_is_read_only(s->bs)) {
+#if defined(DEBUG_IDE)
+ printf("Attempt to write on read-only device %s\n", s->bs->filename);
+#endif
+ s->status = WRERR_STAT;
+ s->error = ABRT_ERR;
+ ide_set_irq(s);
+ break;
+ }
ide_cmd_lba48_transform(s, lba48);
s->error = 0;
s->status = SEEK_STAT | READY_STAT;
case CFA_WRITE_MULTI_WO_ERASE:
if (!s->mult_sectors)
goto abort_cmd;
+ if (bdrv_is_read_only(s->bs)) {
+#if defined(DEBUG_IDE)
+ printf("Attempt to multiwrite on read-only device %s\n", s->bs->filename);
+#endif
+ s->status = WRERR_STAT;
+ s->error = ABRT_ERR;
+ ide_set_irq(s);
+ break;
+ }
ide_cmd_lba48_transform(s, lba48);
s->error = 0;
s->status = SEEK_STAT | READY_STAT;
case WIN_WRITEDMA_ONCE:
if (!s->bs)
goto abort_cmd;
+ if (bdrv_is_read_only(s->bs)) {
+#if defined(DEBUG_IDE)
+ printf("Attempt to DMA write to read-only device %s\n", s->bs->filename);
+#endif
+ s->status = WRERR_STAT;
+ s->error = ABRT_ERR;
+ ide_set_irq(s);
+ break;
+ }
ide_cmd_lba48_transform(s, lba48);
ide_sector_write_dma(s);
s->media_changed = 1;
#define SENSE_NOT_READY 2
#define SENSE_HARDWARE_ERROR 4
#define SENSE_ILLEGAL_REQUEST 5
+#define SENSE_DATA_PROTECT 7
#define STATUS_GOOD 0
#define STATUS_CHECK_CONDITION 2
|| action == BLOCK_ERR_STOP_ANY) {
r->status |= SCSI_REQ_STATUS_RETRY;
vm_stop(0);
+ } else if (error == SENSE_DATA_PROTECT) {
+ scsi_command_complete(r, STATUS_CHECK_CONDITION,
+ SENSE_DATA_PROTECT);
} else {
scsi_command_complete(r, STATUS_CHECK_CONDITION,
SENSE_HARDWARE_ERROR);
return 1;
}
+ if (bdrv_is_read_only(r->dev->bdrv)) {
+ scsi_write_complete(r, SENSE_DATA_PROTECT);
+ return 1;
+ }
+
if (r->aiocb)
BADF("Data transfer already in progress\n");
BlockDriverState *bs;
BlockDriver *format;
+ /* Read-only handling for image files */
+ char *mode = NULL;
+ int flags;
+ int is_readonly;
+
/* paths controlled by untrustworthy guest, and values read from them */
char *danger_path;
char *danger_buf = NULL;
}
}
pstrcpy(bs->filename, sizeof(bs->filename), params);
- if (bdrv_open2(bs, params, BDRV_O_CACHE_WB /* snapshot and write-back */, format) < 0)
+
+ flags = BDRV_O_CACHE_WB; /* snapshot and write-back */
+ is_readonly = 0;
+ if (pasprintf(&buf, "%s/mode", bpath) == -1)
+ continue;
+ free(mode);
+ mode = xs_read(xsh, XBT_NULL, buf, &len);
+ if (mode == NULL)
+ continue;
+ if (strchr(mode, 'r') && !strchr(mode, 'w'))
+ is_readonly = 1;
+
+ if (!is_readonly)
+ flags |= BDRV_O_ACCESS & O_RDWR;
+
+ fprintf(stderr, "Using file %s in read-%s mode\n", bs->filename, is_readonly ? "only" : "write");
+
+ if (bdrv_open2(bs, params, flags, format) < 0)
fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s' format '%s')\n", buf, params, drv ? drv : "?", format ? format->format_name : "0");
}
out:
free(danger_type);
+ free(mode);
free(params);
free(dev);
free(bpath);