From 893284e93b349b260434c934cacc3c4b6b09d477 Mon Sep 17 00:00:00 2001 From: Javier Date: Wed, 13 Apr 2022 00:23:28 +0200 Subject: add rename support --- int21dos.h | 2 +- sftsr.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- vboxdev.h | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ vboxshfl.h | 48 ++++++++++++++++++++++++++++++----- 4 files changed, 186 insertions(+), 18 deletions(-) diff --git a/int21dos.h b/int21dos.h index a827b8f..30aa68b 100644 --- a/int21dos.h +++ b/int21dos.h @@ -33,7 +33,7 @@ enum dos_error { DOS_ERROR_INVALID_FUNCTION = 1, DOS_ERROR_FILE_NOT_FOUND = 2, DOS_ERROR_PATH_NOT_FOUND = 3, - DOS_ERROR_ERROR_TOO_MANY_OPEN_FILES = 4, + DOS_ERROR_TOO_MANY_OPEN_FILES = 4, DOS_ERROR_ACCESS_DENIED = 5, DOS_ERROR_INVALID_HANDLE = 6, DOS_ERROR_ARENA_TRASHED = 7, diff --git a/sftsr.c b/sftsr.c index 3f95323..a213200 100644 --- a/sftsr.c +++ b/sftsr.c @@ -31,7 +31,7 @@ TSRDATA data; /** Private buffer for VirtualBox filenames. */ static SHFLSTRING_WITH_BUF(shflstr, SHFL_MAX_LEN); -static SHFLDIRINFO_WITH_BUF(shfldirinfo, SHFL_MAX_LEN); +static SHFLDIRINFO_WITH_NAME_BUF(shfldirinfo, SHFL_MAX_LEN); static SHFLCREATEPARMS createparms; @@ -122,11 +122,15 @@ static bool is_call_for_mounted_drive(union INTPACK __far *r) static void clear_dos_err(union INTPACK __far *r) { + dlog_puts("->ok"); r->x.flags &= ~INTR_CF; } static void set_dos_err(union INTPACK __far *r, int err) { + dlog_print("->dos error "); + dlog_printd(err); + dlog_endline(); r->x.flags |= INTR_CF; r->x.ax = err; } @@ -148,6 +152,10 @@ static int vbox_err_to_dos(int32_t err) return DOS_ERROR_NO_MORE_FILES; case VERR_ALREADY_EXISTS: return DOS_ERROR_FILE_EXISTS; + case VERR_TOO_MANY_OPEN_FILES: + return DOS_ERROR_TOO_MANY_OPEN_FILES; + case VERR_WRITE_PROTECT: + return DOS_ERROR_WRITE_PROTECT; default: return DOS_ERROR_GEN_FAILURE; } @@ -155,13 +163,16 @@ static int vbox_err_to_dos(int32_t err) static void set_vbox_err(union INTPACK __far *r, int32_t err) { - dlog_print("vbox error "); - dlog_printx(err >> 16); - dlog_print(":"); - dlog_printx(err & 0xFFFF); + dlog_print("->vbox error "); + if (err < INT16_MIN || err > INT16_MAX) { + dlog_printx(err >> 16); + dlog_print(":"); + dlog_printx(err & 0xFFFF); + } else { + dlog_printd(err); + } dlog_endline(); - r->x.flags |= INTR_CF; - r->x.ax = vbox_err_to_dos(err); + set_dos_err(r, vbox_err_to_dos(err)); } static int my_strrchr(const char __far *str, char c) @@ -345,7 +356,7 @@ static void handle_create_open_ex(union INTPACK __far *r) openfile = find_free_openfile(); if (!openfile) { - set_dos_err(r, DOS_ERROR_ERROR_TOO_MANY_OPEN_FILES); + set_dos_err(r, DOS_ERROR_TOO_MANY_OPEN_FILES); return; } @@ -374,6 +385,11 @@ static void handle_create_open_ex(union INTPACK __far *r) createparms.CreateFlags |= SHFL_CF_ACCESS_READ; } + if (!(createparms.CreateFlags & SHFL_CF_ACCESS_WRITE)) { + // Do we really want to create new files without opening them for writing? + createparms.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW; + } + dlog_print("vbox createparms flags="); dlog_printx(createparms.CreateFlags); dlog_endline(); @@ -613,6 +629,45 @@ static void handle_delete(union INTPACK __far *r) clear_dos_err(r); } +static void handle_rename(union INTPACK __far *r) +{ + const char __far *src = data.dossda->fn1; + int srcdrive = drive_letter_to_index(src[0]); + const char __far *dst = data.dossda->fn2; + int dstdrive = drive_letter_to_index(dst[0]); + SHFLROOT root = data.drives[srcdrive].root; + int32_t err; + + dlog_print("handle_rename "); + dlog_fprint(src); + dlog_print(" to "); + dlog_fprint(dst); + dlog_endline(); + + if (srcdrive != dstdrive) { + set_dos_err(r, DOS_ERROR_NOT_SAME_DEVICE); + return; + } + + copy_drive_relative_filename(&shflstr.shflstr, src); + translate_filename_to_host(&shflstr.shflstr); + + // Reusing shfldirinfo buffer space here + // Hoping no one does concurrent find_next and rename + copy_drive_relative_filename(&shfldirinfo.dirinfo.name, dst); + translate_filename_to_host(&shfldirinfo.dirinfo.name); + + err = vbox_shfl_rename(&data.vb, data.hgcm_client_id, root, + &shflstr.shflstr, &shfldirinfo.dirinfo.name, + SHFL_RENAME_DIR | SHFL_RENAME_FILE); + if (err) { + set_vbox_err(r, err); + return; + } + + clear_dos_err(r); +} + static void handle_getattr(union INTPACK __far *r) { const char __far *path = data.dossda->fn1; @@ -624,7 +679,7 @@ static void handle_getattr(union INTPACK __far *r) dlog_fprint(path); dlog_endline(); - copy_drive_relative_dirname(&shflstr.shflstr, path); + copy_drive_relative_filename(&shflstr.shflstr, path); translate_filename_to_host(&shflstr.shflstr); memset(&createparms, 0, sizeof(SHFLCREATEPARMS)); @@ -750,8 +805,6 @@ static int32_t find_next_from_vbox(uint8_t search_attr) return VERR_INVALID_HANDLE; } - shfldirinfo.dirinfo.name.u16Size = sizeof(shfldirinfo.buf); - while (1) { // Loop until we have a valid file (or an error) unsigned size = sizeof(shfldirinfo), resume = 0, count = 0; dlog_puts("calling vbox list"); @@ -760,6 +813,12 @@ static int32_t find_next_from_vbox(uint8_t search_attr) data.files[SEARCH_DIR_FILE].root, data.files[SEARCH_DIR_FILE].handle, SHFL_LIST_RETURN_ONE, &size, &shflstr.shflstr, &shfldirinfo.dirinfo, &resume, &count); + + // Reset the size of the buffer here since VirtualBox "shortens" it, + // (since it expects to fit in more entries in the same space, but + // we won't allow that via SHFL_LIST_RETURN_ONE). + shfldirinfo.dirinfo.name.u16Size = sizeof(shfldirinfo.buf); + if (err) { return err; } @@ -1033,6 +1092,9 @@ static bool int2f_11_handler(union INTPACK r) case DOS_FN_DELETE: handle_delete(&r); return true; + case DOS_FN_RENAME: + handle_rename(&r); + return true; case DOS_FN_GET_FILE_ATTR: handle_getattr(&r); return true; diff --git a/vboxdev.h b/vboxdev.h index 15db0e1..062c9dc 100644 --- a/vboxdev.h +++ b/vboxdev.h @@ -54,6 +54,28 @@ #define VERR_INVALID_HANDLE (-4) /** Invalid loader handle. */ #define VWRN_INVALID_HANDLE 4 +/** Failed to lock the address range. */ +#define VERR_LOCK_FAILED (-5) +/** Invalid memory pointer. */ +#define VERR_INVALID_POINTER (-6) +/** Failed to patch the IDT. */ +#define VERR_IDT_FAILED (-7) +/** Memory allocation failed. */ +#define VERR_NO_MEMORY (-8) +/** Already loaded. */ +#define VERR_ALREADY_LOADED (-9) +/** Permission denied. */ +#define VERR_PERMISSION_DENIED (-10) +/** Permission denied. */ +#define VINF_PERMISSION_DENIED 10 +/** Version mismatch. */ +#define VERR_VERSION_MISMATCH (-11) +/** The request function is not implemented. */ +#define VERR_NOT_IMPLEMENTED (-12) +/** The request function is not implemented. */ +#define VINF_NOT_IMPLEMENTED 12 +/** Invalid flags was given. */ +#define VERR_INVALID_FLAGS (-13) #define VERR_FILE_IO_ERROR (-100) /** File/Device open failed. */ @@ -72,6 +94,50 @@ #define VERR_TOO_MANY_OPEN_FILES (-106) /** Seek error. */ #define VERR_SEEK (-107) +/** Seek below file start. */ +#define VERR_NEGATIVE_SEEK (-108) +/** Trying to seek on device. */ +#define VERR_SEEK_ON_DEVICE (-109) +/** Reached the end of the file. */ +#define VERR_EOF (-110) +/** Reached the end of the file. */ +#define VINF_EOF 110 +/** Generic file read error. */ +#define VERR_READ_ERROR (-111) +/** Generic file write error. */ +#define VERR_WRITE_ERROR (-112) +/** Write protect error. */ +#define VERR_WRITE_PROTECT (-113) +/** Sharing violation, file is being used by another process. */ +#define VERR_SHARING_VIOLATION (-114) +/** Unable to lock a region of a file. */ +#define VERR_FILE_LOCK_FAILED (-115) +/** File access error, another process has locked a portion of the file. */ +#define VERR_FILE_LOCK_VIOLATION (-116) +/** File or directory can't be created. */ +#define VERR_CANT_CREATE (-117) +/** Directory can't be deleted. */ +#define VERR_CANT_DELETE_DIRECTORY (-118) +/** Can't move file to another disk. */ +#define VERR_NOT_SAME_DEVICE (-119) +/** The filename or extension is too long. */ +#define VERR_FILENAME_TOO_LONG (-120) +/** Media not present in drive. */ +#define VERR_MEDIA_NOT_PRESENT (-121) +/** The type of media was not recognized. Not formatted? */ +#define VERR_MEDIA_NOT_RECOGNIZED (-122) +/** Can't unlock - region was not locked. */ +#define VERR_FILE_NOT_LOCKED (-123) +/** Unrecoverable error: lock was lost. */ +#define VERR_FILE_LOCK_LOST (-124) +/** Can't delete directory with files. */ +#define VERR_DIR_NOT_EMPTY (-125) +/** A directory operation was attempted on a non-directory object. */ +#define VERR_NOT_A_DIRECTORY (-126) +/** A non-directory operation was attempted on a directory object. */ +#define VERR_IS_A_DIRECTORY (-127) +/** Tried to grow a file beyond the limit imposed by the process or the filesystem. */ +#define VERR_FILE_TOO_BIG (-128) /** @name Generic Directory Enumeration Status Codes * @{ @@ -1286,6 +1352,10 @@ typedef struct _SHFLCREATEPARMS /** Lock entire object. */ #define SHFL_LOCK_ENTIRE (0x8) +#define SHFL_RENAME_FILE (0x1) +#define SHFL_RENAME_DIR (0x2) +#define SHFL_RENAME_REPLACE_IF_EXISTS (0x4) + /** @name Shared Folders mappings. * @{ */ diff --git a/vboxshfl.h b/vboxshfl.h index 04afed0..36cd818 100644 --- a/vboxshfl.h +++ b/vboxshfl.h @@ -22,17 +22,19 @@ #include "vboxhgcm.h" -#define SHFLSTRING_WITH_BUF(name, size) \ +#define SHFLSTRING_WITH_BUF(varname, bufsize) \ struct { \ SHFLSTRING shflstr; \ - char buf[size]; \ - } name = { {size, 0} } + char buf[bufsize]; \ + } varname = { .shflstr = { .u16Size = bufsize} } -#define SHFLDIRINFO_WITH_BUF(name, size) \ +#define SHFLDIRINFO_WITH_NAME_BUF(varname, bufsize) \ struct { \ SHFLDIRINFO dirinfo; \ - char buf[size]; \ - } name + char buf[bufsize]; \ + } varname = { \ + .dirinfo = { .name = { .u16Size = bufsize} } \ + } static inline unsigned shflstring_size_with_buf(const SHFLSTRING *str) { @@ -429,6 +431,40 @@ static int32_t vbox_shfl_remove(LPVBOXCOMM vb, hgcm_client_id_t client_id, SHFLR return req->header.result; } +static int32_t vbox_shfl_rename(LPVBOXCOMM vb, hgcm_client_id_t client_id, SHFLROOT root, + const SHFLSTRING *src, const SHFLSTRING *dst, unsigned flags) +{ + VMMDevHGCMCall __far *req = (void __far *) vb->buf; + vbox_hgcm_init_call(req, client_id, SHFL_FN_RENAME, 4); + + // arg 0 in uint32 "root" + req->aParms[0].type = VMMDevHGCMParmType_32bit; + req->aParms[0].u.value32 = root; + + // arg 1 in shflstring "src" + req->aParms[1].type = VMMDevHGCMParmType_LinAddr; + req->aParms[1].u.Pointer.size = shflstring_size_with_buf(src); + req->aParms[1].u.Pointer.u.linearAddr = linear_addr(src); + + // arg 2 in shflstring "dst" + req->aParms[2].type = VMMDevHGCMParmType_LinAddr; + req->aParms[2].u.Pointer.size = shflstring_size_with_buf(dst); + req->aParms[2].u.Pointer.u.linearAddr = linear_addr(dst); + + // arg 3 in uint32 "flags" + req->aParms[3].type = VMMDevHGCMParmType_32bit; + req->aParms[3].u.value32 = flags; + + vbox_send_request(vb->iobase, vb->dds.physicalAddress); + + if (req->header.header.rc < 0) { + return req->header.header.rc; + } else if (req->header.header.rc == VINF_HGCM_ASYNC_EXECUTE) { + vbox_hgcm_wait(&req->header); + } + + return req->header.result; +} static int32_t vbox_shfl_set_utf8(LPVBOXCOMM vb, hgcm_client_id_t client_id) { -- cgit v1.2.3