Partial implementation of sparsebundles; still needs Info.plist parsing

This commit is contained in:
Dave Vasilevsky 2013-02-24 13:02:16 -05:00
parent 0c3516ef5a
commit 091db05aac
4 changed files with 227 additions and 1 deletions

View File

@ -0,0 +1,154 @@
/*
* disk_sparsebundle.cpp - Apple sparse bundle implementation
*
* Basilisk II (C) Dave Vasilevsky
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "disk_unix.h"
#include <limits.h>
// TODO
// - Factory needs to actually check stuff
// - Add to basilisk build
// - Add to 'make links'
typedef ssize_t (band_func)(int fd, void *buf, size_t len);
static ssize_t band_read(int fd, void *buf, size_t len) {
ssize_t err = (fd == -1 ? 0 : ::read(fd, buf, len));
if (err == -1)
return err;
if (err < len)
memset((char*)buf + err, 0, len - err);
return len;
}
static ssize_t band_write(int fd, void *buf, size_t len) {
return ::write(fd, buf, len);
}
struct disk_sparsebundle : disk_generic {
disk_sparsebundle(char *bands, int fd, bool read_only, loff_t band_size,
loff_t total_size)
: token_fd(fd), read_only(read_only), band_size(band_size),
total_size(total_size), band_dir(bands), band_cur(-1), band_fd(0) {
}
virtual ~disk_sparsebundle() {
if (band_fd)
close(band_fd);
close(token_fd);
free(band_dir);
}
virtual bool is_read_only() { return read_only; }
virtual loff_t size() { return total_size; }
virtual size_t read(void *buf, loff_t offset, size_t length) {
return band_do(&band_read, buf, offset, length);
}
virtual size_t write(void *buf, loff_t offset, size_t length) {
return band_do(&band_write, buf, offset, length);
}
protected:
int token_fd;
bool read_only;
loff_t band_size, total_size;
char *band_dir;
loff_t band_cur;
int band_fd;
size_t band_do(band_func func, void *buf, loff_t offset, size_t length) {
char *b = (char*)buf;
loff_t band = offset / band_size;
size_t done = 0;
while (length) {
if (!open_band(band))
break;
size_t start = offset % band_size;
size_t segment = band_size - start;
if (segment > length)
segment = length;
if (band_fd != -1 && lseek(band_fd, start, SEEK_SET) == -1)
return done;
ssize_t err = func(band_fd, buf, segment);
if (err > 0)
done += err;
if (err < segment)
break;
b += segment;
offset += segment;
length -= segment;
++band;
}
return done;
}
// Open band index 'band', return false on error
bool open_band(loff_t band) {
if (band_cur == band)
return true;
char path[PATH_MAX + 1];
if (snprintf(path, PATH_MAX, "%s/%lx", band_dir,
(unsigned long)band) >= PATH_MAX) {
return false;
}
int oflags = read_only ? O_RDONLY : (O_RDWR | O_CREAT);
band_fd = open(path, oflags, 0644);
if (band_fd == -1) {
if (read_only) {
band_cur == -1;
return true;
} else {
return false;
}
}
band_cur = band;
return true;
}
};
disk_generic *disk_sparsebundle_factory(const char *path, bool read_only) {
if (strstr(path, ".sparsebundle") == NULL)
return NULL; // FIXME: real test
// FIXME: actually read these
loff_t band_size = 1048576;
loff_t total_size = 53687091200;
// FIXME: check for double-mount, writable
int token = 0;
read_only = false;
char buf[PATH_MAX + 1];
if (snprintf(buf, PATH_MAX, "%s/%s", path, "bands") >= PATH_MAX)
return NULL;
char *bands = strdup(buf);
return new disk_sparsebundle(bands, token, read_only, band_size,
total_size);
}

View File

@ -0,0 +1,40 @@
/*
* disk_unix.h - Generic disk interface
*
* Basilisk II (C) Dave Vasilevsky
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DISK_UNIX_H
#define DISK_UNIX_H
#include "sysdeps.h"
struct disk_generic {
disk_generic() { }
virtual ~disk_generic() { };
virtual bool is_read_only() = 0;
virtual size_t read(void *buf, loff_t offset, size_t length) = 0;
virtual size_t write(void *buf, loff_t offset, size_t length) = 0;
virtual loff_t size() = 0;
};
typedef disk_generic *(disk_factory)(const char *path, bool read_only);
extern disk_factory disk_sparsebundle_factory;
#endif

View File

@ -56,6 +56,7 @@
#include "prefs.h" #include "prefs.h"
#include "user_strings.h" #include "user_strings.h"
#include "sys.h" #include "sys.h"
#include "disk_unix.h"
#if defined(BINCUE) #if defined(BINCUE)
#include "bincue_unix.h" #include "bincue_unix.h"
@ -83,6 +84,7 @@ struct mac_file_handle {
loff_t file_size; // Size of file data (only valid if is_file is true) loff_t file_size; // Size of file data (only valid if is_file is true)
bool is_media_present; // Flag: media is inserted and available bool is_media_present; // Flag: media is inserted and available
disk_generic *generic_disk;
#if defined(__linux__) #if defined(__linux__)
int cdrom_cap; // CD-ROM capability flags (only valid if is_cdrom is true) int cdrom_cap; // CD-ROM capability flags (only valid if is_cdrom is true)
@ -525,6 +527,7 @@ static mac_file_handle *open_filehandle(const char *name)
memset(fh, 0, sizeof(mac_file_handle)); memset(fh, 0, sizeof(mac_file_handle));
fh->name = strdup(name); fh->name = strdup(name);
fh->fd = -1; fh->fd = -1;
fh->generic_disk = NULL;
#if defined __MACOSX__ #if defined __MACOSX__
fh->ioctl_fd = -1; fh->ioctl_fd = -1;
fh->ioctl_name = NULL; fh->ioctl_name = NULL;
@ -616,6 +619,18 @@ void *Sys_open(const char *name, bool read_only)
} }
#endif #endif
// FIXME
disk_generic *generic = disk_sparsebundle_factory(name, read_only);
if (generic) {
mac_file_handle *fh = open_filehandle(name);
fh->generic_disk = generic;
fh->file_size = generic->size();
fh->read_only = generic->is_read_only();
fh->is_media_present = true;
sys_add_mac_file_handle(fh);
return fh;
}
int open_flags = (read_only ? O_RDONLY : O_RDWR); int open_flags = (read_only ? O_RDONLY : O_RDWR);
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__)
open_flags |= (is_cdrom ? O_NONBLOCK : 0); open_flags |= (is_cdrom ? O_NONBLOCK : 0);
@ -727,6 +742,8 @@ void Sys_close(void *arg)
if (fh->is_bincue) if (fh->is_bincue)
close_bincue(fh->bincue_fd); close_bincue(fh->bincue_fd);
#endif #endif
if (fh->generic_disk)
delete fh->generic_disk;
if (fh->is_cdrom) if (fh->is_cdrom)
cdrom_close(fh); cdrom_close(fh);
@ -759,6 +776,9 @@ size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
return vhd_unix_read(fh->vhd_fd, buffer, offset, length); return vhd_unix_read(fh->vhd_fd, buffer, offset, length);
#endif #endif
if (fh->generic_disk)
return fh->generic_disk->read(buffer, offset, length);
// Seek to position // Seek to position
if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
return 0; return 0;
@ -784,6 +804,9 @@ size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
return vhd_unix_write(fh->vhd_fd, buffer, offset, length); return vhd_unix_write(fh->vhd_fd, buffer, offset, length);
#endif #endif
if (fh->generic_disk)
return fh->generic_disk->write(buffer, offset, length);
// Seek to position // Seek to position
if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
return 0; return 0;
@ -813,6 +836,9 @@ loff_t SysGetFileSize(void *arg)
return fh->file_size; return fh->file_size;
#endif #endif
if (fh->generic_disk)
return fh->file_size;
if (fh->is_file) if (fh->is_file)
return fh->file_size; return fh->file_size;
else { else {
@ -951,6 +977,9 @@ bool SysIsFixedDisk(void *arg)
return true; return true;
#endif #endif
if (fh->generic_disk)
return true;
if (fh->is_file) if (fh->is_file)
return true; return true;
else if (fh->is_floppy || fh->is_cdrom) else if (fh->is_floppy || fh->is_cdrom)
@ -975,6 +1004,9 @@ bool SysIsDiskInserted(void *arg)
return true; return true;
#endif #endif
if (fh->generic_disk)
return true;
if (fh->is_file) { if (fh->is_file) {
return true; return true;

View File

@ -59,7 +59,7 @@ SRCS = ../main.cpp main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp
../macos_util.cpp ../timer.cpp timer_unix.cpp ../xpram.cpp xpram_unix.cpp \ ../macos_util.cpp ../timer.cpp timer_unix.cpp ../xpram.cpp xpram_unix.cpp \
../adb.cpp ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp \ ../adb.cpp ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp \
../gfxaccel.cpp ../video.cpp video_blit.cpp ../audio.cpp ../ether.cpp ../thunks.cpp \ ../gfxaccel.cpp ../video.cpp video_blit.cpp ../audio.cpp ../ether.cpp ../thunks.cpp \
../serial.cpp ../extfs.cpp \ ../serial.cpp ../extfs.cpp disk_sparsebundle.cpp \
about_window_unix.cpp ../user_strings.cpp user_strings_unix.cpp \ about_window_unix.cpp ../user_strings.cpp user_strings_unix.cpp \
vm_alloc.cpp sigsegv.cpp rpc_unix.cpp \ vm_alloc.cpp sigsegv.cpp rpc_unix.cpp \
sshpty.c strlcpy.c $(SYSSRCS) $(CPUSRCS) $(MONSRCS) $(SLIRP_SRCS) sshpty.c strlcpy.c $(SYSSRCS) $(CPUSRCS) $(MONSRCS) $(SLIRP_SRCS)