Changeset 32973 in vbox
- Timestamp:
- Oct 7, 2010 11:16:28 AM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r32888 r32973 37 37 #include <VBox/log.h> 38 38 #include <iprt/asm.h> 39 #include <iprt/assert.h> 40 #include <iprt/file.h> 39 41 #include <iprt/getopt.h> 42 #include <iprt/list.h> 43 #include <iprt/path.h> 40 44 #include <iprt/stream.h> 41 45 #include <iprt/string.h> … … 554 558 } 555 559 560 #ifdef VBOX_WITH_COPYTOGUEST 561 562 #define VBOX_ISO9660_MAX_SYSTEM_ID 32 563 #define VBOX_ISO9660_MAX_VOLUME_ID 32 564 #define VBOX_ISO9660_MAX_PUBLISHER_ID 128 565 #define VBOX_ISO9660_MAX_VOLUME_ID 32 566 #define VBOX_ISO9660_MAX_VOLUMESET_ID 128 567 #define VBOX_ISO9660_MAX_PREPARER_ID 128 568 #define VBOX_ISO9660_MAX_APPLICATION_ID 128 569 #define VBOX_ISO9660_STANDARD_ID "CD001" 570 #define VBOX_ISO9660_SECTOR_SIZE 2048 571 572 #pragma pack(1) 573 typedef struct VBoxISO9660DateShort 574 { 575 uint8_t year; 576 uint8_t month; 577 uint8_t day; 578 uint8_t hour; 579 uint8_t minute; 580 uint8_t second; 581 int8_t gmt_offset; 582 } VBoxISO9660DateShort; 583 584 typedef struct VBoxISO9660DateLong 585 { 586 char year[4]; 587 char month[2]; 588 char day[2]; 589 char hour[2]; 590 char minute[2]; 591 char second[2]; 592 char hseconds[2]; 593 int8_t gmt_offset; 594 } VBoxISO9660DateLong; 595 596 typedef struct VBoxISO9660DirRecord 597 { 598 uint8_t record_length; 599 uint8_t extented_attr_length; 600 uint32_t extent_location; 601 uint32_t extent_location_big; 602 uint32_t extent_data_length; /* Number of bytes (file) / len (directory). */ 603 uint32_t extent_data_length_big; 604 VBoxISO9660DateShort date; 605 uint8_t flags; 606 uint8_t interleave_unit_size; 607 uint8_t interleave_gap_size; 608 uint16_t volume_sequence_number; 609 uint16_t volume_sequence_number_big; 610 uint8_t name_len; 611 /* Starting here there will be the actual directory entry name 612 * and a padding of 1 byte if name_len is odd. */ 613 } VBoxISO9660DirRecord; 614 615 typedef struct VBoxISO9660PriVolDesc 616 { 617 uint8_t type; 618 char name_id[6]; 619 uint8_t version; 620 char system_id[VBOX_ISO9660_MAX_SYSTEM_ID]; 621 char volume_id[VBOX_ISO9660_MAX_VOLUME_ID]; 622 uint8_t unused2[8]; 623 uint32_t volume_space_size; /* Number of sectors, Little Endian. */ 624 uint32_t volume_space_size_big; /* Number of sectors Big Endian. */ 625 uint8_t unused3[32]; 626 uint16_t volume_set_size; 627 uint16_t volume_set_size_big; 628 uint16_t volume_sequence_number; 629 uint16_t volume_sequence_number_big; 630 uint16_t logical_block_size; /* 2048. */ 631 uint16_t logical_block_size_big; 632 uint32_t path_table_size; /* Size in bytes. */ 633 uint32_t path_table_size_big; /* Size in bytes. */ 634 uint32_t path_table_start_first; 635 uint32_t path_table_start_second; 636 uint32_t path_table_start_first_big; 637 uint32_t path_table_start_second_big; 638 VBoxISO9660DirRecord root_directory_record; 639 uint8_t directory_padding; 640 char volume_set_id[VBOX_ISO9660_MAX_VOLUMESET_ID]; 641 char publisher_id[VBOX_ISO9660_MAX_PUBLISHER_ID]; 642 char preparer_id[VBOX_ISO9660_MAX_PREPARER_ID]; 643 char application_id[VBOX_ISO9660_MAX_APPLICATION_ID]; 644 char copyright_file_id[37]; 645 char abstract_file_id[37]; 646 char bibliographic_file_id[37]; 647 VBoxISO9660DateLong creation_date; 648 VBoxISO9660DateLong modification_date; 649 VBoxISO9660DateLong expiration_date; 650 VBoxISO9660DateLong effective_date; 651 uint8_t file_structure_version; 652 uint8_t unused4[1]; 653 char application_data[512]; 654 uint8_t unused5[653]; 655 } VBoxISO9660PriVolDesc; 656 657 typedef struct VBoxISO9660PathTableHeader 658 { 659 uint8_t length; 660 uint8_t extended_attr_sectors; 661 /** Sector of starting directory table. */ 662 uint32_t sector_dir_table; 663 /** Index of parent directory (1 for the root). */ 664 uint16_t parent_index; 665 /* Starting here there will be the name of the directory, 666 * specified by length above. */ 667 } VBoxISO9660PathTableHeader; 668 669 typedef struct VBoxISO9660PathTableEntry 670 { 671 char *path; 672 char *path_full; 673 VBoxISO9660PathTableHeader header; 674 RTLISTNODE Node; 675 } VBoxISO9660PathTableEntry; 676 677 typedef struct VBoxISO9660File 678 { 679 RTFILE file; 680 RTLISTNODE listPaths; 681 VBoxISO9660PriVolDesc priVolDesc; 682 } VBoxISO9660File; 683 #pragma pack() 684 685 void rtISO9660DestroyPathCache(VBoxISO9660File *pFile) 686 { 687 VBoxISO9660PathTableEntry *pNode = RTListNodeGetFirst(&pFile->listPaths, VBoxISO9660PathTableEntry, Node); 688 while (pNode) 689 { 690 VBoxISO9660PathTableEntry *pNext = RTListNodeGetNext(&pNode->Node, VBoxISO9660PathTableEntry, Node); 691 bool fLast = RTListNodeIsLast(&pFile->listPaths, &pNode->Node); 692 693 if (pNode->path) 694 RTStrFree(pNode->path); 695 if (pNode->path_full) 696 RTStrFree(pNode->path_full); 697 RTListNodeRemove(&pNode->Node); 698 RTMemFree(pNode); 699 700 if (fLast) 701 break; 702 703 pNode = pNext; 704 } 705 } 706 707 void RTISO9660Close(VBoxISO9660File *pFile) 708 { 709 if (pFile) 710 { 711 rtISO9660DestroyPathCache(pFile); 712 RTFileClose(pFile->file); 713 } 714 } 715 716 int rtISO9660AddToPathCache(PRTLISTNODE pList, const char *pszPath, 717 VBoxISO9660PathTableHeader *pHeader) 718 { 719 AssertPtrReturn(pList, VERR_INVALID_PARAMETER); 720 AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER); 721 AssertPtrReturn(pHeader, VERR_INVALID_PARAMETER); 722 723 VBoxISO9660PathTableEntry *pNode = (VBoxISO9660PathTableEntry*)RTMemAlloc(sizeof(VBoxISO9660PathTableEntry)); 724 if (pNode == NULL) 725 return VERR_NO_MEMORY; 726 727 pNode->path = NULL; 728 if (RT_SUCCESS(RTStrAAppend(&pNode->path, pszPath))) 729 { 730 memcpy((VBoxISO9660PathTableHeader*)&pNode->header, 731 (VBoxISO9660PathTableHeader*)pHeader, sizeof(pNode->header)); 732 733 pNode->path_full = NULL; 734 pNode->Node.pPrev = NULL; 735 pNode->Node.pNext = NULL; 736 RTListAppend(pList, &pNode->Node); 737 return VINF_SUCCESS; 738 } 739 return VERR_NO_MEMORY; 740 } 741 742 int rtISO9660GetParentPathSub(PRTLISTNODE pList, VBoxISO9660PathTableEntry *pNode, 743 char *pszPathNode, char **ppszPath) 744 { 745 int rc = VINF_SUCCESS; 746 if (pNode->header.parent_index > 1) 747 { 748 uint16_t idx = 1; 749 VBoxISO9660PathTableEntry *pNodeParent = RTListNodeGetFirst(pList, VBoxISO9660PathTableEntry, Node); 750 while (idx++ < pNode->header.parent_index) 751 pNodeParent = RTListNodeGetNext(&pNodeParent->Node, VBoxISO9660PathTableEntry, Node); 752 char *pszPath; 753 if (RTStrAPrintf(&pszPath, "%s/%s", pNodeParent->path, pszPathNode)) 754 { 755 rc = rtISO9660GetParentPathSub(pList, pNodeParent, pszPath, ppszPath); 756 RTStrFree(pszPath); 757 } 758 else 759 rc = VERR_NO_MEMORY; 760 } 761 else 762 { 763 char *pszPath = RTStrDup(pszPathNode); 764 *ppszPath = pszPath; 765 } 766 return rc; 767 } 768 769 /* Is a *flat* structure! */ 770 int rtISO9660UpdatePathCache(VBoxISO9660File *pFile) 771 { 772 AssertPtrReturn(pFile, VERR_INVALID_PARAMETER); 773 rtISO9660DestroyPathCache(pFile); 774 775 RTListInit(&pFile->listPaths); 776 777 /* Seek to path tables. */ 778 int rc = VINF_SUCCESS; 779 Assert(pFile->priVolDesc.path_table_start_first > 16); 780 uint64_t uTableStart = (pFile->priVolDesc.path_table_start_first * VBOX_ISO9660_SECTOR_SIZE); 781 Assert(uTableStart % VBOX_ISO9660_SECTOR_SIZE == 0); /* Make sure it's aligned. */ 782 if (RTFileTell(pFile->file) != uTableStart) 783 rc = RTFileSeek(pFile->file, uTableStart, RTFILE_SEEK_BEGIN, &uTableStart); 784 785 /* 786 * Since this is a sequential format, for performance it's best to read the 787 * complete path table (every entry can have its own level (directory depth) first 788 * and the actual directories of the path table afterwards. 789 */ 790 791 /* Read in the path table ... */ 792 uint32_t cbLeft = pFile->priVolDesc.path_table_size; 793 VBoxISO9660PathTableHeader header; 794 while ((cbLeft > 0) && RT_SUCCESS(rc)) 795 { 796 size_t cbRead; 797 rc = RTFileRead(pFile->file, (VBoxISO9660PathTableHeader*)&header, sizeof(VBoxISO9660PathTableHeader), &cbRead); 798 if (RT_FAILURE(rc)) 799 break; 800 cbLeft -= cbRead; 801 if (header.length) 802 { 803 Assert(cbLeft >= header.length); 804 Assert(header.length <= 31); 805 /* Allocate and read in the actual path name. */ 806 char *pszName = RTStrAlloc(header.length + 1); 807 rc = RTFileRead(pFile->file, (char*)pszName, header.length, &cbRead); 808 if (RT_SUCCESS(rc)) 809 { 810 cbLeft -= cbRead; 811 pszName[cbRead] = '\0'; /* Terminate string. */ 812 /* Add entry to cache ... */ 813 rc = rtISO9660AddToPathCache(&pFile->listPaths, pszName, &header); 814 } 815 RTStrFree(pszName); 816 /* Read padding if required ... */ 817 if ((header.length % 2) != 0) /* If we have an odd length, read/skip the padding byte. */ 818 { 819 rc = RTFileSeek(pFile->file, 1, RTFILE_SEEK_CURRENT, NULL); 820 cbLeft--; 821 } 822 } 823 } 824 825 /* Transform path names into full paths. This is a bit ugly right now. */ 826 VBoxISO9660PathTableEntry *pNode = RTListNodeGetLast(&pFile->listPaths, VBoxISO9660PathTableEntry, Node); 827 while ( pNode 828 && !RTListNodeIsFirst(&pFile->listPaths, &pNode->Node) 829 && RT_SUCCESS(rc)) 830 { 831 rc = rtISO9660GetParentPathSub(&pFile->listPaths, pNode, 832 pNode->path, &pNode->path_full); 833 if (RT_SUCCESS(rc)) 834 pNode = RTListNodeGetPrev(&pNode->Node, VBoxISO9660PathTableEntry, Node); 835 } 836 837 return rc; 838 } 839 840 int RTISO9660Open(const char *pszFileName, VBoxISO9660File *pFile) 841 { 842 AssertPtrReturn(pszFileName, VERR_INVALID_PARAMETER); 843 AssertPtrReturn(pFile, VERR_INVALID_PARAMETER); 844 845 RTListInit(&pFile->listPaths); 846 #if 1 847 Assert(sizeof(VBoxISO9660DateShort) == 7); 848 Assert(sizeof(VBoxISO9660DateLong) == 17); 849 int l = sizeof(VBoxISO9660DirRecord); 850 RTPrintf("VBoxISO9660DirRecord=%ld\n", l); 851 Assert(l == 33); 852 /* Each volume descriptor exactly occupies one sector. */ 853 l = sizeof(VBoxISO9660PriVolDesc); 854 RTPrintf("VBoxISO9660PriVolDesc=%ld\n", l); 855 Assert(l == VBOX_ISO9660_SECTOR_SIZE); 856 #endif 857 int rc = RTFileOpen(&pFile->file, pszFileName, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); 858 if (RT_SUCCESS(rc)) 859 { 860 uint64_t cbSize; 861 rc = RTFileGetSize(pFile->file, &cbSize); 862 if ( RT_SUCCESS(rc) 863 && cbSize > 16 * VBOX_ISO9660_SECTOR_SIZE) 864 { 865 uint64_t cbOffset = 16 * VBOX_ISO9660_SECTOR_SIZE; /* Start reading at 32k. */ 866 size_t cbRead; 867 VBoxISO9660PriVolDesc volDesc; 868 bool fFoundPrimary = false; 869 bool fIsValid = false; 870 while (cbOffset < _1M) 871 { 872 /* Get primary descriptor. */ 873 rc = RTFileRead(pFile->file, (VBoxISO9660PriVolDesc*)&volDesc, sizeof(VBoxISO9660PriVolDesc), &cbRead); 874 if (RT_FAILURE(rc) || cbRead < sizeof(VBoxISO9660PriVolDesc)) 875 break; 876 if ( RTStrStr((char*)volDesc.name_id, VBOX_ISO9660_STANDARD_ID) 877 && volDesc.type == 0x1 /* Primary Volume Descriptor */) 878 { 879 memcpy((VBoxISO9660PriVolDesc*)&pFile->priVolDesc, 880 (VBoxISO9660PriVolDesc*)&volDesc, sizeof(VBoxISO9660PriVolDesc)); 881 fFoundPrimary = true; 882 } 883 else if(volDesc.type == 0xff /* Termination Volume Descriptor */) 884 { 885 if (fFoundPrimary) 886 fIsValid = true; 887 break; 888 } 889 cbOffset += sizeof(VBoxISO9660PriVolDesc); 890 } 891 892 if (fIsValid) 893 rc = rtISO9660UpdatePathCache(pFile); 894 else 895 rc = VERR_INVALID_PARAMETER; 896 } 897 if (RT_FAILURE(rc)) 898 RTISO9660Close(pFile); 899 } 900 return rc; 901 } 902 903 /* Parses the extent content given at a specified sector. */ 904 int rtISO9660FindEntry(VBoxISO9660File *pFile, const char *pszFileName, 905 uint32_t uExtentSector, uint32_t cbExtent /* Bytes */, 906 VBoxISO9660DirRecord **ppRec) 907 { 908 AssertPtrReturn(pFile, VERR_INVALID_PARAMETER); 909 Assert(uExtentSector > 16); 910 911 int rc = RTFileSeek(pFile->file, uExtentSector * VBOX_ISO9660_SECTOR_SIZE, 912 RTFILE_SEEK_BEGIN, NULL); 913 if (RT_SUCCESS(rc)) 914 { 915 rc = VERR_FILE_NOT_FOUND; 916 917 uint8_t uBuffer[VBOX_ISO9660_SECTOR_SIZE]; 918 uint32_t cbLeft = cbExtent; 919 while (!RT_SUCCESS(rc) && cbLeft > 0) 920 { 921 size_t cbRead; 922 int rc2 = RTFileRead(pFile->file, (void*)&uBuffer, sizeof(uBuffer), &cbRead); 923 Assert(RT_SUCCESS(rc2) && cbRead == VBOX_ISO9660_SECTOR_SIZE); 924 cbLeft -= cbRead; 925 926 uint32_t idx = 0; 927 while (idx < cbRead) 928 { 929 VBoxISO9660DirRecord *pCurRecord = (VBoxISO9660DirRecord*)&uBuffer[idx]; 930 if (pCurRecord->record_length == 0) 931 break; 932 933 Assert(pCurRecord->name_len > 0); 934 char *pszName = RTStrAlloc(pCurRecord->name_len + 1); 935 AssertPtr(pszName); 936 Assert(idx + sizeof(VBoxISO9660DirRecord) < cbRead); 937 memcpy(pszName, &uBuffer[idx + sizeof(VBoxISO9660DirRecord)], pCurRecord->name_len); 938 939 if ( pCurRecord->name_len == 1 940 && pszName[0] == 0x0) 941 { 942 /* This is a "." directory (self). */ 943 } 944 else if ( pCurRecord->name_len == 1 945 && pszName[0] == 0x1) 946 { 947 /* This is a ".." directory (parent). */ 948 } 949 else /* Regular directory or file */ 950 { 951 if (pCurRecord->flags & RT_BIT(1)) /* Directory */ 952 { 953 /* We don't recursively go into directories 954 * because we already have the cached path table. */ 955 pszName[pCurRecord->name_len] = 0; 956 /*rc = rtISO9660ParseDir(pFile, pszFileName, 957 pDirHdr->extent_location, pDirHdr->extent_data_length);*/ 958 } 959 else /* File */ 960 { 961 /* Get last occurence of ";" and cut it off. */ 962 char *pTerm = strrchr(pszName, ';'); 963 if (pTerm) 964 pszName[pTerm - pszName] = 0; 965 966 /* Don't use case sensitive comparison here, in IS0 9660 all 967 * file / directory names are UPPERCASE. */ 968 if (!RTStrICmp(pszName, pszFileName)) 969 { 970 VBoxISO9660DirRecord *pRec = (VBoxISO9660DirRecord*)RTMemAlloc(sizeof(VBoxISO9660DirRecord)); 971 if (pRec) 972 { 973 memcpy(pRec, pCurRecord, sizeof(VBoxISO9660DirRecord)); 974 *ppRec = pRec; 975 rc = VINF_SUCCESS; 976 break; 977 } 978 else 979 rc = VERR_NO_MEMORY; 980 } 981 } 982 } 983 idx += pCurRecord->record_length; 984 } 985 } 986 } 987 return rc; 988 } 989 990 int rtISO9660ResolvePath(VBoxISO9660File *pFile, const char *pszPath, uint32_t *puSector) 991 { 992 AssertPtrReturn(pFile, VERR_INVALID_PARAMETER); 993 AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER); 994 AssertPtrReturn(puSector, VERR_INVALID_PARAMETER); 995 996 int rc = VERR_FILE_NOT_FOUND; 997 char *pszTemp = RTStrDup(pszPath); 998 if (pszTemp) 999 { 1000 RTPathStripFilename(pszTemp); 1001 1002 bool bFound = false; 1003 VBoxISO9660PathTableEntry *pNode; 1004 if (!RTStrCmp(pszTemp, ".")) /* Root directory? Use first node! */ 1005 { 1006 pNode = RTListNodeGetFirst(&pFile->listPaths, VBoxISO9660PathTableEntry, Node); 1007 bFound = true; 1008 } 1009 else 1010 { 1011 RTListForEach(&pFile->listPaths, pNode, VBoxISO9660PathTableEntry, Node) 1012 { 1013 if ( pNode->path_full != NULL /* Root does not have a path! */ 1014 && !RTStrICmp(pNode->path_full, pszTemp)) 1015 { 1016 bFound = true; 1017 break; 1018 } 1019 } 1020 } 1021 if (bFound) 1022 { 1023 *puSector = pNode->header.sector_dir_table; 1024 rc = VINF_SUCCESS; 1025 } 1026 RTStrFree(pszTemp); 1027 } 1028 else 1029 rc = VERR_NO_MEMORY; 1030 return rc; 1031 } 1032 1033 int rtISO9660ReadFileInternal(VBoxISO9660File *pFile, const char *pszPath, 1034 uint32_t cbOffset, size_t cbToRead, size_t *pcbRead) 1035 { 1036 AssertPtrReturn(pFile, VERR_INVALID_PARAMETER); 1037 AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER); 1038 1039 uint32_t uSector; 1040 int rc = rtISO9660ResolvePath(pFile, pszPath, &uSector); 1041 if (RT_SUCCESS(rc)) 1042 { 1043 /* Seek to directory table. */ 1044 rc = RTFileSeek(pFile->file, uSector * VBOX_ISO9660_SECTOR_SIZE, 1045 RTFILE_SEEK_BEGIN, NULL); 1046 if (RT_SUCCESS(rc)) 1047 { 1048 size_t cbRead; 1049 VBoxISO9660DirRecord dir_table; 1050 rc = RTFileRead(pFile->file, (VBoxISO9660DirRecord*)&dir_table, sizeof(VBoxISO9660DirRecord), &cbRead); 1051 if (RT_SUCCESS(rc)) 1052 { 1053 Assert(cbRead == sizeof(VBoxISO9660DirRecord)); 1054 VBoxISO9660DirRecord *pRecord = NULL; 1055 rc = rtISO9660FindEntry(pFile, 1056 RTPathFilename(pszPath), 1057 dir_table.extent_location, 1058 dir_table.extent_data_length, 1059 &pRecord); 1060 if ( RT_SUCCESS(rc) 1061 && pRecord) 1062 { 1063 RTMemFree(pRecord); 1064 } 1065 } 1066 else 1067 rc = VERR_INVALID_PARAMETER; 1068 } 1069 } 1070 return rc; 1071 } 1072 1073 int RTISO9660ReadFile(VBoxISO9660File *pFile, const char *pszFileName, 1074 uint32_t cbOffset, size_t cbToRead, size_t *pcbRead) 1075 { 1076 return rtISO9660ReadFileInternal(pFile, pszFileName, cbOffset, cbToRead, pcbRead); 1077 } 1078 #endif 1079 556 1080 static int handleCtrlCopyTo(HandlerArg *a) 557 1081 { 1082 VBoxISO9660File file; 1083 int vrc = RTISO9660Open("c:\\Downloads\\VBoxGuestAdditions_3.2.8.iso", &file); 1084 if (RT_SUCCESS(vrc)) 1085 { 1086 uint32_t uOffset = 0; 1087 size_t cbRead; 1088 while (RT_SUCCESS(vrc)) 1089 { 1090 vrc = RTISO9660ReadFile(&file, "32BIT/OS2/readme.txt", 1091 uOffset, _4K, &cbRead); 1092 uOffset += cbRead; 1093 } 1094 RTISO9660Close(&file); 1095 } 1096 return vrc; 1097 558 1098 /* 559 1099 * Check the syntax. We can deduce the correct syntax from the number of
Note:
See TracChangeset
for help on using the changeset viewer.