1120 lines
31 KiB
PHP
1120 lines
31 KiB
PHP
; =============================================================================
|
||
; Модуль : VBox SharedFolder Service
|
||
; Назначение : Подключение VBox shared folders как ФС в KolibriOS
|
||
; Файл : services/shared_folders/shared_folders.inc
|
||
; Протокол : HGCM (VBoxSharedFolders)
|
||
;
|
||
; Функционал:
|
||
; - Подключение к HGCM сервису VBoxSharedFolders
|
||
; - Включение UTF-8 режима (SHFL_FN_SET_UTF8)
|
||
; - Запрос и подключение всех shared folders
|
||
; - Регистрация диска через DiskAdd + ФС через FsAdd
|
||
; - Обслуживание ReadFolder/Read/GetFileInfo через SHFL
|
||
; =============================================================================
|
||
|
||
svc_shfl_name db "SHARED_FOLDERS", 0
|
||
|
||
align 4
|
||
sz_shfl_hgcm_service db 'VBoxSharedFolders', 0
|
||
|
||
; --- Data ---
|
||
align 4
|
||
sf_state SF_STATE
|
||
|
||
; Данные для диска
|
||
align 4
|
||
vboxsf_data VBOXSF_DISK
|
||
|
||
; Буферы выделяются динамически в shfl_init, указатели хранятся в sf_state
|
||
|
||
; Состояние
|
||
align 4
|
||
sf_map_count dd 0 ; Количество найденных mappings
|
||
sf_list_resume dd 0 ; Resume point для LIST пагинации
|
||
sf_list_total dd 0 ; Общее количество файлов (все страницы)
|
||
|
||
; vboxsf_add_folder — Добавить папку в массив vboxsf_data
|
||
proc vboxsf_add_folder stdcall uses ebx ecx edx esi edi, root:dword, name_ptr:dword
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] add_folder: root=%d name='%s'\n", [root], [name_ptr]
|
||
|
||
; Проверить лимит
|
||
cmp dword [vboxsf_data.count], 32
|
||
jae .error
|
||
|
||
; Выделить память для SF_FOLDER
|
||
invoke KernelAlloc, 4096
|
||
test eax, eax
|
||
jz .error
|
||
|
||
; Инициализировать структуру
|
||
mov edi, eax
|
||
push edi
|
||
|
||
; Очистить
|
||
push eax
|
||
xor eax, eax
|
||
mov ecx, sizeof.SF_FOLDER / 4
|
||
rep stosd
|
||
pop eax
|
||
pop edi
|
||
|
||
; Сохранить указатель в массив
|
||
mov ecx, [vboxsf_data.count]
|
||
mov [vboxsf_data.folders + ecx*4], edi
|
||
|
||
; Установить root handle
|
||
mov edx, [root]
|
||
mov [edi + SF_FOLDER.root_handle], edx
|
||
|
||
; Установить active
|
||
mov dword [edi + SF_FOLDER.active], 1
|
||
|
||
; Скопировать имя папки (UTF-8)
|
||
mov esi, [name_ptr]
|
||
lea edi, [edi + SF_FOLDER.name]
|
||
mov ecx, 255
|
||
|
||
.copy_name:
|
||
lodsb
|
||
stosb
|
||
test al, al
|
||
jz .name_done
|
||
dec ecx
|
||
jnz .copy_name
|
||
|
||
.name_done:
|
||
mov byte [edi], 0 ; гарантировать null-terminator
|
||
|
||
; Увеличить счётчик папок
|
||
inc dword [vboxsf_data.count]
|
||
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] folder added, total count: %d\n", [vboxsf_data.count]
|
||
xor eax, eax
|
||
ret
|
||
|
||
.error:
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] add_folder: failed\n"
|
||
mov eax, -1
|
||
ret
|
||
endp
|
||
|
||
; vboxsf_register_disk — Зарегистрировать виртуальный диск + ФС в системе
|
||
; Смещения в структуре DISK ядра (вычислены из kernel/trunk/blkdev/disk.inc + const.inc)
|
||
; MUTEX = LHEAD(8) + count(4) = 12 bytes
|
||
; DISKMEDIAINFO = Flags(4) + SectorSize(4) + Capacity(8) + LastSessionSector(4) = 20 bytes
|
||
; DISK layout: Next(4) + Prev(4) + Functions(4) + Name(4) + UserData(4) +
|
||
; DriverFlags(4) + RefCount(4) + MediaLock(12) +
|
||
; MediaInserted(1) + MediaUsed(1) + pad(2) + MediaRefCount(4) +
|
||
; MediaInfo(20) = 68
|
||
KDISK_OFS_NUMPARTITIONS = 68
|
||
KDISK_OFS_PARTITIONS = 72
|
||
|
||
proc vboxsf_register_disk stdcall uses ebx ecx edx esi edi
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Registering filesystem...\n"
|
||
|
||
; Проверить что есть хотя бы одна папка
|
||
cmp dword [vboxsf_data.count], 0
|
||
je .no_folders
|
||
|
||
; --- Шаг 1: DiskAdd — создать виртуальный диск ---
|
||
; НЕ используем FsAdd — в ядре баг: fs_add итерирует ВСЕ диски
|
||
; включая те, у которых NumPartitions не инициализирован (CD без диска),
|
||
; что вызывает GPF. Вместо этого вручную ставим FSUserFunctions.
|
||
invoke DiskAdd, vboxsf_disk_functions, sz_vboxsf_diskname, vboxsf_data, 0
|
||
|
||
DEBUGF __DEBUG_SF__, "[DiskAdd] result eax=0x%x\n", eax
|
||
test eax, eax
|
||
jz .disk_failed
|
||
|
||
mov [vboxsf_data.disk_handle], eax
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] DiskAdd OK, handle=0x%x\n", eax
|
||
|
||
; --- Шаг 2: DiskMediaChanged — ядро создаст raw-раздел ---
|
||
; vboxsf_read_sectors вернёт нули → нет MBR → disk_add_partition создаст
|
||
; один раздел с default_fs_functions (ни одна встроенная ФС не узнает).
|
||
invoke DiskMediaChanged, [vboxsf_data.disk_handle], 1
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] DiskMediaChanged done\n"
|
||
|
||
; --- Шаг 3: Вручную установить наши FSUserFunctions на раздел ---
|
||
mov eax, [vboxsf_data.disk_handle]
|
||
mov ecx, [eax + KDISK_OFS_NUMPARTITIONS]
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] NumPartitions=%d\n", ecx
|
||
|
||
test ecx, ecx
|
||
jz .no_partitions
|
||
|
||
mov ecx, [eax + KDISK_OFS_PARTITIONS] ; ecx = Partitions array
|
||
mov ecx, [ecx] ; ecx = first PARTITION*
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Partition[0]=0x%x, old FSUserFuncs=0x%x\n", ecx, [ecx + KPARTITION_OFS_FSUSERFUNCTIONS]
|
||
|
||
; Заменить default_fs_functions на наши
|
||
mov dword [ecx + KPARTITION_OFS_FSUSERFUNCTIONS], vboxsf_user_functions
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Set FSUserFunctions=0x%x\n", vboxsf_user_functions
|
||
|
||
; Верификация: прочитать обратно и показать содержимое таблицы
|
||
mov eax, [ecx + KPARTITION_OFS_FSUSERFUNCTIONS]
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Verify readback=0x%x\n", eax
|
||
mov eax, [vboxsf_user_functions + 0]
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Table[0] free=0x%x\n", eax
|
||
mov eax, [vboxsf_user_functions + 4]
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Table[1] count=%d\n", eax
|
||
mov eax, [vboxsf_user_functions + 8]
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Table[2] subfn0_Read=0x%x\n", eax
|
||
mov eax, [vboxsf_user_functions + 12]
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Table[3] subfn1_ReadFolder=0x%x\n", eax
|
||
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Disk + FS registered, accessible via /vbox/1/\n"
|
||
mov eax, [vboxsf_data.disk_handle]
|
||
ret
|
||
|
||
.no_folders:
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] No folders to register\n"
|
||
xor eax, eax
|
||
ret
|
||
|
||
.no_partitions:
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] ERROR: DiskMediaChanged created 0 partitions\n"
|
||
xor eax, eax
|
||
ret
|
||
|
||
.disk_failed:
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] DiskAdd failed\n"
|
||
xor eax, eax
|
||
ret
|
||
|
||
endp
|
||
|
||
; shfl_init — Инициализация SharedFolder сервиса
|
||
proc shfl_init uses ebx ecx edx esi edi
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Initializing SharedFolders...\n"
|
||
|
||
; Проверка что HGCM готов
|
||
mov eax, [vbox_device.hgcm_connect_virt]
|
||
test eax, eax
|
||
jz .hgcm_not_ready
|
||
|
||
; Уже подключены?
|
||
cmp dword [sf_state.connected], 1
|
||
je .already_connected
|
||
|
||
; --- Выделить init-буферы ---
|
||
invoke KernelAlloc, 4096 ; sf_packet
|
||
test eax, eax
|
||
jz .alloc_fail
|
||
mov [sf_state.packet_ptr], eax
|
||
|
||
invoke KernelAlloc, 4096 ; sf_listbuf
|
||
test eax, eax
|
||
jz .alloc_fail_free1
|
||
mov [sf_state.listbuf_ptr], eax
|
||
|
||
invoke KernelAlloc, 4096 ; small_bufs: mappings+namebuf+cp866+dir_path+createparms
|
||
test eax, eax
|
||
jz .alloc_fail_free2
|
||
mov [sf_state.small_bufs_ptr], eax
|
||
|
||
; Вычислить указатели внутри small_bufs
|
||
lea ecx, [eax + 0]
|
||
mov [sf_state.mappings_ptr], ecx ; +0: 512 байт
|
||
lea ecx, [eax + 512]
|
||
mov [sf_state.namebuf_ptr], ecx ; +512: 512 байт
|
||
lea ecx, [eax + 1024]
|
||
mov [sf_state.cp866_buf_ptr], ecx ; +1024: 512 байт
|
||
lea ecx, [eax + 1536]
|
||
mov [sf_state.dir_path_ptr], ecx ; +1536: 32 байт
|
||
lea ecx, [eax + 1568]
|
||
mov [sf_state.createparms_ptr], ecx ; +1568: 128 байт
|
||
|
||
DEBUGF 2, "[VBoxGuest] [SF] Init buffers allocated\n"
|
||
|
||
; Подключение к HGCM сервису
|
||
DEBUGF 2, "[VBoxGuest] [SF] Connecting to '%s'...\n", sz_shfl_hgcm_service
|
||
stdcall hgcm_connect, sz_shfl_hgcm_service
|
||
test eax, eax
|
||
jz .connect_failed
|
||
|
||
mov [sf_state.client_id], eax
|
||
mov dword [sf_state.connected], 1
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Connected! client_id=%d\n", eax
|
||
|
||
; --- Выделить FS-буферы ---
|
||
invoke KernelAlloc, 4096 ; fs_packet
|
||
test eax, eax
|
||
jz .fs_alloc_fail
|
||
mov [sf_state.fs_packet_ptr], eax
|
||
|
||
invoke KernelAlloc, 4096 ; fs_listbuf
|
||
test eax, eax
|
||
jz .fs_alloc_fail_f1
|
||
mov [sf_state.fs_listbuf_ptr], eax
|
||
|
||
invoke KernelAlloc, 65536 ; fs_iobuf (64KB bounce buffer)
|
||
test eax, eax
|
||
jz .fs_alloc_fail_f2
|
||
mov [sf_state.fs_iobuf_ptr], eax
|
||
|
||
invoke KernelAlloc, 4096 ; fs_cparms (page-aligned for PageList)
|
||
test eax, eax
|
||
jz .fs_alloc_fail_f3
|
||
mov [sf_state.fs_cparms_ptr], eax
|
||
|
||
invoke KernelAlloc, 4096 ; fs_small_bufs: pathbuf+pathbuf2
|
||
test eax, eax
|
||
jz .fs_alloc_fail_f4
|
||
mov [sf_state.fs_small_bufs_ptr], eax
|
||
|
||
; Вычислить указатели внутри fs_small_bufs
|
||
lea ecx, [eax + 0]
|
||
mov [sf_state.fs_pathbuf_ptr], ecx ; +0: 1024 байт
|
||
lea ecx, [eax + 1024]
|
||
mov [sf_state.fs_pathbuf2_ptr], ecx ; +1024: 1024 байт
|
||
|
||
DEBUGF 2, "[VBoxGuest] [SF] FS buffers allocated\n"
|
||
|
||
; Перечислить папки, подключить, зарегистрировать диск+ФС
|
||
stdcall shfl_list_all
|
||
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] Initialized OK\n"
|
||
xor eax, eax
|
||
ret
|
||
|
||
.connect_failed:
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] HGCM connect failed\n"
|
||
; Init-буферы уже выделены — освободить
|
||
call shfl_free_init_bufs
|
||
mov eax, VERR_HGCM_SERVICE_NOT_FOUND
|
||
ret
|
||
|
||
; FS buffer allocation failure cascade
|
||
.fs_alloc_fail_f4:
|
||
invoke KernelFree, [sf_state.fs_cparms_ptr]
|
||
mov dword [sf_state.fs_cparms_ptr], 0
|
||
.fs_alloc_fail_f3:
|
||
invoke KernelFree, [sf_state.fs_iobuf_ptr]
|
||
mov dword [sf_state.fs_iobuf_ptr], 0
|
||
.fs_alloc_fail_f2:
|
||
invoke KernelFree, [sf_state.fs_listbuf_ptr]
|
||
mov dword [sf_state.fs_listbuf_ptr], 0
|
||
.fs_alloc_fail_f1:
|
||
invoke KernelFree, [sf_state.fs_packet_ptr]
|
||
mov dword [sf_state.fs_packet_ptr], 0
|
||
.fs_alloc_fail:
|
||
DEBUGF 2, "[VBoxGuest] [SF] KernelAlloc failed for FS buffers\n"
|
||
; HGCM уже подключен — отключить
|
||
stdcall hgcm_disconnect, [sf_state.client_id]
|
||
mov dword [sf_state.connected], 0
|
||
mov dword [sf_state.client_id], 0
|
||
call shfl_free_init_bufs
|
||
mov eax, VERR_NO_MEMORY
|
||
ret
|
||
|
||
; Init buffer allocation failure cascade
|
||
.alloc_fail_free2:
|
||
invoke KernelFree, [sf_state.listbuf_ptr]
|
||
mov dword [sf_state.listbuf_ptr], 0
|
||
.alloc_fail_free1:
|
||
invoke KernelFree, [sf_state.packet_ptr]
|
||
mov dword [sf_state.packet_ptr], 0
|
||
.alloc_fail:
|
||
DEBUGF 2, "[VBoxGuest] [SF] KernelAlloc failed for init buffers\n"
|
||
mov eax, VERR_NO_MEMORY
|
||
ret
|
||
|
||
.hgcm_not_ready:
|
||
DEBUGF __DEBUG_SF__, "[VBoxGuest] [SF] HGCM not ready\n"
|
||
mov eax, VERR_NOT_READY
|
||
ret
|
||
|
||
.already_connected:
|
||
DEBUGF 2, "[VBoxGuest] [SF] Already connected\n"
|
||
xor eax, eax
|
||
ret
|
||
endp
|
||
|
||
; shfl_list_all — Перечислить все shared folders, подключить, зарегистрировать
|
||
proc shfl_list_all uses ebx ecx edx esi edi
|
||
locals
|
||
map_idx dd ?
|
||
map_root dd ?
|
||
endl
|
||
|
||
cmp dword [sf_state.connected], 1
|
||
jne .not_connected
|
||
|
||
; ================================================================
|
||
; Шаг 1: SET_UTF8 (fn=16, 0 параметров)
|
||
; ================================================================
|
||
mov edi, [sf_state.packet_ptr]
|
||
xor eax, eax
|
||
mov ecx, 256/4
|
||
rep stosd
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
mov dword [edi + 0], 44 ; size (header only)
|
||
mov dword [edi + 4], 0x00010001 ; version
|
||
mov dword [edi + 8], 62 ; HGCM_CALL32
|
||
mov dword [edi + 12], VERR_GENERAL_FAILURE ; rc
|
||
mov dword [edi + 16], 0 ; reserved1
|
||
mov dword [edi + 20], 0x00000081 ; f_requestor
|
||
mov dword [edi + 24], 0 ; fu32Flags
|
||
mov dword [edi + 28], 0 ; result
|
||
mov eax, [sf_state.client_id]
|
||
mov dword [edi + 32], eax ; client_id
|
||
mov dword [edi + 36], 16 ; SHFL_FN_SET_UTF8
|
||
mov dword [edi + 40], 0 ; param_count = 0
|
||
|
||
stdcall hgcm_send_request, edi
|
||
|
||
mov eax, dword [edi +28]
|
||
DEBUGF __DEBUG_SF__, "[SF] SET_UTF8 result: %d\n", eax
|
||
|
||
; ================================================================
|
||
; Шаг 2: QUERY_MAPPINGS (fn=1, 3 параметра)
|
||
; ================================================================
|
||
mov edi, [sf_state.packet_ptr]
|
||
xor eax, eax
|
||
mov ecx, 1024/4
|
||
rep stosd
|
||
|
||
mov edi, [sf_state.mappings_ptr]
|
||
xor eax, eax
|
||
mov ecx, 512/4
|
||
rep stosd
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
|
||
mov dword [edi + 0], 96
|
||
mov dword [edi + 4], 0x00010001
|
||
mov dword [edi + 8], 62
|
||
mov dword [edi + 12], 0xFFFFFFFF
|
||
mov dword [edi + 16], 0
|
||
mov dword [edi + 20], 0x00000081
|
||
mov dword [edi + 24], 0
|
||
mov dword [edi + 28], 0
|
||
mov eax, [sf_state.client_id]
|
||
mov dword [edi + 32], eax
|
||
mov dword [edi + 36], 1 ; SHFL_FN_QUERY_MAPPINGS
|
||
mov dword [edi + 40], 3 ; 3 params
|
||
|
||
; parm[0] @ +44: flags = SHFL_MF_UTF8 (1)
|
||
mov dword [edi + 44], 1
|
||
mov dword [edi + 48], 1
|
||
mov dword [edi + 52], 0
|
||
|
||
; parm[1] @ +56: numberOfMappings = SHFL_MAX_FOLDERS
|
||
mov dword [edi + 56], 1
|
||
mov dword [edi + 60], SHFL_MAX_FOLDERS
|
||
mov dword [edi + 64], 0
|
||
|
||
; parm[2] @ +68: PageList OUT, cbData = SHFL_MAX_FOLDERS * 8
|
||
mov dword [edi + 68], 10 ; type = PAGELIST
|
||
mov dword [edi + 72], SHFL_MAX_FOLDERS * 8
|
||
mov dword [edi + 76], SHFL_MAX_FOLDERS * 8
|
||
|
||
; PageListInfo @ +80
|
||
push edi
|
||
mov eax, [sf_state.mappings_ptr]
|
||
and eax, PAGE_BASE_MASK
|
||
invoke GetPhysAddr
|
||
mov ebx, eax
|
||
pop edi
|
||
|
||
mov dword [edi + 80], 2
|
||
mov eax, [sf_state.mappings_ptr]
|
||
and eax, PAGE_OFFSET_MASK
|
||
mov word [edi + 84], ax
|
||
mov word [edi + 86], 1
|
||
mov dword [edi + 88], ebx
|
||
mov dword [edi + 92], 0
|
||
|
||
stdcall hgcm_send_request, edi
|
||
|
||
mov eax, dword [edi +12]
|
||
mov ebx, dword [edi +28]
|
||
DEBUGF __DEBUG_SF__, "[SF] QUERY_MAPPINGS: rc=0x%x result=%d\n", eax, ebx
|
||
|
||
test ebx, ebx
|
||
jnz .qm_failed
|
||
|
||
mov ecx, dword [edi +60]
|
||
DEBUGF __DEBUG_SF__, "[SF] Found %d shared folders\n", ecx
|
||
|
||
test ecx, ecx
|
||
jz .no_folders
|
||
|
||
cmp ecx, SHFL_MAX_FOLDERS
|
||
jbe @f
|
||
mov ecx, SHFL_MAX_FOLDERS
|
||
@@:
|
||
mov [sf_map_count], ecx
|
||
|
||
; ================================================================
|
||
; Шаг 3: Для каждого mapping — получить имя, подключить, добавить
|
||
; ================================================================
|
||
mov dword [map_idx], 0
|
||
mov esi, [sf_state.mappings_ptr]
|
||
|
||
.folder_loop:
|
||
mov eax, [map_idx]
|
||
cmp eax, [sf_map_count]
|
||
jae .all_done
|
||
|
||
push esi
|
||
|
||
; Получить root index из SHFLMAPPING
|
||
mov eax, [esi + 4]
|
||
|
||
; --- 3a: QUERY_MAP_NAME ---
|
||
mov edi, [sf_state.namebuf_ptr]
|
||
push eax
|
||
xor eax, eax
|
||
mov ecx, 512/4
|
||
rep stosd
|
||
pop eax
|
||
mov edi, [sf_state.namebuf_ptr]
|
||
mov word [edi + 0], 508
|
||
mov word [edi + 2], 0
|
||
|
||
push eax
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
xor eax, eax
|
||
mov ecx, 256/4
|
||
rep stosd
|
||
|
||
pop eax
|
||
mov edi, [sf_state.packet_ptr]
|
||
|
||
mov dword [edi + 0], 92
|
||
mov dword [edi + 4], 0x00010001
|
||
mov dword [edi + 8], 62
|
||
mov dword [edi + 12], 0xFFFFFFFF
|
||
mov dword [edi + 16], 0
|
||
mov dword [edi + 20], 0x00000081
|
||
mov dword [edi + 24], 0
|
||
mov dword [edi + 28], 0
|
||
push eax
|
||
mov eax, [sf_state.client_id]
|
||
mov dword [edi + 32], eax
|
||
pop eax
|
||
mov dword [edi + 36], 2
|
||
mov dword [edi + 40], 2
|
||
|
||
mov dword [edi + 44], 1
|
||
mov dword [edi + 48], eax
|
||
mov dword [edi + 52], 0
|
||
|
||
mov dword [edi + 56], 10
|
||
mov dword [edi + 60], 512
|
||
mov dword [edi + 64], 68
|
||
|
||
push edi
|
||
mov eax, [sf_state.namebuf_ptr]
|
||
and eax, PAGE_BASE_MASK
|
||
invoke GetPhysAddr
|
||
mov ebx, eax
|
||
pop edi
|
||
|
||
mov dword [edi + 68], 3
|
||
mov eax, [sf_state.namebuf_ptr]
|
||
and eax, PAGE_OFFSET_MASK
|
||
mov word [edi + 72], ax
|
||
mov word [edi + 74], 1
|
||
mov dword [edi + 76], ebx
|
||
mov dword [edi + 80], 0
|
||
|
||
stdcall hgcm_send_request, edi
|
||
|
||
mov eax, dword [edi +28]
|
||
test eax, eax
|
||
jnz .name_failed
|
||
|
||
mov edi, [sf_state.namebuf_ptr]
|
||
movzx eax, word [edi + 2]
|
||
test eax, eax
|
||
jz .name_failed
|
||
|
||
; Null-terminate имя
|
||
lea edi, [edi + 4]
|
||
mov byte [edi + eax], 0
|
||
|
||
; Конвертировать UTF-8 -> CP866 для отладочного вывода
|
||
push eax
|
||
stdcall sf_utf8_to_cp866, edi, [sf_state.cp866_buf_ptr], eax
|
||
pop eax
|
||
|
||
DEBUGF __DEBUG_SF__, "[SF] Folder[%d]: '%s'\n", [map_idx], [sf_state.cp866_buf_ptr]
|
||
|
||
; --- 3b: MAP_FOLDER ---
|
||
mov edi, [sf_state.namebuf_ptr]
|
||
movzx eax, word [edi + 2]
|
||
inc eax
|
||
mov word [edi + 0], ax
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
xor eax, eax
|
||
mov ecx, 256/4
|
||
rep stosd
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
|
||
mov dword [edi + 0], 108
|
||
mov dword [edi + 4], 0x00010001
|
||
mov dword [edi + 8], 62
|
||
mov dword [edi + 12], 0xFFFFFFFF
|
||
mov dword [edi + 16], 0
|
||
mov dword [edi + 20], 0x00000081
|
||
mov dword [edi + 24], 0
|
||
mov dword [edi + 28], 0
|
||
mov eax, [sf_state.client_id]
|
||
mov dword [edi + 32], eax
|
||
mov dword [edi + 36], 17
|
||
mov dword [edi + 40], 4
|
||
|
||
mov dword [edi + 44], 10
|
||
push ecx
|
||
mov ecx, [sf_state.namebuf_ptr]
|
||
movzx eax, word [ecx + 0]
|
||
pop ecx
|
||
add eax, 4
|
||
mov dword [edi + 48], eax
|
||
mov dword [edi + 52], 92
|
||
|
||
mov dword [edi + 56], 1
|
||
mov dword [edi + 60], 0
|
||
mov dword [edi + 64], 0
|
||
|
||
mov dword [edi + 68], 1
|
||
mov dword [edi + 72], '/'
|
||
mov dword [edi + 76], 0
|
||
|
||
mov dword [edi + 80], 1
|
||
mov dword [edi + 84], 1
|
||
mov dword [edi + 88], 0
|
||
|
||
push edi
|
||
mov eax, [sf_state.namebuf_ptr]
|
||
and eax, PAGE_BASE_MASK
|
||
invoke GetPhysAddr
|
||
mov ebx, eax
|
||
pop edi
|
||
|
||
mov dword [edi + 92], 1
|
||
mov eax, [sf_state.namebuf_ptr]
|
||
and eax, PAGE_OFFSET_MASK
|
||
mov word [edi + 96], ax
|
||
mov word [edi + 98], 1
|
||
mov dword [edi + 100], ebx
|
||
mov dword [edi + 104], 0
|
||
|
||
stdcall hgcm_send_request, edi
|
||
|
||
mov ebx, dword [edi +28]
|
||
test ebx, ebx
|
||
jnz .map_failed
|
||
|
||
; Получить root handle
|
||
mov eax, dword [edi +60]
|
||
mov [map_root], eax
|
||
DEBUGF __DEBUG_SF__, "[SF] Mapped, root=%d\n", eax
|
||
|
||
; --- 3c: Добавить папку в массив для диска ---
|
||
mov edi, [sf_state.namebuf_ptr]
|
||
lea edi, [edi + 4] ; UTF-8 имя
|
||
stdcall vboxsf_add_folder, eax, edi
|
||
|
||
; --- 3d: Листинг корневой директории (debug) ---
|
||
stdcall shfl_list_root, [map_root]
|
||
|
||
jmp .next_folder
|
||
|
||
.name_failed:
|
||
DEBUGF __DEBUG_SF__, "[SF] Folder[%d]: <name query failed>\n", [map_idx]
|
||
jmp .next_folder
|
||
|
||
.map_failed:
|
||
DEBUGF __DEBUG_SF__, "[SF] Folder[%d]: <map failed, result=%d>\n", [map_idx], ebx
|
||
|
||
.next_folder:
|
||
pop esi
|
||
add esi, 8
|
||
inc dword [map_idx]
|
||
jmp .folder_loop
|
||
|
||
.all_done:
|
||
DEBUGF __DEBUG_SF__, "[SF] All %d folders enumerated\n", [sf_map_count]
|
||
|
||
; --- Шаг 4: Зарегистрировать диск + ФС ---
|
||
stdcall vboxsf_register_disk
|
||
test eax, eax
|
||
jz .disk_failed
|
||
|
||
DEBUGF __DEBUG_SF__, "[SF] Virtual disk registered OK\n"
|
||
xor eax, eax
|
||
ret
|
||
|
||
.disk_failed:
|
||
DEBUGF __DEBUG_SF__, "[SF] Failed to register virtual disk\n"
|
||
xor eax, eax
|
||
ret
|
||
|
||
.qm_failed:
|
||
DEBUGF __DEBUG_SF__, "[SF] QUERY_MAPPINGS failed: result=%d\n", ebx
|
||
ret
|
||
|
||
.no_folders:
|
||
DEBUGF __DEBUG_SF__, "[SF] No shared folders found\n"
|
||
xor eax, eax
|
||
ret
|
||
|
||
.not_connected:
|
||
DEBUGF __DEBUG_SF__, "[SF] Not connected\n"
|
||
mov eax, -1
|
||
ret
|
||
endp
|
||
|
||
; shfl_list_root — Листинг корневой директории mapped папки (debug)
|
||
proc shfl_list_root uses ebx ecx edx esi edi, root_handle:dword
|
||
locals
|
||
dir_handle_lo dd ?
|
||
dir_handle_hi dd ?
|
||
list_bytes dd ?
|
||
list_files dd ?
|
||
endl
|
||
|
||
; Подготовить SHFLSTRING path = "/"
|
||
mov edi, [sf_state.dir_path_ptr]
|
||
xor eax, eax
|
||
mov ecx, 4
|
||
rep stosd
|
||
mov edi, [sf_state.dir_path_ptr]
|
||
mov word [edi + 0], 2
|
||
mov word [edi + 2], 1
|
||
mov byte [edi + 4], '/'
|
||
mov byte [edi + 5], 0
|
||
|
||
; Подготовить SHFLCREATEPARMS
|
||
mov edi, [sf_state.createparms_ptr]
|
||
xor eax, eax
|
||
mov ecx, 128/4
|
||
rep stosd
|
||
mov edi, [sf_state.createparms_ptr]
|
||
mov dword [edi + 12], 0x00001104
|
||
|
||
; CREATE "/"
|
||
mov edi, [sf_state.packet_ptr]
|
||
xor eax, eax
|
||
mov ecx, 512/4
|
||
rep stosd
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
mov dword [edi + 0], 112
|
||
mov dword [edi + 4], 0x00010001
|
||
mov dword [edi + 8], 62
|
||
mov dword [edi + 12], 0xFFFFFFFF
|
||
mov dword [edi + 16], 0
|
||
mov dword [edi + 20], 0x00000081
|
||
mov dword [edi + 24], 0
|
||
mov dword [edi + 28], 0
|
||
mov eax, [sf_state.client_id]
|
||
mov dword [edi + 32], eax
|
||
mov dword [edi + 36], 3
|
||
mov dword [edi + 40], 3
|
||
|
||
mov dword [edi + 44], 1
|
||
mov eax, [root_handle]
|
||
mov dword [edi + 48], eax
|
||
mov dword [edi + 52], 0
|
||
|
||
mov dword [edi + 56], 10
|
||
mov dword [edi + 60], 6
|
||
mov dword [edi + 64], 80
|
||
|
||
mov dword [edi + 68], 10
|
||
mov dword [edi + 72], 108
|
||
mov dword [edi + 76], 96
|
||
|
||
push edi
|
||
mov eax, [sf_state.dir_path_ptr]
|
||
and eax, PAGE_BASE_MASK
|
||
invoke GetPhysAddr
|
||
mov ebx, eax
|
||
pop edi
|
||
|
||
mov dword [edi + 80], 3
|
||
mov eax, [sf_state.dir_path_ptr]
|
||
and eax, PAGE_OFFSET_MASK
|
||
mov word [edi + 84], ax
|
||
mov word [edi + 86], 1
|
||
mov dword [edi + 88], ebx
|
||
mov dword [edi + 92], 0
|
||
|
||
push edi
|
||
mov eax, [sf_state.createparms_ptr]
|
||
and eax, PAGE_BASE_MASK
|
||
invoke GetPhysAddr
|
||
mov ebx, eax
|
||
pop edi
|
||
|
||
mov dword [edi + 96], 3
|
||
mov eax, [sf_state.createparms_ptr]
|
||
and eax, PAGE_OFFSET_MASK
|
||
mov word [edi + 100], ax
|
||
mov word [edi + 102], 1
|
||
mov dword [edi + 104], ebx
|
||
mov dword [edi + 108], 0
|
||
|
||
stdcall hgcm_send_request, edi
|
||
|
||
mov ebx, dword [edi +28]
|
||
test ebx, ebx
|
||
jnz .create_failed
|
||
|
||
mov ecx, [sf_state.createparms_ptr]
|
||
mov eax, dword [ecx + 0]
|
||
mov ebx, dword [ecx + 4]
|
||
mov [dir_handle_lo], eax
|
||
mov [dir_handle_hi], ebx
|
||
|
||
; LIST с пагинацией
|
||
mov dword [sf_list_resume], 0
|
||
mov dword [sf_list_total], 0
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
xor eax, eax
|
||
mov ecx, 512/4
|
||
rep stosd
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
mov dword [edi + 0], 172
|
||
mov dword [edi + 4], 0x00010001
|
||
mov dword [edi + 8], 62
|
||
mov dword [edi + 12], 0xFFFFFFFF
|
||
mov dword [edi + 16], 0
|
||
mov dword [edi + 20], 0x00000081
|
||
mov dword [edi + 24], 0
|
||
mov dword [edi + 28], 0
|
||
mov eax, [sf_state.client_id]
|
||
mov dword [edi + 32], eax
|
||
mov dword [edi + 36], 8
|
||
mov dword [edi + 40], 8
|
||
|
||
mov dword [edi + 44], 1
|
||
mov eax, [root_handle]
|
||
mov dword [edi + 48], eax
|
||
mov dword [edi + 52], 0
|
||
|
||
mov dword [edi + 56], 2
|
||
mov eax, [dir_handle_lo]
|
||
mov dword [edi + 60], eax
|
||
mov eax, [dir_handle_hi]
|
||
mov dword [edi + 64], eax
|
||
|
||
mov dword [edi + 68], 1
|
||
mov dword [edi + 72], 0
|
||
mov dword [edi + 76], 0
|
||
|
||
mov dword [edi + 80], 1
|
||
mov dword [edi + 84], 4096
|
||
mov dword [edi + 88], 0
|
||
|
||
mov dword [edi + 92], 10
|
||
mov dword [edi + 96], 0
|
||
mov dword [edi + 100], 140
|
||
|
||
mov dword [edi + 104], 10
|
||
mov dword [edi + 108], 4096
|
||
mov dword [edi + 112], 156
|
||
|
||
mov dword [edi + 116], 1
|
||
mov dword [edi + 120], 0
|
||
mov dword [edi + 124], 0
|
||
|
||
mov dword [edi + 128], 1
|
||
mov dword [edi + 132], 0
|
||
mov dword [edi + 136], 0
|
||
|
||
mov dword [edi + 140], 1
|
||
mov word [edi + 144], 0
|
||
mov word [edi + 146], 1
|
||
mov dword [edi + 148], 0
|
||
mov dword [edi + 152], 0
|
||
|
||
push edi
|
||
mov eax, [sf_state.listbuf_ptr]
|
||
and eax, PAGE_BASE_MASK
|
||
invoke GetPhysAddr
|
||
mov ebx, eax
|
||
pop edi
|
||
|
||
mov dword [edi + 156], 2
|
||
mov eax, [sf_state.listbuf_ptr]
|
||
and eax, PAGE_OFFSET_MASK
|
||
mov word [edi + 160], ax
|
||
mov word [edi + 162], 1
|
||
mov dword [edi + 164], ebx
|
||
mov dword [edi + 168], 0
|
||
|
||
.list_page:
|
||
push edi
|
||
mov edi, [sf_state.listbuf_ptr]
|
||
xor eax, eax
|
||
mov ecx, 4096/4
|
||
rep stosd
|
||
pop edi
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
mov dword [edi + 12], 0xFFFFFFFF
|
||
mov dword [edi + 24], 0
|
||
mov dword [edi + 28], 0
|
||
mov dword [edi + 84], 4096
|
||
mov eax, [sf_list_resume]
|
||
mov dword [edi + 120], eax
|
||
mov dword [edi + 132], 0
|
||
|
||
stdcall hgcm_send_request, edi
|
||
|
||
mov ebx, dword [edi +28]
|
||
|
||
cmp ebx, -201
|
||
je .list_done
|
||
cmp ebx, -18
|
||
je .list_done
|
||
|
||
test ebx, ebx
|
||
js .list_failed
|
||
|
||
mov eax, dword [edi +84]
|
||
mov [list_bytes], eax
|
||
mov eax, dword [edi +132]
|
||
mov [list_files], eax
|
||
|
||
test eax, eax
|
||
jz .list_done
|
||
|
||
mov esi, [sf_state.listbuf_ptr]
|
||
xor ebx, ebx
|
||
|
||
.parse_entry:
|
||
cmp ebx, [list_files]
|
||
jae .page_done
|
||
|
||
mov eax, esi
|
||
sub eax, [sf_state.listbuf_ptr]
|
||
cmp eax, [list_bytes]
|
||
jae .page_done
|
||
|
||
mov eax, dword [esi + SHFLDIRINFO_OFS_SIZE_LO]
|
||
mov ecx, dword [esi + SHFLDIRINFO_OFS_FMODE]
|
||
movzx edx, word [esi + SHFLDIRINFO_OFS_NAME_LENGTH]
|
||
|
||
push eax ecx esi
|
||
lea eax, [esi + SHFLDIRINFO_OFS_NAME_STRING]
|
||
stdcall sf_utf8_to_cp866, eax, [sf_state.cp866_buf_ptr], edx
|
||
pop esi ecx eax
|
||
|
||
push esi ebx eax
|
||
mov edx, [sf_list_total]
|
||
add edx, ebx
|
||
|
||
test ecx, 0x4000
|
||
jnz .is_dir
|
||
|
||
DEBUGF __DEBUG_SF__, "[SF] [%d] F '%s' size=%d\n", edx, [sf_state.cp866_buf_ptr], eax
|
||
jmp .printed
|
||
.is_dir:
|
||
DEBUGF __DEBUG_SF__, "[SF] [%d] D '%s'\n", edx, [sf_state.cp866_buf_ptr]
|
||
.printed:
|
||
pop eax ebx esi
|
||
|
||
movzx eax, word [esi + SHFLDIRINFO_OFS_NAME_SIZE]
|
||
add eax, SHFLDIRINFO_OFS_NAME_STRING
|
||
add esi, eax
|
||
|
||
inc ebx
|
||
jmp .parse_entry
|
||
|
||
.page_done:
|
||
mov eax, [list_files]
|
||
add [sf_list_total], eax
|
||
|
||
mov eax, dword [edi +120]
|
||
mov [sf_list_resume], eax
|
||
|
||
mov eax, dword [edi +28]
|
||
test eax, eax
|
||
jg .list_page
|
||
|
||
mov eax, [list_files]
|
||
test eax, eax
|
||
jnz .list_page
|
||
|
||
.list_done:
|
||
DEBUGF __DEBUG_SF__, "[SF] Total: %d entries\n", [sf_list_total]
|
||
|
||
.close_dir:
|
||
mov edi, [sf_state.packet_ptr]
|
||
xor eax, eax
|
||
mov ecx, 256/4
|
||
rep stosd
|
||
|
||
mov edi, [sf_state.packet_ptr]
|
||
mov dword [edi + 0], 68
|
||
mov dword [edi + 4], 0x00010001
|
||
mov dword [edi + 8], 62
|
||
mov dword [edi + 12], 0xFFFFFFFF
|
||
mov dword [edi + 16], 0
|
||
mov dword [edi + 20], 0x00000081
|
||
mov dword [edi + 24], 0
|
||
mov dword [edi + 28], 0
|
||
mov eax, [sf_state.client_id]
|
||
mov dword [edi + 32], eax
|
||
mov dword [edi + 36], 4
|
||
mov dword [edi + 40], 2
|
||
|
||
mov dword [edi + 44], 1
|
||
mov eax, [root_handle]
|
||
mov dword [edi + 48], eax
|
||
mov dword [edi + 52], 0
|
||
|
||
mov dword [edi + 56], 2
|
||
mov eax, [dir_handle_lo]
|
||
mov dword [edi + 60], eax
|
||
mov eax, [dir_handle_hi]
|
||
mov dword [edi + 64], eax
|
||
|
||
stdcall hgcm_send_request, edi
|
||
|
||
xor eax, eax
|
||
ret
|
||
|
||
.create_failed:
|
||
DEBUGF __DEBUG_SF__, "[SF] CREATE '/' failed: result=%d\n", ebx
|
||
ret
|
||
|
||
.list_failed:
|
||
DEBUGF __DEBUG_SF__, "[SF] LIST failed: result=%d\n", ebx
|
||
jmp .close_dir
|
||
endp
|
||
|
||
; shfl_disable — Отключить SharedFolder сервис
|
||
proc shfl_disable uses ebx ecx edx esi edi
|
||
DEBUGF 2, "[VBoxGuest] [SF] Disabling (removing disk)...\n"
|
||
|
||
; 1. Заблокировать FS callbacks (guard в vboxsf.inc)
|
||
mov dword [sf_state.connected], 0
|
||
|
||
; 2. Удалить диск из системы
|
||
; DiskDel вызывает disk_media_changed(0) внутри →
|
||
; → освобождает разделы (вызывает vboxsf_fs_free) →
|
||
; → удаляет диск из глобального списка
|
||
cmp dword [vboxsf_data.disk_handle], 0
|
||
je .no_disk
|
||
invoke DiskDel, [vboxsf_data.disk_handle]
|
||
mov dword [vboxsf_data.disk_handle], 0
|
||
DEBUGF 2, "[VBoxGuest] [SF] DiskDel done\n"
|
||
.no_disk:
|
||
|
||
; 3. Отключить HGCM
|
||
cmp dword [sf_state.client_id], 0
|
||
je .no_hgcm
|
||
stdcall hgcm_disconnect, [sf_state.client_id]
|
||
mov dword [sf_state.client_id], 0
|
||
.no_hgcm:
|
||
|
||
; 4. Освободить буферы
|
||
call shfl_free_fs_bufs
|
||
call shfl_free_init_bufs
|
||
|
||
; 5. Освободить SF_FOLDER структуры и сбросить счётчик
|
||
call shfl_free_folders
|
||
|
||
DEBUGF 2, "[VBoxGuest] [SF] Disabled, disk removed\n"
|
||
xor eax, eax
|
||
ret
|
||
endp
|
||
|
||
; shfl_free_init_bufs — Освободить init-буферы SharedFolders
|
||
proc shfl_free_init_bufs
|
||
cmp dword [sf_state.packet_ptr], 0
|
||
je @f
|
||
invoke KernelFree, [sf_state.packet_ptr]
|
||
mov dword [sf_state.packet_ptr], 0
|
||
@@:
|
||
cmp dword [sf_state.listbuf_ptr], 0
|
||
je @f
|
||
invoke KernelFree, [sf_state.listbuf_ptr]
|
||
mov dword [sf_state.listbuf_ptr], 0
|
||
@@:
|
||
cmp dword [sf_state.small_bufs_ptr], 0
|
||
je @f
|
||
invoke KernelFree, [sf_state.small_bufs_ptr]
|
||
mov dword [sf_state.small_bufs_ptr], 0
|
||
; Обнулить указатели-потомки
|
||
mov dword [sf_state.mappings_ptr], 0
|
||
mov dword [sf_state.namebuf_ptr], 0
|
||
mov dword [sf_state.cp866_buf_ptr], 0
|
||
mov dword [sf_state.dir_path_ptr], 0
|
||
mov dword [sf_state.createparms_ptr], 0
|
||
@@:
|
||
ret
|
||
endp
|
||
|
||
; shfl_free_fs_bufs — Освободить FS-буферы SharedFolders
|
||
proc shfl_free_fs_bufs
|
||
cmp dword [sf_state.fs_packet_ptr], 0
|
||
je @f
|
||
invoke KernelFree, [sf_state.fs_packet_ptr]
|
||
mov dword [sf_state.fs_packet_ptr], 0
|
||
@@:
|
||
cmp dword [sf_state.fs_listbuf_ptr], 0
|
||
je @f
|
||
invoke KernelFree, [sf_state.fs_listbuf_ptr]
|
||
mov dword [sf_state.fs_listbuf_ptr], 0
|
||
@@:
|
||
cmp dword [sf_state.fs_iobuf_ptr], 0
|
||
je @f
|
||
invoke KernelFree, [sf_state.fs_iobuf_ptr]
|
||
mov dword [sf_state.fs_iobuf_ptr], 0
|
||
@@:
|
||
cmp dword [sf_state.fs_cparms_ptr], 0
|
||
je @f
|
||
invoke KernelFree, [sf_state.fs_cparms_ptr]
|
||
mov dword [sf_state.fs_cparms_ptr], 0
|
||
@@:
|
||
cmp dword [sf_state.fs_small_bufs_ptr], 0
|
||
je @f
|
||
invoke KernelFree, [sf_state.fs_small_bufs_ptr]
|
||
mov dword [sf_state.fs_small_bufs_ptr], 0
|
||
; Обнулить указатели-потомки
|
||
mov dword [sf_state.fs_pathbuf_ptr], 0
|
||
mov dword [sf_state.fs_pathbuf2_ptr], 0
|
||
@@:
|
||
ret
|
||
endp
|
||
|
||
; shfl_free_folders — Освободить SF_FOLDER структуры и сбросить счётчик
|
||
proc shfl_free_folders uses ebx esi
|
||
mov ebx, [vboxsf_data.count]
|
||
test ebx, ebx
|
||
jz .done
|
||
xor esi, esi
|
||
.loop:
|
||
cmp dword [vboxsf_data.folders + esi*4], 0
|
||
je .next
|
||
invoke KernelFree, [vboxsf_data.folders + esi*4]
|
||
mov dword [vboxsf_data.folders + esi*4], 0
|
||
.next:
|
||
inc esi
|
||
dec ebx
|
||
jnz .loop
|
||
.done:
|
||
mov dword [vboxsf_data.count], 0
|
||
ret
|
||
endp
|
||
|
||
include 'vboxsf.inc'
|
||
|
||
REGISTER_SERVICE svc_shfl_name, 0, VMMDEV_GUEST_SUPPORTS_SHARED_FOLDERS, \
|
||
shfl_init, shfl_init, shfl_disable, 0, 0, AUTOSTART_SHARED_FOLDERS
|