#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
+#include <malloc.h>
#include <windows.h>
+#include <winioctl.h>
#include "widgets.h"
#include "rawdisk.h"
+#define IMG_FNAME "disk.img"
+
+#define WIN_XPAD 10
+#define WIN_YPAD 15
+
+static int instimg(const char *devpath);
+static void update_disks(void);
+static void onclick(struct wgt_widget *w);
+static void onmodify(struct wgt_widget *w);
+static void ck_usbonly_handler(struct wgt_widget *w);
+
+
static struct wgt_window *win;
-static struct wgt_widget *lb_instto, *bn_inst, *bn_cancel, *cb_devs, *ck_usbonly;
+static struct wgt_widget *lb_instto, *bn_inst, *bn_cancel, *cb_devs, *ck_usbonly, *bn_cancel_inst;
+
static struct rawdisk_device rawdev[64];
+static const char *items[64];
static int num_rawdev;
-static void onclick(struct wgt_widget *w);
-static void onmodify(struct wgt_widget *w);
+static FILE *imgfile;
+static long imgfile_size;
+static const char *err_noimg_fmt =
+ "Failed to open 256boss disk image: " IMG_FNAME "\n"
+ "%s\n"
+ "\n"
+ "Please run this installer from the 256boss distribution directory";
+static const char *fail_err_str;
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprevinst, char *cmdline, int showcmd)
{
- int i, x, y;
+ int x, y, width, height, max_width;
MSG msg;
- static const char *items[64];
+ char *msgbuf, *errmsg;
- if((num_rawdev = rawdisk_detect(rawdev, sizeof rawdev / sizeof *rawdev)) == -1) {
+ if(!(imgfile = fopen(IMG_FNAME, "rb"))) {
+ errmsg = strerror(errno);
+ msgbuf = alloca(strlen(err_noimg_fmt) + strlen(errmsg) + 1);
+ sprintf(msgbuf, err_noimg_fmt, errmsg);
+ MessageBox(0, msgbuf, "Missing disk image!", MB_OK | MB_ICONSTOP | MB_APPLMODAL);
return 1;
}
- for(i=0; i<num_rawdev; i++) {
- items[i] = rawdev[i].name;
- }
+ fseek(imgfile, 0, SEEK_END);
+ imgfile_size = ftell(imgfile);
- if(!(win = wgt_window("256boss USB stick installer", 400, 300))) {
+ if(!(win = wgt_window("256boss USB stick installer", 420, 170))) {
+ fclose(imgfile);
return 1;
}
- lb_instto = wgt_label(win, "Install to device:", 10, 10);
+
+ max_width = 0;
+ y = WIN_YPAD;
+ lb_instto = wgt_label(win, "Install to device:", WIN_XPAD, WIN_YPAD);
x = wgt_xpos_after(lb_instto, WGT_AUTO);
- cb_devs = wgt_combo(win, items, num_rawdev, 0, x, 10, WGT_AUTO, WGT_AUTO,
- onmodify);
+ cb_devs = wgt_combo(win, items, num_rawdev, 0, x, WIN_YPAD, 270, WGT_AUTO, onmodify);
+ if((width = wgt_xpos_after(cb_devs, WIN_XPAD)) > max_width) max_width = width;
y = wgt_ypos_after(cb_devs, 16);
ck_usbonly = wgt_checkbox(win, "only show USB devices", 1, x, y,
- WGT_AUTO, WGT_AUTO, 0);
+ WGT_AUTO, WGT_AUTO, ck_usbonly_handler);
+ if((width = wgt_xpos_after(ck_usbonly, WIN_XPAD)) > max_width) max_width = width;
- y = wgt_ypos_after(ck_usbonly, 16);
- bn_inst = wgt_button(win, "Install", 10, y, WGT_AUTO, WGT_AUTO, onclick);
+ y = wgt_ypos_after(ck_usbonly, 32);
+ bn_inst = wgt_button(win, "Install", 70, y, 100, WGT_AUTO, onclick);
+ bn_cancel = wgt_button(win, "Cancel", 230, y, 100, WGT_AUTO, onclick);
- x = wgt_xpos_after(bn_inst, WGT_AUTO);
- bn_cancel = wgt_button(win, "Cancel", x, y, WGT_AUTO, WGT_AUTO, onclick);
+ height = wgt_ypos_after(bn_inst, WIN_YPAD);
+
+ wgt_resize_window(win, max_width, height);
+
+ update_disks();
while(GetMessage(&msg, 0, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
- wgt_destroy_window(win);
+ fclose(imgfile);
+ wgt_free_window(win);
+ return 0;
+}
+
+#define MIN_BS (4 * 1024 * 1024)
+
+static int instimg(const char *devpath)
+{
+ MSG msg;
+ HANDLE hdev;
+ DWORD wrcount;
+ DISK_GEOMETRY geom;
+ int width, max_width, height, y, sz, blksz = 512, status = -1;
+ char *blkbuf;
+ struct wgt_window *win_inst;
+ struct wgt_widget *w, *pbar, *ptext;
+ struct wgt_rect *rect;
+ long num_blk_done, total_blk;
+ int progr;
+
+ if((hdev = CreateFile(devpath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0)) == INVALID_HANDLE_VALUE) {
+ DWORD err = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0,
+ &fail_err_str, 0, 0);
+ return -1;
+ }
+
+ /*if(rawdisk_eject(hdev) == 0) {
+ rawdisk_load(hdev);
+ }*/
+
+ if(DeviceIoControl(hdev, IOCTL_DISK_GET_DRIVE_GEOMETRY, 0, 0, &geom, sizeof geom, &wrcount, 0)) {
+ blksz = geom.BytesPerSector;
+ }
+
+ while(blksz < MIN_BS) blksz <<= 1;
+
+ num_blk_done = 0;
+ total_blk = (imgfile_size + blksz - 1) / blksz;
+
+ if(!(blkbuf = malloc(blksz))) {
+ CloseHandle(hdev);
+ fail_err_str = "failed to allocate block buffer";
+ return -1;
+ }
+
+ max_width = 0;
+
+ win_inst = wgt_window("Installing ...", 320, 140);
+ wgt_quit_on_close(win_inst, 0);
+
+ y = WIN_YPAD;
+ sprintf(blkbuf, "Device sector size: %d bytes", (int)geom.BytesPerSector);
+ w = wgt_label(win_inst, blkbuf, WIN_XPAD, y);
+ if((width = wgt_xpos_after(w, WIN_XPAD)) > max_width) max_width = width;
+
+ y = wgt_ypos_after(w, 8);
+ sprintf(blkbuf, "Copying in blocks of: %d bytes", blksz);
+ w = wgt_label(win_inst, blkbuf, WIN_XPAD, y);
+ if((width = wgt_xpos_after(w, WIN_XPAD)) > max_width) max_width = width;
+
+ y = wgt_ypos_after(w, 8);
+ sprintf(blkbuf, "Image size: %ld bytes (%ld blocks)", imgfile_size, total_blk);
+ w = wgt_label(win_inst, blkbuf, WIN_XPAD, y);
+ if((width = wgt_xpos_after(w, WIN_XPAD)) > max_width) max_width = width;
+
+ y = wgt_ypos_after(w, 8);
+ ptext = wgt_label(win_inst, "-/- (0%)", WIN_XPAD, y);
+
+ y = wgt_ypos_after(ptext, 8);
+ pbar = wgt_progbar(win_inst, WIN_XPAD, y, width - WIN_XPAD * 2, WGT_AUTO, 0);
+ if((width = wgt_xpos_after(pbar, WIN_XPAD)) > max_width) max_width = width;
+
+ y = wgt_ypos_after(pbar, 8);
+ bn_cancel_inst = wgt_button(win_inst, "Cancel", 100, y, WGT_AUTO, WGT_AUTO, onclick);
+ rect = wgt_widget_rect(bn_cancel_inst, 0);
+ wgt_move_widget(bn_cancel_inst, WIN_XPAD + (width - rect->width) / 2, rect->y);
+
+ height = wgt_ypos_after(bn_cancel_inst, WIN_YPAD);
+
+ wgt_resize_window(win_inst, max_width, height);
+
+ /* go through any pending messages once first, to allow the window to get drawn correctly */
+ while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ if(msg.message == WM_CLOSE || msg.message == WM_DESTROY) {
+ goto end;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ rewind(imgfile);
+ while((sz = fread(blkbuf, 1, blksz, imgfile)) > 0) {
+ if(sz < blksz) {
+ memset(blkbuf + sz, 0, blksz - sz);
+ }
+ SetFilePointer(hdev, num_blk_done * blksz, 0, FILE_BEGIN);
+ if(!WriteFile(hdev, blkbuf, blksz, &wrcount, 0)) {
+ DWORD err = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0,
+ &fail_err_str, 0, 0);
+ goto end;
+ }
+
+ num_blk_done++;
+ progr = num_blk_done * 100 / total_blk;
+ sprintf(blkbuf, "%ld/%ld (%d%%)", num_blk_done, total_blk, progr);
+ wgt_set_text(ptext, blkbuf);
+ wgt_set_progress(pbar, progr);
+
+ while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ if(msg.message == WM_CLOSE || msg.message == WM_DESTROY) {
+ goto end;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ rawdisk_refresh(hdev);
+
+ status = 0;
+end:
+ wgt_free_window(win_inst);
+
+ free(blkbuf);
+ CloseHandle(hdev);
+ return status;
+}
+
+static int isusbdev(struct rawdisk_device *dev)
+{
+ char *ptr = dev->path;
+ while(*ptr) {
+ int i;
+ char buf[3];
+ for(i=0; i<3; i++) {
+ buf[i] = tolower(ptr[i]);
+ }
+ if(memcmp(buf, "usb", 3) == 0) {
+ return 1;
+ }
+ ptr++;
+ }
return 0;
}
+static void update_disks(void)
+{
+ int i;
+
+ for(i=0; i<num_rawdev; i++) {
+ free(rawdev[i].name);
+ free(rawdev[i].path);
+ }
+
+ if((num_rawdev = rawdisk_detect(rawdev, sizeof rawdev / sizeof *rawdev)) == -1) {
+ MessageBox(0, "Failed to detect storage devices!", 0, MB_OK);
+ exit(1);
+ }
+
+ if(wgt_checkbox_checked(ck_usbonly)) {
+ i = 0;
+ while(i < num_rawdev) {
+ if(!isusbdev(rawdev + i)) {
+ free(rawdev[i].name);
+ free(rawdev[i].path);
+ rawdev[i] = rawdev[--num_rawdev];
+ } else {
+ i++;
+ }
+ }
+ }
+
+ for(i=0; i<num_rawdev; i++) {
+ items[i] = rawdev[i].name;
+ }
+
+ wgt_combo_setitems(cb_devs, items, num_rawdev);
+
+ if(num_rawdev) {
+ wgt_enable_widget(cb_devs);
+ wgt_enable_widget(bn_inst);
+ } else {
+ wgt_disable_widget(cb_devs);
+ wgt_disable_widget(bn_inst);
+ }
+}
+
+static const char *verify_fmt = \
+ "You are about to install 256boss to: %s\n"
+ "\n"
+ "Device path:\n"
+ "%s\n"
+ "\n"
+ "Any existing data in the selected device will be lost!\n"
+ "Please verify you have selected the intended device.\n"
+ "\n"
+ "Are you certain you wish to proceed with the installation?\n";
+
+static const char *success_str = \
+ "Installation complete!\n"
+ "\n"
+ "If the 256boss partition doesn't show up immediately,\n"
+ "please eject and re-attach the device\n";
+
+static const char *fail_fmt = \
+ "Installation failed!\n"
+ "Error: %s\n";
+
static void onclick(struct wgt_widget *w)
{
- MessageBox(0, "clicked", "clicked", MB_OK);
+ int sel, len;
+ unsigned int flags;
+ char *msgbuf;
+ static int inst_running;
+
+ if(w == bn_inst) {
+ if(inst_running) return;
+
+ sel = wgt_combo_selected(cb_devs);
+ if(sel < 0 || sel >= num_rawdev) {
+ return;
+ }
+
+ len = strlen(verify_fmt) + strlen(rawdev[sel].name) + strlen(rawdev[sel].path);
+ msgbuf = alloca(len + 1);
+ sprintf(msgbuf, verify_fmt, rawdev[sel].name, rawdev[sel].path);
+
+ flags = MB_YESNO | MB_ICONWARNING | MB_APPLMODAL | MB_SETFOREGROUND;
+ if(MessageBox(0, msgbuf, "Proceed with installation?", flags) == IDYES) {
+ inst_running = 1;
+ if(instimg(rawdev[sel].path) == -1) {
+ int prev_len = len;
+ len = strlen(fail_fmt) + (fail_err_str ? strlen(fail_err_str) : strlen("unknown"));
+ if(len > prev_len) {
+ alloca(len - prev_len);
+ }
+ sprintf(msgbuf, fail_fmt, fail_err_str ? fail_err_str : "unknown");
+ MessageBox(0, msgbuf, 0, MB_OK | MB_ICONSTOP | MB_APPLMODAL | MB_SETFOREGROUND);
+ } else {
+ MessageBox(0, success_str, "Done", MB_OK | MB_ICONASTERISK | MB_APPLMODAL | MB_SETFOREGROUND);
+ }
+ inst_running = 0;
+ }
+
+ } else if(w == bn_cancel) {
+ PostQuitMessage(0);
+
+ } else if(w == bn_cancel_inst) {
+ struct wgt_window *win = wgt_widget_window(w);
+ PostMessage(wgt_window_handle(win), WM_CLOSE, 0, 0);
+ }
}
static void onmodify(struct wgt_widget *w)
const char *selstr = wgt_get_combo_item(w, sel);
MessageBox(0, selstr, "selected item", MB_OK);
}
+}
+
+static void ck_usbonly_handler(struct wgt_widget *w)
+{
+ update_disks();
+}
+
+static int close_action(struct wgt_window *w)
+{
+ if(w != win) return 0;
+ return 1;
}
\ No newline at end of file