pax_global_header00006660000000000000000000000064147017664430014526gustar00rootroot0000000000000052 comment=f2ca37ef3510543172657b82493d1eceefa9a134 open-vm-tools-stable-12.5.0/000077500000000000000000000000001470176644300156025ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/README.md000066400000000000000000000425551470176644300170740ustar00rootroot00000000000000# General ## What is the open-vm-tools project? open-vm-tools is a set of services and modules that enable several features in VMware products for better management of, and seamless user interactions with, guests. It includes kernel modules for enhancing the performance of virtual machines running Linux or other VMware supported Unix like guest operating systems. open-vm-tools enables the following features in VMware products: - Graceful execution of power operations (reboot and shutdown) in the guest. - Execution of built-in or user configured scripts in the guest during various power operations. - Running programs, commands and file system operations in the guest to enhance guest automation. - Authentication for guest operations. - Generation of heartbeat from guest to host for vSphere HA solution to determine guest's availabilty. - Clock synchronization between guest and host. - Quiescing guest file systems to allow host to capture file-system-consistent guest snapshot. - Execution of pre-freeze and post-thaw scripts while quiescing guest file systems. - Customization of the guest immediately after power on. - Periodic collection of network, disk, and memory usage information from the guest. - Resizing the graphical desktop screen of the guest. - Shared Folders operations between host and guest file systems on VMware Workstation and VMware Fusion. - Copying and pasting text, graphics, and files between guest and host or client desktops. - Dragging and dropping files between guest and host UI. - Periodic collection of running applications, services, and containers in the guest. - Accessing content from GuestStore. - Publishing data to Guest Data Publisher. - Managing Salt-Minion desired state specified in a guest variable. ## Can you provide more details on the actual code being released? The following components have been released as open source software: - Linux, Solaris and FreeBSD drivers for various devices and file system access. - The PowerOps plugin to perform graceful power operation and run power scripts. - The VIX plugin to run programs and commands, and perform file system operations in guest. - The GuestInfo plugin to periodically collect various statistics from guest. - The TimeSync plugin to perform time synchronization. - The dndcp plugin to support drag and drop, and text and file copy/paste operations. - The ResolutionSet plugin to adjust guest screen resolutions automatically based on window sizes. - The vmbackup plugin to support quiesced snapshot operation. - The GuestStore plugin to support GuestStore operation. - The gdp plugin to support guest data publishing operation. - The AppInfo plugin to periodically collect application information. - The ServiceDiscovery plugin to periodically collect service information. - The ContainerInfo plugin to periodically collect container information. - The ComponentMgr plugin to handle desired state operations. - The guest authentication service. - The toolbox command to perform disk wiping and shrinking, manage power scripts, and time synchronization. - The guest SDK libraries to provide information about virtual machine to guest. - Client and server for shared folders support. - Multiple monitor support. - Other utilities. ## Is open-vm-tools available with Linux distributions? Yes. open-vm-tools packages for user space components are available with new versions of major Linux distributions, and are installed as part of the OS installation in several cases. Please refer to VMware KB article http://kb.vmware.com/kb/2073803 for details. All leading Linux vendors support open-vm-tools and bundle it with their products. For information about OS compatibility for open-vm-tools, see the VMware Compatibility Guide at http://www.vmware.com/resources/compatibility Automatic installation of open-vm-tools along with the OS installation eliminates the need to separately install open-vm-tools in guests. If open-vm-tools is not installed automatically, you may be able to manually install it from the guest OS vendor's public repository. Installing open-vm-tools from the Linux vendor's repository reduces virtual machine downtime because future updates to open-vm-tools are included with the OS maintenance patches and updates. **NOTE**: Most of the Linux distributions ship two or more open-vm-tools packages. "open-vm-tools" is the core package without any dependencies on X libraries and "open-vm-tools-desktop" is an additional package with dependencies on "open-vm-tools" core package and X libraries. The "open-vm-tools-sdmp" package contains a plugin for Service Discovery. There may be additional packages, please refer to the documentation of the OS vendor. Note that the open-vm-tools packages available with Linux distributions do not include Linux drivers because Linux drivers are available as part of Linux kernel itself. Linux kernel versions 3.10 and later include all of the Linux drivers present in open-vm-tools except the vmhgfs driver. The vmhgfs driver was required for enabling shared folders feature, but is superseded by vmhgfs-fuse which does not require a kernel driver. ## Will there be continued support for VMware Tools and OSP? VMware Tools will continue to be available under a commercial license. It is recommended that open-vm-tools be used for the Linux distributions where open-vm-tools is available. VMware will not provide OSPs for operating systems where open-vm-tools is available. ## How does this benefit other open source projects? Under the terms of the GPL, open source community members are able to use the open-vm-tools code to develop their own applications, extend it, and contribute to the community. They can also incorporate some or all of the code into their projects, provided they comply with the terms of the GPL. # License Related ## What license is the code being released under? The code is being released under GPL v2 and GPL v2 compatible licenses. To be more specific, the Linux kernel modules are being released under the GPL v2, while almost all of the user level components are being released under the LGPL v2.1. The SVGA and mouse drivers have been available under the X11 license for quite some time. There are certain third party components released under BSD style licenses, to which VMware has in some cases contributed, and will continue to distribute with open-vm-tools. ## Why did you choose these licenses? We chose the GPL v2 for the kernel components to be consistent with the Linux kernel's license. We chose the LGPL v2.1 for the user level components because some of the code is implemented as shared libraries and we do not wish to restrict proprietary code from linking against those libraries. For consistency, we decided to license the rest of the userlevel code under the LGPL v2.1 as well. ## What are the obligations that the license(s) impose? Each of these licenses have different obligations. For questions about the GPL, LGPL licenses, the Free Software Foundation's GPL FAQ page provides lots of useful information. For questions about the other licenses like the X11, BSD licenses, the Open Source Initiative has numerous useful resources including mailing lists. The Software Freedom Law Center provides legal expertise and consulting for free and open source software (FOSS) developers. ## Can I use all or part of this code in my proprietary software? Do I have to release the source code if I do? Different open source licenses have different requirements regarding the release of source code. Since the code is being released under various open source licenses, you will need to comply with the terms of the corresponding licenses. ## Am I required to contribute back any changes I make to the code? No, you aren't required to contribute any changes that you make back to the open-vm-tools project. However, we encourage you to do so. ## Can I use all or part of this code in another open source package? Yes, as long as you comply with the appropriate license(s). ## Can I package this for my favorite operating system? Yes! Please do. ## Will the commercial version (VMware Tools) differ from the open source version (open-vm-tools)? If so, how? Our goal is to work towards making the open source version as close to the commercial version as possible. However, we do currently make use of certain components licensed from third parties as well as components from other VMware products which are only available in binary form. ## If I use the code from the open-vm-tools project in my project/product, can I call my project/product VMware Tools? No, since your project/product is not a VMware project/product. # Building open-vm-tools ## How do I build open-vm-tools? open-vm-tools uses the GNU Automake tool for generating Makefiles to build all sources. More information about Automake can be found here: http://www.gnu.org/software/automake/ ## Project build information: The following steps will work on most recent Linux distributions: ``` autoreconf -i ./configure make sudo make install sudo ldconfig ``` ### Service Discovery (sdmp) plugin To build the optional sdmp (Service Discovery) plugin use the `--enable-servicediscovery` option to invoke the configure script: ``` ./configure --enable-servicediscovery ``` ### The open-vm-tools 12.0.0 release introduces an optional setup script and two plugins (one optional) * Salt Minion Setup * Component Manager plugin * ContainerInfo plugin (optional) ### Salt Minion Setup The Salt support on Linux consists of a single bash script to setup Salt Minion on VMware virtual machines. The script requires the "curl" and "awk" commands to be available on the system. Linux providers supplying open-vm-tools packages are recommended to provide Salt Minion support in a separate optional package - "open-vm-tools-salt-minion". To include the Salt Minion Setup in the open-vm-tools build use the `--enable-salt-minion` option when invoking the configure script. ``` ./configure --enable-salt-minion ``` ### Component Manager (componentMgr) plugin The component Manager manages a preconfigured set of components available from VMware that can be made available on the Linux guest. Currently the only component that can be managed is the Salt Minion Setup. ### ContainerInfo (containerInfo) plugin The optional containerInfo plugin retrieves a list of the containers running on a Linux guest and publishes the list to the guest variable "**guestinfo.vmtools.containerinfo**" in JSON format. The containerInfo plugin communicates with the containerd daemon using gRPC to retrieve the desired information. For containers that are managed by Docker, the plugin uses libcurl to communicate with the Docker daemon and get the names of the containers. Since this plugin requires additional build and runtime dependencies, Linux vendors are recommended to release it in a separate, optional package - "open-vm-tools-containerinfo". This avoids unnecessary dependencies for customers not using the feature. #### Canonical, Debian, Ubuntu Linux | Build Dependencies | Runtime | |:------------------------:|:----------------:| | `libcurl4-openssl-dev` | `curl` | | `protobuf-compiler` | `protobuf` | | `libprotobuf-dev` | `grpc++` | | `protobuf-compiler-grpc` | | `libgrpc++-dev` | | `golang-github-containerd-containerd-dev` | | `golang-github-gogo-protobuf-dev` | #### Fedora, Red Hat Enterprise Linux, ... | Build Dependencies | Runtime | |:------------------------:|:----------------:| | `libcurl-devel` | `curl` | | `protobuf-compiler` | `protobuf` | | `protobuf-devel` | `grpc-cpp` | | `grpc-plugins` | | `grpc-devel` | | `containerd-devel` | #### Configuring the build for the ContainerInfo plugin The configure script defaults to building the ContainerInfo when all the needed dependencies are available. ContainerInfo will not be built if there are missing dependencies. Invoke the configure script with `--enable-containerinfo=no` to explicitly inhibit building the plugin. ``` ./configure --enable-containerinfo=no ``` If the configure script is given the option `--enable-containerinfo=yes` and any necessary dependency is not available, the configure script will terminate with an error. ``` ./configure --enable-containerinfo=yes ``` ## Getting configure options and help If you are looking for help or additional settings for the building of this project, the following configure command will display a list of help options: ``` ./configure --help ``` When using configure in the steps above it is only necessary to call ./configure once unless there was a problem after the first invocation. # Getting Involved ## How can I get involved today? You can get involved today in several different ways: - Start using open-vm-tools today and give us feedback. - Suggest feature enhancements. - Identify and submit bugs under issues section: https://github.com/vmware/open-vm-tools/issues - Start porting the code to other operating systems. Here is the list of operating systems with open-vm-tools: * Red Hat Enterprise Linux 7.0 and later releases * SUSE Linux Enterprise 12 and later releases * Ubuntu 14.04 and later releases * CentOS 7 and later releases * Debian 7.x and later releases * Oracle Linux 7 and later * Fedora 19 and later releases * openSUSE 11.x and later releases * Flatcar Container Linux, all releases * Rocky 8 and later releases * AlmaLinux OS 8 and later releases ## Will external developers be allowed to become committers to the project? Yes. Initially, VMware engineers will be the only committers. As we roll out our development infrastructure, we will be looking to add external committers to the project as well. ## How can I submit code changes like bug fixes, patches, new features to the project? Initially, you can submit bug fixes, patches and new features to the project development mailing list as attachments to emails or bug reports. To contribute source code, you will need to fill out a contribution agreement form as part of the submission process. We will have more details on this process shortly. ## What is the governance model for managing this as an open source project? The feature roadmap and schedules for the open-vm-tools project will continue to be defined by VMware. Initially, VMware engineers will be the only approved committers. We will review incoming submissions for suitability for merging into the project. We will be looking to add community committers to the project based on their demonstrated contributions to the project. Finally, we also plan to set up a process for enhancement proposals, establishing sub-projects and so on. ## Will you ship code that I contribute with VMware products? If so, will I get credit for my contributions? Contributions that are accepted into the open-vm-tools project's main source tree will likely be a part of VMware Tools. We also recognize the value of attribution and value your contributions. Consequently, we will acknowledge contributions from the community that are distributed with VMware's products. ## Do I need to sign something before making a contribution? Yes. We have a standard contribution agreement that covers all contributions made to the project. It gives VMware and you joint copyright interests in the code you are contributing. The agreement also gives VMware flexibility with licensing and also helps avoid any copyright/licensing related issues that may arise in the future. In order for us to include your contribution in our source tree, we ask that you send us a signed copy of the agreement. You can do this in one of two ways: Fax to +1.650.427.5003, Attn: Product & Technology Law Group Scan and email it to oss-queries_at_vmware.com Agreement: http://open-vm-tools.sourceforge.net/files/vca.pdf ## My version of Linux is not recognized. How do I add my Linux name to the known list? The open-vm-tools source contains a table mapping the guest distro name to the officially recognized short name. __Please do not submit pull requests altering this table and associated code.__ Any changes here must be accompanied by additional changes in the VMware host. Values that are not recognized by the VMware host will be ignored. Use the appropriate generic Linux designation when configuring a VM for your Linux version. The selection available will vary by virtual hardware version being used. - Other 5.x or later Linux (64-bit) - Other 5.x or later Linux (32-bit) - Other 4.x Linux (64-bit) - Other 4.x Linux (32-bit) - Other 3.x Linux (64-bit) - Other 3.x Linux (32-bit) - Other Linux (64-bit) - Other Linux (32-bit) # Compatibilty ## What Operating Systems are supported for customization? The [Guest OS Customization Support Matrix](http://partnerweb.vmware.com/programs/guestOS/guest-os-customization-matrix.pdf) provides details about the guest operating systems supported for customization. ## Which versions of open-vm-tools are compatible with other VMware products? The [VMware Product Interoperability Matrix](http://partnerweb.vmware.com/comp_guide2/sim/interop_matrix.php) provides details about the compatibility of different versions of VMware Tools (includes open-vm-tools) and other VMware Products. # Internationalization ## Which languages are supported? open-vm-tools supports the following languages: - English - French - German - Spanish - Italian - Japanese - Korean - Simplified Chinese - Traditional Chinese # Other ## Mailing Lists Please send an email to one of these mailing lists based on the nature of your question. - Development related questions : open-vm-tools-devel@lists.sourceforge.net - Miscellaneous questions: open-vm-tools-discuss@lists.sourceforge.net - General project announcements: open-vm-tools-announce@lists.sourceforge.net open-vm-tools-stable-12.5.0/ReleaseNotes.md000066400000000000000000000072071470176644300205230ustar00rootroot00000000000000# open-vm-tools 12.5.0 Release Notes Updated on: 8 October 2024 open-vm-tools | 8 OCTOBER 2024 | Build 24276846 Check back for additions and updates to these release notes. ## What's in the Release Notes The release notes cover the following topics: * [What's New](#whatsnew) * [Internationalization](#i18n) * [Product Support Notice](#suppnote) * [Guest Operating System Customization Support](#guestop) * [Interoperability Matrix](#interop) * [Resolved Issues](#resolvedissues) * [Known Issues](#knownissues) ## What's New * Please see the [Resolved Issues](#resolvedissues) and [Known Issues](#knownissues) sections below. * A complete list of the granular changes in the open-vm-tools 12.5.0 release is available at: [open-vm-tools ChangeLog](https://github.com/vmware/open-vm-tools/blob/stable-12.5.0/open-vm-tools/ChangeLog) ## Internationalization open-vm-tools 12.5.0 is available in the following languages: * English * French * German * Spanish * Italian * Japanese * Korean * Simplified Chinese * Traditional Chinese ## Product Support Notice Beginning with the next major release, we will be reducing the number of supported localization languages. The three supported languages will be: * Japanese * Spanish * French The following languages will no longer be supported: * Italian * German * Brazilian Portuguese * Traditional Chinese * Korean * Simplified Chinese Impact: * Users who have been using the deprecated languages will no longer receive updates or support in these languages. * All user interfaces, message catalogs, help documentation, and customer support will be available only in English or in the three supported languages mentioned above. ## Guest Operating System Customization Support The [Guest OS Customization Support Matrix](http://partnerweb.vmware.com/programs/guestOS/guest-os-customization-matrix.pdf) provides details about the guest operating systems supported for customization. ## Interoperability Matrix The [VMware Product Interoperability Matrix](http://partnerweb.vmware.com/comp_guide2/sim/interop_matrix.php) provides details about the compatibility of current and earlier versions of VMware Products.  ## Resolved Issues * **The following github.com/vmware/open-vm-tools pull request has been addressed.** * Revise settings for vmware-user.desktop [Pull request #668](https://github.com/vmware/open-vm-tools/pull/668) * **Accomodate newer releases of libxml2 and xmlsec1.** The configure.ac and VGAuth code updated to avoid deprecated functions and build options based on OSS product version. ## Known Issues * **Shared Folders mount is unavailable on Linux VM.** If the **Shared Folders** feature is enabled on a Linux VM while it is powered off, the shared folders mount is not available on restart. Note: This issue is applicable to open-vm-tools running on VMware Workstation and VMware Fusion. Workaround: If the VM is powered on, disable and enable the **Shared Folders** feature from the interface. For resolving the issue permanently, edit **/etc/fstab** and add an entry to mount the Shared Folders automatically on boot. For example, add the line: vmhgfs-fuse /mnt/hgfs fuse defaults,allow_other 0 0 For more information on how to configure VMware Tools Shared Folders, see [KB 60262](https://kb.vmware.com/s/article/60262) open-vm-tools-stable-12.5.0/open-vm-tools/000077500000000000000000000000001470176644300203215ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/.gitignore000066400000000000000000000020501470176644300223060ustar00rootroot00000000000000*~ *.swp *.o *.ko # autoconf generated files *.cache .deps .libs INSTALL Makefile Makefile.in aclocal.m4 config !common-agent/etc/config config.log config.status configure libtool m4 # project generated files *.la *.lo checkvm/vmware-checkvm docs/api/build docs/api/doxygen.parsed.conf docs/api/warnings.log hgfsclient/vmware-hgfsclient hgfsmounter/mount.vmhgfs lib/guestRpc/nicinfo.h lib/guestRpc/nicinfo_xdr.c lib/include/guestrpc libguestlib/guestlibIoctl.h libguestlib/guestlibIoctl_xdr.c libguestlib/guestlibV3.h libguestlib/guestlibV3_xdr.c libguestlib/vmguestlib.pc rpctool/vmware-rpctool scripts/build/rpcgen_wrapper.sh scripts/poweroff-vm-default scripts/poweron-vm-default scripts/resume-vm-default scripts/suspend-vm-default services/plugins/vmbackup/vmBackupSignals.c services/plugins/vmbackup/vmBackupSignals.h services/vmtoolsd/svcSignals.c services/vmtoolsd/svcSignals.h services/vmtoolsd/vmtoolsd toolbox/vmware-toolbox-cmd vmware-user-suid-wrapper/vmware-user-suid-wrapper vmware-user-suid-wrapper/vmware-user.desktop xferlogs/vmware-xferlogs open-vm-tools-stable-12.5.0/open-vm-tools/AUTHORS000066400000000000000000000106431470176644300213750ustar00rootroot00000000000000The VMware Guest Components Team Contributors to open-vm-tools: Steve Wills Correct __IS_FREEBSD__ macro in vm_basic_defs.h (clang) - https://github.com/vmware/open-vm-tools/pull/136 Bernd Zeimetz Fix gcc6 build issues in linuxDeployment.c file. - https://github.com/vmware/open-vm-tools/pull/107 Josh Paetzel Add support for 64-bit inodes in FreeBSD 12 - https://github.com/vmware/open-vm-tools/pull/190 Sebastian Parschauer Add support to properly report SLES12-SAP - https://github.com/vmware/open-vm-tools/pull/123 Andrew Stormont Fix finding C++ compiler for cross-compiling - https://github.com/vmware/open-vm-tools/pull/206 Josh Paetzel Fix compilation error in clang 6.0 - https://github.com/vmware/open-vm-tools/pull/221 Mike Latimer Restrict udev rules to disk devices only - https://github.com/vmware/open-vm-tools/pull/216 Thomas Mueller Ignore ENXIO errors with SyncDriver - https://github.com/vmware/open-vm-tools/pull/218 Germán M. Bravo FreeBSD: Improper use of sysconf() for getpwent buffer size leads to vmtoolsd crash. - https://github.com/vmware/open-vm-tools/pull/238 Ed Schouten Use standard SYSCTL_ADD_OID() macro to access the sysctl_add_oid() function across supported FreeBSD releases. - https://github.com/vmware/open-vm-tools/pull/125 Steve Wills Fix vmmemctl.ko driver build for supported FreeBSD releases. - https://github.com/vmware/open-vm-tools/pull/140 John Eismeier Propose fix some spelling. - https://github.com/vmware/open-vm-tools/pull/264 Josh Paetzel Additional changes to vmmemctl.ko for FreeBSD 12.0 API changes. - https://github.com/vmware/open-vm-tools/pull/286 [Code]Ai Highlighted a potential NULL pointer dereference and four pieces of dead code. - https://github.com/vmware/open-vm-tools/pull/247 Haruki Tsurumoto Fix Asianux identification - https://github.com/vmware/open-vm-tools/pull/325 MilhouseVH stop systemd-243 udev complaints - https://github.com/vmware/open-vm-tools/pull/371 Josh Paetzel Changes to vmmemctl.ko and vmblock.ko for FreeBSD 13.0 API changes. - https://github.com/vmware/open-vm-tools/pull/398 Josh Paetzel FreeBSD has removed some vnops flags that have never been used. - https://github.com/vmware/open-vm-tools/pull/403 Alexey Shabalin Add recognition of ALT Linux distributions - https://github.com/vmware/open-vm-tools/pull/431 Thom Leggett Propagate new gdk-pixbuf-xlib include location - https://github.com/vmware/open-vm-tools/pull/438 Alexey Shabalin Adding vmtools library dependency to deploypkg library. - https://github.com/vmware/open-vm-tools/pull/432 Christian Ehrhardt Build: fix propagation of libtirpc flags - https://github.com/vmware/open-vm-tools/pull/469 Vincent Milum Jr Adding FreeBSD on ARM64 support to open-vm-tools. - https://github.com/vmware/open-vm-tools/pull/474 Miroslav Rezanina Fix issues using GCC 11 with gtk >= 3.20 and glib >=2.66.3 - https://github.com/vmware/open-vm-tools/pull/505 Marco Trevisan Update open-vm-tools to build with either Fuse 3 or Fuse 2 - https://github.com/vmware/open-vm-tools/pull/544 Bartosz Brachaczek Make HgfsConvertFromNtTimeNsec aware of 64-bit time_t on i386 - https://github.com/vmware/open-vm-tools/pull/387 Bernd Zeimetz Fix building containerinfo plugin on i386 - https://github.com/vmware/open-vm-tools/pull/588 Dirk Mueller Detect the proto files for containerd grpc client on SUSE like systems - https://github.com/vmware/open-vm-tools/pull/626 Jan Engelhardt Fix build problems with grpc (at least) 1.54 - https://github.com/vmware/open-vm-tools/pull/664 Yun Zheng Hu Power Ops: Attempt to execute file path only - https://github.com/vmware/open-vm-tools/pull/689 Joseph Allen Updated NetworkManager calls in suspend/resume scripts - https://github.com/vmware/open-vm-tools/pull/699 Brennan Kinney Revise settings for vmware-user.desktop - https://github.com/vmware/open-vm-tools/pull/668 open-vm-tools-stable-12.5.0/open-vm-tools/COPYING000066400000000000000000000634711470176644300213670ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! open-vm-tools-stable-12.5.0/open-vm-tools/ChangeLog000066400000000000000000016655141470176644300221150ustar00rootroot00000000000000commit 05afe0ae703d6027325059876528fe3b04fdf386 Author: Kruti Date: Thu Oct 10 06:12:07 2024 -0700 ================================================= open-vm-tools 12.5.0 released at this point. ================================================= Update of the ChangeLog with the final changes in preparation for the open-vm-tools 12.5.0 release. commit ef2095ffda17a766a65bf39d61f4cdb9c735fa62 Author: Kruti Date: Wed Oct 9 20:49:01 2024 -0700 Update the ReleaseNotes.md for the 12.5.0 open-vm-tools release. commit 96094bb1a59c67af99d31d5acfdc731f14109e47 Author: Kruti Date: Wed Oct 9 19:47:45 2024 -0700 Prepare for the open-vm-tools 12.5.0 release. - Update the tools version in the configure.ac. - Update the build numbers in the buldNumber.h. commit 412a4b1db38627062a8ebb955b0d483edee0a1ff Author: Kruti Date: Thu Oct 3 23:34:31 2024 -0700 Update ChangeLog with the granular push of Oct 03, 2024. - plus copyright update - plus ChangeLog update of Sep 24, 2024. commit e54a2d61657e3c4c0fd4299cc5c830b4263e27bd Author: Kruti Date: Thu Oct 3 23:17:34 2024 -0700 Correct missed 2024 copyright update. commit a2ff5f28720eca493c5369448b48d1ad595e368b Author: Kruti Date: Thu Oct 3 22:57:50 2024 -0700 open-vm-tools l10n message updates commit a240f6a1d75c4fbacb1e9364ff48dfce304a23dc Author: Kruti Date: Thu Oct 3 22:57:50 2024 -0700 Ignore deprecated warning for LIBXML2 APIs xmlFileXXX. CVE-2024-40896 has been fixed in the following libxml2 releases. - 2.13.3 - 2.12.9 - 2.11.9 The libxml2 version 2.13.0 has deprecated the xmlFileMatch, UserXmlFileOpen, xmlFileRead, xmlFileClose callback functions. This change suppresses a "deprecated-declaration" warning when these functions are invoked. commit a167dff31e77d9599454667220b23dac304fed46 Author: John Wolfe Date: Tue Sep 24 14:31:17 2024 -0700 ==================================================================== The "stable-12.5.x" branch was created from the "devel" branch here. ==================================================================== Update the ChangeLog with the ChangeLog update of Aug 27, 2024. commit 764f00f3c3393e8043ba87c2b63d1df670755c95 Author: Kruti Date: Tue Aug 27 02:31:46 2024 -0700 Update ChangeLog with the granular push of Aug 27, 2024. - plus Copyright pattern update of file tools.conf - plus README.md update of Aug 15, 2024. - plus ChangeLog update of July 15, 2024. commit 25fe7db3739a021103b4dca64255531be02602cd Author: Kruti Date: Tue Aug 27 02:27:38 2024 -0700 Update copyright pattern for tools.conf. commit 21a843e74da24401049f40efeb313a858de53b07 Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common source files not applicable to open-vm-tools. commit 2197581c0da08a4a574703cf56eca39c90ad1a40 Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 26ed84ded19e61801b752f3a606187ea2745e57a Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 5413628f892125da221bd180bfb861b3e773159c Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Annotate the os-release guest identification function HostinfoOsRelease() The HostinfoOsRelease() function examines the os-release standard file(s) to collect distro identification data of interest. This is open-source and users can legally modify the code changing the standard file priority order or accessing other files. Any such change breaks compliance with the os-release standard and may cause confusion in the field. The function header has been updated to remind users of this issue. commit 86b308ab9eb8e4c3e154b30861cb66802c9e4624 Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common header file not applicable to open-vm-tools. commit c401bc0af27dd6928970cad4f6af5f22d48dc7a7 Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 97a7efcc67eb37628181666a642a439cf4bc0bab Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common source file not applicable to open-vm-tools. commit d9a88f25df7cab16374c7ed0c1bc2b4640df22c8 Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 41d772c7ea21442f447872f52ec2fb7bd92d98b3 Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 0a0b23a5080bf6ccb58c69b9b214e0c25c628173 Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common source files not applicable to open-vm-tools. commit 6e7206dbd9be10e1c0853a4ac8b9982e3d307a7e Author: Kruti Date: Tue Aug 27 02:11:00 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 159107b8027f122f8502adafbbc8ffc56b4ff7d7 Author: Kruti Date: Tue Aug 27 02:10:59 2024 -0700 Change to common header file not applicable to open-vm-tools. commit bcc1be6f36d8a3d69c8a86f533d6deb27e6f2fda Author: Kruti Date: Tue Aug 27 02:10:59 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 649d27de9347ee507e3e863b43e861b48e5f0506 Author: Kruti Date: Tue Aug 27 02:10:59 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 4bdc04df610cebde943967dc2042f90b6597d2ad Author: Kruti Date: Tue Aug 27 02:10:59 2024 -0700 Change to common header file not applicable to open-vm-tools. commit a5f761ab56eb7afbb885e4ec57062657cfe0f171 Author: Kruti Date: Tue Aug 27 02:10:59 2024 -0700 Change to common source file not applicable to open-vm-tools. commit 582763347e3384a1fa1abb77a6b9c20d7c353753 Author: Ravindra Kumar Date: Thu Aug 15 18:51:54 2024 -0700 Update README.md Updated open-vm-tools functionality and plugin details commit 88c4194d2c6fb1804159cd36dd7d68e984afc495 Author: Kruti Date: Mon Jul 15 03:00:20 2024 -0700 Update ChangeLog with the granular push of July 15, 2024. - plus ChangeLog update of May 28, 2024. commit 567b94a40a5fe8f478dfe37b3b87fc9106028e45 Author: Kruti Date: Mon Jul 15 02:56:39 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 8ab40432f52747946fe007bf2bd2afc60875ee0a Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 4a8e42d35fcafb5d3ce77e5ea0e42887307172da Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 0ae5e008d7f18600d424e3335da54ee3e09f77bd Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common source file not applicable to open-vm-tools at this time. commit 0e8e439e9fa4f1b196fd40251db0e948cde52ce5 Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common source files not applicable to open-vm-tools. commit c22f4ebfe44a1798c2b5c445ca49cb96d2a2385f Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 95ba5d3d67b94f9f30aab6665728c7145e432a55 Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common header files not applicable to open-vm-tools. commit 621013de8d6e98ccb9e45b69ed26ede7b460500e Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common header file not applicable to open-vm-tools. commit b4c81e8fb510f6b978973975246d1bba78a2361a Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 2ecb5a9bedcc6ddd6a19dd3b24ca577e463c6257 Author: Kruti Date: Mon Jul 15 02:56:38 2024 -0700 Change to common source files not applicable to open-vm-tools. commit 0d6b03ce9ee20260998dabef3fcc7b484d2935a5 Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common source files not applicable to open-vm-tools at this time. commit abe5c72317031ad2eceb21038cca2e67431a4a79 Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 2ad2337e413d65eb88db85740d5515505db16d86 Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common header file not applicable to open-vm-tools. commit aa9d798ac82e84bfdf2bb9101c689338cbfb6dfe Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common header file not applicable to open-vm-tools. commit add970dae8e60ce4a3c98c5fd6b7c7c7d5138066 Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common header file not applicable to open-vm-tools. commit e44d22a272e99890f04ed14a55ec53facaabf7fb Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Update vmware-user.desktop.in and delete vmware-user.desktop. Update settings for vmware-user.desktop.in: - Remove Encoding since it's deprecated. - Uncomment NoDisplay=True since the bug related to it was fixed a while ago. Delete bora-vmsoft/install/common/vmware-user.desktop as it is no longer needed. In open-vm-tools, vmware-user.desktop is generated from vmware-user.desktop.in. Pull request: https://github.com/vmware/open-vm-tools/pull/668 commit 879e7e7600d219e6be04baae3a0903802265be38 Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common source files not applicable to open-vm-tools. commit 5cb816ddf7b4278f4fe7574180a7b1fbf5693e08 Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 3bf397e2a039772cdc62d6a7248a38388d4a58d2 Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common source files not applicable to open-vm-tools. commit e86e129392012521937a8439ab146e79515c5ff6 Author: Kruti Date: Mon Jul 15 02:56:37 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 9bc336c8457ddf1bedb5c6ef8d2fde4b2d4a9d59 Author: Kruti Date: Mon Jul 15 02:56:36 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 515e38c175e0a642865c663334932b2247414d87 Author: Kruti Date: Tue May 28 02:35:23 2024 -0700 Update ChangeLog with the granular push of May 26, 2024. - plus Copyright pattern update of file x86_basic_defs.h - plus ChangeLog update of May 20, 2024. commit fa9c8fb804f47536cddcdca1365b79477dccff88 Author: Kruti Date: Tue May 28 02:00:20 2024 -0700 Update Copyright pattern. commit eedd5a4b61bfd2f54eaabffc2553cb9d7fcabbb5 Author: Kruti Date: Sun May 26 23:55:32 2024 -0700 Change to common source files not applicable to open-vm-tools. commit 0d0b7bd3c8c2f63519c055236af843ecfd6d718f Author: Kruti Date: Sun May 26 23:55:32 2024 -0700 Change to common header file not applicable to open-vm-tools. commit bf2ac0396aedb12330050eeb63d0e3f2af65f847 Author: Kruti Date: Sun May 26 23:55:32 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 5ab6868b2b993a18f3680416ad1257b4240c5f25 Author: Kruti Date: Sun May 26 23:55:32 2024 -0700 Change to common header file not applicable to open-vm-tools. commit f026fcbdf5344d531954d049b05db12c3cf14429 Author: Kruti Date: Sun May 26 23:55:32 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 8112f3d6d12a59d44f87776090643a2519b52f08 Author: Kruti Date: Mon May 20 23:18:11 2024 -0700 Update ChangeLog with the granular push of May 20, 2024. - plus Copyright update of file guestApp.c - plus ChangeLog update of May 3, 2024. commit 9daa47c599c1fd85b60419b9375ef7d53d8d5c0f Author: Kruti Date: Mon May 20 23:10:14 2024 -0700 Correct copyright year to 2024. commit 8cd75607fbb7b5923f791c3cd8270d88b73fbef2 Author: Kruti Date: Mon May 20 22:58:13 2024 -0700 [Coverity]: Fixes for issues found from static application security testing Adding coverity escapes for false-positive issues. hgfsServerParameters.c -- 1 issue reported. issue: Overrunning array of 5 bytes at byte offset 5 by dereferencing pointer "newName". impact: False-Positive fix: suppress 'overrun-local' vmhgfs-fuse/file.c -- 2 issues reported. issue: Overrunning array of n bytes at byte offset n by dereferencing pointer "newNameP" (n is 17 and 5 respectively for those 2 locations where the issue occured). impact: False-Positive fix: suppress 'overrun-local' vmhgfs-fuse/link.c -- 2 issues reported. issue: Overrunning array of n bytes at byte offset n by dereferencing pointer "fileNameP" (n is 17 and 5 respectively for those 2 locations where the issue occured). impact: False-Positive fix: suppress 'overrun-local' vmhgfs-fuse/transport.c -- 1 issue reported. issue: uninit_use_in_call: Using uninitialized value "reply" while calling HgfsCompleteReq() function. impact: Bug fix: Remove function, it is unused/dead code (transport.h too). commit b91770061d3000de3fbe0994480579d1c2ca62f8 Author: Kruti Date: Mon May 20 22:58:13 2024 -0700 Change to common source file not applicable to open-vm-tools. commit 385e9b78195e96089353fbe2e945f069b245a831 Author: Kruti Date: Mon May 20 22:58:13 2024 -0700 Maintain compatibility with libxml2.12.5 and later. commit 9364240246824f9a1daa591cc45af8a6714e046b Author: Kruti Date: Mon May 20 22:58:13 2024 -0700 Change to common header file not applicable to open-vm-tools. commit ebe97d7d8cb01e68826ada7766f0227d3c016508 Author: Kruti Date: Mon May 20 22:58:13 2024 -0700 Change to common header file not applicable to open-vm-tools. commit ae0b62370b6ca926dbabe25bf5856c2a97cdcc5c Author: Kruti Date: Mon May 20 22:58:13 2024 -0700 Verify the xmlsec version before passing the compiler flag "-DXMLSEC_NO_SIZE_T", as it has been deprecated since 1.3.3. The configure option "--enable-size-t" has been set to yes by default starting with 1.3.0. version < 1.3.0 : Add "-DXMLSEC_NO_SIZE_T" if size_t has a size other than 4 bytes. (There was no enable-size-t before 1.2.35 and the enable-size-t is "no" by default in [1.2.35, 1.3.0)) version >= 1.3.0 : Do not add "-DXMLSEC_NO_SIZE_T" (as enable-size-t is "yes" by default in version [1.3.0, 1.3.3) and no need to consider this option since 1.3.3) commit 3fb8fe48f108067c39077934497df465616ba518 Author: Kruti Date: Mon May 20 22:58:13 2024 -0700 Change to common header file not applicable to open-vm-tools. commit b841140771ae6218f8875574de78dac1dd19fd90 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 084e3f4c6911d8036d157ed4f96dbda94f705142 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 1dad197a3419d900e8e4a7e2549abf8586a8b885 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 6196b065644d325d6345db2a42f8778a0fcd9751 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common source files not applicable to open-vm-tools. commit 42ceedd78f9ccb39540c4ea12f40fba7c644a050 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common header file not applicable to open-vm-tools. commit b3b985137250d9b82bb22367a1ce1e424830c21d Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common header file not applicable to open-vm-tools. commit b8fbf56a86b2d7e3d937fba9858add64d9792e8b Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common source file not directly applicable to open-vm-tools. commit 33aa649c612d2a41f850ace726047fb5d6f70475 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Remove unused header files from the open-vm-tools source bundle. commit 2723eb37bad5d86683e67c6c6d09871da35e92e3 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Log customized error exit code from offspring processes. commit 0ffadd28557203cd0c994e48ccb442f1405a85c8 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common header file not applicable to open-vm-tools. commit ec5f27caeb454cf1c4142a7e95f98b9d2e001b3d Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Fix copyright years. commit f9649775dafd0c2666f86357c1f72fb10e0d18c4 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 [Coverity]: UNINIT in resolutionSet finding from static application security testing (SAST) resolutionSet.c -- 1 issue reported in the file issue: capabilityArray not initialized or partially initialized when reaching the statement. impact: False-positive fix: suppress 'uninit_use_in_call' VMTools_WrapArray converts the capabilityArray to a GArray. The 'wrapped' array is allocated space for capabilityCount elements and only the first capabilityCount elements are COPIED from capabilityArray to the allocated GArray. As such, the uninitialized elements of the capabilityArray are never used to generate the returned GArray. While technically true (uninitialized) there is no reason to zero the array indexes from capabilityCount through to the end of the array as these elements are unused. commit b437f6f4ae99b540820cb66dabc716eb43c5c71a Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 31894dfbfcd91efe5a2712c2f33ce9114d942e11 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Fix LOCK_EVASION issue found by Coverity scan. fileLogger.c -- 2 issues reported in file issue: MultiReader/SingleWriter lock race conditions between assign and check. fix: Mitigation more than fix. issue: Coverity seems confused by the MR/SW lock, but there is some data field assignment performed under the wrong lock to clean up. fix: Move assignment made under Read lock to Write lock. Moved setting the data->error status inside of writer lock block. Added re-checking the data->error status at reader -> writer and writer -> reader lock transitions. commit 52596dea1e33e40ad8f518d445b53d7f0a4f34f1 Author: Kruti Date: Mon May 20 22:58:12 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 9e85a0c132b8aa01e27bf958b61a802602352311 Author: Kruti Date: Fri May 3 09:27:03 2024 -0700 Update ChangeLog with the granular push of May 3, 2024. - plus Copyright modification of files vmxnet3_defs.h and get-connection-info.sh. - plus ChangeLog update of Apr 7, 2024. commit a0ffd2a0bf2a1f22cce695adad374628c832555c Author: Kruti Date: Fri May 3 09:15:25 2024 -0700 Copyright update. commit 550b331d8c9b738065ea4c99daa07dcd1ab9235d Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 3abed5b9e3060208a02dd404749a3683b5aec79b Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 ProcManagerPosix.c: Direct child process's logs to stdio. Mutexes in lib/libvmtools/vmtoolsLog.c and glib could have been locked at fork time. The vmtoolsLog.c Debug(), Warning() and Panic()functions are not safe for child processes. - Direct the offspring process's logs to stdio. - Terminate the offspring process with _exit() or abort(). commit 12f3303f0559e74724b0656d192d32bd54957350 Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Fix the Y2K38_SAFETY finding found by Coverity scan. Change the date type to 'long long' to make the size be 64 bits, same as that of time_t. commit f9aaf02fd8c3e928bc1706fc9c692a6190a03a23 Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Service Discovery data collection duration takes > 70 minutes when monitoring large setups. The issue happens on vrops node VMs that are part of large clusters because these kind of nodes typically have a large amount of tcp/udp connections. The root cause of the issue is an enormous number of spaces generated by "ss -antup | grep -E $pattern" command in get-connection-info.sh. The SDMP plugin considers these spaces while calculating the chunk size for writing into NDB and writing about 200-400 chunks for the get-connection-info key. Processing of this amount of data slows down the discovery process on both the adapter and plugin sides and, as a result, the discovery exceeds the timing limit and fails. The solution is to remove unnecessary spaces from the end of the get-connection-info output lines. commit fa6d75da8c15c7fb3a696839c9f4aa7b43344d31 Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Change to common source file not applicable to open-vm-tools at this time. commit 5681e42c30f9a8875abfcdecb8c12ee8c51416f1 Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Record the use of version 12.4.5 in the vm_tools_version.h header commit 200fa56ef5f0097df888c34e24cb52c9c947d287 Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Fixes for issues found in Coverity scan. vgauth/serviceImpl/saml-xmlsec1.c issue: 'string_null' for strlen(pemCert) impact: False-positive fix: suppress 'string_null' issue: leaked_storage: certChain is not cleaned up on error. impact: Memory is leaked on the error path. fix: Add line before return to free certChain. vgauth/common/i18n.c issue: 'leaked_storage' for "name" variable impact: False-positive fix: suppress 'leaked_storage' lib/file/file.c issue: use_after_free for 'src' pointer impact: False-positive fix: suppress 'use_after_free' services/plugins/serviceDiscovery/serviceDiscovery.c issue: overrun-local: gdpErrMsgs array contains one less entry then there are enum defined. impact: Valid but the function never return the GDP_ERR_MAX enum. fix: in gdp.h, add an error entry for GDP_ERR_MAX this way gdpErrMsgs will generate all entries. lib/file/fileLockPosix.c issue: string_null for 'buffer' not being null terminated. impact: False-positive fix: suppress 'string_null' commit 1963bfed9f388aa57c9a8fc5d0f17424c76cbe60 Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 1d19761e81b9a601b6fdb10109c92331f0b11eef Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 5c10fab774d061230e8e747569d918272b182366 Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 Fix the SHELLCHECK_WARNING findings from static application security testing (SAST) install/Linux/scripts/network: Multiple shellcheck issues found in the Linux "network" script with the warning "Remove backticks to avoid executing output (or use eval if intentional)." Removed the backticks from those corresponding lines of the script. commit b892d59578b2a3d65f473d6f597df2f3c95997bf Author: Kruti Date: Fri May 3 09:05:45 2024 -0700 [Coverity]: Fix the Y2K38_SAFETY findings from static application security testing (SAST) guestInfoServer.c -- 2 issues reported in file issue: casting time_t (64bits) to int (32bits) causing Y2K38_SAFETY. impact: delta is a time delta in seconds, overflow if delta >= (G_MAXINT/1000)+1 fix: Remove cast on delta, cast both values as int64. issue: casting time_t to int for logging to a '%d'. impact: delta is a time delta in seconds, not expected to overflow a 32 bit int. fix: Remove cast on delta, change string to use '%"FMT64"d' format and cast the time_t to int64; time_t is defined as 'long int'. vixTools.c -- 7 issues reported in file issue: casting time_t to int for convertion to string (xml) impact: procStartTime is a time from epoch, it will overflow the int in Y2K38. fix: Remove the cast, change the string to use '%"FMT64"d"' and cast the time_t to int64; time_t is defined as 'long int'. issues: casting time_t to int in call to VixToolsPrintProcInfoEx. impact: The times used are time from epoch and will be impacted by Y2K38. fix: Change signature of VixToolsPrintProcInfoEx to take in time_t types. Change VixToolsPrintProcInfoEx to use '%"FMT64"d' in string conversions. and cast the time_t to int64; time_t is defined as 'long int'. commit ae31ed20bfbf0e744701f60b7839f88aa73ae554 Author: Kruti Date: Fri May 3 09:05:44 2024 -0700 Change to common header file not applicable to open-vm-tools. commit ffd52c7e4010098893a34c66b6d70b500d98711e Author: Kruti Date: Fri May 3 09:05:44 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 1b3e41d24086fed921982674daa89f70d3bd677e Author: Kruti Date: Fri May 3 09:05:44 2024 -0700 Style correction in Broadcom copyright. commit 8336d5d8ace540b356813c197794d5f14f2ae38b Author: Kruti Date: Fri May 3 09:05:44 2024 -0700 Change to common header file not applicable to open-vm-tools. commit e2d1f8c418c72f21f0ef44a83262d19e0f68185e Author: Kruti Date: Fri May 3 09:05:44 2024 -0700 Change to common header file not applicable to open-vm-tools. commit c48b6ac791d13313db4cb023b275bb6df90c565a Author: Kruti Date: Fri May 3 09:05:44 2024 -0700 Change to common source files not applicable to open-vm-tools. commit 98e9e31448b81ff4ba8f4ec29c893957aa9d07aa Author: Kruti Date: Fri May 3 09:05:44 2024 -0700 Stop the glib based logging to avoid nested logging from RpcChannel error. commit 7f68542609c84b573b0faee31acd4aa5dfffc94b Author: Kruti Date: Fri May 3 09:05:44 2024 -0700 GuestOS: Explicitly identify Flatcar Linux We support a VMX guestOS string for Flatcar Linux ("flatcar-64"). Update the guest identification code to report Flatcar, rather than generically (other linux - 64). commit 831d35dfed2fc94eb8dfa61cf16cfc7b9d1a2a36 Author: Kruti Date: Sun Apr 7 23:49:24 2024 -0700 Update ChangeLog with the granular push of Apr 7, 2024. - Plus ChangeLog update Mar 18, 2024. commit 9026382b617114a4ea10593be3358d4f5470160a Author: Kruti Date: Sun Apr 7 23:26:32 2024 -0700 Update NetworkManager calls in suspend/resume scripts. Revise the NetworkManager calls in the Linux network script to prefer using the Sleep method over the "Enable" method being used to work around a bug in version 0.9.0. Pull request: https://github.com/vmware/open-vm-tools/pull/699 Issue: https://github.com/vmware/open-vm-tools/issues/426 commit 76177671b4dbe6795b30d7282750daa6bc44c3ce Author: Kruti Date: Sun Apr 7 23:26:32 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 160a2f6464f1f8a391e20445436aac828747944b Author: Kruti Date: Sun Apr 7 23:26:32 2024 -0700 Change to common source file not applicable to open-vm-tools. commit 16b2942637b4b4c8613c97910b0c926aa78f118e Author: Kruti Date: Sun Apr 7 23:26:32 2024 -0700 Change to common header file not applicable to open-vm-tools. commit a27e36f708ba532610bc80aa05c6f646aff2e221 Author: Kruti Date: Sun Apr 7 23:26:32 2024 -0700 Change to common header file not applicable to open-vm-tools. commit d00cb18b872419d1fc9dba12d82a33249c9f8381 Author: Kruti Date: Sun Apr 7 23:26:32 2024 -0700 Change to common header file not applicable to open-vm-tools. commit dc2afa499e80d09f198d056b9f65b34054934eb9 Author: Kruti Date: Sun Apr 7 23:26:31 2024 -0700 Linux network log file permissions fix: 0644 to 0600 Since release 11.3.5, on linux guests, the vmware-network.log file has root default file creation permissions (0644) rather than the expected 0600 permissions. Fix: - Adding chmod 0600 on log file creation. - Adding file creation before first logging. - Adding handling of unset handler in case switch, default to file logging. - Adding logging of unknown or bad handler, and using file logging as default. - Default number of logfiles when network.maxOldLogFiles is set to 0. commit 98d046ba12d3eb3e34ec2cf5752a9c35721946ba Author: Kruti Date: Sun Apr 7 23:26:31 2024 -0700 Change to common header file not applicable to open-vm-tools. commit ef456ec9073f2f223e56117077fd2555a3e3d4c1 Author: Kruti Date: Sun Apr 7 23:26:31 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 9523e770f58e440e7359b3e495f2fe6b03da3447 Author: Kruti Date: Sun Apr 7 23:26:31 2024 -0700 Change to common header file not applicable to open-vm-tools. commit a02c7f8de02dd3108a5ebdd6158dfc9366051409 Author: Kruti Date: Mon Mar 18 11:42:23 2024 -0700 Update ChangeLog with the granular push of Mar 18, 2024. - plus Copyright update of file vmxnet3_defs.h - plus ChangeLog update of Feb 28, 2024. commit c2056a39e9bf4fc91cd457c4ef12c29a3e9af3a7 Author: Kruti Date: Mon Mar 18 11:30:49 2024 -0700 Correct copyright year to 2024. commit f510b78fe043392325ba0cede8066994baaa8276 Author: Kruti Date: Mon Mar 18 11:03:49 2024 -0700 Change to common header file not applicable to open-vm-tools. commit acfd8ab650f10759b09a93f8adde71459a131392 Author: Kruti Date: Mon Mar 18 11:03:49 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 3ad15e4e776738b993c8c2da8119f0c1a7bf0a91 Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 652a17c1d06a0ced2fceecde700ad93623d311b6 Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 9adc1653c0d40aef5e27e415bfa7cc111bda31bd Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 7884ab85eebacf7c864e1eecab600b94dc9dd844 Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit d27143ceb08381f644fc93d8b685965685f87f1a Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 51036fade754381b95821d54ec5e01dd56bbd5dd Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit ad34c945344422fac091d7e7d5c1869edf4b0cdf Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit 96d97fdf1031b1c71656c7089e0ecfb7390af2eb Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit fc9c9503ee2d4a1a18aed73d001ef6340491d302 Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 [GDP][GdpPlugin] Subscriber presence interrogation (ZeroData). This change allows empty/0 byte payload to be sent from GDP Plugin on guest to the gdp daemon on host when querying for subscriber presence, without publishing the data to the subscribers. commit 66fb7a4816661670889d3f6f6cb74895cfb8c6fe Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common header file not applicable to open-vm-tools. commit e3ca1f9beea77e7423c1c21d8f698b18d4ebe942 Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Change to common source file not applicable to open-vm-tools. commit 0eeef953ab3034bfd7034b5db7c064c9b287b791 Author: Kruti Date: Mon Mar 18 11:03:48 2024 -0700 Bump the VMware Tools version to 12.5.0 on "devel" branch. Ear-marked "SOCKET_WRENCH" as the tools tag for the 12.4.x series of releases. commit 11647ac4a337e7b768c98b3753acd4e814e58939 Author: Kruti Date: Wed Feb 28 10:01:36 2024 -0800 Update Changelog with the granular push of Feb 28, 2024. - plus ChangeLog update of Feb 23, 2024. commit a4b3c5996c1027cefc2e8dddcac24af2193c6284 Author: Kruti Date: Wed Feb 28 09:33:57 2024 -0800 Change to common header file not applicable to open-vm-tools. commit 3b63dd72bf283e575d86d1b691d1191f26df7c0e Author: Kruti Date: Fri Feb 23 08:06:32 2024 -0800 Update Changelog with the granular push of Feb 23, 2024. - plus ChangeLog update of Feb 19, 2024. commit 70684e40254279f8b8e16dbf51a33c0407d22703 Author: Kruti Date: Fri Feb 23 02:25:10 2024 -0800 Change to common header file not applicable to open-vm-tools. commit f9769f7b4f90e5da0ee51b699b203e1e737e0b90 Author: Kruti Date: Fri Feb 23 02:25:10 2024 -0800 Changes to common source files not applicable to open-vm-tools. commit fe771b09686ac3160886f685488a3fd7dede7831 Author: Kruti Date: Fri Feb 23 02:25:10 2024 -0800 Change to common header file not applicable to open-vm-tools. commit c199ccedd3fd8417c0d58b4ca1d3675224d8ac48 Author: Kruti Date: Fri Feb 23 02:25:10 2024 -0800 Power Ops: Attempt to execute file path only Adding a check to verify that the path to execute is a file only and not a directory. Pull request: https://github.com/vmware/open-vm-tools/pull/689 commit c35063e1280f549342a993453cadff3cc12b8ca6 Author: Kruti Date: Fri Feb 23 02:25:10 2024 -0800 Change to common header file not applicable to open-vm-tools. commit e4f0f9b0d72f583b5129fc8d2b19dd5bb4497d74 Author: Kruti Date: Fri Feb 23 02:25:09 2024 -0800 Change to common source files not applicable to open-vm-tools. commit 190202266d0d198cef38c34420be6057bd75e3e2 Author: Kruti Date: Fri Feb 23 02:25:09 2024 -0800 Change to common header file not applicable to open-vm-tools. commit 56ecc8b15b195a66d1476360b0a51579324e3820 Author: Kruti Date: Mon Feb 19 07:07:41 2024 -0800 Update Changelog with the granular push of Feb 19, 2024. - plus ChangeLog update of Nov 21, 2023. commit 9c0491a6654630397aad6a884e6aa04f1cd962e1 Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 Changes to common source files not applicable to open-vm-tools at this time. commit 6057078343bc803ff1614fc2039e31bec49bcf35 Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 Change to common header file not applicable to open-vm-tools. commit e8cbf5e4db323638b95999bb268a0d2cb2ab4ce5 Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 Changes to common source files not applicable to open-vm-tools at this time. commit 86b1b5bf4a688e9e986400249a8170d03f24bea9 Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 Change to common header file not applicable to open-vm-tools. commit aad5ad195a0a502982e7cc8d5269d13ea6e38a85 Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 Change to common header file not applicable to open-vm-tools. commit 3095d26c3d3f044911771d436c31b0cf51abea35 Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 Change to common header file not applicable to open-vm-tools. commit 60094472f75aefbbc957574faa8c1663ee0625d4 Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 lib/file/file.c: Handle EACCES during File_CreateDirectoryHierarchyEx On DELL thinOS, while creating an existing dir in a path without write permission, mkdir returns EACCES. This breaks the directory hierarchy check. This patch handles the EACCES by checking the file with euidaccess after an EACCES failure. commit 777dc80ddfcf8980c055ab33091200923a06ab67 Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 Change to common header file not applicable to open-vm-tools. commit c0cc78a3fa53c8f6ea82aafda981251e753bae4d Author: Kruti Date: Mon Feb 19 06:32:44 2024 -0800 Fix out-of-bound access issues reported by Coverity Do not pass PATH_MAX and FILENAME_MAX to Str_Strlen function call. commit 4986a2b0cbb94e8d6e3a6e4414215246aa0cbbbd Author: Katy Feng Date: Tue Nov 21 12:23:20 2023 -0800 Update Changelog with the granular push of Nov. 21, 2023. - plus ChangeLog update of Nov. 16, 2023. commit e6c2e7a6426335e6b6cef87e223a687b4623ce8a Author: Katy Feng Date: Tue Nov 21 12:17:25 2023 -0800 Change to common source file not applicable to open-vm-tools. commit 76b60aa06da13f2c1e42e10a3bef7a62a51fc896 Author: Katy Feng Date: Tue Nov 21 12:17:25 2023 -0800 Change to common header file not applicable to open-vm-tools. commit af68bed4751d1415b292d310e41f557d8c7ffcde Author: Katy Feng Date: Tue Nov 21 12:17:25 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 4bf9de66e43222f50d1280f7181bc542b059d02f Author: Katy Feng Date: Tue Nov 21 12:17:25 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 39e99567d4febf2987f22cc778c4cbefff40d307 Author: Katy Feng Date: Tue Nov 21 12:17:25 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 5bc44d481b88ddf14e9c46d56b7bd8f0ebff6b6d Author: Katy Feng Date: Tue Nov 21 12:17:25 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 7994b3261aa968f69c0fa6eabac63e4d68423bbc Author: Katy Feng Date: Thu Nov 16 09:23:56 2023 -0800 Update Changelog with the granular push of Nov. 16, 2023. - plus ChangeLog update of Nov. 13, 2023. commit 7f7374c8ab89c546e4e32d3302442103c0a0ba5e Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Fix double free in guestInfoServer.c. Double free in "GuestInfoGather(gpointer data)" for osNameFullOverride. commit db767e6d28188cbed8a13b2497877e05c5fd38ab Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Drop group privileges before dropping user privileges in vmtoolsd vmusr service. commit d3bce5781e8c869fcdd398d2bb1fcceb4ef84076 Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Send guest detailed data to VMX even when short-name is set in tools.conf. commit 7c2e898997a5b5667ed0a932652124dc85b80560 Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 1910ed7b5ac64c98d03b14532f8af7460fa0ebe0 Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Changes to common source files not applicable to open-vm-tools. commit f094b993b7be5583e47a0d3f10fcbabe1db49122 Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Changes to common source files not applicable to open-vm-tools. commit 5d5bbbecd32cbc054b81b05a5af4bdbf62aee3a7 Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change in Guest Data Producer plugin API and Guest Data Producer protocol/handshake between the host and guest to support ‘no subscribers’ error feedback. The Service Discovery plugin was updated for API compatibility. Changes in the GDP protocol/handshake introduce versioning of the protocol. The new version is “2” and introduces new attributes (‘version’ and ‘requireSubs’) in the guest request header sent to the host publisher service. The response from the host publisher service to the guest producer client is also versioned and changes more significantly: V2 response messages have new attributes (‘version’, ‘error-id’, and ‘error-text’) and have the ‘status’ attributes type change from string (‘ok’, ‘bad’) to Boolean (‘true’, ‘false’). The ‘error-id’, when present, contains a string identifier for an error type/code and ‘error-text’, when present, contains textual details for the error. The host publisher supports all protocol versions up to the version it provides for backward and forward compatibility. The host publisher service responds with the same version of protocol as the incoming request or its highest protocol version when the incoming request version is higher than it supports. The guest producer client supports all response versions up to the version it provides for backward and forward compatibility. The guest producer client always sends request to the host publisher service using the highest protocol version it supports. commit c7c88a4aacd05f7d6f232c11c5537f2d43934d6b Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 7800de416d88ba03db4f8bd818d7c99d51048bdf Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common source file not applicable to open-vm-tools. commit 72effb954333e49657315835c4df87fc0417ad2a Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 14ada379295c86b9eed8d407753c88610312a6e8 Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 2683d53f2ef4e8e01c938b6ec81f87e46e187c3d Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 8f03cddae70d27fe10b2833d53995f1dd3985f37 Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 77f6b260876aba27c497a96c833b26ec5d50578a Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common header file not applicable to open-vm-tools. commit f76fea45d2c4de6ebcc0d7f5ed40a6c24689abef Author: Katy Feng Date: Thu Nov 16 09:21:20 2023 -0800 Change to common header file not applicable to open-vm-tools. commit f756d77a51c5e1c7d66b46e5e33774b5503e21de Author: Katy Feng Date: Mon Nov 13 13:14:45 2023 -0800 Update Changelog with the granular push of Nov. 13, 2023. - plus ChangeLog update of Oct. 5, 2023. commit 8647f0cf7a15f1c3a06e903cb15e053871d23c36 Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 Change to common header file not applicable to open-vm-tools. commit beb027f7eccea977d00ef2a91da29e19ccc0a6d8 Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 Change to common header file not applicable to open-vm-tools. commit e7c2898e1a2b61948efd7bfd582a36a0e9363b3b Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 Guest identification: Asianux Linux is now Miracle Linux The Asianux distro rebranded itself as Miracle Linux. Our infrastructure already knows about Asianux however the guest identification that runs in tools does not. Add the necessary aliasing code to the "in guest" code. commit b7775db161d414bb1311a1eb120a7f8474d59aeb Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 Change to common header file not applicable to open-vm-tools. commit e6937680a6ee85431799d956c521971113508dd2 Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 Change to common source file not applicable to open-vm-tools. commit 34035501b125caadae9e0a9598f1e68bbe56282e Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 Change to common header file not applicable to open-vm-tools. commit f612000e31b788f3da054aae9d3f296447d00039 Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 File descriptor vulnerability in the open-vm-tools vmware-user-suid-wrapper on Linux Move the privilege drop logic (dropping privilege to the real uid and gid of the process for the vmusr service) from suidWrapper to vmtoolsd code. Now vmtoolsd is not executed with dropped privileges (started as setuid program) and the dumpable attribute of the process is not reset. Unprivileged users will not have access to the privileged file descriptors in the vmtoolsd vmusr process. Also, set the FD_CLOEXEC flag for both uinputFd and blockFd preventing those file descriptors from being inherited any further from vmtoolsd. commit fd4c58055253ba80d84a17778d9f2e93d117350e Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 Don't accept tokens with unrelated certs If a SAML token has a cert that's not a part of a chain, fail the token as invalid. commit 0546037841f16e8fe4148c8434e2b02cb2b0a6dd Author: Katy Feng Date: Mon Nov 13 12:07:34 2023 -0800 Change to common header file not applicable to open-vm-tools. commit c10d8436ff4137dbd66b17d12ffe1be7e00a1f2d Author: Katy Feng Date: Mon Nov 13 12:07:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit cdbc0b2bee9d771ab3c3312abe737cabecf4bfc8 Author: Katy Feng Date: Mon Nov 13 12:07:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit fa2b47d9a4d0f27be5a5172c5d0eb6f197fca596 Author: Katy Feng Date: Mon Nov 13 12:07:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit e9cab85bc079a3b5b0cc9f154a0aa90946314c72 Author: Katy Feng Date: Mon Nov 13 12:07:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit fdb122f3e196835e97d2828fd77580d4f7bedb1a Author: Katy Feng Date: Mon Nov 13 12:07:33 2023 -0800 Suppress optional arg to backup scripts when empty string. Backup scripts can be called with an optional argument. Don't pass the optional arg to the script if it's an empty string. commit e60562e9409f81541281c452af5f8426a1cc1df2 Author: Katy Feng Date: Mon Nov 13 12:07:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit b4b5483324bd241a1895e080489383ed59335117 Author: Katy Feng Date: Mon Nov 13 12:07:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 92cc832c4493c272cb9227a87f68a9ae0cf18fec Author: Katy Feng Date: Mon Nov 13 12:07:33 2023 -0800 Checking flag 'disable_vmware_customization' in more cloud-init config files Currently, the deployPkg plugin checks the existence of the flag 'disable_vmware_customization: false' in the /etc/cloud/cloud.cfg file to determine whether VMware customization is enabled on cloud-init side when cloud-init is available in guest. Instead, keep local settings, such as this flag, in config files under the /etc/cloud/cloud.cfg.d directory, for example: /etc/cloud/cloud.cfg.d/somefile.cfg This change implements the following adjustments to make sure this flag is handled the same way as cloud-init does in ds-identify and Datasource: 1. Instead of regex matching flag 'disable_vmware_customization: false', check the value of flag 'disable_vmware_customization': If the value is 'false', it means VMware customization is enabled. If the value is 'true', it means VMware customization is disabled. If the flag is not set, by default VMware customization is disabled on cloud-init side. 2. Besides cloud-init /etc/cloud/cloud.cfg file, also check all .cfg files under /etc/cloud/cloud.cfg.d directory. 3. The value of flag 'disable_vmware_customization' in .cfg files under /etc/cloud/cloud.cfg.d directory will overwrite the one in the /etc/cloud/cloud.cfg file. 4. The value of flag 'disable_vmware_customization' in a .cfg file listed further down in alphabetical order under the /etc/cloud/cloud.cfg.d directory will overwrite the value in a .cfg file listed earier. 5. If a cloud-init config file contains more than one instance of this flag, the value of the later flag will overwrite the former one. Github Issue: https://github.com/vmware/open-vm-tools/issues/310 commit 2cb54143f98031d5ab42c08e4fb1a6c9133b44b0 Author: Katy Feng Date: Thu Oct 5 15:53:07 2023 -0700 Update Changelog with the granular push of Oct. 5, 2023. - plus ChangeLog update of Aug. 25, 2023. commit d0605c5ba368a3f417ad1a24fc9dc28c0de5bef7 Author: Katy Feng Date: Thu Oct 5 15:42:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 12c2e213b1de63349c58561612333fb9af8eb00e Author: Katy Feng Date: Thu Oct 5 15:42:41 2023 -0700 Change to common source file not applicable to open-vm-tools at this time. commit 5d08866eafbc2536732d9fce9d8f024532fe0364 Author: Katy Feng Date: Thu Oct 5 15:42:41 2023 -0700 Record the use of tools version 12.2.6 for an emergency patch. Also updating 12.3.0 as released and adding the scheduled 12.3.5 update relase. commit b7f4cf3d0dcd9de5df3340ee088bb701725b4597 Author: Katy Feng Date: Thu Oct 5 15:42:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit e61042ddf3627af614a2cce12406ce7a5b5e7869 Author: Katy Feng Date: Thu Oct 5 15:42:41 2023 -0700 Enabling the open-vm-tools VGAuth Host Verification feature. The Host Verified SAML token work is complete. Adding the new code to the open-vm-tools source. commit 058863ab5eaef42aa3511d4974c32db11a3cf9d7 Author: Katy Feng Date: Thu Oct 5 10:50:32 2023 -0700 Correct missed 2023 copyright update. commit d442791014bde010be93f5b9ce588a88fcd68bc3 Author: Katy Feng Date: Thu Oct 5 10:35:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 9201543b6e4e6d5bc4788433b8231fb8d8e678a9 Author: Katy Feng Date: Thu Oct 5 10:35:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit ce61f2591ceed0b6acb4ad744a32d9362ca4b258 Author: Katy Feng Date: Thu Oct 5 10:35:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit f8b150212afbf963241685406c42002b80b10a11 Author: Katy Feng Date: Thu Oct 5 10:35:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit ad9066280a11bfc8466747e4fa4d9f60e2d29df4 Author: Katy Feng Date: Thu Oct 5 10:35:28 2023 -0700 Change to common source file not applicable to open-vm-tools. commit fe7e5654fbb69baec6c8e6de5c367346580934bc Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Linux guest identification: Correct the misidentification of Big Cloud Enterprise Linux. commit 045ccf2067bb1f9e29d20a0e8a8b9053da999cf6 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Change to common header file not applicable to open-vm-tools. commit aeb469eda96b721bb382e294f63342139c7ae694 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Remove support for building with xml-security-c and xerces-c. commit 59bff291726794b85921edf206290cd43c2b3cc2 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 6e43c69c0ab3e84a6d63d39d9fb832fc02d6076c Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit f48cd857d9fd17f4587b1d6d7213f9d88e658b5d Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 6ab97407104bd86f63ef4ab30462c2234b72e47e Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 07c13237ef07e62927fc540c0f77cd67bb6b03b1 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 0c494e27261531aaa6bc5d431e11dcf43691be61 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Allow only X509 certs to verify the SAML token signature. commit eba62c065fa21ee88d7c3e27533f1fbc4e959688 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Changes to common source files not applicable to open-vm-tools at this time. commit 3ddae17a251d51c15a576fe3da7643574a96c061 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Change to common source file not applicable to open-vm-tools. commit f906dc45d324bf531219b14c5af0f405f801d5f4 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Change to common header file not applicable to open-vm-tools. commit af8cb38e92ac414539655f563f1f05fdaf532fe6 Author: Katy Feng Date: Thu Oct 5 10:35:27 2023 -0700 Change to common source file not applicable to open-vm-tools. commit d90cefe349130cedc7af9722bac77198b4e0b891 Author: Katy Feng Date: Thu Oct 5 10:35:26 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 60ede3ec06d81bf7033ca2ac68431148506baf1b Author: Katy Feng Date: Thu Oct 5 10:35:26 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 2138a3fd2c8599d1d5ce66a423e86f61ba4dfe69 Author: Katy Feng Date: Thu Oct 5 10:35:26 2023 -0700 Remove Glib usage from stringxx/ubstr_t. Replace Glib::RefPtr with std::shared_ptr. commit e367c428ff4062517228171ea63359fdbe252e66 Author: Katy Feng Date: Thu Oct 5 10:35:26 2023 -0700 Update Glib header inclusion to address C++ compatibility issues. commit a2f775b5c3e1d6c4859308bb87d9209018a28716 Author: Katy Feng Date: Thu Oct 5 10:35:26 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 0633d24feca0d9aa28696b4156c6f1944d3e7644 Author: Katy Feng Date: Thu Oct 5 10:35:26 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit 126f05a2c2834ce20bc507b5e0f96b3b5929ed1a Author: Katy Feng Date: Thu Oct 5 10:35:26 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit 1930fbc010efcfb95196a999e6f24c9bcb19087f Author: Katy Feng Date: Thu Oct 5 10:35:26 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit e796234eb7a790ac1accc87534106e10140394fa Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Change to common header file not applicable to open-vm-tools. commit bacfb532b8f904c7d4141891ca95db7b4b6c0ac6 Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Allow pre-Windows 2000 style user logon for Linux Guests. With this change, applications that require user/password type authentication/authorization (done by VGAuth service) for guestOps can now use pre-windows 2000 style user logon for Linux Guests too. Github Issue: https://github.com/vmware/open-vm-tools/issues/641 commit 6267410529bdc7ba4c4e89293232d72f7d824641 Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 1536a14b450633ba8040f3fc57e922e39d9b3311 Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Change to common header file not applicable to open-vm-tools. commit f2485a10afcbc3a81b9cfc4726e2492a338b729a Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit 97fd6909e336796e5eb3829d853754de9ac3b97a Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 7a6e765d2a5f3946513abdec8fc61c00385dc120 Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 2f1d2a0231db89c035b1dcd8a6266ea8ae49c9c4 Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Bump the VMware Tools version to 12.4.0 in the "devel" branch. Setting the development VMware Tools version to 12.4.0. Adding the tag "HEDGE_TRIMMER" to the 12.3.0 version. commit 5188bd21d33180eb70612f57d5cb2aef8188108a Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Change to common source file not applicable to open-vm-tools at this time. commit 093aef15e1e390a613237a3bdd7a8c794ab672cc Author: Katy Feng Date: Thu Oct 5 10:35:25 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 75a751e2fda529a14de79fd32fb25ca97612400c Author: Katy Feng Date: Fri Aug 25 12:11:31 2023 -0700 Add missed 2023 copyright change. commit 1335787e74fc86752984c81ea7b0bd1b0065ce89 Author: Katy Feng Date: Fri Aug 25 11:57:15 2023 -0700 ChangeLog update of Aug. 25, 2023. commit 518a77a39a30d39c4397d2533bae57880f44ec6e Author: Katy Feng Date: Fri Aug 25 11:51:12 2023 -0700 ==================================================================== The "stable-12.3.x" branch was created from the "devel" branch here. ==================================================================== Update ChangeLog with the granular push of Aug. 22, 2023. - plus ChangeLog update of Apr. 24, 2023. commit 14dfd9c00b5321bafc012f678ef1cd2129e03a73 Author: Katy Feng Date: Tue Aug 22 15:51:19 2023 -0700 Fix build problems with grpc Updating Makefiles to put -l specifiers into LIBADD and not LDFLAGS. Use the grpc++ pkgconfig (.pc file) if it exists to retrieve flags and libraries for linking. Pull request: https://github.com/vmware/open-vm-tools/pull/664 commit 6584bcaa8c25da5ef0f20c7f6a17e6b173a25f2d Author: Katy Feng Date: Tue Aug 22 15:51:19 2023 -0700 Change to common source file not applicable to open-vm-tools. commit a1f318dfb992cfee9555a747207fce6721313e2c Author: Katy Feng Date: Tue Aug 22 15:51:19 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit f584dca10f4cc7e0a0733ac5dc8844aac65af7ae Author: Katy Feng Date: Tue Aug 22 15:37:45 2023 -0700 Enable hostVerfied SAML token feature in Tools. commit 4463b84006034879cb1d8cba8ae43f9509c6d0ac Author: Katy Feng Date: Tue Aug 22 11:11:43 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 6430649b834da00a81410f7c1d87ca4e67409ada Author: Katy Feng Date: Tue Aug 22 11:11:43 2023 -0700 Changes to common header files not applicable to open-vm-tools. commit 6489b7c0bc4d8fb603cf11ff4605a5d2a975daa8 Author: Katy Feng Date: Tue Aug 22 11:11:43 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 447f17dfb33a69a43a6d4ad1b5e486a6b20a6f77 Author: Katy Feng Date: Tue Aug 22 11:11:43 2023 -0700 Change to common header file not applicable to open-vm-tools. commit dfc6ee8aa66b3bfcdefe8020639f2b2ef03c215d Author: Katy Feng Date: Tue Aug 22 11:11:43 2023 -0700 Changes to common header files not applicable to open-vm-tools. commit 859849c55f34a777e6ac2a4e38aab30028b5207a Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 759613baeb1377708123772be1fe70da341b1707 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 972d10eab23dda4d219f919685fbcd2651a57165 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 6852459279251412d01b073de977c1848119918c Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 8a3103cfb7d68f7e501c16f8ddb4cc998a68ad20 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Changes to common header files not applicable to open-vm-tools. commit 8047bc8787d3bf04748fb3435c1731cc03f30405 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Fix VThreadBase_ForgetSelf using wrong format specifier for VThread_CurID. commit c3eb0c034c53a80d92acbdc1cb8699c4d9a724df Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 1a27960f1761ad9f9e5bb7e5eb952f51e2fa0a60 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 901511c7de7a1d870725eeeb5f660f8728dd119d Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 8205b35f6b29c10a6e12616785f65c18b0c5204b Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Changes to common header files not applicable to open-vm-tools. commit 17543c6584bdd41ff75d1ea85b4cf61c7b39f65e Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 89831b1c249ba89d683d74b3624efe77ad3f3e53 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 svtminion scripts v1.6 fixes for salt-minion release 3006.0 Fix output of getent group, so don't make noise on Linux. commit eabbaf9bca1320b45fb7ad46cf48f5fbf49e958f Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 60c3a80ddc2b400366ed05169e16a6bed6501da2 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Provide alternate method to allow (expected) pre-frozen filesystems when taking a quiesced snapshot. Effective with open-vm-tools 12.2.0, Linux quiesced snapshots will fail if any filesystem(s) have been prefrozen by other than the vmtoolsd process. This has been done to assure that filesystems are inactive while the snapshots are being taken. Some existing prefreeze scripts may be freezing some filesystem(s). In these cases, the vmtoolsd process must be informed of anticipated pre-frozen filesystems by providing an "excludedFileSystem" list in the [vmbackup] section of the tools.conf file. This change provides a new switch in the tools.conf file to allow pre-frozen filesystems to be encountered and accepted when doing a quiesced snapshot operation. With the default value of "false", the "ignoreFrozenFileSystems" can be configured with a setting of "true" to notify the quiesced snapshot operation that pre-frozen filesystems are allowed. commit baf812a3d942e9f1a6fe9774ddc5e514b976f059 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit b3c23d050ffab46ae24d6fc8e98851a07863dd2a Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 99ee819329e6b1b51affcf15673c2020bfe4e059 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit dcc090563d12ba436c7137bb3861b2966fc372cd Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common source file not applicable to open-vm-tools. commit c0116f300bfe2d37919fb333d63fd401dc228e5b Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 3f4dd03d969efe60c6c77002a3b8c8ddfd325ab3 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 6aa05e8959408d0981c18ed8dfc29513b71c98a8 Author: Katy Feng Date: Tue Aug 22 11:11:42 2023 -0700 Change to common header file not applicable to open-vm-tools. commit f6c27bbe691ba06f535d9b5d5dbabd4d4d5e3b1b Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 01d4788e191d1a846dbe7220442e25bba2cb545c Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 9d8054800e10cabeed6911a5b8ac85d612565fe6 Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 0bc0f8e68339c1bae63e9d8734d4d10c8d4b5fa9 Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 549f04fabbba57a33b8983e02064e216b8393485 Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Changes to common header files not applicable to open-vm-tools. commit 508933ad4fb97cde6d19544d13005c88eaa9362f Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 9f1c97526ba6414bfbc342fcf0f8a83118dbee8d Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 016fa52e6bcbf868a08b5dbac0fdb8f19ab14c9a Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Removing appUtil library from open-vm-tools. Several Linux distributions have deprecated the use of gdk-pixbuf-xlib library and many may follow suit in future. Remove the appUtil library, which was required by Unity but is no longer supported on Linux guests. Github Issue: https://github.com/vmware/open-vm-tools/issues/658 commit 55d4f25e7ad27b77268bf5f2d61e75336890dacc Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit 2a770fead82a86a8b67107c40fa8e5986fd39416 Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common source file not applicable to open-vm-tools. commit bea8dba7af41c6988a76bf6cbc47efd1d35761f3 Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Remove some dead code. commit 3a897d916ed6e69ebcede282ee36757808ee29af Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 svtminion scripts update for salt 3006 release Scripts Ver. 1.5, support for status 106 code feature. commit 5cf3023cf9981a97cd65f3600d03dc4714b4cc5e Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 8b940e736ed25a7e7bad47a476f6e0db154620aa Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit eb771586d88bd46fc38853b4f63cc01262a168b1 Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Introduce the new CAP_HOST_VERIFIED_SAML_TOKEN capability. commit 2793302b6d4bcd427a6e4b70263b4ce8069fdd00 Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 0b24b9b517c939059535aae8bfcd2ad70acaced1 Author: Katy Feng Date: Tue Aug 22 11:11:41 2023 -0700 Modify the comment for the CONFNAME_DEPLOYPKG_PROCESSTIMEOUT value range. commit a353e69b9438ca149a185a2249d076c951d945fe Author: Katy Feng Date: Thu Jun 1 10:22:47 2023 -0700 Copyright symbol updates. commit a15a0bda093255eadb3768fb845b96a185ac6af9 Author: Katy Feng Date: Mon Apr 24 12:46:20 2023 -0700 Update ChangeLog with the granular push of Apr 24, 2023. - plus ChangeLog update of Apr 6, 2023. commit b4ecba012795fd6e227a36f9da43ae390f8ac121 Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common header file not applicable to open-vm-tools. commit a5eb9f3ce90f3c9ac79673db7e21486fcc8b434d Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 5321737607c4779936ea7d1ca4eb7cc02f0ba452 Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 68b465af17e333d04776fc606088fc39b2a3dcdc Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Changes to common header files not applicable to open-vm-tools. commit 68107d0bd5e7f900c2af5946ef560fdcd5454534 Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 27ea45d66f2358c1dcc8400a600f5e4ed8a419a1 Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 8c7bbf28197c254d6859ac6727ab88355b2cb7f8 Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common header file not applicable to open-vm-tools. commit c66fb5c9ec87167f82d8b72c611a2df35af514a9 Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 0fb50371215f5a6924103309980e565eebff08a6 Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common header file not applicable to open-vm-tools at this time. commit a480533a0a2bbeb9701f305cf3f78278e1279347 Author: Katy Feng Date: Mon Apr 24 12:30:14 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 87eb9ad7ed9ded840ac577cad2c027c3eaf9b49f Author: Katy Feng Date: Thu Apr 6 11:36:37 2023 -0700 Update ChangeLog with the granular push of Apr 6, 2023. - plus ChangeLog update of Mar 24, 2023. commit 0c15d1214d340893719c9eaaee7a071318bd7399 Author: Katy Feng Date: Thu Apr 6 11:33:31 2023 -0700 Correct missed 2023 copyright update. commit 41f7e48c7570673bf84938bdf243dd78ad66c608 Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Update the AUTHORS file in open-vm-tools. commit 377f82a668c6c02a3fa15ad3f2da3a5b7849f39a Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Changes to common header files not applicable to open-vm-tools. commit d65cdcb30a38f8de7f127f9b6c8bf78e8c987b98 Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit 06081ea162cb73754b9bcb6574db78cba6db5aa7 Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 215d87b455bc630f33c22f67d362a6e530fdd1db Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 0365b80e3a5c67ecedd3dcc312e425ef4b2ec9dc Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Changes to common source files not applicable to open-vm-tools. commit 9c861f7feade19ef863a46f5ddd59c44d98a7b83 Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Changes to common header files not applicable to open-vm-tools. commit 8ee7744f7716467185c2a7abda8776ea10387f5f Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 241b8eefe7090086a8fc8bab5b9504578731eaf1 Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 3a16728979d86ed78009817f1940a3ddc40b9103 Author: Katy Feng Date: Thu Apr 6 11:27:41 2023 -0700 Improve POSIX guest identification Many Linux distros do not provide LSB information. Instead, they rely exclusively on the the os-release standard information. We previously used a ranking system that rates the LSB data (if present) against the os-release data (if present). With the LSB data install much more rare than before, perform a quick check for the LSB before attempting expensive operations. This is in response to these GitHub issues: https://github.com/vmware/open-vm-tools/issues/647 https://github.com/vmware/open-vm-tools/issues/648 Note that we cannot look just for the os-release data. In older Linux releases, there are mistakes or differences between the os-release and LSB data. We must continue to do what we do now or risk changing the identification of older releases. This optimization is very effective. commit b9da6af8a561b911c6d59cfffb5b96cd5af3b6f7 Author: Katy Feng Date: Fri Mar 24 13:48:17 2023 -0700 Update ChangeLog with the granular push of Mar 24, 2023. - plus ChangeLog update of Mar 6, 2023. commit dfe0aa7ef53ea6051d31cc69f406e746e8d0f80c Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Change to common source file not applicable to open-vm-tools. commit 5e28e7e7577b35c585d4c45e053a162615bdbb1b Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 2a9a730985ff05bcb808e68e4526856bb77a4c17 Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit acff74d7fa4e4f3bb70c575a287cac2762cfdaec Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Record the usage of VMware Tools version 12.2.5 in vm_tools_version.h Adding tools TOOLS_VERSION_BANDSAW_UPDATE1 for 12.2.5 into the vm_tools_version.h header file. commit c30e8e66dcc41fd6e869c3a87d712ab29a90df8a Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Record the GA release of VMware Tools 12.2.0. Adding the "_RELEASE" suffix to the tools 12.2.0 tagname in vm_tools_version.h. commit a1a29b2358c8ca022d5116ee199c02337ec6a4a9 Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Add UNMANAGED InstallStatus value for components The UNMANAGED InstallStatus is returned from components operations to indicate that the component is installed (detected) but is not to be managed by the Component Manager. The Component Manager will not take actions (except checkStatus) until the UNMANAGED status for the component gets resolved (externally). The Salt Minion (salt_minion) component returns code 106 ("ExternalInstall") is equivalent to UNMANAGED. commit 62dc9fe959f8cc6fee64a716cc1de2dee0f0d0ef Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 lib/file: Fix timetools breakage to use memset GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) wrongly complains about using the zero initializer in some circumstances. commit f26fad0849a5107018bbcc0b4687b460432e6d3c Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Change to common source files not applicable to open-vm-tools. commit ab7a609bd52b57e74946a58f9a989845128555d3 Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 12cc8ad99a9cd8faaf990d03010d511d50f88ee2 Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit 425df45b9551383ec393d44926782f3d64603d83 Author: Katy Feng Date: Fri Mar 24 13:29:28 2023 -0700 Change to common header file not applicable to open-vm-tools. commit e0cec2ba3f7fcf0958077d6209a58951f5a6d275 Author: Katy Feng Date: Mon Mar 6 10:42:40 2023 -0800 Update Changelog with the granular push of Mar 6, 2023. - plus ChangeLog update of Feb 23, 2023. commit 813d8531e739f6a12a4e3c92f18786e10f46eacc Author: Katy Feng Date: Mon Mar 6 10:32:39 2023 -0800 Add antrea and calico interface pattern to GUESTINFO_DEFAULT_IFACE_EXCLUDES. Since k8s are more popular nowadays and their CNI also has IPs for pods, we should also exclude the IP assigned by popular CNI. Fixes issue: https://github.com/vmware/open-vm-tools/issues/638 Pull request: https://github.com/vmware/open-vm-tools/pull/639 commit b822932f2b0ea864fdc85005e6ed7bf34c4b2a75 Author: Katy Feng Date: Mon Mar 6 10:32:39 2023 -0800 Change to common source files not applicable to open-vm-tools. commit 11141b784b66a941a98cb8d781125837bbcb267b Author: Katy Feng Date: Mon Mar 6 10:32:39 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 43cab44867c952b67255d92acfda43bb89ce7cbf Author: Katy Feng Date: Thu Feb 23 11:55:53 2023 -0800 Update Changelog with the granular push of Feb 23, 2023. - plus ChangeLog update of Feb 3, 2023. commit a9e42290898d7077f73cda7fceeab046f0164388 Author: Katy Feng Date: Thu Feb 23 11:52:12 2023 -0800 Correct missed 2023 copyright update. commit e4d5478f95dc0e38b4e152278b30e49960784be9 Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 lib/file: Improve File_SetTimes There is a new system call for setting times that removes race conditions. Use it when it is available. commit 2e8ac3a7963a5ba98808c2b0748773140da6be86 Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 7173a629c81bd6acf45cb07dbb169fda5ab73adf Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Change to common source file not applicable to open-vm-tools. commit 202c4939446da2e251ded55a9566c54d0d9f655a Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Inclusive terminology - "sanity check" Address uses of the term "sanity check" in some files used by open-vm-tools. commit e530a014e677213e5660106c75eddb72d151016b Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 076aa3f0276010daaae95a95b2c3d4aea56b55bd Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Remove SSL_NewContext() declaration from sslDirect.h commit 8d7402b5b309275a4ef0c609966afed086d91e13 Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 7ab29ed5a2ec3b80f0d5e69a437e48e667bca8ec Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 6927da94f892ce3a9acae9cb297842c4f7852b16 Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Change to common source file not applicable to open-vm-tools. commit 355ea8ce3cd4b5038fb79e0a6ca10777ec4fdf79 Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 62b3b42fa69fc7a7fc8fdda9d1a8cd158244c819 Author: Katy Feng Date: Thu Feb 23 11:27:13 2023 -0800 Change to common source file not applicable to open-vm-tools. commit 830e9031f64d614c7bfe0acab022a9c33da9da2a Author: Katy Feng Date: Fri Feb 3 09:57:46 2023 -0800 ChangeLog update of Feb. 3, 2023. commit 632a516d8c4b64025ed0f7b0ee890ebb36a99a15 Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit d0346245ddb589e8d35e02650321682987c60f09 Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit b2acb8fb61dd2b3888ee58e78313ee29581c41fb Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 33b542fff5ecb78a0f1da4a005b09d11853f7026 Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common source file not applicable to open-vm-tools. commit 007203173890d75171db2c450bcaf37eb23c6a1d Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit e470e09b81a417e9f0c123793e3b4f0bfc1cd0cc Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit b40e6808fd6bb6483cef741cd80c3ab58f4094c8 Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 58580a5d5bd3f8a0661408031dca52ac5c70183a Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 82379efe344790ee4ab58927a194a55d6931bc3d Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Inclusive terminology - "sanity check" "sanity check" clean-up: - Rename functions: - ./scripts/linux/network -> Renamed "sanity_check" to "confidence_check". - ./vgauth/lib/proto.c -> Renamed "Proto_SanityCheckReply" to "Proto_ConfidenceCheckReply". - Replace "sanity check" with "confidence check" in comments. commit 556f27f7011927d27283923b6b86dd446fd2ff17 Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Bump the VMware Tools version to 12.3.0 in the "devel" branch. Setting the development VMware Tools version to 12.3.0. Adding the tag "BANDSAW" to the 12.2.0 version. commit 3232ed80db1af22c9906d78d12804681dc23fbfd Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit afc98393dfefae36bb26c9018b9d6e2d149688ad Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 486ca6223aad2474e356b0651476db53d4917a49 Author: Katy Feng Date: Fri Feb 3 09:41:08 2023 -0800 Changes to common header files not applicable to open-vm-tools. commit 3bc128aa58770d400de28f899cd867804f8aefb3 Author: Katy Feng Date: Tue Jan 17 19:32:04 2023 -0800 ChangeLog update of Jan. 17, 2023. commit 512af95b8788f5784126368462866eb0e4d76524 Author: Katy Feng Date: Tue Jan 17 19:22:16 2023 -0800 ==================================================================== The "stable-12.2.x" branch was created from the "devel" branch here. ==================================================================== Update ChangeLog with the granular push of Jan. 17, 2023. - plus ChangeLog update of Dec 31, 2022. commit 891f1f654a6d2bffb270d6f3c7e69caec431d860 Author: Katy Feng Date: Tue Jan 17 19:15:28 2023 -0800 Correct missed 2023 copyright update. commit 9d458c53a7a656d4d1ba3a28d090cce82ac4af0e Author: Katy Feng Date: Tue Jan 17 19:08:33 2023 -0800 Track Linux filesystem id (FSID) for quiesced (frozen) filesystems Tracking the filesystem FSID along with each file descriptor (FD) as the ioctl FIFREEZE is done. An EBUSY could be seen because of an attempt to freeze the same superblock more than once depending on the OS configuration (e.g. usage of bind mounts). An EBUSY could also mean another process has locked or frozen that filesystem. When an EBUSY is received, the filesyste FSID is checked against the list of filesystems that have already be quiesced. If not previously seen, a warning that the filesystem is controlled by another process is logged and the quiesced snapshot request will be rejected. commit 193200d3ce31461f876f4779ced3ca5c85f32459 Author: Katy Feng Date: Tue Jan 17 19:08:33 2023 -0800 Salt-Minion 1.4 copyright and license updates. commit c3d2d7a23ad0deac57bf53667ebe5d14c24d53c2 Author: Katy Feng Date: Tue Jan 17 19:08:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit ebd466b5a4f55e68486cc0e747ee6b76a4f171f1 Author: Katy Feng Date: Tue Jan 17 19:08:33 2023 -0800 backdoor_def.h: Update the Arm specific comment to be arm64 only. commit 998ff379939defc09834ae55fea450ee61f46ca9 Author: Katy Feng Date: Tue Jan 17 19:08:33 2023 -0800 FreeBSD: Support newer releases and code clean-up for earlier versions. Changes to allow open-vm-tools and drivers to be compiled for newer FreeBSD releases and clean-up/remove code for earlier FreeBSD releases that are no longer supported by the FreeBSD Foundation. - remove old FreeBSD version support. - trap SIGBUS while VmCheckSafe(). - fix build on recent versions. - fix build after 1400043 - fix build after 1400051. - replace deprecated NO_MAN by MK_MAN=no. Pull request: https://github.com/vmware/open-vm-tools/pull/584 commit ab1728ebe46703624f151d09a65a100ccd514891 Author: Katy Feng Date: Tue Jan 17 19:08:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit aad49df92c53aa561c4a23507ef4617c09a449ba Author: Katy Feng Date: Tue Jan 17 19:08:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 739cc1b828c1e23daca46a61b105391e8f271bb2 Author: Katy Feng Date: Tue Jan 17 19:08:33 2023 -0800 Change to common header file not applicable to open-vm-tools. commit 0ab6ba968e040f0b72e564338c6ea2b52bcb9e7c Author: John Wolfe Date: Sat Dec 31 22:42:11 2022 -0800 Update Changelog with the granular push of Dec 31, 2022. - plus ChangeLog update of Dec 22, 2022. commit 301cea5522870a746112cd6d634a04c465dcf7cc Author: John Wolfe Date: Sat Dec 31 22:13:07 2022 -0800 open-vm-tools SUSE: Detect the proto files for the containerd grpc client On SUSE systems, the Go src'es are installed in a different location, namely /usr/share/go/1.18/contrib/src. Extend the config checks to detect that location. OVT pull request: https://github.com/vmware/open-vm-tools/pull/626 commit f749bd5b0647c7bdf8aa46ca035e070b5def352e Author: John Wolfe Date: Sat Dec 31 22:13:07 2022 -0800 Add missing error codes for AsyncSocket_GetGenericError() AsyncSocket_GetGenericError() returns ETIMEDOUT or ECONNREFUSED errors when they are encountered. Added cross-platform #defines that represent these codes. commit df63ef8559535bc57dfb5cecff7944074aca33e4 Author: John Wolfe Date: Sat Dec 31 22:13:07 2022 -0800 Common header file change not applicable to open-vm-tools. commit 11d107a07440c8cd97f4a3c34b8664a2089812ac Author: John Wolfe Date: Sat Dec 31 22:13:07 2022 -0800 Changes to common source files not directly applicable to open-vm-tools. commit 47a5bd3bd87f00e9e39cd3641028940eecbb315a Author: Katy Feng Date: Thu Dec 22 16:37:51 2022 -0800 Update Changelog with the granular push of Dec 22, 2022. - plus ChangeLog update of Nov 29, 2022. commit 082f7f784b28452058ac6a6529f289144b5694d9 Author: Katy Feng Date: Thu Dec 22 16:25:51 2022 -0800 Inclusive terminology - "sanity check" Partial "sanity check" clean-up: - Change comments from "sanity check" to "confidence check" commit 63a35ed428b16baedc4cea0d666ac1b8d762de2e Author: Katy Feng Date: Thu Dec 22 16:25:51 2022 -0800 Powerops plugin: Enhance logging and response message when a previous powerops script is still running. commit 91e8725d65565b4b3452085a2e9db6e3f0bb1dcf Author: Katy Feng Date: Thu Dec 22 16:25:51 2022 -0800 lib/panic: Remove Panic_GetCoreFileName and Panic_SetCoreFileName. Panic_[GS]etCoreFileName have been dead code for a very long time. This change removes them, along with the underlying panicState.coreDumpFile field. Also, do some reformatting and tidy a few comments. commit f2d8ed1e924818d9611db104a5a259290e53f68f Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Common header file change not applicable to open-vm-tools. commit bd63d8029852af847383f19cd13d62adcabaabaf Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Source file changes not directly applicable to open-vm-tools. Minor cleanup in a couple of Makefile.am files. commit 4a2332747dc9e95e7b93d2b6d28b1d7fd474e3f2 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Linux guest identification: Make the code more robust Additional clean up. commit 049e37fef87a515c69471e7682ed5c3274942cf0 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Common header file change not applicable to open-vm-tools. commit 264c9c4cd4d8fbd06abaa3dc9266e4e16d2380d2 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Inclusive terminology - "disabled" Partial "disabled" clean-up: - Change comments from "disable(d)" to "deactivate(d)" - Change comments from "enable" to "activate" for grammar consistency commit 4f884c52df4d03246e40715d771a23a9af17436e Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Linux guest identification: Make the code more robust. The code to read and parse the os-release data isn't doing a good job of protecting the tools daemon. Fixed this. - do not depend on sscanf. - bound the size of parameters; - better checking for syntax errors. commit 1f1a34edda47b37d3bd7040b9f2080f8dcb23275 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Silence ComponentMgr logs for a missing support file. Components managed by the componentMgr plugin are often optional. The missing component script file is a normal condition. Silenced the logs by changing the message level from g_info to g_debug. commit 422205fcad59a9202a06b65fe28e9ced1d3b1a3b Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Limit the number of RPC vsocket connect() retries for ECONNRESET errors. If a guest VM has been configured with 'guest_rpc.rpci.usevsocket = "FALSE"' to work around a problem in ESXi 6.0 ot 6.5 (KB 2149941), that guest VM may experience high CPU usage on open-vm-tools 12.1.0 and 12.1.5. commit 4e278d12ea1ad9b541de94791065bf4658ed781d Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Change to common header file not applicable to open-vm-tools. commit a7da31373c5bb21d647a22c240a204645fa5f9ef Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 [TimeInfo] Handle notifications and get updates TimeInfo, which is part of TimeSync plugin, can be used to query, set, subscribe, and receive updates for time-related information from the host when guest is using precisionclock to consume time from the host. Previous changes laid foundation to subscribe and unsubscribe for TimeInfo updates in open-vm-tools during init/shutdown. When open-vm-tools subscribes for TimeInfo updates, VMX will send a notification GuestRPC to tools if and when the timing properties change. This change adds support to handle such GuestRPCs from VMX. The handler for the GuestRPC is pretty straightforward for now: it queues an async task that simply gets all updates and logs them. commit 4ab39d04ddde473a9698660a545c356aa5614dcb Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 0b2992f6718150d7c04ce4268e071033d4222e45 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Limit retry if the VMX RESETs a vsock connection If guest_rpc.rpci.usevsocket = "FALSE" is set, a vsock connect() will always fail with RESET. This confused code that thought it could only happen for secure sockets when they were quickly re-used. Limit retry, and only for secure connections. commit 3cfb89bd45978bababef56404e33da7e645b0b5a Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 [TimeInfo] Subscribe/unsubscribe to notifications during init/shutdown This change adds support for subscribing to time info notifications when this feature is enabled in the tools. As a result VMX will send time info notifications to the tools when host timing properties change. The change adds support to perform subscribe/ unsubscribe GuestRPCs from tools. Note that, handling of notification (received from VMX) will be implemented in the next change. commit a23ac6dc590374f3b990f4d220ec59d1c3d82195 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 70c64efdedfc4b6772fe540f502113b8b58d6aad Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 11d8bddccab30dea8c33ab8fb895b599ea6b8419 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 4e5ff11a5927ebf711656d30166914725fd811f9 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 [TimeInfo] Introduce TimeInfo in TimeSync plugin This change lays a foundation for upcoming changes to support TimeInfo feature in open-vm-tools. TimeInfo feature is introduced as part of TimeSync plugin and can be used to query, set, subscribe, and receive updates for time-related information from the host when guest is using precisionclock to consume time from the host. This change simply adds a new file and basic init/shutdown routines which are called as part of TimeSync plugin load/unload. The change also introduces a config option to enable/disable this feature (default is off). The feature is Linux-only for now. Upcoming changes will add support for subscribing and receiving TimeInfo updates. commit 042b463ba64d527345c0a6048915d1b9a6a3402c Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 6c4e9964f58d94b31fda5bcc54c976959dd4f339 Author: Katy Feng Date: Thu Dec 22 16:25:50 2022 -0800 Inclusive language - "disabled" Use “deactivated” instead of “disabled” in some files used by open-vm-tools. commit e85f51de2849566e8dd08f035474bfc626a17d8d Author: Katy Feng Date: Thu Dec 22 16:25:49 2022 -0800 Enhance the guest identification code for Linux The Linux guest identification code is enhanced to return two additional fields (when a distro makes them available): 1) The VERSION field This field sometimes contains additional information not found in other fields. For instance, on SLES, this provides the patch level information. 2) The CPE_NAME field This is the NIST Common Platform Enumeration Specification string. If present, this may provide information in a standardized form. commit 569c595128322339d1435d6a745243d2d7aec860 Author: Katy Feng Date: Tue Nov 29 12:22:44 2022 -0800 Update Changelog with the granular push of Nov 29, 2022. - plus ChangeLog update of Nov 4, 2022. commit e058df3ebf6aa0b4cd1b15f1f55ac4d56f09c5ed Author: Katy Feng Date: Tue Nov 29 12:11:43 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 136de61dd7c2a473ca926e2df1800c6d76aa5da0 Author: Katy Feng Date: Tue Nov 29 12:11:43 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 6208fe0c286f45c70c621c15bdf90e935a5a56ee Author: Katy Feng Date: Tue Nov 29 12:11:43 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 7a94ee4524da9c794a68d6b2e7106d719209d93e Author: Katy Feng Date: Tue Nov 29 12:11:42 2022 -0800 Change to common header file not applicable to open-vm-tools. commit 5405d130aba6724ba671cf5d3ff8b250147d624c Author: John Wolfe Date: Fri Nov 4 11:58:14 2022 -0700 Update Changelog with the granular push of Nov 4, 2022. - plus ChangeLog update of Oct 21, 2022. commit bf074c36924f28b3f36f88aa4bed0337a0b695be Author: John Wolfe Date: Fri Nov 4 11:45:05 2022 -0700 Add explanatory comments for Coverity false positives. Add comments for two memory leak false positives reported by a Coverity scan of open-vm-tools. Don't annotate since the annotations can't be made specified to the leaked variable, so that if an actual leak were introduced in the future an annotation would cause it to be reported as a false positive. For the same reason, replace a leaked storage annotation added previously with an explanatory comment. commit b85ab7a63a97d9b7258df73638c76f9b7c149a4f Author: John Wolfe Date: Fri Nov 4 11:45:05 2022 -0700 Change to common header file not applicable to open-vm-tools. commit da618bbbdaa6341c478d548a7d951250c571ad8e Author: John Wolfe Date: Fri Nov 4 11:45:05 2022 -0700 Changes to common source files not applicable to open-vm-tools. commit f5eb126149dccb3172a90e772f6d5471a6c2c435 Author: John Wolfe Date: Fri Nov 4 11:45:05 2022 -0700 Change to common source file not applicable to open-vm-tools. commit d88dcf561315a316c1e2efda6a96ec22e2183306 Author: John Wolfe Date: Fri Oct 21 12:11:07 2022 -0700 Update ChangeLog with the granular push of Oct 21, 2022. - plus ChangeLog update of Oct 12, 2022. commit 3e1154b1e260982a47f66a9c807b7613ced95f59 Author: John Wolfe Date: Fri Oct 21 11:39:49 2022 -0700 Common header file change not applicable to open-vm-tools. commit 6d934775155d5b1ee000056319290780e4e79b80 Author: John Wolfe Date: Fri Oct 21 11:39:49 2022 -0700 Fix a regression caused by the previous guestOps ListFiles() change. If maxResults is 0, return an empty file list plus the remaining number of files. commit 3c7bcfc3a3ca1e8a4d80b2eded28cb36535717f0 Author: John Wolfe Date: Fri Oct 21 11:39:49 2022 -0700 Fix printf format type found by Coverity scan. printf format should be using %zu to print a size_t value. commit f56f1573158d0d5c1962202fba4a4aa8d0bfa35e Author: John Wolfe Date: Fri Oct 21 11:39:49 2022 -0700 Common header file change not applicable to open-vm-tools. commit 40c74575b37430a2e30dbdd149b5de8c45978949 Author: John Wolfe Date: Fri Oct 21 11:39:49 2022 -0700 Avoid a vmtoolsd service error message if not on a VMware hypervisor. When open-vm-tools comes preinstalled in a base Linux release, the vmtoolsd services are started automatically at system start and desktop login. If running on physical hardware or in a non-VMware hypervisor, the services will emit an error message to the systemd's logging service before stopping. This change removes the unwanted error message. commit c1ba736f18d35d5b1e149aa43a902cb2a69927f3 Author: John Wolfe Date: Fri Oct 21 11:39:49 2022 -0700 Common header file change not applicable to open-vm-tools. commit 6224a7616e26fd816772a82e100674ffdd87cf9f Author: John Wolfe Date: Fri Oct 21 11:39:49 2022 -0700 Common header file change not applicable to open-vm-tools. commit 6ec06e4a6482872421a87367814849f340bfb1a8 Author: John Wolfe Date: Wed Oct 12 13:21:25 2022 -0700 Update ChangeLog with the granular push of Oct 12, 2022. - plus ChangeLog update of Sep 21, 2022. commit 7909b89d2d847f416257932e3c6ef96085a69ad4 Author: John Wolfe Date: Wed Oct 12 13:04:00 2022 -0700 Add missed 2022 copyright change. commit cb762155088e5f56535d1f8990718d8880d165ff Author: John Wolfe Date: Wed Oct 12 12:40:37 2022 -0700 Common header file change not applicable to open-vm-tools. commit 51a5cca0c77ea4f246e5a411727221fcf70f240e Author: John Wolfe Date: Wed Oct 12 12:40:37 2022 -0700 Common header file change not applicable to open-vm-tools. commit 70a10365ba86e871710551d54e565ba6b8b3f4eb Author: John Wolfe Date: Wed Oct 12 12:40:37 2022 -0700 Common header file change not applicable to open-vm-tools. commit 7645e6cd7e3e8f13a862ce3489ea04bad3a26bf2 Author: John Wolfe Date: Wed Oct 12 12:40:37 2022 -0700 Update the guestOps to handle some edge cases. When File_GetSize() fails or returns a -1 indicating the user does not have access permissions: 1) Skip the file in the output of the ListFiles() request. 2) Fail an InitiateFileTransferFromGuest operation. Properly handle the hostd request offset value returned in a ListFiles() guest operation when the results are truncated. commit 2f759e610c5ceabe420df9f678d23474dd423df4 Author: John Wolfe Date: Wed Oct 12 12:40:37 2022 -0700 Move deployPkgFormat.h to lib/include/deployPkg. commit 90445a78a9d34da3b651fcc9ca7e967d8c397fda Author: John Wolfe Date: Wed Oct 12 12:40:37 2022 -0700 Changes to common header files not applicable to open-vm-tools. commit 7ac0e26580dcc2e2e1311ab16fb937da2a2e4e72 Author: John Wolfe Date: Wed Oct 12 12:40:36 2022 -0700 Inclusive terminology - "rule of thumb" Update bora/lib/public/fileIO.h to use "general rule" instead of "rule of thumb". commit 521eecf6eb591c7ef6106f9f44eee728c14a5795 Author: John Wolfe Date: Wed Oct 12 12:40:36 2022 -0700 Common header file change not applicable to open-vm-tools. commit 83e3f82592ae15cc2d213591693d5684a8c88b5f Author: John Wolfe Date: Wed Oct 12 12:40:36 2022 -0700 Common header file change not applicable to open-vm-tools. commit 2a7556c850fae76f830a1805f4dfbdf9f49e3899 Author: John Wolfe Date: Wed Sep 21 11:18:00 2022 -0700 Update ChangeLog with the granular push of Sep 21, 2022. - plus ChangeLog update of Sep 13, 2022. commit ce6d6d1abd652c766de597120b5a19c65a9a2f3f Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Common header file change not applicable to open-vm-tools. commit c0002b9761a0fc18e363d1e414f9330d1acab950 Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Add an example of a new deployPkg/wait-cloudinit-timeout setting to tools.conf. commit e210b4f0b28f7411ea2e45d4304725d0679481d2 Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Inclusive terminology - "suffer" Update bora/public/backdoor_def.h to not use "suffer". commit 045cc568c053096ca2d5e142787ab039c03ba654 Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 1d13616f84f10e836cb589a1bab62d8ae3331c7d Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 7d4360383274807b488fcdf16ca6844ad27891a8 Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 7ec8864176d51356ea5bdb6713496d1770aff2ba Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Common header file change not applicable to open-vm-tools. commit e49ffc8d24257a4c1568e3a36d1f001a16b9d4cc Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Change to common header file not applicable to open-vm-tools. commit e873df9b63d4b16239f15dd0a4abfc7c1375e936 Author: John Wolfe Date: Wed Sep 21 10:53:28 2022 -0700 Change to common source file not applicable to open-vm-tools. commit b5329468f4c2115d57ccfff54d0b4e9c703df33e Author: John Wolfe Date: Tue Sep 13 11:04:06 2022 -0700 Update ChangeLog with the granular push of Sep 13, 2022. - plus ChangeLog update of Sep 8, 2022. commit ab5b5fa4453fd1e1998d8571cab30b2b590053ba Author: John Wolfe Date: Tue Sep 13 10:54:06 2022 -0700 Add missed 2022 copyright. commit 7de3c1c208596a6dfaa967d9bb3b58d7f77c8671 Author: John Wolfe Date: Tue Sep 13 10:31:15 2022 -0700 Record the usage of open-vm-tools version 12.1.5. Update bora/public/vm_tools_version.h with an entry that associates version 12.1.5 with the tag TOOLS_VERSION_MITER_SAW_UPDATE1. commit abd63f3785f8e4ec5384f55021b070be22c7cf8f Author: John Wolfe Date: Tue Sep 13 10:31:15 2022 -0700 Add a null undo function to the vmbackup null provider. If a snapshot operation times out, vmbackup can attempt to undo quiescing. Since no quiescing is done for the null backup provider, no undo function was provided. If vmbackup attempts to call the undo function, it dereferences a garbage pointer resulting in a segfault. Rather than add null backup provider specific checks to vmbackup, this change adds a null undo function to provide vmbackup with a valid function pointer it can call. The new undo function updates the vmbackup state machine state with a new currentOpName, but has no other effect. currentOpName is set to the calling function name, e.g. __FUNCTION__. commit 42437c1131ee990737986d3fd5248bd17ec3e5ff Author: John Wolfe Date: Tue Sep 13 10:31:15 2022 -0700 Change to common header file not applicable to open-vm-tools. commit f1e30c3cb3b698a91de4966206350df2e08be128 Author: John Wolfe Date: Tue Sep 13 10:31:15 2022 -0700 Changes to common source files not applicable to open-vm-tools. commit 484ab8d8443ac6dd42f2ba7aabae4a7b44eda2e3 Author: John Wolfe Date: Tue Sep 13 10:31:15 2022 -0700 Common header file change not applicable to open-vm-tools. commit 8b98bd41def988342c16a870a4e7e880885dc81d Author: John Wolfe Date: Tue Sep 13 10:31:15 2022 -0700 Common header file change not applicable to open-vm-tools. commit 6d0cf2442fb9ec26be9528952e871c35019a1854 Author: John Wolfe Date: Tue Sep 13 10:31:15 2022 -0700 Common header file change not applicable to open-vm-tools. commit 064033a0ea74599d93f2a9988e0331efbe8f981f Author: John Wolfe Date: Tue Sep 13 10:31:14 2022 -0700 [deployPkg] Increase the maximum timeout for cloud-init execution to complete. commit f3979ace5779c481073004968d6d9787d24c1096 Author: John Wolfe Date: Tue Sep 13 10:31:14 2022 -0700 Record the use of VMware Tools version 10.3.26 in vm_tools_version.h Tracking the use of 10.3.26 for TOOLS_VERSION_JACKHAMMER_PATCH13. commit 22f7f76e19c906890f5cd35bde1a43ae90e77f79 Author: John Wolfe Date: Tue Sep 13 10:31:14 2022 -0700 Make Linux perl based customization work with the cloud-init workflow. To resolve issues seen where users want to set a vm's networking and apply cloud-init userdata together before the vm is booted, the deployPkg plugin has been modified to wait for cloud-init execution to finish. This allows cloud-init to finish execution completely before the customization process triggers a reboot of the guest. This change is solely in the deployPkg plugin side, so a user can get this change by upgrading their open-vm-tools in the guest/template. commit 15e8c9828bcef3eb41e7655b0f18c575dc495b25 Author: John Wolfe Date: Tue Sep 13 10:31:14 2022 -0700 Common header file change not applicable to open-vm-tools. commit a2cb7be60dbaa2b632872b37e187570a92fe6b2a Author: John Wolfe Date: Tue Sep 13 10:31:14 2022 -0700 Common header file change not applicable to open-vm-tools. commit 1dbbb6e91e5388a88fe063d61d0cbb9602fb75a1 Author: John Wolfe Date: Tue Sep 13 10:31:14 2022 -0700 Address Coverity issues. base64.c - buffer overrun (out); false positive hashTable.c - expression always false; false positive commit 587be32ec29a3665e30f7509d3d3c8f8ada505e7 Author: John Wolfe Date: Thu Sep 8 14:57:36 2022 -0700 Update ChangeLog with the granular push of Sep 8, 2022. - plus ChangeLog update of Aug 21, 2022. commit 29b92ada5842c2b9d1cde7dbc9dafb69d6a18b96 Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 Change to common source file not applicable to open-vm-tools. commit 775671dc79aa47d82df2ad43e63e18d215625510 Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 Common header file change not applicable to open-vm-tools. commit 95b78cf63ea7dc37b6d9bd5b0f37cd074359ed0f Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 Changes to common header files not applicable to open-vm-tools. commit 8fa7eef2d27971753d9d6d1dd4fd5bd1a7a3dd17 Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 [dnd] Coverity Fixes dndCommon.c - truncating time value; false positive commit 900e24d53bca579d8ad6b12687daf670fb7fe5a6 Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 [asyncsocket] Coverity Fixes asyncsocket.c - dereferencing null pointer (asock); false positive. commit 8aa0bc98bf2986b47800dd7eaf544e7e800a075e Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 Change to common header file not applicable to open-vm-tools. commit d3a4f33d29db6050ca84f504c9d3a557484e4a7d Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 Common header file change not applicable to open-vm=tools. commit bdca47456a592040474b21ad0db40f820dcc87f9 Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 Common header file change not applicable to open-vm-tools. commit 2875dd33aa494879103b9bf6a635781a99c1292a Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 lib/rpcin/rpcin.c: Address issues reported by Coverity. commit bbf4831bcfdb90428dae3aeee2304e5e16f7c7a9 Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 Change to common source file not applicable to open-vm-tools. commit d379cf84e479c11f4c3b470130a27f22005ab56d Author: John Wolfe Date: Thu Sep 8 14:51:40 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 8a8bcb4ad1773fd62ad5a8bee352bf6ed34946a6 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Move HostinfoProcessQuery() from hostinfo.c into hostinfoPosix.c. commit c6de70b61177943130040563243ba6f671a0556e Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 L10n drop for open-vm-tools 12.1.0. commit b6c4eca1f575a6f116a3ce9e1bbb6e99dd134d33 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Common header file change not applicable to open-vm-tools. commit 53f331ccbbbc57eeaf4dfc51c94ec6f3e9a31a65 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Common header file change not applicable to open-vm-tools. commit 662eb2af666ca75532777ac28a11e29df1a6b413 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 lib/file: Speed up FileSimpleRandom. Also remove potential lock rank violations. commit db405bfe35567f1cafaff49c623d1f5568baea58 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Bump the open-vm-tools version to 12.2.0 in the "devel" branch. Setting the development open-vm-tools version to 12.2.0. Adding the tag name "MITER_SAW_RELEASE" to tools version 12.1.0 commit 366096f02bbaa95e057ed89a5de5c05a1168d23c Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Record the use of VMware Tools version 12.0.6 for an express patch. Adding the use of version 12.0.6 to lib/include/vm_tools_version.h. commit 948eb98761b2662bceda35791a3be420391ebec3 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Common header file change not applicable to open-vm-tools. commit 7066a131959f212a71e678f7538159b5f421ffc1 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Common header file change not applicable to open-vm-tools. commit a2299e2022718f7fd833714a2252252c07249745 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 lib/file: Clarify why File_GetSize opens and closes the file. Spell out what's going on. commit d1f0cb0906d3a479fd3a3320ea202d96134fb16d Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Common header file change not applicable to open-vm-tools. commit 3f426fb27d85e71e10bb3264f622fdca0d1f8cd7 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Common header file change not applicable to open-vm-tools. commit 7991ed9acfe0917bc8642a48e7db82db5c779277 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Changes to common header files not applicable to open-vm-tools. commit 365db99d442774c49234ae157fc4373d0bb6c4f8 Author: John Wolfe Date: Thu Sep 8 14:51:39 2022 -0700 Common source file changes not applicable to open-vm-tools. commit 732bb7a3287ebdb2be079f364da4b0ea6a4c08bd Author: John Wolfe Date: Sun Aug 21 12:42:12 2022 -0700 ChangeLog update of Aug. 21, 2020 commit 7fa57304ab41a26f1de972f4a024e7da3632df69 Author: John Wolfe Date: Sun Aug 21 09:37:23 2022 -0700 ==================================================================== The "stable-12.1.x" branch was created from the "devel" branch here. ==================================================================== Update ChangeLog with the granular push of Aug. 21, 2022. - plus ChangeLog update of July 29, 2022. commit 70a74758bfe0042c27f15ce590fb21a2bc54d745 Author: John Wolfe Date: Sun Aug 21 07:56:49 2022 -0700 Properly check authorization on incoming guestOps requests. Fix public pipe request checks. Only a SessionRequest type should be accepted on the public pipe. commit 08cac55b2a37fac30adfb090748ca2b96c3256db Author: John Wolfe Date: Sun Aug 21 07:56:49 2022 -0700 Common header file change not applicable to open-vm-tools. commit a4f13c6a3427a2a9366945c817222c12c957f5af Author: John Wolfe Date: Sun Aug 21 07:56:49 2022 -0700 Address issues reported by Coverity. commit d2b1bb8fd315124de4cdcceb5b82b2e5b2882f30 Author: John Wolfe Date: Sun Aug 21 07:56:49 2022 -0700 Common header file change not applicable to open-vm-tools. commit 581091addcbb6484047587f6d12038a04f2cc14a Author: John Wolfe Date: Sun Aug 21 07:56:49 2022 -0700 Changes to common header files not directly applicable to open-vm-tools. ARM: native atomics commit 37aefc9db67398e04f4bd9017af69edd16670080 Author: John Wolfe Date: Sun Aug 21 07:56:49 2022 -0700 Common header file change not applicable to open-vm-tools. commit ff29587e22711489207d020794b8f588058dfe52 Author: John Wolfe Date: Fri Jul 29 15:50:29 2022 -0700 Update ChangeLog with the granular push of July 28 & 29, 2022. - plus ChangeLog update of July 12, 2022. commit d5b73e64a5857d40905acee1242edaaac7ce9494 Author: John Wolfe Date: Fri Jul 29 11:11:04 2022 -0700 Correct missed 2022 copyright update. commit 1bd202e0a819c520896c743b51f2c1365f7ae2b2 Author: John Wolfe Date: Thu Jul 28 20:03:43 2022 -0700 Common header file change not applicable to open-vm-tools. commit 306498ca0676354eb541b5817426191e615d0ef2 Author: John Wolfe Date: Thu Jul 28 20:03:43 2022 -0700 Common header file change not applicable to open-vm-tools. commit b3f0be90d03a5da6d3bb695e9e1dd44f071814aa Author: John Wolfe Date: Thu Jul 28 20:03:43 2022 -0700 Common header file change not applicable to open-vm-tools. commit 5887bf59e95cba480568ad731f7b037894058fef Author: John Wolfe Date: Thu Jul 28 20:03:43 2022 -0700 Common header file change not applicable to open-vm-tools. commit 9982eee37884c819759aadcec987324d9fe5b41e Author: John Wolfe Date: Thu Jul 28 20:03:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit b5997ab6ecdbc6981a8a35b2349b3bd98c746a19 Author: John Wolfe Date: Thu Jul 28 20:03:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit 24594a971f9807fbee2253ee7680846de6cd9a63 Author: John Wolfe Date: Thu Jul 28 20:03:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit bc9ab15472ed53a3071902ca5ec41d60e2f00d88 Author: John Wolfe Date: Thu Jul 28 20:03:42 2022 -0700 lib/misc/hostinfoPosix.c: iopl(3) is not avaiable on ARM. commit 6907610abb95f96c3e8a10389483bfe54efd3eee Author: John Wolfe Date: Thu Jul 28 20:03:42 2022 -0700 Changes to common source files not directly applicable to open-vm-tools. commit b76e3218ddb24e49a87ef35913f9bf1389166033 Author: John Wolfe Date: Thu Jul 28 20:03:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit 155a8d440df8ae889d93c9aaee9d15bec9d7640d Author: John Wolfe Date: Thu Jul 28 20:03:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit 7452011db95a49aaaa19c293fb1ff1ea0944d6db Author: John Wolfe Date: Thu Jul 28 20:03:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit 386e493c3cd58723d183ecbd3f0594706778e423 Author: John Wolfe Date: Tue Jul 12 10:49:28 2022 -0700 Update ChangeLog with the granular push of July 12, 2022. - plus ChangeLog update of June 7, 2022. commit eb48b7972c0c64735cb6fe7ca7ac3f505b80c7d4 Author: John Wolfe Date: Tue Jul 12 10:25:28 2022 -0700 Correct missed 2022 copyright update. commit ddfb569588d8b1a9cd31cb3bb5d33c58c72f7fbc Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Fix a bug in CodeSet_JsonEscape. Fix a bug introduced in an earlier change in which CodeSet_JsonEscape erroneously tests the first character in the buffer when checking whether to escape the character currently being processed. commit a816c2e149010bdca27a47006932aa10b686a895 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common header file change not applicable to open-vm-tools. commit 6aa2e661a35b88f0f69e744b4918340437cd6485 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Fix a grammar error of c++11 scoped enumeration "enum class". commit e5e9a9ba31791d4f10e7dd75a8dbab179926511f Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Escape all control characters in JSON. Update CodeSet_JsonEscape to escape all control characters between U+0000 and U+001F as required by the JSON standard. Delete CodeSet_Utf8Escape as it is no longer used. Also update datasets in-guest API tests accordingly. commit 47f47851a026cce6ee9738015759b45cf6931cc2 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common header file change not applicable to open-vm-tools. commit bb2f24ed14f8d5102df6387253ba4ac4271bf4f5 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Changes to common source files not applicable to open-vm-tools. commit f45b8f435f2d9b3536f283098ddaf69218ae7456 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Add a comment with the bump of the Guest Msg Channels to 128. commit f272162cad49f13dc2d86eafb9aec7f0c2c7c8b4 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common header file change not applicable to open-vm-tools. commit 523df70f7f1b0ef760fe753404a0682b79b095b8 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Bump up the Guest Msg Channels to 128. commit 9e371bd289f53585e67853a97328906c196af818 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common header file change not applicable to open-vm-tools. commit d5b28c0380fb6687fd106e6ebd65570473940878 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common header file change not applicable to open-vm-tools. commit 42c136b5a3cddb077b5c39d933141e30d4c2c129 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common header file change not applicable to open-vm-tools. commit 091d43b06052d742e321d3f61c8620284d56b959 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common header file change not applicable to open-vm-tools. commit df0099727e96292279398c3fbd7f3901f215e4f3 Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common source file changes not directly applicable to open-vm-tools. commit 5317dfb778ee97c6fe83fbf23ee2e800fb608eaa Author: John Wolfe Date: Tue Jul 12 09:56:01 2022 -0700 Common header file change not applicable to open-vm-tools. commit 575f1ec1bee338c1a0ac6f14072429f926cf2f52 Author: John Wolfe Date: Tue Jun 7 10:07:23 2022 -0700 Update ChangeLog with the granular push of June 7, 2022. - plus the sync of the README.md with the stable-12.0.x branch. - plus ChangeLog update of May 17, 2022. commit 95956d193464f2aa0547e6dbd4f51bc2052d5f82 Author: John Wolfe Date: Tue Jun 7 09:52:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit dd2f50d4cc956d5d45638d31f68c449ba8afbca4 Author: John Wolfe Date: Tue Jun 7 09:52:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit 9a38d3f49bad645826aad7f0cb778098ba6ca381 Author: John Wolfe Date: Tue Jun 7 09:52:42 2022 -0700 Common header file change not directly applicable to open-vm-tools. commit 0f78b84aeedab75e3614bfdda9fe5fd86268686e Author: John Wolfe Date: Tue Jun 7 09:52:42 2022 -0700 Log Facility: Improve wording of group level messages and filtering. Common header file change not directly applicable to open-vm-tools. commit 41509dbb7223fa7e8905718c357fbd6f243f06e3 Author: John Wolfe Date: Tue Jun 7 09:52:42 2022 -0700 Report consistent customization error status when custom script is disabled. commit f83c890a91e29febbe54a7be0ffe96c1e14f8057 Author: John Wolfe Date: Tue Jun 7 09:52:42 2022 -0700 Guest OS: Prepare for Linux 6 The basics are already there, update guest identification. commit 0b6597b97ce0d1607cb0602731b9c2d4ca0c5162 Author: John Wolfe Date: Tue Jun 7 09:52:42 2022 -0700 Common header file change not applicable to open-vm-tools. commit 9945bb6cc3aa6d811ef46d9ddf2c2ae462baa38d Author: John Wolfe Date: Tue Jun 7 09:52:41 2022 -0700 Common header file change not applicable to open-vm-tools at this time. commit d669d0263887a3da2242d55bae7eab224981e075 Author: John Wolfe Date: Tue Jun 7 09:52:41 2022 -0700 Common header file change not applicable to open-vm-tools. commit 7fa64a4e23e65224b1752e5037854fd6f9ea43cb Author: John Wolfe Date: Tue Jun 7 09:52:41 2022 -0700 Common header file change not applicable to open-vm-tools. commit cff50b62e0db5f5978c14bb09b0e2fe7c1c89fc3 Author: John Wolfe Date: Tue Jun 7 09:52:41 2022 -0700 Log Facility: Enhance logging for grouped (named) log message. Common header file change not directly applicable to open-vm-tools. commit 939545b3e0445858cf7be038c978e7df2d8547ff Author: John Wolfe Date: Wed May 25 05:55:52 2022 -0700 Sync the README.md file with the version released with 12.0.5. commit 4c620fd78b6281ca8a045f3dffdf2180dd9c480f Author: John Wolfe Date: Tue May 17 18:47:08 2022 -0700 Update ChangeLog with the granular push of May 17, 2022. - plus ChangeLog update of May 6, 2022. commit 29ba7eb2a1e6c62357ad46bc67daff94b0fc0dc4 Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 Salt-minion plugin update: The Salt Minion installer script svtminion.sh has been updated. - version 1.3 - configurable download source - requires the "wget" command commit e1a6796a1aecd22a7b76f5b4871d215b82277f18 Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 Changes to common header files not applicable to open-vm-tools. commit b42ed315b7844660e9f9546c7bd85e1804938526 Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 Common header file change not applicable to open-vm-tools. commit 074cd660a718e817e7db0df57f71252107d23490 Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 Common header file change not applicable to open-vm-tools. commit ce9459965a1900159b5f563c030385e554ba3e49 Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 Common header file change not applicable to open-vm-tools. commit bac24ee80957feea0336f7ac597630aedf13ec86 Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 784c520757e883c5e46e1d3a593e24d171cd280e Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 Common header file change not applicable to open-vm-toole. commit 32db37a3cf437578efcb64d954aae9d5cca1ff83 Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 Common header file change not applicable to open-vm-tools. commit 619f656f4444af598179345f8c35e056e3563de1 Author: John Wolfe Date: Tue May 17 18:36:21 2022 -0700 vm-support: Capture the locale configuration of the Linux guest. To aid in debugging issues related to locale configuration, the vm-support command has been updated to collect the following: - The contents of the /etc/default/locale file if it exists. - The contents of the /etc/locale.conf file if it exists. - The output of the 'locale' command for the current environment. - The output of the 'locale -a' command for a list of available locales. commit 0c675d3d53f9e859eaa396cabfbf68c85a9f5f72 Author: John Wolfe Date: Tue May 17 12:57:40 2022 -0700 Sync the README.md file with the version last released in the stable-12.0.x and master branches. commit e7d6abcbd3134e01cd5a8602fe4edd01b9e60aec Author: John Wolfe Date: Fri May 6 14:40:22 2022 -0700 Update ChangeLog with the granular push of May 6, 2022. - plus ChangeLog update of Apr. 19, 2022. commit 605c30a33f6dedc07ded8e24ce1491fba162ce82 Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Fix a compilation issue in the containerInfo plugin for i386 builds. The "gint64" type used for time values in the code is not a "long" on i386. The fix using the glib "G_GINT64_FORMAT" macro was provided by the Debian OVT maintainer. github PR: https://github.com/vmware/open-vm-tools/pull/588 commit be5c99cbb69afc1586315195f40d0e31d4f742b1 Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Change to common header file not applicable to open-vm-tools. commit cf19772adf10706fa1da83aca21a9fc45977c387 Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Change to common header file not applicable to open-vm-tools. commit fde902600d26f8b38f13a7c535d094963f989697 Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 0073b6ae4aed8466a2e657fe853cd993a60abd1b Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Changes to common source files not applicable to open-vm-tools. commit f9da69911d845d36515f8c45f6d5840f934a1189 Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Change to common header file not applicable to open-vm-tools. commit c613b3d554c49fe8bdc6103d90aa028e7bee854e Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 9b9f221c486069d90ed6460edab72cb545ca0361 Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 82e373eb02505791f34b0154a8c2762040034fd8 Author: John Wolfe Date: Fri May 6 14:28:00 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 6df59bd95ec5a1a23be67483ef6a4c34cf849506 Author: John Wolfe Date: Fri May 6 14:27:59 2022 -0700 Change to common header file not applicable to open-vm-tools. commit 875d19750952f575f6f41b6ce4631ecdbe74b90a Author: John Wolfe Date: Fri May 6 14:27:59 2022 -0700 Service Discovery: Cassandra service version missed for a default Cassandra installation. Updated the get-versions.sh script to correctly report the version of the Cassandra service running in the guest. commit 6452e34357b1dc258a038ea5137fd27d13f9f4ca Author: John Wolfe Date: Tue Apr 19 14:48:06 2022 -0700 Update ChangeLog with the granular push of Mar. 23, 2022. - plus ChangeLog update of Apr. 4, 2022. commit f1e56311c8f245d6aba2a94d37e5df7220398ed5 Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Common header file change not applicable to open-vm-tools. commit 911b68fef82a3dfb083daa3bf0f61ed793e2961e Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Common header file change not directly applicable to open-vm-tools. commit c8f345b0cc50417665b0eff6bf19f0af2526ff74 Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Common header file change not applicable to open-vm-tools. commit b3c2a0e00e3d40e979dacab1833a6711e0e5620a Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Common header file change not applicable to open-vm-tools. commit 19e2a77e0a2b29b77866876a5d45ec2df8f96d4f Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Changes to common header files not applicable to open-vm-tools. commit 93af2bbbe583e95598cfb46d042ac6025a6dcac8 Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Improve the "don't touch this" comments for Linux guest identification. Pull requests to add distro identification information are often submitted. Open-vm-tools does not own the guest identification code. Such a change requires coordinated changes throughout the VMware product stack. Improve the text to reduce pull requests for changes to common source code that open-vm-tools does not own and cannot make. commit 36eea633611e678f3ea17a913c0990f319135c48 Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Make HgfsConvertFromNtTimeNsec aware of 64-bit time_t on i386. The change incorporates the support of 64 bit time epoch conversion from Windows NT time to Unix Epoch time on i386. Addresses pull request: https://github.com/vmware/open-vm-tools/pull/387 commit 472335e347018fbddfbbe45618193075e77fa836 Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Common header file change not applicable to open-vm-tools. commit bb8a37981bfb76d9314d797c3ab1b394ce431d1d Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Changes to common header files not applicable to open-vm-tools. commit fb011741deec7e277f34974e32f88c60826e0db3 Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Common header file change not applicable to open-vm-tools. commit d232afd908f22104a632e3060c9bf4170ac18018 Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Common header file change not applicable to open-vm-tools. commit 1b4db25a65153bd2c1c5a725303bf22a61ac931f Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Added the following miscellaneous checks for the deploypkg plugin. 1. Check if the plugin is running in a VMware VM. 2. Check if the plugin is loaded by the main tools service. 3. Check if the underlying hypervisor is ESXi. commit df63c64bf5e12a5f5bc0ba9bda4b786a4295ae5b Author: John Wolfe Date: Tue Apr 19 14:30:54 2022 -0700 Inclusive language - "kill" Address uses of the term "kill" in some files used by open-vm-tools. commit e057e41fc4d4e4e084cf46c9d16243fb05a7df19 Author: John Wolfe Date: Tue Apr 19 14:30:53 2022 -0700 Inclusive Language - "whitelist" Use allowlist instead of whitelist in some files used by open-vm-tools. commit 532cf9f3bb9dd3011239fb193f7458fc78ae921e Author: John Wolfe Date: Tue Apr 19 14:30:53 2022 -0700 ContainerInfo Plugin: correct compiler warnings in containerInfo_grpc.cc - The local variable "containersAdded" should be an 'unsigned int' since it's compared with an 'unsigned int' parameter. - Remove the unreferenced local variable "numContainers". commit 92a6422d03a932ab92f4b7c791673cf2f17bf3b9 Author: John Wolfe Date: Tue Apr 19 14:29:06 2022 -0700 Reverting previous bad patch erroneously comitted. commit 36b7f58392fbbb9e7bb336c0cf07202cba4d92cc Author: John Wolfe Date: Mon Apr 4 13:22:16 2022 -0700 Update ChangeLog with the granular push of Apr. 4, 2022. - plus ChangeLog update of Mar. 23, 2022. commit 37f5400a44d1fbe4fdeef0fe048e8903af9f1907 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 Common header file change not applicable to open-vm-tools. commit 8665272146a9302faf16c98992f57d5cce6530bc Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 Common header file change not directly related to open-vm-tools. commit 66644fb9b74bcad603a2e175e99be80b756bd6c8 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 VGAuth: Add secure VMX RPC support. - Added some error handling to work around VMX closing a port that is being reused. commit eef3be312ad6f7ed5d96cafa15ffafc89bc43851 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 VGAuth: Update some error messages with certificate error text. commit b53ae31eaa20ec80f2d97f85ac6b9a295e21c287 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 Common header file change not applicable to open-vm-tools. commit bd8be34a9a4e897d78297eb8ae970300e80253a0 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 DynBuf: Implement new function DynBuf_SafeInternalInsert(). commit d59878b05d57393770f1cf064141a17c9a8af3f4 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 DynBuf: Implement new function DynBuf_Insert. - DynBuf_Insert(): Insert data at a given offset within a dynamic buffer. commit 70509b63b728b65adfeb62afa40488782cc7f5f1 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 Record use of tools version 10.3.25. Adding version 10.3.25 to the list of releases or planned releases of VMware Tools. commit 33b7eb9f3f3b8d58025f484a9c5fd30293f60622 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 Common header file change not applicable to open-vm-tools. commit e7b3c7180fdf8f62b9852af90cdad725e69480da Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 Common header file change not applicable to open-vm-tools. commit 936537f6234690f8ae1afba3ae8b0a6a89df6625 Author: John Wolfe Date: Mon Apr 4 12:58:41 2022 -0700 Generalize VMX RPC code in vgauthservice. - Rework the code so that it can used for other RPCs in the future. - Rework the code reading the RPC reply, since it can now be much larger. - Also remove the attempt to use the "guest.log.text" RPC since the VMX will just drop the logging on the floor with no error if the virtual HW version is too old. A smart fail over is not possible. commit 2fe3cccfc1c36e946f46fb57813dd50c6c7f89dd Author: John Wolfe Date: Wed Mar 23 13:00:26 2022 -0700 Update ChangeLog with the granular push of Mar. 23, 2022. - plus ChangeLog update of Mar. 10, 2022. commit 405c57fbcfe8772679fdaf594b368f5a68b31edf Author: John Wolfe Date: Wed Mar 23 12:04:31 2022 -0700 Common header file change not applicable to open-vm-tools. commit b167d985e0632d6455334e09437905ab54fa1a60 Author: John Wolfe Date: Wed Mar 23 12:04:31 2022 -0700 Record the use of tools version 12.0.5. commit 577764a4adf5e6ff595e23fe54c30ccdce353977 Author: John Wolfe Date: Wed Mar 23 12:04:31 2022 -0700 Change to common header files not applicable to open-vm-tools. commit f0cb3eebe942fba3f5abca32303998985a756b90 Author: John Wolfe Date: Wed Mar 23 12:04:31 2022 -0700 Common header file change not applicable to open-vm-tools. commit b571bf4026b6f2dee31102a55dd7338c276646f9 Author: John Wolfe Date: Wed Mar 23 12:04:31 2022 -0700 VGAuth: Customize libxml2 to open local file with unescaped file name only. commit c0408788b07ec42f8c1bcf3e7373032d8b9784b3 Author: John Wolfe Date: Thu Mar 10 12:06:56 2022 -0800 Update ChangeLog with the granular push of Mar. 10, 2022. - plus README.md updates related to 12.0.0 OVT release. - plus ChangeLog update of Feb. 17, 2022. commit b47748c330f1fa495f099db0d6fcc300f9e82240 Author: John Wolfe Date: Thu Mar 10 11:36:24 2022 -0800 Common header file change not applicable to open-vm-tools. commit 6e16f34ac546f5cdf156cc484b29823b84603f76 Author: John Wolfe Date: Thu Mar 10 11:36:24 2022 -0800 Changes to common header files not directly related to open-vm-tools. commit e57a78d2fa4afe47b1a5d2d12d4e0a4a71db1073 Author: John Wolfe Date: Thu Mar 10 11:36:24 2022 -0800 Service Discovery: Script correction to collect the version of Cassandra. commit dfff48a686515a5046d8e33b8181f34f79fe6fa6 Author: John Wolfe Date: Thu Mar 10 11:36:23 2022 -0800 Common header file change not applicable to open-vm-tools. commit 092cc7135b6d0f5fc4dbbf8b14a3093dbee402d8 Author: John Wolfe Date: Thu Mar 10 11:36:23 2022 -0800 Common header file change not applicable to open-vm-tools. commit 68391545c1c7ac7804429f7dc73a158d74690b82 Author: John Wolfe Date: Thu Mar 10 11:36:23 2022 -0800 Common header file change not applicable to open-vm-tools. commit 69ce810007b0390a369425bc3561ab7befdb040c Author: John Wolfe Date: Thu Mar 10 11:36:23 2022 -0800 Common header file change not applicable to open-vm-tools. commit 97440ff3bc72428be0158cada3afc2513ead463a Author: John Wolfe Date: Wed Mar 2 16:49:49 2022 -0800 Update the README.md document. - Adding configure and build information for new plugins and service(s) added in the 12.0.0 tools release. commit 09ea13cfb0947137dd31cd1f278739e49aff95fc Author: John Wolfe Date: Tue Feb 22 16:52:02 2022 -0800 Update the list of operating system with open-vm-tools. Add: * Flatcar Container Linux, all releases * Rocky 8 and later releases * AlmaLinux OS 8 and later releases Addresses: https://github.com/vmware/open-vm-tools/pull/573 https://github.com/vmware/open-vm-tools/pull/513 commit 43d17bd3f2e93566ee7b588494d29ab857c7a95f Author: John Wolfe Date: Thu Feb 17 15:10:47 2022 -0800 Update ChangeLog with the granular push of Feb. 17, 2022. - plus ChangeLog update of Feb. 7, 2022. commit 2cf575e2fb0a6c83211e8e09339491889bdcc8fe Author: John Wolfe Date: Thu Feb 17 15:01:31 2022 -0800 Add missing 2022 copyright. commit 66b79830eccb5fd8c7b85f07b8090c763e12783c Author: John Wolfe Date: Thu Feb 17 14:51:25 2022 -0800 Common header file change not applicable to open-vm-tools. commit 27bd6b5a84370ad488227614df3740ad6c2014db Author: John Wolfe Date: Thu Feb 17 14:51:25 2022 -0800 Common header file change not applicable to open-vm-tools. commit bb597ad25dbf695b5d16ddea3c09080d1a715967 Author: John Wolfe Date: Thu Feb 17 14:51:25 2022 -0800 Backout previous changes to common header files not applicable to open-vm-tools. commit 92254389f42b0a09ea140427afb4d0352a56cb4b Author: John Wolfe Date: Thu Feb 17 14:51:25 2022 -0800 Adding configuration information for the GlobalConf feature. As part of the GlobalConf feature, a "globalconf" section is introduced into tools.conf to provide custom configuration options for the feature. The configuration parameters are as follows: * enabled=false - Enable/disable the GlobalConf module. * poll-interval=3600 - Poll interval for the GlobalConf feature. * resource= - Defines the location of the tools.conf in the GuestStore. There is a separate default for Windows and Linux guests. commit 1b5114ab87e342af85eb340237ba2d747b49fdad Author: John Wolfe Date: Thu Feb 17 14:51:25 2022 -0800 Common header file change not applicable to open-vm-tools. commit f35987b39f2874f13b2f4facd1b1d3dde7ae2a63 Author: John Wolfe Date: Thu Feb 17 14:51:25 2022 -0800 Common header file change not applicable to open-vm-tools. commit de6d129476724668b8903e2a87654f50ba21b1b2 Author: John Wolfe Date: Thu Feb 17 14:51:25 2022 -0800 asyncsocket.c: Use size_t in place of int type for array size and indexing. Glibc 2.35 with GCC 11 and 12 produces additional warnings about strings and array bounds. Switching from "int" to "size_t" type for variable used for the array size and element indexing. GCC warned when an integer value is passed as the size of the struct pollfd array to poll(). Fixes https://github.com/vmware/open-vm-tools/issues/570 commit 956fd221b6697242405bc3c1f8fe5c18236a9b68 Author: John Wolfe Date: Thu Feb 17 14:51:25 2022 -0800 Changes to common header files not applicable to open-vm-tools. commit 760d6ca22de590ffcce82c43926d8b91474cf101 Author: John Wolfe Date: Mon Feb 7 10:01:44 2022 -0800 Update ChangeLog with the granular push of Feb. 7, 2022. - plus ChangeLog and late copyright update of Jan. 20, 2022. commit 8406802f4bf9269f02b6850b10741a7fce1635bc Author: John Wolfe Date: Mon Feb 7 09:52:43 2022 -0800 Correct missed 2022 copyright update. commit 4311a4a5d2952703cb808feb1f6372e28c2afc68 Author: John Wolfe Date: Mon Feb 7 09:40:01 2022 -0800 Common header file change not applicable to open-vm-tools. commit e9e485b9d6fd41acb5a777896b7c7efb32632722 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common header file change not applicable to open-vm-tools. commit a085da930a078f956192bb257de251a58e49a5f2 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common header file change not applicable to open-vm-tools. commit 5b0c9eada72482a7149a5188f11d470272e53087 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common header file change not applicable to open-vm-tools. commit 8692a2327c0bcd4608fd40d8f7539da5d82e6b28 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Enable time step correction log in all builds. Enabled logging of the information in all builds of open-vm-tools. This is useful for auditing and for debugging. commit 87389ed6975ed40bdc7883c64c2509da6650a435 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common header file change not applicable to open-vm-tools. commit 05943d86fbc47821c3036eaa3b11b7b7a1eb2780 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common header file change not applicable to open-vm-tools. commit d8ad6f5c0d2237ed6eb3230720be9701547e2ed9 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Service Discovery script update. Updated the get-version.sh script to retrieve the vRLI version. commit a9e72b211bafb19ca0e674bf73351e1aa859d083 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common header file change not applicable to open-vm-tools. commit 5a040d4c25705565e8397b2135506e93e320bd54 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common header file cahnge not applicable to open-vm-tools. commit 627f748ab314c6bd2b6a5023d1f17684bd8eec0d Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common source file change not applicable to open-vm-tools. commit 2290690693f0590bb5ffbd592ebd4b8062d57513 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 AppVisibility: Skip terminated/stopped containers. Added code to skip terminated/stopped containers. This is done by using TaskStub to retrieve the pid for the running container. If the pid cannot be retrieved, then that container is skipped. The previously suppressed "default" namespace has been restored. Fixed another minor issue with calculating the number of containers that were added. Note: This changeset introduces a dependency on Tasks.proto, and Tasks.proto depends on a few other proto files like mount, metrics, descriptor and task. Modified the makefile to generate the necessary C++ files from the proto files. Additional notes: - .proto -> generates .pb.h, .pb.c and .grpc.pb.cc files. - For compiling and building the library (.so file), the .grpc.pb.{h,cc} and .pb.{h,cc} files are needed. - The protoc compiler generates .pb.h and .pb.c files when the --cpp_out option is specified. - The protoc compiler generates .grpc.pb.* when the --grpc_out option is specified. commit 5e79bc1414f31a07a9fb74c624b8b435546e0212 Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common source file change not applicable to open-vm-tools. commit 75f3a3e2e6b4cfec157c02e8f06e5ac139ad98cc Author: John Wolfe Date: Mon Feb 7 09:40:00 2022 -0800 Common header file change not applicable to open-vm-tools. commit 192667e6e65ad7d7592798ef567278dbe15c293d Author: John Wolfe Date: Thu Jan 20 15:01:49 2022 -0800 Last minute 2022 copyright updates to several files. commit 99c00042476803def0d1aea4fc28cd59e271859d Author: John Wolfe Date: Thu Jan 20 11:50:29 2022 -0800 Update ChangeLog with the granular push of Jan. 20, 2022. - plus ChangeLog update of Jan 2, 2022. commit bd0f9506e5ad3ee42c95cbd1aea0c9381e4abf59 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change not applicable to open-vm-tools. commit ddd97d710b1b49a2d8b3679ac07c70feacb2aeb0 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change not applicable to open-vm-tools. commit b4a4387294cc9dc3cb890093398abad4d0800bc2 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change. Prepare to recognize macOS 14, Debian GNU/Linux 12, Rocky Linux, and AlmaLinux. commit cbc229407f734a7b44aeecb9e3a6a51975ace35e Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 open-vm-tools-12.0.0 L10n drop. commit e85e58885523f69b01fc8a49ee40732df6b6e2a6 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 ContainerInfo: Remove 'default' namespace from the default allowed namespace list. commit b9ebabe69f0d864bfaa28bf8773a4c8a51e29416 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Changes to common source files not applicable to open-vm-tools. commit e2de0491601d6c14e5aa4b64467cced413ff28e6 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change not applicable to open-vm-tools. commit 28dd7a83e35173ac7d1869906442ded5d1c632eb Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change not applicable to open-vm-tools. commit 750eed3fc4dc6d0265bc3e28b845e76ca3acf944 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change not applicable to open-vm-tools. commit b59acd69c499825b1e0cc451f3c3798b1bb18d1c Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change not applicable to open-vm-tools. commit 0f084152e3e03d22dcaa5d80118f244dba3f1455 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Set tools builds on the "devel" branch to version 12.1.0. Also, add back the definitions of TOOLS_VERSION_NEXT* inadvertently removed in the previous change to vm_tools_version.h. commit f48b8797c14d43b3786fddae8bd38b890e48cd9d Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change not applicable to open-vm-tools. commit 87396d0925299645ce77491ca8ad30ad1cb01c85 Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Restrict Enable Salt Minion feature to x86_64 systems. Currently Salt Minion is available only for x86_64 systems. Update configure.ac to exclude ENABLE_SALTMINION from ARM and 32-bit systems. commit 9c171d9aede372e9647fe05f09a0e127df6d1dbd Author: John Wolfe Date: Thu Jan 20 11:40:15 2022 -0800 Common header file change not applicable to open-vm-tools. commit bc9832a87009a1d41729ea6d07d1fae960026655 Author: John Wolfe Date: Sun Jan 2 02:20:56 2022 -0800 Update ChangeLog with the granular changes through 12/31/21. - granular push of Jan. 2, 2022 - plus ChangeLog update of Dec. 25. commit 34415b186a26a563690025d50b582cb7a73aef77 Author: John Wolfe Date: Sun Jan 2 02:10:04 2022 -0800 Set SABRE_SAW as the code name for the VMware Tools 12.0.0 release. commit e52bbb643aebf0a414d00c519cbe748a378d1570 Author: John Wolfe Date: Sun Jan 2 02:10:04 2022 -0800 The header added to the vmsvc log file is repeated at log file rotation. The log entry with the tools version, tools build number and guest OS details added at the start of the vmsvc log file is repeated when log file rotation occurs. commit c4220766355a623901f3d562ad03ddd3745729fd Author: John Wolfe Date: Sat Dec 25 10:10:54 2021 -0800 ==================================================================== The "stable-12.0.x" branch was created from the "devel" branch here. ==================================================================== Update ChangeLog with the granular push of Dec. 25, 2021. - plus ChangeLog update of Dec. 21. commit f6d49e0acd81353d8022b639e231bc517a69b166 Author: John Wolfe Date: Sat Dec 25 09:51:13 2021 -0800 Common source file changes not directly applicable to open-vm-tools. commit ff6e8264fedfc3237ab66b91598d998bfa7eae39 Author: John Wolfe Date: Sat Dec 25 09:51:13 2021 -0800 Salt-minion and componentMgr plugin updates. Lastest version of the Salt Minion installer script. The poll-interval of the componentMgr can be set to a minimum value of five (5) seconds when compiled with -DVMX86_DEBUG. commit f0b616649db5cb3c7a5251cd981401bbf74039c7 Author: John Wolfe Date: Sat Dec 25 09:51:13 2021 -0800 Common header file change not applicable to open-vm-tools. commit 3c3cfcc9a9d16e79a9ef886f2831a7be28e9e596 Author: John Wolfe Date: Tue Dec 21 13:19:21 2021 -0800 Update ChangeLog with the granular push of Dec. 21, 2021. - plus ChangeLog update of Dec. 4. commit 7987a3440f0d05b18faa77b9f9f67ae55d8a1cf1 Author: John Wolfe Date: Tue Dec 21 13:07:55 2021 -0800 Update missed 2021 copyright. commit 4c66981405127910285d182930e049c4fb496a7a Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Change to a common header file not applicable to open-vm-tools. commit cc72edfdd60497b86b8e7f20495c85ce414d6106 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Changed the log domain of the containerInfo plugin to containerinfo. This will make both 'config group name' and 'logging domain' name the same. Did some code-reorg. commit 97917fce5828ef0efdae59d7bb6e4dd7f0caeae0 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Update open-vm-tools to build with either Fuse 3 or Fuse 2 Vendors are requesting that open-vm-tools can be built with either Fuse 2 or Fuse 3. While both Fuse 2 and Fuse 3 runtime can be installed on a Linux system, vendors would prefer to switch from Fuse 2 to Fuse 3 at the same time for all products to be available with the base OS. Updating the configure.ac file to check for the presence of the Fuse 3 or Fuse 2 development packages in the build environment. Providing configure options to allow users to control the version of Fuse to be used. --without-fuse - vmblock-fuse and vmhgfs-fuse will be disabled. --with-fuse=fuse3|3 - use Fuse 3.x --with-fuse=fuse|2 - use Fuse 2.x --with-fuse=auto - check for Fuse 3 or Fuse 2 availability; disable vmblock-fuse and vmhgfs-fuse if unavailable. --with-fuse - implicit "yes". --with-fuse=yes - check for Fuse 3 or Fuse 2 availability; disable vmblock-fuse and vmhgfs-fuse if unavailable. Pull request: https://github.com/vmware/open-vm-tools/pull/544 Fixes issue: https://github.com/vmware/open-vm-tools/issues/314 The vmblock-fuse code is also used by WorkStation. Configure defines are not available in internal builds. Reworked preprocessor tests to use FUSE_MAJOR_VERSION from the fuse headers to determine API to be used during compilation. commit d0571b23fe1513c0ec83e8b57bd8e91edd5b86a3 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Changes to common source files not applicable to open-vm-tools. commit 7776c845db0bc24c5103d80a8d8f76d73f79ec39 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Change to a common header file not applicable to open-vm-tools. commit ec4040bfc25818e5979f8c681f13b4c0e3d9c38a Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Changes to a common source file not applicable to open-vm-tools. commit 3695f042018aedbca6d37751d3d1577bf1887aa1 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Common source file change not applicable to open-vm-tools. commit 7cb1006b6f362a1e19b6dbaea5ae30bd727d4f5b Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Fix potential integer overflow when calling g_timeout_source_new() or g_timeout_source_new_seconds(). commit c69332a9252413b265b4a146c072bcae8b16a3d3 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Common header file change not applicable to open-vm-tools. commit 1c916a09107b2b6c901488587711db569ade9223 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Changes to common header files not applicable to open-vm-tools. commit 8296854e348014441368af01edc41c728b80de86 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Clean up of guest OS tables. Use official defines for Arm and guestOS strings. commit d5a3e4b02c5515cde9f10e351b67dade9c073d6e Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Remove the collection of GRUB files from the vm-support script GRUB configuration files have not been needed in the past. Therefore, as part of this change, removing the code from vm-support script which collects any grub configuration files. commit 63abb4f4b0fe73205888bedca91385faf3f53bf7 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Adding Alma Linux and Rocky Linux to tools guest ID code. commit 89d3e8d9560708be308b0511bbacece903651790 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Refactored the componentMgr plugin code following standard practices. commit d33c816998b8680b67b39a096f44e95d5019e1ab Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Adding Alma and Rocky Linux for x86 and Arm architectures. commit dce3b03c433e4ff77df5703e97519e3b32c9cf14 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Common header file change not applicable to open-vm-tools. commit 32dd72b34033ba0f7eda8456a67bd45fee98c483 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Common source file changes not directly applicable to open-vm-tools. commit 6b3e2e5ae06c77c122bc890a8ff8c3dede6368c9 Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 Changes to common header files not applicable to open-vm-tools. commit ed84c0a175c0122555a6a7cc947590569d28becb Author: John Wolfe Date: Tue Dec 21 12:48:50 2021 -0800 containerInfo Plugin: list the Docker and Kubernetes containers in a guest VM. Added code for a new open-vm-tools plugin, containerInfo. - Added a new configure option --disable-containerinfo to disable building the containerinfo plugin. --disable-containerinfo : Will not check for any dependent packages and will not build the containerinfo plugin. --enable-containerinfo=no : Same as --disable-containerinfo --enable-containerinfo=auto : Checks for the dependent packages. If they are available, then the containerinfo plugin will be built. Otherwise, a warning is printeds and the containerinfo plugin will be skipped. --enable-containerinfo --enable-containerinfo=yes : Checks for the dependent packages. If they are available, then the containerinfo plugin will be built. Otherwise, the configure will terminate with an error. - Updated the sample tools.conf file with various settings related to the containerinfo plugin. - Due to an issue reported in https://github.com/protocolbuffers/protobuf/issues/9184, implemented a workaround by changing 'import weak ' to 'import ' in the .proto files while generating the header files. Build dependencies: (packages names may vary with Linux release). - or - - libcurl4-openssl-dev libcurl-devel - protobuf-compiler protobuf-compiler - libprotobuf-dev protobuf-devel - protobuf-compiler-grpc grpc-plugins - libgrpc++-dev grpc-devel - golang-github-containerd-containerd-dev containerd-devel - golang-github-gogo-protobuf-dev Runtime requirements: - curl, protobug and grpc-cpp commit b36b275bc8cd14c1e2e64f76e3b41307e24a165f Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Set the "svtminion.sh" script version to '1.0'. commit 53949064ee169cdba0925d99a1f9a75f63dbf39b Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Common header file change not applicable to open-vm-tools. commit b38a34acdf9ed3113e53f5e9f2c3cc0927df50eb Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Common header file change not applicable to open-vm-tools. commit 308259f3e5e3630cd30bd04aa0fd0d4c952d7ff2 Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Added the componentMgr plugin to the vmtoolsd vmsvc process. The new componentMgr plugin manages adding/removing of components in the guest. commit db3a1dc6c9cc771bf4c4d8a268b6747f167bcad7 Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Salt Stack Script Integration for Linux. Added the "svtminion.sh" script which will be packaged for Linux to support SaltStack integration and management from the componentMgr plugin. commit 50500199ac9e36ee67deffe51ccd714a6a90ef46 Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Activate the componentMgr plugin build and enablement of the Salt-Minion plugin. commit 67383c5669650766fbdb18962ce05afafb6d0dca Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Prepare to enable Mac OS 14 (Darwin 23) as a new guest. commit 3ca3a1d1ff4edb9ab6dbe5e30079167710ee5d06 Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 filePosix.c: Increased the hash table size for better performance. Improved the performance of the functions File_ListDirectory() and File_WalkDirectoryStart(). commit 011d680184caa26fd4d4d6fe77f77a862aee0adb Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Changes to common header files not applicable to open-vm-tools. commit be8ec133fb755dec100de90d6f5d42dd2a56cf6c Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Common header file change not applicable to open-vm-tools. commit 8b97e826ce53cbcd6ca5aa568906ffbe1b57f0d4 Author: John Wolfe Date: Tue Dec 21 12:48:49 2021 -0800 Common header file change not applicable to open-vm-tools. commit de920bf8398bcf7a017a4b012e84cf98d67babab Author: John Wolfe Date: Sat Dec 4 23:09:31 2021 -0800 Update ChangeLog with the granular push of Dec. 4, 2021. - plus ChangeLog update of Nov. 19. commit 2cadef44dc8c156d8543111d62340212c501aa0d Author: John Wolfe Date: Sat Dec 4 22:55:11 2021 -0800 Common header file change not applicable to open-vm-tools. commit 5fc921074bbf7eba8ee1827de7f12417769e30ca Author: John Wolfe Date: Sat Dec 4 22:55:11 2021 -0800 Adding RHEL9_ARM and OTHERLINUX6_ARM to the ALLARM group. commit b3cb33a91bb97a17b575b77fa9a622b1a9a74a74 Author: John Wolfe Date: Sat Dec 4 22:55:11 2021 -0800 Changes to common header files not applicable to open-vm-tools. commit 8459c9bcda9b7901de0128d1cb594227b33eea1a Author: John Wolfe Date: Sat Dec 4 22:55:11 2021 -0800 Common header file change not applicable to open-vm-tools. commit 611dce7461466fbde66466b08efed436c3c9b3cb Author: John Wolfe Date: Sat Dec 4 22:55:11 2021 -0800 Common header file change not applicable to open-vm-tools. commit 9920a7e9141ae4910cc77b7891dd14607ee8a474 Author: John Wolfe Date: Fri Nov 19 12:52:20 2021 -0800 Update ChangeLog with the granular push of Nov. 19, 2021. - plus ChangeLog update of Nov. 8. commit 28666842fb665b9039ea32a0de5602e6873ac442 Author: John Wolfe Date: Fri Nov 19 11:40:50 2021 -0800 [AsyncSocket] Avoid a potential NULL pointer dereference in a log message. A log message in AsyncTCPSocketListenerCreateImpl() accesses an error code through an optional parameter. Introduce a local error variable to capture any error code from called functions and have it available for the log message. commit 342fd81a270bf36c79baec5bb928a9a979e95af2 Author: John Wolfe Date: Fri Nov 19 11:40:50 2021 -0800 Correct the guestFamily reported for RHEL 9. RHEL 9 had not been added to the ALLLINUX macro. This has been corrected. commit 36514e38f5e31a74ef2e38cb13cebd054a52179d Author: John Wolfe Date: Fri Nov 19 11:40:50 2021 -0800 Common source file change not directly applicable to open-vm-tools. commit a91770b88b3d6f534944867f9c58f982b3f6c37a Author: John Wolfe Date: Fri Nov 19 11:40:50 2021 -0800 Change to common header file not applicable to open-vm-tools. commit 9997bb0c311e5d931d53f1a4328ced07ec911b77 Author: John Wolfe Date: Fri Nov 19 11:40:50 2021 -0800 Change to common header file not applicable to open-vm-tools. commit e4b6231aab74fcc51cf6a22848d9512605be8d28 Author: John Wolfe Date: Fri Nov 19 11:40:50 2021 -0800 Change to common header file not applicable to open-vm-tools. commit 44f883c59b11912eccfc67df5a9723a2848433b1 Author: John Wolfe Date: Mon Nov 8 14:03:23 2021 -0800 Update ChangeLog with the granular push of Nov. 8, 2021. - plus ChangeLog update of Oct. 18. commit 819a20bd5fd2d4f84ae56183d2b2fa4fc88dd72b Author: John Wolfe Date: Mon Nov 8 13:33:58 2021 -0800 Common header file change not applicable to open-vm-tools. commit 53a3387f9bb7f15fd504d6a44c4d8608c1b6ef56 Author: John Wolfe Date: Mon Nov 8 13:33:58 2021 -0800 Code clean up. - Fix assignments of pointer to constant data to a non-constant pointer type. - Remove code that has been commented out. - Updated treatment of pointers as a boolean expression to be a true boolean expression. - Fixed some formatting issues. commit 04515ad7b6f3291af6236ef492de8bfb927d3151 Author: John Wolfe Date: Mon Nov 8 13:33:58 2021 -0800 Update open-vm-tools 12.0.0 to work with openssl 1.1.1 or 3.0.0. commit 0186a8af01f1dd09090cfcd1ddd5487d60c1026e Author: John Wolfe Date: Mon Nov 8 13:33:58 2021 -0800 AppInfo Enhancement: Remove duplicate applications. Update appinfo to remove duplicate applications from guestVar. Add a "remove-duplicates" tools.conf key, which is enabled by default. Setting "remove-duplicates=false" disables the functionality. commit 899063f29c498d1a0abd7ffce71ae05260a5555d Author: John Wolfe Date: Mon Nov 8 13:33:57 2021 -0800 Common header file change not applicable to open-vm-tools. commit aaaefaf7e0cc39bc7ec1c7f89069f5bf96baf5ca Author: John Wolfe Date: Mon Nov 8 13:33:57 2021 -0800 ServiceDiscovery: Enhance version scripts to discover vRLi and Cassandra services versions. commit 8a4e38f66325092f84ba612e614f6fd16e135752 Author: John Wolfe Date: Mon Nov 8 13:33:57 2021 -0800 Common header file change not applicable to open-vm-tools. commit ffbbc2932e8fa348e7177f3cf91c1085641a295c Author: John Wolfe Date: Mon Nov 8 13:33:57 2021 -0800 Common header file change not applicable to open-vm-tools. commit e501f711f59b30ce4d402d5bbc2361cb5b29f541 Author: John Wolfe Date: Mon Nov 8 13:33:57 2021 -0800 Common header file change not applicable to open-vm-tools. commit df85d1e571414fdecabc98492da53fe2950a8e6b Author: John Wolfe Date: Mon Nov 8 13:33:57 2021 -0800 Changes to common source files not applicable to open-vm-tools. commit d40c8b6d3086f95980b41a1012639ae796e80fbc Author: John Wolfe Date: Mon Nov 8 13:33:57 2021 -0800 Common header file change not applicable to open-vm-tools. commit 16e24c8d789f8ff81a9fbb915858cb6af88f66a5 Author: John Wolfe Date: Mon Oct 18 07:44:47 2021 -0700 Update ChangeLog with the granular push of Oct. 18, 2021. plus ChangeLog update of Oct. 6. commit d3158f108ec8119d270d08d613545b61f4a6d50b Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit 8407406335a8f1bc25a23497cdb5b880fc2db6aa Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit e9907529c68df57dbf1baa5c5b0872098fb3bbeb Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit 1ec43b3ef88719d8d3ad206e7a427c479c496e0d Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Remove characters from saml-schema-assertion-2.0.xsd. The file, created with Windows in 2011, has been changed to Unix encoding. commit ae7d374ee335277a637ec99ada728df7545f2459 Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit f9bfc57babb4cc18e8fcada6f44c26d7dfca90ce Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit a45ded9333305f71eea2e0ab4cc144fc2efad74f Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit 6ff8e802b6a2fdf1595d032a1ab94b9f83a2f61b Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit 8f2a9bb928e5d41c308684e68ed68a742dfd8222 Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit c9639690ec6d7bce96a7c06d0a05546b811d6b1f Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit a1aa6abc127d872966415e5fd01a9e35db0f2ef5 Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit 88de2de0f48cb0334cb8b57bca5ad016133d1674 Author: John Wolfe Date: Mon Oct 18 07:31:44 2021 -0700 Common header file change not applicable to open-vm-tools. commit fe739dc30671ab0d6de67acd1dde374f88fe499c Author: John Wolfe Date: Mon Oct 18 07:31:43 2021 -0700 Common header file change not applicable to open-vm-tools. commit c5bc4c37b8f948e3d9bf8d7e2f85196f5099d311 Author: John Wolfe Date: Wed Oct 6 23:52:03 2021 -0700 Update ChangeLog with the granular push of Oct. 6, 2021. plus ChangeLog update of Sept. 20. commit 4aecc2978e09dddc1f7a0c9af7e9b8ffa57227e2 Author: John Wolfe Date: Wed Oct 6 23:40:31 2021 -0700 Common header file change not applicable to open-vm-tools. commit 02b9fea09af950780fdf6e93141edf97de9075de Author: John Wolfe Date: Wed Oct 6 23:40:31 2021 -0700 Common header file change not applicable to open-vm-tools. commit d3147cbb1cec5b5ac41c1d1955f28a20d2bedf5a Author: John Wolfe Date: Wed Oct 6 23:40:31 2021 -0700 Common header file change not applicable to open-vm-tools. commit 8929bd9db5fc57a76491d3f1d8e314955c7b5823 Author: John Wolfe Date: Wed Oct 6 23:40:31 2021 -0700 Common header file change not applicable to open-vm-tools. commit db093d15c263262632a854342b447c6b67e72394 Author: John Wolfe Date: Wed Oct 6 23:40:31 2021 -0700 Common header file change not applicable to open-vm-tools. commit 3b586cc541a0ead1bc60a6b11ec655e10e83c29c Author: John Wolfe Date: Wed Oct 6 23:40:31 2021 -0700 Common header file change not applicable to open-vm-tools. commit daf6e0fb8ac80cc8bd718b6564b037fc9eb6b654 Author: John Wolfe Date: Mon Sep 20 08:51:19 2021 -0700 Update ChangeLog with the granular push of Sept. 20, 2021. plus ChangeLog update of Sept. 7. commit fe059f34e4ab93f21c41b4598da6846eafd9bc20 Author: John Wolfe Date: Mon Sep 20 08:07:36 2021 -0700 Change to common header file not directly applicable to open-vm-tools. commit ffa5d491194412213882cdcc808d621b439ae2a6 Author: John Wolfe Date: Mon Sep 20 08:07:36 2021 -0700 Common header file change not applicable to open-vm-tools. commit 03b6ca66c23289da7b34d1e47f5769d063ee3ad9 Author: John Wolfe Date: Mon Sep 20 08:07:36 2021 -0700 Common header file change not applicable to open-vm-tools. commit a3e4fd4e4692e36b5b66b5feb4044faa41d46f22 Author: John Wolfe Date: Mon Sep 20 08:07:36 2021 -0700 resolutionKMS: Add support for the svga3 device The resolution plugin was checking for only the svga2 device, which does not exist on ARM. This makes the resolution plugin work on ARM. commit 21f193b21e3d2be122a6ee9755a45536671cf4e9 Author: John Wolfe Date: Mon Sep 20 08:07:36 2021 -0700 Common header file change not applicable to open-vm-tools. commit fe8803ea205da66e8a5040f447835fd2292de89e Author: John Wolfe Date: Mon Sep 20 08:07:36 2021 -0700 Log the guest OS name and full name. Added a log message for the guest OS name and full name that is sent as guestInfo. Messages are logged only when the guestInfo is successfully updated to the VMX log. commit 7b58f891b283c4eb42602bba07f4713815a508da Author: John Wolfe Date: Tue Sep 7 06:49:29 2021 -0700 Update ChangeLog with the granular push of Sept. 7, 2021. plus ChangeLog update of Aug. 23. commit 9a793fb5399b36cb473c57eb3a41570adfccc078 Author: John Wolfe Date: Tue Sep 7 06:39:53 2021 -0700 Common header file change not applicable to open-vm-tools. commit d09c3d5247e21f0a881406a020e6cdf87ab0ee2d Author: John Wolfe Date: Tue Sep 7 06:39:53 2021 -0700 Common header file change not applicable to open-vm-tools. commit b963fdd5363d1ecd347045408cf1b40e5ac27188 Author: John Wolfe Date: Tue Sep 7 06:39:53 2021 -0700 Common header file change not applicable to open-vm-tools. commit ee2fe611e1c6f27d0e918a361a967f13da10ba08 Author: John Wolfe Date: Tue Sep 7 06:39:53 2021 -0700 Common header file change not directly applicable to open-vm-tools. commit e551b81709ee4f42e79f2f4aaa47d9443e24a2fa Author: John Wolfe Date: Tue Sep 7 06:39:53 2021 -0700 Common header file change not applicable to open-vm-tools. commit adb9c0476a8dd9d15947857343b23c6ffe9b395c Author: John Wolfe Date: Tue Sep 7 06:39:53 2021 -0700 Common header file change not applicable to open-vm-tools. commit 6336dec45c73d60d8bd100ddc71f3b125a2a9cc9 Author: John Wolfe Date: Mon Aug 23 20:22:35 2021 -0700 Update ChangeLog with the granular push of Aug. 22, 2021. plus ChangeLog update of Aug. 12. commit a6923583d4519019e25860abcd16c2205d8a3fde Author: John Wolfe Date: Mon Aug 23 20:13:37 2021 -0700 Replace the use of appInfo's internal json escape function with libmisc's CodeSet_JsonEscape(). commit c7a5a3e189494e44c16ed7c21ab0b4fac28b26b8 Author: John Wolfe Date: Mon Aug 23 20:13:37 2021 -0700 Common header file change not applicable to open-vm-tools. commit 3bae54175a7a72872920ba62842a5091a87ae11a Author: John Wolfe Date: Mon Aug 23 20:13:37 2021 -0700 Common header file change not applicable to open-vm-tools. commit 61331a189a0eeb76f014db28288b06c0323bc0b9 Author: John Wolfe Date: Mon Aug 23 20:13:36 2021 -0700 Removal of the hgfsmounter/mount.vmhgfs command from open-vm-tools. The hgfsmounter (mount.vmhgfs) command is no longer used in Linux open-vm-tools. It has been replaced by hgfs-fuse. Remove all references to the hgfsmounter in Linux builds. commit f5fb3a9fb32ea465f965aa971bc40bdff8edc36f Author: John Wolfe Date: Mon Aug 23 20:13:36 2021 -0700 Further refinement of the toolsDeployPkg.log file. Modified the build info description with the module name instead of "imgcust" or "sysimage". commit 1f971148e368b2df87cb20c74568494b7b543ced Author: John Wolfe Date: Thu Aug 12 12:57:20 2021 -0700 Update ChangeLog with the granular push of Aug. 12, 2021. plus ChangeLog update of July 27. commit 38f8606a3f4faeb0b8ae1f9277c9c1b50ac19bbe Author: John Wolfe Date: Thu Aug 12 12:46:05 2021 -0700 Common header file change not applicable to open-vm-tools. commit 574cbbe55abdc716a6af03a752260699c3e22784 Author: John Wolfe Date: Thu Aug 12 12:46:05 2021 -0700 Common header file change not applicable to open-vm-tools. commit 5003c79aaf398fbdc965c510c1b0be2350be7e64 Author: John Wolfe Date: Thu Aug 12 12:46:05 2021 -0700 Common header file change not applicable to open-vm-tools. commit f254eef58523fc9539e3836d825056b999ff192b Author: John Wolfe Date: Thu Aug 12 12:46:05 2021 -0700 Reduce the scope of a local variable. The 'Codacy' tool reported that the scope of a local variable can be reduced in the Debug() function of linuxDeployment.c. commit 63d9fd68f5513b683aae855d30a2da4d4e4f72a7 Author: John Wolfe Date: Thu Aug 12 12:46:05 2021 -0700 Common header file change not directly applicable to open-vm-tools. commit f39d4c1fe303d94a079f0d0e9ed098cde1cb0316 Author: John Wolfe Date: Thu Aug 12 12:46:05 2021 -0700 VmCheck_IsVirtualWorld(): assume VMware hypervisor if USE_VALGRIND is defined. Updating the VmCheck_IsVirtualWorld() function to assume that if the open-vm-tools build was configured with "--enable-valgrind", the tools will be used on a VMware hypervisor for memory leak detection. In this case, simply return TRUE and avoid touching the backdoor. The "backdoor" touch test cannot be handled by Valgrind. commit 1c31dbfc3df970bd6f4e0ad297f8d79e105a2690 Author: John Wolfe Date: Thu Aug 12 12:46:05 2021 -0700 Update VMware Tools version to 12.0.0. The next major VMware Tools / open-vm-tools will be version 12.0.0. commit dd78c6abbb4f376afea1db423acaf483c4f56f32 Author: John Wolfe Date: Thu Aug 12 12:46:04 2021 -0700 Common header file change not applicable to open-vm-tools. commit e76f136563a8e78676f9c1e069175dec835eaade Author: John Wolfe Date: Thu Aug 12 12:46:04 2021 -0700 Common header file change not applicable to open-vm-tools. commit beee0873cbf0d0399d52cb762b2b3e85054c5774 Author: John Wolfe Date: Tue Jul 27 10:54:08 2021 -0700 Update ChangeLog with the granular push of July 27, 2021. - plus ChangeLog update of July 8. commit 26e7c2f3b5198621c8234c4890431dc16698bcf3 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Common header file change not applicable to open-vm-tools. commit d78011e325c6275bc9199b102983544057dfc0bc Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Common header file change not applicable to open-vm-tools. commit 8db9ab140d15787064745c4ba0497fc7d162ab84 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Common header file change not applicable to open-vm-tools. commit 4eb519b107745cd01018194aa059a5d0b39c3cf4 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Common header file change not applicable to open-vm-tools. commit c387b16795b4a78a53c89f607a8ca31580138e05 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Changes to common source files not applicable to open-vm-tools. commit 8259e2e5238e7b90c7f1ddf396ec47fc9acabfe1 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Add tools version and build info into the toolsDeployPkg.log file. commit 2fe6126e92f4bd4dc9eb683e59df84000b312398 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Common header file change not directly applicable to open-vm-tools. commit 8c788af23d0855f1876e8e6de665d050a157c557 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Common header file change not applicable to open-vm-tools. commit cb8741edd1fe30dd423cf8533d63a4dc8bb39d8a Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Terminology cleanup in some comments. commit b873cda6c5bf0228b0442d1c3be402feafadf8c1 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 GuestOS: Support Fedora and Debian 10 for ARM Since we support Fedora, support ARM Fedora - 64 bit only. Remove VCPUHOTADD from ARM guests. There is no support for this. commit 3a599078d238c12c26d3ca3e39c743f7d9c65555 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 guest_os.h: A bit of clean up Arrange things in a nicer way. commit 61e3c68f029af528e61de5b22b215ef689870be2 Author: John Wolfe Date: Tue Jul 27 10:37:24 2021 -0700 Changes to common source files not applicable to open-vm-tools. commit 3226203c1c49e8d0fca9aa6a8557ac757c91c3a8 Author: John Wolfe Date: Thu Jul 8 20:35:44 2021 -0700 Update ChangeLog with the granular push of July 8, 2021. - plus ChangeLog update of June 30. commit b033e5c2d77ee66e9426973005cf1f48a5b3cceb Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Common header file changes not applicable to open-vm-tools. commit c907662b1034bd783dab4728bec3af06892f6e4a Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Changes to common header files not directly applicable to open-vm-tools. commit e6ff175716602a91fa1385c30846961c57d089f2 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Common header file change not directly applicable to open-vm-tools. commit d21b1402ac2e1f59851560ac08516ee8ddaa13b0 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Changes to common header files not applicable to open-vm-tools. commit 35c78d66e0202a5ce217193d03bd48a50ce87c3c Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Added a configurable logging capability to the network script. The network script has been updated to: - use the vmware-toolbox-cmd to query any network logging configuration. - use 'vmtoolsd --cmd "log ..."' to log a message to the vmx logfile when the logginging handler is configured to "vmx" or when the logfile is full or is not writeable. Added an example configuration in the tools.conf example file. commit b484ab6727bbfd8691e8dd4f8d6ae297e06a8672 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Common header file change not applicable to open-vm-tools. commit 102714ebe1d0253a7a2afb373f5d73d9d25687fb Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Fixed the possible use of an uninitialized variable in Util_ExpandString. Additionally, several Boolean expressions were updated to be proper Boolean values, for readability and consistency. commit 0ae179aa40ed68f3357faabbe6f101035206cd32 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Changes to common header files not applicable to open-vm-tools. Prepared the basic infrastructure for adding Windows 11 guests. commit e1f850a1fa20a911abf9a3d7f2ca7ae6c2a44209 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Record the use of VMware Tools version 11.3.5 in vm_tools_version.h Add TOOLS_VERSION_JIGSAW_UPDATE1 for version 11.3.5 in the header file lib/include/vm_tools_version.h commit d5605d3861c1dd8a5cf968b627b7adad2da98308 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Common header file change not applicable to open-vm-tools. commit 77196a4b4fe7edbdddab1adb402021979f224a0f Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Changes to common header files not applicable to open-vm-tools. commit 38777a57a1e9befbb5d858934e8c032923fb2242 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Common header file change not applicable to open-vm-tools. commit 7caa442246e75e60e266f936538d68a0fa6045a8 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Common header file change not applicable to open-vm-tools. commit 6e5c26b8bddbe7817d49b2f48dba6776e5d4f851 Author: John Wolfe Date: Thu Jul 8 20:10:23 2021 -0700 Common header file change not applicable to open-vm-tools. commit c9bc765c083db8e3d4705eb14715792cdfba8d0c Author: John Wolfe Date: Wed Jun 30 11:53:41 2021 -0700 Update ChangeLog with the granular push of Jun 30, 2021. - plus ChangeLog update of June 7. commit 4ac7706c44c4d29f38e8d1c7d2ac9cf45521cf4f Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to a common header file not applicable to open-vm-tools. commit d5f0c71fd909527fcfd03f858d277abc9fae9569 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Add page size defines for 64KB pages. commit c1457815c1c5e579a3d26c99fff3f6b9e6ed0d41 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to a common header file not applicable to open-vm-tools. commit 248830d868b7ade3ce199894fc0cb3c4771dd364 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to common source file not applicable to open-vm-tools. commit bd5dede3536c30e2799fa8c788a9dc9b7f904d35 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Use os-release preferentially for guest identification. If the "score" of the Linux guest identification from os-release is the same as from the LSB score, use the os-release data. The os-release standard is well established and the LSB is deprecated. commit 5fac74631a896e3e5b121a024a4293dcede5eaa1 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to a common header file not applicable to open-vm-tools. commit d9ff40dc4cf48b78cdebe9d05a393bd283429fa0 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to a common header file not applicable to open-vm-tools. commit 843e5851ac692c4bcaca1cfa262eda7e610417f0 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to a common header file not directly applicable to open-vm-tools. This is part of a host-side fix for an intermittent DnD issue. commit 19c38e8ed9be5272dd45cd07d362345456d9c3ed Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Fix an issue of re-running scripts. Fix an issue in the service discovery plugin where scripts can be re-run while the previously started one is still active. commit 26b6e174f9a6ba780a052657cce3290f2174bcba Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to a common header file not applicable to open-vm-tools. commit 03d3b6978b2c9d0e66d4b45b992724167ab14f03 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to a common header file not applicable to open-vm-tools. commit 59fe3b61458659b0bdcce7d8ac0e4ae9e4ae7b3d Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Changes to a common header file not applicable to open-vm-tools. commit 81745623ae421c510fedba499ecfe0d916265a28 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Allow setting a custom poll interval in the service discovery plugin for debugging. commit 08649561962e115cda98d6f1ef85a3559b12efe3 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Change to common header file not applicable to open-vm-tools. commit 185952f4b8c85d0fb04eecd08be0673f9e800f70 Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Add preliminary guest OS support of RHEL-9 for Arm. commit 176a0490fa001892e74237d1cf49607574bf8c4a Author: John Wolfe Date: Wed Jun 30 11:37:27 2021 -0700 Throttle the "Nic limit reached" log message from the guestInfo plugin. Implement a wrapper API for throttling vmtools log messages. Use the API to throttle the repetitive log message, "Nic limit reached", from the guestInfo plugin. This change addresses the log spew reported in open-vm-tools issue: https://github.com/vmware/open-vm-tools/issues/128 commit c3ad5e62cb9892e28486839aba19116aaadd76ef Author: John Wolfe Date: Wed Jun 30 11:37:26 2021 -0700 Add a header to the vmsvc log file. Add a log entry at the start of the vmsvc log file that includes the tools version, build number, and guest OS details. commit 1d25adfe20a5da7a3ed37c970e72699d487f3cca Author: John Wolfe Date: Mon Jun 7 10:53:14 2021 -0700 Adding missed 2021 copyright updates in granular pushes. commit a01a33d95d511a1019c6f9ab7a525635c9a61c61 Author: John Wolfe Date: Mon Jun 7 08:25:09 2021 -0700 Enhanced the VMware Tools SDMP plugin to support GDP. commit 1751cd1e49edb5d88cb4d5175bdbb7ac5d86054c Author: John Wolfe Date: Mon Jun 7 08:25:09 2021 -0700 Add check that the packet size received is >= expected packet header size. DnD RpcV3: A corrupted packet received may result in an out of bounds (OOB) memory access if the length of the message received is less than the size of the expected packet header. commit e3de1afdd4d802596bffdbbb63ec6708fafcf51a Author: John Wolfe Date: Mon Jun 7 08:25:09 2021 -0700 GOS support: Add Linux 6.x support. commit bd151c59769f9bac14fc2df0d1076faa902734bf Author: John Wolfe Date: Mon Jun 7 08:25:09 2021 -0700 Change to a common source file not directly applicable to open-vm-tools. Adding a NULL pointer check. commit d5938385597f4c13b6e9d265a399a67258c47f41 Author: John Wolfe Date: Mon Jun 7 08:25:09 2021 -0700 Common header file change not applicable to open-vm-tools. commit 26b72e101e3d9a66e97e2179f142ce8961c7869f Author: John Wolfe Date: Mon Jun 7 08:25:09 2021 -0700 Update the tools version to 11.4.0 on the "devel" branch. commit 5c1025a2f29f199a65cf703b93c1ae5294ff0053 Author: John Wolfe Date: Mon Jun 7 08:25:09 2021 -0700 Open-vm-tools 11.3.0 L10n updates. commit 40e473ea1378ab1874f4cdf8aa38d39e11299fe9 Author: John Wolfe Date: Mon Jun 7 08:25:08 2021 -0700 Customization: Retry the Linux reboot if telinit is a soft link to systemctl. Issues have been reported on some newer versions of Linux where the VM failed to reboot at the end of a traditional customization. The command '/sbin/telinit 6' exited abnormally due to SIGTERM sent by systemd and where telinit is a symlink to systemctl. This fix checks if telinit is a soft link to systemctl and if yes, retries a system reboot until the telinit command succeeds or the reboot literally happens. commit f8eedf7070b0c11c73f86e1374c004a1bc0212e1 Author: John Wolfe Date: Mon Jun 7 08:25:08 2021 -0700 Change to common source file not directly applicable to open-vm-tools. commit 5acc2a69256aa351e38d7abe1914b7785de6d6b2 Author: John Wolfe Date: Mon Jun 7 08:25:08 2021 -0700 Changes to common source files not applicable to open-vm-tools. commit 9ff3c61c5d5ab58922c55db77704bab56bac75d6 Author: John Wolfe Date: Mon Jun 7 08:25:08 2021 -0700 Common source file change not applicable to open-vm-tools. commit dc39fc8c67180b3e7213d01449868482c17b36f4 Author: John Wolfe Date: Mon Jun 7 08:25:08 2021 -0700 Switch the current thread to "C" locale to parse /proc files. commit 912fecf2f9e28a8083fee6e29b83a926c35b8661 Author: John Wolfe Date: Fri May 21 11:57:16 2021 -0700 Match the copyright style as in the main source repository. commit b35069156e3d73b2149e78238eed38671481b0b4 Author: John Wolfe Date: Thu May 20 11:58:01 2021 -0700 Update ChangeLog with the granular push of May 20, 2021 - plus ChangeLog update of May 3. commit dde0b8e906ea1ef1f5e752e51e9887be002b07f0 Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Common header file change not applicable to open-vm-tools. commit b4a3a288b013202bfc01f99093c420b75051ffb4 Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Change to common source file not immediately applicable to open-vm-tools. commit b2c8baeaa8ac365e1445f941cf1b80999ed89a9d Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Remove unwanted "volatile" from static variable used with g_once_init_enter() The glib api documentation for g_once_init_enter() specifically states that "volatile" should NOT be used with the address passed as the argument. Recent compilers (GCC-11 & clang 11) and recent versions of glib-2 will result in a warning that the "volatile" qualifier has been dropped if it has been used. Remove the unneeded and unwanted "volatile" qualifier from the definition of "inited" in pollGtk.c. Fixes: https://github.com/vmware/open-vm-tools/issues/509 commit 33ba0f01a3a15b245857e0f8ba2563b3177ced25 Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Add backdoor support for host time of day in Arm The timeSync plugin makes backdoor calls to get host time of day. Update the time of day backdoor calls to function with the Arm backdoor implementation. Also fix a bug where an error returned by the GETTIME backdoor handler is incorrectly treated as a time value. commit 39b499fb2fcedc7b984510edf2ed0ea43fb0fe24 Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Common header file change not applicable to open-vm-tools. commit 35dbe93510857ea9fa58bb93a959f26dea1bed7d Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Common header file change not applicable to open-vm-tools. commit c693dcf8212bcb01827cf131910e1d66132f50e1 Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Common source file change not directly applicable to open-vm-tools. Introduce peek() to the asyncsocket API, only supported by TCP vtable. Peeks are similar to recv(), except that they do not drain the socket after reading. Subsequent peek/recv reads the same data back. However since recv does SSL_Read, a recv() following a peek() may not get the same data as peek() after SSL is initialized. This is not a problem when peeks are done before SSL setup. Implementation notes: - peek is a one-shot operation. The poll callback is unregistered once it fires (recv keeps the callback until recv is cancelled). - non-partial peek is not supported, so the peek callback will be fired when any amount of data less than or equal amount of the requested length is available in the socket buffer. - It is possible to invoke recv() or peek() recursively from within the peek() callback. A peek is disallowed from within the recv() callback. commit 95cbd990ec667a34b6b76c1d53182317c33e5330 Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Fix an ASSERT in bora/lib/misc/timeutil.c. Fix a problem with TimeUtil_NtTimeToUnixTime on Arm that was encountered when running tools tests on Apple silicon. The problem was the routine assumed that a variable was 32-bits if VM_X86_64 was not defined. This may have been true in the past, but it is no longer true now that the code is also built for 64-bit Arm. commit abfd599dea18f0f6a5acc35d539cec0322d194df Author: John Wolfe Date: Thu May 20 11:38:38 2021 -0700 Additional changes for the network interface limit logging. 1) Use the VM_SAFE_STR macro for string null check. 2) Since free() is NULL safe, remove the "if" check before the free(). 3) Fix an alignment issue. commit 78f19996702a14066d9f5424c522167780151f0e Author: John Wolfe Date: Thu May 20 11:38:37 2021 -0700 Update terms used in code that is distributed publicly in open-vm-tools. Use alternate terms wherever possible. This does not address function names, structure elements, or macros. commit d55475adf7617516fd8ec2bdc4403c1b7fdcf83f Author: John Wolfe Date: Thu May 20 11:38:37 2021 -0700 Common header file change not directly applicable to open-vm-tools. commit bbcdb619382645179f2a8091818f55314c44291d Author: John Wolfe Date: Mon May 3 20:01:43 2021 -0700 Update ChangeLog with the granular push of May 3, 2021 - plus ChangeLog update of April 19. commit 16e2be2e2c67d49ed01032348368157ad9867920 Author: John Wolfe Date: Mon May 3 19:39:41 2021 -0700 VGAuth: Use GUESTRPCPKT_FIELD_FAST_CLOSE flag for log messages. VGauth is a single action service. With the GUESTRPCPKT_FIELD_FAST_CLOSE flag added, VMX closes the vsocket as soon as the RPC response is sent. This cleans up the vsocket connections faster and minimizes the number of connect() failures in the guest. commit 092a4cfd7b577b55abc71e636748dbbb25240171 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not applicable to open-vm-tools. commit 8994d7c3a9c5164c5c88b5d882d32238a9964628 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Asyncsocket: Add comments about AsyncSocket_SetErrorFn usage. Document that AsyncSocket_SetErrorFn must be called before an internal asyncsocket callback can fire and trigger a call to the error handler. The error handler must be set immediately after the asyncsocket is created, either from the poll thread, which requires no additional synchronization, or while holding the asyncsocket lock, which is passed via pollParams. commit 4abc2d2b6cf754914e6c0f08d245a2852f04e368 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not applicable to open-vm-tools. commit a3db034717c4bd77ffcf4f6ac2682096d360e2e0 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Tools gdp plugin updates. commit 037825f8b73cdc04e6f19e5868224e3e911c1acb Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not applicable to open-vm-tools. commit 62daa89681b48ad0fe33a92332a04a5c33c862e2 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not applicable to open-vm-tools. commit 306366fa79a390b632c89b4eab29fdd01659b688 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Format the VMCI port in a guest RPC connect request using "unsigned int" type. commit 6c01c0ad957152d00cec28fb059a5781acb5a607 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not applicable to open-vm-tools. commit e0b4963730505f1bb746b1f93998b5e9a8a9af58 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not directly applicable to open-vm-tools. commit 2693e19a54d93dac0a206bf2634f6e6b908fc8b9 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 vmwgfxctrl: Refactor the 'for' loop index declarations for C89 compatibility. commit 86fa9e400b3866407be4acfebd52f9093483f8b1 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not applicable to open-vm-tools. commit d9dae1062ab61a15c54f02ccc8b74f69a1ead3f9 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Fusion does not need to fork on certain file opens anymore. An NFS issue in MacOS 10.4 was worked around by forking and sending credentials to the child. Removing the work-around since it is no longer needed. commit b2078e875dfaa3257cb8a709a574b8a3cb8e8069 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not applicable to open-vm-tools. commit f59fe38baa986b5d5e1a8504ac70c5e3d4938cc6 Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Log messages when the network interface limit is hit. Whenever the maximum NIC limit is reached, log a message to both the VM guest.log file on the host and the vmsvc.log file inside the guest. Moved the logging api added for powerOps plugin to vmtoolslib so that it is available for all plugins. Modified the powerOps code accordingly. commit 09b035ad85475df08cd9bae8cc2d7aea6d8f0ffe Author: John Wolfe Date: Mon May 3 19:39:40 2021 -0700 Common header file change not directly applicable to open-vm-tools. commit cf65239bd6f5dede5394d1090615e6d70b06cd48 Author: John Wolfe Date: Mon Apr 19 12:41:43 2021 -0700 Update ChangeLog with the granular push of April 19, 2021 - plus ChangeLog update of April 5. commit b5ec5c1b60db89fe8fb4c223b204a8e50077851b Author: John Wolfe Date: Mon Apr 19 12:32:41 2021 -0700 Sync "(c)" vs. "(C)" usage in another header file. commit e4e7aee59955326f1480fc27ffb8eef080fbbefc Author: John Wolfe Date: Mon Apr 19 12:19:57 2021 -0700 Update copyright date missed by developer. commit b8058d49454e7c15fcd4806e51244803b08170b8 Author: John Wolfe Date: Mon Apr 19 11:16:36 2021 -0700 Sync the (c) copyright symbol with the (C) in the Perforce repository; will avoid granular update problems when the copyright changes on these files. commit 315b159733f55bd617391abf472a4ef2be22a624 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit 1ebf8c871c8db79278fa6cd3f7d24edd4db7ce2d Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common source file change not applicable to open-vm-tools. commit 52523347adccc1ec3670488c6c61ed4c998372f3 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Changes to common source files not directly applicable to open-vm-tools. commit cd80433f04bb0f760759a4b64cc52d9950c07230 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit 7417e628d777f598c75d832564478ec199e709d8 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit 5f982aadfcfbdb11d38978c764678c94575eb4b8 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit 48c0a778d94c99ebb0e51a284aa8ea1f6a8d6338 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common source file change not applicable to open-vm-tools. commit fe2192f866a2faed6f9d27a1674838d56aa9f69f Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit a183c79fbd8188a1d2aa1322469d19e71be7d676 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Unescape JSON in UTF-8. Add a routine to unescape JSON escape sequence in UTF-8 strings. commit 865b31e49350e4aefa0858b6575051eae7def5e1 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit 5883b498a44c7d64025e6af761e784a7e2ce72aa Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit e834e17b698f56313e6b6a1f34c2b0c52665e3cd Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit 3827120a9edac868a1094cdd225b02920f952a0e Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header files change to facilitate building with x86_64 and arm64. Simplify _DMB/_DSB. commit 5e5494ef373917c706bc14c3fc5f90cdd07a0f4a Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit 65519ffb067661ecea1e0bae077dea5d3ce23197 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Correct a typo that rendered an if statment to always be true. commit 27d9e866243ce119746a57d60690efb4c4502fb7 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Common header file change not applicable to open-vm-tools. commit 964ecc057dd482efd53c809921a9f97b8efd3313 Author: John Wolfe Date: Mon Apr 19 11:08:11 2021 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 57d9962108e0fdd56721ad03a7acec6abb7fdb86 Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Adding thread ID to logging messages. As more threads (even short-lived worker threads) are added to vmtoolsd, add logging of the thread ID to simplify debugging. commit 4dca880085556da2e7c3515067667a53acf43d54 Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Common header file change not applicable to open-vm-tools. commit 0f6d89fc0bbf119e2284ba5195b7072d99a503f2 Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Common header file change not applicable to open-vm-tools. commit a58b9c39768dd4582a2ccbd2483ae6c02d894528 Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Check a previously unchecked return value. Fixes an "Unused value" issue reported from a Coverity scan of open-vm-tools. commit b9c4441ed7316d1f807697c7145e2c09656f3e5e Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Common header file change not applicable to open-vm-tools. commit 82931a1bcb39d5132910c7fb2ddc086c51d06662 Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Fix issues using GCC 11 with gtk >= 3.20 and glib >=2.66.3 With glib2.0 releases >= 2.66.3, glib header files inside an extern "C" block will encounter compilation errors. This has impacted several OSS packages. Consumers of newer versions of glib2.0 must not include glib headers in an extern "C" block. GTK 3.20 has deprecated gdk_display_get_device_manager(); using the newer gdk_display_get_default_seat() when the GTK version is >= 3.20. The return value from read() must be used to avoid an unused result warning from the compiler. This can be avoided by using dummy retyping in the case where the return value is not used or in this case, using the returned value in a debug log message. Pull Request: https://github.com/vmware/open-vm-tools/pull/505 Addresses: https://github.com/vmware/open-vm-tools/issues/500 Addresses: https://github.com/vmware/open-vm-tools/issues/509 commit d8ccbf4f386ca996778ed843073f6ad5743c8093 Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Common header file change not applicable to open-vm-tools. commit fc6368df777de8e862dcc7fac3dec5ccdc8cf817 Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Common header file change not applicable to open-vm-tools. commit 50a9a23dd3abda3df63f96433821a79f74742bd1 Author: John Wolfe Date: Mon Apr 19 11:08:10 2021 -0700 Common header file change not applicable to open-vm-tools. Add new definition for darwin22-64 (macOS 13) commit 78631eb8a2e4ce12794b1e75a6232482f08d0c96 Author: John Wolfe Date: Mon Apr 5 09:28:52 2021 -0700 Update ChangeLog with the granular push of April 5, 2021 - plus ChangeLog update of March 25. commit b81140454253dfe3c836c03e221aa832da4ac9e8 Author: John Wolfe Date: Mon Apr 5 09:01:43 2021 -0700 Check return value from VmCheck_GetVersion. Fixed an issue reported by Coverity scan of open-vm-tools. commit f68f15d091fcda7ab393586498683d2061f9a85e Author: John Wolfe Date: Mon Apr 5 09:01:43 2021 -0700 L10n drop for updated wording in user visible messages to conform to guidelines. commit d1d9f2fca56a40159b7039f2955410acc3de3489 Author: John Wolfe Date: Mon Apr 5 09:01:43 2021 -0700 Common header file change not applicable to open-vm-tools. commit 585747b2d0b6091ffcc9ffce585ef89dd43ea9e8 Author: John Wolfe Date: Mon Apr 5 09:01:43 2021 -0700 Common header file change not applicable to open-vm-tools. commit 3256fd9e85d75768f9bcbeb39037a35e2b7c3908 Author: John Wolfe Date: Mon Apr 5 09:01:43 2021 -0700 Common header file change not directly applicable to open-vm-tools. commit ba6744a874786f5a890e641fb94f2d048fc39e69 Author: John Wolfe Date: Mon Apr 5 09:01:43 2021 -0700 Common header file change not applicable to open-vm-tools. commit ec8b7d139c72287140e660ad4f43c083981b9a6d Author: John Wolfe Date: Mon Apr 5 09:01:42 2021 -0700 Fix dereference after null check reported by Coverity. Removed a NULL pointer test for gErr that causes Coverity to report a dereference after null check. commit d19fe417deed03b2b8a9b8a22cbed1bcc836e0f3 Author: John Wolfe Date: Mon Apr 5 09:01:42 2021 -0700 Tools gdp plugin updates. commit 58fca5f585180c19311d084a536ed8014f5c102b Author: John Wolfe Date: Mon Apr 5 09:01:42 2021 -0700 Common header file change not applicable to open-vm-tools. commit 08d82bad0db6d0d04b257748e8434a28f5a7c1c4 Author: John Wolfe Date: Mon Apr 5 09:01:42 2021 -0700 JSMN: Miscellaneous log message fixes. * One log message in jsmn_parse_string function referred to a primitive instead of a string. * When the parsing fails, the log message specified the wrong position where the parsing failed. * Changed '%c' to '0x%02x' in the log messages to avoid any issues with printing the invalid/unprintable characters. * Added a new log message for better debugging in one specific error code path. commit 5bf72167ec1870b75699e46df1b5e5e86520492a Author: John Wolfe Date: Mon Apr 5 09:01:42 2021 -0700 Common header file change not applicable to open-vm-tools. commit a5b6b94525ee86d4283ae1db3c424435c93dac61 Author: John Wolfe Date: Mon Apr 5 09:01:42 2021 -0700 lib/misc/hostinfoPosix.c: Correct an ifdef typo introduced in an earlier change. commit 47df40cccede41beffa9658889b51ce1738c61bd Author: John Wolfe Date: Mon Apr 5 09:01:42 2021 -0700 lib/file/file.c: File_UnlinkIfExists() Revised File_UnlinkIfExists() to return 0 for success and an errno for failure. Previously, a failure was indicated by a -1 and the caller had to retrieve the errno. commit 48f6c1cefc31cab095718ac4383a4fb7fd08d51b Author: John Wolfe Date: Mon Apr 5 09:01:41 2021 -0700 lib/file/file.c: File_Unlink() Revised File_Unlink() to return 0 for success and an errno for failure. Previously, a failure was indicated by a -1 and the caller had to retrieve the errno. commit 996626d977b3e5186d4664491b740a8afc6f45cd Author: John Wolfe Date: Mon Apr 5 09:01:41 2021 -0700 Common source file change not directly applicable to open-vm-tools. lib/file/file.c: Revised File_UnlinkRetry() and File_UnlinkNoFollow() to return 0 for success and an errno for failure. Previously, a failure was indicated by a -1 and the caller had to retrieve the errno. commit 8a98b8f5d3669812e1524cd692e1dd897e5f0ba9 Author: John Wolfe Date: Mon Apr 5 09:01:41 2021 -0700 Change to common source files not directly applicable to open-vm-tools. Add a common function to detect if HyperV is present. commit 761631d7c7d7c0210dafd6f4e4d5281a6d46a52a Author: John Wolfe Date: Mon Apr 5 09:01:41 2021 -0700 Don't follow symlinks in File_Rotate_ByRename(). Delete the directory entries, not where they point to in the case of symlinks. Also, clean up some of the related and similar source code. commit f9821bdf9031eda30bc515b4b869522119684393 Author: John Wolfe Date: Mon Apr 5 09:01:41 2021 -0700 Common header file change not applicable to open-vm-tools. commit 5f14d310fa604a2d6802b76c8bbe48baac7e7b90 Author: John Wolfe Date: Mon Apr 5 09:01:41 2021 -0700 Pre-enabled MacOS 13 (Darwin 22). commit 0c88931b229a0099e6c70cb6eecc83b1b00846d3 Author: John Wolfe Date: Thu Mar 25 20:51:05 2021 -0700 Update ChangeLog with the granular push of Mar. 25, 2021. - plus ChangeLog update of March 5. commit 244e5bad740fa06eb40c48a7973ae8c519106019 Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Common header file change not applicable to open-vm-tools. commit c8c330b4df2878b6b152ac8be4f1bc999febe615 Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Add Arm FreeBSD to the ALLARM set in guest_os.h. commit 2df1c32e009649602f0f3179272107afa2c966b3 Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Clean up the classification information for Ubuntu, Debian, and FreeBSD. Some important information about these distros was not reflected in the macros in guest_os.h. Fixed this. commit 0ec0bb8ec20b45b7b1714701276d377db63acabc Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Changes to common source files not applicable to open-vm-tools. commit 1a6546dfe7e0d4ed572434bd794d94f5228763b4 Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Fix an uninitialized variable issue reported by a Coverity scan of open-vm-tools. commit f06d7cf7225a8c5e2a58fa2bf6a8f5d301964dfa Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Record the assignment of 11.2.6 for a VMware Tools emergency patch. commit a95a56f95b01b3028c72e4da2af7c44fb38a4900 Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Common header file change not applicable to open-vm-tools. commit d26c6dfb4cf8dd0783df79589b3621f87c71071e Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Common header file change not applicable to open-vm-tools. commit f5a922bfd6268ee0690f0aabc03d88bdb781b867 Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Disable NVMe quiesced snapshot by default. Open-vm-tools has no FSS. Enable the feature only when it has been completely verified and FSS is enabled on the host side. commit a58a79da6affce6fc993b0fa18b3d2b718a32d18 Author: John Wolfe Date: Thu Mar 25 20:21:18 2021 -0700 Common header file change not applicable to open-vm-tools. commit 004a5ddc3f79e126a1a14bac0ac5cf53630c833c Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Add RHEL9 to the guest_os_tables.h header file. commit c82f1d9ced8a9c1b13a19256da9d92b64c896906 Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 FreeBSD now supports Arm Upgrade the guest identification code to handle this. commit 4f7441d8cd20923e509ff819084693bbd8c928df Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Fix a memory leak reported by a partner from their Coverity scans. commit 6cda6b456e88c570aac9c3eb8ee1765347e43a27 Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Linux guest identification: Support multiple architectures. Allow machine architecture information to be present in the "short string" and the guestOS string. This is done via a prefix, "-" (e.g. arm-ubuntu-64, riscv-debian11-64, arm-windows10-64) with the X86 architecture being implied (no explicit "-"). Add the recognition of the Arm machine architecture to the Linux guest identification code. commit 3694c7e9071771ccc6690a7f1473206cc21b3452 Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Style change, alignment correction. commit 6e980e3adeed221af11edc3ef66dcb382474642c Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Clipboard logging improvement. Add a log instruction in CPClipboard_SetItem() to print the data size for every format. commit c6b98a52e69488006fef87c63a3cc186ab3d9525 Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Add machine architecture information to os.detailed.data. The detailed data now include information about the guest's running machine architecture. A later change will deal with the guest "short name" (a.k.a. the guestOS string). commit f387d5a2cc4a2221bb4802915e4e432adc1a945f Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Tools gdp plugin updates. commit 5689130bbc010843b718a0691ee3765624beca00 Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Implement log redirection for the deployPkg plugin. On Linux, /var/log/vmware-imc/toolsDeployPkg.log is the default deployPkgs log file. This change allows users to redirect that log to the vmware.log on the host or to another file located on the guest VM. Redirection is controlled by settings in the "logging" section of the tools.conf file. See the examples in the sample tools.conf file provided in the distribution. commit ce844c061dc2c8049d8c6f4c6499848cfa145728 Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Changes to common header files. GuestOS: Begin recognizing Arm in VMware products. commit 49ca4d0632ab5920c45e536883db5154cad2b8e4 Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Stylistic changes to the serviceDiscovery plugin Makefile. Replaced all occurrences of "$(libdir)/open-vm-tools" with "$(pkglibdir)". Split the makefile command lines to fit within 80 columns. commit 807a1167e3bef3f070773ea1d8e2fd812f82cfd6 Author: John Wolfe Date: Thu Mar 25 20:21:17 2021 -0700 Common header file change not applicable to open-vm-tools. commit adaeae034bd8d4fa150700f96f617e40fc22edf1 Author: John Wolfe Date: Fri Mar 5 11:28:17 2021 -0800 Update the ChangeLog with Mar. 5 corrections - plus ChangeLog update of Mar. 4. commit fdc50f3716bd23dd891eccf292741c3f48d342e1 Author: John Wolfe Date: Fri Mar 5 11:19:30 2021 -0800 Added complete LICENSE file to the jsmn.h and jsmn.c source files. commit 7fb7dd20e9b879c4c75eb9349c761ca0f284f9d1 Author: John Wolfe Date: Thu Mar 4 16:41:38 2021 -0800 Update ChangeLog with the granular push of Mar. 4, 2021. - plus Changelog update of Feb. 22. commit 1a13bb349ab93d6861cdb57daf6cec451cca616a Author: John Wolfe Date: Thu Mar 4 16:34:57 2021 -0800 Correct some missed copyright dates for 2021 publication. commit 30a9f295681983c778ea89eef379b8822518e524 Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Configuring OVT with the --without-pam option will implicitly disable vgauth. When no vgauth option is given alongside -–without-pam, a warning is displayed with a message “Building without PAM; vgauth will be disabled.”. When -–disable-vgauth is supplied alongside –-without-pam, no warning or error message is displayed. When -–enable-vgauth is supplied alongside -–without-pam, an error will be thrown and the configure stage will be aborted with an error message “Cannot enable vgauth without PAM. Please configure without --without-pam or without --enable-vgauth.” Github Issue: https://github.com/vmware/open-vm-tools/issues/481 commit edeef6123b1c1edeac42acd4b45f5dab96a8c8d3 Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Common header file change not applicable to open-vm-tools. commit f28bea2dde358e4a12f90f4436d276d9c5e3be77 Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Common source file changes not applicable to open-vm-tools. commit 65d92cd11edafe3e9ff7c96e83d824da6ecf4ae7 Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Tools gdp plugin updates. commit c94ae5a4c7524f0d424ffd0a2cbc0aa685a6a710 Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Common header file change not applicable to open-vm-tools. commit 662f85c3f7d356cfbb8e23dff0a7c4dfa6f74fba Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 tools/vmwgfxctrl: Add a command line tool for controlling vmwgfx. vmwgfxctrl is a small command line tool used to control various aspects of the vmwgfx kernel driver. Currently it can both display and set current topology of the vmwgfx kernel driver. It should be distributed alongside other open-vm-tools binaries. It's incredibly useful when trying to set custom resolution on any recent distro (that includes multi-monitor setups). commit b00709f8f9af26a1fb5803ef22c155b5983086ac Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Change not applicable to open-vm-tools. Windows: Add default setting to example tools.conf. commit e239a31df9563c38ffbc0468deb1018b52334e02 Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 stringxx: Replace usage of deprecated glibmm function Glibmm::RefPtr::clear() has been deprecated for a while and was removed in 2.51. The reasoning is listed in the 2.44 header: "/// @deprecated Use reset() instead because this leads to confusion with clear() methods on the underlying class." reset() has been available since 2.16, so it is trivial to switch to it. commit 44bfc5bc266ae7fc9c8c3df551220942c187c587 Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Common header file change not applicable to open-vm-tools. commit b2f9775cac95500b3ab19ac35bc9d40d48d41d2e Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 PowerOps plugin logging of diagnostic messages on the host. To assist with diagnosis of VM power operations, have the powerOps plugin log messages about guest OS reboot, shutdown, power-on/power-off, script execution, and exit status to the VM's guest.log file on the host. commit c3fad0b7d4f505f22e5606c6587833948f420c7e Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Common header file change not applicable to open-vm-tools. commit 9bdfa71a8d86b7182c0ed2b8ea9e42f6aa0d33e8 Author: John Wolfe Date: Thu Mar 4 13:48:46 2021 -0800 Reduce or eliminate Linux dependency on the "net-tools" package. The "ifconfig" and "netstat" commands are deprecated in more recent releases of Linux. Update the Linux vm-support script to use the "ip" and "ss" commands when available. If Available: Fallback: ip ifconfig ip route route ss netstat Addresses: https://github.com/vmware/open-vm-tools/issues/446 commit 9b2d46f1f36535e7a0838890a151cd63a853f198 Author: John Wolfe Date: Mon Feb 22 10:13:53 2021 -0800 Update ChangeLog with the granular push of Feb. 22, 2021. plus Changelog update of Feb. 4. commit a7f9569f76f4ff05886dc3f4f9b5d3531d87c0ef Author: John Wolfe Date: Mon Feb 22 09:37:00 2021 -0800 Common header file change not applicable to open-vm-tools. commit ff99f1169acc775d2e150f9cd4035c3bbd5eaf02 Author: John Wolfe Date: Mon Feb 22 09:37:00 2021 -0800 lib/file: Deleting a directory tree should not care about missing files Tolerate a directory entry disappearing while a directory tree is being deleted. commit 533d1a6ee716635f0175584e62aaa6a1a115e00e Author: John Wolfe Date: Mon Feb 22 09:37:00 2021 -0800 Common header file changes: additional pre-gcc-4.4 clean up. commit 433270c8dc916aeafd222a55a9bd2a301ac573f6 Author: John Wolfe Date: Mon Feb 22 09:37:00 2021 -0800 Fix miscellaneous Codacy warnings in Tools and VGAuth code. Multiple warnings "The scope of the variable can be reduced" reported by the Codacy static analysis tool have been addressed. commit d0b0527a75c4e265e5e9b21cfa87e9bc40733cb5 Author: John Wolfe Date: Mon Feb 22 09:37:00 2021 -0800 Common header file change not applicable to open-vm-tools. commit 5c27a31bbe54cdff6f53825a163d65e1c559a884 Author: John Wolfe Date: Mon Feb 22 09:37:00 2021 -0800 Adding FreeBSD on ARM64 support to open-vm-tools. Updating the FreeBSD specific sections of open-vm-tools to adjust where necessary for ARM64. The FreeBSD vmballoon driver (vmmemctl.ko) will use the backdoorGcc64_arm64.c when built for ARM64. Pull request: https://github.com/vmware/open-vm-tools/pull/474 commit f3f8353eb2037f84d7f7ed6101086680ec58bdff Author: John Wolfe Date: Mon Feb 22 09:37:00 2021 -0800 Common header file change not applicable to open-vm-tools. commit 51328a83a99526be033774c32ef78934b0a4f6e2 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not applicable to open-vm-tools. commit fb05d52910e9929ed3e23374a2d59bbbd96e4a8d Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not applicable to open-vm-tools. commit 4071ec7e4067f57d3747f2e95a04de23859d1735 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not applicable to open-vm-tools. commit 08b6d1d81dc574a9ddbeead44ea8b72dcf5d4c00 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not applicable to open-vm-tools. commit 05c7fa93f68be1c96badaa596d25c12a6654eed1 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not applicable to open-vm-tools. commit 619df79c8d3661d5609d68419c42a7e9e81463c5 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not applicable to open-vm-tools. commit f200cb67cd75913c0850df7758a3adc5a462a688 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Clean up pre-gcc-4.4 macros Gcc is now "always" at least gcc-4.4 (checked in vm_basic_types.h), which means many conditionals for earlier gcc can be removed. commit 6c116db015bf794f420019aa4210004ebff262fd Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not directly applicable to open-vm-tools. commit 4fa8c3dde624e209af5ecaaeb6ac720d9abfaa81 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Compiler minimums: bump to gcc-4.4 commit cbd0de661501194f0834ff0f8ff215344989ef38 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Fix miscellaneous Codacy warnings in deployPkg plugin code. Multiple warnings "The scope of the variable can be reduced" reported by the Codacy static analysis tool have been addressed. commit 08e78ef8082830191d1be09a0b3a6806bd408c9e Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not applicable to open-vm-tools. commit 649dc72afb024063fc9c5871ee411bb1ad82f45d Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 [open-vm-tools part] Support raw cloud-init data in VM customization. To support this feature, open-vm-tools needs to check whether cloud-init can support raw cloud-init data; then copy the data to the cloud-init cfg directory. commit 39c9113caae0750342ef6049201f6c8976d8535b Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Added 2 error codes for supporting raw cloud-init data in VM customization. Header file updated with errors detected when using raw cloud-init data in guest customization. - cloud-init version is too old to support raw cloud-init data. - cloud-init meta data format is invalid. commit 5bf675afdc2c7d021bdac29f3bebe2d3bbb70c37 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Common header file change not applicable to open-vm-tools. commit bd2c979437f44ecdc5a23a24b3e0afd301a21151 Author: John Wolfe Date: Mon Feb 22 09:36:59 2021 -0800 Remove lib/include/vmware_pack_*.h header files. Previous changes have removed the last usages of these headers; now using '#pragma pack' 100% of the time. commit 0da0823a61677c6140a71a8407acccdf5b4a3de8 Author: John Wolfe Date: Thu Feb 4 10:13:38 2021 -0800 Update ChangeLog with the granular push of Feb. 4, 2021. - plus Changelog update of Jan. 22. commit 38a44105dfc934aded80b38e4cb242daacc2bca5 Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not directly applicable to open-vm-tools. commit 3d114fa0a5c050d1e84d6e73a9942d2e82aa8f00 Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Drop usage of vmware_pack_*.h header files. Both gcc and clang support the Microsoft-style "pragma pack" syntax. commit ff5eb5f448c78448b96f9c3db957d19f0288a9b6 Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 resolution: Fix kms autodetection Currently, the elf binary of the xorg driver is loaded to check for a string that was put in the .modinfo section in the driver. Unfortunately there are two problems with this approach: 1) Distros now ship without xorg, so the xorg .so doesn't exist and there's nothing to check. 2) Distros (e.g. Fedora) do heavy optimizations and remove the .modinfo section from the .so, so the string cannot be found even though the driver exists. To fix both, stop depending on being able to parse the elf binary of the xorg driver. Instead, let the plugin check for the existence of the drm driver with a sufficiently high version, and if it exists, use kms. This removes the dependency on X for kms. Also increase the version of vmwgfx required to ensure atomic mode-setting plus relevant bug fixes (in the kernel since 2017) are available. commit c5b510fded54592eae1c5a4a61f8119f69666a3f Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Add a switch to the vm-support script to transfer the support bundle to the hypervisor The vm-support script unconditionally transferred the support bundle to to the VMware hypervisor, thereby filling vmware.log. This fix changes the default behavior of the Linux and Windows scripts to *not* transfer the logs to the host. Added an option '-x' to both scripts to let the user elect to transfer the guest support bundle to the host. commit f7ddf98958097197468cd153227317cba205a19c Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Add NVMe capability for vmbackup. The vmx/vmbackup logic checks if tools/vmbackup can support NVMe. If it is supported, vmx/vmbackup can further go through the app quiesce process. Otherwise, vmx/vmbackup requests the filesystem quiesce process. commit 61a691368b6e102d939173583e5e08c6ed1673dc Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not applicable to open-vm-tools. commit b797923f9a5e960bb5c2971132d7cac592defc00 Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not applicable to open-vm-tools. commit ce4ad3f984f4926d75888360b58b1b9b5637528d Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not applicable to open-vm-tools. commit e2eb818a1d6d8947bc9c95801f714af202692963 Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not directly applicable to open-vm-tools. commit 056936aea88980f1474daaf34f20aacf34cc39c5 Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not applicable to open-vm-tools. commit 2c10a53bc8c41baaff4f8817d8f35d2808291c3a Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not applicable to open-vm-tools. commit 4e9abe77c7ca725b3cbc70ed0659794a6e54f269 Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not applicable to open-vm-tools. commit 4ab1a9303926a9c50ec099bd9ed2778d02ed7fdf Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Add tools version 10.3.24 to list of tools versions. Document use of 10.3.24 for the next possible release of VMware Tools (tartools) or OSPS for older releases of Linux. commit 3d237b31774e58d637c88047567cf4394d3f8654 Author: John Wolfe Date: Thu Feb 4 09:57:03 2021 -0800 Common header file change not applicable to open-vm-tools. commit 7a830f9330fc9a5599a6d04ad07b0ac6cffcb3c3 Author: John Wolfe Date: Fri Jan 22 12:55:24 2021 -0800 Added in the ChangeLog update comment from Dec 31. commit 5ad6d8f3f627c050e2b58acc916166d09822f221 Author: John Wolfe Date: Fri Jan 22 12:52:09 2021 -0800 Update ChangeLog with the granular push of Jan. 22, 2021. commit c777cf7c2d053948c18fda88bba8e2564c495518 Author: John Wolfe Date: Fri Jan 22 12:39:50 2021 -0800 Correct missing 2021 copyright dates. commit c41a0d7d9f3d9e30b62eb64b30a8cba362edcd59 Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 Common header file change not applicable to open-vm-tools. commit 7a300e61857eeb16174f97eb8f95bb47f2499561 Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 Common header file change not applicable to open-vm-tools. commit 3e5288ecb310ad2cb8dcdce586aaee11abd080ba Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 File_Rotate: Optimize FileRotateByRenumber performance commit f06ab994230b074a361edbd76e29e00a7b3160ef Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 Fix an issue where CustomizationUnknownFailure is generated multiple times on Linux. For Linux, sysimage sends a failure status to VMX when the deploy pkg failed. The tools plugin then sends the failure notice again. Changing the plugin to only send the failure notice for Windows guests where the failure has yet to be logged. commit 61d8c3cfd2d1ed84c6527ae446f543324a341f38 Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 Common header file change not directly applicable to open-vm-tools. commit 41b2a9b1f07e4e1971f7523290c9443d0b251f29 Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 Common header file change not applicable to open-vm-tools. commit 4a9cdfb5190706a8471bf668247011a0725af09c Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 Customization: Set log level to info, not error, for failed /sbin/telinit command The error message of a failed /sbin/telinit command is confusing for customers who might think customization failed. On some Guest OSes, the repeatedly executing /sbin/telinit command can fail while a reboot is happening and the init daemon has been killed. This change sets log level to info, not error, for failed /sbin/telinit command. Note: The first /sbin/telinit commmand failure will fail customization with error 127; this is unchanged. commit ecf07f0bf6cbab57c9e970efa32ca53e6c207aab Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 lib/file/file.c: Use Err_Errno instead of errno directly. commit 741870477774566d0c065ae7f432ecda3e0caafc Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 lib/file/file.c: Fix memory leak Don't continue; jump to ensure string free. commit 5f8671ff14899d34f7abc07550812d5951e927b0 Author: John Wolfe Date: Fri Jan 22 12:25:41 2021 -0800 Invalid file name causes the VMX to crash in log file rotation Parse the log file names without using sscanf. This way no "%" in a file name can look like a valid scanf directive. commit 2b2d31c783c551b25d6a5525c3227d2dc87e64d7 Author: John Wolfe Date: Fri Jan 22 12:25:40 2021 -0800 Common header file change not applicable to open-vm-tools. commit 68853a46e351f6d850973c01762b1188a685001a Author: John Wolfe Date: Fri Jan 22 12:25:40 2021 -0800 Common header file change not applicable to open-vm-tools. commit d37933efb2dacaadc11fd5df8de51d7537bd9306 Author: John Wolfe Date: Fri Jan 22 12:25:40 2021 -0800 Common header file change not applicable to open-vm-tools. commit 69b5354e7df1ab0579f1c25fa2e0cf5414cec037 Author: John Wolfe Date: Fri Jan 22 12:25:40 2021 -0800 [resolution/x11] Preserve the rotation The screen orientation/rotation was being reset on each mode set. In general that is not a bad behavior. But it does break with a fit to window and such as it will continuously reset the user requested orientation. This patch preserves the orientation/rotation on mode changes. commit d65ad41e69517cbd2ef653b30ddcfca528b835c3 Author: John Wolfe Date: Fri Jan 22 12:25:40 2021 -0800 Log file name becomes invalid after a rotation This is because the accounting is done unsigned but the printf used (in multiple places) was "%d". Fix this by using "%u". As documented in the function header, the wrap around case was not handled properly, so this was fixed as well. If the maximum rotation number hits MAX_UINT32, all of the files are renamed to pack the files as if this was the beginning of a rotation sequence. commit 462c995f2deeaa578792b65c22eb082b9f487305 Author: John Wolfe Date: Fri Jan 22 12:25:40 2021 -0800 Common header file change not applicable to open-vm-tools. commit ba3483f293b56d696b962f691fa66fd888cc2964 Author: John Wolfe Date: Fri Jan 22 12:25:40 2021 -0800 Common header file change not applicable to open-vm-tools. commit 937691d51dd93ee8043adc83c24f3b7fe4c25bcb Author: John Wolfe Date: Thu Dec 31 10:16:50 2020 -0800 Update ChangeLog with the granular push of Dec. 31. commit 2ca1201b81d7513cc4d709ae766daf7eb4ae3612 Author: John Wolfe Date: Thu Dec 31 10:12:25 2020 -0800 Correcting missed copyright date updates. Adding 2020 to the copyright of a few files modified in this year. commit 73491aa22b8892784b68ef2b7e285c6d95261fa6 Author: John Wolfe Date: Thu Dec 31 10:12:25 2020 -0800 Common header file change not applicable to open-vm-tools. commit 2d07080e644b2c6f12aae02006eb40adcac2a1ca Author: John Wolfe Date: Thu Dec 31 10:12:25 2020 -0800 Common header file change not applicable to open-vm-tools. commit 64ccc4db5bc5d2aac817af5041fe482e2982c7ed Author: John Wolfe Date: Tue Dec 22 13:01:04 2020 -0800 Update some copyright dates for 2020 publication. commit 2b6aac74cdc34ce88a7ca04aee3bfa4df888f391 Author: John Wolfe Date: Tue Dec 22 12:22:04 2020 -0800 Changes to common source files not immediately applicable to open-vm-tools. Staging source files and changes for a future feature. commit af42d91f5881f1fcec0a902206386f546306dfe9 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 OVT: Build only fuse-based or kernel module vmblocktest programs. The OVT configuration determines whether open-vm-tools will build a vmblock kernel module or a vmblock-fuse user level VMBlock implementation. Both versions of the vmblocktest program(s) are not needed. Linux OVT is only using the vmblock-fuse implementation. Select the version to build based on the HAVE_FUSE setting from the ./configure run. This fixes https://github.com/vmware/open-vm-tools/issues/467 commit 2a6f597bc91b8806601d186ab5be9d219ce01637 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 2a0984da06bd84dc85228368f4a449e53cf04b91 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 4c15a5dd7ea13adee0774298d837fc3e712be910 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 1d8243ee2d6b606f0be546fdaae494229c0714a6 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common source file change not applicable to open-vm-tools commit 2a8f1de3f7ff1d81f45c9a81f06beae95b74af07 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common header file change not directly applicable to open-vm-tools. commit 9b2d29f394066714ac0131c9904c01a5430ce16d Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Changes to a common source file not applicable to open-vm-tools. commit 54d0128fc4ec2f2b256b88ad978b780c696b9c5d Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Corrected a few typos and reworded sentences in tools.conf. Corrected a few typos, reworded a few sentences, added some details for quiescing scripts and removed some duplicates. commit c80f0f3db5df3a055c70949e4c07326f98ac7045 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 MXUser Semaphores - nanosecond resolution wait times The graphics team requested the ability to have semaphore wait times less than a millisecond. This would greatly improve some graphics operations. Since POSIX platforms (i.e. ESXi, MacOS, Linux) support nanosecond resolution for semaphore wait times, a new timed semaphore wait routine with nanosecond resolution is introduced. commit a2396202001370cf37d4cea3087b6a83bcb0cb61 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit bc9196b59469f9269c73d8cca605e7628d6b3d17 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Update copyright date for products to be released in 2021. commit 6284afd17986fe3053fc6d69560d319dacb5299c Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit dec004f0853468937b8e1e7b25f5062c58d131e2 Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 30874008335209a51531a50bc27d05b7fac513fe Author: John Wolfe Date: Tue Dec 22 12:22:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 816f569db5207ffe321372edf75836eb4cff1992 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Common header file change not applicable to open-vm-tools. commit 197124856f619fb303f8bb5f91489c8f6753e0e4 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Change to common source file not immediately applicable to open-vm-tools. GuestStore Upgrade: add settings to the tools.conf file This change adds the GuestStore Upgrade settings to the tools.conf file installed with Tools. Settings are: [gueststoreupgrade] # The guestStoreUpgrade plugin is only available for Windows. # The policy value is one of the settings listed below. # off = no VMware Tools upgrade from GuestStore. Feature is # disabled. # manual = (Default) VMware Tools upgrade from GuestStore is # manually started. # powercycle = VMware Tools upgrade from GuestStore on system # power on. #policy=manual # Time interval for periodically checking available VMware Tools package # version in the GuestStore. # User-defined poll interval in seconds. Set to 0 to disable polling. # Minimum valid value is 900 seconds (15 minutes) # Default value is 3600 seconds (60 minutes) #poll-interval=3600 # VMware Tools package version metadata key to specify a VMware Tools # package version in the GuestStore. # User-defined key for VMware Tools package version. # Default value is "vmtools" which points to the latest version of # VMware Tools package in the GuestStore. #vmtools-version-key=vmtools commit 36519ebbb0c6f14b0d2e56525223938ff4b65595 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Common header file change not applicable to open-vm-tools. commit cad956d8cb6c71f5726fa630602085f90855d56a Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Changes to common header files not applicable to open-vm-tools. commit 6630aeda4ae52007744dbe789e59f0212a5cd818 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Common header file change not applicable to open-vm-tools. commit d70f18262ccf9719f490671d1a2b7b3df57a5336 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Common header file change not applicable to open-vm-tools. commit c504335ff4d11b93d6225a3f68f2faa88fe36f4a Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 The next Windows Server OS is Windows Server 2022 Originally guessed 2021 based on early data, but now Microsoft has provided the official name and date. Update the internals appropriately. Add some TBD markers as a reminder to update the guest identification code once Windows Server 2022 has an official build number. commit f5c38172e4d87342ffd8bf6f3f3e498d98705f5e Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Common header file change not applicable to open-vm-tools. commit 4f55ff374583417645fcf22ceaad8dabbf049f1c Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Update Mac OS related comments: 10.15->11, 10.16->12 Apple changed their naming scheme. commit d8db55524a278f05671bc60fe3691e9edafd85c3 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Changes to common l10n files not applicable to open-vm-tools. commit c38b77280bc273abc07dccdc46c01fd5b7386e18 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Common header file change not applicable to open-vm-tools. commit 7aef446280d018a738d66caafc932f3d5842e43e Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Changes to toolbox-cmd not immediately applicable to open-vm-tools. commit f2a099bb3402c5f15c3b2d23e27703fda32974b6 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Backout previous header file change not applicable to open-vm-tools. commit 36ded5ccac2c86e3accbed54e7930a4eb60723d4 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Common header file change not applicable to open-vm-tools. commit 526156a867563020c90f681030dd697bbfa527a5 Author: John Wolfe Date: Thu Dec 10 19:34:56 2020 -0800 Changes to common l10n files not applicable to open-vm-tools. commit 735b9639a70429a3f0f50bfbd5bdc506999532c3 Author: John Wolfe Date: Fri Nov 20 08:37:31 2020 -0800 Common header file change not applicable to open-vm-tools. commit fbd4f01c7b0e707aba1a2df045dc76fafac3d3a5 Author: John Wolfe Date: Fri Nov 20 08:37:31 2020 -0800 Common header file change not applicable to open-vm-tools. commit 9ea59704795a431c19fafe6e1b4ed4019b601c1c Author: John Wolfe Date: Fri Nov 20 08:37:31 2020 -0800 Common header file change not applicable to open-vm-tools. commit 31fc9ee42b23fbcc482a787572a95d602afbec25 Author: John Wolfe Date: Fri Nov 20 08:37:31 2020 -0800 Common header file change not applicable to open-vm-tools. commit 52bc97aa454ca2140ea62e6421f56c61d6954cf4 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit c9fe171752a499a66d76e64c1333373cfa2bd5f4 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Update wording of user visible messages to conform to guidelines. commit b8d8c9f706558372d19edaa8c3a1ad4518960cd9 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common source file change not applicable to open-vm-tools. commit 2f4cc717102813ffabf8c534e59d690f4af7e669 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit decf8d536e55aa54ccfb64e39599151725cf4b58 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Record use of tools version 11.2.1 for an emergency patch. Update bora/public/vm_tools_version.h with the assignment of version 11.2.1 as a patch for 11.2.0. Also updating 11.2.0 as released and adding the scheduled 11.2.5 update relase. commit 2d51c8c2a7ce103417fb9a85204458099192fa1e Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit de14e31cbd95c3fa847ef4d16dbaebdf97b0be87 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Resolving autoreconf warning caused by recently submitted xferlogs change. commit 242478158e241275a284bcf5e87e26c3585031d7 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit 02b9f17acb8249571b4be15a00f0a7f82d695d4c Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit e82101b0cd6cdaaba8109e6c689f8d6edeb252cd Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Fix propagation of libtirpc flags into build of test source. Starting with glibc 2.32, the Linux libc-dev no longer provides the /usr/include/rpc/rpc.h header. The configure script will detect the availability of the libtirpc package and use the rpc.h header from /usr/include/tirpc/rpc/rpc.h. This fix extends the necessary compilation and linking options to the build of the open-vm-tools services test programs that utilize RPC. Fixes: https://github.com/vmware/open-vm-tools/issues/468 Pull Request: https://github.com/vmware/open-vm-tools/pull/469 commit 3c20d288d6b1348ac5625c9b574db1edac16e8d9 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit 8efe182cdfeb85b7fb6b180a526c465714dd89f5 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit 0e83a002e2b0836634bfcbfcff5dd45168cd25c0 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common source file change not applicable to open-vm-tools. commit bf677ea09702cb9185409dbdd6ca94478dcc7227 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Replace g_key_file() usage in the Vix plugin with VMTools functions. commit d8eb9171431f69f818430699bb9ece67b1d39c76 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit 50b718b2462ef24483bc0e3895a752f784eb64a8 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Adding localized messages for new toolbox-cmd subcommands in development. commit 40c55773a03e552ff13bf0982d78962c7c9507a9 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Remove the pam_securetty.so reference from the SUSE pam configuration file. The PAM config file for SUSE includes a library that is not necessary. This changeset removes the unnecessary library per KB 78521. commit b40b15bce04fb65641fa469b49627f59fe874a69 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit 4ed052eab5972e7c28ba40302c14e229c9e2cac7 Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Changes to common header files not directly applicable to open-vm-tools. commit 24cb1ecb455d9d1e348a2eb2bc7ced692e9f4f6d Author: John Wolfe Date: Fri Nov 20 08:37:30 2020 -0800 Common header file change not applicable to open-vm-tools. commit d37e545258fe051acba22d728aa3d2b2232e0710 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 4b09058fb66e07b2545d779e5aee80e18c02e6ed Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 JSON escape a UTF8 string, plus a general purpose routine. Provide a JSON escape routine working with UTF8 built on top of a general purpose escape routine. commit 1ef815ffcbced6cb22cd7ecf84ee6ca23e20da2a Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 381f8471434b84af40733a60163810734b437b4b Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit e51d9ca883dc892c126ba231ece82d2cc87898e7 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Misc cleanup of "xferlogs" utility. Update the xferlogs usage message to include a 'upd' option, and use glib to parse and print usage. Remove the dependency on the vmtools library. commit 330eb4025c26305e85fc5603dba88cefed261778 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 3cb3c6735d9f90b777765b93b93587ffe1db3a9a Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not directly applicable to open-vm-tools. commit 263fd9cf2c07cf20214a51427b6a9afb14ed0c2b Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not appplicable to open-vm-tools. commit 6cbd023665f07949526f7985d36d15739cf8ca90 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not directly applicable to open-vm-tools. commit f775ee10e6be1714b7fc3cf79037fdca6916a689 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Service Discovrey: Fix a task thread and child process deadlock. Correct argument order in a warning message. commit 4f127053603aeffe722a9441f51529d1819cd658 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 vm_assert.h: Document usage patterns where they're easy to find. This is a formatting and comment change. commit 85004da3412c57a5ca40b6b4b4a087fe4a3e6591 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 807af42f5574a933d7e45c627e2537f1137c1e47 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common source file change not applicable to open-vm-tools. commit dc029b6a3b3e269a13a3a52142411e38ed5e163e Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not directly applicable to open-vm-tools. commit 4dff6fd60f99d79c5fa8739e19c82c8bef21dcab Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit 5f7df88d6bd7d3621a241cb0267b6523d28f9311 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Changes to common header files not applicable to open-vm-tools. commit 004f1603ef72cd4baeb713b1d10ec67490777d5f Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Add a usage message for the "checkvm" utility. This change alters the functionality of the -h option to print a usage message by using glib options. The previous functionality of -h was to print hardware version, which prints invalid results. This change also removes a repeated header file and removes the -r option which prints invalid results. commit 2614ce5bbf473c3df03f35d68cd8eceee8dbbf98 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Common header file change not applicable to open-vm-tools. commit c27a6eac336305d36ee2fba7c192e5d0ea4bf0e4 Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Change the default Unicode error errno. In times long past, EINVAL was chosen for the errno returned when a Unicode problem was detected. This overloads EINVAL, particularly when using POSIX system calls. Unfortunately, the overloading makes it very difficult to recover from some errors as there is no way to know the difference between a "real" EINVAL and a Unicode problem EINVAL. Over 10 years of data shows that we *RARELY* encounter Unicode errors. Inspecting the source base shows the code segments that do check for errno after an error either: 1) Post the errno value and die. 2) Have switch handle cases but also have a default catcher. 3) Have an if/else waterfall with a final else. Another observation is that Unicode routines are not involved with anything that would return a math related errno (e.g. ERANGE, EDOM). Changing the value of UNICODE_CONVERSION_ERRNO to ERANGE and avoid any overloading. commit d35ef560247e7f0bd798ae45646eeaee38d3a12b Author: John Wolfe Date: Mon Nov 9 12:29:03 2020 -0800 Changes to common source files not applicable to open-vm-tools. commit e47338fd721f3393823d778e487ee3c937594311 Author: John Wolfe Date: Mon Nov 9 12:29:02 2020 -0800 Common header file change not applicable to open-vm-tools. commit d6ba5ae8996e44e52c9ee967c6d44036fa2eba92 Author: John Wolfe Date: Mon Oct 26 17:29:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit a4c1458c67a291c2a2d69d2a7f829daac00face1 Author: John Wolfe Date: Mon Oct 26 17:29:55 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit 727a554c3d44ae615e23361a450ccfd793198019 Author: John Wolfe Date: Mon Oct 26 17:29:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit e18e67f727d0354b08a55b685178fd05f542c6da Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Fix memory leaks. A Coverity scan of open-vm-tools reported a number of memory leaks on error code paths. Fix seven reported leaks, and modify code to address two false positives in order to make the code clearer and/or keep Coverity from reporting the issues. Also fix additional leaks found in the routine Proto_TextContents during code review. commit bf3a15812b587bc46f79f8ca97253d7a867456d5 Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit 646eaa37a982d4f665443b6a017f8d420fc80546 Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 tools: Fix Coverity errors in resolution plugin. Fix multiplication overflow and fgetc usage to avoid Coverity errors. commit 1548fae0093271462d23bb5d66eb9c2e6521fece Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Fix a memory leak in HgfsOplockMonitorFileChange In the error case, "data" was not freed. commit 2bb9aab991f787cf07941d6c76812c089ea830ab Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit 90aeb31d98be541fdd2324e97160cef7abad93cf Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Terminology cleanup commit 23e7479ca368d392395499a3db192c97112a156c Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Common header file change not applicable to open-vm-tools. commit 8bc0c0b8e3274cbfacb4ab1ace1a1fb644b66c64 Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Common header file change not applicable to open-vm-tools. commit 26fc16779ffbce1833ea90d1d5efdba83708bb87 Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Update vm_basic_types.h for apple silicon Apple silicon compilers will define __arm64__ as their name for their new CPU. But they also define __aarch64__ which existing 64-bit ARM CPUs use. Add a little bit of logic to enforce and document this. commit f73fa790abde3fe385cca37ed8583073eea36b7f Author: John Wolfe Date: Mon Oct 26 17:29:54 2020 -0700 Common header file change not applicable to open-vm-tools. commit b924451d819b646f2c25b873682c35937856dd1e Author: John Wolfe Date: Mon Oct 26 17:29:53 2020 -0700 Common header file change not applicable to open-vm-tools. commit 75aabacdb096aa39252a14cf9ecbb11d7539369b Author: John Wolfe Date: Mon Oct 26 17:29:53 2020 -0700 [GlobalConf] Support for vmusr service to load Global Configuration. Currently, the vmsvc service periodically downloads the Global Configuration from the GuestStore and applies the downloaded configuration. 'vmusr' service doesn't have the support. In this changeset, made the changes for both vmusr and vmsvc services to periodically check and apply the changes. To keep thing simple and easy, the new approach is check the modification time every time the regular tools conf is read and if changes are detected, the configuration is applied. With this new approach, signalling mechanism is not needed and that code is removed. vmsvc: * Starts a background thread which periodically fetches the global configuration from the GuestStore. vmusr: * No background thread is created. But checks and loads the configuration everytime the regular tools.conf is checked. commit 00531302d7e56bddaa037e5e4ae006135a34cca8 Author: John Wolfe Date: Mon Oct 26 17:29:53 2020 -0700 Check in tools gdp plugin OVT installer code. commit d3ed2aebcb5b33581ad49f85e41e6fa0eca98738 Author: John Wolfe Date: Fri Oct 16 21:03:23 2020 -0700 Get the latest README.md from the stable-11.1.x branch commit eae2394df5fc0856c4bc4133c569e13f5e327efb Author: John Wolfe Date: Tue Oct 6 14:30:56 2020 -0700 Common header file change not applicable to open-vm-tools. commit b76c75ae9a48e68e55412d0fd97f238a66409ea0 Author: John Wolfe Date: Tue Oct 6 14:30:56 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit b966cb3822b3a8cb9815af6f2da46f8f367b58cd Author: John Wolfe Date: Tue Oct 6 14:30:56 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 99d5a9ea8605ad5ce085f109d4e3d378bf327db4 Author: John Wolfe Date: Tue Oct 6 14:30:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit fd75f811c8d09b662ee78f072d90ec6c915fcec6 Author: John Wolfe Date: Tue Oct 6 14:30:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit c1f88125233b074398bb6ba38d7b5c2ae19e7085 Author: John Wolfe Date: Tue Oct 6 14:30:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit ece245c662d28b3880eb0ee40e8c427a2aafe4c8 Author: John Wolfe Date: Tue Oct 6 14:30:55 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 695d2fab5c8a036b8b7584877fb490bf505c178b Author: John Wolfe Date: Tue Oct 6 14:30:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit 84d87f789f8d93e5d265afe4288a6111c90341c4 Author: John Wolfe Date: Tue Oct 6 14:30:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit 48e96c64a3a51b9bca2dd7614b1c7a04cc4dbb1d Author: John Wolfe Date: Tue Oct 6 14:30:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit 49103fbe71707b99323c996a23ec22fde5cb1438 Author: John Wolfe Date: Tue Oct 6 14:30:55 2020 -0700 Common header file change not applicable to open-vm-tools. commit 08333afefd17ac7617ba5d4b1e3f087cccd97056 Author: John Wolfe Date: Tue Oct 6 14:30:54 2020 -0700 L10n drop for open-vm-tools 10.2.0. commit 6cbee265af33370fe41a47db63c90cfd52ecdba4 Author: John Wolfe Date: Tue Oct 6 14:30:54 2020 -0700 Common header file change not applicable to open-vm-tools. commit a869ed128c313d6335316fa10ebfbe15ace2be73 Author: John Wolfe Date: Tue Oct 6 14:30:54 2020 -0700 Common header file change not applicable to open-vm-tools. commit b6f81f00fcfbc602838b48feca9f85da2847cf59 Author: John Wolfe Date: Tue Oct 6 14:30:54 2020 -0700 Common header file change not applicable to open-vm-tools. commit 66eb1b16e7cea8399c67d71eee45acd015e12a49 Author: John Wolfe Date: Tue Oct 6 14:30:54 2020 -0700 Adding the vgauthImport utility to open-vm-tools. The vmware-alias-import utility is not currently packaged with the open-vm-tools bundle; this change adds the utility. It is built only if vgauth is enabled. commit a021b598a61aadccd7da931c7ab717312ca03c0f Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Fix the exit code when toolbox-cmd disk shrink is canceled. The toolbox-cmd disk shrink operation was exiting with status 0 when a SIGINT is received. A non-zero exit status is expected. Change the exit code to 130, which is the appropriate value according to TLDP: https://tldp.org/LDP/abs/html/exitcodes.html commit 985c9a0ea8e4ff00d5cfbadbb0397c12a8ec0240 Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Common header file change not applicable to open-vm-tools. commit 81aff3a41e14b4aaae285bebb95cc6545a600c77 Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Fix memory leaks in guestInfo/diskInfo.c. When checking for IDE, SATA and SAS disk drives, the glib GMatchInfo is passed to a g_regex_match() function inside a for loop. It was not properly passed to g_match_info_free() before subsequently being reused. This addresses https://github.com/vmware/open-vm-tools/issues/452 commit 1c5d9dbbd3c19eb135633f9fefc47c654eacde76 Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Common header file change not applicable to open-vm-tools. commit 30c87d05d1bb654b2bc37f482c779961bdb20506 Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit 457adfe51c0e03610705d32b0fb5cba55deb1304 Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Common header file change not applicable to open-vm-tools. commit cd6824eb5014508f479bb8deda86529bc5a21e79 Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Common header file change not applicable to open-vm-tools. commit 9338c579fba6ee1f8d3a50df63f67cec7785d71b Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Common header file change not applicable to open-vm-tools. commit 5ba9b23033f6500570f6a706aee18477c72039ac Author: John Wolfe Date: Tue Sep 22 14:54:07 2020 -0700 Common header file change not applicable to open-vm-tools. commit 77c30381461404f2b9468edfd6d010f36183f3ca Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit 65fd0bf725a223d31d09c249675a5e1d1eb5dabb Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit 3267a1eb6964a4bb35806d1a117531b3a4119c9d Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Common header file change not applicable to open-vm-tools. commit cd53ce69a494ac0929523010f768a03e4cafec24 Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Common header file change not applicable to open-vm-tools. commit c86819a35d2a64a47bc846eeb8083a0dbd18b742 Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Common header file change not applicable to open-vm-tools. commit d6d96d1c7e53ea53affacb538342857d688a7aa1 Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Fix a minor memory leak in VIX Listfiles(). The GError structure is not cleared in an error code path, which leads to a minor memory leak. Explicitly call g_clear_error(). commit af4e12648002f9ac4fdcc50a3aa04dddbaf5398b Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Common header file change not applicable to open-vm-tools. commit c7b7ff477ca923833deebed645fec6b1612d4c5a Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Changes to common header files not applicable to open-vm-tools. commit ee09d506dac785a790e78b0e0dca0b99f447c694 Author: John Wolfe Date: Tue Sep 22 14:54:06 2020 -0700 Common header file change not applicable to open-vm-tools. commit bc811a0fcd6b80082fc7f513928e9c448e7bf46b Author: John Wolfe Date: Tue Sep 22 14:54:05 2020 -0700 hgfsServerOplockMonitor.c HgfsOplockUnmonitorFileChange(): There is no need to cancel the monitor action if the oplock monitor module has already been destroyed. Avoid a possible NULL pointer dereference. commit 49c898507badc4d19e17a5e3230116505aa58f93 Author: John Wolfe Date: Tue Sep 22 14:54:05 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 2d3a1ce819c86360cf00c7a3352c501674daaae1 Author: John Wolfe Date: Tue Sep 22 14:54:05 2020 -0700 Common header file change not applicable to open-vm-tools. commit ce5044577a89c0a66f4b427067c2843f4094044b Author: John Wolfe Date: Tue Sep 22 14:54:05 2020 -0700 Update the development tools version for the next major point release. commit ea2e57b14f0b4b063556fda617829ad1320d8565 Author: John Wolfe Date: Tue Sep 22 14:54:05 2020 -0700 Common header file change not applicable to open-vm-tools. commit 97582346292959b5b4d125485ab7cf9747c1c391 Author: John Wolfe Date: Tue Sep 22 14:54:05 2020 -0700 Fix a potential null pointer dereference in asyncsocket. commit 9a3f9c925037fc7cba45761c6fcae762ded0668d Author: John Wolfe Date: Tue Sep 22 08:20:25 2020 -0700 Captured the "devel" change log history since the start of the "stable-11.1.x" branch. ***** Created the "stable-11.2.x" branch at this point. ***** commit 19d12e9a038a1835155ae26631b9a34d5a54cfcd Author: John Wolfe Date: Fri Sep 11 12:11:06 2020 -0700 Common source file changes not applicable to open-vm-tools. commit 5e0117e5ac8620ee00906fb9f070e92ac6a15baf Author: John Wolfe Date: Fri Sep 11 12:11:06 2020 -0700 Changes to Common source files not applicable to open-vm-tools. commit e71f137295a2aa94931369060a08a9fd6c1dde33 Author: John Wolfe Date: Fri Sep 11 12:11:06 2020 -0700 GuestOS: Add Flatcar Linux (64-bit only) as a new guest. commit 53c5a3a8cb653031d3efa8009274b2b96c84ce25 Author: John Wolfe Date: Fri Sep 11 12:11:06 2020 -0700 Common header file change not applicable to open-vm-tools. commit d93e52f060d979baea5bcb63fac62a32a276becf Author: John Wolfe Date: Fri Sep 11 12:11:06 2020 -0700 Common source file change not applicable to open-vm-tools. commit 6c40ef8aa76485edbc322711cae34cb75df56d2a Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 hostinfo.h: stop including x86cpuid.h With the removal of Hostinfo_GetAllCpuid in an earlier change, hostinfo.h can stop including x86cpuid.h and only needs vendor IDs from x86vendor.h. Unfortunately, quite a few source files depended in hostinfo.h's automatic inclusion of x86cpuid.h. Fix them to include what they need. The lib/include/guestStats.h is a special case that happened to succeed because of a warning that was disabled in x86cpuid.h which also happens to have been included earlier than this header. Re-disable the warning. commit 1f66f283c20f7f5cd154ca34c33e3e145659916a Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Ensuring vmtools utilities are only used in a VMware virtual environment. Several utilities do not check that their running environment is in a VMware hypervisor. Add checks and generate error messages if the running environment is a physical machine. Some makefiles were altered o resolve dependency issues. commit 6f78dd5ce2733ea964fe969cb739daa55e329e70 Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 VGAuth: vgauthd service fails if vgauth.conf samlSchemaDir has trailing whitespace When reading the vgauth.conf samlSchemaDir, remove any trailing whitespace. Also remove trailing whitespace when reading any preference string. commit e6b3847d7bd9b811faff47126da72436d0e69ea2 Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Additional clean up of vmware_pack files. commit 1cb3b54c545608fff271ca076b832c991a9316fb Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Updating authors for OVT contributions https://github.com/vmware/open-vm-tools/pull/432 commit 098d213d1db4b4bb22823036cca7f3bc6f06af71 Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Changing permissions of tools configuration example file. Also made a small change to another makefile for more consistency in style. commit 6ef9d2fb20c127d633210b4537848021b1840013 Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3b5f6264e905911ed87196cd49eec8387205da1e Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Common header file change not applicable to open-vm-tools. commit 46c324e50081f63b12890cae9f0a9147805cdbee Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Additional clean up of vmware_pack files. commit daa348acc12b0c24075276874c03d97acd2d247e Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Additional clean up of vmware_pack files. commit fdcc1ae11383e627ba624dc06c94d2ea0b62032f Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Additional clean up of vmware_pack files. commit 8cb221c581abe6a905ebd348d32cc3ecb6cabb93 Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Common header file change not applicable to open-vm-tools. commit c2553fbd4906f47984f01f11a208fea742683a5a Author: John Wolfe Date: Fri Sep 11 12:11:05 2020 -0700 Change to common header file not applicable to open-vm-tools. commit c161dcb11d061c6bd4ef3c5aa563b15b13167bdd Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Common header file change not applicable to open-vm-tools. commit 4da428cb1bbea7a5e1e9da2df40d410ca557f63f Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Back out earlier common header file changes. commit 7903a7eaee51685e70abfd7c227d1828c34e9373 Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Backout the previous header file change. commit ccba10c950c5a5a30c884c6ad3f5b2e71add5b09 Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Common header file change not applicable to open-vm-tools. commit 27ef6c9deabdc9fe31de7b4f5da02a4408463410 Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Changes to common header files not applicable to open-vm-tools. commit 2e5c40274f3f09d95084dafc9608123bf59f80b7 Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Replace a bogus URL provided in a vmcheck.c error message. Previously the URL "http://www.vmware.com/info?id=99" appeared in an error message in the vmware_checkvm binary to refer to VMware Tools updating information that may change from one release to the next. That information is now available from the single VMware Tools URL" https://docs.vmware.com/en/VMware-Tools/index.html. commit fe7c6ebcd1fdf3e25246c7e1725063f8c4978db3 Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Get rid of more vmware_pack files. gcc supports the Microsoft-style "pragma pack" syntax. Standardize on it. The conversion is somewhat non-trivial, as gcc requires "pragma" to be before or after a statement, not in the middle. commit 055fed60e4f1a545e923c2aa0c14f5ecdb53b6ab Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Common source file change not applicable to open-vm-tools. commit 3afc566751b7d151b2adb75703b5dfc10bff2237 Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Log Facility: Infrastructure changes for module level filtering Additional changes to log.h and loglevel_userVars.h commit 0516ef4a9a98f435aa3fbf20be43fc9581b34115 Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3a10aafdeaac5c708d951e122bba816d9574b2be Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Remove PANIC() macro in favor of Panic() or VERIFY() commit 54d36be9679eec0971a31d5b608bb51ecb07dd25 Author: John Wolfe Date: Fri Sep 11 12:11:04 2020 -0700 Record usage of VMware Tools version 11.1.6 commit 90ac21d93e9159582865955c83d47676db2ea34f Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3df677d2ba3b4ddefc81c0ae0e381c782c81bbb6 Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Changes to common header files not applicable to open-vm-tools. commit 652aeafa2cee7893b66f73f3096077232e6dce93 Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Adding null check for results passed to log function. In several files, replies/results from RPC functions can possibly be null if the function fails. This changeset adds a function-like macro which does the null checks and is applied to the replies when passed into logging functions. commit 31e14a2def83c8cf4450543c042c61a5e811eada Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Ensure the servicediscovery plugin isn't enabled in an open-vm-tools build for non Linux OS. The servicediscovery plugin is supported only on Linux platforms. This change checks that this plugin is enabled only if the OS is Linux. Otherwise, an error message is printed. commit be533613b3efdc8f78f6762aa31574173443e7e8 Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Tools consumes loglevel_user.h Adding lib/include/loglevel_userVars.h. commit 5a9242dd13e229929e1c1dbe6a872b4c0e9e3361 Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Split out the log level defs from the log level vars. This way the Log Facility can use the same name space as LOG for its domain specific level filtering by including loglevel_userVars.h directly. commit 3fbb1d39f298f37248ec9690f08c550872846940 Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Backout the previous log level defines change. commit 34a64c375ee0a16db7e1f85f358c90d12815dac2 Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Split out the log level defs from the log level vars. commit 606ed341010cec4a3c32233ba47e88aca9eb7b4d Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Get rid of vmware_pack files (devices edition) gcc supports the Microsoft-style "pragma pack" syntax. Standardize on it. The conversion is somewhat non-trivial, as gcc requires "pragma" to be before or after a statement, not in the middle. commit 2174f3237b58391e9155e37895ef63c0043b0b35 Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 vm_assert.h: Remove unused PANIC_BUG commit 42af202affbf0cc2bb533dd430933bf5ee2ce247 Author: John Wolfe Date: Fri Sep 11 12:11:03 2020 -0700 Swap out Log+PANIC for Panic Just call Panic with an appropriate string instead of a Log+PANIC. commit e61fbb2ebeb701063ec1e1362d7e1b19695ba183 Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 LOG: Keep the LOG_LEVEL entries sorted This is the first in a series of changes to the Log Facility that will add the ability to have domain specific filtering (e.g. foobar domain can have log calls which are filtered by domain (name) and level). This will make LOG like abilities usable in all build types, even a release build. The LOG_LEVEL entries are difficult to find since they are in a jumbled order. The existing grouping isn't useful as many of the modules are shared. Create one big sorted list. commit 16f81450b4820a4634dfefbaea222dda161e445c Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit d2404fe3a2dfc88b118bd8dcf3655a960b52c822 Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 Common header file change not applicable to open-vm-tools. commit 31542efae6854d989d51b5d4c3333d3baa43dfc8 Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 Removing unnecessary code from rpc header file. Several macros related to VMDB are no longer needed in the guestrpc header file. This change deletes those unused macros. commit 0bb2d1599b4a29486aef2d4bced25992a99154cf Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 Improve the logging for deployPkg in a few workflows When executing Perl script in Linux Guest OS customization, log an error if the execution fails. commit 1c3925b3078008ff48b2c89c1ed080c583aba840 Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 Add --cmdfile argument Some OSes (Windows) have a relatively small cmdline limit. Expose a cmdfile argument which works like --cmd, but reads the input from a file. This allows RPCs which can have huge arguments (guestVars, namespaceDB, DataSets) to work. commit 00d5ee23bdbbc01ac7eb326715ae7a98c0acdd06 Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 Common source file change not applicable to open-vm-tools. commit 248ef2c5361a0a8a7e4bed9cafec50598a313899 Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 Fix a stack-use-after-scope issue in FileLockScanDirectory. commit 504e2b8021b5c1e51c7f208c11acaac444531feb Author: John Wolfe Date: Fri Sep 11 12:11:02 2020 -0700 Common header file change not applicable to open-vm-tools. commit 79790f72cac52853dba8abba51e51226dad721f0 Author: John Wolfe Date: Tue Aug 18 07:46:26 2020 -0700 Update copyright dates. commit dd54c97c7aca69dda041e82fd1a62a836c20db4f Author: John Wolfe Date: Tue Aug 18 07:14:12 2020 -0700 Remove the guestApp.h header file that is not needed in conf.h The configuration header file conf.h includes the guestapp header file guestApp.h, but there are no related references to the guestapp header file. This change removes the unnecessary header file. The guestApp.h header file is included in the few source files with a dependency on it. commit 1b7f86e63a4a03170de159aa719c5e5be7e2dcea Author: John Wolfe Date: Tue Aug 18 07:14:12 2020 -0700 Including appinfo and servicediscovery settings in configuration file Adding the default configuration settings to the tools.conf sample. commit 45d0a2d16b5fb25ec11df8e9f75000917e279c22 Author: John Wolfe Date: Tue Aug 18 07:14:12 2020 -0700 Common header file change not applicable to open-vm-tools. commit 093fcc60b980a6d48e9e3ed2156e79c6a6790f99 Author: John Wolfe Date: Tue Aug 18 07:14:12 2020 -0700 [HGFS Server] Add file attributes/symlink check status cache using oplock support An investigation found that while copying a group of small files from host to guest using the shared folder, the HGFS_OP_GETATTR_V3 message was handled in HGFS server 276,140 times over a period of ~35 seconds. Caching the file attributes in HGFS on the server-side can reduce the time significantly (from experimental results, 35s => 8s). It was also discovered that Posix_RealPath is called repeatedly to check whether a path is a symlink, since HgfsServerGetLocalNameInfo is called when handling a series of requests. Integrate a key-value cache to HGFS server to cache the symlink check results and file attributes, using the file path as the key. This task will be divided into multiple change: 1. Add oplock support 2. Add a customized LRU cache in HGFS server for file attributes and symlink check results - New files: hgfsCache.h/c: implements a customized LRU cache which is built by combining two data structures: a doubly linked list and a hash table. - The cache will be allocated only when oplock is enabled. - The cache relies on the file change monitor provided by oplock to ensure there is no stale data. When adding an entry into the cache, also register the file change callback to oplock. Upon receiving the file change callback, invalidate the cache. Once the cache is full, remove the LRU entry and unregister the file change callback for it. commit e860f4aaaac89aa0043a948ae79ac1b2a8dab6b4 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Change to common header files not applicable to open-vm-tools. commit fac536ee236d87e779a323bc99e6f5c66550abf8 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit f7ac1c4b756bc8a0b4b248299f725df773858695 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Common header file change not applicable to open-vm-tools. commit 07b065dbceadc6968f9b145dcef13a9fdfde1587 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Define "Unknown Command" Macro to replace hard coded strings in rpc files This changeset finds all instances of the hardcoded string "Unknown Command" in a few rpc files and replaces it with a macro defined in a shared header file. commit 468fcf407bd71983cca6652d71547099772f37f6 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Changes to common header files not directly applicable to open-vm-tools. commit bab170d03516705690ec347ba4c0ffbf5338f42a Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Changes to common header files not applicable to open-vm-tools. commit 2f11b89440dfb80a8b3a8ff1b343642367b2491b Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Fix log recursion issue in DestroyRpcChannel() Avoid calling g_xxx() logging routines in any function directly or indirectly invoked from VmxGuestLog(). Change the g_debug() call in DestroyRpcChannel() to a Debug() call. commit 46808762d89d92cdb2d2d382ff01227bdaf99f49 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 7ea7359bcac3bab10db4d568156ccc9c7849ef40 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Remove #include for headers that are not needed in serviceDiscovery.c file. commit 697e20320ee71b8feb248582ccf0100b919f5b32 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit e70b82a46f92f8094d321a44f5402de1686f22b2 Author: John Wolfe Date: Tue Aug 18 07:14:11 2020 -0700 Removing windows header file which is not needed for OVT build Changeset deletes code which references a Windows specific header file and cleans up some whitespace. commit 95f424ea52f3a674a3d3181759cb1fbf7315b315 Author: John Wolfe Date: Tue Aug 18 07:14:10 2020 -0700 Adding vmtools library dependency to deploypkg library Some functions are not found in shared libraries when linking, which generates several warnings. Added a library with the needed functions to the list of dependencies. commit cfbb787aa6c14ed71314b848fde915dc40fb8055 Author: John Wolfe Date: Tue Aug 18 07:14:10 2020 -0700 Backout the previous common souce file changes. Restore files to original state commit 78871a8b52d44aa4211890e4e7dadac31a56fe97 Author: John Wolfe Date: Tue Aug 18 07:14:10 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 98ac6d11bd48531c138f2fa82d70e71ec848a515 Author: John Wolfe Date: Tue Aug 11 21:26:23 2020 -0700 Update the copyright commit 32e653c935977b511470fafccb3cddcdb566df85 Author: John Wolfe Date: Fri Aug 7 12:03:26 2020 -0700 Backout the previous common souce file changes. commit f08d6f6d9a2cefe2f5a24fbe6836362c6fddde23 Author: John Wolfe Date: Fri Aug 7 12:03:26 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 09c15cc2d69d00799361b1ffc3b87550377b5f31 Author: John Wolfe Date: Fri Aug 7 12:03:26 2020 -0700 Common header file change not applicable to open-vm-tools. commit 62896f05bb22a2217851dc5dda59d0605e76d2bf Author: John Wolfe Date: Fri Aug 7 12:03:26 2020 -0700 Address some Log spew for toolsdeployPkg.log 1. Remove the extra '\n' at the tail of logging messages in imgcust. 2. Update the log printting function, do not add '\n' if the original log message has already included it. commit 9cbda48c6a5b778b30db123d621c358a15d215bf Author: John Wolfe Date: Fri Aug 7 12:03:26 2020 -0700 Add copyright header to service discovery scripts commit 3aef7599dc3ea7468149be55d9ed5c3bbcb6061b Author: John Wolfe Date: Fri Aug 7 12:03:26 2020 -0700 common header file change not applicable to open-vm-tools. commit 1eb8a82ac5e2f493ad23caf67e9bab8fd4cd3802 Author: John Wolfe Date: Fri Aug 7 12:03:25 2020 -0700 Common source file changes not directly applicable to open-vm-tools. commit d2c7b255e902fcced1b60d30ff472d88595613ea Author: John Wolfe Date: Fri Aug 7 12:03:25 2020 -0700 Common header file change not applicable to open-vm-tools. commit a65b1788534991fa3989a3a65942e944588df897 Author: John Wolfe Date: Fri Aug 7 12:03:25 2020 -0700 Common header file change not applicable to open-vm-tools. commit 8dc74b22555398fbea5a7895914a910411909803 Author: John Wolfe Date: Fri Aug 7 12:03:25 2020 -0700 Updating the copyright date on a few files. commit bddf9cdc61846cf9d6e8f36585dcdc0b39339beb Author: John Wolfe Date: Fri Aug 7 12:03:25 2020 -0700 Resubmit the gcc baseline to 4.1 bump. commit 563ab298de4a7d25355fd7768542b655660e22b9 Author: John Wolfe Date: Fri Aug 7 12:03:25 2020 -0700 Backout the previous gcc-4.1 enforcement. commit 57b3aa2a537fc1a7d5c6e04cdbbcb39e472f38af Author: John Wolfe Date: Fri Aug 7 12:03:25 2020 -0700 Bump gcc baseline to 4.1 commit ac7098903f510f69b8aefdd9ae2625f691389ba8 Author: John Wolfe Date: Fri Aug 7 12:03:25 2020 -0700 [HGFS Server] Support oplock inside HGFS server for Windows host Missed two source files for previous HGFS Server changeset. commit 31978d3150e9730e75266689e18404f49430ca44 Author: John Wolfe Date: Fri Aug 7 12:03:24 2020 -0700 [HGFS Server] Support oplock inside HGFS server for Windows host The motivation for this change is to cache file/directory related information in host side, for example the file/directory attributes. To make the cache correct, we will use the oplock(Windows)/lease(Linux) to monitor the file/directory change event. When the file/directory changes, the item in cache will be invalidated. In this change, two new functions are defined: - HgfsOplockMonitorFileChange This function is used to monitor the change event for a file/directory, and the callback will be called if file/directory is changed. - HgfsOplockUnmonitorFileChange This function is used to cancel the change event monitoring. This patch only implements the oplock support for Windows host, the support for Linux will be delivered in another patch. commit 3b40aceb52c8fd2b001c0b5aa192018fad3fa2c1 Author: John Wolfe Date: Fri Aug 7 12:03:24 2020 -0700 Common header file change not applicable to open-vm-tools. commit 6757870e37708413ea005c5790f292f1115b12ec Author: John Wolfe Date: Fri Jul 31 13:36:35 2020 -0700 The new table driven guest identification code did not handle Red Hat properly. It needs to be checked for before Enterprise Linux. commit 17f34b99fcde4d7f1a5dd26e766c502dc804a2db Author: John Wolfe Date: Fri Jul 31 13:36:35 2020 -0700 Changes to common header files not applicable to open-vm-tools. commit 623f1d057fd552a2a20110c8f2ad2e00ec01b0ad Author: John Wolfe Date: Fri Jul 31 13:36:35 2020 -0700 Common header file change not applicable to open-vm-tools. commit 6578e6a740a027e8957b8af1442277feba022ef9 Author: John Wolfe Date: Fri Jul 31 13:36:35 2020 -0700 Remove duplicate global definitions. Remove duplicate and unused global definitions for GDK_SELECTION_TYPE_TIMESTAMP and GDK_SELECTION_TYPE_UTF8_STRING. This fix will address https://github.com/vmware/open-vm-tools/issues/451 commit bd2b5b4a8dfa4f449cc0afa4262e28bb4db06714 Author: John Wolfe Date: Fri Jul 31 13:36:35 2020 -0700 Changes to common header files not applicable to open-vm-tools. commit 012ae95c08eaba8c46152422a23a2a82ff330f0c Author: John Wolfe Date: Fri Jul 31 13:36:35 2020 -0700 serviceDiscovery: Double quoting script variables that might contain whitespaces. commit 6908a9f51956ef77c5e7a45d42ab09c3aba2c818 Author: John Wolfe Date: Fri Jul 31 13:36:35 2020 -0700 Update to the tools.conf sample file not applicable to open-vm-tools. commit 3d311af531f06e7de255b51534818dcf777c81b7 Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 Common header file change not applicable to open-vm-tools. commit 96daffa492eee5aa9e5ad03f1b67c17e5ccfae42 Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 Common header file change not applicable to open-vm-tools. commit e6927bc3ac49fec1241bbf78cb35158553bab400 Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 Common header file change not applicable to open-vm-tools. commit 631280670bd5e0f50c2ece8ea43cc01c8586eb46 Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 Changes to common header files not directly applicable to open-vm-tools. commit c275d66d52a532ddae5ca0bfe4b1af7f71209524 Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 [Coverity] Remove superfluous condition in if statement commit 45b48c92746b4151b1eb118efdbfcb045cb4b97e Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 Rewrite Linux guest shortname identification Replaced guest identification with easy to maintain tables as well as added general table search abstractions for easy maintainability. commit 9e70e3db1038b2703b7c0e9d5e12afad1407e95c Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 GOSC event doesn't report at once after customization process timer is reached When process timer is reached, the command process is killed and function ProcessRead is called to read all the output till EOF. But EOF can't be reached immediately. The reason is pre-customization script is launched by perl script, and killing perl script process doesn't kill the pre-customization script process. This code update includes: 1. Do not read stdout/stderr when gosc command process exits abnormally to avoid the EOF blocking. 2. Add READSTATUS_PENDING_TO_EOF in enum ReadStatus to avoid the confusion with READSTATUS_PENDING. 3. Close the write ends of pipes (stdout[1]/stderr[1]) for child command process before it exists. 4. In processPosix.c, the write ends of pipes have been closed in line 180, 181, so the read ends should be closed in line 254, 255. 5. Add explicit note for the beginning and the end of the perl script log. commit 641874bfb831fc63e8ea289ee00d12d67734285e Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 Common hesder file change not applicable to open-vm-tools. commit 534f6bcbdda25bc9999c306cdd0d8e3e89f8f95c Author: John Wolfe Date: Fri Jul 31 13:36:34 2020 -0700 Common header file change not applicable to open-vm-tools. commit f1625fd8cad09739da8e67c952c27bdd425e096b Author: John Wolfe Date: Fri Jul 31 13:36:33 2020 -0700 Common header file change not applicable to open-vm-tools. commit 44ad3675a33b804dd262bfab3279410aff442bcc Author: John Wolfe Date: Tue Jul 21 11:53:01 2020 -0700 Fix memory leak issue for "vmtoolsd" binary on receiving SIGINT or SIGUSR1. Valgrind complains of a memory leak issue on receiving SIGINT or SIGUSR1 signal, because we lost call to RpcIn_Destruct(chan->in) in RpcChannelTeardown(). It just happens to be released only at service shutdown or on receiving SIGUSR1 signal; not a major concern. Cleaning up the code. commit 2696fb719e9589dd82477f296c7cf81cc3cad617 Author: John Wolfe Date: Tue Jul 21 11:53:01 2020 -0700 Common header file change not applicable to open-vm-tools. commit f1330b36a316d38930aa3a654ea288a40f5a2a70 Author: John Wolfe Date: Tue Jul 21 11:53:01 2020 -0700 [CLI] "removeAll" missing in first line of vmware-vgauth-cmd help info commit 511b4a8d729adef45964aceb8b3f1a7ef285c132 Author: John Wolfe Date: Tue Jul 21 11:53:01 2020 -0700 Remove unnecessary FreeBSD strings commit c9a362419af2cdc312591c5dd63258a765d6f8f0 Author: John Wolfe Date: Tue Jul 21 11:53:01 2020 -0700 Unknown Linux, later than 5 should report 5, not 4 We want to report the highest version we know about in the short name. commit 0265c8e2a43d45bfcbf9276168c55aa5fa69265e Author: John Wolfe Date: Tue Jul 21 11:53:01 2020 -0700 Improve the LSB distro identification table documentation Explain the LSB distro identification table and provide directions about when to use it. commit 87128716f810df6140987db6de8c73905e8a3b8c Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Fix a comment about POSIX/Linux guest identification The comment is not clear. Fix this. commit 0dabbdf36c4f2fdc248f75a5c5325b9d82728c59 Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Common header file change not applicable to open-vm-tools. commit 99ccb81ebb4d0d085a25b9b531c86d43e646be6e Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3980498b245bf7a6a46a42d11dcdb725a326da70 Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3b9521c96f0ec985d4965c73e9fd70e9718b3d53 Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Common source file changes not directly applicable to open-vm-tools at this time. commit 695611c22bb41a50abf71850ebc69de5ee415b09 Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 hostinfoPosix: remove NOT_IMPLEMENTED() when NO_IOPL When running "vmtoolsd -b pidfile" on Linux arm64, we hit this error: [error] [vmsvc] NOT_IMPLEMENTED hostinfoPosix.c:2526 Linux arm64 does not implement iopl() and the Hostinfo_ResetProcessState() is raising a NOT_IMPLEMENTED() because of that. However if there's no iopl(), there is no reason to drop IO privileges, so we can just skip that code. This change also restores usage of getloadavg() for non Android arm64 platforms: ESX vmx and tools for Linux arm64. commit b1fdd4f15337cfb314652b66bbcc7be4bca100c3 Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Resubmit - Move vgauth to gcc6 and openssl-1.1.1e. commit 31d769f152106333e00902432a4bf49158defecd Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 ServiceDiscovery: Reducing scope of local variables in checkForWrite(). Reducing scope of variables 'clientTimeStamp', 'clientInterval' and 'currentTime' in function 'checkForWrite()'. commit 0e6bd1e045daeb194d624bf09a768f60a199b223 Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Common header file change not applicable to open-vm-tools. commit 48a140340865ca769d022d741f6fdd6c73384a5c Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Common header file change not applicable to open-vm-tools. commit e0152be9ef541f359bf2cc4452b838825cefd581 Author: John Wolfe Date: Tue Jul 21 11:53:00 2020 -0700 Common header file change not applicable to open-vm-tools. commit de28bcaf8e4e85bdfcc2d67577bb2a3656f76d4f Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Backout the previous vgauth changes for openssl 1.1.1. commit 8180c0dd6c2e07631173d00437934a369bf7e715 Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Move vgauth to gcc6 and openssl-1.1.1. commit 4f6cec30425e7e65405ca3e7191bfcd03ffe97d9 Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 vmware-toolsbox-cmd: Fix illegal read memory issue reported by Valgrind Replace the static function MsgUnescape() and its memmove() call that moves 1 byte beyond the termination '\0' with glib's g_strcompress(). commit d5a24c41aa23c155a24ed65174cd986452fddd0d Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Backout the immediately previous changes to common files. commit f078797c6b17ae91e3788da47a606313b141d0d9 Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Common source file changes not directly applicable to open-vm-tools at this time. commit 7bd7bb9e062c7e93f94197b52211d09ef535b4e9 Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit 3e83452afcc6cc86b106b2c87527489c0126635b Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Common header file change not applicable to open-vm-tools. commit a08df7a3eef47c1ed211ef034ae390a4ee898df9 Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Changes to common source files not applicable to open-vm-tools. commit 92022a07d524a16cccc71e44f4cbbbafdd1062bf Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 open-vm-tools: Propagate new gdk-pixbuf-xlib include location #438 From github PR #438 (https://github.com/vmware/open-vm-tools/pull/438). commit cffddcca7187adc043c82a24b5f15296fa6428c0 Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit c0dfe4248701323394959b34814bd48d2b157bbc Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Common header file change not applicable to open-vm-tools. commit 27fe47c54402b6d3e941b2c45e611b98a6c862e9 Author: John Wolfe Date: Tue Jul 21 11:52:59 2020 -0700 Common header file change not applicable to open-vm-tools. commit 29b3ab0fd346f411e65a39a3b89f56eb85d30b20 Author: John Wolfe Date: Tue Jul 21 11:52:58 2020 -0700 Common header file change not applicable to open-vm-tools. commit 6ae818a5c9c261c16c630fc3f5814cbf8d080022 Author: John Wolfe Date: Tue Jul 21 11:52:58 2020 -0700 Common header file change not applicable to open-vm-tools. commit e5d0e1a2d33bd9060d843007d6bafebac677735d Author: Oliver Kurth Date: Thu Jun 11 20:43:21 2020 -0700 Fix misc. issues in appinfo plugin source. Used the proper @param and @return statements in the function documentation for AppInfoServerSetOption. Re-organized an if code block. commit d5517e5255770cd66eab3239c9d617147a3b0077 Author: Oliver Kurth Date: Thu Jun 11 20:43:21 2020 -0700 ServiceDiscovery: Replacing deprecated 'netstat' command with 'ss' Updating the Linux serviceDiscovery scripts to use "ss" in place of the deprecated "netstat" command. commit 9afd238cddc0cb0511d8daa903b4f5c9a52b8dc3 Author: Oliver Kurth Date: Thu Jun 11 20:43:21 2020 -0700 Code cleanup to address a Coverity issue. Coverity reports a "dereference after NULL check" in BkdoorChannelStart. However, at the point of dereference it's known that chan->inStarted is TRUE, which means chan->in is guaranteed to be non-NULL, so it's not a bug. Still, given that an input channel, if present, must have been started before calling BkdoorChannelStart, it's possible to do some code cleanup that will also get Coverity to stop reporting the issue. Change what's currently a test into an ASSERT, test chan->in rather than chan->inStarted, and add comments to make it clearer what's going on. commit 5e1388e10828cec3885ab0107711f483fe732d33 Author: Oliver Kurth Date: Thu Jun 11 20:43:21 2020 -0700 Common header file change not applicable to open-vm-toold. commit e52ffacc9d189e4a4fd5880e3b1c9593cb6c32b6 Author: Oliver Kurth Date: Thu Jun 11 20:43:21 2020 -0700 Fix Coverity-reported dead code issue. The underlying problem was that retryCount was being zeroed on every iteration of the while loop. Zero it before entering the loop instead. commit e3a31877f56c1f0274a7e45b39d3be16a5f64c5f Author: Oliver Kurth Date: Thu Jun 11 20:43:20 2020 -0700 Common header file change not applicable to open-vm-tools. commit 1669fe0b0c0161884f19bcce257e0b10328c14c6 Author: Oliver Kurth Date: Thu Jun 11 20:43:20 2020 -0700 Correct an issue reported by Coverity. lib/asyncsocket/asyncsocket.c: - AsyncSocket_SetKeepAlive() calls AsyncSocket_GetFd() which may return a negative result. If that should happen, simply return FALSE. commit 013e0137786b28fef01bf3a09d79087d656e8f6e Author: Oliver Kurth Date: Wed Jun 10 12:05:46 2020 -0700 open-vm-tools: add distribution specific pam config files Add distribution specific pam config files for Debian/Ubuntu, SuSE and Redhat/Fedora/CentOS. Install a generic file by default, with comments to KB article. The distribution files are intended to be used by OS vendors in their open-vm-tools packages. commit 6ffc688caa7755febe912851d70de304d1ad447a Author: Oliver Kurth Date: Wed Jun 10 12:05:46 2020 -0700 Update the AUTHORS file for OVT an contribution. https://github.com/vmware/open-vm-tools/pull/431 commit 384414d61846f5bd81ce691662efe9d8616a6c69 Author: Oliver Kurth Date: Wed Jun 10 12:05:46 2020 -0700 Appinfo.h: Add define for APP_INFO_GUESTINFO_KEY commit 13ac4d1bff79b0218675fcd1b64205f39cdbc768 Author: Oliver Kurth Date: Wed Jun 10 12:05:46 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3d1d9c92f7ff88b8bd7dfaec674c30a7298b596e Author: Oliver Kurth Date: Wed Jun 10 12:05:46 2020 -0700 Improve Linux guest identification function documentation. Make it clear that the "short name" of a Linux distro has a default value and that the default value should not be overwritten unless VMware does this. If someone cheats and sends down an unsupported "short name", the guestMapper will protect the software stack, mapping the unsupported "short name" to that of the guestOS config found in the VMX file. We know that is OK since the VM couldn't power on and run the guest unless it was valid. All older, supported ESXi have updates that contain the guestMapper. If the guestMapper is not in place - an older, unpatched release - the software stack can become confused causing problems and crashes. Change augments https://github.com/vmware/open-vm-tools/pull/431 commit 0cfda58aaa8bc0fea56f1211897e7f2237f6070a Author: Oliver Kurth Date: Wed Jun 10 12:05:46 2020 -0700 Make peeking back into the stack work for back traces GCC 10 doesn't like peeking back before the end of an arrary (which is used to peek into the stack). Fix this. https://github.com/vmware/open-vm-tools/issues/429 commit c7f4a5150d398184062b4d9ddba18d2c481c37f1 Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 Pick up the LSB distro file for ALT Linux Improve the documentation of the Linux identification routine so others know that nothing needs to be changed in the field. Only VMware needs to add identification codes. https://github.com/vmware/open-vm-tools/pull/431 commit ae80317fcbf2026896b9fe5885992d919062d79c Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 SDMP plugin logs warning message every 5 minute if there is no Namespace DB instance created on a VM. Changing the log level to debug to solve the problem. commit 94fe542015b2764db1ea6b29c55cf53d9ce94f5a Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 Common header file change not applicable to open-vm-tools. commit 0cbe4240689df8c7f6670bb2acf8d9c674063bb7 Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 Clean up lib/file/file.c Consistency with the remainder of lib/file. commit 070142eaf4742eff23d7bba2a20d07c0064f37d7 Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 Common header file change not applicable to open-vm-tools. commit 8c65a2773817208831d2c2db836a124fb6f6dd0a Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 Add a new definition for amazonlinux3_64 commit dca1937e894674fa41e7e0e2f622fb297ab74c08 Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 Implement Set_option handler in appInfo plugin. * Added a handler for the Set_option for appInfo plugin. The poll loop will be immediately turned off when the feature is turned off at the host side. The poll loop will be immediately turned on when the feature is turned on at the host side. * Added the code to handle VM vmotion to an older host that doesn't have logic to send 'set_option'. commit 3e3968f0b805d368b77e42902ec8283ba31dda7f Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 Enable recognition of other5xLinux and other5xLinux64 guests commit f860921bce04cd0d7ad9f9eff977567d83b294a4 Author: Oliver Kurth Date: Wed Jun 10 12:05:45 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3bd995723f1c11e44ea391c296ad41cf5bc5f151 Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Directive argument is null from GCC 9.3.0 There are paths that do not properly deal with NULL in FileMakeTempEx2Work. Fix this. https://github.com/vmware/open-vm-tools/issues/428 commit 88b016d68ec5bc3b03ae8255a47a9f2fb8630f3a Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Add new definition for rhel9_64 and clones. commit 5612d4889d6dae21dfbb27ec4291807baa55ce7d Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Add recognition of FreeBSD 13. commit 041028cd617331def7b3e6ef7cb98985c64cde38 Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Enable recognition of SLES 16_64. commit b48233cb1a996928cf13f6e48131fadabc6e31e9 Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Add recognition of Windows Server 2021. commit f40ebc8d757924b08af60956e290e7957274a14c Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Enable recognition of darwin20_64 (macOS 10.16) and darwin21_64 (macOS 10.17). commit 10e5fe6eb5bd803fe0545371d820133813b3e7d5 Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 guest_os_tables.h: Backout previous change for SLES-16. commit 5978c6bcb8fdf6900c30e2e220f8478070f3bf12 Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Enable recognization of SLES 16. commit 0c7eb59720429fb8fa5872e432104731520e8799 Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Move appInfo and serviceDiscovery plugin related header files. As part of an upcoming project, some appinfo and serviceDiscovery header files are needed at a different location in the common source tree. * Moved the appInfo.h and serviceDiscovery.h to a different location. * Made necessary code and OVT changes to refer to new file paths. * Did some cleanup related to the MACRO names for the keys and scripts. commit ffc6f72e9babdf82010a96c7c76a0e99d5d9633e Author: Oliver Kurth Date: Wed Jun 10 12:05:44 2020 -0700 Fix a Coverity-reported NULL pointer issue. Check whether a pointer is NULL before dereferencing it. Also updated a stale comment, edited a couple of other comments for line length, and deleted some trailing white space. commit 96c50d2068e45f2803b8ad8c1e186480d82f4411 Author: Oliver Kurth Date: Wed Jun 10 12:05:43 2020 -0700 Fix dereference after null check reported by Coverity. Remove a superfluous NULL pointer test that causes Coverity to report a dereference after null check. commit 60d527ae5ea021a7c04a8df7437ef8e5914e5404 Author: Oliver Kurth Date: Wed Jun 10 12:05:43 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3dfcedc9f383454baa79dcaa6508c676077177ca Author: Oliver Kurth Date: Wed Jun 10 12:05:43 2020 -0700 Enable recognition of Amazone Linux 3. commit 47c78f0e7ebbc80c9addeaa48fad88d507bcc759 Author: Oliver Kurth Date: Wed Jun 10 12:05:43 2020 -0700 Header file vm_verison.h not needed in lib/user/util.c. commit cab6d8d915d86abd5558d00592e8b64386b50f22 Author: Oliver Kurth Date: Wed Jun 10 12:05:43 2020 -0700 Common header file change not applicable to open-vm-tools. commit d689c5de5349c48e3a84e72eaf7e2a6be52b8c08 Author: Oliver Kurth Date: Wed Jun 10 12:05:43 2020 -0700 Common source file change not directly applicable to open-vm-tools. commit 8c0f47c895bd3cd901ddcc6df450a8d28fdf3578 Author: Oliver Kurth Date: Wed Jun 10 12:05:43 2020 -0700 Coverity reported issue: missing break Add the missing break. commit bb11e038323893d2428eb2ce94f8742233b45546 Author: Oliver Kurth Date: Wed Jun 10 12:05:43 2020 -0700 Changes to common source file not applicable to open-vm-tools. commit 421e77f5cbb0436bbafdb4d2ec7c39e637061838 Author: Oliver Kurth Date: Wed Jun 10 12:05:42 2020 -0700 Common source file change not directly applicable to open-vm-tools. commit 88836e5df83b215fed8821b3f31bb4a3091d9848 Author: Oliver Kurth Date: Tue May 26 15:32:59 2020 -0700 Common header file change not applicable to open-vm-tools. commit 06ac81cfa3a6a31db045a719733a6b9f804063db Author: Oliver Kurth Date: Tue May 26 15:32:59 2020 -0700 Common header file change not applicable to open-vm-tools. commit 5a521ce9b164f0db7f860b154ab4baed553f5390 Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 serviceDiscovery: Updating 'get-versions.sh' script The following changes have been made: 1. Environment variable 'ALIVE_BASE' is used to construct the path of the file where vcops version is stored. The variable is not avialable when running the script inside serviceDiscovery plugin process, so a hardcoded path is used. 2. Added command to retrieve tcserver version commit 20ad411ebeff55e6d7bfd15afc3fdd6fc3947511 Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Common header file change not applicable to open-vm-tools. commit c1832d6a60475850a25093d05ccf8c786dd89a50 Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Deprecate VMGuestLib_GetHostMemKernOvhdMB GuestSDK API. * GUESTLIB_HOST_MEM_KERN_OVHD_MB metric was already deprecated in ESXi starting from 7.1. It's time to deprecate the corresponding VMGuestLib_GetHostMemKernOvhdMB API in GuestSDK. The documentation will be update denoting that this API is deprecated. After one or two releases, the API will be removed completely. Untill then, the API is modified to explicity return 0 for the metric. * Only a few functions listed in vmGuestLib.h are exposed in the vmGuestLibJava interface. The remaining functions are encapsulated in '#ifndef SWIG' to hide them from SWIG utility which is used to generate the Java bindings. Note: The external customer facing documentation for this API will be documented later. Note: Once this changeset is submitted, the vmStatsProvider module will be updated to stop using the deprecated API. commit 6a5123f2e020e6e35d2111777f99879c791088a2 Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Common header file change not applicable to open-vm-tools. commit a1bb9128e3087602ce5280f43d639cd87e5487cc Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Changes to common source files not applicable to open-vm-tools. commit 0682a7064f553a3d50a55ac881b0e5e6b78a257e Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Update to bora/public/vm_tools_version.h Add tools versions 11.1.1 and 11.1.5 to bora/public/vm_tools_version.h commit d1ce2c08c47a82a4cfddae55a55c4b9619b08042 Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Common header file change not applicable to open-vm-tools. commit 53473f83f7dfda6a0b592bbfdf1a5e6144b426e7 Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Changes to common source files not applicable to open-vm-tools. commit a99fcf43fbef64cc36473750a441cb2f6265a1dd Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Backout previous changes to common source files. commit 8f68d75e3d6642e2f8d7d7ef9a4cbfcab052b3be Author: Oliver Kurth Date: Tue May 26 15:32:58 2020 -0700 Changes to common source files not applicable to open-vm-tools. commit 34d7c760709cec8938488d1c60831960bc30441d Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Common source file changes not directly applicable to open-vm-tools. commit f3423aa7a1d2f0d864eaaa6d11b8b34eacb04c3c Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Common source file changes not directly applicable to open-vm-tools. commit e25e233b02557a944babad5d8140472eb25c2210 Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Common header file change not applicable to open-vm-tools. commit 5ed3bc8fe0cfee2b15b469b4f5e71c1fbb28bad9 Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Backout previous common header file change - not applicable to open-vm-tools. commit 2f6676c69e332677b7bd598505de02d6e78e1fbb Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Common header file change not applicable to open-vm-tools. commit 0128592fd7ec406824237af5e184f72726715f59 Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Updating the bora/public/vm_tools_version.h history. Tracking version info for the 10.3.22 patch release and 10.2.23 development version of tools for older Linux guests. commit 146971ddbe43d24380891c4297493cce2d4a46c6 Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Common header file change not applicable to open-vm-tools. commit 29c1c6743f5b1a2c9bf6d86f2eaacd10f2102aa2 Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Common source file changes not directly applicable to open-vm-tools. commit 25320e4af24664ebb6ab324db0a1cdfebf241f37 Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Common source file changes not directly applicable to open-vm-tools. Pre-enable SUSE 16 commit ecdd9001cf809b2ce359f07f8b84d54cd436a573 Author: Oliver Kurth Date: Tue May 26 15:32:57 2020 -0700 Common source file changes not directly applicable to open-vm-tools Pre-enable RHEL 9, CentOS 9, Oracle 9, and Asianux 9 guests commit 66e52b635938b8c4e5276944daaec1cddc5ae6f9 Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 GuestSDK and vmtoolslib cleanup. * Removed the vmtools dependency for guestsdk. This has been already done for tar tools build/target. The same is being done for OVT builds. * Used various static libraries for building guestlib in OVT instead of depending on vmtoolslib. Similar thing has already been done for appmonitor library in OVT. * GuestSDK_{Panic|Debug|Warning|Log} functions in vmtoolslib are not used anywhere and hence they are completely removed from the code. commit 66b70db09241bef18694bc0e45bd94a1804b201d Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 Common header file change not directly applicable to open-vm-tools. commit e4fdad51c47f5e2605a3ad9dd9e3451b25ba6fbd Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 Changes to common header files not applicable to open-vm-tools. commit a760361f0b603f0dabe2e82cec1a728e5b3f796b Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 Pre-enablment: Recognition of FreeBSD 13 commit 80ce8edc04fcd3253174be476b0f09bdf5527bf5 Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 Improve logging on signature verification If xmlsec and vgauth are built inconsistently, xmlSecSize can differ between the two, which results in a key datastructure being a different size, and vgauth ends up looking in the wrong place in memory for the signature check status. Log the status, so that if its not one of the two expected values, we have some ideas of what went wrong. commit 4dbd9ff2e404957147ad1c22233388302b726d71 Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 Changes to common header files not directly related to open-vm-tools. Recongition of MacOS 10.17 (darwin21-64) - pre-enablement on hosts. commit f01d92c41b756f0167308ef7b5596b0554a661b8 Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 lib/file: Fix a memory leak in FileLock_Lock. Valgrind complained about a minor leak within FileLock_Lock when running test-vmx Firmware.Efi.QuickBoot . FileLockScanner builds a list of "active locks" and traverses that list repeatedly, but whenever it decides to remove an entry from the list, it would simply leak it. This change ensures that the list item is not leaked by Posix_Free()ing it once it is no longer needed. commit c27281f24e043f64a9e627e2eaeccd9c196fc938 Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 Hgfs Linux/OSX Server: fix write-only shares access check creating new files Linux and OS X Hgfs server has an incorrect failure status check when a user has a write-only share enabled. In a write-only share any failure is mapped to EACESS unless the error is ENOENT when a new file is to be created. The error check currently fails all errors when it should only allow creation of new files i.e., ENOENT with flags specifying O_CREAT. The check should be if (status == EACCES) goto exit commit 5a300cffdb3c7069a104559b598f6315a6dbae00 Author: Oliver Kurth Date: Tue May 26 15:32:56 2020 -0700 Common source file changes not directly applicable to open-vm-tools. commit e256c4eb87e602c981cd9b92ec4c52df861094f4 Author: Oliver Kurth Date: Tue May 26 15:32:55 2020 -0700 Common source file change not applicable to open-vm-tools. commit d663f02db62cf44ee246956f50666f1c044cee2a Author: Oliver Kurth Date: Tue May 26 15:32:55 2020 -0700 Common source file change not applicable to open-vm-tools. commit c3d1c32369ec29653bd32beb3851d2d283dadd0c Author: Oliver Kurth Date: Tue May 26 15:32:55 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 215d376160a4c2f4e53666fd4275f7e8c7edc2da Author: Oliver Kurth Date: Mon May 4 11:54:13 2020 -0700 Common header file change not applicable to open-vm-tools. commit 3e5fd5d7976d9d047229b33f9a209c250f928384 Author: Oliver Kurth Date: Mon May 4 11:54:13 2020 -0700 [AppInfo] Tweak the gather loop only for a real config reload. The poll loop for the appInfo is being tweaked (destroyed and recreated) for every conf reload even when nothing related to appinfo changed. This may cause few scenarios where the 'application information' will never be collected inside the guest. Fixed the code, to tweak the loop only when there is a real appinfo related config change in the tools.conf file. commit c5f0d8d38bfedc576b9fec40b579a0d5f6c85688 Author: Oliver Kurth Date: Mon May 4 11:54:13 2020 -0700 Use RPCI_UNKNOWN_COMMAND macro instead of hardcoded 'Unknown command" string. At few places in the code, the result from the RPC channel send APIs is explicitly compared with a harcoded "Unknown command" string. We already have a well defined macro for that. Changed the code to re-use the macro wherever possible. commit 7a981dcaa625a982e62e93ab63648dc02ac31595 Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Clean up a few things in the random.h header file. commit bdd112cee037f58b2788d7bc3f1dbc9fa5344d97 Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Fix minor misc. issues. * In ServiceLoadFileContentsPosix() function, fd is always a positive value when close() is called. The if check 'fd >= 0' is not really required. Removed it. * Fixed the function name in the "procedure comment block" for the ParseShareName function. commit 384b1e7b9e9a6dac67a285eef0acdd52f5c997e5 Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Fix minor 'Comparison is always true' warning in linuxDeployment.c pkgProcessTimeout is uint16 and comparison is always true because pkgProcessTimeout <= 65535, so remove the check. commit 4b57bd2d1c9fa37994a562a63be2232af6c4587d Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Deprecate GUESTLIB_HOST_MEM_KERN_OVHD_MB at ESXi level. Decided to deprecate GUESTLIB_HOST_MEM_KERN_OVHD_MB. This changeset implements the necessary changes to deprecate the metric at the ESXi level. Will address the deprecation changes in GuestLib SDK/API in a separate changeset. commit cb0a946b284d99f78da58e012a91c38eb81e492e Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Common header file change not applicable to open-vm-tools. commit aa346e71e6bbc9a55f0a48d7d7b728e3128ae4bf Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Backout previous change to guestlibV3.x commit 0f90e3fdd95d62294452b159c11a66368f8114e3 Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Deprecate GUESTLIB_HOST_MEM_KERN_OVHD_MB at ESXi level. Decided to deprecate GUESTLIB_HOST_MEM_KERN_OVHD_MB. This changeset implements the necessary changes to deprecate the metric at the ESXi level. Will address the deprecation changes in GuestLib SDK/API in a separate changeset. commit 91923b6c7d19edfedac6d7a36c4a9b795a7ef37c Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Common source file change not applicable to open-vm-tools. commit 7058e42e6fa34dcf60438d27827d9b9ba20f5bd1 Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Define macro for "Permission Denied" message returned from RpcChannel send APIs. In error cases, RpcChannel Send APIs (RpcChannel_SendOneRaw, RpcChannel_SendOneRawPriv return 'hard coded' "Permission Denied" error message. This changeset adds the MACRO for that error message. If there are any callers who compare the results (ex: ServiceDiscovery), they don't have to use 'hardcoded' messages and can reuse the MACROs. commit 4c286c51e21e94e35b76a7f56c143a3b69e9a7e1 Author: Oliver Kurth Date: Mon May 4 11:54:12 2020 -0700 Common header file change not applicable to open-vm-tools. commit fde53d238b14ca984179aa821d7de95d6d6985ba Author: Oliver Kurth Date: Mon May 4 11:54:11 2020 -0700 CodeSet: Fix copyright header in codeset.h commit ced22726ccf583d54ebeaa83e5736fb249b730be Author: Oliver Kurth Date: Mon May 4 11:54:11 2020 -0700 CodeSet: Add CodeSet_IsValidUTF8String() and more comments This change adds a new function CodeSet_IsValidUTF8String() to lib/misc/codesetUTF8.c, and adds comments for CodeSet_IsValidUTF8() and CodeSet_IsStringValidUTF8(). commit adcaf9cd9ad65a45459ee8058ebfc267844477d6 Author: Oliver Kurth Date: Mon May 4 11:54:11 2020 -0700 ServiceDiscovery: Deleting keys from NDB by chunks to reduce RPC calls. Setting chunk size to 25 keys at a time. commit 619329e43a785831683f09d13f53f9d76615c559 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Common header file change not applicable to open-vm-tools. commit 2fb29808e01636ef6621ec6cbc815b024f2aed68 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Common header file change not applicable to open-vm-tools. commit 9e3875bc727141e69d7325af393e797353929833 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Fix a trivial typo in the VIX log message. * Fixed a trivial typo in the VIX log message. * Fixed an indentation issue. commit 08218dcd4eb03aafe823ae3585d99a23f7bee3c0 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Use random poll-interval for appInfo on channel reset. In few workflows like instant clone, when a large number of VMs are cloned at the same time, if the appinfo plugin runs at the same time in all the VMs, the underlying ESXi may encounter heavy load. To avoid these situations, a random poll interval should be used for the appinfo whenever applicable workflows are detected. Detecting a 'rpc channel reset' is a simple approach to detect. In this changeset, add the following changes: - Added a new callback function for the 'rpc channel reset'. If the rpc channel is reset, a new random poll interval is calculated and poll timer is adjusted accordingly. If the existing appinfo poll interval is greater than the minimum interval of 30 seconds, random interval will be generated between 30 and appinfopollinterval. If the existing poll interval is less than the minimum 30 seconds time, then random interval will not be changed. - Code refactoring for few functions. - Changed one global variable as static. - Added few debug/info log messages. commit 9b79ed9bc118860518028828a6c7858af62757a8 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Common header file change not applicable to open-vm-tools. commit 9a9aab94168189302e74dd97939415ef1e07fb20 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Common header file change not applicable to open-vm-tools. commit a8086de2c4317d4463b0bb1a3b602cda0833bd3e Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Common header file change not applicable to open-vm-tools. commit 8e2e15a2da54f3603a7ccdc09249aec0b58f6ed9 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Free old ununsed loggers when tools.conf changes. Existing unused loggers are leaked when there is a change in logging configuration. Added a check to free the loggers that are not used after tools.conf is modified. commit 1852a9e98e3b1c31542986b2d332c707e4a0b540 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Changes to common source files not directly applicable to open-vm-tools. commit 86ca532794728e4cf3d6b5fd29b3a10ff4f36141 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Add option to vmware-vgauth-cmd to support remove alias by [username] and subject a. subject is mandatory b. if user only provide subject, will only remove subject matched mapped aliases c. if user provide username and subject, remove matched aliases commit 3324db715f71d850f12f91e7941745792edacb63 Author: Oliver Kurth Date: Tue Apr 21 14:43:46 2020 -0700 Make Backdoor fallback temporary. When RpcOut falls to Backdoor, it stays with Backdoor permanently for the life of vmtoolsd service. It is a long standing bug in the reset handling code. Typically, channel type is not changed during reset. Our reset handling code can either keep the channel type same or switch it from vsocket to Backdoor, but it can't do other way. Though it is supposed to switch to vsocket on reset caused by events like vmtoolsd being restarted or VMX breaking the channel for some VM management operation. With this change when we start the channel, we always try vsocket first unless Backdoor is enforced by the caller. Using Backdoor for too long is not desirable because privileged RPCs can't be used on such channel. So, we need to retry switching the channel back to vsocket periodically. We don't want to try vsocket on every RpcChannel_Send call because that adds to overhead and increases the latency of RpcChannel_Send due to connection timeouts. So, we retry vsocket with a backoff delay between 2sec-5min. As some RpcChannel callers intend to use Backdoor channel we need to differentiate between such usage from the callers that create vsocket channel and fallback to Backdoor. Therefore, introduced a concept of mutable channel. The vsocket channel is mutable as it can fallback to Backdoor and restore vsocket. However, if a caller creates Backdoor channel, it will not be mutable and stay with Backdoor for its lifetime. As vmxLogger frequently connects and disconnects the channel for every log message and does not use any privileged RPC, so make it use Backdoor channel permanently to avoid frequent vsocket connections. Additionally, removed the redundant 'stopRpcOut' interface and renamed 'onStartErr' to 'destroy'. commit 4a049ceec7e2e1fafbfece34e29c4f7b14962e7c Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 AppInfo updates. While most of the changes are only applicable to VMware Tools for Windows and are not applicable to open-vm-tools, the following changes do apply. - Modified few log messages from g_debug from g_warning. - Modified the default poll interval to 360 minutes (Once in six hours). - Modified log messages to log the filepath whose version is being retrieved. commit 500eadfa9b5b8304ce57d9f881247ab67205d40b Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 Common header file changes not applicable to open-vm-tools. commit 5f9bc344328dd144c5539dd44fe1508d0f7b8b6f Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 Common source file changes not applicable to open-vm-tools. Tools Windows: test plugin DLLs are the correct version commit 4c1fed3a4676d664a049da5db6516a8baee1fbb9 Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 Backout previous change for the vmware-vgauth-cmd. commit f62afa8e4462c100105b8ac8d88f5379094e87cd Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 Add option to vmware-vgauth-cmd to support remove alias by [username] and subject a. subject is mandatory b. if user only provide subject, will only remove subject matched mapped aliases c. if user provide username and subject, remove matched aliases commit bf687d16a380a2f94952a9d9ad84d492376d2895 Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 Common source file changes not applicable to open-vm-tools. commit f2b9d8028ad88583f9f3575d26ca68cf5664fef7 Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 Common header file change not applicable to open-vm-tools. commit d1a02b45838f568d8a70d22f16e28bd2da8c447e Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 Common source file changes not applicable to open-vm-tools. commit fa6fb17347de72a56d6c5a6ffcf713b97b9e73c1 Author: Oliver Kurth Date: Tue Apr 21 14:43:45 2020 -0700 Common source file changes not applicable to open-vm-tools. commit 86053c524c617ba1faa744a04b1e18986ebb929f Author: Oliver Kurth Date: Wed Apr 8 12:05:18 2020 -0700 update version commit 32df621461ca3f7f7188763be0f3b269b71b87cb Author: Oliver Kurth Date: Wed Apr 8 12:04:15 2020 -0700 sync tclodefs.h to source commit 5b3b243dc5edae6d94e0bd376290605044a2bf89 Author: Oliver Kurth Date: Wed Apr 1 11:31:38 2020 -0700 serviceDiscovery: Adding sleep before 'RpcChannel_SendOneRawPriv' call. commit a4560863d4fedc050b4917b3bc764c384b5c007f Author: Oliver Kurth Date: Wed Apr 1 11:31:38 2020 -0700 Do a 100 msec delay for each vsock channel start retry. Move the 100 msec delay into the vsock RPC start retry loop. The 100 msec delay before each start retry is needed for errors that will return quickly. commit ffe0dc255114856f123b6f9dd04dc714ab6f1eb9 Author: Oliver Kurth Date: Wed Apr 1 11:31:38 2020 -0700 Common source file change not directly applicable to open-vm-tools. commit 8e221a1311bab1f526bef16d97d9d2798bf09e49 Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 Fix localization issue on windows guests. Some fields of GOptionContext used in help are not public, so add 2 arguments to Usage to get needed info. commit 6fcc7bdd696cec8f04c748d3807bbce4dd3230b5 Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 Add a retry loop to VSockChannelStart() to recover on start failure. On failure, a vsock RPC channel will eventually fallback to the backdoor channel. Services that require or are limited to the priviledge RPC channel will fail. Adding a simple, limited loop in VSockChannelStart to retry the vsock channel start before ultimately switching to the backdoor channel. Retries are not done for "send once" operations. commit 39ceb37ce4d6093cb1b64baf6eeddf2532b0b3a1 Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 Destroy the dedicated RPCI channel set up for the Vmx Guest Logging when vmtoolsd process exits. commit b911e5c94cd18b7985e920875249d2314029f0a6 Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 Fixing some log messages 1. PublishScriptOutputToNamespaceDB can fail for various reasons, caller can't know exact reason from return values, so just printing that the function failed in case return value is FALSE. Exact cause must be inferred from the function's logs itself. 2. Printing log for chunkCount only if we successfully wrote it in NDB commit 6934e672378dbbdb505467682092d7bb905fe10e Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 ServiceDiscovery: Fixing failure of sending message via RPCChannel after it has failed to the backdoor. commit 03f9392540cdfabd1220e220842ead210edfe7d2 Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 Common header file change not applicable to open-vm-tools. commit 04e99532df99d8a11fc160882a3a8455a2d7c23c Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 Common header file change not applicable to open-vm-tools. commit b4e6f4f8334be3bcc35c483dcf869de871ccac92 Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 Common header file change not applicable to open-vm-tools. commit c556b1d10671366e1d5ddba14785c3e9b270db84 Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 open-vm-tools: stage all *.vmsg files Only a subset of the *.vmsg files were installed. Fixing this by using a glob. commit 9a3f8e4b57537e522dba8831eef3529a6dd6b9e1 Author: Oliver Kurth Date: Wed Apr 1 11:31:37 2020 -0700 Record the assignment of tools version 11.0.6. Add TOOLS_VERSION_SLEDGEHAMMER_PATCH2 for version 11.0.6 to the historical version information. commit 2fa133ac0af2588f0295228795f427bc5cd44465 Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 Common header file change not applicable to open-vm-tools. commit 9cbdf3a6e2cb23a7673fe19b2a3f888714095019 Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 Add a Coverity annotation. The Coverity scan of open-vm-tools reports an out-of-bounds access issue in Util_BacktraceWithFunc. This is intentional, to compute the base pointer for a stack trace. commit 7db9613b49a77e59c3cb1ed045905e2d0bbb2280 Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 Common header file change not applicable to open-vm-tools. commit af4db666735d0af28ba013c63b92fef743bec125 Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 Updating the tools version on the devel branch to 11.2.0. commit ded2a20ac11ef4f9340847d19ae2a14431a4702f Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 lib/unicode/unicodeSimpleTypes.c: fix leak on exit The hashtable used for encoding name -> IANA table index lookups was not getting freed. Also, HashTable_AllocOnce() incorrectly instructs the hashtable to clear its clientData, which contains an integer index and not a pointer, using "free". commit ef20d06e9b2e3fbe8e7f6f709c4707ebf7c57d72 Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 Annotate a Coverity false positive. The open-vm-tools Coverity scan reports a NULL pointer dereference for the variable untrustedCerts. However, untrustedCerts is NULL only if no untrusted certs are found, in which case the code that dereferences untrustedCerts isn't executed. commit 3777c7008da506fe35b1b8003b3d1ae7067662ae Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 lib/mics/sha1.c: Include string.h unconditionally. string.h is part of POSIX, lets include it unconditionally commit 8774b6383b6dcb024335dd115c8fcae2b00c4d16 Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 Common header file change not applicable to open-vm-tools. commit 0bbaf772c27a8df913ade55d7086d651652a2f17 Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 vmtools: fix compiler errors in posix service discovery core plugin As we build the vmtools for arm (unfortunately not on main), we hit a compiler warnings "ISO C90 forbids mixed declarations and code" in this new code. commit 65b6819ed3ba196f52639c5984be40475ce2fffc Author: Oliver Kurth Date: Wed Apr 1 11:31:36 2020 -0700 Common header file change not applicable to open-vm-tools. commit 5ef6682ae1038942f4b1d873cd0ca93d688f83e0 Author: Oliver Kurth Date: Wed Apr 1 11:31:35 2020 -0700 Common header file change not applicable to open-vm-tools. commit 74351e2121e866ca0b28644a6fc545c97e8bfbda Author: Oliver Kurth Date: Wed Apr 1 11:31:35 2020 -0700 Fix localization issue of vmware-vgauth-cmd 1. default msg catalog folder is wrong, add correct msgCatalog in vgauth.conf 2. rename vmsg file name to "VGAuthCli" since file name used in main is "VGAuthCli" 3. Move I18n init up to fix variable localization issue ***** Created the "stable-11.1.x" branch at this point. ***** 2013.04.16 Dmitry Torokhov This release tag contains commits up to the following id: 867ea989d5e6889abcac77b4c7dae7db2651df58 2012.12.26 Dmitry Torokhov This release tag contains commits up to the following id: 530ef7f26ed041ab1b6655f2cdc79f3af97fc50b 2012.10.14 Dmitry Torokhov This release tag contains commits up to the following id: d85408321c66c927bffdb05106a26581244edd4a 2012.05.21 Dmitry Torokhov This release tag contains commits up to the following id: 482332b8d4282df09838df5ea4c58df9cdb4faf3 2012.03.13 Dmitry Torokhov This release tag contains commits up to the following id: 0114aabd54bf2db4556563b7149c4fbbdec3d87b 2011.12.20 Marcelo Vanzin This release tag contains commits up to the following id: dfca5cf9d1c2335c5d001deedd9266c84956b508 2011.11.20 Marcelo Vanzin This release tag contains commits up to the following id: 6c197b8e5eccf32bfee0e2452d8926968182aada 2011.10.26 Marcelo Vanzin This release tag contains commits up to the following id: 6271fde90248a4fd49e38aa61498db9e1dbf37c3 2011.09.23 Marcelo Vanzin This release tag contains commits up to the following id: 05baddbed1c5e47e9789a44d30bb217d7184232a 2011.08.21 Marcelo Vanzin This release tag contains commits up to the following id: 2b3d76ba776f55d06fb5b62499b189ebd6bc1c75 2011.07.19 Marcelo Vanzin This release tag contains commits up to the following id: 5bed6f1369ca6e9c2c7fbaf4205d86e50f219c5f 2011.06.27 Marcelo Vanzin This release tag contains commits up to the following id: 166bbe1d28da4dab763b9568f163c8dca99ced9c 2011.05.27 Marcelo Vanzin This release tag contains commits up to the following id: 3793ddc9c9b5facf376a2625d4c2252aa9bd3daa 2011.04.25 Marcelo Vanzin This release tag contains commits up to the following id: 3112c27981074deb53e86e30e1c168d55e42220c 2011.03.28 Marcelo Vanzin This release tag contains commits up to the following id: ec43520f5f3a50f5a980a73d22ae231380f97555 2011.02.23 Marcelo Vanzin This release tag contains commits up to the following id: 96cf4718ac0aff1743e50a2165599306ba442fe1 2011.01.24 Marcelo Vanzin This release tag contains commits up to the following id: 60c470337c8932a6d9564130dcaf06c7a1a3df53 2010.12.19 Marcelo Vanzin This release tag contains commits up to the following id: 5aef2b20a519788613350752575bcba0ac71df79 2010.11.17 Marcelo Vanzin This release tag contains commits up to the following id: 11c0273ed4269f6f7a92f82f6c822df7da4c8720 2010.10.18 Marcelo Vanzin This release tag contains commits up to the following id: 2162c5d770cdac3b0e275907a1a5d22ece8ce23c 2010.09.19 Marcelo Vanzin This release tag contains commits up to the following id: c92a8bfbb406a906bcd2fb9ef6801f92c5b64d1f 2010.08.24 Marcelo Vanzin This release tag contains commits up to the following id: 94e63742d734b41638d37580602de4232da5ece6 2010.07.25 Marcelo Vanzin This release tag contains commits up to the following id: b15cffc7961b97129d0b77643db42b4d4d8e3da7 2010.06.16 Marcelo Vanzin This release tag contains commits up to the following id: ec87703fccdd0f954a118640c0b097e383994391 2010.04.25 Marcelo Vanzin This release tag contains commits up to the following id: 6fafd672e006208c1e479b297e19618170ff19bd 2010.03.20 Marcelo Vanzin This release tag contains commits up to the following id: 7cdbb623125729b41bf54068568dfbcc2dd58733 2010.02.23 Marcelo Vanzin This release tag contains commits up to the following id: 8baa8588d5fd4cf64efb17164cb70c86c758d0c6 2010.01.19 Marcelo Vanzin This release tag contains commits up to the following id: 8ee82a5774ae7badeb98ecf4dc629c7e9aac7077 2009.12.16 Marcelo Vanzin This release tag contains commits up to the following id: 0d28106da5684dc31ea52ebb5a2dc6a0af5c1d61 2009.11.16 Marcelo Vanzin This release tag contains commits up to the following id: 6f4cdd0f38be020d722f2393c0b78d7cd13f04d2 2009.10.15 Marcelo Vanzin This release tag contains commits up to the following id: d2f1b83daab1d7882fd651ad1cc77c729bbd9760 2009.09.18 Marcelo Vanzin This release tag contains commits up to the following id: 8bb94fbfbdf65b53b87279cf81529756dba7a2ca Other changes not captured in the git logs: * Resync with internal dev branch (2009.08.24) * hgfsmounter/hgfsmounter.c: allow hgfs users to set ttl to 0 at mount time. * lib/guestApp/guestApp.c, lib/include/conf.h, lib/include/netutil.h, lib/include/procMgr.h, lib/include/system.h, lib/vixTools/vixTools.c, lib/vmCheck/vmcheck.c: remove (now unused) Netware checks. * lib/message/*, modules/freebsd/vmhgfs/Makefile, modules/linux/vmhgfs/Makefile.*, modules/solaris/vmhgfs/Makefile: remove unused message transport abstraction. The rpcChannel library is now used to do RPC abstraction. * modules/*/vmmemctl/*: refactor of the vmmemctl module as part of adding support for Mac OS guests. * modules/linux/pvscsi/pvscsi.c: don't clobber RESERVATION_CONFLICT sdstat up from linux pvscsi driver. * modules/linux/shared/*: VMCI changes unrelated to the guest driver. * modules/linux/vmhgfs/fsutil.c, modules/linux/vmhgfs/inode.c: fix the case where two directories refer to the same inode. * scripts/linux/*: support older versions of NetworkManager. 2009-08-24 Marcelo Vanzin * Resync with internal trunk (2009.08.19) * configure.ac: remove support for Linux kernels < 2.6.9. * lib/include/vmtools.h, libvmtools/vmtoolsLog.c, doc/api/services/util.txt: add new log handled that allows appending to existing log files, and fix an issue where old log files would be "rotated" whenever the config file was reloaded. * lib/appUtil/appUtilX11.c, lib/ghIntegration/ghIntegrationX11.c, lib/include/appUtil.h: fix compilation issues on FreeBSD when unity was enabled. * lib/dnd/dndLinux.c, lib/include/vmblock_user.h, tests/testVmblock/*: add vmblock tests and, as part of the change, do some refactoring of vmblock related functions. * lib/guestInfo/guestInfo.c, lib/include/wiper.h, lib/wiper/*, toolbox/toolboxcmd-shrink.c, toolbox/toolboxShrink.c: refactor the wiper structures so that they behave the same on Win32 and other platforms, and also reuse data structures already in use by other parts of the code. This fixes an "use after free" issue that toolbox-cmd had on Win32. * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoInt.h, lib/guestInfo/guestInfoPosix.c, lib/guestRpc/nicinfo.x, lib/include/guestInfo.h, lib/include/netutil.h, lib/include/slashProc.h, lib/netutil/netUtilLinux.c, lib/slashProc/*, services/plugins/guestInfo/guestInfoServer.c: add support for sending more network-related information to the host, such as routing tables and name servers. * lib/hgfsBd/hgfsBd.c: don't log RPC errors when HGFS is disabled. * lib/hgfsHelper/*, lib/include/hgfsHelper.h, lib/vixTools/vixTools.c: new library with functions to query information about HGFS; expose some HGFS properties through VIX. * lib/hgfsServer/*, lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c, lib/include/hgfsServerPolicy.h: fix checking of whether an object belongs to a particular share; this was causing issues with invalid information being returned in certain cases. * lib/hgfsServer/*, lib/include/hgfsProto.h: changes to support new VIX API calls (mostly affecting Win32 only). * lib/include/guestCaps.h, lib/include/unityCommon.h: add boilerplate for new RPCs for setting windows as sticky / non-sticky (not yet implemented). * lib/include/hgfsProto.h: new definitions for the next version of the HGFS protocol. * lib/include/xdrutil.h: make XDRUTIL_ARRAYAPPEND() more type-safe when using GCC. * lib/misc/codesetOld.c: fix some issues with UTF16 -> UTF8 conversion. * lib/rpcChannel/rpcChannel.c, libvmtools/signalSource.c, libvmtools/vmtools.c, libvmtools/vmtoolsConfig.c: g_assert -> ASSERT. * lib/unityWindowTracker/unityWindowTracker.c: fix issue with z-ordering of modal dialogs. * libvmtools/vmtoolsConfig.c: fix some old config translation issues. * modules/freebsd/shared/*, modules/freebsd/vmblock/*: make vmblock work on FreeBSD 8. * modules/freebsd/vmmemctl/*, modules/linux/vmmemctl/*, modules/solaris/vmmemctl/*, : refactoring and code changes to support the driver on Mac OS X. * modules/linux/vmblock/*, modules/linux/vmci/*, modules/linux/vsock/linux/*: remove compatibility code for older kernels. * modules/linux/vmhgfs/*: fix memory leak in HgfsAccessInt(). * modules/linux/vmxnet3/*: fix kunmap usage in vmxnet3_shm, and reset the shared pages when the char device is closed. * modules/linux/vsock/linux/af_vsock.{c,h}, modules/linux/vsock/linux/util.c: add vsock protocol negotiation for notifyOn ops. This allows the driver to negotiate with the remove end which version of the notification protocol to use. * modules/linux/vsock/linux/notify.c, modules/linux/vsock/linux/notify.h, modules/linux/vsock/linux/notifyQState.c, modules/linux/vsock/linux/vsockPacket.h: add pktOn protocol. This new protocol improves performance by detecting changes in the queue state instead of sending WAITING_READ and WAITING_WRITE packets. * services/plugins/hgfsServer/hgfsPlugin.c, services/plugins/resolutionSet/resolutionSet.c, services/vmtoolsd/mainLoop.c, services/vmtoolsd/pluginMgr.c, services/vmtoolsd/toolsRpc.c: load plugins even when an RPC channel cannot be instantiated (i.e., when running outside of a virtual machine); this allows plugins to perform actions (at load time) also when running outside virtual machines (e.g., to undo some configuration done when the OS was run in a VM). * services/vmtoolsd/mainLoop.c, services/vmtoolsd/mainPosix.c, services/vmtoolsd/toolsCoreInt.h: handle SIGHUP differently; instead of stopping the service, just re-load the config data. This should make it easier to integrate the tools service with other tools such as logrotate. * toolbox/toolbox-cmd.c, toolbox/toolboxcmd-stat.c: remove memory info query, which didn't really return useful information. * vmware-user/copyPasteUI.cpp: if the clipboard/primary with most recent timestamp has no data on it, try the other before giving up during copy/paste. 2009-07-22 Marcelo Vanzin * Resync with internal trunk (2009.07.17) * configure.ac: fix detection of "dot" and its usage in the doxygen config file. * configure.ac, libguestlib/Makefile.am, libguestlib/vmguestlib.pc.in: install vmguestlib headers and add new pkgconfig script. * lib/dndGuest/dnd.{cc,hh}, lib/include/dndBase.h, vmware-user/dndUI.{cpp,h}: fix an issue where the DnD code would prevent drops to other windows in Unity mode, instead of just intercepting drops to the desktop. * lib/dndGuest/dnd.{cc,hh}, lib/dndGuest/dndRpc.hh, lib/dndGuest/dndRpcV3.cc, lib/include/dndBase.h, vmware-user/dndUI.{cpp,h}: fix an issue where the host Unity code would cause an undesired drop event. * lib/dndGuest/dnd.{cc,hh}, lib/dndGuest/dndRpc.hh, lib/dndGuest/dndRpcV3.cc, lib/include/dndBase.h: cleanup mouse simulation code, and fix an issue where a drag would be canceled if the contents were dragged out of a guest and then back in. * lib/dndGuest/dndRpcV3.cc, vmware-user/copyPasteDnDWrapper.cpp, vmware-user/dndUI.cpp, vmware-user/dndUI.h, vmware-user/dragDetWnd.cpp, vmware-user/dragDetWnd.h: several DnD fixes; make the DnD code behave more like other GTK applications (based on analysing the flow of signals on a test widget), and get rid of one of the detection windows, merging both the Unity and non-Unity windows. Also, some code refactoring. * lib/ghIntegration/*, lib/guestRpc/*, lib/include/guestCaps.h, lib/include/unityCommon.h: add stubs for a few new GHI functions (setting window focus, tray icon updates and enhanced app info) - currently only implemented on Win32. * lib/ghIntegration/ghIntegrationX11.c: examine WM_CLASS when determining which DE Tools are running in. The previous code was failing to show a few entries set as "OnlyShowIn=xxx" because checking WM_NAME wasn't enough to properly detect the desktop environment in certain cases. * lib/guestApp/guestAppPosixX11.c: use gconftool-2 to detect the user's browser, since gnome-open fails to open "file://" URLs which contain query strings. Also, use "kde-open" when running under KDE. * lib/guestInfo/guestInfo.c, lib/include/wiper.h, lib/wiper/wiperPosix.c: allow shrinking LVM partitions. * lib/include/appUtil.h: partial refactoring of icon retrieval code. * lib/include/dbllnklst.h, lib/misc/dbllnklst.c: inline linked list functions. * lib/include/guest_os.h, lib/misc/hostinfoPosix.c: add a couple of distros to the known distro list. * lib/include/netutil.h, lib/netUtil/netUtilLinux.c: add Linux interface name, index lookup routines. * lib/include/system.h, lib/system/systemLinux.c, services/plugins/timeSync/timeSync.c: fixes a few bugs in the backwards time sync code, mostly due to unit mismatches. * lib/include/unityWindowTracker.h, lib/unity/unity.c, lib/unity/unityPlatform.h, lib/unity/unityPlatformX11Window.c, lib/unityWindowTracker/unityWindowTracker.c: expose two new properties in the window tracker to save an RPC to retrieve those properties. * lib/include/vmtoolsApp.h, services/vmtoolsd/mainLoop.c, services/vmtoolsd/pluginMgr.c, services/vmtoolsd/toolsCoreInt.h: add support for "application providers", which allow plugins to add support to new kinds of application frameworks through vmtoolsd. * lib/unity/unityPlatformX11.c: only enable GIO channels when Unity is actually active. * lib/unity/*: cleanup old GTK1 code. * libvmtools/vmtoolsConfig.c: don't complain if config file is empty. * modules/linux/dkms.conf, modules/linux/dkms.sh: fix dkms.conf, and provide a script to create a dkms tree from open-vm-tools. * modules/linux/shared/vmci_queue_pair.h, modules/linux/vmci/vmciKernelIf.c: remove two (now) unneeded functions. * modules/linux/vmhgfs/*: code cleanups, properly initialize the list head, and allow receives to timeout so that hibernation works. * modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet3/vmxnet3_drv.c: fix drivers for kernels 2.6.29+. * modules/linux/vmxnet3/*: add shared memory support for faster communication between user space and the device backend; this doesn't affect the regular driver functionality, but is used by some VMware code not part of Tools. * modules/linux/vsock/*: fix an issue where it was possible for users to send VMCI datagrams directly to the hypervisor. * scripts/common/vmware-user.desktop: work around a bug in KDE where desktop files with "NoDisplay" fail to autostart. * scripts/freebsd/suspend-vm-default: use netif to bring down interfaces, since dhclient doesn't understand "-r" in the default install. * services/plugins/vmbackup/*: add some new code used by enhancements being done in the Win32 version of the plugin. * services/vmtoolsd/mainPosix.c: fix running in background when executing vmtoolsd while relying on PATH. * services/vmtoolsd/Makefile.am: point to the correct plugin install directory. * toolbox/*: better command line handling in the CLI utility, plus some code cleanup. * vmware-user/copyPaste.c, vmware-user/copyPasteDnDWrapper.cpp, vmware-user/copyPasteDnDWrapper.h, vmware-user/dnd.c: properly unregister RPCs to avoid multiple registrations (and the ensuing ASSERT) in certain cases. * vmware-user/copyPasteUI.{cpp,h}: change way data is retrieved from the clipboard, using the gtk+ clipboard wait APIs (which turn out to be more reliable than the previous approach). 2009-06-18 Marcelo Vanzin * Resync with internal trunk (2009.06.15) * docs/api/Makefile.am: replace all variables in the doxygen conf file with the correct values. * lib/appUtil/appUtilX11.c: try alternate file extensions during icon search. Sometimes a package lists its icon as icon-foo.png, but the package didn't include icon-foo.png. Instead, it included icon-foo.xpm. Ex: Ubuntu 8.04's hwtest. * lib/guestApp/guestAppPosixX11.c: change detection of the default browser so that the new help system works; the help files are not yet available in open-vm-tools. * lib/hgfs/*, lib/include/cpName.h, lib/include/cpNameLite.h, lib/include/hgfsUtil.h: avoid compiling certain parts of the source in kernel modules. * lib/hgfsServer/*: return correct error when files / directories don't exist. * lib/include/hgfsChannel.h, modules/linux/vmhgfs/*: added support for vsock channel for HGFS. * lib/include/util.h, lib/misc/utilMem.c: un-inline a bunch of functions to reduce the size of binaries. * lib/include/vm_tools_version.h: bumped Tools version. * lib/resolution/resolutionX11.c: fix for issue where the host would send a "topology set" command with a top-left corner that was not (0, 0) and cause the screen to be reconfigured in the wrong way. * lib/unity/unityPlatformX11Window.c: check for errors in calls to XQueryTree. * lib/wiper/wiperPosix.c: check return of fgets() to avoid compiler warnings. * libvmtools/vmtools.c: fix initialization of wiper library on Win32. * modules/Makefile.am: install vsock header file on Linux. * modules/freebsd/vmhgfs/*, modules/linux/vmci/*, modules/linux/vsock/*: changes related to 64-bit Mac drivers, don't affect either the FreeBSD or Linux drivers. * modules/linux/vmhgfs/hgfs.h: removed duplicate file. * modules/linux/vmhgfs/fsutil.c, modules/linux/vmhgfs/inode.c, modules/linux/vmhgfs/module.h: fix issue where two files would get the same inode number in some situations. * modules/linux/vmxnet/vmxnet.c: re-probe vmxnet2 device features on resume from hibernate, to cover the case where a VM is resumed on a platform with a different version of the device backend (bug #2209565). * scripts/resume-vm-default, scripts/suspend-vm-default: use NetworkManager to handle networking where it is available. * services/plugins/hgfsServer/Makefile.am, services/plugins/vix/Makefile.am: fix installation of vmusr plugins that are shared with vmsvc. * services/plugins/timeSync/timeSync.c: fix backwards time sync. * services/vmtoolsd/cmdLine.c, toolbox/toolbox-cmd.c: print build number as part of "-v" output. * toolbox/toolboxcmd-shrink.c: correctly ignore unsupported partitions when shrinking. * toolbox/toolbox-gtk.c: changes for the new help system, not yet available for open-vm-tools. * toolbox/toolboxInt.{c,h}, toolbox/toolboxScripts.c: some code refactoring. * vmware-user/Makefile.am: fix linking when compiling without gtkmm. 2009-05-22 Marcelo Vanzin * Resync with internal trunk (2009.05.18) * configure.ac, m4/vmtools.m4: check for PAM and enable PAM support when available. * configure.ac, services/plugins/*/Makefile.am, tests/*/Makefile.am: avoid the "-rpath" hack to create plugins, using plugin_LTLIBRARIES instead (and manually fixing things when necessary). Thanks to Dominique Leuenberger for the suggestion (and sample patch). * docs/api/Makefile.am: fix doc target directories. * configure.ac, lib/Makefile.am, lib/deployPkg/*, lib/include/deployPkg.h: remove the deployPkg code, which depends on some VMware code that is not yet open source. * lib/backdoor/*, lib/hgfs/*, lib/hgfsBd/*, lib/include/*, lib/include/compat/*, lib/message/*, lib/misc/dbllnklst.c, lib/rpcOut/rpcout.c: as part of sharing code between user-level code and kernel modules, some files have been tagged with more than one license. * lib/dndGuest/*, lib/include/dndBase.h, lib/include/dndMsg.h, lib/include/unity*, lib/unity/unityPlatformX11.c: implement mouse movement from within the guest; this avoids a dependency on "unofficial" mouse APIs in the VMware host code, making DnD more reliable, and makes a few things (such as cancelling an ongoing DnD operation) easier. * lib/file/filePosix.c: make File_FullPath()'s behavior consistent when the input path starts with a '/'. * lib/ghIntegration/ghIntegration.c: send more info about the "start menu" contents to the host (only usable for Windows guests). * lib/ghIntegration/ghIntegrationX11.c: prettify the category names of menu items. This is a temporary solution before actually reading this information from .desktop files. * lib/guestApp/guestApp.c, libguestlib/vmGuestLib.c, lib/include/guestApp.h, toolbox/toolbox-gtk.c, vmware-user/foreignVM*, vmware-user/vmware-user.cpp, configure.ac, lib/Makefile.am, lib/include/socketMgr.h, lib/socketMgr.*: remove code related to "foreign VM" support, which was never really used. * lib/guestInfo/guestInfo.c, lib/include/wiper.h, lib/wiper/wiperPosix.c: properly report disk info for LVM volumes. * lib/hgfsServer/hgfsDirNotify*, lib/hgfsServer/hgfsServer.c: add support for directory / file monitoring. It's currently only implemented on Mac OS X. * lib/hgfsServer/hgfsServer*: fix issue where it was possible to create a file on a read-only share on Windows hosts. * lib/hgfsServer/hgfsServer*, lib/hgfsServerManagerGuest/*, lib/include/hgfs*.h, services/plugins/hgfsServer/hgfsPlugin.c, services/plugins/vix/foundryToolsDaemon.c: some refactoring caused by the work to make HGFS support pluggable transports. * lib/include/procMgr.h, lib/procMgr/procMgrPosix.c: remove ProcMgr_GetAsyncStatus(). * lib/include/vmsupport.h, scripts/vm-support, xferlogs/xferlogs.c, services/plugins/guestInfo/guestInfoServer.c: new feature to automatically collect support data from the guest from the VMware UI. * lib/panicDefault/*, lib/user/*: change file names to avoid clash with another file (Mac OS linker doesn't really like that). * lib/rpcChannel/rpcChannel.c: try to reinitialize the outbound channel on failure. * lib/vixTools/vixTools.c, lib/include/vixCommands.h, lib/include/vixOpenSource.h: add backend for new VIX API call to list the guest's filesystems. * libvmtools/vmtoolsLog.c: lazily open the log file, instead of opening it during configuration of the log system. This way two processes can use the same conf file and not overwrite each other's log files (assuming the conf data is sane). * modules/Makefile.am, modules/linux/vmci/Makefile.kernel, modules/linux/vsock/Makefile.kernel: don't store VMCI module symbols in /tmp during build; this avoids a possible symlink attack that could cause data to be overwritten when building open-vm-tools. * modules/*/*, vmblock-fuse/*: remove a lot of duplicated files by either moving them to a shared location or reusing files that were already available elsewhere. * modules/freebsd/vmblock/subr.c, modules/freebsd/vmblock/vmblock_k.h, modules/freebsd/vmblock/vnoops.c: fix a possible kernel crash caused by trying to read / write to the mount point (something vmware-user does to detect whether it's using fuse or non-fuse vmblock). * modules/linux/pvscsi/*: adds support for a generic msg framework that is currently used to deliver hot-plug/unplug notifications; get rid of a few divisions; fix a bug where pvscsi_probe could return 0 (aka success) if a call to kmalloc() failed; remove a few unused fields. * modules/linux/shared/vmci*: mostly changes related to the host VMCI drivers (removed user-level queue-pair daemon, added support for trusted VMCI endpoints) to keep binary compatibility between the host and guest VMCI drivers. * modules/linux/hgfs/inode.c: check host's access rights when checking file permissions, so that permissions are correctly checked when the guest's user id is different from the host's user id. * modules/linux/bdhandler.*, modules/linux/filesystem.c; modules/linux/tcp.*, modules/linux/transport.*,: postpone opening the channels so that module can load successfully even if shared folders are disabled on the host; fix a synchronization problem between recv and close/open; allow hibernation to work by timing out the recv thread; correctly handle failures in recv, including injecting a dummy error to the pending requests when the recv thread exits; move the recv code to the channel's implementation so that it can be simpler. * modules/linux/vmxnet3/vmxnet3.c, modules/linux/shared/compat_pci.h: fix Wake-On-LAN for 2.6.27 and newer Linux guests. * modules/linux/vsock/linux/*: changes to support trusted VMCI host apps; pull out notification and stats logging code into their own files. * modules/solaris/vmhgfs/vnode.c: do not substitute errors returned by uiomove() calls with EIO, propagate returned error code (which is EFAULT) up the stack. * services/vmtoolsd/Makefile.am, scripts/common/linux/pam.d/vmtoolsd-x64, scripts/common/linux/pam.d/64/vmtoolsd: install the 64-bit PAM config file with the correct name. * services/plugins/powerOps/powerOps.c: fix running default scripts by making sure the path to the script is absolute. * services/vmtoolsd/Makefile.am, services/vmtoolsd/pluginMgr.c: use info from the configure step to define the plugin path; this avoids requiring a symlink to be placed in /etc/vmware-tools for vmtoolsd to be able to find the plugins. * services/vmtoolsd/toolsRpc.c: send the build information to the host so it's logged in the VM's logs. * toolbox/toolbox-cmd.c, toolbox/toolboxcmd-*, toolbox/toolboxCmdInt.h: make string comparison case-insensitive on Win32. * toolbox/toolboxcmd-shrink.c: properly finish the shrinking process by sending the "disk.shrink" RPC to the host. * toolbox/toolboxScripts.c: fix showing default settings for power ops scripts (should show default script enabled, not script disabled). * vmblock-fuse/Makefile.am: fix compilation on FreeBSD. * vmware-user/copyPasteUI.cpp: disallow copy-paste text of size greater than 4MB, instead of truncating the data. * vmware-user/dndUI.*, lib/dndGuest/dnd.cc, lib/include/dndBase.h: remove drag timeout callback (which was not needed), and add new signal to indicate that a GH DnD was cancelled. * vmware-user/Makefile.am: remove C++ link hack (not needed now since vmware-user has C++ code already). 2009-04-23 Marcelo Vanzin * Resync with internal trunk (2009.04.17) * configure.ac, Makefile.am, docs/*: build API docs for vmtools; the documentation files are provided under a BSD-style license. * configure.ac, Makefile.am, guestd/*, lib/Makefile.am, lib/guestInfo/*, lib/include/vmbackup_def.h, lib/include/vmBackup.h, lib/vmBackupLib/*, libvmtools/Makefile.am, services/plugins/vmbackup/vmbackup_def.h: remove guestd from open-vm-tools, and clean up code in other places that was only there because of guestd. * configure.ac, modules/solaris/vmblock/*, modules/solaris/vmmemctl/*: add Solaris vmblock and vmmemctl driver sources. The vmmemctl module also includes a user-level daemon (vmmemctld.c). * lib/conf/conf.c, lib/include/conf.h, libvmtools/vmtoolsConfig.c: remove unused config options. * lib/deployPkg/toolsDeployPkg.h: code refactoring. * lib/dnd/dndClipboard.c: if size of clipboard exceeds the maximum backdoor packet size, only keep text data (dropping the RTF data). * lib/dnd/dndLinux.c, lib/include/dnd.h, lib/include/vmblock.h, vmware-user/copyPaste.c, vmware-user/dnd.c, vmware-user/vmware-user.cpp, vmware-user/vmwareuserint.h, vmware-user-suid-wrapper/main.c: detect whether plain vmblock or vmblock-fuse is being used, allowing the same executable to be used with either. * lib/dndGuest/*, vmware-user/copyPaseDnDWrapper.{cpp,h}, vmware-user/dndUI.{cpp,h}, vmware-user/dragDetWnd.{cpp,h}: vmware-user/vmware-user.cpp: more DnD V3 protocol work. * lib/ghIntegration/*, lib/include/guestCaps.h, lib/include/unityCommon.h: work related to mapping Outlook folders over HGFS and exposing the Windows Recycle Bin to the host (doesn't really affect open-vm-tools). * lib/ghIntegration/ghIntegrationX11.c: restore the native environment when launching external applications. This doesn't really affect open-vm-tools. * lib/guestRpc/*, vmware-user/copyPasteUI.{cpp,h}: implement RTF and file contents copy & paste. * lib/include/circList.h, lib/include/vm_basic_math.h, lib/include/vm_device_version.h, modules/linux/*, modules/Makefile.am: changes to share files between the user space code and the kernel code, instead of duplicating the same source files in different places. * lib/include/rpcChannel.h, lib/rpcChannel/*, tests/testDebug/testDebug.c, test/vmrpcdbg/debugChannel.c: some code cleanup, and fix crash when dealing with multiple reset messages. * lib/include/system.h, lib/system/systemLinux.c, services/vmtoolsd/mainPosix.c: remove System_Daemon() (replaced with Hostinfo_Daemonize()). * lib/include/unityCommon.h, lib/unity/*: ressurrect UNITY_RPC_WINDOW_SHOW and UNITY_RPC_WINDOW_HIDE RPCs. * lib/procMgr/procMgrPosix.c: fix ProcMgr_IsProcessRunning(). * lib/system/systemLinux.c: fix shutdown / reboot commands on Solaris; fix rebuilding of native environment from variables set by VMware scripts (this last one doesn't really affect open-vm-tools). * lib/unicode/unicodeSimpleTypes.c: speed up UnicodeIANALookup, and fix case where C++ constructors could call UnicodeIANALookup before Unicode_Init() was called by lazily creating the internal cache. * libguestlib/*: link libguestlib against libvmtools. This avoids having two definitions of certain symbols (like Debug()) when an application links to both libraries. * modules/linux/vmblock/linux/control.c: only set directory entry owner when needed. * modules/linux/vmhgfs/bdhandler.{c,h}, modules/linux/vmhgfs/dir.c, modules/linux/vmhgfs/file.c, modules/linux/vmhgfs/filesystem.c, modules/linux/vmhgfs/fsutil.c, modules/linux/vmhgfs/inode.c, modules/linux/vmhgfs/module.{c,h}, modules/linux/vmhgfs/page.c, modules/linux/vmhgfs/request.{c,h}, modules/linux/vmhgfs/super.c, modules/linux/vmhgfs/tcp.{c,h}, modules/linux/vmhgfs/transport.{c,h}: cleanup use of atomic variables in HGFS; add a transport abstraction layer, and add an initial version of a socket-based transport (not yet stable and not yet supported by any released VMware product). * modules/linux/vmxnet3/vmxnet3.c: fix build on kernel 2.6.29. * modules/linux/vsock/af_vsock.c: export more functions to other kernel modules; some changes to statistics gathering code. * modules/solaris/vmhgfs/filesystem.c: make module loadable on Solaris 9. * modules/solaris/vmhgfs/vnode.c: unify mapping of HGFS to Solaris error codes. * scripts/*: restart network before running user scripts in resume scripts. * services/plugin/powerOps/powerOps.c: fix running default power scripts. * services/vmtoolsd/pluginMgr.c: better error logging. * toolbox/toolbox-cmd.c: fix help string. * vmblock-fuse/block.c: fix vmblock-fuse compilation on FreeBSD. 2009-03-18 Marcelo Vanzin * Resync with internal trunk (2009.03.13) * configure.ac: check for FreeBSD kernel tree when building modules; warn about which version of make to use when building kernel modules on FreeBSD and Solaris; add compiler defines for identifying Solaris 9 and 11. * configure.ac, modules/Makefile.am: handle SYSDIR on FreeBSD. * guestd/main.c, modules/solaris/vmhgfs/Makefile: remove HGFS-related that is now obsolete with the recent changes to the HGFS module on Solaris. * guestd/toolsDaemon.c: default to the configuration dir when the power script path is not absolute. * guestd/toolsDaemon.c, lib/include/guestInfo.h, lib/netUtil/netUtilLinux.c: handle case when all network interfaces have been disabled and send an "unknown" IP address to the host. * guestd/toolsDaemon.c, services/vmtoolsd/toolsRpc.c: always send TOOLS_VERSION_UNMANAGED from an open-vm-tools build, so there's no need for a config file option anymore. * hgfsclient/*: make it link to libvmtools to avoid code duplication. * lib/appUtil/appUtil.c: update list of "skippable" apps when figuring out an application's path. * lib/auth/authPosix.c, scripts/linux/pam.d/*, guestd/Makefile.am, services/vmtoolsd/Makefile.am : change the name of the PAM application to "vmtoolsd" to reflect the new service name. * lib/dnd/dndFileContentsUtil.h, lib/dnd/dndInt.h, lib/dndGuest/*.hh, and corresponding files in lib/include: relocate private headers. * lib/ghIntegration/ghIntegration.c, lib/ghIntegration/ghIntegrationInt.h, lib/ghIntegration/ghIntegrationX11.c, lib/include/unityCommon.h: glue code for Outlook mirrored folder, which does not affect open-vm-tools. * lib/guestRpc/guestlibV3.x, lib/include/vmGuestLib.h, libguestlib/vmGuestLib.c: add new guestlib counters. * lib/include/conf.h, toolbox/toolbox-gtk.c: remove the need for the "helpdir" config option; this doesn't really affect open-vm-tools since the help files are not yet included. * lib/include/guest_os.h, lib/misc/hostinfoPosix.c: more guest OS names; fix name used to identify Solaris to match what VMware's host code expects. * lib/include/guestStats.h: documentation changes. * lib/include/hostinfo.h, lib/user/hostinfoPosix.c: add a new function that behaves like daemon(3), but is more Mac OS-friendly. * lib/include/toolsLogger.h, lib/Makefile.am, lib/toolsLogger/*: removed library, which is not used anymore. * lib/include/vm_basic_types.h, lib/misc/timeutil.c: fixes to compile under (Open) Solaris 11. * lib/include/vmtoolsApp.h, services/plugins/vmbackup/stateMachine.c, services/vmtoolsd/mainLoop.c, services/vmtoolsd/mainPosix.c, services/vmtoolsd/serviceObj.c, services/vmtoolsd/toolsCoreInt.h: add new signal handler to gather debugging information from a running vmtoolsd instance. * lib/misc/posixPosix.c: fix off-by-one error. * lib/unity/unity.c, lib/unity/unityPlatform.h, lib/unity/unityPlatformX11.c, lib/unity/unityPlatformX11Settings.c: always send Unity updates using RPCI; this avoids a possible race between replying to an incoming RPC and sending an Unity update from a different thread; also, API documentation updates. * lib/unity/unityPlatformX11.c: verify the DnD detection window was initialized before actually using it. * lib/unity/unityPlatformX11Settings.c, lib/unity/unityPlatformX11Window.c: reset _NET_WM_DESKTOP as necessary before exiting Unity; this could cause guest taskbars to disappear when in Unity mode. * lib/unity/unityPlatformX11.c, lib/unity/unityPlatformX11Window.c, lib/unity/unityX11.h: examine WM_CLIENT_LEADER when gathering application information; certain applications use this property to define the window where the WM_COMMAND property should be. * lib/vixTools/vixTools.c: do not follow symlinks when deleting files in the guest using the VIX API. * libvmtools/vmtools.c, libvmtools/vmtoolsLog.c: allow the logging subsystem to be re-configured, and clean up the logging data when unloading the library; allow ${USER} and ${PID} to be used in log file paths. * modules/freebsd/vmblock/subr.c, modules/freebsd/vmblock/vnops.c: fix kernel panic on FreeBSD 7. * modules/linux/*/Makefile: remove GCC version check. * modules/linux/*/compat_wait.h: fix COMPAT_DEFINE_WAIT for "vanilla" 2.4 kernels. * modules/linux/vmhgfs/Makefile.normal: fix build of HGFS module on 2.4 kernels. * modules/linux/vmxnet/*, modules/linux/vmxnet3/*: avoid using compat functions when they're not needed; add compatibility functions for newer Linux kernels. * modules/linux/vsock/linux/af_vsock.c: fix two races; one when the socket state changed between calls to VSockVmciRecvStreamCB and VSockVmciRecvPktWork, and another when trying to read from the socket after a RST arrived after the socket got a detach notification. * modules/solaris/vmxnet3/*: add Solaris vmxnet3 driver. * rpctool/*: add "rpctool", a simple, stand-alone tool to send RPC commands to the host software. * services/plugins/guestInfo/guestInfoServer.c: don't cache configuration data. * services/plugins/guestInfo/perfMonLinux.c: fix problem with overwriting flags after GuestInfoMonitorReadMeminfo() was called. (Same as fix to lib/guestInfo on previous release.) * services/plugins/powerOps/powerOps.c: handle power ops-related options sent from the host. * services/vmtoolsd/mainLoop.c: handle re-loading the configuration file. * services/vmtoolsd/mainPosix.c: exec after forking on Mac OS, since CoreFoundation classes don't work after a fork. * services/vmtoolsd/pluginMgr.c: allow both 32 and 64 bit plugins to be installed on Solaris by loading them from the appropriate directory; add library loading code that is not really needed (nor used) in open-vm-tools. * services/vmtoolsd/toolsRpc.c: send another "capability" the host expects from Tools. * toolbox/toolbox-gtk.c: add F1 shortcut to invoke help. * toolbox/toolboxScripts.c: fix issue with freeing data that should not be freed. * vmware-user/*: implement the new DnD protocol (V3). 2009-02-18 Marcelo Vanzin * Resync with internal trunk (2009.02.13) * configure.ac, m4/vmtools.m4: clean up a lot of the library detection code. * configure.ac: remove support for gtk+ 1.2 (code already depended on it in any case); enforce need for glib 2.6.0 or later due to new code being added; add detection for gtkmm; check for C++ compiler when it's needed; reorder the include path to avoid clashing with system headers in some situations. * guestd/foundryToolsDaemon.*, vmware-user/foundryToolsDaemon.*, guestd/Makefile.am, vmware-user/Makefile.am: moved shared source files to a new place to avoid duplication. * hgfsmounter/hgfsmounter.c: add support for Solaris. * lib/appUtil/appUtilX11.c: fix loading of icons when the name has a period. * lib/dnd/dndClipboard.c, lib/dnd/dndInt.h, lib/dnd/dndMsg.c, lib/dnd/Makefile.am, lib/dndGuest/*, lib/include/copyPasteBase.h, lib/include/copyPaste.hh, lib/include/copyPasteRpc.hh, lib/include/copyPasteRpcV3.hh, lib/include/dndBase.h, lib/include/dndClipboard.h, lib/include/dndFileContentsUtil.h, lib/include/dndFileList.hh, lib/include/dnd.h, lib/include/dnd.hh, lib/include/dndInt.h, lib/include/dndMsg.h, lib/include/dndRpc.hh, lib/include/dndRpcV3.hh, lib/include/dndTransportGuestRpc.hh, lib/include/dndTransport.hh, lib/include/libExport.hh, vmware-user/copyPaste.cpp, vmware-user/copyPasteUI.{cpp,h}, vmware-user/copyPasteV3.h, vmware-user/copyPasteWrapper.{cpp,h}, vmware-user/dnd.cpp, vmware-user/Makefile.am, vmware-user/vmware-user.{c,cpp}, vmware-user/vmwareuserInt.h, vmware-user/stringxx/string.{cc,hh}, vmware-user/stringxx/ubstr_t.hh: add support for new version of the DnD protocol. * lib/guestInfo/guestInfoPerfMonLinux.c: fix problem with overwriting flags after GuestInfoMonitorReadMeminfo() was called. * lib/guestRpc/guestlibV3.x, lib/include/vmGuestLib.h, libguestlib/vmGuestLib.c: add new host stats. * lib/guestRpc/Makefile.am: fix a few compatibility issues with non-GNU versions of make. * lib/hgfsServer/hgfsServer.c, lib/hgfsServer/hgfsServerInt.h, lib/hgfsServer/hgfsServerLinux.c, */hgfsProto.h, modules/freebsd/vmhgfs/vnops.c, modules/freebsd/vmhgfs/vnopscommon.{c,h}: don't trust the local VFS layer, check the HGFS server to see if an operation would succeed. * lib/include/rpcChannel.h, lib/rpcChannel/*: add new Guest RPC channel abstraction library used by the new "core services" code. * lib/include/vmrpcdbg.h, tests/*: add test code from the "core services" project. * lib/include/vmtoolsApp.h, lib/include/vmtoolsd_version.h, services/vmtoolsd/*: add "vmtoolsd", the new service "shell" used in the "core services" project. * lib/unity/unityPlatformX11Window.c: don't send initial "region" updates for shaped windows. This works around an issue where resizing a shaped window would not work as expected in Unity mode. * lib/wiper/wiperPosix.c: fix major number detection for disks on newer Linux kernels. * libvmtools/Makefile.am: link more libraries needed by vmtoolsd and the new plugins. * modules/linux/pvscsi/pvscsi.c, modules/linux/pvscsi/pvscsi_version.h: use PCI-specific memory allocation functions and update driver version. * modules/linux/vmci/vmciKernelIf.c: disable queue pair support in the host version of the driver on older Linux kernels. This doesn't affect the guest driver. * modules/linux/vmci/vmci_queue_pair.h: implement MSG_PEEK support on Linux driver. * modules/linux/vmhgfs/bdhandler.c, modules/linux/vmhgfs/compat_sched.h, modules/linux/vmmemctl/os.c: fix issue with HGFS module interfering with suspend / hibernation on newer Linux kernels (bug #2523263). * modules/linux/vmhgfs/compat_cred.h, modules/linux/vmhgfs/file.c, modules/linux/vmhgfs/filesystem.c, modules/linux/vmhgfs/inode.c: changes for compatibility with newer Linux kernels, where it's not possible to change fsuid/capabilities directly anymore. * modules/linux/vmhgfs/compat_pagemap.h, modules/linux/vmhgfs/page.c: fix warning, and compatibility changes for newer Linux kernels (2.6.28.1 and newer; bug #2530616). * modules/linux/vmhgfs/inode.c: fix creation of symlinks (bug #2531303). * modules/linux/vmxnet/vmxnet.c: use PCI-specific memory allocation functions. * modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet3/vmxnet3.c: add option to disable LRO. * modules/linux/vsock/af_inet.{c,h}, modules/linux/vsock/util.{c,h}: add MSG_PEEK support; remove ifdefs that were disabling support for queue pairs on the host kernel module; fix compilation with certain versions of gcc (bug #2531283). * modules/solaris/vmhgfs/*: move backdoor handling code to the HGFS driver; this makes the user-level code to handle the driver (currently in vmware-guestd) obsolete. * modules/solaris/vmxnet/*: add vmxnet driver for Solaris, under the CDDL. * services/plugins/*: add all currently available "core services" plugins. The current set of plugins provide the functionality available in vmware-guestd; there are a few plugins that replace functionality from vmware-user, but not all features are ported yet (and vmtoolsd - with vmware-user plugins - and vmware-user cannot run at the same time). * toolbox/toolboxAbout.c: fix the copyright character. * toolbox/toolbox-cmd.c: reword a few messages, fix typos. * toolbox/toolboxCmdInt.h, toolbox/toolboxcmd-record.c, toolbox/toolbox-gtk.c, toolbox/toolboxRecord.c: remove the "record" functionality from tools (due to internal request). * toolbox/toolboxInt.c, toolbox/toolboxScripts.c, toolbox/toolbox-scripts.c: changes to use the new config file format used by the "core services" code. * */Makefile.am: make sure 'rm' and 'mv' are being used instead of $(RM) and $(MV) (which are not defined by automake; bug #2492040). 2009-01-21 Marcelo Vanzin * Resync with internal trunk (2009.01.19) * configure.ac: detect the presence of FUSE libraries. * configure.ac, Makefile.am: compile kernel modules for Solaris, and vmblock-fuse module if FUSE is available. * lib/ghIntegration/ghIntegrationX11.c: retrieved localized application names. * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoPosix.c, lib/include/hostinfo.h, lib/misc/hostinfo_misc.c, lib/misc/hostinfoPosic.c, lib/vixTools/vixTools.c: refactoring to move code shared with other VMware products to a common library. * lib/guestRpc/guestlibV3.x, lib/guestRpc/Makefile.am, lib/include/vmGuestLib.h, libguestlib/*: add new iteration of the "guestlib" protocol. This is a more extensible solution than the current protocol, and should make it easier to add new information when needed. * lib/include/dynarray.h, lib/include/dynbuf.h, lib/misc/dynarray.c, lib/misc/dynbuf.c: make some DynArray/DynBuf functions inline for speed. * lib/include/unityCommon.h: more documentation about the Unity protocol. * lib/unity/unityPlatformX11.c: fix Unity<->guest desktop ID mappings. * libvmtools/vmtoolsLog.c: change the way log domains are configured; now sub-domains inherit the default handler for the app if no handler is specified. * modules/freebsd/vmhgfs/state.c, modules/freebsd/vmhgfs/state.h, modules/freebsd/vmhgfs/vnopscommon.{c,h}: implement support for mmap on the Mac OS driver, which allows running executables from an HGFS share. The FreeBSD module still does not support this functionality. * modules/freebsd/vmhgfs/transport.{c,h}: refactoring for sharing structure definitions. * modules/linux/pvscsi/pvscsi.c, modules/linux/vmblock/linux/module.c, modules/linux/vmci/vmci_drv.c, modules/linux/hgfs/module.c, modules/linux/vmmemctl/os.c, modules/linux/vmsync/sync.c, modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet3/vmxnet3.c: add support for Novell's proprietary module info tag ("supported"). * modules/linux/vmci/vmciKernelIf.c: add support for VMCI queue pairs on the host. This does not affect the driver when it runs inside virtual machines. * modules/linux/vmci/*.h, modules/linux/vsock/*.h: some changes in the common code to support Mac OS X, and also queue pairs on the Solaris VMCI module. * modules/linux/vsock/af_vsock.{c,h}: add functions for registering with the vsock driver from within the kernel. * modules/linux/*/Makefile: add $(LINUXINCLUDE) to the compiler flags; this allows compiling the modules against recent kernels which removed that from $(KBUILD_CPPFLAGS). * modules/Makefile.am: add support for compiling Solaris kernel modules. * modules/solaris/vmhgfs/*: initial release of the Solaris HGFS driver in open-vm-tools. Driver is licensed under the CDDL 1.0. * vmblock-fuse/*: add the user-level implementation of the vmblock driver, which is build on top of FUSE, to open-vm-tools. vmware-user hasn't yet been modified to use this version of vmblock. * vmware-user/copyPaseV3.h: new header introduced during development of the next version of copy paste / DnD for X11 platforms. 2008-11-23 Marcelo Vanzin * Resync with internal trunk (2008.12.19) * configure.ac, */Makefile.am: standardize on using libtool archives for the libraries. This also means several makefiles were removed, since there's no need to build two archives of the same library anymore. * configure.ac: add logic to detect glib 2.6; this is the minimum version required by the "Core Services" project. Currently it's an optional dependency. * configure.ac: disable Unity when user specifies --disable-multimon. * configure.ac: actually build the pvscsi modules if the detected kernel version supports it. * configure.ac, Makefile.am, lib/guestInfo/Makefile.am, lib/stubs/Makefile.am, libvmtools/*, lib/include/vmtools.h: add the "vmtools" shared library used in the "Core Services" project. The library is a collection of a lot of other libraries used by most VMware Tools programs, and adds some functionality on top of glib that is used in the "Core Services" project. Currently no other components from that project are available as part of open-vm-tools. * lib/deployPkg/deployPkgLog.h, lib/deployPkg/toolsDeployPkg.h: moved private headers out of the public header directory. * lib/guestRpc/Makefile.am, modules/Makefile.am: fix the makefiles so that it's possible to build open-vm-tools from a directory different from the source dir. * lib/hgfsServer/hgfsServer.c: changes to support aliases on Mac OS hosts. * lib/hgfsServer/hgfsServerLinux.c: changes to map Windows attributes to Mac OS FileInfo. * lib/include/circList.h: removed unused file. * lib/include/unityCommon.h, lib/unity/unity.c: changes to add documentation to various application RPCs used in Tools. * lib/misc/posixPosix.c, toolbox/toolboxScripts.c: fix include path for syslimits.h on FreeBSD. * lib/unity/unityPlatformX11.c: better detection of the guest's work area boundaries; fixes a problem when dragging a Window in Unity mode with the host's task bar on the left/right of screen would result in weird behavior. * lib/unity/unityPlatformX11Settings.c, lib/unity/unityPlatformX11Window.c, lib/unity/unityX11.h: preserve the _NET_WM_DESKTOP setting when hiding windows; this fixes a problem where hiding a panel and later restoring it would result in the wrong _NET_WM_DESKTOP property being set for the panel, causing it to only display on the first virtual desktop. * modules/linux/vmci/*: minor changes related to internal development of the Mac OS drivers. * modules/linux/vmhgfs/page.c: fix HGFS driver for kernel 2.6.28. * modules/linux/vsock/linux/af_vsock.c: added code to gather some performance statistics for the driver. * toolbox/toolbox-gtk.c: a few fixes to the help functionality. * vmware-user/vmware-user.c, vmware-user-suid-wrapper/main.c: change the "blockFd" argument to have an extra dash so it follows the convention of common command line parsing libraries. * Other bug fixes and changes in shared code that don't affect open-vm-tools. 2008-11-18 Marcelo Vanzin * Resync with internal trunk (2008.11.14) * lib/include/vm_version.h: Bumped TOOLS_VERSION. * guestd/toolsDaemon.c, lib/include/vm_app.h: changes related to host-side configuration of power operations. * hgfsclient/hgfsclient.c, lib/dnd/dndCommon.c, lib/dnd/dndLinux.c, lib/hgfs/*, lib/hgfsServer/*, lib/include/cpName.h, lib/include/dnd.h, lib/include/hgfsEscape.h, lib/include/staticEscape.h, modules/*/vmhgfs/*, vmware-user/dnd.c: refactor the HGFS character escaping code; escape invalid characters when the sender allows characters in the file name that the receiver does not allow. * lib/hgfsServer/hgfsServerLinux.c: return proper error code when the remote path points to a non-existent directory. * lib/deployPkg/deployPkg.c, lib/deployPkg/deployPkgLog.c, lib/include/deployPkg.h, lib/include/rpcin.h, lib/rpcin/rpcin.c: refactoring for the Tools Core Services project. * lib/dnd/dndCommon.c: don't ASSERT if the staging directory is not actually a directory. * lib/dynxdr/xdrutil.c, lib/include/xdrutil.h: more XDR-related utility functions. * lib/file/file.c, lib/file/fileLockPrimitive.c, lib/include/vm_basic_defs.h: replace use of strtok with strtok_r. * lib/guestApp/guestApp.c, lib/include/guestApp.h: more utility functions. * lib/guestApp/guestApp.c, lib/include/backdoor_def.h, vmware-user/pointer.c: add the ability to detect whether the mouse hardware can be used in absolute mode, which allows for auto grab / auto ungrab to work. * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoPosix.c, lib/guestRpc/nicinfo.x: provide the prefix length of an IPv6 address in a separate field of the NicInfo struct. * lib/guestInfo/guestInfoPerfMonLinux.c: reduce log spew. * lib/guestInfo/guestInfoServer.c, lib/include/guestInfo.h: changes related to how the VMware code in the host handles Tools version information. * lib/include/unityCommon.h: changes related to documenting the Unity API. * lib/include/unity.h, lib/unity/*: remove a few unused RPCs, add a new function used to notify the host of the status of Unity. * modules/freebsd/vmhgfs/state.c, modules/vmhgfs/freebsd/vnops.c, modules/vmhgfs/freebsd/vnopscommon.*: support symlinks on FreeBSD and Mac OS. * modules/freebsd/vmhgfs/worker.c: fix mutex not being unlocked in some error paths. * modules/linux/dkms.conf: add rudimentary dkms support. * modules/linux/pvscsi/*: add a driver for VMware's paravirtualized SCSI device. * modules/linux/*/Makefile, modules/linux/vmci/Makefile.kernel, modules/linux/vsock/Makefile.kernel: add support for exporing symbols, needed for dependent modules to load if a kernel >= 2.6.26 is compiled with CONFIG_MODVERSIONS. Make the vsock module reference the vmci module's symbols. * modules/vmmemctl/freebsd/os.c: add sysctl to get driver status. Information can be retrieved with "sysctl vm.vmmemctl". * modules/linux/vmci/vmci_defs.h, modules/linux/vmci/vmci_call_defs.h, modules/linux/vsock/vmciHostKernelAPI.h: changes related to VMCI work on VMware ESX. * modules/linux/vsock/linux/*: improve performance of some applications by improving the poll behavior and sending less packets when waiting for a response. * modules/linux/vmsnc/sync.c: fix panic on kernels < 2.6.20. * modules/linux/vmxnet3/vmxnet3.c, modules/linux/vmxnet3/vmxnet3_int.h, modules/linux/vmxnet3/vmxnet3_version.h: inherit net device features to avoid having the kernel setting the PSH flag on every TCP packet (among other issues). * modules/*/*/*: Reflected changes from elsewhere. * scripts/common/vmware-user.desktop: add missing "Type" information; fixes auto-start of vmware-user on Ubuntu 8.10. * toolbox/*: fix a GTK+ warning caused when trying to unref a dialog instance from a signal callback. * vmware-user/copyPaste.c: work around an issue when OpenOffice's "cut" command is used; it sets the timestamp of both the clipboard and the primary selection, but only puts data in the clipboard. * Other files: minor refactorings, and changes unrelated to open-vm-tools. 2008-10-13 Adar Dembo * Resync with internal trunk (2008.10.09) * configure.ac, modules/Makefile.am: Added a command-line option to skip privileged operations during make install (requested by Dennis Leroy). Integrated new vmxnet3 kernel module. * configure.ac, lib/guestInfo/Makefile.am, lib/guestInfo/guestInfoPerfMonLinux.c, lib/include/vm_procps.h: Removed open-vm-tools dependency on libproc-dev by providing some procps bits and pieces in our own vm_procps.h (Sourceforge bug 1960947). * hgfsmounter/Makefile.am: Removed chown calls. Only call chmod if we're running as root (requested by Dennis Leroy). * */foreignVMToolsDaemon.c, */foundryToolsDaemon.[ch], lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoServer.c, lib/include/guestInfoServer.h, lib/include/vixTools.h, lib/rpcin/rpcin.c, lib/vixTools/vixTools.c, vmware-user/copyPaste.c, vmware-user/vmware-user.c: More refactoring from the Tools core services project. * */foundryToolsDaemon.c: Changed HGFS mounting behavior such that the global HGFS share is mounted at /mnt/hgfs instead of relying on "mount -a". * guestd/toolsDaemon.[ch], lib/include/backdoor_def.h, lib/include/system.h, lib/include/vm_app.h, lib/system/systemLinux.c: Added backwards time synchronization functionality. Moved Tools scripts checking from VMX to guestd. * hgfsmounter/hgfsmounter.c: Added handling for multiple "-o" flags on the command line. * lib/dynxdr/dynxdr.c: Fixed x_putint32 behavior on 64-bit Solaris. * lib/file/*, lib/include/codeset.h, lib/include/file.h, lib/include/fileIO.h, lib/include/hostinfo.h, lib/include/loglevel_user.h, lib/include/productState.h, lib/include/timeutil.h, lib/include/unicodeTypes.h, lib/include/vixCommands.h, lib/include/vix.h, lib/include/vm_basic_asm.h, lib/include/vm_basic_types.h, lib/include/vm_legal.h, lib/include/vm_product.h, lib/include/win32util.h, lib/include/x86cpuid.h, lib/misc/codeset.c, lib/misc/codesetOld.[ch], lib/misc/posixPosix.c, lib/misc/timeutil.c, lib/region/region.c, lib/string/bsd_vsnprintf.c, lib/unicode/*, lib/user/hostinfoPosix.c, modules/freebsd/vmhgfs/sha1.c, modules/*/*/vm_device_version.h, modules/linux/*/vmci_iocontrols.h, modules/linux/*/vmci_version.h, modules/linux/vmhgfs/hgfsEscape.h: Changes from work unrelated to open-vm-tools on internal trunk. * lib/ghIntegration/ghIntegrationX11.c: Fixed some bugs in menu-spec and desktop-entry-spec support in Linux guests. * lib/guestApp/guestApp.c, lib/include/guestApp.h, lib/include/statelogger_backdoor_def.h, toolbox/Makefile.am, toolbox/toolbox-cmd.c, toolbox/toolbox-gtk.c, toolbox/toolboxCmdInt.h, toolbox/toolboxGtkInt.h, toolbox/toolboxInt.h, toolbox/toolboxRecord.c, toolbox/toolboxcmd-record.c: Patches from Yiwen Zhang to add basic record/replay controls to the gtk and command-line toolbox apps. * lib/guestInfo/guestInfoPosix.c: Fixed a bug where we assumed the primary interface's addresses were all IPv4 addresses. * lib/guestInfo/guestInfoServer.c: Fixed a memory leak. * lib/guestRpc/Makefile.am, lib/guestRpc/unityActive.x, lib/include/guestCaps.h, lib/include/unityCommon.h, lib/unity/unity.c, vmware-user/Makefile.am: Added new unityActive xdr protocol, used for tracking whether Unity is enabled or not. * lib/hgfsServer/hgfsServer.c, lib/hgfsServer/hgfsServerLinux.c, lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c, lib/include/hgfsProto.h: Fixed bug where we were invalidating HGFS handles on the share of entire drive ("/"). Added optional symlink following behavior to HGFS server. Fixed a UTF-8 validation issue. Added volume ID field to attribute fields. * lib/include/vm_tools_version.h: Bumped internal Tools backdoor version. * lib/include/vm_version.h: Bumped TOOLS_VERSION. * lib/procMgr/progMgrPosix.c: Fixed impersonation behavior so that uids are passed to setresuid instead of gids. Added alternate way to list processes in situations where a process lacks a command line. * lib/region/region.c: Reforked xorg miregion.c and apply open-vm-tools specific patches. * lib/unity/*, lib/unityWindowTracker/unityWindowTracker.c: Fixed an overflow that lead to a panic when a window title exceeded 1024 bytes. Fixed some initialization assumptions when using virtual desktops. * lib/unity/unityPlatformX11Window.c: Fixed an issue with restacking windows above non-existent windows. Other minor fixes. * modules/*/*/*: Reflected changes from elsewhere. * modules/linux/*/Makefile.kernel: Changed clean target to remove Module.markers and modules.order. * modules/linux/vsock/include/compat_sock.h, modules/linux/vsock/*: Fixed several issues in vsock. 2008-09-03 Adar Dembo * Resync with internal trunk (2008.08.29) * Makefile.am, aclocal.m4, m4/*: Moved macros to 'm4' subdir. * compile, config.guess, config.sub, config/*, depcomp, install-sh, ltmain.sh, missing: Moved auxiliary build tools to 'config' subdir. * configure.ac: Moved macros and auxiliary build tools into separate subdirectories. Added command line option to force the use of gtk1 over gtk2. Cosmetic fixes. Reworked libicu detection. Switched over to libtool-2.2. Added library check for new gdk symbol. Added library check for libnotify. Reworked use of macros from AC_PATH_XTRA and some X11 library checks. * */foundryToolsDaemon.c, toolbox/toolbox-cmd.c, guestd/main.c, lib/guestInfo/guestInfoPerfMonLinux.c, lib/guestInfo/guestInfoPosix.c, lib/misc/posixPosix.c, lib/panic/panic.c, lib/system/systemLinux.c, modules/linux/vsock/linux/util.c, xferlogs/xferlogs.c: Added checks for return codes of certain functions and passed %s to formatted string functions where appropriate (needed to compile on Ubuntu Intrepid). * lib/appUtil/appUtilX11.c: Fixed command line skipping logic and added more icon paths. Removed unnecessary chdir(2) canonicalization logic. * lib/deployPkg/runDeployPkgPosix.c, lib/file/fileIO.c, lib/file/fileIOPosix.c, lib/file/fileLockPrimitive.c, lib/file/filePosix.c, lib/hgfsServer/hgfsServerLinux.c, lib/include/bsdfmt.h, lib/include/file.h, lib/include/fileIO.h, lib/include/iovector.h, lib/include/msgfmt.h, lib/include/str.h, lib/include/vm_basic_defs.h, lib/include/vm_basic_types.h, lib/misc/hostname.c, lib/misc/idLinux.c, lib/misc/posixPosix.c, lib/SLPv2Parser/*.c, lib/wiper/wiperPosix.c, toolbox/toolboxScripts.c: Added FreeBSD compatibility glue. * guestd/toolsDaemon.c, lib/file/file.c, lib/foundryMsg/foundryPropertyListCommon.c, lib/image/imageUtilPng.c, lib/include/appUtil.h, lib/include/backdoor_def.h, lib/include/conf.h, lib/include/cpuid_info.h, lib/include/guest_os.h, lib/include/hostinfo.h, lib/include/imageUtil.h, lib/include/imageUtilTypes.h, lib/include/log.h, lib/include/loglevel_user.h, lib/include/netutil.h, lib/include/posix.h, lib/include/timeutil.h, lib/include/util.h, lib/include/uuid.h, lib/include/vix.h, lib/include/vixOpenSource.h, lib/include/vm_atomic.h, lib/include/vm_legal.h, lib/include/vm_version.h, lib/include/x86cpuid.h, lib/misc/codesetOld.c, lib/misc/timeutil.c, lib/string/bsd_vsnprintf.c, lib/user/util.c, lib/user/utilPosix.c, lib/vixTools/vixTools.c, modules/linux/*/vmci_kernel_if.h, modules/linux/vmxnet/compat_timer.h, toolbox/toolboxCmdInt.h, toolbox/toolboxcmd-*.c: Changes from work unrelated to open-vm-tools on internal trunk. * lib/ghIntegration/ghIntegration.c, lib/guestRpc/ghiGetBinaryHandlers.x: Don't send oversized messages. Increased maximum number of binary handlers. * lib/ghIntegration/ghIntegrationX11.c, lib/guestApp/guestAppPosix.c, lib/include/guestApp.h, lib/include/system.h, lib/system/systemLinux.c, toolbox/toolbox-gtk.c: Improved "run program" functionality by restoring program environment and stripping any VMware wrapper script changes to LD_LIBRARY_PATH. * lib/guestApp/guestAppPosixX11.c: Now using glib to open URLs instead of system(3). Improved gnome and kde session detection. * lib/guestApp/Makefile.am: This library needed GTK_CPPFLAGS too. * lib/guestInfo/guestInfoInt.h, lib/guestInfo/guestInfoPosix.c, lib/guestInfo/guestInfoServer.c: Added logic to optionally convert subnet mask to an ASCII string. * lib/guestRpc/Makefile.am: Cleaned up generated xdr headers better. * lib/hgfsServer/hgfsServer.c, lib/hgfsServer/hgfsServerInt.h, lib/hgfsServer/hgfsServerLinux.c: Fixed problems when packing V3 replies. * lib/hgfsServer/hgfsServerLinux.c: Fixed UTF-8 normal form D/C conversions on the root directory. * lib/include/dndGuest.h: Changed preprocessor usage to allow gtk1 to access UnityDnD. * lib/include/dnd.h, vmware-user/copyPaste.c: Code motion. * lib/include/guestCaps.h: Resort the capabilities table. * lib/include/rpcin.h, lib/rpcIn/rpcin.c, : Beginnings of the Tools core services. This is a full-fledged refactoring of the Tools userlevel apps to a "service" vs. "plugin" programming model. * lib/include/vmblock.h, modules/*/vmblock/block.c, modules/*/vmblock/stubs.c, modules/*/vmblock/stubs.h: Changes needed to support the fuse-based implementation of vmblock (coming soon). * lib/include/vm_tools_version.h: Some Tools version bumps. * modules/*/*/*: Reflected changes from elsewhere. * modules/*/*/compat/compat_stdarg.h: Added compatibility wrappers for stdarg features. * modules/freebsd/vmhgfs/debug.*: Cosmetic fixes. * modules/freebsd/vmhgfs/*: Make driver compliant with HGFSv3. * modules/*/vmmemctl/vmballoon.c: Allow module to yield the processor when allocating many pages. * modules/linux/*/autoconf/cachector1.c, modules/linux/*/include/compat_sched.h, modules/linux/*/include/compat_semaphore.h, modules/linux/*/include/compat_slab.h, modules/linux/vmblock/linux/filesystem.c, modules/linux/*/Makefile.kernel, modules/linux/vmhgfs/bdhandler.c, modules/linux/vmhgfs/filesystem.c, modules/linux/vmhgfs/module.h, modules/linux/vmhgfs/request.c, modules/linux/vmsync/sync.c, modules/linux/vsock/linux/af_vsock.c: Fix modules for 2.6.27 kernels. * modules/linux/*/Makefile: Fixed DRIVER target. * modules/linux/vmci/vmci_drv.c: Moved interrupt registration to be after driver initialization. * modules/linux/vsock/linux/af_vsock.c, modules/linux/vsock/linux/af_vsock.c: Added optimized flow control protocol. * toolbox/toolboxScripts.c, toolbox/toolboxShrink.c: Cosmetic fixes. * vmware-user/copyPaste.c, vmware-user/dnd.c: Fixed edge case behavior with file copy paste and DnD. * vmware-user/modconfig.c, vmware-user/notify.c, vmware-user/vmware-user.c, vmware-user/vmwareuserInt.h: Added stubbed modconfig module out-of-date notification framework. Not useful for open-vm-tools, hence the stubs. 2008-08-08 Adar Dembo * Resync with internal trunk (2008.07.24) * configure.ac, */Makefile.am: Landed support for command line Toolbox, Unity, vsock, and vmci. Refactored and reformatted a few things. Improved portability by using $(SED) and AC_PROG_SED instead of "sed", $(MKDIR_P) and AC_PROG_MKDIR_P instead of "mkdir -p", $(LN_S) and AC_PROG_LN_S instead of "ln -s". Changed icu feature detection and linking to rely on C++ linker instead of C linker. Fixed module compilation checks on FreeBSD. Fixed $(DESTDIR) handling (patch by Mike Auty). Refactored lib/strUtil into lib/misc. Changed hgfsmounter install hook to symlink mount.vmhgfs. Renamed libghIntegrationStub to libGhIntegrationStub. Fixed compilation of lib/guestApp when using --without-x (reported by Martin Preishuber). Renamed libunityStub to libUnityStub. Fix build on FreeBSD by using ":=" instead of "=" when exporting module directories. The vmware-user desktop link now executes vmware-user-suid-wrapper. Properly install vmware-user-suid-wrapper. * */foundryToolsDaemon.c, lib/vixTools/vixTools.c: Use a larger result packet when handling impersonated HGFS requests (since HGFSv3 uses larger packets). * guestd/main.c: Moved foreign VM check. * guestd/toolsDaemon.*: Added plumbing for HGFS usability library calls. * hgfsmounter/hgfsmounter.c: Added support for passing options to the MacOS HGFS driver. * lib/appUtil/*, lib/include/appUtil.h: New library for Unity support. * lib/auth/authPosix.c: Don't try using PAM from the Tools. * lib/dnd/dndCommon.c, lib/dnd/dndLinux.c, lib/file/file.c, lib/file/fileIOPosix.c, lib/file/filePosix.c, lib/include/dnd.h, lib/include/loglevel_user.h, lib/include/panic.h, lib/include/posix.h, lib/include/strutil.h, lib/unicode/unicodeBase.h, lib/include/unicodeOperations.h, lib/include/vix.h, lib/include/vm_app.h, lib/include/vm_assert.h, lib/include/vm_product.h, lib/include/x86cpuid.h, lib/misc/codeset.c, lib/misc/hashTable.c, lib/misc/strutil.c, lib/misc/timeutil.c, lib/panic/panic.c, lib/string/bsd_vsnprintf.c, lib/strUtil/*, lib/unicode/unicodeCommon.c, lib/unicode/unicodeSimpleBase.c, lib/unicode/unicodeStatic.c, lib/user/hostinfoPosix.c, lib/user/util.c, lib/user/utilPosix.c: Changes from work unrelated to open-vm-tools on the internal trunk. * lib/backdoor/backdoorInt.h, lib/deployPkg/runDeployPkgInt.h, lib/dnd/dndInt.h, lib/file/fileInt.h, lib/guestInfo/guestInfoInt.h, lib/hgfs/cpNameInt.h, lib/hgfsServer/hgfsServerInt.h, lib/impersonate/impersonateInt.h, lib/include/backdoorInt.h, lib/include/bsd_output_int.h, lib/include/cpNameInt.h, lib/include/dndInt.h, lib/include/fileInt.h, lib/include/guestInfoInt.h, lib/hgfsServer/hgfsServerInt.h, lib/include/impersonateInt.h, lib/include/runDeployPkgInt.h, lib/include/toolsLoggerInt.h, lib/include/unicodeInt.h, lib/string/bsd_output_int.h, lib/toolsLogger/toolsLoggerInt.h, lib/unicode/unicodeInt.h: Moved some internal header files out of the general include directory and into the appropriate libraries. * lib/ghIntegration/*: New library for Unity support. * lib/guestApp/guestAppPosixX11.c: Reset the value of LD_LIBRARY_PATH before running the web browser. * lib/guestInfo/guestInfoPosix.c, lib/include/guest_os.h: Fixed a typo in Mandriva guest detection. Added Asianux. * lib/guestInfo/guestInfoServer.c: Fixed behavior for sending nicInfo updates to the host (patch by Jason Lunz). * lib/guestRpc/ghi*.*: New xdr protocol for Unity support. * lib/guestRpc/nicinfo.x: Correctly applied LGPL to file. * lib/hgfs/cpNameLinux.c: Allow building for versions of Solaris newer than 10. * lib/hgfsServer/hgfsServer.c, lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c, lib/include/hgfsServerPolicy.h: Provide an override setting for disabling case conversion during file lookups. * lib/hgfsServer/hgfsServerLinux.c: Only perform case insensitive file lookups if a case sensitive lookup fails. * lib/image/imageUtilPng.c, lib/include/imageUtil.h, lib/include/imageUtilTypes.h: New library for Unity support. * lib/include/conf.h, toolbox/toolbox-gtk.c: Robustified the help page discovery mechanism. * lib/include/dndGuest.h: Allow inclusion of header into source files without GTK2 support. * lib/unity/*, lib/include/guestCaps.h, lib/include/unityCommon.h: New library for Unity support. * lib/include/hgfsUtil.h: Fixed a precedence issue in a macro. * lib/raster/*, lib/include/rasterConv.h: New library for Unity support. * lib/region/*, lib/include/region.h: New library for Unity support. * lib/include/system.h: Added new OS type for WinXP 64-bit, reformatted enums. * lib/unityWindowTracker/*, lib/include/unityWindowTracker.h: New library for Unity support. * lib/include/vm_version.h: Bumped TOOLS_VERSION. * lib/wiper/wiperPosix.c: Replaced BSD_VERSION with __FreeBSD_version. * modules/*/*/*: Reflected changes from elsewhere. * modules/freebsd/vmhgfs/*: Reflected changes from MacOS HGFS work, and fixed file permissions so that they're not all owned by root. * modules/linux/vmblock/linux/dentry.c: Changed d_revalidate to properly invalidate negative dentries. * modules/linux/vmci/*: Landed the Virtual Machine Communication Interface guest module. * modules/linux/vmmemctl/os.c: Fixed vmmemctl to build on 2.6.26 (reported by Pavol Rusnak). * modules/linux/vmsync/sync.c: Fixed vmsync to build on 2.6.26 (reported by Pavol Rusnak). * modules/linux/vsock/*: Landed the VMCI sockets interface module. * modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet/vmxnet2_def.h, modules/linux/vmxnet/vmxnetInt.h: Increased rx ring size for enhanced vmxnet2. * toolbox/*: Refactored pieces of GTK Toolbox and landed the command line Toolbox. Fixed mnemonic collisions in the GTK Toolbox. * vmware-user/copyPaste.c: Fixed several bugs with file copy paste behavior. * vmware-user/notify.c, vmware-user/vmware-user.c, vmware-user/vmwareuserInt.h: Added stubs for notification framework. * vmware-user/pointer.c: Reverted fix for bug with clipboard retry behavior. * vmware-user/vmware-user.c: Fixed build with gtk 1.2 (reported by Stephen Duncan). Added signal handlers for SIGUSR1/SIGUSR2 used by VMware Tools installer to reload vmware-user cleanly during a Tools upgrader. Reload vmware-user on a fatal X I/O error. Don't panic if run outside of a VM. Don't leave Unity mode on a Tools reset. 2008-07-01 Adar Dembo * Resync with internal trunk (2008.06.30) * configure.ac, lib/guestApp/*, toolbox/Makefile.am, vmware-user/Makefile.am: Split lib/guestApp into two libraries, one with X11 functionality, and one without. Improved detection of gnome-open. * guestd/*, lib/netUtil/netUtilLinux.c: guestd now compiles for MacOS guests. * guestd/main.c, lib/include/system.h, lib/system/systemLinux.c: Refactored GuestdWritePidfile into System_Daemon. * guestd/toolsDaemon.c: Fixed a backwards time synchronization issue. Thanks to Eric Castan for reporting the bug. * lib/conf/conf.c, lib/include/conf.h: Removed obsolete configuration keys and values. * lib/file/*, lib/dict/*, lib/foundryMsg/*, lib/include/backdoor_def.h, lib/include/codeset.h, lib/include/config.h, lib/include/file_extensions.h, lib/include/fileInt.h, lib/include/loglevel_user.h, lib/include/msg.h, lib/include/msgid.h, lib/include/posix.h, lib/include/preference.h, lib/include/unity.h, lib/include/vixCommands.h, lib/include/vix.h, lib/include/vmbackup_def.h, lib/include/vmBackup.h, lib/include/vm_basic_defs.h, lib/include/vm_basic_types.h, lib/include/vm_product.h, lib/include/win32util.h, lib/include/x86cpuid.h, lib/misc/codeset.c, lib/misc/codesetOld.c, lib/misc/codesetOld.h, lib/misc/posixPosix.c, lib/strUtil/strutil.c, lib/user/hostinfoPosix.c, lib/user/util.c, lib/vmBackupLib/stateMachine.c, modules/*/vmxnet/net.h: Changes from work unrelated to open-vm-tools on the internal trunk. * lib/guestRpc/Makefile.am: Added comment about misuse of CFLAGS. * lib/hgfsServer/hgfsServer.c: Corrected pointer arithmetic so that new node and search allocation works consistently in 64-bit apps. * lib/hgfsServer/hgfsServerLinux.c, lib/include/hgfsProto.h: Added HGFS_ATTR_HIDDEN_FORCED and set it when returning hidden files. * lib/hgfsServer/*, lib/hgfsServerPolicy/hgfsServerPolicyGuest.c, lib/include/hgfsServerInt.h, lib/include/hgfsServerPolicy.h: Refactored and cleaned up some code. * lib/include/resolution.h, lib/resolution/*, vmware-user/vmware-user.c: Refactored some functions. * lib/include/vm_legal.h: Added another patent to the patent string. * lib/include/vm_tools_version.h: Added a pair of Tools version macros. * lib/include/vm_version.h: Bumped Tools product version. * lib/Makefile.am: Included a fix for compilation --without-x. Thanks to Mark Foster for reporting the issue. * lib/misc/Makefile.am, lib/misc/shared/Makefile.am: Realphabetized some sources and added missing source files. * lib/misc/posixWin32.c: Removed unneeded file from tree. * lib/procMgr/procMgrPosix.c: Made safe for -fPIC and for MacOS. * modules/*/*/*: Reflected changes from elsewhere. * modules/freebsd/vmhgfs/*: Added some code to handle codeset conversions between UTF-8 precomposed and decomposed strings. * modules/linux/vmhgfs/*: Refactored string escaping/unescaping code. * toolbox/*: Added mnemonics for some buttons. * vmware-user/pointer.c: Fixed bug in clipboard retry behavior. * vmware-user/vmware-user.c: Added handlers for SIGUSR1 and SIGUSR2 to facilitate smooth vmware-user upgrades with respect to the vmblock kernel module. 2008-06-20 Elliot Lee * Resync with internal trunk (2008.06.13) * FreeBSD 7/8 fixes from Martin Blapp. * Fix getpwnam_r etc. on FreeBSD & Solaris. * configure.ac: Add --without-kernel-modules, --with-linux-release, and --with-linuxdir (gissa). * configure.ac, lib/guestRpc/*, lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoServer.c, lib/dynxdr/*, {vmware-user,guestd}/foreignVMToolsNetworking.c, guestd/Makefile.am, {vmware-user,guestd}/foundryToolsDaemon.c, lib/include/dynxdr.h, lib/include/guestInfo.h, lib/include/vmxrpc.h, lib/include/xdrutil.h, lib/Makefile.am, lib/netUtil/*, lib/vixTools/Makefile.am: Add support for XDR encoding of RPC values, including the NicInfoV2 structure. * guestd/stub.c, hgfsclient/Makefile.am, hgfsclient/stub.c, hgfsclient/stub-user-util.c, hgfsmounter/Makefile.am, hgfsmounter/stub.c, lib/stubs/*, libguestlib/Makefile.am, libguestlib/stubs.c, toolbox/Makefile.am, toolbox/stub.c, vmware-user/stub.c: Centralize stubs. * lib/guestInfo/guestInfoPerfMonLinux.c: Convert ioInRate and ioOutRate to be in terms of KB instead of pages. * lib/hgfsBd/hgfsBd.c, lib/hgfsServer/hgfsServer.c, lib/hgfsServer/hgfsServerLinux.c: Large packet support, and additional case-insensitivity fixes. * lib/include/hgfsBd.h, lib/include/hgfs.h, lib/include/hgfsProto.h: Add HGFS error code. * lib/hgfs/hgfsUtil.c, lib/guestInfo/Makefile.am, lib/guestInfo/guestInfoPosix.c, lib/guestApp/guestApp.c, lib/foundryMsg/foundryMsg.c, lib/file/fileLockPrimitive.c, lib/file/fileIOPosix.c, lib/file/fileLockPosix.c, guestd/toolsDaemon.c, guestd/debugStdio.c, guestd/main.c, lib/hgfsServerManagerGuest/hgfsServerManagerGuest.c, lib/include/codeset.h, lib/include/cpuid_info.h, lib/include/dnd.h, lib/include/file_extensions.h, lib/include/fileInt.h, lib/include/ghIntegration.h, lib/include/guestApp.h, lib/include/guestStats.h, lib/include/hgfsServerInt.h, lib/include/hgfsUtil.h, lib/include/hostinfo.h, lib/include/loglevel_user.h, lib/include/netutil.h, lib/include/panic.h, lib/include/posix.h, lib/include/unicode*.h, lib/include/util.h, lib/include/vix.h, lib/include/vixTools.h, lib/include/vm_app.h, lib/include/vm_basic_defs.h, lib/include/vm_product.h, lib/include/vm_tools_version.h, lib/include/vm_version.h, lib/include/x86cpuid.h, lib/misc/codeset.c, lib/misc/codesetOld.c, lib/misc/codesetOld.h, lib/misc/hashTable.c, lib/misc/hostname.c, lib/misc/timeutil.c, lib/panic/panic.c, lib/string/str.c, lib/sync/syncMutex.c, lib/system/systemLinux.c, lib/unicode/*.c, lib/unityStub/*, lib/user/hostinfo.c, lib/user/hostinfoPosix.c, lib/vixTools/*, modules/linux/vmxnet/*, toolbox/debugStdio.c, vmware-user/debugStdio.c, vmware-user/dnd.c, vmware-user/main.c: Bug fixes. * modules/linux/vmxnet/*: Remove unused BPF code. Add ethtool callbacks to get & set driver settings. * lib/user/util.c: Add function for getting backtraces. * lib/resolution/*, vmware-user/*, lib/Makefile.am, configure.ac: Move resolution-changing code into separate library. * guestd/main.c, lib/include/tools.h: Allow disabling tools version reporting to the host, via config file. * lib/rpcIn/*, lib/include/rpcin.h, guestd/toolsDaemon.c, toolbox/toolbox-gtk.c: Updated RPC API * lib/include/dndGuest.h: Helper API for DnD code * modules/freebsd/vmhgfs/*, modules/freebsd/vmmemctl/*, modules/freebsd/vmblock/*, modules/linux/vmhgfs/*, modules/linux/vmmemctl/*: Reflect changes from main source tree. * vmware-user/copyPaste.c: Copy/paste cleanup. * vmware-user/vmware-user.c: Updated locking code to use X11 display instead of lockfiles. 2008-06-03 Adar Dembo * Resync with internal trunk (2008.05.28). * configure.ac, Makefile.am, */Makefile.am: Added rudimentary `make install` support. Fixes Sourceforge bug 1839981. * configure.ac, Makefile.am, vmware-user-suid-wrapper/*: Added vmware-user-suid-wrapper to help autostart vmware-user. Added some informational tags to AC_DEFINE macros. * */debugStdio.c: Fixed a format string vulnerability in Debug. Allocate fd on the stack in DebugToFile. * lib/auth/authPosix.c, lib/dnd/dndCommon.c, lib/dnd/dndLinux.c lib/impersonate/impersonate.c: Add inclusion of vmware.h and refactor some include statements. * lib/file/file.c, lib/include/file.h: Added File_UnlinkNoFollow function. * lib/file/fileIO.c, lib/file/fileLockPrimitive.c, lib/include/fileIO.h: Added error case for ENAMETOOLONG to FileIO_Lock. Constified 'buf' in FileIO_Pwrite. * lib/file/fileIOPosix.c: Removed coalescing and decoalescing code. Consolidated some Unicode calls. * lib/file/filePosix.c: Reworked some error handling logic. * lib/foundryMsg/foundryMsg.c: Refactored buffer encoding and decoding logic into a single pair of functions. * lib/foundryMsg/foundryThreads.c, lib/include/foundryThreads.h lib/include/util.h, lib/misc/util_misc.c: Changed generic thread type from uintptr_t to Util_ThreadID. * lib/hgfsServer/*, lib/hgfs/hgfsProto.h, modules/linux/vmhgfs/*: Additional HGFSv3 fixes and refactoring. * lib/include/dbllnklst.h, lib/misc/dbllnklst.c: Constified argument to DblLnkLst_IsLinked. * lib/include/dnd.h: Added support for DnD of RTF. * lib/include/fileInt.h: Removed prototype of FileLockFileSize. * lib/include/hashTable.h, lib/misc/hashTable.c: Cosmetic changes. Added HashTable_ReplaceIfEqual. * lib/include/loglevel_user.h: Added hpet loglevel. * lib/include/msg.h: Removed prototype of MsgSetPostStderrBlock. * lib/include/posix.h: Removed certain includeCheck allowances. * lib/include/productState.h: Added VDM client product. * lib/include/unicode*, lib/unicode/*: Ongoing i18n work. * lib/include/vixCommands.h: Added command to set snapshot information. * lib/include/vix.h: Added more errors and a new flag. * lib/include/vixOpenSource.h: Reworked asserts and added VIX_ASSERT. * lib/include/vm_app.h: Added Tools tray app. * lib/include/vm_product.h: Reworked VMRC product definitions and added VDM client product definitions. * lib/include/vm_tools_version.h: Added WS65 Tools version. * lib/include/vm_version.h: Bumped Tools version. Added logic for VMRC product. * lib/include/x86cpuid.h: Modified a flag and trimmed an unneeded macro. * lib/misc/codesetOld.c: Implement UTF-16 codest conversion to UTF-8 for CURRENT_IS_UTF8. * lib/misc/dynbuf.c: Modified dynbuf growing behavior. * lib/misc/posixDlopen.c, lib/misc/posixInt.h, lib/misc/posixPosix.h: Refactored codeset conversion code into PosixConvertToCurrent. * lib/misc/posixWin32.c: Added some path checks. * lib/misc/timeutil.c: Win32-wrappified TimeUtil_GetTimeFormat. * lib/misc/vmstdio.c: Reduce virtual memory usage and add '\r' as a line ending in StdIO_ReadNextLine. * lib/rpcout/rpcout.c: Added comments. * lib/str/str.c: Cosmetic changes. * lib/vixTools/vixTools.c: Added unlink(2) logic to avoid deleting symlink targets. Cosmetic changes. * modules/*/*/*: Reflect changes from elsewhere in the source tree. * modules/linux/vmhgfs/super.c: Fix vmhgfs to properly report the available space on the host (Sourceforge bug 1924246). * vmware-user/vmware-user.c: Add advisory locking code to help maintain only one vmware-user instance per X session. * xferlogs/xferlogs.c: Fix a formatted string vulnerability. 2008-05-12 Elliot Lee * Resync with internal trunk (2008.05.08). * configure.ac, **/Makefile.am: Use CPPFLAGS instead of CFLAGS to eliminate warning about proc/sysinfo.h. * guestd/foreignVMToolsNetworking.c, vmware-user/foreignVMToolsNetworking.c lib/hgfsServer/hgfsServerLinux.c, lib/include/hgfsServerInt.h, modules/linux/vmhgfs/bdhandler.c, modules/linux/vmhgfs/dir.c, modules/linux/vmhgfs/file.c, modules/linux/vmhgfs/filesystem.h, modules/linux/vmhgfs/fsutil.h, modules/linux/vmhgfs/inode.c, modules/linux/vmhgfs/link.c, modules/linux/vmhgfs/module.h, modules/linux/vmhgfs/page.c, modules/linux/vmhgfs/request.c, modules/linux/vmhgfs/request.h: Whitespace cleanups. * guestd/main.c: Removed "blessed app" code for starting vmware-user. Hooray! * lib/deployPkg/deployPkg.c: Remove unneeded Utf8 conversion for Windows. * lib/file/filePosix.c: Use new Posix_RealPath implementation. * lib/guestApp/guestApp.c, lib/include/guestApp.h: Remove/cleanup UTF-8 related RPC functions. * lib/guestInfo/guestInfoPerfMonLinux.c, lib/guestInfo/guestInfoPosix.c, lib/include/guestInfo.h, lib/include/guestInfoInt.h, lib/include/guestStats.h: Rename structures to GuestMemInfo, GuestNicInfo, and GuestDiskInfo. * lib/guestInfo/guestInfoServer.c, lib/include/guest_msg_def.h: As above, and also GUESTMSG_MAX_IN_SIZE moved to guest_msg_def.h, and misc locking updates. Also add GuestInfoServer_Main(), and cleanup whitespace. * lib/hgfsServer/hgfsServer.c: Cleanup UTF-8 handling. * lib/include/codeset.h: Update defines that indicate whether the current platform is using UTF-8. * lib/include/dnd.h: Add prototypes for a couple of string conversion functions. * lib/include/file_extensions.h: Add OVF and Archived OVF file extensions. * lib/include/file.h: C++ guard thingies. Update a couple of function prototypes to work on file descriptors instead of filenames. * lib/include/hashTable.h, lib/include/guest_os.h, lib/include/loglevel_defs.h, lib/include/stats_user_defs.h, lib/include/stats_user_setup.h, lib/include/str.h, lib/include/unicodeTypes.h, lib/include/util.h: Allow inclusion in kernel modules... * lib/include/loglevel_user.h: As above, and add a couple of loglevel variables. * lib/include/util.h, lib/misc/util_misc.c: Allow inclusion in kernel modules as above, and add some utility functions on Windows for manipulating canonical paths. * lib/include/hgfsProto.h, lib/include/hgfsUtil.h: Move request/reply payload macros to hgfsProto.h. * lib/include/hgfsServerPolicy.h: Add ShareList management prototypes and structure members. * lib/include/msg.h: Add function prototypes for creating and posting lists of messages. * lib/include/system.h: Add types & functions related to desktop switch monitoring on Windows. * lib/include/unicodeOperations.h: Add/update inline unicode operations. * lib/include/vixCommands.h: Add VIX requests and events. * lib/include/vmbackup_def.h, lib/vmBackupLib/stateMachine.c: Move backup status enum to public header. * lib/include/vm_basic_asm_x86_64.h: Div643232 now also works on MSC. * lib/include/vm_basic_defs.h: Add debug output macros for Windows drivers. * lib/include/vm_basic_types.h: Update the FMTPD macro, add SCANF_DECL macro for arg checking on scanf-like functions. * lib/include/x86cpuid.h: Defines for AMD L2/L3 cache separately, and CPUID for Nehalem. * lib/misc/codesetOld.c: Bug fixes and general unicode handling updates. * lib/system/systemLinux.c: Use Posix_Getenv/Posix_Setenv impls. * lib/vixTools/vixTools.c, lib/vmBackupLib/scriptOps.c: Bug fixes. * modules/freebsd/*, modules/linux/*: Updates to correspond to updates of files in main tree. * modules/freebsd/vmhgfs/hgfs_kernel.h: Bug fixes. * modules/freebsd/vmxnet/vm_device_version: Add SCSI_IDE_HOSTED_CHANNEL define, update SCSI_MAX_CHANNELS. * modules/freebsd/vmxnet/vmnet.def: Add capabilities for IPv6 checksumming and TSO, and large packet TSO. * lib/include/vmblock.h, modules/linux/vmblock/linux/control.c, modules/linux/vmblock/linux/vmblockInt.h: Use a macro to better abstract the vmblock mount point & device. * vmware-user/vmware-user.c: Add SIGPIPE to the list of signals that vmware-user handles. 2008-05-02 Adar Dembo * Resync with internal trunk (2008.04.19). * configure.ac, guestd/Makefile.am, hgfsclient/Makefile.am, lib/misc/*/Makefile.am, lib/string/*/Makefile.am, toolbox/Makefile.am, vmware-user/Makefile.am, xferlogs/Makefile.am: Added libicu support for codeset conversions. This includes some makefile logic as well as autoconf arguments for controlling libicu behavior at compile-time. * */foreignVMToolsNetworking.c, lib/vixTools/vixTools.c: Unicode fixes. * */foundryToolsDaemon.c, lib/foundryMsg/vixTranslateErrOpenSource.c, lib/panic/panic.c, lib/printer/printer.c: Added calls to Win32 Unicode wrappers. * guestd/main.c: Cleaned up guestInfo server when guestd shuts down. * guestd/toolsDaemon.c, vmware-user/resolution.c: Disabled multi-mon advertisement for Win2k. * lib/auth/authPosix.c, lib/dnd/dndLinux.c, lib/file/*, lib/impersonate/impersonatePosix.c, lib/include/mntinfo.h, lib/sync/syncWaitQPosix.c, lib/user/hostinfoPosix.c, lib/user/util.c, lib/user/utilPosix.c, lib/wiper/wiperPosix.c: Added calls to POSIX Unicode wrappers. * lib/file/*: Replaced calls to string functions with calls to the "safe" family of string functions. * lib/dict/dictll.c, lib/include/dictll.h: Detect and tolerate UTF-8 dictionary files that contain the UTF-8 BOM. * lib/err/*, lib/include/err.h, lib/include/msgfmt.h, lib/include/msg.h: Added support for localization of error strings. * lib/foundryMsg/foundryThreads.c, lib/include/foundryThreads.h, lib/misc/util_misc.c: Added opaque type for threads/process IDs. * lib/guestInfo/guestInfoServer.c: Removed separate thread context. * lib/hgfsServer/*, lib/include/hgfs*.h: Additional HGFSv3 cleanup. * lib/hgfsServer/hgfsServerLinux.c: Added calls to POSIX Unicode wrappers. Fixed some alias detection code for MacOS. * lib/include/backdoor_def.h: Added backdoor call for debugging events. * lib/include/bsdfmt.h, lib/string/bsd_vsnprintf.c, lib/string/bsd_vsnprintfw.c: Replaced BSDFmt_WCSonv with BSDFmt_WChartoUTF8. * lib/include/codeset.h, lib/include/codesetOld.h, lib/misc/codeset.c, lib/misc/codesetOld.c, lib/string/convertutf.h: Implemented libicu-backed codeset layer. When building without libicu, fallback on codesetOld. * lib/include/guestApp.h: Added wide versions of dictionary functions. * lib/include/loglevel_user.h: Added two new loglevels. * lib/include/posix.h, lib/misc/posixPosix.c: Added new POSIX wrappers. * lib/include/str.h: Clarified the use of some functions. * lib/include/syncMutex.h, lib/include/syncWaitQ.h: Removed unneeded macros. * lib/include/unicode*.h, lib/unicode/*: Ongoing Unicode work. * lib/include/util.h: Added Util_FreeStringList, removed Util_FreeList. * lib/include/uuid.h: Added new UUID creation scheme. * lib/include/vix*.h: Tweaked some VIX commands, errors, and properties. * lib/include/vmBackup.h, lib/vmBackupLib/scriptOps.c, lib/vmBackupLib/stateMachine.c: Moved disabled targets logic from library to Windows VSS provider. * lib/include/vm_basic_asm_x86*.h: Allow emitted FX functions to modify main memory as a side effect. * lib/include/vm_tools_version.h: Bump Tools version. * lib/include/vm_version.h: Added several product versions. * modules/linux/vmhgfs/*: Additional cleanup for HGFSv3. Use new kthread wrapper when possible. Bump module version. * modules/linux/vmmemctl/*: Use new kthread wrapper when possible. Remove dead delayed work code. Bump module version. * modules/linux/*/compat_kthread.c: Added kthread wrapper implementation for modules that use kernel threads. * modules/*/*/*: Reflect header file changes from elsewhere in the source code tree. * vmware-user/copyPaste.c, vmware-user/pointer.c, vmware-user/vmwareuserInt.h: Stop wastefully polling for pointer updates if the VMX is new enough. * xferlogs/xferlogs.c: Fixed a warning in the call to fwrite. (Thanks to Denis Leroy for reporting this bug.) 2008-04-14 Elliot Lee * Resync with internal trunk (2008.04.01). * Fixed legal header on all LGPL-licensed files. * vmware-user/resolution.c: Normalize the display topology that comes in from the host, and report 'global_offset' capability. * toolbox/Makefile.am, vmware-user/Makefile.am, lib/misc/Makefile.am, lib/misc/atomic.c, lib/Makefile.am, lib/atomic/*, hgfsclient/Makefile.am: Move libAtomic stuff into libmisc * vmware-user/foundryToolsDaemon.c, lib/vixTools/vixTools.c, lib/include/hgfsServerInt.h, guestd/toolsDaemon.c, guestd/foundryToolsDaemon.c: Remove WIN9XCOMPAT, and some SOCKET_MGR code. * vmware-user/copyPaste.c: Copy/paste fixes for cross-platform operation. * modules/linux/vmxnet/vmnet_def.h: Add SG_SPAN_PAGES capability. * modules/linux/vmxnet/vm_device_version.h: Update some device limits. * modules/linux/*/compat_sched.h: Add TASK_COMM_LEN define. * modules/linux/*/compat_kernel.h, modules/linux/*/kernelStubsLinux.c: Add vsnprintf define. * modules/linux/*/x86cpuid.h: Add new CPUs. * modules/linux/vmhgfs/vmhgfs_version.h: Bump HGFS version. * modules/linux/*/vm_basic_asm_x86.h, modules/linux/*/vm_basic_asm_x86_64.h, lib/include/vm_basic_asm_x86.h, lib/include/vm_basic_asm_x86_64.h: Formatting fixes, and change asm directives used. * modules/linux/vmhgfs/module.h, modules/linux/vmhgfs/filesystem.c, modules/linux/vmhgfs/bdhandler.c, modules/linux/*/compat_kthread.h: compat_kthread fixes. * modules/freebsd/vmxnet/net_compat.h, modules/freebsd/vmxnet/if_vxn.c: Updates for FreeBSD 7.0. (Thanks to Martin Blapp for contributing to these changes.) * lib/misc/util_misc.c, lib/include/loglevel_user.h, lib/user/hostinfoPosix.c, lib/misc/hostname.c: Bugfix. * lib/unityStub/unityStub.c, lib/include/unity.h: Add stub and enums related to DnD support. * lib/unicode/unicodeSimpleTypes.c, lib/unicode/unicodeSimpleTransforms.c, lib/unicode/unicodeSimpleBase.c, lib/unicode/unicodeCommon.c, lib/include/unicodeTypes.h, lib/include/unicodeTransforms.h, lib/include/unicodeBase.h, lib/include/unicodeCommon.h: Add additional Unicode-related functions. * lib/sync/syncMutex.c, lib/include/syncMutex.h: Add TryLock method. * lib/strUtil/strutil.c: Add int64-related functions. * lib/string/str.c: Compile fix * lib/string/bsd_output_shared.c: Better handling of floating point on Windows. * lib/include/progMgr.h, lib/procMgr/procMgrPosix.c: Clarify that the strings are in UTF-8, do conversion as needed. * lib/include/posix.h, lib/misc/posixPosix.c, lib/misc/posixWin32.c, lib/file/filePosix.c: Add new Posix_ function implementations, and unicodify existing ones. * lib/misc/hashTable.c, lib/include/hashTable.h: Add lock-less hash table functions. * lib/misc/util_misc.c, lib/include/w32util.h: Add a couple of Win32 utility functions. * lib/include/vm_version.h: Add WS5 config version. * lib/include/vm_atomic.h: Add typecasts to atomic operations to make compilers stop complaining, and expand the AtomicUseFence option. * lib/include/vm_app.h: Add a couple of HGFS-related options. * lib/include/vix.h: Update a few errors and other macros. * lib/include/vixCommands.h, lib/foundry/foundryMsg.c: Change a bunch of structure members from int32 to uint32, and add a parsing function. * lib/include/msgfmt.h, lib/include/msg.h: Additional message-handling prototypes. * lib/include/guestInfoInt.h, lib/include/guestInfo.h, lib/guestInfo/Makefile.am, lib/guestInfo/guestInfoServer.c, lib/guestInfo/guestInfoPosix.c, lib/guestInfo/guestInfoPerfMonLinux.c: Add IPv6 support, and the ability to read mem stats on Linux. * lib/include/fileIO.h, lib/file/fileIOPosix.c: Add MacOS function related to Time Machine. * lib/guestApp/guestApp.c: Use Posix_ variants of functions. * lib/ghIntegrationStub/ghIntegrationStub.c: Add GHI capabilities stubs. * lib/dnd/dndCommon.c, lib/file/file.c: Use new Unicode_Format() function, bugfix. * guestd/main.c: Fix a security bug. * configure.ac: Allow calling libdnet 'dumbnet' for Debian systems. Detect libprocps. 2008-03-19 Adar Dembo * Resync with internal trunk (2008.03.13). * vm_version.h: Updated Tools version. * configure.ac: Added dynamic dnet detection and --without-dnet flag. * guestd/debugStdio.c, lib/include/system.h, lib/system/systemLinux.c: Modified debugging to file behavior to prepend debug strings with human readable timestamps. * guestd/main.c, guestd/toolsDaemon.c, lib/conf/conf.c, lib/guestApp/guestApp.c, lib/include/guestApp.h: Internationalized GuestApp_GetInstallPath and GuestApp_GetconfPath. * lib/auth/authPosix.c, lib/dnd/dndLinux.c, lib/file/*, lib/impersonate/impersonatePosix.c, lib/include/fileInt.h, lib/include/posix.h, lib/misc/posix*.c: Refactored, extended, and made use of the set of POSIX internationalization-safe function wrappers. * lib/dnd/dndCommon.c, lib/include/dnd.h, lib/include/dndInt.h, vmware-user/copyPaste.c, vmware-user/dnd.c: Replaced some duplicated UTF-8 formatting code with calls to lib/unicode. * lib/guestInfo/guestInfoPosix.c: Replaced the old syscall-based implementation of nicinfo with a simpler implementation that uses dnet. * lib/guestInfo/guestInfoServer.c, lib/include/guestInfo.h, lib/include/guestInfoInt.h: Added Win32 implementation of meminfo. POSIX implementation to follow. * lib/hgfsServer/hgfsServerLinux.c: Replaced a direct readlink(3) call with a call to the POSIX wrapper for readlink(3). Relax an overeager ASSERT in symlink checking when using the special empty share. * lib/include/codeset.h, lib/string/bsd_vsnprintf.c, lib/string/str.c, lib/unicode/unicodeSimpleOperations.c, lib/unicode/unicodeSimpleUTF16.h: Refactored ICU routines from unicodeSimpleUtf16.h to codeset.h, which is now licensed under the ICU license (BSD variant). * lib/include/file.h, lib/file/file.c: Added function File_StripSlashes. * lib/include/hgfsProto.h: Removed an A acute from a comment to allow the file to be built on Windows systems where the default language isn't English. * lib/include/hostinfo.h, lib/include/util.h, lib/user/hostinfoPosix.c, lib/user/util.c, lib/user/utilPosix.c: More conversions to lib/unicode. Added Util_ZeroFreeStringW function for Windows in util.h. * lib/include/msg.h: Removed obsolete NO_MSGFMT macro. * lib/include/unicodeBase.h, lib/unicode/unicodeCommon.c, lib/unicode/unicodeSimpleBase.c: Added some more encoding functions. * lib/include/vixCommands.h, lib/include/vixOpenSource.h: Added another user credential type, some command flags, some command layouts, some error codes, some properties, and tweaked existing commands. * lib/include/vixTools.h: Added VixToolsUserIsMemberOfAdministratorGroup function. * lib/include/vm_assert.h, lib/include/vm_basic_defs.h: Move IMPLIES to vm_basic_defs.h. Removed some vprobes definitions. * lib/include/vmBackup.h, lib/vmBackupLib/scriptOps.c, lib/vmBackupLib/stateMachine.c: Added infrastructure to disable quiescing targets from a config file. * lib/include/vm_basic_asm.h: Changed __GET_CPUID2 handling for Windows. * lib/include/vm_produt.h: Added VDM product. * lib/include/vm_tools_version.h: Bumped internal Tools version. * lib/include/win32util.h, lib/misc/hostname.c, lib/misc/util_misc: Refactored functions to separate set of Win32 wrappers (next to the POSIX wrappers mentioned earlier). * lib/misc/codeset.c: Made CodeSetGetCurrentCodeSet non-static. * lib/misc/*/Makefile.am: Added POSIX wrappers to build system. * lib/strUtil/strutil.c: Fixed bug in StrUtil_EndsWith function. * lib/include/unicodeTypes.h, lib/unicode/unicodeSimpleTypes.c: Removed ISO-8859-11 encoding. Added cross-reference of IANA character set names, windows code pages, and ICU encodings. * lib/vixTools/vixTools.c: Impersonation tweaks. * modules/*/*/*: Reflect header file changes from elsewhere in the source code tree. 2008-03-11 Adar Dembo * vm_version.h: Updated Tools version. * modules/vmblock/linux/*: Make vmblock build under 2.6.25-rc2. The dentry and mount objects have been moved out of struct nameidata and into the new struct path. Also, path_release() is now path_put(). * modules/vmsync/linux/*: Make vmsync build under 2.6.25-rc2. The same changes were needed here as in vmblock above. 2008-03-10 Adar Dembo * vm_version.h: Updated Tools version. * modules/vmhgfs/linux/*: Make vmhgfs build under 2.6.25-rc1. The iget() function has been removed and filesystems are now expected to implement it themselves using iget_locked(). 2008-02-27 Elliot Lee * configure.ac, guestd/Makefile.am, toolbox/Makefile.am, vmware-user/Makefile.am: Allow passing custom LDFLAGS in to build process (patch by Mike Auty). * Resync with internal trunk (2008.02.27). * guestd/foundryToolsDaemon.c, lib/vixTools/vixTools.c, vmware-user/foundryToolsDaemon.c: Win9x compat changes. * guestd/toolsDaemon.c: Style fixes. * hgfsmounter/hgfsmounter.c: Bug fixes. * lib/dnd/dndLinux.c, lib/dnd/dndCommon.c: Move some code to the platform-independant file, some DnDv3 support. * lib/include/dnd.h, lib/include/dndInt.h: DnDv3 support. * lib/file/file.c, lib/file/fileIO.c, lib/file/fileIOPosix.c, lib/file/fileLockPrimitive.c, lib/file/filePosix.c, lib/include/file_extensions.h, lib/include/fileInt.h, lib/include/fileIO.h: Move functions around, Unicode fixes, misc fixes. * lib/foundryMsg/foundryPropertyListCommon.c: Error handling fixes. * lib/hgfsServer/*.c, lib/include/hgfs*.h, modules/freebsd/vmhgfs/*, modules/linux/vmhgfs/*: HGFS v3 support, updates to improve code re-use between the FreeBSD and MacOS X ports, and updates to make the Linux port build on 2.6.25-rc1 (but not rc2, yet). * lib/include/auth.h, lib/include/codeset.h, lib/include/hostinfo.h, lib/include/str.h, lib/include/unicode*.h, lib/include/vm_basic_types.h, lib/misc/hostname.c, lib/unicode/*.c, lib/user/hostinfoPosix.c: Unicode fixes. * lib/include/backdoor_def.h: Add a new command for use by the BIOS in checking the GuestOS against Darwin. * lib/include/dynarray.h, lib/misc/dynarray.c, lib/misc/Makefile.am, lib/misc/shared/Makefile.am: Add Dynarray implementation. * lib/include/bsdfmt.h, lib/include/bsd_output_int.h, lib/string/bsd_output_shared.c, lib/string/bs_vsnprintf.c, lib/string/bsd_vsnwprintf.c, lib/string/str.c: Rework built-in printf implementation, esp. for Unicode fixes. * lib/include/ghIntegration.h: Shuffle types around. * lib/include/loglevel_user.h, lib/include/unity.h, lib/syncDriver/syncDriverPosix.c, lib/user/util.c, toolbox/toolbox-gtk.c: Misc fixes. * lib/include/vmBackup.h, lib/vmBackupLib/scriptOps.c, lib/vmBackupLib/stateMachine.c, lib/vmBackupLib/vmBackupInt.h: Rework scripts for freeze & thaw operations. * lib/include/vm_product.h, lib/include/vm_version.h: Add new product defs (VMRC). * lib/include/vm_tools_version.h: Add ESX 3.5U1 product. * lib/include/vixCommands.h, lib/include/vix.h: Add new VIX commands and error code. * lib/include/win32util.h: Add misc Win32 utilities. * modules/*/*/*: Reflect header file changes from elsewhere in the source code tree. 2008-02-13 Adar Dembo * Resync with internal trunk (2008.02.12). * configure.ac, lib/unityStub/*, lib/ghIntegrationStub/*, lib/Makefile.am, vmware-user/Makefile.am, vmware-user/vmware-user.c: Added lib/unityStub and lib/ghIntegrationStub. Unity and guest-host integration features for X11 guests are on the way. * configure.ac, guestd/Makefile.am, lib/fileUtf8/*, lib/vixTools/vixTools.c, vmare-user/Makefile.am: lib/file is now fully internationalized. Removed unneeded lib/fileUtf8. * foundryToolsDaemon.c: Fixed a leak of the sync driver handle. * guestd/toolsDaemon.c: Send guestd's "config directory" to the VMX for publishing. * hgfsmounter/hgfsmounter.c: Port to MacOS. * lib/dnd/*, lib/err/err.c, lib/file/*, lib/include/dnd*, lib/include/file*, lib/include/unicode*, lib/include/util.h, lib/unicode/*, lib/user/utilPosix.c: More Unicodification. * lib/file/file.c, lib/include/file.h: Added File_EnsureDirectory. * lib/foundryMsg/foundryMsg.c, lib/guestInfo/guestInfoServer.c, lib/misc/codeset.c, lib/misc/vmstdio.c, lib/SLPv2Parser/SLPv2MsgAssembler.c, lib/user/util.c: Removed some unneeded casts. * lib/foundryMsg/foundryThreads.c, lib/include/foundryThreads.h: Added FoundryThreads_Free. * lib/guestInfo/*, lib/include/guest_os.h, lib/include/guestInfo.h: Refactored GetSystemBitness. Removed osNames.h. * lib/hgfsServer/hgfsServerLinux.c: Modified MacOS alias resolution code so as not to mount volumes. Made HGFS query volume code more resilient to failures. * lib/include/backdoor_def.h: Added commands for VAssert. * lib/include/escape.h, lib/misc/escape.c: Escape_Do is no longer declared inline. * lib/include/hashTable.h, lib/misc/hashTable.c, lib/misc/Makefile.am, lib/misc/shared/Makefile.am: Renamed from hash.[ch]. * lib/include/iovector.h, lib/include/vm_basic_types.h: Added SectorType definition. * lib/include/loglevel_user.h: Added additional log levels. * lib/include/msgfmt.h: Modified for use in VMKERNEL. Added MsgFmt_GetArgswithBuf. * lib/include/msg.h: Added Msg_AppendVob for ESX. * lib/include/stats_user*: Modified some preprocessing steps. Added SETUP_WANT_GETVAL to retrieve named stat counter values. * lib/include/str.h: Modified behavior Str_* family of functions for Windows. * lib/include/strutil.h, lib/strUtil/strutil.c: Removed Split, Grep, GrepFd, and GrepFree. Added EndsWith and DecimalStrToUint. * lib/include/syncWaitQ.h, lib/sync/*: Modified SyncWaitQ_Add and SyncWaitQ_Remove to use PollDevHandle fd types instead of int fd types. * lib/include/timeutil.h, lib/misc/timeutil.c: Added TimeUtil_GetLocalWindowsTimeZoneIndex and some helper functions. * lib/include/util.h, lib/user/utilPosix.c: Added Util_BumpNoFds. * lib/include/vixCommands.h: Added commands for device hotplug and remote debugging. * lib/include/vix.h, lib/include/vixOpenSource.h: Added some new errors and properties. Added more VM manipulation functions. * lib/include/vm_atomic.h: Comment cleanup and added VMKERNEL-specific calls for fencing. * lib/include/vm_basic_asm_x86_64.h: Added inline routines to save and restore ES1. * lib/include/vm_basic_types.h: Added some types and cleaned up a bit. * lib/include/vm_legal.h: Updated COPYRIGHT_YEARS. * lib/include/vm_product.h: Added hostd service name. * lib/include/x86cpuid.h: Cleaned up the file and added some definitions for Penryn processors. * lib/misc/codeset.c: Added new UTF-16 --> UTF-8 conversion routine. * lib/misc/util_misc.c, lib/user/util.c: Moved Util_GetCurrentThreadId and friends to util_misc.c. * lib/procMgr/procMgrPosix.c: Cleaned up some code and reworked asynchronous process execution so as to properly track the grandchild's pid instead of the child's pid. * lib/string/bsd*: Reorganized BSD formatter. * lib/string/str.c: Updated unit tests. Added some Windows corner case behavior for Str_Vsnwprintf. * lib/strUtil/strutil.c: Fixed some corner cases in existing functions that call strtoul. * lib/vixTools/vixTools.c: Changed signature of VixToolsImpersonateUser. Changed error code handling in a few places. * modules/freebsd/vmhgfs/*: Refactored a lot of code so that it can be safely reused within the MacOS vmhgfs module. * modules/*/*/kernelStubs*: Removed dead System_Uptime function. * modules/linux/*/compat_wait.h: Reworked VMW_HAVE_EPOLL macro. Added waitqueue helper macros for older kernels. * modules/linux/vmhgfs/file.c, modules/linux/vmhgfs/fsutil.*, modules/linux/vmhgfs/inode.c: Added HgfsSetUidGid function and used it to preserve uid/gid after creating a directory. * modules/linux/vmhgfs/vmhgfs_version.h: Bumped driver version. * modules/linux/vmsync/compat_workqueue.h: Basic implementation of work queues and delayed work queues (using taskqueues and timers) for older kernels. * modules/linux/vmsync/sync.c: Modified internal state to use new compatible work queue implementation. * modules/linux/vmxnet/compat_ioport.h, modules/linux/vmxnet/compat_netdevice.h, modules/linux/vmxnet/compat_pci.h, modules/linux/vmxnet/compat_skbuff.h, modules/linux/vmxnet/vmxnetInt.h: Added and refactored compatibility macros for use in vmxnet3 and vmci sockets modules. * modules/linux/vmxnet/vmxnet.c: Hide some kernel functions behind compatibility macros. 2008-01-23 Adar Dembo * Resync with internal trunk (2008.01.08). * configure.ac, guestd/Makefile.am, hgfsclient/Makefile.am, lib/Makefile.am, toolbox/Makefile.am, vmware-user/Makefile.am: integrated lib/unicode for internationalizing strings. * guestd/main.c: Stopped using pgrep for finding existing instances of guestd. Removed ancient bandwidth test code. * guestd/toolsDaemon.c: Moved initial send of the guest's uptime from when guestd sends its version to when guestd registers its capabilities. * lib/file/*, lib/include/file*.h : Massive overhaul of lib/file to integrate the new unicode strings that are i18n-safe. Quite a bit of cleanup and refactoring as well. * lib/file/file.c: Addition of File_PrependToPath function. * lib/file/fileIOPosix.c: Addition of FileIO_SetExcludedFromTimeMachine and FileIO_PrivilegedPosixOpen functions. * lib/fileUTF8/fileUTF8Linux.c, lib/include/fileUTF8.h: Removal of some casts and addition of FileUTF8_GetSize function. * lib/foundryMsg/foundryMsg.c, lib/misc/vmstdio.c, lib/SLPv2Parser/SLPv2MsgAssembler.c: Addition of some casts. * lib/foundryMsg/foundryPropertyListCommon.c: Robustified some error cases. * lib/foundryMsg/vixTranslateErrOpenSource.c, lib/include/vixOpenSource.h: Added VIX_E_OUT_OF_MEMORY error code. Added Vix_TranslateCOMError function. ADded VIX_DEBUG macro. * lib/guestInfo/guestInfoServer.c, lib/include/guestInfo.h: Added some casts and refactored some functions. Also fixed a crash that hinders backwards compatibility. * lib/hgfs/cpNameUtil.c, lib/hgfs/cpNameUtilLinux.c, lib/hgfsBd/hgfsBd.c, lib/include/cpName.h, lib/include/cpNameLite.h, lib/include/escBitvector.h, lib/include/hgfsUtil.h, lib/message/messageBackdoor.c, lib/message/message.c, lib/message/messageStub.c, lib/rpcout/rpcout.c, modules/freebsd/vmhgfs/kernelStubs.h: Made safe for inclusion in MacOS kernel module code. * lib/include/backdoor.h: Refactored some type definitions. * lib/include/bsd_output_int.h, lib/include/safetime.h, lib/string/bsd_output_shared.c: Made safe for Win64 builds. * lib/include/dynbuf.h: Added DynBuf_AppendString function. * lib/include/err.h: Assorted cleanup. * lib/include/escape.h, lib/misc/escape.c: Converted Escape_Do to be inline. Some cleanup. * lib/include/guest_os.h: Assorted cleanup. * lib/include/hash.h, lib/misc/hash.c, lib/misc/Makefile.am, lib/misc/shared/Makefile.am: Added basic hash table implementation. * lib/include/hostinfo.h, lib/user/hostinfoPosix.c: Refactored and added several timekeeping functions. * lib/include/localconfig.h, lib/include/util_shared.h: Modified statements for include check. * lib/include/log.h: Changed the value of some macros when debugging. * lib/include/loglevel_defs.h: Refactoed some code, added macros for use in the VMM. * lib/include/loglevel_user.h: Added loglevels for some new components. * lib/include/msgfmt.h: Added new functions. * lib/include/msg.h: Added new Msg_LocalizeList function. * lib/include/netutil.h: Modified prototypes for two Windows-only functions. * lib/include/preference.h: Added new Preference_GetInt64 and Preference_SetFromString functions. * lib/include/strutil.h, lib/strUtil/strutil.c: Cleaned up and added some new functions. * lib/include/su.h: Cleanup. * lib/include/syncMutex.h, lib/sync/syncMutex.c: Added NetWare implementation of some synchronization primitives. * lib/include/unicode*, lib/unicode/*: New library for handling Unicode-aware strings. * lib/include/util.h, lib/user/util.c: Assorted refactoring and addition of some new functions, one related to backtracing. * lib/include/vixCommands.h: New commands for vprobes, replay, message dialogs, and others, plus cleanup of some existing commands. * lib/include/vm_assert.h: Added IMPLIES macro. * lib/include/vm_atomic.h, lib/include/vm_basic_asm.h: Refactored for safe Win64 builds. * lib/include/vm_basic_defs.h: Added compatibility code for __va_copy. * lib/include/vm_basic_types.h: Added FMTH for printing the value of handles. Set a new #pragma to ignore size_t truncation warnings on Windows. Added several other macros, as well as a ssize_t definition for some versions of BSD. * lib/include/vm_legal.h: Added more patents to the patent string. * lib/include/vm_product.h: Added new macros for some products. * lib/include/vm_tools_version.h: Added macros for certain older Tools versions and for PRODUCT_BUILD_NUMBER refactoring. * lib/include/vm_version.h: Tweaked some product expiration dates and versions. Refactored many uses of BUILD_NUMBER to PRODUCT_BUILD_NUMBER. * lib/include/x86cpuid.h: Tweaked definition of RDTSCP flag. Refactored BIT_MASK macro to VMW_BIT_MASK. * lib/misc/base64.c: Modified calling contract for Base64_EasyEncode. * lib/misc/codeset.c: Tweaked casts and preprocessor conditioning. * lib/misc/idLinux.c: Added IdAuthCreateWithFork and reworked several other functions to work around a bug in Apple's detection of GUI processes. * lib/misc/util_misc.c: Moved W32Util_GetLongPathName and W32UTil_LookupSidForAccount elsewhere. * lib/rpcin/rpcin.c: Addition of a ping GuestRPC callback. * lib/string/str.c: Removed a comment. * lib/sync/syncWaitQPosix.c: Added code to disable a workaround for a MacOS bug when appropriate (it was fixed in Leopard). * lib/vixTools/vixTools.c: Refactored some code, added code to modify the guest's networking configuration, added some casts, and added code to prevent renaming a file to itself. * modules/freebsd/*/Makefile, modules/linux/*/Makefile.normal: Set a make variable so the module file will be build in the parent directory. Removed some unused rules. * modules/freebsd/vmhgfs/kernelStubsBSD.c, modules/linux/vmhgfs/kernelStubsLinux.c: Removed unused function. * modules/linux/*/include/driver-config.h: Added check to prevent uintptr_t from being declared twice. * modules/linux/vmblock/linux/filesystem.c, modules/linux/vmblock/Makefile.kernel: Added check for newer kernels where the slab allocator's constructor function expects three arguments. Makes it work with 2.6.25-rc1 (but not rc2, yet). * modules/linux/vmblock/linux/vmblock_version.h: Bumped module version. * modules/linux/vmhgfs/filesystem.c, modules/linux/vmhgfs/inode.c, modules/linux/vmhgfs/module.h, modules/linux/vmhgfs/page.c: Added support for writeback caching in conformant kernels. * modules/linux/vmhgfs/vmhgfs_version.h: Bumped module version. * modules/linux/vmxnet/vmxnetInt.h: Renamed a type and removed the inclusion of unnecessary headers. Pruned said headers from codebase. 2007-11-15 Elliot Lee * Bandsaw release (2007.11.15). * configure.ac: Handle building modules for multiple OS's. Improve X detection to allow building --without-x. Improve Gtk+ detection. Detect libdnet on Solaris. Detect which -Wwarning flags the compiler can handle. * vmware-user/foreignVMToolsNetworking.c, lib/vixTools/vixTools.c, guestd/foreignVMToolsNetworking.c, lib/include/netutil.h, lib/include/guestInfo.h, lib/netUtil/netUtilLinux.c, lib/include/guestInfoInt.h, lib/guestInfo/guestInfoPosix.c, lib/guestInfo/guestInfoServer.c: Move to new NicInfo structures. * vmware-user/foundryToolsDaemon.c, guestd/foundryToolsDaemon.c: Make sure requestMsg is not NULL before looking inside it. * guestd/main.c: Cleanup of HGFS pserver and mounting code. Check for some type of signal when sending an RPC. * guestd/toolsDaemon.c, vmware-user/resolution.c: Have the guest tell the host whether screen resolution changes should be sent, instead of having the host guess it based on the OS type set in the .vmx file. Better timeout checking to avoid problems when host & guest time diverge. * hgfsmounter/hgfsmounter.c: FreeBSD support. Fixes to compile on old systems. * lib/backdoor/backdoor.c: Tweak for FreeBSD kernel modules. * lib/include/mntinfo.h, lib/dnd/dndLinux.c, lib/wiper/wiperPosix.c, lib/syncDriver/syncDriverPosix.c: Fixes to compile on new systems w/gcc 4.2. * lib/err/err.c, lib/err/errPosix.c, lib/err/Makefile.am: Move Err_Errno2String function into POSIX-specific source file. * lib/file/fileIOPosix.c: Handle EDQUOT if applicable. Fixes to compile on new systems where SYS__llseek may not be available. Better reporting of errors, by translating errno into FILEIO_* error codes. * lib/file/fileLockPosix.c: Fixes to compile on old systems. Add a bunch of functions to the FileLock* API. * lib/file/fileLockPrimitive.c, lib/include/fileInt.h: Bunch of file locking cleanups and bug fixes. * lib/file/filePosix.c: Bunch of MacOS-related fixes. Add File_GetTimes(), FilePosixGetParent(), FilePosixGetBlockDevice(), etc. * lib/fileUtf8/fileUTF8Linux.c: Add FileUTF8_GetTimes() function. * lib/foundry/foundryMsg.c, lib/include/vixCommands.h: Add VIX_USER_CREDENTIAL_HOST_CONFIG_HASHED_SECRET credential type, and a bunch of VIX commands relating to record-replay. * lib/foundryMsg/vixTranslateErrOpenSource.c: Translate a couple more error codes. * lib/guestInfo/guestInfoPosix.c, lib/guestInfo/Makefile.am: Use libdnet on Solaris to retrieve networking info. * lib/hgfs/cpNameUtil.c, lib/hgfs/cpNameUtilInt.h, lib/hgfs/cpNameUtilLinux.c: Couple more CPName <-> UTF8 conversion routines. Some MacOS changes as well. * lib/hgfs/hgfsUtil.c, lib/include/hgfs.h, modules/linux/vmhgfs/fsutil.c: Handle ENAMETOOLONG. * lib/hgfs/staticEscape.c, lib/hgfs/hgfsBd.c: Handle FreeBSD as well. * lib/hgfsServer/hgfsServer.c: Tie in the cpNameUtil UTF8 changes on MacOS. * lib/hgfsServer/hgfsServerLinux.c: Make the getdents() wrapper work on a wider range of Linux systems. Add "alias" resolution on MacOS, and tie in the cpNameUtil UTF8 changes on MacOS. * lib/hgfsServer/hgfsServerPolicyGuest.c: Handle FreeBSD. * lib/include/backdoor_def.h: Add BDOOR_CMD_LAZYTIMEREMULATION and BDOOR_CMD_BIOSBBS. * lib/include/str.h, lib/include/bsd_output.h, lib/include/bsd_output_int.h: include compat_stdarg.h, change vsnwprintf prototype, add HAVE_BSD_WPRINTF define, other compat fixups. * lib/include/cpNameUtil.h, lib/include/codeset.h, lib/misc/codeset.c: Changes to correspond to cpNameUtil UTF8 changes. * lib/include/compat/compat_stdarg.h: New header for doing stdarg easily across platforms. * lib/include/cpName.h: FreeBSD fixes. * lib/include/dnd.h: Add Dnd_SetClipboard and Dnd_GetFileList(). * lib/include/escBitvector.h: FreeBSD fixes. * lib/include/file.h, lib/include/fileUTF8.h: Add new MacOS routines and File_GetTimes/FileUTF8_GetTimes. * lib/include/hgfsProto.h: Explanation of the whole cpNameUtil and codeset UTF8 changes and how they tie in with HGFS. * lib/include/hgfsUtil.h: Random compatibility changes. * lib/include/loglevel_user.h: Add a few LOGLEVEL_VAR definitions. * lib/include/msg.h: s/USE_MSGFMT/NO_MSGFMT/ * lib/include/osNames.h: Add Windows 2003 Datacenter Edition, and user-visible 64bit suffix macro. * lib/misc/random.c, lib/include/random.h: Add Random_Quick() and Random_QuickSeed() routines. * lib/misc/idLinux.c, lib/include/su.h: Add Id_AuthGetLocal() and Id_GetAuthExternal() routines, and compat fixes. * lib/misc/timeutil.c, lib/include/timeutil.h: Add TimeUtil_UnixTimeToNtTime() routine. * lib/include/util.h: Add a couple of MacOS routines. * lib/include/vmBackup.h, lib/vmBackupLib/stateMachine.c: add a couple of structure elements for Windows backup fixes. * lib/include/vm_basic_asm.h: fixes for reading TSC on 64-bit platforms. * lib/include/vm_basic_defs.h: Add other va_copy macros. * lib/include/vm_basic_types.h: Fixes for compiling on a wide range of systems. * lib/include/vm_legal.h: Change the PATENTS_STRING * lib/include/vm_product.h: Add "License Infrastructure" product. * lib/include/vm_tools_version.h: Change tools versions listed for various upcoming product releases. * lib/include/vm_version.h: Update the versions. * lib/include/x86cpuid.h: Define more CPU flags & fields, add new CPU models. Fixes for fully writable TSC detection. * lib/message/message.c, lib/message/messageBackdoor.c: Fixes for FreeBSD. * lib/misc/util_misc.c: Handle MacOS. * lib/rpcIn/rpcin.c: Fail a badly-formed RPC instead of ASSERT()'ing into oblivion. * lib/string/bsd_vsnprintf.c: Various fixes to synchronize with bsd_vsnwprintf.c. * lib/string/Makefile.am, lib/string/shared/Makefile.am, lib/string/str.c lib/string/bsd_vsnwprintf.c: New file to implement vsnwprintf() for compat purposes. * lib/vixTools/vixTools.c: New FileUTF8 routines. * Makefile.am, modules/Makefile.am: --without-x fixes, add xferlogs, move kernel module building into separate Makefile.am * modules/freebsd/*: Add FreeBSD kernel modules (vmblock, vmhgfs, vmmemctl, vmxnet). * modules/linux/*/include/compat_*.h, modules/linux/*/autoconf/cachector.c, modules/linux/*/autoconf/cachecreate.c, modules/linux/*/backdoor.c, modules/linux/vmhgfs/filesystem.c, modules/linux/vmhgfs/hgfsBd.c, lib/procMgr/procMgrPosix.c, lib/rpcOut/rpcout.c, lib/user/util.c, lib/vmCheck/vmcheck.c, libguestlib/Makefile.am, lib/deployPkg/runDeployPkgPosix.c, lib/include/vm_atomic.h: Compat fixes. * modules/linux/*/kernelStubs.h: Update for FreeBSD. * modules/linux/*/include/*.h, modules/linux/*/backdoor_def.h, modules/linux/*/cpName.h, modules/linux/*/hgfs.h, modules/linux/*/hgfsProto.h, modules/linux/*/hgfsUtil.[ch], modules/linux/*/kernelStubsLinux.c, modules/linux/*/messageBackdoor.c, modules/linux/*/message.c, modules/linux/*/rpcout.c, modules/linux/*/rpcin.c, modules/linux/*/staticEscape.c, modules/linux/*/vm_basic_asm.h, modules/linux/*/vm_basic_defs.h, modules/linux/*/vm_basic_types.h, modules/linux/*/x86cpuid.h, modules/linux/*/compat_*.h: Pull in updated files from main source tree. * modules/linux/*/Makefile.kernel: Remove CC_WARNINGS/CC_OPTS gunk. * modules/linux/*/README, modules/linux/*/Makefile.normal: Build foo.o driver by default on systems with VM_KBUILD=no. * modules/linux/vmhgfs/vmhgfs_version.h: Updated VMHGFS driver version. * modules/linux/vmmemctl/os.[ch], modules/linux/vmmemctl/vmballoon.c: Implement and use os_yield() to deprioritize the Balloon_Deallocate operation. * modules/linux/vmsync/*: New sync driver to make VM snapshots consistent. * modules/linux/vmxnet/bpf_meta.h: New file. * modules/linux/vmxnet/net_dist.h: Update NET_MAX_IMPL_PKT_OVHD value. * modules/linux/vmxnet/vm_device_version.h: Mention VMXNET3 * modules/linux/vmxnet/vmkapi_status.h: Updated VMK_ERR codes. * modules/linux/vmxnet/vmkapi_types.h: Add VMK_CONST64(U) macros. * modules/linux/vmxnet/vmxnet2_def.h, modules/linux/vmxnet/vmnet_def.h, modules/linux/vmxnet/vmxnet_def.h, modules/linux/vmxnet/vmxnetInt.h, modules/linux/vmxnet/vmxnet.c: Add (optional) BPF support. * modules/linux/vmxnet/vmxnetInt.h, modules/linux/vmxnet/vmxnet.c: Add vmxnet_link_check to propagate device link status to netdev. * common/vm-support: New script to gather support info from a VM. * scripts/*/*-default: New poweron/poweroff/suspend/resume scripts for a VM. Add support for dropping user-provided scripts into a subdirectory. * toolbox/toolboxAbout.c: Eliminate warnings about unused variables. * toolbox/toolboxShrink.c: Update wording of message. * toolbox/copyPaste.c: Try cutting & pasting UTF8 text if we can. * xferlogs/*: New log transfer utility. 2007-10-26 Elliot Lee * Initial import of 2007.09.04-56574 code ("Axe" release). * Import 2007.10.08 snapshot, which includes patches to fix the --without-x flag, and compilation with gcc 4.2. open-vm-tools-stable-12.5.0/open-vm-tools/LICENSE000066400000000000000000001263121470176644300213330ustar00rootroot00000000000000LICENSE Open-vm-tools v10.3.0 The Linux kernel modules are released under the GPL v2, a majority of the user level components are released under the LGPL v2.1, and the SVGA and mouse drivers are released under the X11 license. Copyright 2007-2018 VMware, Inc. All rights reserved. ========================================================================= GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ========= GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ========= X11 License Copyright (c) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======== Open-vm-tools v10.3.0 includes a number of subcomponents with separate copyright notices and license terms. Your use of the source code for these subcomponents is subject to the terms and conditions of the following licenses. SECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES >>> freebsd-base64-4.8 >>> unicode-5.0 =================================================== --------------- SECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES ---------- BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES are applicable to the following component(s). >>> freebsd-base64-4.8 base64.c -- routines to encode/decode base64 data $OpenLDAP: pkg/ldap/libraries/liblutil/base64.c,v 1.15 2006/01/03 22:12:11 kurt Exp $ / This work is part of OpenLDAP Software . Copyright 1998-2006 The OpenLDAP Foundation. Portions Copyright 1998-2003 Kurt D. Zeilenga. Portions Copyright 1995 IBM Corporation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted only as authorized by the OpenLDAP Public License. A copy of this license is available in the file LICENSE in the top-level directory of the distribution or, alternatively, at . The OpenLDAP Public License Version 2.8, 17 August 2003 Redistribution and use of this software and associated documentation ("Software"), with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source form must retain copyright statements and notices, 2. Redistributions in binary form must reproduce applicable copyright statements and notices, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution, and 3. Redistributions must contain a verbatim copy of this document. The OpenLDAP Foundation may revise this license from time to time. Each revision is distinguished by a version number. You may use this Software under terms of this license revision or under the terms of any subsequent revision of the license. THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The names of the authors and copyright holders must not be used in advertising or otherwise to promote the sale, use or other dealing in this Software without specific, written prior permission. Title to copyright in this Software shall at all times remain with copyright holders. OpenLDAP is a registered trademark of the OpenLDAP Foundation. Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, California, USA. All Rights Reserved. Permission to copy and distribute verbatim copies of this document is granted. ADDITIONAL LICENSE INFORMATION: Portions Copyright (c) 1996, 1998 by Internet Software Consortium. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. This work is based upon Base64 routines (developed by IBM) found Berkeley Internet Name Daemon (BIND) as distributed by ISC. They were adapted for inclusion in OpenLDAP Software by Kurt D. Zeilenga. >>> unicode-5.0 Copyright (c) 2008 VMware, Inc. All rights reserved. Copyright (c) 1991-2007 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that (a) the above copyright notice(s) and this permission notice appear with all copies of the Data Files or Software, (b) both the above copyright notice(s) and this permission notice appear in associated documentation, and (c) there is clear notice in each modified Data File or in the Software as well as in the documentation associated with the Data File(s) or Software that the data or software has been modified. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. [OPENVMTOOLS1030GANV061518] open-vm-tools-stable-12.5.0/open-vm-tools/Makefile.am000066400000000000000000000042311470176644300223550ustar00rootroot00000000000000################################################################################ ### Copyright (c) 2007-2024 Broadcom. All Rights Reserved. ### Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc. ### and/or its subsidiaries. ### ### Top-level Makefile for building the VMware OSS Tools. ### ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ # These flags get passed to aclocal when autoreconf calls it, and tell aclocal # that all of our macros are in the 'm4' subdirectory. ACLOCAL_AMFLAGS = -I m4 SUBDIRS = SUBDIRS += lib if LINUX SUBDIRS += libguestStoreClient endif SUBDIRS += libvmtools SUBDIRS += libhgfs SUBDIRS += hgfsclient if ENABLE_VGAUTH SUBDIRS += vgauth SUBDIRS += vgauthImport endif SUBDIRS += checkvm SUBDIRS += libguestlib if ENABLE_DEPLOYPKG SUBDIRS += libDeployPkg endif SUBDIRS += rpctool SUBDIRS += namespacetool SUBDIRS += scripts SUBDIRS += services SUBDIRS += toolbox if HAVE_X11 SUBDIRS += vmware-user-suid-wrapper endif if HAVE_FUSE SUBDIRS += vmblock-fuse SUBDIRS += vmhgfs-fuse endif if !LINUX SUBDIRS += vmblockmounter endif SUBDIRS += xferlogs if ENABLE_TESTS SUBDIRS += tests endif if WITH_KERNEL_MODULES SUBDIRS += modules endif SUBDIRS += docs if ENABLE_LIBAPPMONITOR SUBDIRS += libappmonitor endif if HAVE_UDEV SUBDIRS += udev SUBDIRS += vmwgfxctrl endif install-data-local: $(INSTALL) -d $(DESTDIR)/etc/vmware-tools/ $(INSTALL) -m 644 $(srcdir)/tools.conf $(DESTDIR)/etc/vmware-tools/tools.conf.example open-vm-tools-stable-12.5.0/open-vm-tools/NEWS000066400000000000000000000546361470176644300210360ustar00rootroot00000000000000open-vm-tools 2013.04.16 changes: * VMCI/VMSOCK Linux kernel modules are disabled for kernels 3.9 and above. * HGFS compilation fixes, performance and other improvements. * Disable glib deprecation warnigns on newer Linux distributions. * Configure script will automatically detect procps-ng. * Other fixes and cleanups. open-vm-tools 2012.12.26 changes: * vmsync is not longer being compiled on newer (3.0+) Linux kernels since they support FIFREEZE/FITHAW ioctls. * vmblock is not longer being compiled on newer (3.0+) Linux kernels, such systems should use vmblock-fuse. * The draft SOCK_SEQPACKET code is removed from VSOCK driver. * Fixes for the vmballoon driver. * Other fixes and cleanups. open-vm-tools 2012.10.14 changes: * Changes and cleanups to VMCI driver * Changes to HGFS to allow compiling on newer kernels * Fix MTU handling in vmxnet3 for Solaris driver. * Updates to the vmballon driver to handle new protocol. * Fix for FreeBSD version of vmblock driver to stop kernel panics on unload on FreeBSD 9.0 * Fix to guestinfo plugin causing vmtoolsd to crash when guest had too many NICs. * Other fixes and cleanups. open-vm-tools 2012.05.21 changes: * Updates for newer Linux kernel releases (3.4). * Fix for vmxnet driver and IPV6 * VMCI updates and fixes. * Other fixes and cleanups. open-vm-tools 2012.03.13 changes: * Updates for newer Linux kernel releases (3.3). * Updates for Solaris 11. * Updates for FreeBSD 9.0. * Translation updates. * Other fixes and cleanups. open-vm-tools 2011.12.20 changes: * Updates for new Linux kernel releases, including some fixes for Fedora's re-versioned 3.x kernels. * VMCI sockets has some changes for a new socket type, targeted at replacing the "backdoor" communication used by the tools services. * HGFS has better session support. * Miscelaneous bug fixes and small enhancements in other parts of the code. open-vm-tools 2011.11.20 changes: * Updates for new Linux kernel releases. * Better Unity and DnD compatibility with newer Linux distros. * Other minor fixes and cleanups. open-vm-tools 2011.10.26 changes: * Mostly cleanups and bug fixes. * Code can now compile with uClibc, with some caveats. open-vm-tools 2011.09.23 changes: * open-vm-tools now can use the built in Linux freeze / thaw support for block devices, making the vmsync driver unnecessary in kernels supporting that feature. * The VMCI driver has been simplified, removing VM-to-VM communication support (which is being removed from VMware products). * The Unity team decided to remove the Unity plugin from open-vm-tools, given its partial brokenness due to reliance on internally-modified version of GNOME libraries, among other reasons. * Other bug fixes and code cleanup. open-vm-tools 2011.08.21 changes: * Enabled several VIX APIs on FreeBSD. * Minor bug fixes and code cleanup. open-vm-tools 2011.07.19 changes: * Fix an issue in the HGFS driver that could lead to a kernel panic. * Update some code to support new compiler and kernel versions. * Minor bug fixes and code cleanup. open-vm-tools 2011.06.27 changes: * A few enhancements to Unity: XFCE support, better interaction with "the other" (Ubuntu's) Unity and compositing window managers, better X error handling, and a few bug fixes. * A few bug fixes in HGFS, and minor bug fixes in other components. * Otherwise, mostly code cleanup. open-vm-tools 2011.05.27 changes: * Mostly cleanups and a few bug fixes. open-vm-tools 2011.04.25 changes: * Mostly cleanups and small bug fixes in this release. * Logging is enabled by default in vmtoolsd, writing to syslog. The default log level is not chatty, so few messages should make it to syslog during normal operation. * The GUI version of the toolbox was removed. open-vm-tools 2011.03.28 changes: * HGFS mounter and vmusr's suid wrapper were changed to avoid issues with symlink attacks. A new mount utility for vmblock on Solaris and FreeBSD was added. * The VMCI driver was thoroughly reworked so that it can serve as both the host and guest VMCI driver. This is mostly targeted at supporting nested VMs. * vmusr got better integration with X's session manager, including proper cleanup during session teardown. * Unity has been enhanced to better handle some desktop environments. * Many small bug fixes in other areas, including updates for newer Linux kernels. open-vm-tools 2011.02.23 changes: * Some copy & paste issues with KDE were fixed. * Mostly cleanups and bug fixes, with a few build enhancements. open-vm-tools 2011.01.24 changes: * Mostly cleanups and bug fixes. * Install code fixed to handle translation catalogs correctly. open-vm-tools 2010.12.19 changes: * New version of DnD code lands in open-vm-tools. The host part of the new DnD protocol is not available yet in VMware products, though. * vmtoolsd gets some new functionality to support new features being developed internally. * vmxnet driver for FreeBSD fixed to allow changing the MAC address. * lots of bug fixes and other cleanups in various areas. open-vm-tools 2010.11.17 changes: * Mostly cleanups and bug fixes. * vmxnet3 on Solaris now supports jumbo frames. open-vm-tools 2010.10.18 changes: * The unity plugin has received some refactoring work, and the menu gathering code has been enhanced to be more DE-agnostic and support the new app icon code. It now needs glib 2.24 to compile. * Several bug fixes and enhancements to the VIX plugin. * Bug fixes to the guest info plugin so that it better supports VMs with several network interfaces. * Other minor enhancements and bug fixes in several areas, including vsock, vmmemctl and copy & paste. open-vm-tools 2010.09.19 changes: * Mostly cleanups and minor bug fixes. * VIX plugin has been updated with lots of new commands being added to the next VIX API release. open-vm-tools 2010.08.24 changes: * HGFS and VMCI kernel module bug fixes, and updates to compile in newer Linux kernels. * HGFS server interface refactoring was finished, now supports the transport abstraction available for the kernel interface. * VIX operations are now properly implemented on Solaris, plus new operations added to support features under development. * Other minor cleanups and bug fixes. open-vm-tools 2010.07.25 changes: * Features previously provided by vmware-user are now provided as vmtoolsd plugins. vmware-user has been removed and code that interacted with it changed to start the correct vmtoolsd instance. * Lots of cleanup: removed old compatibility headers not needed anymore, removed dead code, consolidated logging code. * Time synchronization now works more like NTP. * New code for features not yet exposed by VMware host software is being added. open-vm-tools 2010.06.16 changes: * VMCI moves towards unifying the guest and host driver APIs, and gets support for MSI/MSI-X. * More work on new VMCI-backed HGFS protocol. * vmmemctl: Linux driver removed (it's now upstream), plus cleanup and simplification of the FreeBSD and Solaris drivers. * some Linux kernel compatibility fixes. * Cleanup of old kernel support code. * Some cleanup of old VIX features. * toolbox-cmd was updated to use newer APIs, and got some i18n enhancements. * some bug fixes and enhancements to the logging code. * update detection and use of some needed libraries. * More progress in making libraries thread-safe. open-vm-tools 2010.04.25 changes: * VMCI and HGFS get some initial work for new features. * vmbackup support has been extended to more systems, allowing its use even if the system lacks a proper "sync" implementation. * A few bug fixes in different areas: Unity/X11, vmware-user startup on upstart-based systems, and other minor fixes / thread safety fixes. * The pvscsi driver was removed from the open-vm-tools distribution (it is upstream as of Linux 2.6.33). * The vmmemctl driver will be upstream as of Linux 2.6.34, at which point it will be removed from open-vm-tools. open-vm-tools 2010.03.20 changes: * New i18n support for Tools; it is based on VMware's internal tools (instead of gettext). * Logging infrastructure has been enhanced and now supports rotation (without the need for logrotate) and syslog. * Bug fixes in several areas (DnD, backup support, thread safety). * Updates in Linux kernel modules for compatibility with newer kernels. * New functionality in the Unity support code. open-vm-tools 2010.02.23 changes: * Mostly bug fixes, cleanups and code refactoring. open-vm-tools 2010.01.19 changes: * Linux modules have been updated to compile on newer kernels. * Solaris modules now should compile on OpenSolaris (tested on 2009.06). * Other than those, mostly bug fixes and minor refactoring. open-vm-tools 2009.12.16 changes: * Some improvements to vmtoolsd, base libraries and and the plugin interface. * Some library refactoring: use new lock library, changes to support compilation of some code on ARM. * some fixes in configure.ac to try to correctly support newer distros. * vsock/vmci improvements. * bug fixes in the vmxnet / vmxnet3 drivers, and FreeBSD's vmblock driver. * vmxnet3 for Linux is now upstream (as of Linux 2.6.32), and will be removed from later releases of open-vm-tools. * pvscsi will be available upstream starting with Linux 2.6.33 and at that time will be removed from open-vm-tools. open-vm-tools 2009.11.16 changes: * Lots of refactoring and cleanup in the code, mainly targeting the definition of a set of public APIs. * vmblock-fuse can now replace the vmblock kernel module for DnD operations. * Fix some memory leaks in the guestInfo module. Users of the 2009.10.15 release are recommended to upgrade, or at least crossport cid 6a8d4279. open-vm-tools 2009.10.15 changes: * The HGFS module got some performance enhancements. * Minor enhancements to vmtoolsd and the logging system. * Fix for a few issues reported on the sourceforge bug tracker. * Lots of code refactoring, and a few bug fixes. open-vm-tools 2009.09.18 changes: * Mostly bug fixes and minor enhancements. * The pvscsi code was re-factored in preparation for upstreaming. The driver has been sent to the LKML for inclusion in the main Linux tree, and might be removed from open-vm-tools once it's accepted. open-vm-tools 2009.08.24 changes: * Remove support for Linux kernels < 2.6.9. * The vsock now implements a new notification protocol that has better performance than the previous. * New infrastructure for sending more network config-related information about the virtual machine to the host. * Other bug fixes and minor improvements to the code. open-vm-tools 2009.07.22 changes: * Better support for dkms by means of a script to help create a dkms tree. * "make install" now also installs header files for public libraries, plus a few fixes to incorrect install behavior. * Lots of improvements to the new DnD code. * This will be the last release with support for Linux kernels < 2.6.9. open-vm-tools 2009.06.18 changes: * Mostly a bug fix release. * vmhgfs now is able to use vsock as a transport (although backend support for HGFS over vsock is not yet released in VMware products). open-vm-tools 2009.05.22 changes: * Mostly a cleanup and bug fix release. * Fix a build issue where a symlink attack could cause the open-vm-tools build to overwrite data (by placing a symlink in /tmp). * Second (and last?) batch of changes to clean up duplicate files in the source tree, including Solaris and FreeBSD kernel modules and other module-specific shared files. * Plugins now are properly built using plugins_LTLIBRARIES so that "-rpath" doesn't need to be used (this would cause an RPATH entry to be added to the final binary, which some tools didn't like). Thanks to Dominique Leuenberger for the suggestion. * open-vm-tools now properly detects PAM and enables PAM support in the code. open-vm-tools 2009.04.23 changes: * Implemented copy & paste support for RTF data and file contents. * guestd has been removed from open-vm-tools; vmtoolsd is now the only option for the main tools service. * Added vmblock and vmmemctl modules for Solaris (under the CDDL). * vmware-user can now work with both vmblock-fuse and vmblock. * Linux HGFS now has a stream-based (TCP, vsock) transport, still under development. * First batch of changes to cleanup duplicated files in the source tree. Most duplicated files in the Linux kernel modules have been cleaned up. open-vm-tools 2009.03.18 changes: * Mostly a bug fix release. * Solaris vmxnet3 driver was added; open-vm-tools now should also compile on OpenSolaris (tested on 08.11), as long as the --without-gtkmm option is used. * The new DnD V3 protocol is now available in open-vm-tools. * Added "rpctool", a simple, stand-alone tool to send RPC commands to the host software. * vmtoolsd is now preferred in lieu of vmware-guestd; vmware-guestd will most probably be completely removed in the next release. open-vm-tools 2009.02.18 changes: * open-vm-tools now depend on glib 2.6.0 as a minimum requirement. * Added vmxnet module for Solaris, and reworked the HGFS module so it works without help from vmware-guestd. * Added implementation of new DnD protocol, which adds a dependency on a C++ compiler and the gtkmm library to vmware-user. * The code from the "core services" has been added to open-vm-tools, including a few tests. vmtoolsd + plugins are now capable of replacing vmware-guestd (vmware-user still needs to have some features ported over), but this code is still not to be considered as stable as the legacy services, so vmware-guestd is still included. * A few fixes for compatibility with non-GNU toolchains, newer Linux kernels and old gcc compilers. open-vm-tools 2009.01.21 changes: * First open source release of the HGFS module for Solaris, under the CDDL. Other modules are expected to be added in the upcoming releases. * Added an implementation of vmblock on top of FUSE; vmware-user still doesn't use this module even if it is available, though. * Linux modules now add the "supported" tag used by Novell in their SLES 10 SP2 release when loading modules. * Fix compilation of modules in newer Linux kernels which don't include $(LINUXINCLUDE) in the compiler flags anymore. open-vm-tools 2008.12.23 changes: * Lots of makefile cleanup with the switch to using libtool archives. * Automatically disable Unity if multimon support is disabled. * Actually build the pvscsi modules. * First bits of the "Core Service" project are starting to show up; the base "vmtools" library was added to the package. It currently is mostly a collection of the existing libraries already shipped with open-vm-tools, plus some extra functionality build on top of glib. Currently no other code in open-vm-tools uses it, so it's optional. * The HGFS driver was fixed for the Linux 2.6.28 kernel. open-vm-tools 2009.11.18 changes: * The pvscsi Linux kernel module has been added (for kernels >= 2.6.8). It provides access to VMware's new paravirtualized SCSI device. * The HGFS driver and user-level code has seen a lot of refactoring to enable more consistent name escaping. The FreeBSD driver now supports symlinks. * The Linux module makefiles now support exporting symbol version files, allowing modules with dependencies (such as vsock, which depends on vmci) to correctly build and load on Linux >= 2.6.26 with CONFIG_MODVERSIONS. * Rudimentary support for dkms. * Assortment of bug fixes. open-vm-tools 2009.10.13 changes: * The vmxnet3 Linux kernel module has been added. This module provides better network performance for the guest. The corresponding virtual hardware is available beginning with Workstation 6.5, though performance benefits are unlikely to be realized until a later VMware product release. The module should work for all kernels beginning with 2.6. * The open-vm-tools no longer depend on libproc-dev. Several people reported this issue (Sourceforge bug 1960947). * Added a command line argument to skip privileged operations during make install (--without-root-privileges). * Guestd now supports backwards time synchronization, though the corresponding hypervisor-side changes are not yet part of any shipping VMware products. * Assortment of bug fixes. open-vm-tools 2009.09.03 changes: * Fixed an issue where open-vm-tools fails to configure when using --without-icu. Thanks to Timo Gurr for reporting the issue (Sourceforge bug 2046262). * Fixed failed build on Ubuntu Intrepid and Fedora 9. Thanks to Nathan Charles for reporting the issue (Sourceforge bug 2048423). * Fixed kernel module build issues on 2.6.27 pre-release kernels. Thanks to Dominique Leuenberger for reporting the issue (Sourceforge bug 2071170). * ...and other bug fixes. open-vm-tools 2008.08.08 changes: * Unity for X11 guests has been added. Unity is implemented within vmware-user and requires no additional setup beyond setting up the vmware-user application itself. Unity should work with Fusion 1.x releases as well as with the upcoming Workstation 6.5 release. Our in-house testing was with Linux guests, and they should mostly work. There is very little standing in the way of FreeBSD/Solaris support, though we've never built or tested Unity for those platforms. * The VMCI Linux kernel module has been added. This module provides high-speed datagram and socket interfaces for guest<->guest and host<->guest communication. It should work for all kernels beginning with 2.4, and for VMware products beginning with Workstation 6.5. * The VMCI sockets Linux kernel module has been added. It provides both datagram and stream socket interfaces to userlevel for use with VMCI. As with VMCI, it should work for kernels 2.4 or later, and for VMware products beginning with Workstation 6.5. * The command-line Toolbox has been added. This application provides the same functionality as the GTK Toolbox, but with a scriptable command-line interface. It also has some statistic retrieval commands that aren't found in the GTK Toolbox. * Fixed compilation of vmsync and vmmemctl Linux kernel modules on 2.6.26. Thanks to Pavol Rusnak for the report (Sourceforge bug 2032683). * Fixed an issue with guestd's nicInfo updating mechanism. Thanks to Jason Lunz for the patch (not tracked on Sourceforge). * Fixed handling of $(DESTDIR) in automake. Thanks to Mike Auty for the patch (Sourceforge bug 2018802). * Fixed build of vmware-user using gtk 1.2. Thanks to Stephen Duncan for the report (Sourceforge bug 2014338). * Fixed compilation of lib/guestApp when using --without-x. Thanks to Martin Preishuber for the report (Sourceforge bug 2013568). * As usual, other bug fixes. open-vm-tools 2008.07.01 changes: * Fixed a backwards time synchronization issue (not tracked on Sourceforge). Thanks to Eric Castan for reporting it. * Fixed an issue where open-vm-tools configured via --without-x didn't compile (not tracked on Sourceforge). Thanks to Mark Foster for reporting the bug. * Other bug fixes. open-vm-tools 2008.06.20 changes: * Fixed Sourceforge bug 1847750 (FreeBSD 7 & 8 builds) and Sourceforge bug 1981632 (build failure on Solaris). This should get open-vm-tools building and running on FreeBSD 7 & 8 and Solaris. Thanks to Martin Blapp for all the FreeBSD patches, and Jonathan Keatley for reporting the Solaris bug. * Fixed Sourceforge bug 1968416 (packet counting in FreeBSD vmxnet). Thanks to Shunsuke SHINOMIYA for reporting this bug. * Fixed Sourceforge bug 1983375 (Cannot specify kernel constraints). You can now pass --without-kernel-modules, --with-kernel-release, and --with-linuxdir to the ./configure script. Thanks to Craig Phillips for reporting this bug. * Other bug fixes. open-vm-tools 2008.06.03 changes: * Added the vmware-user-suid-wrapper application, with implementations for Linux, FreeBSD, and Solaris. This app is needed to make correct use of vmware-user with the vmblock kernel module. It should have been in the previous code refresh, but we accidentally overlooked it. * Fixed Sourceforge bug 1924246: vmhgfs on Linux properly reports the available space on the host. Thanks to Mikhail Krivtsov for reporting the bug. * Fixed Sourceforge bug 1839981: we now have rudimentary `make install` support. On any platform, it should copy files and kernel modules to the location specified at build-time, and on Linux, it will additionally run `depmod -a` to make the kernel modules accessible to modprobe. This change also adds a "--with-pam-prefix" argument to the configure script, which controls the location of guestd's pam files. * Other bug fixes. open-vm-tools 2008.05.15 changes: * guestd no longer starts vmware-user. Packagers will need to use the XDG autostart spec, Xsession drop-in scripts, or other appropriate mechanisms to make sure that vmware-user is started as part of X session initialization. Please see http://open-vm-tools.wiki.sourceforge.net/Packaging for more details. * Bug fixes as usual. open-vm-tools 2008.05.02 changes: * Continued Unicode support. * open-vm-tools now depends on libicu for codeset conversions. If you wish to build open-vm-tools without libicu, pass "--without--icu" when configuring the package. Without libicu, codeset conversions will be done as before, via calls to iconv. * A few more bug fixes. open-vm-tools 2008.04.14 changes: * Update the license stamp on all LGPL files. * Continued Unicode support. * Handle libdumbnet on Debian. * More bug fixes, including a security fix in guestd. open-vm-tools 2008.03.19 changes: * Continued Unicode support. * A few bug fixes. open-vm-tools 2008.03.03 changes: * Bug fixes (including the ability to specify custom LDFLAGS at build time, thanks to Mike Auty). * First cut of HGFSv3 implementation. * Beginnings of DnDv3 implementation. * Add Unicode support all over the code base. open-vm-tools 2008.02.13 changes: * Some bug fixes. open-vm-tools 2008.01.23 changes: * The Linux HGFS kernel module now supports writeback caching, which should yield better performance. * Added a generic Unicode-aware library to ease i18n and l10n work. * A bunch of bug fixes. open-vm-tools 2007.11.15 "Bandsaw" changes: * Kernel modules for FreeBSD, including an experimental port of HGFS to FreeBSD. * Add the vmsync driver on Linux to make VM snapshots consistent. * Added the xferlogs utility, the *-vm-default scripts, and the vm-support script. * Build on a wider variety of systems. * Lots of smaller bug fixes throughout the code. open-vm-tools 2007.09.04 "Axe" changes: * Initial release of open-vm-tools. open-vm-tools-stable-12.5.0/open-vm-tools/README000066400000000000000000000003051470176644300211770ustar00rootroot00000000000000This file is no longer distributed with open-vm-tools. For current project information and release notes, please refer to README.md and ReleaseNotes.md at https://github.com/vmware/open-vm-tools open-vm-tools-stable-12.5.0/open-vm-tools/checkvm/000077500000000000000000000000001470176644300217415ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/checkvm/COPYING000066400000000000000000000634711470176644300230070ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! open-vm-tools-stable-12.5.0/open-vm-tools/checkvm/Makefile.am000066400000000000000000000027541470176644300240050ustar00rootroot00000000000000################################################################################ ### Copyright (c) 2007-2016,2020 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ bin_PROGRAMS = vmware-checkvm vmware_checkvm_SOURCES = vmware_checkvm_SOURCES += checkvm.c vmware_checkvm_LDADD = vmware_checkvm_LDADD += @GLIB2_LIBS@ vmware_checkvm_LDADD += @VMTOOLS_LIBS@ vmware_checkvm_CPPFLAGS = vmware_checkvm_CPPFLAGS += @GLIB2_CPPFLAGS@ if HAVE_ICU vmware_checkvm_LDADD += @ICU_LIBS@ vmware_checkvm_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXX) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ else vmware_checkvm_LINK = $(LINK) endif open-vm-tools-stable-12.5.0/open-vm-tools/checkvm/checkvm.c000066400000000000000000000061231470176644300235270ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2007-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * checkvm.c -- * * Check if we are running in a VM or not */ #include #include #include #if !defined(_WIN32) #include #endif #include "vm_basic_types.h" #include "vmcheck.h" #if defined(_WIN32) #include "getoptwin32.h" #include "vmware/tools/win32util.h" #endif #include "checkvm_version.h" #include "vm_version.h" #include "embed_version.h" VM_EMBED_VERSION(CHECKVM_VERSION_STRING); /* * Start of main program. Check if we are in a VM, by reading * a backdoor port. Then process any other commands. */ int main(int argc, char *argv[]) { uint32 version[2]; gchar *gAppName; GError *gErr = NULL; gboolean product = FALSE; int success = 1; GOptionEntry options[] = { {"prod", 'p', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &product, "print VMware hypervisor product.", NULL}, {NULL} }; GOptionContext *optCtx; #if defined(_WIN32) WinUtil_EnableSafePathSearching(TRUE); #endif /* * set up glib options context. */ gAppName = g_path_get_basename(argv[0]); g_set_prgname(gAppName); optCtx = g_option_context_new(NULL); g_option_context_add_main_entries(optCtx, options, NULL); if (!VmCheck_IsVirtualWorld()) { g_printerr("Error: %s must be run inside a virtual machine" " on a VMware hypervisor product.\n", gAppName); goto out; } if (!VmCheck_GetVersion(&version[0], &version[1])) { g_printerr("%s: Couldn't get version\n", gAppName); goto out; } if (!g_option_context_parse(optCtx, &argc, &argv, &gErr)) { g_printerr("%s: %s\n", gAppName, gErr->message); g_error_free(gErr); goto out; } /* * product is true if 'p' option was passed to parser */ if (product) { switch (version[1]) { case VMX_TYPE_SCALABLE_SERVER: g_print("ESX Server\n"); break; case VMX_TYPE_WORKSTATION: g_print("Workstation\n"); break; default: g_print("Unknown\n"); break; } success = 0; goto out; } g_print("%s version %d (good)\n", PRODUCT_LINE_NAME, version[0]); success = 0; out: g_option_context_free(optCtx); g_free(gAppName); return success; } open-vm-tools-stable-12.5.0/open-vm-tools/checkvm/checkvm_version.h000066400000000000000000000030151470176644300252760ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * checkvm_version.h -- * * Version definitions for the VM checking utility. */ #ifndef _CHECKVM_VERSION_H_ #define _CHECKVM_VERSION_H_ /* * This component's version is coupled with Tools versioning. The effect * is that the version increments with each build, and with each Tools * version bump. If and when it becomes necessary to version the component * manually, make sure that the version is bumped any time the component or * its dependencies are changed. */ #include "vm_tools_version.h" #define CHECKVM_VERSION_COMMAS TOOLS_VERSION_EXT_CURRENT_CSV #define CHECKVM_VERSION_STRING TOOLS_VERSION_EXT_CURRENT_STR #endif /* _CHECKVM_VERSION_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/configure.ac000066400000000000000000001660021470176644300226140ustar00rootroot00000000000000################################################################################ ### Copyright (c) 2007-2024 Broadcom. All Rights Reserved. ### The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. ### ### Configure script for building the VMware OSS Tools. ### ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ ################################################################################ # In addition to the usual environment variables and command line # arguments that a configure script usually takes (CFLAGS, LDFLAGS, # etc.), this script also accepts variables of the form: # # CUSTOM_LIB_CPPFLAGS: compile-time flags for LIB # CUSTOM_LIB_LIBS: link-time flags for LIB # RPCGENFLAGS: extra flags to pass to rpcgen # # The following libraries are currently tested: DNET, FUSE, GLIB2, GMODULE, # GOBJECT, GTHREAD, GTK, GTKMM, ICU, LIBPNG, PAM, URIPARSER, ZLIB ################################################################################ ### ### Initialization ### TOOLS_VERSION="12.5.0" AC_INIT( [open-vm-tools], [12.5.0], [open-vm-tools-devel@lists.sourceforge.net]) # In order to make this configure script auto-detect situations where # people have a 32-bit userland running with a 64-bit kernel, we try to ask # the compiler (assumedly gcc) for its default Target:. # We have to set up $TEST_CC manually, since AC_PROG_CC hasn't yet been run (and can't be until AC_CANONICAL_HOST & AC_CANONICAL_BUILD are run) # The purpose of all this is to set up $host_alias/$build_alias in a more # intelligent way than config.guess currently does. TEST_CC="$CC_FOR_BUILD" test -z "$TEST_CC" && TEST_CC="$HOST_CC" test -z "$TEST_CC" && TEST_CC="$CC" if test -n "$TEST_CC" -a -z "$host_alias"; then host_alias="`$TEST_CC -dumpmachine`" if test -z "$build_alias" -a -n "$host_alias"; then build_alias="$host_alias" fi fi unset TEST_CC # checkvm/checkvm.c has no special significance - we just need to pass in a file that # helps autoconf verify that it really has found the source tree. AC_CONFIG_SRCDIR([checkvm/checkvm.c]) # Keep the top-level directory tidy by putting auxiliary build tools and local # macros in separate subdirectories. AC_CONFIG_AUX_DIR([config]) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_HOST AC_CANONICAL_BUILD # Quote the regular expressions case "$host_cpu" in [i[3456]86]) arch="x32" ;; [amd64|x86_64]) arch="x64" ;; [aarch64]) arch="arm64" ;; [*]) AC_MSG_ERROR([Unknown architecture.]) ;; esac # Operational arguments. AC_ARG_WITH([root-privileges], [AS_HELP_STRING([--without-root-privileges], [does not perform any operations that require root privileges])], [], [with_root_privileges=yes]) # Kernel arguments. # The kernel args have to go here otherwise the KERNEL_RELEASE won't be visible # to getOsVersion() AC_ARG_WITH([kernel-release], [AS_HELP_STRING([--with-kernel-release], [specifies the kernel release you want to build against])], [KERNEL_RELEASE="$withval"], [KERNEL_RELEASE=`uname -r`]) AC_ARG_WITH([linuxdir], [AS_HELP_STRING([--with-linuxdir], [specifies the Linux directory you want to use])], [LINUXDIR="$withval"], [LINUXDIR=/lib/modules/$KERNEL_RELEASE]) # Turn the uname output into something we can run comparisons on. getOsVersion() { major_version="`echo $KERNEL_RELEASE | cut -f1 -d. | cut -f1 -d-`" minor_version="`echo $KERNEL_RELEASE | cut -f2 -d. | cut -f1 -d-`" micro_version="`echo $KERNEL_RELEASE | cut -f3 -d. | cut -f1 -d-`" printf '%02d%02d%03d' $major_version $minor_version $micro_version } case "$host_os" in [linux*]) os="linux" ;; [freebsd*]) os="freebsd" ;; [kfreebsd*-gnu]) os="kfreebsd-gnu" ;; [solaris*]) os="solaris" ;; [*]) AC_MSG_WARN([This is an untested and unsupported Operating System. Proceed at your own peril.]) ;; esac osVersion="`getOsVersion`" AC_ARG_ENABLE( glibc-check, AS_HELP_STRING( [--disable-glibc-check], [Skip checking the glibc version on the system. (off by default)]), [enable_glibc_check=$enableval], [enable_glibc_check="yes"]) if test "x$enable_glibc_check" != "xno" ; then if test "x$os" = "xlinux" ; then libc_ver=`ldd --version 2>/dev/null | head -1 | sed 's/.* //;q'` if test "x$libc_ver" = "x"; then AC_MSG_ERROR(["Failed to detect glibc version installed in the system."]) fi libc_ver_mjr=`expr "$libc_ver" : "\([[0-9]]*\)"` libc_ver_mnr=`expr "$libc_ver" : "[[0-9]]*\.\([[0-9]]*\)"` libc_ver_num=`expr $libc_ver_mjr \* 1000 + $libc_ver_mnr` if test "$libc_ver_num" -lt 2011; then AC_MSG_ERROR(["glibc version $libc_ver detected. This version of open-vm-tools requires glibc version 2.11 or later. Please use an older version of open-vm-tools for this system."]) fi fi fi if test "x$os" = "xfreebsd" -a "$osVersion" -lt 1000000; then AC_MSG_ERROR(["This version of open-vm-tools requires FreeBSD version 10 or later. Please use an older version of open-vm-tools for this system."]) fi AC_ARG_WITH([kernel-modules], [AS_HELP_STRING([--with-kernel-modules], [compile and install the kernel modules])], [], [if test "x$os" = "xlinux" ; then with_kernel_modules=no else with_kernel_modules=yes fi ]) if test "$with_kernel_modules" = "yes"; then case "$os" in linux) AC_MSG_ERROR([Building kernel modules for Linux is no longer supported.]) ;; freebsd) freebsd_sysdir=/usr/src/sys if test -n "$SYSDIR"; then freebsd_sysdir="$SYSDIR" fi if test ! -f "$freebsd_sysdir/conf/kmod.mk"; then AC_MSG_ERROR([FreeBSD kernel tree not found. Please install the kernel sources (or provide the location using SYSDIR) or configure using --without-kernel-modules.]) fi ;; esac fi # Locates X includes and lib, adds --without-x option, # and sets no_x. AC_PATH_XTRA AC_CHECK_HEADER([valgrind/valgrind.h], [], [have_valgrind=no], []) AC_ARG_ENABLE( valgrind, AS_HELP_STRING( [--enable-valgrind], [enables building with valgrind]), [enable_valgrind="$enableval"], [enable_valgrind="no"]) if test "$enable_valgrind" = "yes" ; then if test "$have_valgrind" = "no" ; then AC_MSG_ERROR([valgrind/valgrind.h not found. Make sure you have the valgrind headers installed.]), fi CPPFLAGS="$CPPFLAGS -DUSE_VALGRIND=1" fi # Arguments for disabling individual open-vm-tools features or libraries. AC_ARG_ENABLE( multimon, AS_HELP_STRING( [--disable-multimon], [disables multimon, enabled by default]), [enable_multimon="$enableval"], [enable_multimon="yes"]) AC_ARG_WITH( gtk3, AS_HELP_STRING( [--without-gtk3], [compiles without Gtk 3.0]), [with_gtk3="$withval"], [with_gtk3="auto"]) AC_ARG_WITH( gtk2, AS_HELP_STRING( [--without-gtk2], [compiles without Gtk 2.0]), [with_gtk2="$withval"], [with_gtk2="auto"]) if test "$no_x" = "yes" ; then with_gtk2="no" with_gtk3="no" else if test "$with_gtk2" = "auto" ; then if test "$with_gtk3" = "auto" ; then with_gtk2="no" with_gtk3="yes" elif test "$with_gtk3" = "no" ; then with_gtk2="yes" elif test "$with_gtk3" = "yes" ; then with_gtk2="no" fi elif test "$with_gtk2" = "no" ; then if test "$with_gtk3" = "auto" ; then with_gtk3="yes" elif test "$with_gtk3" = "no" ; then AC_MSG_ERROR('need either gtk2 or gtk3 or build with --without-x to disable building desktop plugins') fi elif test "$with_gtk2" = "yes" ; then if test "$with_gtk3" = "auto" ; then with_gtk3="no" elif test "$with_gtk3" = "yes" ; then AC_MSG_ERROR('cannot set both --with-gtk2 and --with-gtk3') fi fi fi if test "$with_gtk2" = "no" ; then with_gtkmm="no" fi if test "$with_gtk3" = "no" ; then with_gtkmm3="no" fi if test "$with_gtk3" = "yes"; then AC_ARG_WITH( gtkmm3, AS_HELP_STRING( [--without-gtkmm3], [compiles without Gtkmm 3, sigc++, and related libs]), [with_gtkmm3="$withval"], [with_gtkmm3="yes"]) with_gtkmm="no" elif test "$with_gtk2" = "yes"; then AC_ARG_WITH( gtkmm, AS_HELP_STRING( [--without-gtkmm], [compiles without Gtkmm, sigc++, and related libs]), [with_gtkmm="$withval"], [with_gtkmm="yes"]) with_gtkmm3="no" fi AC_ARG_ENABLE( docs, AS_HELP_STRING( [--disable-docs], [disables generation of API documentation; by default, docs are built if doxygen is available.]), [enable_docs="$enableval"], [enable_docs="yes"]) AC_ARG_ENABLE( tests, AS_HELP_STRING( [--disable-tests], [disable compilation of test code.]), [enable_tests="$enableval"], [enable_tests="auto"]) AC_ARG_ENABLE( resolutionkms, AS_HELP_STRING( [--enable-resolutionkms], [build the linux / unix resolutionkms module.]), [], [enable_resolutionkms="auto"]) AC_ARG_ENABLE( vmwgfxctrl, AS_HELP_STRING( [--enable-vmwgfxctrl], [build the linux / unix vmwgfxctrl tool.]), [], [enable_vmwgfxctrl="auto"]) AM_INIT_AUTOMAKE ### ### Constants ### # These need to be declared after initialization. # Some of our macro call-sites require changes to # CPPFLAGS/CFLAGS/LDFLAGS. In such places, we save the original value # of CPPFLAGS/CFLAGS/LDFLAGS before the macro call and restore it when # the call is done. We must perform this save at each macro site, # because CPPFLAGS/CFLAGS/LDFLAGS may change over the course of # configuration. # # CPPFLAGS is intended for preprocessor options (-D and -I mainly) # CFLAGS is intended for compiler options (-O, -f, -W, and so forth) CPPFLAGS="$CPPFLAGS -DUSING_AUTOCONF=1 -DOPEN_VM_TOOLS" ### ### Programs ### # C preprocessor and compiler. AC_PROG_CPP AC_PROG_CC # C++ compiler. Note that unlike AC_PROG_CC, this call does not trigger an # error if no C++ compiler was found; it'll just set the variable CXX to 'g++'. AC_PROG_CXX # This allows features like per-target compiler flags. I.e., you can compile # one copy of the same sources twice with different flags. (See lib/guestApp # for an example.) AM_PROG_CC_C_O # Needed for the various install and uninstall hooks. AC_PROG_INSTALL AC_PROG_SED AC_PROG_LN_S AC_PROG_MKDIR_P # Needed for creating the archives in lib/ and the shared libraries. AC_PROG_LIBTOOL if test "$ac_cv_prog_AR" = false; then AC_MSG_ERROR([The 'ar' utility was not found. Please put ar on the path.]) fi # We use pkg-config to set up the cflags and libs for gtk. AC_CHECK_TOOL( [PKG_CONFIG], [pkg-config], [not_found]) if test "$GCC" != "yes"; then AC_MSG_ERROR([Only GCC is currently supported. Please put gcc in the path.]) fi ### ### Libraries ### # # Check for libintl.h. When configuring using "--without-x", /usr/local/include # may not be added to the include path, so code that use glib's i18n functions # would fail to compile because it can't find libintl.h. # AC_CHECK_HEADER([libintl.h], [], [have_libintl=no], []) if test "$have_libintl" = "no"; then unset ac_cv_header_libintl_h CPPFLAGS="$CPPFLAGS -I/usr/local/include" AC_CHECK_HEADER([libintl.h], [], [AC_MSG_ERROR([libintl.h not found. Make sure you have the gettext headers installed.])], []) fi AC_ARG_ENABLE([deploypkg], [AS_HELP_STRING([--disable-deploypkg], [do not build deploypkg plugin.])], [], [ if test "$os" = "linux"; then enable_deploypkg=yes else enable_deploypkg=no fi ]) if test "$enable_deploypkg" = "yes"; then AC_VMW_CHECK_LIB([mspack], [MSPACK], [libmspack], [], [0.0.20040308alpha], [mspack.h], [mspack_version], [], [AC_MSG_ERROR([mspack >= 0.0.20040308alpha is required.])]) fi AC_ARG_ENABLE([libappmonitor], [AS_HELP_STRING([--enable-libappmonitor], [Build the libappmonitor library.])], [], [ enable_libappmonitor=no ]) AC_ARG_ENABLE([servicediscovery], [AS_HELP_STRING([--enable-servicediscovery], [Build the Service Discovery Plugin.])], [ enable_servicediscovery=$enableval ], [ enable_servicediscovery=no ]) # # Check that servicediscovery is enabled only on linux systems # if test "$enable_servicediscovery" = "yes"; then if test "$os" != "linux"; then AC_MSG_ERROR([The Service Discovery plugin is only supported for Linux platforms. Try configure without --enable-servicediscovery option.]) fi fi AC_ARG_ENABLE([salt-minion], [AS_HELP_STRING([--enable-salt-minion], [Install salt_minion related script files.])], [ enable_saltminion=$enableval ], [ enable_saltminion=no ]) # # Check that salt_minion is enabled only on linux systems # if test "$enable_saltminion" = "yes"; then if test "$os" != "linux"; then AC_MSG_ERROR([The salt_minion package is only supported for Linux platforms. Try configure without --enable-salt-minion option.]) fi fi # # Check for glib 2.34.0 or greater. # AC_VMW_CHECK_LIB([glib-2.0], [GLIB2], [glib-2.0], [], [2.34.0], [glib.h], [g_key_file_new], [], [AC_MSG_ERROR([glib2 >= 2.34.0 is required.])]) AC_VMW_CHECK_LIB([gmodule-2.0], [GMODULE], [gmodule-2.0], [], [2.34.0], [], [g_module_open], [], [AC_MSG_ERROR([gmodule >= 2.34.0 is required.])]) AC_VMW_CHECK_LIB([gobject-2.0], [GOBJECT], [gobject-2.0], [], [2.34.0], [glib-object.h], [g_object_new], [], [AC_MSG_ERROR([gobject >= 2.34.0 is required.])]) AC_VMW_CHECK_LIB([gthread-2.0], [GTHREAD], [gthread-2.0], [], [2.34.0], [], [g_thread_new], [], [AC_MSG_ERROR([gthread >= 2.34.0 is required.])]) AC_CHECK_PROG([have_genmarshal], [glib-genmarshal], [yes], [no]) if test "$have_genmarshal" != "yes"; then AC_MSG_ERROR([glib-genmarshal is required; make sure it is available in your path.]) fi # # Check for fuse. # AC_ARG_WITH([fuse], [AS_HELP_STRING([--without-fuse], [compiles without FUSE support (disables vmblock-fuse/vmhgfs-fuse).])], [with_fuse="$withval"], [with_fuse=auto]) case "$with_fuse" in fuse|2) with_fuse="fuse" ;; fuse3|3) with_fuse="fuse3" ;; auto) ;; yes) ;; no) have_fuse3=no; have_fuse=no; ;; *) AC_MSG_FAILURE([--with-fuse was given with an unsupported paramter $with_fuse]) ;; esac if test "$with_fuse" = "auto" || test "$with_fuse" = "fuse3" || test "$with_fuse" = "yes"; then # # Check for fuse3. # # FUSE_USE_VERSION sets the version of the FUSE API that will be exported. AC_VMW_CHECK_LIB([fuse3], [FUSE3], [fuse3], [], [3.10.0], [fuse3/fuse.h], [fuse_main], [have_fuse3=yes; AC_DEFINE([HAVE_FUSE3], 1, [Define to 1 if using FUSE3.]) AC_DEFINE([FUSE_USE_VERSION], 35, [FUSE API version to use.])], [have_fuse3=no]) if test "$have_fuse3" = "no"; then if test "$with_fuse" = "auto" || test "$with_fuse" = "yes"; then AC_MSG_NOTICE([Fuse3 is missing, trying to use older Fuse library.]) else AC_MSG_FAILURE([Fuse3 was requested but unavailable on the system.]) fi fi fi if test "$with_fuse" = "fuse" || ( ( test "$with_fuse" = "auto" || test "$with_fuse" = "yes" ) && test "$have_fuse3" = "no" ); then # # Check for fuse. # # FUSE_USE_VERSION sets the version of the FUSE API that will be exported. AC_VMW_CHECK_LIB([fuse], [FUSE], [fuse], [], [], [fuse.h], [fuse_main], [have_fuse=yes; AC_DEFINE([HAVE_FUSE], 1, [Define to 1 if using FUSE.]) AC_DEFINE([FUSE_USE_VERSION], 29, [FUSE API version to use.])], [have_fuse=no]) if test "$have_fuse" = "no"; then if test "$with_fuse" = "auto" || test "$with_fuse" = "yes"; then AC_MSG_NOTICE([Fuse is missing, vmblock-fuse/vmhgfs-fuse will be disabled.]) else AC_MSG_FAILURE([Fuse2 was requested but unavailable on the system.]) fi fi fi if test "$with_fuse" = "no"; then AC_MSG_WARN([Fuse or Fuse3 is suppressed, vmblock-fuse/vmhgfs-fuse will be disabled.]) fi # # Check for PAM. # AC_ARG_WITH([pam], [AS_HELP_STRING([--without-pam], [compiles without PAM support (disables vgauth).])], [with_pam="$withval"], [with_pam=yes]) if test "$with_pam" = "yes"; then AC_VMW_DEFAULT_FLAGS([PAM]) AC_VMW_CHECK_LIB([pam], [PAM], [], [], [], [security/pam_appl.h], [pam_start], [PAM_CPPFLAGS="$PAM_CPPFLAGS -DUSE_PAM"], [AC_VMW_LIB_ERROR([PAM], [pam])]) fi AC_ARG_ENABLE([containerinfo], [AS_HELP_STRING([--disable-containerinfo], [do not build containerinfo plugin.])], [ enable_containerinfo=$enableval ], [ if test "$os" = "linux"; then enable_containerinfo=auto else enable_containerinfo=no fi ]) # # Check that containerinfo plugin is enabled only on linux systems. # if test "$os" != "linux"; then if test "$enable_containerinfo" = "yes"; then AC_MSG_ERROR([The containerinfo plugin is only supported for Linux platforms. Try configure with --disable-containerinfo option.]) fi fi if test "$enable_containerinfo" = "yes" || test "$enable_containerinfo" = "auto"; then can_build_containerinfo=yes # # AC_VMW_CONTAINERINFO_MSG(library) # # Wrapper around AC_MSG_WARN to print a standard message about missing libraries. # # library ($1): name of missing library / package. # AC_DEFUN([AC_VMW_CONTAINERINFO_MSG],[ can_build_containerinfo=no AC_MSG_WARN(["$1 is missing which is required for building containerinfo plugin."]) ]) AC_VMW_DEFAULT_FLAGS([CURL]) AC_VMW_CHECK_LIB([curl], [CURL], [], [], [], [curl/curl.h], [curl_easy_init], [CURL_CPPFLAGS="$CURL_CPPFLAGS"], [AC_VMW_CONTAINERINFO_MSG([CURL])]) AC_VMW_CHECK_LIB([protobuf], [PROTOBUF], [protobuf], [], [3.0.0], [], [], [], [AC_VMW_CONTAINERINFO_MSG(["protobuf >= 3.0.0"])]) AC_VMW_DEFAULT_FLAGS([GRPC]) AC_VMW_CHECK_LIBXX([grpc++], [GRPC], [grpc++], [], [1.3.2], [grpc++/grpc++.h], [], [PKG_CHECK_MODULES([grpcxx], [grpc++ >= 1.3.2])], [AC_VMW_CONTAINERINFO_MSG(["grpc++ >= 1.3.2"])]) # # proto files needed by containerd grpc client. # # Installation location varies between Linux vendors. # Canonical, Ubuntu and Debian: in /usr/share/gocode/src # openSUSE/SUSE: in /usr/share/go//contrib/src # for d in /usr/share/gocode/src /usr/share/go/1.*/contrib/src; do if test -d "$d"/github.com; then src_prefix="$d" break fi done shared_prefix=$src_prefix/github.com AC_SUBST(TYPES_DIR, github.com/containerd/containerd/api/types) AC_SUBST(TASKS_PROTOPATH, $shared_prefix/containerd/containerd/api/services/tasks/v1) AC_SUBST(DEP_PROTOPATH, $src_prefix) AC_SUBST(CONTAINERD_PROTOPATH, $shared_prefix/containerd/containerd/api/services/containers/v1) AC_SUBST(GOGO_PROTOPATH, $shared_prefix/gogo/protobuf) AC_CHECK_FILE([${CONTAINERD_PROTOPATH}/containers.proto], [], [AC_VMW_CONTAINERINFO_MSG(["containerd package"])]) AC_CHECK_FILE([${TASKS_PROTOPATH}/tasks.proto], [], [AC_VMW_CONTAINERINFO_MSG(["containerd package"])]) AC_CHECK_FILE([${DEP_PROTOPATH}/${TYPES_DIR}/mount.proto], [], [AC_VMW_CONTAINERINFO_MSG(["containerd package"])]) AC_CHECK_FILE([${DEP_PROTOPATH}/${TYPES_DIR}/metrics.proto], [], [AC_VMW_CONTAINERINFO_MSG(["containerd package"])]) AC_CHECK_FILE([${DEP_PROTOPATH}/${TYPES_DIR}/descriptor.proto], [], [AC_VMW_CONTAINERINFO_MSG(["containerd package"])]) AC_CHECK_FILE([${DEP_PROTOPATH}/${TYPES_DIR}/task/task.proto], [], [AC_VMW_CONTAINERINFO_MSG(["containerd package"])]) AC_CHECK_FILE([${GOGO_PROTOPATH}/gogoproto/gogo.proto], [], [AC_VMW_CONTAINERINFO_MSG(["gogoproto package"])]) # # Binaries needed to build for containerd grpc client. # AC_CHECK_PROG([GRPC_CPP], [grpc_cpp_plugin], [grpc_cpp_plugin], [not found]) if test "$GRPC_CPP" != "grpc_cpp_plugin" ; then AC_VMW_CONTAINERINFO_MSG(["grpc_cpp_plugin binary"]) fi AC_CHECK_PROG([PROTOC], [protoc], [protoc], [not found]) if test "$PROTOC" != "protoc" ; then AC_VMW_CONTAINERINFO_MSG(["protoc binary"]) fi if test "$can_build_containerinfo" = "no" ; then if test "$enable_containerinfo" = "auto" ; then enable_containerinfo=no AC_MSG_WARN(["Cannot enable containerinfo plugin since one ore more required packages are missing."]) else AC_MSG_ERROR(["Cannot enable containerinfo plugin since one or more required packages are missing. Please configure without containerinfo (using --disable-containerinfo), or install the necessary libraries and devel package(s)."]) fi else enable_containerinfo=yes fi fi AC_ARG_ENABLE([vgauth], [AS_HELP_STRING([--disable-vgauth], [do not build vgauth])], [ if test "$with_pam" = "no" -a "$enableval" = "yes"; then AC_MSG_ERROR([Cannot enable vgauth without PAM. Please configure without --without-pam or without --enable-vgauth.]) fi enable_vgauth="$enableval" ], [ if test "$with_pam" = "no"; then enable_vgauth="no" AC_MSG_WARN("Building without PAM; vgauth will be disabled.") elif test "$os" = "linux"; then enable_vgauth=yes else enable_vgauth=no fi ]) # # Check for openssl, xmlsec1, xml2 # AC_ARG_WITH([ssl], [AS_HELP_STRING([--without-ssl], [compiles without openssl support (disables vgauth)])], [if test "$withval" = "no"; then enable_vgauth = "no"; fi], [with_ssl="yes"]) AC_ARG_WITH([xmlsec1], [AS_HELP_STRING([--without-xmlsec1], [compiles without xmlsec1 support (disables vgauth)])], [if test "$withval" = "no"; then enable_vgauth = "no"; fi], [with_xmlsec1="yes"]) AC_ARG_WITH([xml2], [AS_HELP_STRING([--without-xml2], [compiles without xml2 support (disables vgauth)])], [if test "$withval" = "no"; then enable_vgauth = "no"; fi], [with_xml2="yes"]) AC_ARG_WITH([tirpc], [AS_HELP_STRING([--without-tirpc], [compiles with/without libtirpc])], [], [with_tirpc=auto]) # Make sure we are building with openssl 1.0.1 and above so that # we use only TLSv1_2. if test "$enable_vgauth" = "yes" ; then AC_VMW_DEFAULT_FLAGS([SSL]) AC_VMW_CHECK_LIB([ssl], [SSL], [openssl], [], [1.0.1], [], [BIO_new_file], [], [AC_VMW_LIB_ERROR([SSL], [ssl])]) CPPFLAGS="$CPPFLAGS -DUSE_VGAUTH" AC_VMW_DEFAULT_FLAGS([XML2]) AC_VMW_CHECK_LIB([xml2], [XML2], [], [], [], [], [], [], [AC_VMW_LIB_ERROR([XML2], [xml2])]) # Multiple distros built xmlsec1 with -DXMLSEC_NO_SIZE_T but # their xmlssec1-config --cflags doesn't properly report it. # Force it on following the xmlSecSize changelog in below link: # https://www.aleksey.com/xmlsec/news.html # The xmlsec configure flag "enable_size_t" is "yes" by default # since 1.3.0, and both the configure flag and CPP flag has been # deprecated since 1.3.3, which means the size_t is used by default # and no need to add CPP flag -DXMLSEC_NO_SIZE_T since 1.3.0. AC_VMW_DEFAULT_FLAGS([XMLSEC1]) AC_VMW_CHECK_LIB([xmlsec1], [XMLSEC1], [], [xmlsec1-config], [], [xmlsec/xmlsec.h], [xmlSecCheckVersionExt], [XMLSEC1_VER=`pkg-config --modversion xmlsec1` xmlsec1_major_version="`echo $XMLSEC1_VER | cut -f1 -d. | cut -f1 -d-`" xmlsec1_minor_version="`echo $XMLSEC1_VER | cut -f2 -d. | cut -f1 -d-`" xmlsec1_micro_version="`echo $XMLSEC1_VER | cut -f3 -d. | cut -f1 -d-`" xmlsec1_version=`printf '%02d%02d%02d' $xmlsec1_major_version $xmlsec1_minor_version $xmlsec1_micro_version` AC_CHECK_SIZEOF(size_t) if test "$xmlsec1_version" -lt 010300 -a "$ac_cv_sizeof_size_t" -ne 4 ; then XMLSEC1_CPPFLAGS="$XMLSEC1_CPPFLAGS -DXMLSEC_NO_SIZE_T" fi ], [AC_VMW_LIB_ERROR([XMLSEC1], [xmlsec1])]) fi # # Check for CUnit and disable test code if not available. # if test "$enable_tests" = "auto" -o "$enable_tests" = "yes"; then AC_VMW_DEFAULT_FLAGS([CUNIT]) AC_VMW_CHECK_LIB([cunit], [CUNIT], [], [], [], [CUnit/CUnit.h], [CU_initialize_registry], [have_cunit=yes], [have_cunit=no]) if test "$have_cunit" = "no"; then if test "$enable_tests" = "yes"; then AC_VMW_LIB_ERROR([CUNIT], [cunit]) else AC_MSG_WARN([CUnit not found, tests won't be compiled.]) fi fi fi # If the user explicitly disables X11, then don't try to detect the X-related libraries if test "$have_x" = "disabled"; then enable_multimon="no" elif test "$have_x" != "yes"; then AC_MSG_ERROR( [The X11 libraries were not found. Please configure without X11 (using --without-x), or install the libX11 devel package(s).]) else CPPFLAGS="$CPPFLAGS $X_CFLAGS" COMMON_XLIBS="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" AC_CHECK_LIB( [Xext], [XeviQueryVersion], [COMMON_XLIBS="-lXext $COMMON_XLIBS"], [AC_MSG_ERROR( [libXext not found. Please configure without X11 (using --without-x), or install the libXext devel package(s).])], [$COMMON_XLIBS]) AC_CHECK_HEADER( [X11/extensions/extutil.h], [], [AC_MSG_ERROR( [X11/extensions/extutil.h header not found - you are probably on Solaris 10 or older. Please copy that header file onto your system manually, or configure without X11 (using --without-x).])], [#include #include ]) if test "$enable_multimon" != "no"; then AC_CHECK_LIB( [Xinerama], [XineramaQueryVersion], [COMMON_XLIBS="-lXinerama $COMMON_XLIBS"], [AC_MSG_ERROR( [libXinerama not found. Please configure without multimon (using --disable-multimon), configure without X11 (using --without-x), or install the libXinerama devel package(s).])], [$COMMON_XLIBS]) fi AC_CHECK_LIB( [Xi], [XOpenDevice], [COMMON_XLIBS="-lXi $COMMON_XLIBS"], [AC_MSG_ERROR( [libXi not found. Please configure without X11 (using --without-x), or install the libXi devel package(s).])], [$COMMON_XLIBS]) AC_CHECK_LIB( [Xrender], [XRenderQueryVersion], [COMMON_XLIBS="-lXrender $COMMON_XLIBS"], [AC_MSG_ERROR( [libXrender not found. Please configure without X11 (using --without-x), or install the libXrender devel package(s).])], [$COMMON_XLIBS]) AC_CHECK_LIB( [Xrandr], [XRRQueryVersion], [COMMON_XLIBS="-lXrandr $COMMON_XLIBS"], [AC_MSG_ERROR( [libXrandr not found. Please configure without X11 (using --without-x) or install the libXrandr devel package(s).])], [$COMMON_XLIBS]) AC_CHECK_LIB( [Xtst], [XTestQueryExtension], [COMMON_XLIBS="-lXtst $COMMON_XLIBS"], [AC_MSG_ERROR( [libXtst not found. Please configure without X11 (using --without-x) or install the libXtst devel package(s).])], [$COMMON_XLIBS]) AC_CHECK_LIB( [SM], [SmcOpenConnection], [XSM_LIBS="-lSM -lICE" && have_xsm_lib="yes"], [] [-lICE]) AC_CHECK_HEADERS([X11/SM/SMlib.h X11/ICE/ICElib.h], [have_xsm_header="yes"], [], []) if test "$have_xsm_lib" = "yes" -a "$have_xsm_header" = "yes"; then have_xsm="yes" fi AC_CHECK_LIB( [Xcomposite], [XCompositeQueryExtension], [XCOMPOSITE_LIBS="-lXcomposite"], [have_xcomposite="no"] []) AC_CHECK_HEADERS([X11/extensions/Xcomposite.h], [], [have_xcomposite="no"], []) if test "$have_xcomposite" != "no"; then have_xcomposite="yes" fi # Check whether we have gtk+ 3.0. if test "$with_gtk3" != "no"; then # gdk_display_get_default_group (added in gtk+ 2.4.0) is function currently # needed by vmware-user. AC_VMW_CHECK_LIB([gtk-3], [GTK], [gtk+-3.0], [], [3.0.0], [gtk/gtk.h], [gdk_display_get_default_group], [GTK_CPPFLAGS="$GTK_CPPFLAGS -DGTK3"], [AC_MSG_ERROR([Gtk+ 3.0 library not found or too old. Please configure without Gtk+ support (using --without-gtk3) or install the Gtk+ 3.0 devel package.])]) # Check whether we have gtk+ 2.0. elif test "$with_gtk2" != "no"; then AC_VMW_CHECK_LIB([gtk-x11-2.0], [GTK], [gtk+-2.0], [], [2.4.0], [gtk/gtk.h], [gdk_display_get_default_group], [GTK_CPPFLAGS="$GTK_CPPFLAGS -DGTK2"], [AC_MSG_ERROR([Gtk+ 2.0 library not found or too old. Please configure without Gtk+ support (using --without-gtk2) or install the Gtk+ 2.0 devel package.])]) fi # # Check for gtkmm 2.4.0 or greater. # if test "$with_gtkmm" != "no" -o "$with_gtkmm3" != "no"; then if test "$with_gtkmm3" != "no"; then AC_VMW_CHECK_LIBXX([gtkmm-3.0], [GTKMM], [gtkmm-3.0], [], [3.0.0], [gtkmm.h], [], [GTKMM_CPPFLAGS="$GTKMM_CPPFLAGS -DHAVE_GTKMM"], [AC_MSG_ERROR([gtkmm3 library not found. Please install the libgtkmm devel package(s), or re-configure using --without-gtkmm3.])]) elif test "$with_gtkmm" != "no"; then CUSTOM_GTKMM_CPPFLAGS="$CUSTOM_GTKMM_CPPFLAGS $GTK_CPPFLAGS" AC_VMW_CHECK_LIBXX([gtkmm-2.4], [GTKMM], [gtkmm-2.4], [], [2.4.0], [gtkmm.h], [], [GTKMM_CPPFLAGS="$GTKMM_CPPFLAGS -DHAVE_GTKMM"], [AC_MSG_ERROR([gtkmm library not found. Please install the libgtkmm devel package(s), or re-configure using --without-gtkmm.])]) fi # # libsigc++-2.0 >= 2.5.1 requires C++11 support # # Calling AC_VMW_CHECK_LIBXX would duplicate the sigc++ # flags we would have already got as part of gtkmm call # above. This is OK because we are not seeing any issues # because of this and calling AC_VMW_CHECK_LIBXX function # provides other benefits like picking custom flags. # # AC_VMW_CHECK_LIBXX sets CPPFLAGS and LIBS variables only, # so we have to use SIGCXX_CPPFLAGS instead of SIGCXX_CXXFLAGS. # AC_VMW_CHECK_LIBXX([sigc++-2.0], [SIGCXX], [sigc++-2.0], [], [2.5.1], [sigc++.h], [], [SIGCXX_CPPFLAGS="$SIGCXX_CPPFLAGS -std=c++11"], [SIGCXX_CPPFLAGS="$SIGCXX_CPPFLAGS"]) fi fi # End of checks for X libraries AC_CHECK_LIB( [crypt], [crypt], [HAVE_CRYPT="yes"], [AC_MSG_ERROR( [libcrypt not found. Please install the libc/libcrypt devel package(s).])]) AC_CHECK_FUNCS( dlopen, , [AC_CHECK_LIB( dl, dlopen, [VIX_LIBADD="$VIX_LIBADD -ldl" LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -ldl" VGAUTH_LIBADD="$VGAUTH_LIBADD -ldl" RESOLUTIONSET_LIBADD="$RESOLUTIONSET_LIBADD -ldl" ], [AC_MSG_ERROR( [dlopen was not found, but is required for open-vm-tools to function properly. Please contact your OS vendor.])])]) AC_CHECK_FUNCS([ecvt]) AC_CHECK_FUNCS([fcvt]) AC_CHECK_FUNC([mkdtemp], [have_mkdtemp=yes]) if test "$os" = "freebsd" -a "$osVersion" -ge 600000; then AC_CHECK_LIB( [thr], [pthread_mutex_init], [THREAD_LIBS=-lthr], [AC_MSG_ERROR( [Unable to locate required threading library libthr.])]) else AC_CHECK_LIB( [pthread], [pthread_mutex_init], [THREAD_LIBS=-lpthread], [AC_MSG_ERROR( [libpthread not found. Please install the libc/libpthread devel package(s).])]) fi # PAM prefix AC_ARG_WITH([pam-prefix], [AS_HELP_STRING([--with-pam-prefix], [specifies where pam files go. Default is $(sysconfdir)])], [PAM_PREFIX="$withval"], [if test "$os" = "freebsd" ; then PAM_PREFIX='$(sysconfdir)'; else PAM_PREFIX='/etc'; fi]) if test "$os" = "linux"; then with_dnet_dflt="no" else with_dnet_dflt="yes" fi AC_ARG_WITH([dnet], [AS_HELP_STRING([--with-dnet], [specifies whether to build with libdnet - the default is without for Linux, and with it otherwise])], [], [with_dnet="$with_dnet_dflt"]) have_dnet="no" if test "$with_dnet" = "yes"; then # On Debian, dnet is installed via the libdumbnet package. We need to # detect this so that our source files include dumbnet.h instead of # dnet.h, which is part of a different package altogether. AC_VMW_CHECK_LIB([dumbnet], [DNET], [], [dumbnet-config], [], [dumbnet.h], [intf_open], [have_dnet="yes"; AC_DEFINE([DNET_IS_DUMBNET], 1, [Define to 1 if substituting libdumbnet for libdnet in Debian.])], []) if test $have_dnet = "no"; then AC_VMW_CHECK_LIB([dnet], [DNET], [], [dnet-config], [], [dnet.h], [intf_open], [have_dnet="yes"], []) fi if test $have_dnet = "no"; then AC_MSG_ERROR( [dnet-config was not found on your PATH. Please configure without dnet or install dnet - http://libdnet.sourceforge.net]) fi fi if test "$with_dnet" != "yes"; then AC_DEFINE([NO_DNET], 1, [Define to 1 if building without libdnet.]) fi AC_ARG_WITH([icu], [AS_HELP_STRING([--with-icu], [enables support for ICU])], [], [with_icu=no]) if test "$have_x" = "yes" -o "$with_icu" = "yes"; then # AC_CHECK_PROG fails to locate CXX if it's set to an absolute # path and it includes arguments, which is often the case when # cross compling. Try to handle this case directly. case "$CXX" in [/*]) AS_IF(test -x ${CXX%% *}, [have_cxx=yes], [have_cxx=no]) ;; [*]) AC_CHECK_PROG([have_cxx], [$CXX], [yes], [no]) ;; esac if test "$have_cxx" = "no"; then AC_MSG_ERROR([C++ compiler not found. Make sure you have a C++ compiler installed or configure without X11 (using --without-x) and without ICU (using --without-icu).]) fi fi if test "$with_icu" = "yes"; then AC_VMW_CHECK_LIBXX([icui18n], [ICU], [icu-i18n], [icu-config], [], [unicode/utf.h], [], [ICU_CPPFLAGS="$ICU_CPPFLAGS -DUSE_ICU"], [AC_MSG_ERROR([ICU library not found. Please configure without ICU (using --without-icu) or install ICU - http://www.icu-project.org])]) # Check whether we have ICU >= 3.8. AC_LANG_PUSH([C++]) AC_MSG_CHECKING([for ucasemap_utf8ToTitle in ICU]) ORIGINAL_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $ICU_CPPFLAGS" AC_TRY_COMPILE([#include ], [ (void) &ucasemap_utf8ToTitle; return 0; ], [ ICU_CPPFLAGS="$ICU_CPPFLAGS -DHAVE_ICU_38" AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])]) CPPFLAGS="$ORIGINAL_CPPFLAGS" AC_LANG_POP([C++]) # Easier to give all modules the ICU defines/includes... CPPFLAGS="$CPPFLAGS $ICU_CPPFLAGS" else CPPFLAGS="$CPPFLAGS -DNO_ICU" fi if test "$with_tirpc" != "no"; then AC_VMW_CHECK_LIB([libtirpc], [TIRPC], [libtirpc], [], [], [], [], [have_tirpc="yes"], [have_tirpc="no"]) fi if test "$with_tirpc" != "yes"; then AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ #include #include int main() { struct xdr_ops xdr; #if defined(__GLIBC__) xdr.x_putint32(NULL, NULL); #endif return 0; } ]])], [need_tirpc="no"], [need_tirpc="yes"]) AC_MSG_NOTICE([tirpc is needed: $need_tirpc]) fi if test "$with_tirpc" = "no"; then if test "$need_tirpc" = "yes"; then AC_MSG_ERROR([libtirpc is required but it is disabled.]) fi use_tirpc="no" elif test "$with_tirpc" = "auto"; then if test "$need_tirpc" = "yes" -a "$have_tirpc" = "no"; then AC_MSG_ERROR([cannot find libtirpc but it is required.]) fi use_tirpc=$need_tirpc elif test "$with_tirpc" = "yes"; then if test "$have_tirpc" = "no"; then AC_MSG_ERROR([cannot build with libtirpc because it cannot be found.]) fi use_tirpc="yes" fi XDR_LIBS= XDR_CPPFLAGS= if test "$use_tirpc" = "yes"; then AC_MSG_NOTICE([building with libtirpc]) XDR_LIBS="$TIRPC_LIBS" XDR_CPPFLAGS="-DUSE_TIRPC $TIRPC_CPPFLAGS" else AC_MSG_NOTICE([building without libtirpc]) # In Solaris, the XDR-related functions are not in libc like in Linux and # FreeBSD, so binaries need to be linked to some extra libraries. if test "$os" = "solaris"; then XDR_LIBS="-lnsl -lrpcsvc" fi fi AC_PATH_PROG( [RPCGEN], [rpcgen], [not_found]) if test "$RPCGEN" == "not_found"; then AC_MSG_ERROR([rpcgen not found.]) fi ### ### Headers ### AC_CHECK_HEADERS([crypt.h]) AC_CHECK_HEADERS([inttypes.h]) AC_CHECK_HEADERS([stdint.h]) AC_CHECK_HEADERS([stdlib.h]) AC_CHECK_HEADERS([wchar.h]) AC_CHECK_HEADERS([sys/inttypes.h]) AC_CHECK_HEADERS([sys/io.h]) AC_CHECK_HEADERS([sys/param.h]) # Required to make the sys/user.h check work correctly on FreeBSD AC_CHECK_HEADERS([sys/sysinfo.h]) AC_CHECK_HEADERS([sys/types.h]) AC_CHECK_HEADERS([sys/user.h], [], [], [ #ifdef HAVE_SYS_PARAM_H # include #endif ]) AC_CHECK_HEADERS([sys/vfs.h]) AC_CHECK_HEADERS([syslimits.h]) # On Freebsd, the unwind.h header file is available in the libunwind # package, but the necessary functions are only available if __GNU_SOURCE # is defined to enable "all" GCC extensions. if test "$os" = "freebsd"; then ac_cv_header_unwind_h="no" fi AC_CHECK_HEADERS([unwind.h]) AC_CHECK_HEADER( [wchar.h], [HAVE_WCHAR_H="yes"], [HAVE_WCHAR_H="no"]) if test "$os" = "linux"; then # Make sure kernel-headers package is installed. AC_CHECK_HEADER( [linux/unistd.h], [], [AC_MSG_ERROR(linux/unistd.h is not found. Please install kernel-headers/linux-userspace-headers/linux-libc-dev package.)]) fi if test "$enable_multimon" != "no"; then AC_CHECK_HEADER( [X11/extensions/panoramiXproto.h], [], [AC_MSG_ERROR( [panoramiXproto.h not found. Please configure without multimon (using --disable-multimon) or install the libXinerama devel package(s).])], [#include #include ]) fi ### ### Typdefs, structs, and compiler quarks. ### AC_HEADER_STDBOOL AC_C_CONST AC_TYPE_UID_T AC_C_INLINE AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_CHECK_MEMBERS([struct stat.st_rdev]) AC_HEADER_TIME AC_STRUCT_TM AC_C_VOLATILE ### ### Specific features and OS/arch flags / actions ### ### General flags / actions CFLAGS="$CFLAGS -Wall" CFLAGS="$CFLAGS -Werror" # -Wno-unknown-pragmas is due to gcc not understanding '#pragma ident' # in Xlib.h on OpenSolaris. # Glib2 keep changing mutex APIs so we also need to disable 'deprecated' # warnings for now (-Wno-deprecated-declarations). for TEST_CFLAG in -Wno-pointer-sign -Wno-unused-value -fno-strict-aliasing \ -Wno-unknown-pragmas -Wno-uninitialized -Wno-deprecated-declarations \ -Wno-unused-const-variable; do AC_MSG_CHECKING([for GCC flag $TEST_CFLAG]) ORIGINAL_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $TEST_CFLAG" NEW_CFLAG="" AC_TRY_COMPILE( [], [ return 0; ], [NEW_CFLAG=" $TEST_CFLAG" AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) CFLAGS="$ORIGINAL_CFLAGS$NEW_CFLAG" done CPPFLAGS="$CPPFLAGS -DVMX86_TOOLS" CPPFLAGS="$CPPFLAGS" # -fvisibility is used by "core service" plugins, but not required. ORIGINAL_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" AC_MSG_CHECKING([for GCC flag -fvisibility]) AC_TRY_COMPILE([], [return 0;], [PLUGIN_CPPFLAGS="-fvisibility=hidden -DGCC_EXPLICIT_EXPORT"; AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) CFLAGS="$ORIGINAL_CFLAGS" # Detect "unused-but-set-variable" gcc warning and disable it. ORIGINAL_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wno-unused-but-set-variable" AC_MSG_CHECKING([for GCC flag -Wno-unused-but-set-variable]) AC_TRY_COMPILE([], [return 0;], [ORIGINAL_CFLAGS="$ORIGINAL_CFLAGS -Wno-unused-but-set-variable"; AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) CFLAGS="$ORIGINAL_CFLAGS" BUILDDIR="`pwd`" INCLUDE_DIR="`cd $srcdir; pwd`/lib/include" BLD_INCLUDE_DIR="$BUILDDIR/lib/include" CPPFLAGS="-I$INCLUDE_DIR -I$BLD_INCLUDE_DIR $CPPFLAGS" ### ### Documentation. ### if test "$enable_docs" = "yes"; then AC_CHECK_PROG([have_doxygen], [doxygen], [yes], [no]) if test "$have_doxygen" = "no"; then AC_MSG_WARN([doxygen not found; API documentation will not be generated.]) else AC_PATH_PROG([DOT], [dot], []) if test "$DOT" = ""; then HAVE_DOT=NO else DOT=`dirname $DOT` HAVE_DOT=YES fi AC_SUBST([DOT]) AC_SUBST([HAVE_DOT]) AC_PATH_PROG([MSCGEN], [mscgen], [no]) if test "$MSCGEN" != "no"; then MSCGEN_DIR="`dirname $MSCGEN`" else MSCGEN_DIR= fi AC_SUBST([MSCGEN_DIR]) fi fi ### ### OS/arch-specific flags / actions ### MODULES="" MODULES_OS="$os" TARGET_OS="$os" MODULES_DIR="" if test "$os" = "linux"; then MODULES_DIR="$LINUXDIR/kernel/" CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64" CPPFLAGS="$CPPFLAGS -D_LARGEFILE64_SOURCE" CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=500" CPPFLAGS="$CPPFLAGS -D_BSD_SOURCE" CPPFLAGS="$CPPFLAGS -D_SVID_SOURCE" CPPFLAGS="$CPPFLAGS -D_DEFAULT_SOURCE" LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -lrt" # vmxnet is not supported for kernels 3.3.0 and newer if test "$osVersion" -lt 303000; then MODULES="$MODULES vmxnet" fi # See if we need vmhgfs module. Starting with 3.10.0 we use FUSE if test "$osVersion" -lt 310000; then MODULES="$MODULES vmhgfs" fi # See if we need vmci and vsock modules. Starting with 3.9 they made # their way into mainline kernel. if test "$osVersion" -lt 309000; then MODULES="$MODULES vmci vsock" fi if test "$osVersion" -lt 300000; then MODULES="$MODULES vmblock vmsync" fi if test "x$enable_resolutionkms" != "xno" && test "x$enable_vmwgfxctrl" != "xno"; then PKG_CHECK_MODULES( [LIBUDEV], libdrm libudev, [LIBUDEV_CFLAGS="$LIBUDEV_CFLAGS -DHAVE_LIBUDEV"; enable_vmwgfxctrl="yes"], [AC_MSG_WARN( [Missing libdrm or libudev. vmwgfxctrl will be disabled and the resolutionKMS plugin will search for them at run-time.]); enable_vmwgfxctrl="no" ]) enable_resolutionkms="yes" fi fi if test "$os" = "freebsd" || test "$os" = "kfreebsd-gnu"; then LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -lkvm" MODULES_DIR="/boot/modules" if test "$osVersion" -ge 302000; then MODULES="$MODULES vmmemctl" fi if test "$osVersion" -ge 600000; then MODULES="$MODULES vmblock" fi if test "$with_kernel_modules" = "yes"; then echo "****************************************************************" echo " You are building FreeBSD kernel modules. Make sure you use " echo " 'make' to build open-vm-tools, and not GNU make ('gmake'). " echo "****************************************************************" fi fi if test "$os" = "solaris"; then LIB_IMPERSONATE_CPPFLAGS="$LIB_IMPERSONATE_CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" LIB_USER_CPPFLAGS="$LIB_USER_CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -lsocket" LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -lnsl" LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -lresolv" LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -lrpcsvc" LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -lrt" # Setup defines to identify the OS version. if test "$osVersion" -eq 509000; then CPPFLAGS="$CPPFLAGS -DSOL9" fi if test "$osVersion" -eq 510000; then CPPFLAGS="$CPPFLAGS -DSOL10" fi if test "$osVersion" -eq 511000; then CPPFLAGS="$CPPFLAGS -DSOL11" fi MODULES="$MODULES vmxnet vmmemctl" # HGFS and vmblock need Solaris 10 at least. if test "$osVersion" -ge 510000; then MODULES="$MODULES vmhgfs vmblock" fi # vmxnet3 is built on Solaris 10 / 11 only if GLDv3 is installed. if test "$osVersion" -gt 510000; then AC_CHECK_HEADER( [sys/mac.h], [MODULES="$MODULES vmxnet3"], [AC_MSG_WARN([GLDv3 (sys/mac.h) is not installed, vmxnet3 will not be compiled.])]) fi if test "$with_kernel_modules" = "yes"; then echo "****************************************************************" echo " You are building Solaris kernel modules. Make sure you use " echo " GNU make to build open-vm-tools. " echo "****************************************************************" fi fi if test "$os" = "linux"; then have_udev="yes" AC_ARG_WITH([udev-rules-dir], [AS_HELP_STRING([--with-udev-rules-dir=DIR], [where to install udev rules])], [UDEVRULESDIR="$withval"], [ UDEVRULESDIR="/lib/udev/rules.d" if test "$PKG_CONFIG" != "not_found"; then udevdir=$($PKG_CONFIG udev --variable=udevdir) if test "x$udevdir" != "x"; then UDEVRULESDIR="$udevdir/rules.d" fi fi ]) else have_udev="no" UDEVRULESDIR="" fi if test "x$enable_resolutionkms" = "xauto"; then enable_resolutionkms="no" fi if test "x$enable_resolutionkms" = "xyes"; then CPPFLAGS="$CPPFLAGS -DENABLE_RESOLUTIONKMS" fi if test "x$enable_vmwgfxctrl" = "xauto"; then enable_vmwgfxctrl="no" fi AM_CONDITIONAL(LINUX, test "$os" = "linux") AM_CONDITIONAL(SOLARIS, test "$os" = "solaris") AM_CONDITIONAL(FREEBSD, test "$os" = "freebsd" -o "$os" = "kfreebsd-gnu") AM_CONDITIONAL(FREEBSD_CUSTOM_SYSDIR, test \( "$os" = "freebsd" -o "$os" = "kfreebsd-gnu" \) -a -n "$SYSDIR") AM_CONDITIONAL(ARCH_X32, test "$arch" = "x32") AM_CONDITIONAL(ARCH_X64, test "$arch" = "x64") AM_CONDITIONAL(ARCH_ARM64, test "$arch" = "arm64") AM_CONDITIONAL(HAVE_X11, test "$have_x" = "yes") AM_CONDITIONAL(HAVE_ICU, test "$with_icu" = "yes") AM_CONDITIONAL(WITH_KERNEL_MODULES, test "$with_kernel_modules" = "yes") AM_CONDITIONAL(HAVE_XSM, test "$have_xsm" = "yes") AM_CONDITIONAL(HAVE_XCOMPOSITE, test "$have_xcomposite" = "yes") AM_CONDITIONAL(ENABLE_TESTS, test "$have_cunit" = "yes") AM_CONDITIONAL(WITH_ROOT_PRIVILEGES, test "$with_root_privileges" = "yes") AM_CONDITIONAL(HAVE_DOXYGEN, test "$have_doxygen" = "yes") AM_CONDITIONAL(HAVE_FUSE, test "$have_fuse" = "yes" || test "$have_fuse3" = "yes") AM_CONDITIONAL(HAVE_FUSE3, test "$have_fuse3" = "yes") AM_CONDITIONAL(HAVE_GNU_LD, test "$with_gnu_ld" = "yes") AM_CONDITIONAL(HAVE_GTKMM, test "$have_x" = "yes" -a \( "$with_gtkmm" = "yes" -o "$with_gtkmm3" = "yes" \) ) AM_CONDITIONAL(HAVE_PAM, test "$with_pam" = "yes") AM_CONDITIONAL(USE_SLASH_PROC, test "$os" = "linux") AM_CONDITIONAL(ENABLE_CONTAINERINFO, test "$enable_containerinfo" = "yes") AM_CONDITIONAL(ENABLE_DEPLOYPKG, test "$enable_deploypkg" = "yes") AM_CONDITIONAL(ENABLE_VGAUTH, test "$enable_vgauth" = "yes") AM_CONDITIONAL(HAVE_VSOCK, test "$os" = "linux") AM_CONDITIONAL(HAVE_MKDTEMP, test "$have_mkdtemp" = "yes") AM_CONDITIONAL(HAVE_UDEV, test "$have_udev" = "yes") AM_CONDITIONAL(ENABLE_RESOLUTIONKMS, test "x$enable_resolutionkms" = "xyes") AM_CONDITIONAL(ENABLE_VMWGFXCTRL, test "x$enable_vmwgfxctrl" = "xyes") AM_CONDITIONAL(VGAUTH_USE_CXX, test "$with_icu" = "yes") AM_CONDITIONAL(ENABLE_LIBAPPMONITOR, test "$enable_libappmonitor" = "yes") AM_CONDITIONAL(ENABLE_SDMP, test "$enable_servicediscovery" = "yes") AM_CONDITIONAL(ENABLE_SALTMINION, test "$enable_saltminion" = "yes" -a \( "$arch" = "x64" \) ) if test "$have_xsm" != "yes"; then AC_DEFINE([NO_XSM], 1, []) fi if test "$have_xcomposite" != "yes"; then AC_DEFINE([NO_XCOMPOSITE]) fi ### Feature-specific flags / actions # Combine where possible # If control reaches this point and multimon is still enabled, then we know # all of the tests for required components have passed and it's safe to allow # multimon. Otherwise, it should be disabled. if test "$enable_multimon" = "no"; then # XXX: For consistency, change this to ENABLE_MULTIMON. This will require # some additional code cleanup. AC_DEFINE([NO_MULTIMON], 1, [Define to 1 if building without multimon support.]) fi LIB_AUTH_CPPFLAGS="$LIB_AUTH_CPPFLAGS $PAM_CPPFLAGS" if test "$HAVE_CRYPT" = "yes"; then LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD -lcrypt" VIX_LIBADD="$VIX_LIBADD -lcrypt" fi LIBVMTOOLS_LIBADD="$LIBVMTOOLS_LIBADD $THREAD_LIBS" VIX_LIBADD="$VIX_LIBADD $THREAD_LIBS" ### Core Services definitions. HGFS_LIBS="$BUILDDIR/libhgfs/libhgfs.la" VMTOOLS_LIBS="$BUILDDIR/libvmtools/libvmtools.la $GLIB2_LIBS" VMTOOLS_CPPFLAGS="-DVMTOOLS_USE_GLIB $GLIB2_CPPFLAGS" PLUGIN_CPPFLAGS="$VMTOOLS_CPPFLAGS $PLUGIN_CPPFLAGS" PLUGIN_LDFLAGS="-Wl,-z,defs -Wl,-lc -Wl,--as-needed -shared -module -avoid-version" # Installation directories for core services plugins. TEST_PLUGIN_INSTALLDIR=$datadir/open-vm-tools/tests COMMON_PLUGIN_INSTALLDIR=$libdir/open-vm-tools/plugins/common VMSVC_PLUGIN_INSTALLDIR=$libdir/open-vm-tools/plugins/vmsvc VMUSR_PLUGIN_INSTALLDIR=$libdir/open-vm-tools/plugins/vmusr # General definitions INSTVMSG='$(SHELL) $(top_srcdir)/scripts/build/instvmsg.sh' RPCGEN_WRAPPER='$(SHELL) $(top_builddir)/scripts/build/rpcgen_wrapper.sh' ### General substs AC_SUBST([HGFS_LIBS]) AC_SUBST([TOOLS_VERSION]) AC_SUBST([TARGET_OS]) AC_SUBST([KERNEL_RELEASE]) AC_SUBST([LINUXINCLUDE]) AC_SUBST([MODULES_OS]) AC_SUBST([MODULES_DIR]) AC_SUBST([MODULES]) AC_SUBST([COMMON_XLIBS]) AC_SUBST([XSM_LIBS]) AC_SUBST([XCOMPOSITE_LIBS]) AC_SUBST([PAM_PREFIX]) AC_SUBST([PLUGIN_CPPFLAGS]) AC_SUBST([PLUGIN_LDFLAGS]) AC_SUBST([VMTOOLS_CPPFLAGS]) AC_SUBST([VMTOOLS_LIBS]) AC_SUBST([THREAD_LIBS]) AC_SUBST([RPCGENFLAGS]) AC_SUBST([XDR_LIBS]) AC_SUBST([XDR_CPPFLAGS]) AC_SUBST([TEST_PLUGIN_INSTALLDIR]) AC_SUBST([COMMON_PLUGIN_INSTALLDIR]) AC_SUBST([VMSVC_PLUGIN_INSTALLDIR]) AC_SUBST([VMUSR_PLUGIN_INSTALLDIR]) if test "$os" = "freebsd" -a -n "$SYSDIR"; then # If SYSDIR is not defined, AC_SUBST expands to nothing, so we need something # inside this block. true AC_SUBST([SYSDIR]) fi AC_SUBST([INSTVMSG]) AC_SUBST([RPCGEN_WRAPPER]) ### Lib substs AC_SUBST([LIB_AUTH_CPPFLAGS]) AC_SUBST([LIB_IMPERSONATE_CPPFLAGS]) AC_SUBST([LIB_USER_CPPFLAGS]) AC_SUBST([LIBVMTOOLS_LIBADD]) AC_SUBST([RESOLUTIONSET_LIBADD]) ### Program substs AC_SUBST([VIX_LIBADD]) AC_SUBST([VGAUTH_LIBADD]) AC_SUBST([UDEVRULESDIR]) ### ### Create the Makefiles ### AC_CONFIG_FILES([ \ Makefile \ lib/Makefile \ lib/auth/Makefile \ lib/backdoor/Makefile \ lib/asyncsocket/Makefile \ lib/sslDirect/Makefile \ lib/pollGtk/Makefile \ lib/poll/Makefile \ lib/dataMap/Makefile \ lib/hashMap/Makefile \ lib/dict/Makefile \ lib/dynxdr/Makefile \ lib/err/Makefile \ lib/file/Makefile \ lib/foundryMsg/Makefile \ lib/glibUtils/Makefile \ lib/globalConfig/Makefile \ lib/guestApp/Makefile \ lib/guestRpc/Makefile \ lib/guestStoreClientHelper/Makefile \ lib/hgfs/Makefile \ lib/hgfsBd/Makefile \ lib/hgfsHelper/Makefile \ lib/hgfsServer/Makefile \ lib/hgfsServerManagerGuest/Makefile \ lib/hgfsServerPolicyGuest/Makefile \ lib/hgfsUri/Makefile \ lib/impersonate/Makefile \ lib/lock/Makefile \ lib/message/Makefile \ lib/misc/Makefile \ lib/netUtil/Makefile \ lib/nicInfo/Makefile \ lib/panic/Makefile \ lib/panicDefault/Makefile \ lib/procMgr/Makefile \ lib/rpcChannel/Makefile \ lib/rpcIn/Makefile \ lib/rpcOut/Makefile \ lib/rpcVmx/Makefile \ lib/slashProc/Makefile \ lib/string/Makefile \ lib/jsmn/Makefile \ lib/stubs/Makefile \ lib/syncDriver/Makefile \ lib/system/Makefile \ lib/unicode/Makefile \ lib/user/Makefile \ lib/vmCheck/Makefile \ lib/vmSignal/Makefile \ lib/wiper/Makefile \ lib/xdg/Makefile \ services/Makefile \ services/vmtoolsd/Makefile \ services/plugins/Makefile \ services/plugins/gdp/Makefile \ services/plugins/appInfo/Makefile \ services/plugins/componentMgr/Makefile \ services/plugins/containerInfo/Makefile \ services/plugins/serviceDiscovery/Makefile \ services/plugins/desktopEvents/Makefile \ services/plugins/dndcp/Makefile \ services/plugins/guestInfo/Makefile \ services/plugins/guestStore/Makefile \ services/plugins/hgfsServer/Makefile \ services/plugins/powerOps/Makefile \ services/plugins/resolutionSet/Makefile \ services/plugins/resolutionKMS/Makefile \ services/plugins/timeSync/Makefile \ services/plugins/vix/Makefile \ services/plugins/vmbackup/Makefile \ services/plugins/deployPkg/Makefile \ vmware-user-suid-wrapper/Makefile \ toolbox/Makefile \ hgfsclient/Makefile \ checkvm/Makefile \ vmwgfxctrl/Makefile \ rpctool/Makefile \ vgauth/Makefile \ vgauth/lib/Makefile \ vgauthImport/Makefile \ namespacetool/Makefile \ vgauth/cli/Makefile \ vgauth/test/Makefile \ vgauth/service/Makefile \ libguestlib/Makefile \ libguestlib/vmguestlib.pc \ libDeployPkg/Makefile \ libDeployPkg/libDeployPkg.pc \ libhgfs/Makefile \ libguestStoreClient/Makefile \ libvmtools/Makefile \ xferlogs/Makefile \ modules/Makefile \ vmblock-fuse/Makefile \ vmhgfs-fuse/Makefile \ vmblockmounter/Makefile \ tests/Makefile \ tests/vmrpcdbg/Makefile \ tests/testDebug/Makefile \ tests/testPlugin/Makefile \ tests/testVmblock/Makefile \ docs/Makefile \ docs/api/Makefile \ scripts/Makefile \ scripts/build/rpcgen_wrapper.sh \ udev/Makefile \ libappmonitor/Makefile \ libappmonitor/appmonitor.pc \ ]) ### ### Output ### AC_OUTPUT open-vm-tools-stable-12.5.0/open-vm-tools/docs/000077500000000000000000000000001470176644300212515ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/docs/Makefile.am000066400000000000000000000016651470176644300233150ustar00rootroot00000000000000################################################################################ ### Copyright (c) 2009-2016, 2023 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ SUBDIRS = if HAVE_DOXYGEN SUBDIRS += api endif open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/000077500000000000000000000000001470176644300220225ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/Makefile.am000066400000000000000000000053711470176644300240640ustar00rootroot00000000000000################################################################################ ### Copyright (c) 2009-2016,2022-2023 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ DOXYGEN_INPUT = DOXYGEN_INPUT += $(top_srcdir)/docs/api DOXYGEN_INPUT += $(top_srcdir)/docs/api/services DOXYGEN_INPUT += $(top_srcdir)/lib/include/vmware/tools DOXYGEN_INPUT += $(top_srcdir)/libvmtools DOXYGEN_INPUT += $(top_srcdir)/tests/vmrpcdbg DOXYGEN_CPP_PREDEFINED = DOXYGEN_CPP_PREDEFINED += G_LOCK_DEFINE_STATIC(x) DOXYGEN_CPP_PREDEFINED += G_LOG_DOMAIN= DOXYGEN_CPP_EXPAND = DOXYGEN_EXTRA_PATTERNS = DOXYGEN_EXTRA_PATTERNS += *.c DOXYGEN_EXTRA_PATTERNS += *.doxy DOXYGEN_EXTRA_PATTERNS += *.h DOXYGEN_EXTRA_PATTERNS += *.txt # This rule has no dependencies, so it's executed every time. Not optimal, # but generation of the docs is pretty quick, and having the right dependencies # here is very non-trivial. build/index.html: mkdir -p build sed \ -e 's,##{BUILD_DIR}##,$(top_builddir),' \ -e 's,##{BUILD_OUTPUT}##,build,' \ -e 's,##{CLIENT_ROOT}##,$(top_srcdir),' \ -e 's,##{CPP_EXPAND}##,$(DOXYGEN_CPP_EXPAND),' \ -e 's,##{CPP_PREDEFINED}##,$(DOXYGEN_CPP_PREDEFINED),' \ -e 's,##{DOT}##,@DOT@,' \ -e 's,##{FILE_PATTERNS}##,$(DOXYGEN_EXTRA_PATTERNS),' \ -e 's,##{HAVE_DOT}##,@HAVE_DOT@,' \ -e 's,##{INCLUDE_PATHS}##,$(top_srcdir)/lib/include,' \ -e 's,##{INPUT_PATHS}##,$(DOXYGEN_INPUT),' \ -e 's,##{MSCGEN_DIR}##,@MSCGEN_DIR@,' \ -e 's,##{PERL}##,,' \ -e 's,##{PROJECT_NAME}##,@PACKAGE_STRING@,' \ -e 's,##{PROJECT_VERSION}##,@TOOLS_VERSION@,' \ -e 's,##{WARNING_LOG}##,warnings.log,' \ $(top_srcdir)/docs/api/doxygen.conf > doxygen.parsed.conf doxygen doxygen.parsed.conf > /dev/null all-local: build/index.html install-data-local: mkdir -p $(DESTDIR)$(docdir)/api cp -r build/* $(DESTDIR)$(docdir)/api open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/doxygen.conf000066400000000000000000000111561470176644300243520ustar00rootroot00000000000000### ### profile-api.conf - "Public API" Doxygen profile. Includes only non-static ### functions and non-internal documentation. ### #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = "##{PROJECT_NAME}##" PROJECT_NUMBER = "##{PROJECT_VERSION}##" OUTPUT_DIRECTORY = ##{BUILD_OUTPUT}## TAB_SIZE = 3 OPTIMIZE_OUTPUT_FOR_C = YES FULL_PATH_NAMES = YES STRIP_FROM_PATH = ##{CLIENT_ROOT}## #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_LOCAL_CLASSES = NO #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = ##{WARNING_LOG}## #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ##{INPUT_PATHS}## FILE_PATTERNS = ##{FILE_PATTERNS}## #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES INCLUDE_PATH = ##{INCLUDE_PATHS}## PREDEFINED = ##{CPP_PREDEFINED}## EXPAND_AS_DEFINED = ##{CPP_EXPAND}## #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = ##{PERL}## #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = ##{MSCGEN_DIR}## HIDE_UNDOC_RELATIONS = YES HAVE_DOT = ##{HAVE_DOT}## CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = ##{DOT}## DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = NO #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/services/000077500000000000000000000000001470176644300236455ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/services/debug.txt000066400000000000000000000057611470176644300255050ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2016 VMware, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *********************************************************/ /** @defgroup vmtools_debug Debugging Tools Plugins @brief Defines functions and interfaces for debugging Tools plugins. This module provides functions for writing "debug plugins" - plugins which provide functionality for driving the Tools Services when they're running in "debug mode". Debug plugins are dynamically loaded by providing specific command-line options to the Tools service process. @section vmtools_debug_how How debug plugins work Currently, there's only support for GuestRPC-based debug plugins. The debug library implements an RPC channel that can be driven by a debug plugin, according to information provided by the plugin at load time. The debug plugin can provide two types of information: - RPCs to be sent to the application: these are input to the application, and can be tied to a validation function to make sure the response from the application is correct. - Validation functions for "outgoing" RPCs: these are functions called in response to RPCs initiated by the applications; they can be mapped to specific RPC command strings, to make writing the plugin easier. For more details, check the RpcDebugPlugin data structure. Plugins that depend on events that are not only responses to RPC messages (such as timer-based outgoing RPCs) should make sure they tell the library that it should not stop running by incrementing its ref count (see RpcDebug_IncRef()). When the test is complete, the code can then call RpcDebug_DecRef() and, when the ref count reaches zero, the main application loop will be stopped. */ open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/services/guestrpc.txt000066400000000000000000000031111470176644300262360ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2016 VMware, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *********************************************************/ /** @defgroup vmtools_guestrpc GuestRPC functions @brief Functions related to reading and writing data on a GuestRPC channel. */ open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/services/main.doxy000066400000000000000000000040011470176644300254710ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2011-2016 VMware, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *********************************************************/ /** @mainpage VMware Tools Core API The Tools Core API provides functionality for extending Tools by building plugins, and loading them as part of the existing Tools services or by creating new plugin containers. @section tc_main_plugins Basic Plugin Functionality - @ref vmtools_plugins - @ref vmtools_guestrpc - @ref vmtools_vmcf @section tc_main_utils Miscelaneous Utilities - @ref vmtools_utils - @ref vmtools_logging - @ref vmtools_threads - @ref vmtools_i18n @section tc_main_debug Debugging Support - @ref vmtools_debug */ open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/services/plugins.txt000066400000000000000000000041401470176644300260660ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2016 VMware, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *********************************************************/ /** @defgroup vmtools_plugins VMware Tools Plugins @brief Defines the API used by the Tools Services for dynamically loading plugins. Plugins are dynamically loaded into the Tools service process, and may provide applications that hook into the functionality provided by the service, such as the glib main loop and the GuestRPC channel. Plugins that want to remain loaded by the service should always return registration data when their registration function (ToolsPluginOnLoad()) is called. The registration data, defined by the ToolsPluginData data structure, provides information about what events the plugin is interested in (for example, incoming RPCs). */ open-vm-tools-stable-12.5.0/open-vm-tools/docs/api/services/utils.txt000066400000000000000000000000001470176644300255340ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/hgfsclient/000077500000000000000000000000001470176644300224475ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/hgfsclient/COPYING000066400000000000000000000634711470176644300235150ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! open-vm-tools-stable-12.5.0/open-vm-tools/hgfsclient/Makefile.am000066400000000000000000000030671470176644300245110ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ bin_PROGRAMS = vmware-hgfsclient vmware_hgfsclient_LDADD = vmware_hgfsclient_LDADD += ../lib/hgfsBd/libHgfsBd.la vmware_hgfsclient_LDADD += @VMTOOLS_LIBS@ vmware_hgfsclient_LDADD += @HGFS_LIBS@ vmware_hgfsclient_CPPFLAGS = vmware_hgfsclient_CPPFLAGS += @VMTOOLS_CPPFLAGS@ vmware_hgfsclient_SOURCES = vmware_hgfsclient_SOURCES += hgfsclient.c if HAVE_ICU vmware_hgfsclient_LDADD += @ICU_LIBS@ vmware_hgfsclient_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXX) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ else vmware_hgfsclient_LINK = $(LINK) endif open-vm-tools-stable-12.5.0/open-vm-tools/hgfsclient/hgfsclient.c000066400000000000000000000256341470176644300247530ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2006-2019,2021,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsclient.c -- * * Userspace HGFS client. Will one day be as full featured as an HGFS * filesystem driver. * */ #define G_LOG_DOMAIN "hgfsClient" #include "vmware.h" #include "guestApp.h" #include "vmcheck.h" #include "hgfsEscape.h" #include "hgfs.h" #include "hgfsBd.h" #include "hgfsProto.h" #include "conf.h" #include "str.h" #include "vmware/tools/log.h" #include "vmware/tools/utils.h" #ifdef _WIN32 #include "vmware/tools/win32util.h" #endif #include "hgfsclient_version.h" #include "vm_version.h" #include "embed_version.h" VM_EMBED_VERSION(HGFSCLIENT_VERSION_STRING); #include #include #include #include #include RpcOut *gChannel = NULL; char *gPacketBuffer = NULL; static Bool HgfsClient_Open(HgfsHandle *rootHandle); static HgfsFileName *HgfsClient_Read(HgfsHandle rootHandle, int offset); static Bool HgfsClient_Close(HgfsHandle rootHandle); static Bool HgfsClient_PrintShares(void); static Bool HgfsClient_Init(void); static Bool HgfsClient_Cleanup(void); /* *----------------------------------------------------------------------------- * * HgfsClient_Open -- * * Open the root directory on the host. * * Results: * TRUE on success. FALSE otherwise. When TRUE, the root directory handle * is returned as an argument. * * Side effects: * The host has cached an open search for us. * *----------------------------------------------------------------------------- */ static Bool HgfsClient_Open(HgfsHandle *rootHandle) // OUT: Handle to root directory { Bool success = FALSE; HgfsRequestSearchOpen *searchOpenReq; HgfsReplySearchOpen *searchOpenRep = NULL; int err; char const *replyPacket; size_t packetSize; /* Create a SearchOpen and send it. */ searchOpenReq = (HgfsRequestSearchOpen *)gPacketBuffer; memset(searchOpenReq, 0, sizeof *searchOpenReq); searchOpenReq->header.id = 0; searchOpenReq->header.op = HGFS_OP_SEARCH_OPEN; searchOpenReq->dirName.length = 0; searchOpenReq->dirName.name[0] = 0; packetSize = sizeof *searchOpenReq; err = HgfsBd_Dispatch(gChannel, (char *)searchOpenReq, &packetSize, &replyPacket); if (err != 0) { Warning("Failed to send search open request.\n"); goto out; } /* replyPacket has our search handle. */ searchOpenRep = (HgfsReplySearchOpen *)replyPacket; if (searchOpenRep->header.status != HGFS_STATUS_SUCCESS) { Warning("Error in opening root directory.\n"); goto out; } success = TRUE; out: /* We got the root handle. */ if (success) { *rootHandle = searchOpenRep->search; } return success; } /* *----------------------------------------------------------------------------- * * HgfsClient_Read -- * * Read a share name from the host. * * Results: * Pointer into the packet buffer where the caller can find the * HgfsFileName struct. Since this is a pointer into the global * packet buffer, the caller should not free it. * * NULL if there was an error. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static HgfsFileName * HgfsClient_Read(HgfsHandle rootHandle, // IN: Handle to root directory int offset) // IN: Offset of dirent to read { HgfsFileName *shareName = NULL; HgfsRequestSearchRead *searchReadReq; HgfsReplySearchRead *searchReadRep; int err; char const *replyPacket; size_t packetSize; /* Create searchRead and send it. */ searchReadReq = (HgfsRequestSearchRead *)gPacketBuffer; memset(searchReadReq, 0, sizeof *searchReadReq); searchReadReq->header.id = 0; searchReadReq->header.op = HGFS_OP_SEARCH_READ; searchReadReq->search = rootHandle; searchReadReq->offset = offset; packetSize = sizeof *searchReadReq; err = HgfsBd_Dispatch(gChannel, (char *)searchReadReq, &packetSize, &replyPacket); if (err != 0) { Warning("Failed to send search read request.\n"); goto out; } /* replyPacket has our share name. */ searchReadRep = (HgfsReplySearchRead *)replyPacket; if (searchReadRep->header.status != HGFS_STATUS_SUCCESS) { Warning("Error in getting share name.\n"); goto out; } /* We got the share name. */ shareName = &searchReadRep->fileName; out: return shareName; } /* *----------------------------------------------------------------------------- * * HgfsClient_Close -- * * Closes the root directory on the host. * * Results: * TRUE on success, FALSE otherwise. * * Side effects: * Host releases state on our opened search. * *----------------------------------------------------------------------------- */ static Bool HgfsClient_Close(HgfsHandle rootHandle) // IN: Handle to root directory { HgfsRequestSearchClose *searchCloseReq; HgfsReplySearchClose *searchCloseRep; int err; char const *replyPacket; size_t packetSize; /* Create a SearchClose and send it. */ searchCloseReq = (HgfsRequestSearchClose *)gPacketBuffer; memset(searchCloseReq, 0, sizeof *searchCloseReq); searchCloseReq->header.id = 0; searchCloseReq->header.op = HGFS_OP_SEARCH_CLOSE; searchCloseReq->search = rootHandle; packetSize = sizeof *searchCloseReq; err = HgfsBd_Dispatch(gChannel, (char *)searchCloseReq, &packetSize, &replyPacket); if (err != 0) { Warning("Failed to send search close request.\n"); return FALSE; } /* replyPacket has success/failure. */ searchCloseRep = (HgfsReplySearchClose *)replyPacket; if (searchCloseRep->header.status != HGFS_STATUS_SUCCESS) { Warning("Error closing root directory.\n"); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsClient_PrintShares -- * * List all the shares available on the host. * * Results: * TRUE if successful, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsClient_PrintShares(void) { Bool success = FALSE; int offset = 0; char escapedName[PATH_MAX + 1]; HgfsHandle rootHandle; if (!HgfsClient_Open(&rootHandle)) { return success; } while (TRUE) { HgfsFileName *fileName = HgfsClient_Read(rootHandle, offset++); if (fileName == NULL) { break; } /* Are we done? */ if (fileName->length == 0) { success = TRUE; break; } /* * Escape this filename. If we get back a negative result, it means that * the escaped filename is too big, so skip this share. */ if (HgfsEscape_Do(fileName->name, fileName->length, sizeof escapedName, escapedName) < 0) { continue; } /* Skip "." and ".." which can be returned. */ if (strcmp(".", escapedName) == 0 || strcmp("..", escapedName) == 0) { continue; } printf("%s\n", escapedName); } if (!HgfsClient_Close(rootHandle)) { success = FALSE; } return success; } /* *----------------------------------------------------------------------------- * * HgfsClient_Init -- * * Do some initialization "stuff". * * Results: * TRUE if initialization succeeded, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsClient_Init(void) { Bool success = FALSE; GKeyFile *conf = NULL; VMTools_LoadConfig(NULL, G_KEY_FILE_NONE, &conf, NULL); VMTools_ConfigLogging("hgfsclient", conf, FALSE, FALSE); if (conf != NULL) { g_key_file_free(conf); conf = NULL; } if (!VmCheck_IsVirtualWorld()) { Warning("This application must be run in a Virtual Machine.\n"); goto out; } /* Setup an HGFS channel and packet buffer. */ gChannel = HgfsBd_GetChannel(); if (gChannel == NULL) { Warning("Failed to create RPC channel\n"); goto out; } gPacketBuffer = HgfsBd_GetBuf(); if (gPacketBuffer == NULL) { Warning("Failed to create packet buffer\n"); goto out; } /* Find out if HGFS is enabled in the VMX. */ if (!HgfsBd_Enabled(gChannel, gPacketBuffer)) { Warning("HGFS is disabled in the host\n"); goto out; } success = TRUE; out: if (!success) { HgfsClient_Cleanup(); } return success; } /* *----------------------------------------------------------------------------- * * HgfsClient_Cleanup -- * * Do some cleanup crap. * * Results: * TRUE if cleanup succeeded, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsClient_Cleanup(void) { Bool success = TRUE; if (gPacketBuffer != NULL) { HgfsBd_PutBuf(gPacketBuffer); } if (gChannel != NULL) { if (!HgfsBd_CloseChannel(gChannel)) { Warning("Failed to close RPC channel\n"); success = FALSE; } } return success; } /* *----------------------------------------------------------------------------- * * main -- * * Main entry point. Calls into the host's HGFS server and prints out * a list of the available shares. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ int main(int argc, // IN char *argv[]) // IN { #ifdef _WIN32 WinUtil_EnableSafePathSearching(TRUE); # if defined(VMX86_RELEASE) WinUtil_VerifyExePathW(); # endif #endif if (argc == 2 && (!strncmp(argv[1], "-h", 2) || !strncmp(argv[1], "--help", 6))) { fprintf(stderr, "hgfsclient: lists any shared folders.\n"); return 0; } if (!HgfsClient_Init()) { return EXIT_FAILURE; } if (!HgfsClient_PrintShares()) { return EXIT_FAILURE; } if (!HgfsClient_Cleanup()) { return EXIT_FAILURE; } return EXIT_SUCCESS; } open-vm-tools-stable-12.5.0/open-vm-tools/hgfsclient/hgfsclient_version.h000066400000000000000000000030551470176644300265160ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsclient_version.h -- * * Version definitions for the HGFS userspace client application. */ #ifndef _HGFSCLIENT_VERSION_H_ #define _HGFSCLIENT_VERSION_H_ /* * This component's version is coupled with Tools versioning. The effect * is that the version increments with each build, and with each Tools * version bump. If and when it becomes necessary to version the component * manually, make sure that the version is bumped any time the component or * its dependencies are changed. */ #include "vm_tools_version.h" #define HGFSCLIENT_VERSION_COMMAS TOOLS_VERSION_EXT_CURRENT_CSV #define HGFSCLIENT_VERSION_STRING TOOLS_VERSION_EXT_CURRENT_STR #endif /* _HGFSCLIENT_VERSION_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/000077500000000000000000000000001470176644300210675ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/COPYING000066400000000000000000000634711470176644300221350ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! open-vm-tools-stable-12.5.0/open-vm-tools/lib/Makefile.am000066400000000000000000000040361470176644300231260ustar00rootroot00000000000000################################################################################ ### Copyright (c) 2007-2024 Broadcom. All Rights Reserved. ### Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc. ### and/or its subsidiaries. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ SUBDIRS = SUBDIRS += guestRpc SUBDIRS += auth SUBDIRS += backdoor if HAVE_VSOCK SUBDIRS += asyncsocket endif SUBDIRS += sslDirect SUBDIRS += pollGtk SUBDIRS += poll SUBDIRS += dataMap SUBDIRS += hashMap SUBDIRS += dict SUBDIRS += dynxdr SUBDIRS += err SUBDIRS += file SUBDIRS += foundryMsg SUBDIRS += glibUtils SUBDIRS += guestApp if LINUX SUBDIRS += guestStoreClientHelper SUBDIRS += globalConfig endif SUBDIRS += hgfs SUBDIRS += hgfsBd SUBDIRS += hgfsHelper SUBDIRS += hgfsServer SUBDIRS += hgfsServerManagerGuest SUBDIRS += hgfsServerPolicyGuest if HAVE_GTKMM SUBDIRS += hgfsUri endif SUBDIRS += impersonate SUBDIRS += lock SUBDIRS += message SUBDIRS += misc SUBDIRS += netUtil SUBDIRS += nicInfo SUBDIRS += panic SUBDIRS += panicDefault SUBDIRS += procMgr SUBDIRS += rpcChannel SUBDIRS += rpcIn SUBDIRS += rpcOut SUBDIRS += rpcVmx if USE_SLASH_PROC SUBDIRS += slashProc endif SUBDIRS += string SUBDIRS += jsmn SUBDIRS += stubs SUBDIRS += syncDriver SUBDIRS += system SUBDIRS += unicode SUBDIRS += user SUBDIRS += vmCheck SUBDIRS += vmSignal SUBDIRS += wiper SUBDIRS += xdg open-vm-tools-stable-12.5.0/open-vm-tools/lib/asyncsocket/000077500000000000000000000000001470176644300234155ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/asyncsocket/Makefile.am000066400000000000000000000021731470176644300254540ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2013-2017 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libAsyncSocket.la libAsyncSocket_la_SOURCES = libAsyncSocket_la_SOURCES += asyncsocket.c libAsyncSocket_la_SOURCES += asyncSocketBase.c libAsyncSocket_la_SOURCES += asyncSocketInterface.c AM_CFLAGS = AM_CFLAGS += -DUSE_SSL_DIRECT open-vm-tools-stable-12.5.0/open-vm-tools/lib/asyncsocket/asyncSocketBase.c000066400000000000000000000553441470176644300266550ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2016-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * asyncSocketBase.c -- * * This exposes the public functions of the AsyncSocket library. * This file itself just contains stubs which call the function * pointers in the socket's virtual table. * */ #include "vmware.h" #include "asyncsocket.h" #include "asyncSocketBase.h" #include "msg.h" #include "log.h" #define LOGLEVEL_MODULE asyncsocket #include "loglevel_user.h" /* * A version of ASOCKLOG() which is safe to call from inside IncRef, * DecRef or any of the other functions which the regular ASOCKLOG() * implicitly calls. We don't log fd as that isn't available at the * base class level. */ /* gcc needs special syntax to handle zero-length variadic arguments */ #if defined(_MSC_VER) #define ASOCKLOG_NORECURSION(_level, _asock, fmt, ...) \ do { \ if (((_level) == 0) || DOLOG_BYNAME(asyncsocket, (_level))) { \ Log(ASOCKPREFIX "%d " fmt, (_asock)->id, __VA_ARGS__); \ } \ } while(0) #else #define ASOCKLOG_NORECURSION(_level, _asock, fmt, ...) \ do { \ if (((_level) == 0) || DOLOG_BYNAME(asyncsocket, (_level))) { \ Log(ASOCKPREFIX "%d " fmt, (_asock)->id, ##__VA_ARGS__); \ } \ } while(0) #endif /* *----------------------------------------------------------------------------- * * AsyncSocketInternalIncRef -- * * Increments reference count on AsyncSocket struct and optionally * takes the lock. This function is used to implement both Lock * and AddRef. * * Results: * New reference count. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void AsyncSocketInternalIncRef(AsyncSocket *asock, // IN Bool lock) // IN { if (lock && asock->pollParams.lock) { MXUser_AcquireRecLock(asock->pollParams.lock); } ASSERT(asock->refCount > 0); ++asock->refCount; } /* *----------------------------------------------------------------------------- * * AsyncSocketInternalDecRef -- * * Decrements reference count on AsyncSocket struct, freeing it when it * reaches 0. If "unlock" is TRUE, releases the lock after decrementing * the count. * * This function is used to implement both Unlock and DecRef. * * Results: * None. * * Side effects: * May free struct. * *----------------------------------------------------------------------------- */ static INLINE void AsyncSocketInternalDecRef(AsyncSocket *s, // IN Bool unlock) // IN { int count = --s->refCount; if (unlock && s->pollParams.lock) { MXUser_ReleaseRecLock(s->pollParams.lock); } ASSERT(count >= 0); if (UNLIKELY(count == 0)) { ASOCKLOG_NORECURSION(1, s, "Final release; freeing asock struct\n"); VT(s)->destroy(s); } else { ASOCKLOG_NORECURSION(1, s, "Release (count now %d)\n", count); } } /* *---------------------------------------------------------------------------- * * AsyncSocketLock -- * AsyncSocketUnlock -- * * Acquire/Release the lock provided by the client when creating the * AsyncSocket object. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ void AsyncSocketLock(AsyncSocket *asock) // IN: { AsyncSocketInternalIncRef(asock, TRUE); } void AsyncSocketUnlock(AsyncSocket *asock) // IN: { AsyncSocketInternalDecRef(asock, TRUE); } /* *---------------------------------------------------------------------------- * * AsyncSocketIsLocked -- * * If a lock is associated with the socket, check whether the calling * thread holds the lock. * * Results: * TRUE if calling thread holds the lock, or if there is no assoicated * lock. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool AsyncSocketIsLocked(AsyncSocket *asock) // IN: { if (asock->pollParams.lock && Poll_LockingEnabled()) { return MXUser_IsCurThreadHoldingRecLock(asock->pollParams.lock); } return TRUE; } /* *----------------------------------------------------------------------------- * * AsyncSocketAddRef -- * * Increments reference count on AsyncSocket struct. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void AsyncSocketAddRef(AsyncSocket *s) // IN { AsyncSocketInternalIncRef(s, FALSE); } /* *----------------------------------------------------------------------------- * * AsyncSocketRelease -- * * Decrements reference count on AsyncSocket struct, freeing it when it * reaches 0. If "unlock" is TRUE, releases the lock after decrementing * the count. * * Results: * None. * * Side effects: * May free struct. * *----------------------------------------------------------------------------- */ void AsyncSocketRelease(AsyncSocket *s) // IN: { AsyncSocketInternalDecRef(s, FALSE); } /* *---------------------------------------------------------------------------- * * AsyncSocketGetState -- * * Accessor function for the state in the base class. * *---------------------------------------------------------------------------- */ AsyncSocketState AsyncSocketGetState(AsyncSocket *asock) // IN { ASSERT(AsyncSocketIsLocked(asock)); return asock->state; } /* *---------------------------------------------------------------------------- * * AsyncSocketSetState -- * * Modifier function for the state in the base class. * *---------------------------------------------------------------------------- */ void AsyncSocketSetState(AsyncSocket *asock, // IN/OUT AsyncSocketState state) // IN { asock->state = state; } /* *----------------------------------------------------------------------------- * * AsyncSocketGetPollParams -- * * Accessor function for the pollParams struct in the base socket. * *----------------------------------------------------------------------------- */ AsyncSocketPollParams * AsyncSocketGetPollParams(AsyncSocket *s) // IN { return &s->pollParams; } /* *----------------------------------------------------------------------------- * * AsyncSocketInitSocket -- * * Initialize the AsyncSocket base struct. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void AsyncSocketInitSocket(AsyncSocket *s, // IN/OUT AsyncSocketPollParams *pollParams, // IN const AsyncSocketVTable *vtable) // IN { /* * The sockets each have a "unique" ID, which is just an * incrementing integer. */ static Atomic_uint32 nextid = { 1 }; s->id = Atomic_ReadInc32(&nextid); s->refCount = 1; s->vt = vtable; s->inited = TRUE; if (pollParams) { s->pollParams = *pollParams; } else { s->pollParams.pollClass = POLL_CS_MAIN; s->pollParams.flags = 0; s->pollParams.lock = NULL; s->pollParams.iPoll = NULL; } } /* *----------------------------------------------------------------------------- * * AsyncSocketTeardownSocket -- * * Tear down the AsyncSocket base struct. Currently this just * clears the inited flag and releases the initial (user) refcount. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void AsyncSocketTeardownSocket(AsyncSocket *asock) // IN/OUT { /* * Release the initial refcount created when we initialize the * socket struct. */ ASSERT(AsyncSocketIsLocked(asock)); ASSERT(asock->refCount >= 1); ASSERT(asock->inited); asock->inited = FALSE; AsyncSocketRelease(asock); } /* *---------------------------------------------------------------------------- * * AsyncSocket_Init -- * * Initialize the various socket subsytems. Currently just TCP, this * will expand. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * See subsystems. * *---------------------------------------------------------------------------- */ int AsyncSocket_Init(void) { return AsyncTCPSocket_Init(); } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetID -- * * Returns a unique identifier for the asock. * * Results: * Integer id or ASOCKERR_INVAL. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_GetID(AsyncSocket *asock) // IN { if (!asock) { return ASOCKERR_INVAL; /* For some reason we return ID 5 for null pointers! */ } else { return asock->id; } } /* *---------------------------------------------------------------------------- * * AsyncSocket_SetErrorFn -- * * Sets the error handling function for the asock. The error function * is invoked automatically on I/O errors. This should be done * before an internal callback that may call the error handler can be * fired. This usually means doing so immediately after the asyncsocket * is created, either from the poll thread or with the asyncsocket lock * (passed in pollParams) held throughout both calls. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_INVAL. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_SetErrorFn(AsyncSocket *asock, // IN/OUT AsyncSocketErrorFn errorFn, // IN void *clientData) // IN { if (!asock) { return ASOCKERR_INVAL; } else { AsyncSocketLock(asock); asock->errorFn = errorFn; asock->errorClientData = clientData; AsyncSocketUnlock(asock); return ASOCKERR_SUCCESS; } } /* *---------------------------------------------------------------------------- * * AsyncSocketHandleError -- * * Internal error handling helper. Changes the socket's state to error, * and calls the registered error handler or closes the socket. * * Results: * None. * * Side effects: * Lots. * *---------------------------------------------------------------------------- */ void AsyncSocketHandleError(AsyncSocket *asock, // IN int asockErr) // IN { ASSERT(asock); asock->errorSeen = TRUE; if (asock->errorFn) { ASOCKLOG(3, asock, "firing error callback (%s)\n", AsyncSocket_Err2String(asockErr)); asock->errorFn(asockErr, asock, asock->errorClientData); } else { ASOCKLOG(3, asock, "no error callback, closing socket (%s)\n", AsyncSocket_Err2String(asockErr)); AsyncSocket_Close(asock); } } /* *---------------------------------------------------------------------------- * * AsyncSocketCheckAndDispatchRecv -- * * Check if the recv buffer is full and dispatch the client callback. * * Handles the possibility that the client registers a new receive buffer * or closes the socket in their callback. * * Results: * TRUE if the socket was closed or the receive was cancelled, * FALSE if the caller should continue to try to receive data. * * Side effects: * Could fire recv completion or trigger socket destruction. * *---------------------------------------------------------------------------- */ Bool AsyncSocketCheckAndDispatchRecv(AsyncSocket *s, // IN int *result) // OUT { ASSERT(s); ASSERT(result); ASSERT(s->recvFn); ASSERT(s->recvBuf); ASSERT(s->recvLen > 0); ASSERT(s->recvPos > 0); ASSERT(s->recvPos <= s->recvLen); /* * The application may close the socket in this callback. This * asserts that even if that happens, the socket will not be * immediately freed in the middle of our function. */ ASSERT(s->refCount > 1); if (s->recvPos == s->recvLen || s->recvFireOnPartial) { void *recvBuf = s->recvBuf; ASOCKLOG(3, s, "recv buffer full, calling recvFn\n"); /* * We do this dance in case the handler frees the buffer (so * that there's no possible window where there are dangling * references here. Obviously if the handler frees the buffer, * but then fails to register a new one, we'll put back the * dangling reference in the automatic reset case below, but * there's currently a limit to how far we go to shield clients * who use our API in a broken way. */ s->recvBuf = NULL; s->recvFn(recvBuf, s->recvPos, s, s->recvClientData); if (s->state == AsyncSocketClosed) { ASOCKLG0(s, "owner closed connection in recv callback\n"); *result = ASOCKERR_CLOSED; return TRUE; } else if (s->recvFn == NULL && s->recvLen == 0) { /* * Further recv is cancelled from within the last recvFn, see * AsyncSocket_CancelRecv(). So exit from the loop. */ *result = ASOCKERR_SUCCESS; return TRUE; } else if (s->recvPos > 0) { /* * Automatically reset keeping the current handler. Checking * that recvPos is still non-zero implies that the * application has not called AsyncSocket_Recv or * _RecvPartial in the callback. */ s->recvPos = 0; s->recvBuf = recvBuf; *result = ASOCKERR_SUCCESS; return FALSE; } else { *result = ASOCKERR_SUCCESS; return FALSE; } } else { *result = ASOCKERR_SUCCESS; return FALSE; } } /* *---------------------------------------------------------------------------- * * AsyncSocketSetRecvBuf -- * * Helper function to validate socket state and recvBuf * parameters before setting the recvBuf values in the base * class. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_*. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocketSetRecvBuf(AsyncSocket *asock, // IN: void *buf, // IN: int len, // IN: Bool fireOnPartial, // IN: void *cb, // IN: void *cbData) // IN: { ASSERT(AsyncSocketIsLocked(asock)); if (!asock->errorFn) { ASOCKWARN(asock, "%s: no registered error handler!\n", __FUNCTION__); return ASOCKERR_INVAL; } if (!buf || !cb || len <= 0) { ASOCKWARN(asock, "Recv called with invalid arguments!\n"); return ASOCKERR_INVAL; } if (AsyncSocketGetState(asock) != AsyncSocketConnected && AsyncSocketGetState(asock) != AsyncSocketConnectedRdOnly) { ASOCKWARN(asock, "recv called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } if (asock->recvBuf && asock->recvPos != 0) { ASOCKWARN(asock, "Recv called -- partially read buffer discarded.\n"); } asock->recvBuf = buf; asock->recvLen = len; asock->recvFireOnPartial = fireOnPartial; asock->recvFn = cb; asock->recvClientData = cbData; asock->recvPos = 0; return ASOCKERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * AsyncSocketCancelRecv -- * * Call this function if you know what you are doing. This should * be called if you want to synchronously receive the outstanding * data on the socket. It returns number of partially read bytes * (if any). A partially read response may exist as * AsyncSocketRecvCallback calls the recv callback only when all * the data has been received. * * Results: * None * * Side effects: * Subsequent client call to AsyncSocket_Recv can reinstate async behaviour. * *----------------------------------------------------------------------------- */ void AsyncSocketCancelRecv(AsyncSocket *asock, // IN int *partialRecvd, // OUT void **recvBuf, // OUT void **recvFn) // IN { if (partialRecvd) { *partialRecvd = asock->recvPos; } if (recvFn) { *recvFn = asock->recvFn; } if (recvBuf) { *recvBuf = asock->recvBuf; } asock->recvBuf = NULL; asock->recvFn = NULL; asock->recvPos = 0; asock->recvLen = 0; } /* *---------------------------------------------------------------------------- * * AsyncSocket_Err2String -- * * Returns the error string associated with error code. * * Results: * Error string. * * Side effects: * None. * *---------------------------------------------------------------------------- */ const char * AsyncSocket_Err2String(int err) // IN { return Msg_StripMSGID(AsyncSocket_MsgError(err)); } /* *---------------------------------------------------------------------------- * * AsyncSocket_MsgError -- * * Returns the message associated with error code. * * Results: * Message string. * * Side effects: * None. * *---------------------------------------------------------------------------- */ const char * AsyncSocket_MsgError(int asyncSockError) // IN { const char *result = NULL; switch (asyncSockError) { case ASOCKERR_SUCCESS: result = MSGID(asyncsocket.success) "Success"; break; case ASOCKERR_GENERIC: result = MSGID(asyncsocket.generic) "Asyncsocket error"; break; case ASOCKERR_INVAL: result = MSGID(asyncsocket.invalid) "Invalid parameters"; break; case ASOCKERR_TIMEOUT: result = MSGID(asyncsocket.timeout) "Time-out error"; break; case ASOCKERR_NOTCONNECTED: result = MSGID(asyncsocket.notconnected) "Local socket not connected"; break; case ASOCKERR_REMOTE_DISCONNECT: result = MSGID(asyncsocket.remotedisconnect) "Remote disconnected"; break; case ASOCKERR_CLOSED: result = MSGID(asyncsocket.closed) "Closed socket"; break; case ASOCKERR_CONNECT: result = MSGID(asyncsocket.connect) "Connection error"; break; case ASOCKERR_POLL: result = MSGID(asyncsocket.poll) "Poll registration error"; break; case ASOCKERR_BIND: result = MSGID(asyncsocket.bind) "Socket bind error"; break; case ASOCKERR_BINDADDRINUSE: result = MSGID(asyncsocket.bindaddrinuse) "Socket bind address already in use"; break; case ASOCKERR_LISTEN: result = MSGID(asyncsocket.listen) "Socket listen error"; break; case ASOCKERR_CONNECTSSL: result = MSGID(asyncsocket.connectssl) "Connection error: could not negotiate SSL"; break; case ASOCKERR_NETUNREACH: result = MSGID(asyncsocket.netunreach) "Network unreachable"; break; case ASOCKERR_ADDRUNRESV: result = MSGID(asyncsocket.addrunresv) "Address unresolvable"; break; case ASOCKERR_BUSY: result = MSGID(asyncsocket.busy) "Concurrent operations on socket"; break; case ASOCKERR_PROXY_NEEDS_AUTHENTICATION: result = MSGID(asyncsocket.proxyneedsauthentication) "Proxy needs authentication"; break; case ASOCKERR_PROXY_CONNECT_FAILED: result = MSGID(asyncsocket.proxyconnectfailed) "Connection failed through proxy"; break; case ASOCKERR_PROXY_INVALID_OR_NOT_SUPPORTED: result = MSGID(asyncsocket.proxyinvalidornotsupported) "Invalid or not supported type proxy"; break; case ASOCKERR_WEBSOCK_UPGRADE_NOT_FOUND: result = MSGID(asyncsocket.websocketupgradefailed) "Upgrade to websocket error: NOT FOUND, status code 404"; break; case ASOCKERR_WEBSOCK_TOO_MANY_CONNECTION: result = MSGID(asyncsocket.websockettoomanyconnection) "The server-side WebSocket connection limit has been exceeded," " HTTP status code 429"; break; } if (!result) { Warning("%s was passed bad code %d\n", __FUNCTION__, asyncSockError); result = MSGID(asyncsocket.unknown) "Unknown error"; } return result; } /** *----------------------------------------------------------------------------- * * stristr -- * * Do you know strstr from ? * So this one is the same, but without the case sensitivity. * * Results: * return a pointer to the first occurrence of needle in haystack, * or NULL if needle does not appear in haystack. If needle is zero * length, the function returns haystack. * * Side effects: * none * *----------------------------------------------------------------------------- */ const char * stristr(const char *haystack, // IN const char *needle) // IN { if (*needle) { int len = strlen(needle); for (; *haystack; haystack++) { if (strncasecmp(haystack, needle, len) == 0) { return haystack; } } return NULL; } else { return haystack; } } open-vm-tools-stable-12.5.0/open-vm-tools/lib/asyncsocket/asyncSocketBase.h000066400000000000000000000060721470176644300266540ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2011,2014-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #ifndef __ASYNC_SOCKET_BASE_H__ #define __ASYNC_SOCKET_BASE_H__ #ifdef USE_SSL_DIRECT #include "sslDirect.h" #else #include "ssl.h" #endif #include "asyncSocketVTable.h" /* * The abstract base class for all asyncsocket implementations. */ struct AsyncSocket { uint32 id; uint32 refCount; AsyncSocketPollParams pollParams; AsyncSocketState state; Bool inited; Bool errorSeen; AsyncSocketErrorFn errorFn; void *errorClientData; void *recvBuf; int recvPos; int recvLen; AsyncSocketRecvFn recvFn; void *recvClientData; Bool recvFireOnPartial; const AsyncSocketVTable *vt; }; void AsyncSocketInitSocket(AsyncSocket *asock, AsyncSocketPollParams *params, const AsyncSocketVTable *vtable); void AsyncSocketTeardownSocket(AsyncSocket *s); void AsyncSocketLock(AsyncSocket *asock); void AsyncSocketUnlock(AsyncSocket *asock); Bool AsyncSocketIsLocked(AsyncSocket *asock); void AsyncSocketAddRef(AsyncSocket *asock); void AsyncSocketRelease(AsyncSocket *s); AsyncSocketState AsyncSocketGetState(AsyncSocket *sock); void AsyncSocketSetState(AsyncSocket *sock, AsyncSocketState state); int AsyncSocketSetRecvBuf(AsyncSocket *asock, void *buf, int len, Bool fireOnPartial, void *cb, void *cbData); Bool AsyncSocketCheckAndDispatchRecv(AsyncSocket *s, int *result); AsyncSocketPollParams *AsyncSocketGetPollParams(AsyncSocket *s); void AsyncSocketHandleError(AsyncSocket *asock, int asockErr); void AsyncSocketCancelRecv(AsyncSocket *asock, int *partialRecvd, void **recvBuf, void **recvFn); int AsyncTCPSocket_Init(void); #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c000066400000000000000000001601621470176644300276760ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2016-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * asyncSocketInterface.c -- * * This exposes the public functions of the AsyncSocket library. * This file itself just contains stubs which call the function * pointers in the socket's virtual table. * * Which entrypoints are virtual and which are base functionality? * Guidelines: * - functions affecting the underlying transport (e.g. TCP timeouts) * are backend-specific and generally ARE virtualized. * - functions with an immediate effect (e.g. queue bytes for send) * generally ARE virtualized. * - functions affecting the socket abstraction (e.g. how it reports errors * to the caller) are basic functionality and generally are NOT virtualized. * - functions affecting state which is queried later (e.g. close behavior) * generally are NOT virtualized. */ #ifdef _WIN32 #include #else #include #include #include #endif #include "vmware.h" #include "asyncsocket.h" #include "asyncSocketBase.h" #include "msg.h" #include "log.h" #define LOGLEVEL_MODULE asyncsocket #include "loglevel_user.h" /* *---------------------------------------------------------------------------- * * AsyncSocket_SetCloseOptions -- * * Enables optional behavior for AsyncSocket_Close(): * * - If flushEnabledMaxWaitMsec is non-zero, the output stream * will be flushed synchronously before the socket is closed. * (default is zero: close socket right away without flushing) * * - If closeCb is set, the callback will be called asynchronously * when the socket is actually destroyed. * (default is NULL: no callback) * * Results: * ASOCKERR_SUCCESS or ASOCKERR_*. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_SetCloseOptions(AsyncSocket *asock, // IN int flushEnabledMaxWaitMsec, // IN AsyncSocketCloseFn closeCb) // IN { int ret; if (VALID(asock, setCloseOptions)) { AsyncSocketLock(asock); ret = VT(asock)->setCloseOptions(asock, flushEnabledMaxWaitMsec, closeCb); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetState -- * * Returns the state of the provided asock or ASOCKERR_INVAL. Note that * unless this is called from a callback function, the state should be * treated as transient (except the state AsyncSocketClosed). * * Results: * AsyncSocketState enum. * * Side effects: * None. * *---------------------------------------------------------------------------- */ AsyncSocketState AsyncSocket_GetState(AsyncSocket *asock) // IN { AsyncSocketState ret; if (VALID(asock, getState)) { AsyncSocketLock(asock); ret = VT(asock)->getState(asock); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetGenericErrno -- * * Used when an ASOCKERR_GENERIC is returned due to a system error. * The errno that was returned by the system is stored in the asock * struct and returned to the user in this function. * * XXX: This function is not thread-safe. The errno should be returned * in a parameter to any function that can return ASOCKERR_GENERIC. * * Results: * int error code * * Side effects: * None * *---------------------------------------------------------------------------- */ int AsyncSocket_GetGenericErrno(AsyncSocket *asock) // IN: { int ret; if (VALID(asock, getGenericErrno)) { AsyncSocketLock(asock); ret = VT(asock)->getGenericErrno(asock); AsyncSocketUnlock(asock); } else { ret = -1; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetFd -- * * Returns the fd for this socket. * * Results: * File descriptor. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_GetFd(AsyncSocket *asock) // IN { int ret; if (VALID(asock, getFd)) { AsyncSocketLock(asock); ret = VT(asock)->getFd(asock); AsyncSocketUnlock(asock); } else { ret = -1; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetRemoteIPStr -- * * Given an AsyncSocket object, returns the remote IP address associated * with it, or an error if the request is meaningless for the underlying * connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_INVAL. * * Side effects: * * *---------------------------------------------------------------------------- */ int AsyncSocket_GetRemoteIPStr(AsyncSocket *asock, // IN const char **ipRetStr) // OUT { int ret; if (VALID(asock, getRemoteIPStr)) { AsyncSocketLock(asock); ret = VT(asock)->getRemoteIPStr(asock, ipRetStr); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetRemotePort -- * * Given an AsyncSocket object, returns the remote port associated * with it, or an error if the request is meaningless for the underlying * connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_INVAL. * * Side effects: * * *---------------------------------------------------------------------------- */ int AsyncSocket_GetRemotePort(AsyncSocket *asock, // IN uint32 *port) // OUT { int ret; if (VALID(asock, getRemotePort)) { AsyncSocketLock(asock); ret = VT(asock)->getRemotePort(asock, port); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetINETIPStr -- * * Given an AsyncSocket object, returns the IP addresses associated with * the requested address family's file descriptor if available. * * Passing AF_UNSPEC to socketFamily will provide you with the first * usable IP address found (if multiple are available), with a preference * given to IPv6. * * It is the caller's responsibility to free ipRetStr. * * Results: * ASOCKERR_SUCCESS. ASOCKERR_INVAL if there is no socket associated with * address family requested. ASOCKERR_GENERIC for all other errors. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_GetINETIPStr(AsyncSocket *asock, // IN int socketFamily, // IN char **ipRetStr) // OUT { int ret; if (VALID(asock, getINETIPStr)) { AsyncSocketLock(asock); ret = VT(asock)->getINETIPStr(asock, socketFamily, ipRetStr); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetPort -- * * Given an AsyncSocket object, returns the port number associated with * the requested address family's file descriptor if available. * * Results: * Port number in host byte order. MAX_UINT32 on error. * * Side effects: * None. * *---------------------------------------------------------------------------- */ unsigned int AsyncSocket_GetPort(AsyncSocket *asock) // IN { int ret; if (VALID(asock, getPort)) { AsyncSocketLock(asock); ret = VT(asock)->getPort(asock); AsyncSocketUnlock(asock); } else { ret = MAX_UINT32; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_UseNodelay -- * * THIS IS DEPRECATED in favor of AsyncSocket_SetOption(...TCP_NODELAY...). * It exists for now to avoid having to change all existing calling code. * TODO: Remove it fully and fix up all calling code accordingly. * * Sets the setsockopt() value TCP_NODELAY. * asyncSocket may be an AsyncTCPSocket itself * or contain one on which the option will be set. * * This fails if there is no applicable AsyncTCPSocket (asyncSocket or * one inside it). * * Results: * ASOCKERR_SUCCESS on success, ASOCKERR_* otherwise. * There being no applicable AsyncTCPSocket yields ASOCKERR_INVAL. * OS error when setting value yields ASOCKERR_GENERIC. * * Side effects: * Possibly increased bandwidth usage for short messages on this socket * due to TCP overhead, in exchange for lower latency. * *---------------------------------------------------------------------------- */ int AsyncSocket_UseNodelay(AsyncSocket *asyncSocket, // IN/OUT Bool noDelay) // IN { const int noDelayNative = noDelay ? 1 : 0; return AsyncSocket_SetOption(asyncSocket, (AsyncSocketOpts_Layer)IPPROTO_TCP, TCP_NODELAY, &noDelayNative, sizeof noDelayNative); } /* *---------------------------------------------------------------------------- * * AsyncSocket_SetTCPTimeouts -- * * Sets setsockopt() TCP_KEEP{INTVL|IDLE|CNT} if available in the OS. * asyncSocket may be an AsyncTCPSocket itself * or contain one on which the option will be set. * * This fails if there is no applicable AsyncTCPSocket (asyncSocket or * one inside it). * * Results: * ASOCKERR_SUCCESS if no error, or OS doesn't support options. * There being no applicable AsyncTCPSocket yields ASOCKERR_INVAL. * OS error when setting any one value yields ASOCKERR_GENERIC. * * Side effects: * None. * Note that in case of error ASOCKERR_GENERIC, 0, 1, or 2 of the values * may have still been successfully set (the successful changes are * not rolled back). * *---------------------------------------------------------------------------- */ int AsyncSocket_SetTCPTimeouts(AsyncSocket *asyncSocket, // IN/OUT int keepIdleSec, // IN int keepIntvlSec, // IN int keepCnt) // IN { /* * This function is NOT deprecated like the nearby setOption()-wrapping * functions. It's valuable because it: enapsulates OS-dependent logic; and * performs one lock before settong all applicable options together. */ #if defined(__linux__) || defined(VMX86_SERVER) /* * Tempting to call AsyncSocket_SetOption() x 3 instead of worrying about * locking and VT() ourselves, but this way we can reduce amount of * locking/unlocking at the cost of code verbosity. * * Reason for bailing on first error instead of trying all three: * it's what the original code (that this adapts) did. TODO: Find out from * author, explain here. */ int ret; if (VALID(asyncSocket, setOption)) { AsyncSocketLock(asyncSocket); ret = VT(asyncSocket)->setOption (asyncSocket, (AsyncSocketOpts_Layer)IPPROTO_TCP, TCP_KEEPIDLE, &keepIdleSec, sizeof keepIdleSec); if (ret == ASOCKERR_SUCCESS) { ret = VT(asyncSocket)->setOption (asyncSocket, (AsyncSocketOpts_Layer)IPPROTO_TCP, TCP_KEEPINTVL, &keepIntvlSec, sizeof keepIntvlSec); if (ret == ASOCKERR_SUCCESS) { ret = VT(asyncSocket)->setOption (asyncSocket, (AsyncSocketOpts_Layer)IPPROTO_TCP, TCP_KEEPCNT, &keepCnt, sizeof keepCnt); } } AsyncSocketUnlock(asyncSocket); } else { ret = ASOCKERR_INVAL; } return ret; #else // #ifndef __linux__ return ASOCKERR_SUCCESS; #endif } /* *----------------------------------------------------------------------------- * * AsyncSocket_EstablishMinBufferSizes -- * * Meant to be invoked around socket creation time, this tries to ensure * that SO_{SND|RCV}BUF setsockopt() values are set to at least the values * provided as arguments. That is, it sets the given buffer size but only * if the current value reported by the OS is smaller. * * This fails unless asyncSocket is of the "applicable socket type." * Being of "applicable socket type" is defined as supporting the * option: * * layer = SOL_SOCKET, * optID = SO_{SND|RCV}BUF. * * As of this writing, only AsyncTCPSockets (or derivations thereof) * are supported, but (for example) UDP sockets could be added over time. * * Results: * TRUE: on success; FALSE: on failure. * Determining that no setsockopt() is required is considered success. * * Side effects: * None. * Note that in case of a setsockopt() failing, 0 or 1 of the values * may have still been successfully set (the successful changes are * not rolled back). * *----------------------------------------------------------------------------- */ Bool AsyncSocket_EstablishMinBufferSizes(AsyncSocket *asyncSocket, // IN/OUT int sendSz, // IN int recvSz) // IN { Bool ok; if (VALID(asyncSocket, setOption)) { int curSendSz; socklen_t curSendSzSz = sizeof curSendSz; int curRecvSz; socklen_t curRecvSzSz = sizeof curRecvSz; AsyncSocketLock(asyncSocket); /* * For each buffer size, see if the current reported size is already * at least as large (in which case we needn't do anything for that one). * Bail out the moment anything fails, but don't worry about undoing any * change already made (as advertised in doc comment). * * Reason for bailing on first error instead of trying everything: * it's what the original code (that this adapts) did. TODO: Find out from * author, explain here. * * Note that depending on the type of socket and the particular * implementation (e.g., the TCP stack), asking for buffer size N might * result in an even larger buffer, like a multiple 2N. It's not an exact * science. */ ok = (VT(asyncSocket)->getOption(asyncSocket, SOL_SOCKET, SO_SNDBUF, &curSendSz, &curSendSzSz) == ASOCKERR_SUCCESS) && (VT(asyncSocket)->getOption(asyncSocket, SOL_SOCKET, SO_RCVBUF, &curRecvSz, &curRecvSzSz) == ASOCKERR_SUCCESS); if (ok && (curSendSz < sendSz)) { ok = VT(asyncSocket)->setOption(asyncSocket, SOL_SOCKET, SO_SNDBUF, &sendSz, sizeof sendSz) == ASOCKERR_SUCCESS; } if (ok && (curRecvSz < recvSz)) { ok = VT(asyncSocket)->setOption(asyncSocket, SOL_SOCKET, SO_RCVBUF, &recvSz, sizeof recvSz) == ASOCKERR_SUCCESS; } AsyncSocketUnlock(asyncSocket); } else { ok = FALSE; } return ok; } /* *---------------------------------------------------------------------------- * * AsyncSocket_SetSendLowLatencyMode -- * * THIS IS DEPRECATED in favor of * AsyncSocket_SetOption(ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE). * It exists for now to avoid having to change all existing calling code. * TODO: Remove it fully and fix up all calling code accordingly. * * Sets the aforementioned value. See doc comment on * ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE for more info. * * This fails unless asyncSocket is of the "applicable socket type." * Being of "applicable socket type" is defined as supporting the * option: * * layer = ASYNC_SOCKET_OPTS_LAYER_BASE, * optID = ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE. * * Results: * ASOCKERR_SUCCESS on success, ASOCKERR_* otherwise. * asyncSocket being of inapplicable socket type yields ASOCKERR_INVAL. * * Side effects: * See ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE doc comment. * *---------------------------------------------------------------------------- */ int AsyncSocket_SetSendLowLatencyMode(AsyncSocket *asyncSocket, // IN Bool enable) // IN { int ret; if (VALID(asyncSocket, setOption)) { AsyncSocketLock(asyncSocket); ret = VT(asyncSocket)->setOption (asyncSocket, ASYNC_SOCKET_OPTS_LAYER_BASE, ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE, &enable, sizeof enable); AsyncSocketUnlock(asyncSocket); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_SetOption -- * * Sets the value of the given socket option belonging to the given * option layer to the given value. The socket options mechanism is * discussed in more detail in asyncsocket.h. * * The exact behavior and supported options are dependent on the socket * type. See the doc header for the specific implementation for details. * If ->setOption is NULL, all options are invalid for that socket. * Setting an invalid layer+option results in a no-op + error result. * * For native options, layer = setsockopt() level, * optID = setsockopt() option_name. * * For non-native options, optID is obtained as follows: it is converted * from an enum option ID value for your socket type; for example, * from ASYNC_TCP_SOCKET_OPT_ALLOW_DECREASING_BUFFER_SIZE, * where the latter is of type AsyncTCPSocket_OptID. * * The option's value must reside at the buffer valuePtr that is * inBufLen long. If inBufLen does not match the expected size for * the given option, behavior is undefined. * * Results: * ASOCKERR_SUCCESS on success, ASOCKERR_* otherwise. * Invalid option+layer yields ASOCKERR_INVAL. * Failure to set a native OS option yields ASOCKERR_GENERIC. * inBufLen being wrong (for the given option) yields undefined behavior. * * Side effects: * Depends on option. * *---------------------------------------------------------------------------- */ int AsyncSocket_SetOption(AsyncSocket *asyncSocket, // IN/OUT AsyncSocketOpts_Layer layer, // IN AsyncSocketOpts_ID optID, // IN const void *valuePtr, // IN socklen_t inBufLen) // IN { int ret; /* * Lacking a setOption() implementation is conceptually the same as * ->setOption() existing but determining layer+optID to be invalid * (ASOCKERR_INVAL results). */ if (VALID(asyncSocket, setOption)) { AsyncSocketLock(asyncSocket); ret = VT(asyncSocket)->setOption(asyncSocket, layer, optID, valuePtr, inBufLen); AsyncSocketUnlock(asyncSocket); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetOption -- * * Gets the value of the given socket option belonging to the given * option layer. The socket options mechanism is * discussed in more detail in asyncsocket.h. * This is generally symmetrical to ..._SetOption(); most comments applying * to that function apply to this one in common-sense ways. * In particular a layer+optID combo is supported here if and only if it * is supported for ..._SetOption(). * * The length of the output buffer at valuePtr must reside at *outBufLen * at entry to this function. If *outBufLen does not match or exceed the * expected size for the given option, behavior is undefined. * At successful return from function, *outBufLen will be set to the * length of the value written to at valuePtr. * * Results: * ASOCKERR_SUCCESS on success, ASOCKERR_* otherwise. * Invalid option+layer yields ASOCKERR_INVAL. * Failure to get a native OS option yields ASOCKERR_GENERIC. * *outBufLen being wrong (for the given option) yields undefined behavior. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_GetOption(AsyncSocket *asyncSocket, // IN/OUT AsyncSocketOpts_Layer layer, // IN AsyncSocketOpts_ID optID, // IN void *valuePtr, // OUT socklen_t *outBufLen) // IN/OUT { int ret; /* * Lacking a getOption() implementation is conceptually the same as * ->getOption() existing but determining layer+optID to be invalid * (ASOCKERR_INVAL results). */ if (VALID(asyncSocket, getOption)) { AsyncSocketLock(asyncSocket); ret = VT(asyncSocket)->getOption(asyncSocket, layer, optID, valuePtr, outBufLen); AsyncSocketUnlock(asyncSocket); } else { ret = ASOCKERR_INVAL; } return ret; } /* *----------------------------------------------------------------------------- * * AsyncSocket_StartSslConnect -- * * Start an asynchronous SSL connect operation. * * The supplied callback function is called when the operation is complete * or an error occurs. The caller should only free the verifyParam argument * after the sslConnectFn callback is called. * * Results: * ASOCKERR_SUCCESS indicates we have started async connect. * ASOCKERR_* indicates a failure to start the connect. * * Errors during asynchronous processing is reported using the * callback supplied. Detailed SSL verification error can be * retrieved from verifyParam structure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ int AsyncSocket_StartSslConnect(AsyncSocket *asock, // IN SSLVerifyParam *verifyParam, // IN/OPT const char *hostname, // IN/OPT void *sslCtx, // IN AsyncSocketSslConnectFn sslConnectFn, // IN void *clientData) // IN { int ret; if (VALID(asock, startSslConnect)) { AsyncSocketLock(asock); ret = VT(asock)->startSslConnect(asock, verifyParam, hostname, sslCtx, sslConnectFn, clientData); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *----------------------------------------------------------------------------- * * AsyncSocket_ConnectSSL -- * * Initialize the socket's SSL object, by calling SSL_ConnectAndVerify. * NOTE: This call is blocking. * * Results: * TRUE if SSL_ConnectAndVerify succeeded, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool AsyncSocket_ConnectSSL(AsyncSocket *asock, // IN SSLVerifyParam *verifyParam, // IN/OPT const char *hostname, // IN/OPT void *sslContext) // IN/OPT { Bool ret; if (VALID(asock, connectSSL)) { AsyncSocketLock(asock); ret = VT(asock)->connectSSL(asock, verifyParam, hostname, sslContext); AsyncSocketUnlock(asock); } else { ret = FALSE; } return ret; } /* *----------------------------------------------------------------------------- * * AsyncSocket_AcceptSSL -- * * Initialize the socket's SSL object, by calling SSL_Accept. * * Results: * TRUE if SSL_Accept succeeded, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool AsyncSocket_AcceptSSL(AsyncSocket *asock, // IN void *sslCtx) // IN: optional { Bool ret; if (VALID(asock, acceptSSL)) { AsyncSocketLock(asock); ret = VT(asock)->acceptSSL(asock, sslCtx); AsyncSocketUnlock(asock); } else { ret = FALSE; } return ret; } /* *----------------------------------------------------------------------------- * * AsyncSocket_StartSslAccept -- * * Start an asynchronous SSL accept operation. * * The supplied callback function is called when the operation is complete * or an error occurs. * * Results: * ASOCKERR_SUCCESS indicates we have started async accept. * ASOCKERR_* indicates a failure to start the accept. * * Errors during asynchronous processing are reported using the * callback supplied. * * Side effects: * None. * *----------------------------------------------------------------------------- */ int AsyncSocket_StartSslAccept(AsyncSocket *asock, // IN void *sslCtx, // IN AsyncSocketSslAcceptFn sslAcceptFn, // IN void *clientData) // IN { int ret; if (VALID(asock, startSslAccept)) { AsyncSocketLock(asock); ret = VT(asock)->startSslAccept(asock, sslCtx, sslAcceptFn, clientData); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_Flush -- * * Try to send any pending out buffers until we run out of buffers, or * the timeout expires. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call * failures, and ASOCKERR_TIMEOUT if we couldn't send enough data * before the timeout expired. ASOCKERR_INVAL on invalid * parameters or operation not implemented on this socket. * * Side effects: * None. *---------------------------------------------------------------------------- */ int AsyncSocket_Flush(AsyncSocket *asock, // IN int timeoutMS) // IN { int ret; if (VALID(asock, flush)) { AsyncSocketLock(asock); ret = VT(asock)->flush(asock, timeoutMS); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_Recv -- * AsyncSocket_RecvPartial -- * * Registers a callback that will fire once the specified amount of data * has been received on the socket. * * In the case of AsyncSocket_RecvPartial, the callback is fired * once all or part of the data has been received on the socket. * * TCP usage: * AsyncSocket_Recv(AsyncSocket *asock, * void *buf, * int len, * AsyncSocketRecvFn recvFn, * void *clientData) * * Results: * ASOCKERR_*. * * Side effects: * Could register poll callback. * *---------------------------------------------------------------------------- */ int AsyncSocket_Recv(AsyncSocket *asock, // IN void *buf, // IN (buffer to fill) int len, // IN void *cb, // IN void *cbData) // IN { int ret; if (VALID(asock, recv)) { AsyncSocketLock(asock); ret = VT(asock)->recv(asock, buf, len, FALSE, cb, cbData); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } int AsyncSocket_RecvPartial(AsyncSocket *asock, // IN void *buf, // IN (buffer to fill) int len, // IN void *cb, // IN void *cbData) // IN { int ret; if (VALID(asock, recv)) { AsyncSocketLock(asock); ret = VT(asock)->recv(asock, buf, len, TRUE, cb, cbData); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_Peek -- * * Similar to AsyncSocket_RecvPartial, AsyncSocket_Peek reads the socket * buffer contents into the provided buffer by registering a callback that * will fire when data becomes available. * * Due to underying poll implementation, peeks are always "partial" ie. * callback returns when less than or equal amount of requested length is * available to read. Peek callers may use recv() to drain smaller amounts * notified by peek-callback and then peek for more data if that helps. * * There are some noteworthy differences compared to Recv(): * * - By definition, Recv() drains the socket buffer while Peek() does not * * - Asyncsocket Recv() is post-SSL since it internally calls SSL_Read() * so application always gets decrypted data when entire SSL record is * decrypted. Peek() on the other hand is SSL agnostic; it reads * directly from the underlying host socket and makes no attempt to * decrypt it or check for any data buffered within SSL. So asyncsocket * user doing a recv() followed by peek() may get different results. * That is why is it most safe to use peek() before SSL is setup on the * TCP connection. * * - Peek is one-shot in nature, meaning that peek callbacks are * unregistered from poll once fired. * * Results: * ASOCKERR_*. * * Side effects: * Could register poll callback. * *---------------------------------------------------------------------------- */ int AsyncSocket_Peek(AsyncSocket *asock, // IN void *buf, // IN (buffer to fill) int len, // IN void *cb, // IN void *cbData) // IN { int ret; if (VALID(asock, recv)) { AsyncSocketLock(asock); ret = VT(asock)->peek(asock, buf, len, cb, cbData); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_RecvPassedFd -- * * See AsyncSocket_Recv. Besides that it allows for receiving one * file descriptor... * * Results: * ASOCKERR_*. * * Side effects: * Could register poll callback. * *---------------------------------------------------------------------------- */ int AsyncSocket_RecvPassedFd(AsyncSocket *asock, // IN/OUT: socket void *buf, // OUT: buffer with data int len, // IN: length void *cb, // IN: completion calback void *cbData) // IN: callback's data { int ret; if (VALID(asock, recvPassedFd)) { AsyncSocketLock(asock); ret = VT(asock)->recvPassedFd(asock, buf, len, cb, cbData); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *----------------------------------------------------------------------------- * * AsyncSocket_GetReceivedFd -- * * Retrieve received file descriptor from socket. * * Results: * File descriptor. Or -1 if none was received. * * Side effects: * None. * *----------------------------------------------------------------------------- */ int AsyncSocket_GetReceivedFd(AsyncSocket *asock) // IN { int ret; if (VALID(asock, getReceivedFd)) { AsyncSocketLock(asock); ret = VT(asock)->getReceivedFd(asock); AsyncSocketUnlock(asock); } else { ret = -1; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_Send -- * * Queues the provided data for sending on the socket. If a send callback * is provided, the callback is fired after the data has been written to * the socket. Note that this only guarantees that the data has been * copied to the transmit buffer, we make no promises about whether it * has actually been transmitted, or received by the client, when the * callback is fired. * * Send callbacks should also be able to deal with being called if none * or only some of the queued buffer has been transmitted, since the send * callbacks for any remaining buffers are fired by AsyncSocket_Close(). * This condition can be detected by checking the len parameter passed to * the send callback. * * Results: * ASOCKERR_*. * * Side effects: * May register poll callback or perform I/O. * *---------------------------------------------------------------------------- */ int AsyncSocket_Send(AsyncSocket *asock, // IN void *buf, // IN int len, // IN AsyncSocketSendFn sendFn, // IN void *clientData) // IN { int ret; if (VALID(asock, send)) { AsyncSocketLock(asock); ret = VT(asock)->send(asock, buf, len, sendFn, clientData); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_IsSendBufferFull -- * * Indicate if socket send buffer is full. Note that unless this is * called from a callback function, the return value should be treated * as transient. * * Results: * 0: send space probably available, * 1: send has reached maximum, * ASOCKERR_INVAL: null socket or operation not supported. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_IsSendBufferFull(AsyncSocket *asock) // IN { int ret; if (VALID(asock, isSendBufferFull)) { AsyncSocketLock(asock); ret = VT(asock)->isSendBufferFull(asock); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetNetworkStats -- * * Get network statistics from the active socket. * * Results: * ASOCKERR_* * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_GetNetworkStats(AsyncSocket *asock, // IN AsyncSocketNetworkStats *stats) // OUT { int ret; if (VALID(asock, getNetworkStats)) { AsyncSocketLock(asock); ret = VT(asock)->getNetworkStats(asock, stats); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetSNIHostname -- * * Get SNI hostname from the active socket. * * Results: * ASOCKERR_* * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_GetSNIHostname(AsyncSocket *asock, // IN const char **sniHostname) // OUT { int ret; if (VALID(asock, getSNIHostname)) { AsyncSocketLock(asock); ret = VT(asock)->getSNIHostname(asock, sniHostname); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_Close -- * * AsyncSocket destructor. The destructor should be safe to call at any * time. It's invoked automatically for I/O errors on slots that have no * error handler set, and should be called manually by the error handler * as necessary. It could also be called as part of the normal program * flow. * * Results: * ASOCKERR_*. * * Side effects: * Closes the socket fd, unregisters all Poll callbacks, and fires the * send triggers for any remaining output buffers. * *---------------------------------------------------------------------------- */ int AsyncSocket_Close(AsyncSocket *asock) // IN { int ret; if (VALID(asock, close)) { AsyncSocketLock(asock); ret = VT(asock)->close(asock); ASSERT(!asock->inited); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_CloseWrite -- * * Close the write side of AsyncSocket, and leave the read side open. This * can be used to implement a shutdown(SHUT_WR...) equivalent. * * This function is meant to be called after the socket has been connected * If no error, pending send is flushed the same way as AsyncSocket_Close, * and then the socket enters half-closed state, disallowing further send. * * Like AsyncSocket_Close, it's safe to call at any time, but it could err * when the socket is not connected. Unlike Close, read side of the socket * is left intact, and the the socket is not released. * * If the socket is already closed, it returns success. * * Results: * ASOCKERR_*. * * Side effects: * Send is not permitted after this call. * *---------------------------------------------------------------------------- */ int AsyncSocket_CloseWrite(AsyncSocket *asock) // IN { int ret; if (VALID(asock, closeWrite)) { AsyncSocketLock(asock); ret = VT(asock)->closeWrite(asock); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *----------------------------------------------------------------------------- * * AsyncSocket_CancelRecv -- * AsyncSocket_CancelRecvEx -- * * Call this function if you know what you are doing. This should be * called if you want to synchronously receive the outstanding data on * the socket. It removes the recv poll callback. It also returns number of * partially read bytes (if any). A partially read response may exist as * AsyncSocketRecvCallback calls the recv callback only when all the data * has been received. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_INVAL. * * Side effects: * Subsequent client call to AsyncSocket_Recv can reinstate async behaviour. * *----------------------------------------------------------------------------- */ int AsyncSocket_CancelRecv(AsyncSocket *asock, // IN int *partialRecvd, // OUT void **recvBuf, // OUT void **recvFn) // OUT { return AsyncSocket_CancelRecvEx(asock, partialRecvd, recvBuf, recvFn, FALSE); } int AsyncSocket_CancelRecvEx(AsyncSocket *asock, // IN int *partialRecvd, // OUT void **recvBuf, // OUT void **recvFn, // OUT Bool cancelOnSend) // IN { int ret; if (VALID(asock, cancelRecv)) { AsyncSocketLock(asock); ret = VT(asock)->cancelRecv(asock, partialRecvd, recvBuf, recvFn, cancelOnSend); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_CancelCbForClose -- * * This is the external version of AsyncSocketCancelCbForCloseInt(). It * takes care of acquiring any necessary lock before calling the internal * function. * * Results: * ASOCKERR_*. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_CancelCbForClose(AsyncSocket *asock) // IN: { int ret; if (VALID(asock, cancelCbForClose)) { AsyncSocketLock(asock); ret = VT(asock)->cancelCbForClose(asock); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetLocalVMCIAddress -- * * Given an AsyncSocket object, returns the local VMCI context ID and * port number associated with it, or an error if the request is * meaningless for the underlying connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * * *---------------------------------------------------------------------------- */ int AsyncSocket_GetLocalVMCIAddress(AsyncSocket *asock, // IN uint32 *cid, // OUT: optional uint32 *port) // OUT: optional { int ret; if (VALID(asock, getLocalVMCIAddress)) { AsyncSocketLock(asock); ret = VT(asock)->getLocalVMCIAddress(asock, cid, port); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetRemoteVMCIAddress -- * * Given an AsyncSocket object, returns the remote VMCI context ID and * port number associated with it, or an error if the request is * meaningless for the underlying connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * * *---------------------------------------------------------------------------- */ int AsyncSocket_GetRemoteVMCIAddress(AsyncSocket *asock, // IN uint32 *cid, // OUT: optional uint32 *port) // OUT: optional { int ret; if (VALID(asock, getRemoteVMCIAddress)) { AsyncSocketLock(asock); ret = VT(asock)->getRemoteVMCIAddress(asock, cid, port); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetWebSocketError -- * * Return the HTTP error code supplied during a failed WebSocket * upgrade negotiation. * * Results: * Numeric HTTP error code, 0 if no error, or -1 on invalid arguments. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_GetWebSocketError(AsyncSocket *asock) // IN { int ret; if (VALID(asock, getWebSocketError)) { AsyncSocketLock(asock); ret = VT(asock)->getWebSocketError(asock); AsyncSocketUnlock(asock); } else { ret = -1; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetWebSocketURI -- * * Return the URI supplied during a WebSocket connection request. * * Results: * URI or Null if no URI was specified. * * Side effects: * None. * *---------------------------------------------------------------------------- */ char * AsyncSocket_GetWebSocketURI(AsyncSocket *asock) // IN { char *ret; if (VALID(asock, getWebSocketURI)) { AsyncSocketLock(asock); ret = VT(asock)->getWebSocketURI(asock); AsyncSocketUnlock(asock); } else { ret = NULL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetWebSocketCookie -- * * Return the Cookie field value supplied during a WebSocket * connection request. * * Results: * Cookie, if asock is WebSocket. * NULL, if asock is not WebSocket. * * Side effects: * None. * *---------------------------------------------------------------------------- */ char * AsyncSocket_GetWebSocketCookie(AsyncSocket *asock) // IN { char *ret; if (VALID(asock, getWebSocketCookie)) { AsyncSocketLock(asock); ret = VT(asock)->getWebSocketCookie(asock); AsyncSocketUnlock(asock); } else { ret = NULL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_SetWebSocketCookie -- * * Insert Set-Cookie HTTP response header during WebSocket connection. * * Results: * ASOCKERR_SUCCESS if we finished the operation, ASOCKERR_* error codes * otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_SetWebSocketCookie(AsyncSocket *asock, // IN void *clientData, // IN const char *path, // IN const char *sessionId) // IN { int ret = ASOCKERR_INVAL; if (VALID(asock, setWebSocketCookie)) { AsyncSocketLock(asock); ret = VT(asock)->setWebSocketCookie(asock, clientData, path, sessionId); AsyncSocketUnlock(asock); } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetWebSocketCloseStatus -- * * Retrieve the close status, if received, for a websocket connection. * * Results: * Websocket close status code (>= 1000), or 0 if never received. * * Side effects: * None. * *---------------------------------------------------------------------------- */ uint16 AsyncSocket_GetWebSocketCloseStatus(AsyncSocket *asock) // IN { uint16 ret; if (VALID(asock, getWebSocketCloseStatus)) { AsyncSocketLock(asock); ret = VT(asock)->getWebSocketCloseStatus(asock); AsyncSocketUnlock(asock); } else { ret = 0; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_GetWebSocketProtocol -- * * Return the negotiated websocket protocol. Only valid until asock is * destroyed. * * Results: * NULL, if asock is not WebSocket. * AsyncWebSocketProtocol *, if asock is WebSocket. * * Side effects: * None. * *---------------------------------------------------------------------------- */ const char * AsyncSocket_GetWebSocketProtocol(AsyncSocket *asock) // IN { const char *ret; if (VALID(asock, getWebSocketProtocol)) { AsyncSocketLock(asock); ret = VT(asock)->getWebSocketProtocol(asock); AsyncSocketUnlock(asock); } else { ret = NULL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_SetDelayWebSocketUpgradeResponse -- * * Set a flag for whether or not to not automatically send the websocket * upgrade response upon receiving the websocket upgrade request. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_SetDelayWebSocketUpgradeResponse(AsyncSocket *asock, // IN Bool delayWebSocketUpgradeResponse) // IN { int ret = ASOCKERR_INVAL; if (VALID(asock, setDelayWebSocketUpgradeResponse)) { AsyncSocketLock(asock); ret = VT(asock)->setDelayWebSocketUpgradeResponse(asock, delayWebSocketUpgradeResponse); AsyncSocketUnlock(asock); } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_RecvBlocking -- * * Implement "blocking + timeout" operations on the socket. These are * simple wrappers around the AsyncTCPSocketBlockingWork function, which * operates on the actual non-blocking socket, using poll to determine * when it's ok to keep reading/writing. If we can't finish within the * specified time, we give up and return the ASOCKERR_TIMEOUT error. * * Note that if these are called from a callback and a lock is being * used (pollParams.lock), the whole blocking operation takes place * with that lock held. Regardless, it is the caller's responsibility * to make sure the synchronous and asynchronous operations do not mix. * * Results: * ASOCKERR_SUCCESS if we finished the operation, ASOCKERR_* error codes * otherwise. * * Side effects: * Reads/writes the socket. * *---------------------------------------------------------------------------- */ int AsyncSocket_RecvBlocking(AsyncSocket *asock, // IN void *buf, // OUT int len, // IN int *received, // OUT int timeoutMS) // IN { int ret; if (VALID(asock, recvBlocking)) { AsyncSocketLock(asock); ret = VT(asock)->recvBlocking(asock, buf, len, received, timeoutMS); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_RecvPartialBlocking -- * * Implement "blocking + timeout" version of RecvPartial * * Results: * ASOCKERR_SUCCESS if we finished the operation, ASOCKERR_* error codes * otherwise. * * Side effects: * Reads/writes the socket. * *---------------------------------------------------------------------------- */ int AsyncSocket_RecvPartialBlocking(AsyncSocket *asock, // IN void *buf, // OUT int len, // IN int *received, // OUT int timeoutMS) // IN { int ret; if (VALID(asock, recvPartialBlocking)) { AsyncSocketLock(asock); ret = VT(asock)->recvPartialBlocking(asock, buf, len, received, timeoutMS); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_SendBlocking -- * * Implement "blocking + timeout" version of Send * * Results: * ASOCKERR_SUCCESS if we finished the operation, ASOCKERR_* error codes * otherwise. * * Side effects: * Reads/writes the socket. * *---------------------------------------------------------------------------- */ int AsyncSocket_SendBlocking(AsyncSocket *asock, // IN void *buf, // IN int len, // IN int *sent, // OUT int timeoutMS) // IN { int ret; if (VALID(asock, sendBlocking)) { AsyncSocketLock(asock); ret = VT(asock)->sendBlocking(asock, buf, len, sent, timeoutMS); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_DoOneMsg -- * * Spins a socket until the specified amount of time has elapsed or * data has arrived / been sent. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call * failures * ASOCKERR_TIMEOUT if nothing happened in the allotted time. * * Side effects: * None. *---------------------------------------------------------------------------- */ int AsyncSocket_DoOneMsg(AsyncSocket *asock, // IN Bool read, // IN int timeoutMS) // IN { int ret; if (VALID(asock, doOneMsg)) { AsyncSocketLock(asock); ret = VT(asock)->doOneMsg(asock, read, timeoutMS); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_WaitForConnection -- * * Spins a socket currently listening or connecting until the * connection completes or the allowed time elapses. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on failures, and * ASOCKERR_TIMEOUT if nothing happened in the allotted time. * * Side effects: * None. *---------------------------------------------------------------------------- */ int AsyncSocket_WaitForConnection(AsyncSocket *asock, // IN int timeoutMS) // IN { int ret; if (VALID(asock, waitForConnection)) { AsyncSocketLock(asock); ret = VT(asock)->waitForConnection(asock, timeoutMS); AsyncSocketUnlock(asock); } else { ret = ASOCKERR_INVAL; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncSocket_WaitForReadMultiple -- * * Waits on a list of sockets, returning when a socket becomes * available for read, or when the allowed time elapses. * * Note, if this function is called by two threads with overlapping * sets of sockets, a deadlock can occur. The caller should guard * against such scenarios from happening, or making sure that there * is a consistent ordering to the lists of sockets. * * The caller must also make sure synchronous and asynchronous * operations do not mix, as this function does not hold locks * for the entirety of the call. * * Results: * ASOCKERR_SUCCESS if one of the sockets is ready for read, * ASOCKERR_GENERIC on failures, and ASOCKERR_TIMEOUT if nothing * happened in the allotted time. * * Side effects: * None. *---------------------------------------------------------------------------- */ int AsyncSocket_WaitForReadMultiple(AsyncSocket **asock, // IN int numSock, // IN int timeoutMS, // IN int *outIdx) // OUT { int ret; if (numSock > 0 && VALID(asock[0], waitForReadMultiple)) { int i; for (i = 0; i < numSock; i++) { AsyncSocketLock(asock[i]); } ret = VT(asock[0])->waitForReadMultiple(asock, numSock, timeoutMS, outIdx); for (i = numSock - 1; i >= 0; i--) { AsyncSocketUnlock(asock[i]); } } else { ret = ASOCKERR_INVAL; } return ret; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/asyncsocket/asyncSocketVTable.h000066400000000000000000000154331470176644300271600ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2011,2014-2017,2019-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #ifndef __ASYNC_SOCKET_VTABLE_H__ #define __ASYNC_SOCKET_VTABLE_H__ #ifdef USE_SSL_DIRECT #include "sslDirect.h" #else #include "ssl.h" #endif /* * If we change the AsyncSocketVTable, we also need to change the follow files: * apps/asyncSocketProxy/asyncVvcSocket.c * lib/blastSockets/asyncBweSocket.c * lib/blastSockets/asyncProxySocket.c * lib/asyncsocket/asyncsocket.c * lib/asyncsocket/asyncWebSocket.c * lib/asyncsocket/asyncNamedPipe.c * lib/udpfec/fecAsyncSocket.c * lib/udpfec/fecAsyncSslSocket.c * devices/vsock/asyncVmciSocket.c */ typedef struct AsyncSocketVTable { AsyncSocketState (*getState)(AsyncSocket *sock); /* * The socket options mechanism is discussed in asyncsocket.h. * If you're considering adding a new virtual function table entry whose * effect is to call setsockopt() and/or save a value inside the socket * structure and/or forward such a call to a contained AsyncSocket, * strongly consider using this setOption() mechanism instead. * Your life is likely to be made easier by this. */ int (*setOption)(AsyncSocket *asyncSocket, AsyncSocketOpts_Layer layer, AsyncSocketOpts_ID optID, const void *valuePtr, socklen_t inBufLen); /* * A setOption() implementation must have a symmetrical getOption() * counterpart. The converse is not true -- a getOption() * implementation need not have a setOption() counterpart. (One * way to look at this is that an option may be read-only, but it * must not be write-only.) */ int (*getOption)(AsyncSocket *asyncSocket, AsyncSocketOpts_Layer layer, AsyncSocketOpts_ID optID, void *valuePtr, socklen_t *outBufLen); int (*getGenericErrno)(AsyncSocket *s); int (*getFd)(AsyncSocket *asock); int (*getRemoteIPStr)(AsyncSocket *asock, const char **ipStr); int (*getRemotePort)(AsyncSocket *asock, uint32 *port); int (*getINETIPStr)(AsyncSocket *asock, int socketFamily, char **ipRetStr); unsigned int (*getPort)(AsyncSocket *asock); int (*setCloseOptions)(AsyncSocket *asock, int flushEnabledMaxWaitMsec, AsyncSocketCloseFn closeCb); Bool (*connectSSL)(AsyncSocket *asock, struct _SSLVerifyParam *verifyParam, const char *hostname, void *sslContext); int (*startSslConnect)(AsyncSocket *asock, struct _SSLVerifyParam *verifyParam, const char *hostname, void *sslCtx, AsyncSocketSslConnectFn sslConnectFn, void *clientData); Bool (*acceptSSL)(AsyncSocket *asock, void *sslCtx); int (*startSslAccept)(AsyncSocket *asock, void *sslCtx, AsyncSocketSslAcceptFn sslAcceptFn, void *clientData); int (*flush)(AsyncSocket *asock, int timeoutMS); int (*recv)(AsyncSocket *asock, void *buf, int len, Bool partial, void *cb, void *cbData); int (*recvPassedFd)(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); int (*getReceivedFd)(AsyncSocket *asock); int (*send)(AsyncSocket *asock, void *buf, int len, AsyncSocketSendFn sendFn, void *clientData); int (*isSendBufferFull)(AsyncSocket *asock); int (*getNetworkStats)(AsyncSocket *asock, AsyncSocketNetworkStats *stats); int (*getSNIHostname)(AsyncSocket *asock, const char **sniHostname); int (*close)(AsyncSocket *asock); int (*closeWrite)(AsyncSocket *asock); int (*cancelRecv)(AsyncSocket *asock, int *partialRecvd, void **recvBuf, void **recvFn, Bool cancelOnSend); int (*cancelCbForClose)(AsyncSocket *asock); int (*getLocalVMCIAddress)(AsyncSocket *asock, uint32 *cid, uint32 *port); int (*getRemoteVMCIAddress)(AsyncSocket *asock, uint32 *cid, uint32 *port); int (*getWebSocketError)(AsyncSocket *asock); char *(*getWebSocketURI)(AsyncSocket *asock); char *(*getWebSocketCookie)(AsyncSocket *asock); uint16 (*getWebSocketCloseStatus)(AsyncSocket *asock); const char *(*getWebSocketProtocol)(AsyncSocket *asock); int (*setWebSocketCookie)(AsyncSocket *asock, void *clientData, const char *path, const char *sessionId); int (*setDelayWebSocketUpgradeResponse)(AsyncSocket *asock, Bool delayWebSocketUpgradeResponse); int (*recvBlocking)(AsyncSocket *s, void *buf, int len, int *received, int timeoutMS); int (*recvPartialBlocking)(AsyncSocket *s, void *buf, int len, int *received, int timeoutMS); int (*sendBlocking)(AsyncSocket *s, void *buf, int len, int *sent, int timeoutMS); int (*doOneMsg)(AsyncSocket *s, Bool read, int timeoutMS); int (*waitForConnection)(AsyncSocket *s, int timeoutMS); int (*waitForReadMultiple)(AsyncSocket **asock, size_t numSock, int timeoutMS, int *outIdx); int (*peek)(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); /* * Internal function, called when refcount drops to zero: */ void (*destroy)(AsyncSocket *asock); } AsyncSocketVTable; #define VT(x) ((x)->vt) #define VALID(asock, x) LIKELY(asock && VT(asock)->x) #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/asyncsocket/asyncsocket.c000066400000000000000000006415101470176644300261160ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2003-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * asyncsocket.c -- * * The AsyncTCPSocket object is a fairly simple wrapper around a basic TCP * socket. It's potentially asynchronous for both read and write * operations. Reads are "requested" by registering a receive function * that is called once the requested amount of data has been read from * the socket. Similarly, writes are queued along with a send function * that is called once the data has been written. Errors are reported via * a separate callback. */ #include #include #include #include #ifdef _WIN32 /* * We redefine strcpy/strcat because the Windows SDK uses it for getaddrinfo(). * When we upgrade SDKs, this redefinition can go away. * Note: Now we are checking if we have secure libs for string operations */ #if !(defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L) #define strcpy(dst,src) Str_Strcpy((dst), (src), 0x7FFFFFFF) #define strcat(dst,src) Str_Strcat((dst), (src), 0x7FFFFFFF) #endif #include #include #include #include #include #include #if !(defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L) #undef strcpy #undef strcat #endif #else #include #include #include #include #include #include #include #include #include #include #include #include #endif #include "vmware.h" #include "str.h" #include "random.h" #include "asyncsocket.h" #include "asyncSocketBase.h" #include "poll.h" #include "log.h" #include "err.h" #include "hostinfo.h" #include "util.h" #include "msg.h" #include "posix.h" #include "vm_basic_asm.h" #include "vmci_sockets.h" #ifndef VMX86_TOOLS #include "vmdblib.h" #endif #ifdef _WIN32 #define ASOCK_LASTERROR() WSAGetLastError() #else #define ASOCK_LASTERROR() errno #endif #define LOGLEVEL_MODULE asyncsocket #include "loglevel_user.h" #ifdef VMX86_SERVER #include "uwvmkAPI.h" #endif #ifdef __linux__ /* * Our toolchain does not support IPV6_V6ONLY, but the host we are running on * may support it. Since setsockopt will return a error that we treat as * non-fatal, it is fine to attempt it. See define in in6.h. */ #ifndef IPV6_V6ONLY #define IPV6_V6ONLY 26 #endif /* * Linux versions can lack support for IPV6_V6ONLY while still supporting * V4MAPPED addresses. We check for a V4MAPPED address during accept to cover * this scenario. In case IN6_IS_ADDR_V4MAPPED is also not available, define it. */ #ifndef IN6_IS_ADDR_V4MAPPED #define IN6_IS_ADDR_V4MAPPED(a) \ (*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0 && \ *(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0 && \ *(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) #endif #endif #define PORT_STRING_LEN 6 /* "12345\0" or ":12345" */ #define IN_IPOLL_RECV (1 << 0) #define IN_IPOLL_SEND (1 << 1) /* * INET6_ADDRSTRLEN allows for only 45 characters. If we somehow have a * non-recommended V4MAPPED address we can exceed 45 total characters in our * address string format. While this should not be the case it is possible. * Account for the possible: * "[XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:AAA.BBB.CCC.DDD]:12345\0" * (XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:AAA.BBB.CCC.DDD\0 + [] + :12345) */ #define ADDR_STRING_LEN (INET6_ADDRSTRLEN + 2 + PORT_STRING_LEN) typedef enum { ASOCK_FLAG_PEEK = 1 } AsockFlags; #define ASOCK_PEEK(a) (a->flags & ASOCK_FLAG_PEEK) /* Local types. */ /* * Output buffer list data type, for the queue of outgoing buffers */ typedef struct SendBufList { struct SendBufList *next; void *buf; int len; int passFd; AsyncSocketSendFn sendFn; void *clientData; } SendBufList; typedef struct AsyncTCPSocket { /* * The base class, which is just a vtable: */ AsyncSocket base; /* * Everything for the TCP AsyncSocket implementation: */ int fd; SSLSock sslSock; int genericErrno; struct sockaddr_storage localAddr; socklen_t localAddrLen; struct sockaddr_storage remoteAddr; socklen_t remoteAddrLen; AsyncSocketConnectFn connectFn; AsyncSocketSslAcceptFn sslAcceptFn; AsyncSocketSslConnectFn sslConnectFn; int sslPollFlags; /* shared by sslAcceptFn, sslConnectFn */ /* shared by connectFn, sslAcceptFn and sslConnectFn */ void *clientData; PollerFunction internalConnectFn; PollerFunction internalSendFn; PollerFunction internalRecvFn; /* governs optional AsyncSocket_Close() behavior */ int flushEnabledMaxWaitMsec; AsyncSocketCloseFn closeCb; void *closeCbData; Bool recvCb; Bool recvCbTimer; SendBufList *sendBufList; SendBufList **sendBufTail; int sendPos; Bool sendCb; Bool sendCbTimer; Bool sendCbRT; Bool sendBufFull; Bool sendLowLatency; int inLowLatencySendCb; Bool sslConnected; uint8 inIPollCb; Bool inRecvLoop; uint32 inBlockingRecv; struct AsyncTCPSocket *listenAsock4; struct AsyncTCPSocket *listenAsock6; struct { Bool expected; int fd; } passFd; AsockFlags flags; } AsyncTCPSocket; /* * Local Functions */ static AsyncTCPSocket *AsyncTCPSocketCreate(AsyncSocketPollParams *pollParams); static void AsyncTCPSocketSendCallback(void *clientData); static void AsyncTCPSocketRecvCallback(void *clientData); static int AsyncTCPSocketResolveAddr(const char *hostname, unsigned int port, int family, Bool passive, struct sockaddr_storage *addr, socklen_t *addrLen, char **addrString); static AsyncTCPSocket *AsyncTCPSocketAttachToFd( int fd, AsyncSocketPollParams *pollParams, int *outError); static Bool AsyncTCPSocketHasDataPending(AsyncTCPSocket *asock); static int AsyncTCPSocketMakeNonBlocking(int fd); static void AsyncTCPSocketAcceptCallback(void *clientData); static void AsyncTCPSocketConnectCallback(void *clientData); static int AsyncTCPSocketBlockingWork(AsyncTCPSocket *asock, Bool read, void *buf, int len, int *completed, int timeoutMS, Bool partial); static VMwareStatus AsyncTCPSocketPollAdd(AsyncTCPSocket *asock, Bool socket, int flags, PollerFunction callback, ...); static Bool AsyncTCPSocketPollRemove(AsyncTCPSocket *asock, Bool socket, int flags, PollerFunction callback); static unsigned int AsyncTCPSocketGetPortFromAddr( struct sockaddr_storage *addr); static AsyncTCPSocket *AsyncTCPSocketConnect(struct sockaddr_storage *addr, socklen_t addrLen, int socketFd, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketConnectFlags flags, AsyncSocketPollParams *pollParams, int *outError); static int AsyncTCPSocketConnectInternal(AsyncTCPSocket *s); static VMwareStatus AsyncTCPSocketIPollAdd(AsyncTCPSocket *asock, Bool socket, int flags, PollerFunction callback, int info); static Bool AsyncTCPSocketIPollRemove(AsyncTCPSocket *asock, Bool socket, int flags, PollerFunction callback); static void AsyncTCPSocketIPollSendCallback(void *clientData); static void AsyncTCPSocketIPollRecvCallback(void *clientData); static Bool AsyncTCPSocketAddListenCb(AsyncTCPSocket *asock); static void AsyncTCPSocketSslConnectCallback(void *clientData); static void AsyncTCPSocketSslAcceptCallback(void *clientData); static Bool AsyncTCPSocketBind(AsyncTCPSocket *asock, struct sockaddr_storage *addr, socklen_t addrLen, int *outError); static Bool AsyncTCPSocketListen(AsyncTCPSocket *asock, AsyncSocketConnectFn connectFn, void *clientData, int *outError); static AsyncTCPSocket *AsyncTCPSocketInit(int socketFamily, AsyncSocketPollParams *pollParams, int *outError); static void AsyncTCPSocketCancelListenCb(AsyncTCPSocket *asock); static int AsyncTCPSocketRegisterRecvCb(AsyncTCPSocket *asock); static Bool AsyncTCPSocketCancelCbForConnectingClose(AsyncTCPSocket *asock); static int AsyncTCPSocketWaitForConnection(AsyncSocket *s, int timeoutMS); static int AsyncTCPSocketGetGenericErrno(AsyncSocket *s); static int AsyncTCPSocketGetFd(AsyncSocket *asock); static int AsyncTCPSocketGetRemoteIPStr(AsyncSocket *asock, const char **ipStr); static int AsyncTCPSocketGetRemotePort(AsyncSocket *asock, uint32 *port); static int AsyncTCPSocketGetINETIPStr(AsyncSocket *asock, int socketFamily, char **ipRetStr); static unsigned int AsyncTCPSocketGetPort(AsyncSocket *asock); static Bool AsyncTCPSocketConnectSSL(AsyncSocket *asock, struct _SSLVerifyParam *verifyParam, const char *hostname, void *sslContext); static int AsyncTCPSocketStartSslConnect(AsyncSocket *asock, SSLVerifyParam *verifyParam, const char *hostname, void *sslCtx, AsyncSocketSslConnectFn sslConnectFn, void *clientData); static Bool AsyncTCPSocketAcceptSSL(AsyncSocket *asock, void *sslCtx); static int AsyncTCPSocketStartSslAccept(AsyncSocket *asock, void *sslCtx, AsyncSocketSslAcceptFn sslAcceptFn, void *clientData); static int AsyncTCPSocketFlush(AsyncSocket *asock, int timeoutMS); static void AsyncTCPSocketCancelRecvCb(AsyncTCPSocket *asock); static void AsyncTCPSocketCancelSendCb(AsyncTCPSocket *asock); static int AsyncTCPSocketRecv(AsyncSocket *asock, void *buf, int len, Bool partial, void *cb, void *cbData); static int AsyncTCPSocketPeek(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); static int AsyncTCPSocketRecvPassedFd(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); static int AsyncTCPSocketGetReceivedFd(AsyncSocket *asock); static int AsyncTCPSocketSend(AsyncSocket *asock, void *buf, int len, AsyncSocketSendFn sendFn, void *clientData); static int AsyncTCPSocketSendWithFd(AsyncSocket *asock, void *buf, int len, int fd, AsyncSocketSendFn sendFn, void *clientData); static int AsyncTCPSocketIsSendBufferFull(AsyncSocket *asock); static int AsyncTCPSocketClose(AsyncSocket *asock); static int AsyncTCPSocketCloseWrite(AsyncSocket *asock); static int AsyncTCPSocketCancelRecv(AsyncSocket *asock, int *partialRecvd, void **recvBuf, void **recvFn, Bool cancelOnSend); static int AsyncTCPSocketCancelCbForClose(AsyncSocket *asock); static int AsyncTCPSocketGetLocalVMCIAddress(AsyncSocket *asock, uint32 *cid, uint32 *port); static int AsyncTCPSocketGetRemoteVMCIAddress(AsyncSocket *asock, uint32 *cid, uint32 *port); static int AsyncTCPSocketSetCloseOptions(AsyncSocket *asock, int flushEnabledMaxWaitMsec, AsyncSocketCloseFn closeCb); static void AsyncTCPSocketDestroy(AsyncSocket *s); static int AsyncTCPSocketRecvBlocking(AsyncSocket *s, void *buf, int len, int *received, int timeoutMS); static int AsyncTCPSocketRecvPartialBlocking(AsyncSocket *s, void *buf, int len, int *received, int timeoutMS); static int AsyncTCPSocketSendBlocking(AsyncSocket *s, void *buf, int len, int *sent, int timeoutMS); static int AsyncTCPSocketDoOneMsg(AsyncSocket *s, Bool read, int timeoutMS); static int AsyncTCPSocketWaitForReadMultiple(AsyncSocket **asock, size_t numSock, int timeoutMS, int *outIdx); static int AsyncTCPSocketSetOption(AsyncSocket *asyncSocket, AsyncSocketOpts_Layer layer, AsyncSocketOpts_ID optID, const void *valuePtr, socklen_t inBufLen); static int AsyncTCPSocketGetOption(AsyncSocket *asyncSocket, AsyncSocketOpts_Layer layer, AsyncSocketOpts_ID optID, void *valuePtr, socklen_t *outBufLen); static void AsyncTCPSocketListenerError(int error, AsyncSocket *asock, void *clientData); /* Local constants. */ static const AsyncSocketVTable asyncTCPSocketVTable = { AsyncSocketGetState, AsyncTCPSocketSetOption, AsyncTCPSocketGetOption, AsyncTCPSocketGetGenericErrno, AsyncTCPSocketGetFd, AsyncTCPSocketGetRemoteIPStr, AsyncTCPSocketGetRemotePort, AsyncTCPSocketGetINETIPStr, AsyncTCPSocketGetPort, AsyncTCPSocketSetCloseOptions, AsyncTCPSocketConnectSSL, AsyncTCPSocketStartSslConnect, AsyncTCPSocketAcceptSSL, AsyncTCPSocketStartSslAccept, AsyncTCPSocketFlush, AsyncTCPSocketRecv, AsyncTCPSocketRecvPassedFd, AsyncTCPSocketGetReceivedFd, AsyncTCPSocketSend, AsyncTCPSocketIsSendBufferFull, NULL, /* getNetworkStats */ NULL, /* getSNIHostname */ AsyncTCPSocketClose, AsyncTCPSocketCloseWrite, AsyncTCPSocketCancelRecv, AsyncTCPSocketCancelCbForClose, AsyncTCPSocketGetLocalVMCIAddress, AsyncTCPSocketGetRemoteVMCIAddress, NULL, /* getWebSocketError */ NULL, /* getWebSocketURI */ NULL, /* getWebSocketCookie */ NULL, /* getWebSocketCloseStatus */ NULL, /* getWebSocketProtocol */ NULL, /* setWebSocketCookie */ NULL, /* setDelayWebSocketUpgradeResponse */ AsyncTCPSocketRecvBlocking, AsyncTCPSocketRecvPartialBlocking, AsyncTCPSocketSendBlocking, AsyncTCPSocketDoOneMsg, AsyncTCPSocketWaitForConnection, AsyncTCPSocketWaitForReadMultiple, AsyncTCPSocketPeek, AsyncTCPSocketDestroy }; /* Function bodies. */ /* *---------------------------------------------------------------------- * * BaseSocket -- * * Return a pointer to the tcp socket's base class. * *---------------------------------------------------------------------- */ static INLINE AsyncSocket * BaseSocket(AsyncTCPSocket *s) { ASSERT((void *)s == (void *)&s->base); return &s->base; } /* *---------------------------------------------------------------------- * * TCPSocket -- * * Cast a generic AsyncSocket pointer to AsyncTCPSocket, after * asserting this is legal. * *---------------------------------------------------------------------- */ static INLINE AsyncTCPSocket * TCPSocket(AsyncSocket *s) { ASSERT(s->vt == &asyncTCPSocketVTable); ASSERT(s == &((AsyncTCPSocket *)s)->base); return (AsyncTCPSocket *)s; } /* *---------------------------------------------------------------------- * * TCPSocketLock -- * TCPSocketUnlock -- * TCPSocketIsLocked -- * TCPSocketAddRef -- * TCPSocketRelease -- * TCPSocketPollParams -- * TCPSocketGetState -- * TCPSocketSetState -- * TCPSocketHandleError -- * * AsyncTCPSocket versions of base class interfaces. These * simply invoke the corresponding function on the base class * pointer. * *---------------------------------------------------------------------- */ static INLINE void AsyncTCPSocketLock(AsyncTCPSocket *asock) { AsyncSocketLock(BaseSocket(asock)); } static INLINE void AsyncTCPSocketUnlock(AsyncTCPSocket *asock) { AsyncSocketUnlock(BaseSocket(asock)); } static INLINE Bool AsyncTCPSocketIsLocked(AsyncTCPSocket *asock) { return AsyncSocketIsLocked(BaseSocket(asock)); } static INLINE void AsyncTCPSocketAddRef(AsyncTCPSocket *asock) { AsyncSocketAddRef(BaseSocket(asock)); } static INLINE void AsyncTCPSocketRelease(AsyncTCPSocket *asock) { AsyncSocketRelease(BaseSocket(asock)); } static INLINE AsyncSocketPollParams * AsyncTCPSocketPollParams(AsyncTCPSocket *asock) { return AsyncSocketGetPollParams(BaseSocket(asock)); } static INLINE AsyncSocketState AsyncTCPSocketGetState(AsyncTCPSocket *asock) { return AsyncSocketGetState(BaseSocket(asock)); } static INLINE void AsyncTCPSocketSetState(AsyncTCPSocket *asock, AsyncSocketState state) { AsyncSocketSetState(BaseSocket(asock), state); } static INLINE void AsyncTCPSocketHandleError(AsyncTCPSocket *asock, int error) { AsyncSocketHandleError(BaseSocket(asock), error); } /* *---------------------------------------------------------------------- * * TCPSOCKWARN -- * TCPSOCKLOG -- * TCPSOCKLG0 -- * * AsyncTCPSocket versions of base class logging macros. These * simply invoke the corresponding macro on the base class * pointer. * *---------------------------------------------------------------------- */ /* gcc needs special syntax to handle zero-length variadic arguments */ #if defined(_MSC_VER) #define TCPSOCKWARN(a, fmt, ...) \ ASOCKWARN(BaseSocket(a), fmt, __VA_ARGS__) #define TCPSOCKLOG(_level, a, fmt, ...) \ ASOCKLOG(_level, BaseSocket(a), fmt, __VA_ARGS__) #define TCPSOCKLG0(a, fmt, ...) \ ASOCKLG0(BaseSocket(a), fmt, __VA_ARGS__) #else #define TCPSOCKWARN(a, fmt, ...) \ ASOCKWARN(BaseSocket(a), fmt, ##__VA_ARGS__) #define TCPSOCKLOG(_level, a, fmt, ...) \ ASOCKLOG(_level, BaseSocket(a), fmt, ##__VA_ARGS__) #define TCPSOCKLG0(a, fmt, ...) \ ASOCKLG0(BaseSocket(a), fmt, ##__VA_ARGS__) #endif /* *---------------------------------------------------------------------------- * * AsyncTCPSocket_Init -- * * Initializes the host's socket library. NOP on Posix. * On Windows, calls WSAStartup(). * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * On Windows, loads winsock library. * *---------------------------------------------------------------------------- */ int AsyncTCPSocket_Init(void) { #ifdef _WIN32 WSADATA wsaData; WORD versionRequested = MAKEWORD(2, 0); return WSAStartup(versionRequested, &wsaData) ? ASOCKERR_GENERIC : ASOCKERR_SUCCESS; #endif return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetFd -- * * Returns the fd for this socket. If listening, return one of * the asock6/asock4 fds. * * Results: * File descriptor. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetFd(AsyncSocket *base) // IN { AsyncTCPSocket *asock = TCPSocket(base); if (asock->fd != -1) { return asock->fd; } else if (asock->listenAsock4 && asock->listenAsock4->fd != -1) { return asock->listenAsock4->fd; } else if (asock->listenAsock6 && asock->listenAsock6->fd != -1) { return asock->listenAsock6->fd; } else { return -1; } } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetAddr -- * * Given an AsyncTCPSocket object, return the sockaddr associated with the * requested address family's file descriptor if available. * * Passing AF_UNSPEC to socketFamily will provide you with the first * usable sockaddr found (if multiple are available), with a preference * given to IPv6. * * Results: * ASOCKERR_SUCCESS. ASOCKERR_INVAL if there is no socket associated with * address family requested. ASOCKERR_GENERIC for all other errors. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetAddr(AsyncTCPSocket *asock, // IN int socketFamily, // IN struct sockaddr_storage *outAddr, // OUT socklen_t *outAddrLen) // IN/OUT { AsyncTCPSocket *tempAsock; int tempFd; struct sockaddr_storage addr; socklen_t addrLen = sizeof addr; if (asock->fd != -1) { tempAsock = asock; } else if ((socketFamily == AF_UNSPEC || socketFamily == AF_INET6) && asock->listenAsock6 && asock->listenAsock6->fd != -1) { tempAsock = asock->listenAsock6; } else if ((socketFamily == AF_UNSPEC || socketFamily == AF_INET) && asock->listenAsock4 && asock->listenAsock4->fd != -1) { tempAsock = asock->listenAsock4; } else { return ASOCKERR_INVAL; } ASSERT(AsyncTCPSocketIsLocked(tempAsock)); tempFd = tempAsock->fd; if (getsockname(tempFd, (struct sockaddr*)&addr, &addrLen) == 0) { if (socketFamily != AF_UNSPEC && addr.ss_family != socketFamily) { return ASOCKERR_INVAL; } memcpy(outAddr, &addr, Min(*outAddrLen, addrLen)); *outAddrLen = addrLen; return ASOCKERR_SUCCESS; } else { TCPSOCKWARN(tempAsock, "%s: could not locate socket.\n", __FUNCTION__); return ASOCKERR_GENERIC; } } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetRemoteIPStr -- * * Given an AsyncTCPSocket object, returns the remote IP address * associated with it, or an error if the request is meaningless * for the underlying connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetRemoteIPStr(AsyncSocket *base, // IN const char **ipRetStr) // OUT { AsyncTCPSocket *asock = TCPSocket(base); int ret = ASOCKERR_SUCCESS; ASSERT(asock); ASSERT(ipRetStr != NULL); if (ipRetStr == NULL || asock == NULL || (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) || (asock->remoteAddrLen != sizeof (struct sockaddr_in) && asock->remoteAddrLen != sizeof (struct sockaddr_in6))) { ret = ASOCKERR_GENERIC; } else { char addrBuf[NI_MAXHOST]; if (Posix_GetNameInfo((struct sockaddr *)&asock->remoteAddr, asock->remoteAddrLen, addrBuf, sizeof addrBuf, NULL, 0, NI_NUMERICHOST) != 0) { ret = ASOCKERR_GENERIC; } else { *ipRetStr = Util_SafeStrdup(addrBuf); } } return ret; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetRemotePort -- * * Given an AsyncTCPSocket object, returns the remote port * associated with it, or an error if the request is meaningless * for the underlying connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetRemotePort(AsyncSocket *base, // IN uint32 *port) // OUT { AsyncTCPSocket *asock = TCPSocket(base); int ret = ASOCKERR_SUCCESS; ASSERT(asock); if (asock == NULL || (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) || (asock->remoteAddrLen != sizeof(struct sockaddr_in) && asock->remoteAddrLen != sizeof(struct sockaddr_in6))) { ret = ASOCKERR_GENERIC; } else { *port = AsyncTCPSocketGetPortFromAddr(&asock->remoteAddr); } return ret; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetINETIPStr -- * * Given an AsyncTCPSocket object, returns the IP addresses associated with * the requested address family's file descriptor if available. * * Passing AF_UNSPEC to socketFamily will provide you with the first * usable IP address found (if multiple are available), with a preference * given to IPv6. * * It is the caller's responsibility to free ipRetStr. * * Results: * ASOCKERR_SUCCESS. ASOCKERR_INVAL if there is no socket associated with * address family requested. ASOCKERR_GENERIC for all other errors. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetINETIPStr(AsyncSocket *base, // IN int socketFamily, // IN char **ipRetStr) // OUT { AsyncTCPSocket *asock = TCPSocket(base); struct sockaddr_storage addr; socklen_t addrLen = sizeof addr; int ret; ASSERT(AsyncTCPSocketIsLocked(asock)); ret = AsyncTCPSocketGetAddr(asock, socketFamily, &addr, &addrLen); if (ret == ASOCKERR_SUCCESS) { char addrBuf[NI_MAXHOST]; if (ipRetStr == NULL) { TCPSOCKWARN(asock, "%s: Output string is not usable.\n", __FUNCTION__); ret = ASOCKERR_INVAL; } else if (Posix_GetNameInfo((struct sockaddr *)&addr, addrLen, addrBuf, sizeof addrBuf, NULL, 0, NI_NUMERICHOST) == 0) { *ipRetStr = Util_SafeStrdup(addrBuf); } else { TCPSOCKWARN(asock, "%s: could not find IP address.\n", __FUNCTION__); ret = ASOCKERR_GENERIC; } } return ret; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetLocalVMCIAddress -- * * Given an AsyncTCPSocket object, returns the local VMCI context ID and * port number associated with it, or an error if the request is * meaningless for the underlying connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetLocalVMCIAddress(AsyncSocket *base, // IN uint32 *cid, // OUT: optional uint32 *port) // OUT: optional { AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); if (asock->localAddrLen != sizeof(struct sockaddr_vm)) { return ASOCKERR_GENERIC; } if (cid != NULL) { *cid = ((struct sockaddr_vm *)&asock->localAddr)->svm_cid; } if (port != NULL) { *port = ((struct sockaddr_vm *)&asock->localAddr)->svm_port; } return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetRemoteVMCIAddress -- * * Given an AsyncTCPSocket object, returns the remote VMCI context ID and * port number associated with it, or an error if the request is * meaningless for the underlying connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetRemoteVMCIAddress(AsyncSocket *base, // IN uint32 *cid, // OUT: optional uint32 *port) // OUT: optional { AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); if (asock->remoteAddrLen != sizeof(struct sockaddr_vm)) { return ASOCKERR_GENERIC; } if (cid != NULL) { *cid = ((struct sockaddr_vm *)&asock->remoteAddr)->svm_cid; } if (port != NULL) { *port = ((struct sockaddr_vm *)&asock->remoteAddr)->svm_port; } return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketListenImpl -- * * Initializes, binds, and listens on pre-populated address structure. * * Results: * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket, binds and listens. * *---------------------------------------------------------------------------- */ static AsyncTCPSocket * AsyncTCPSocketListenImpl(struct sockaddr_storage *addr, // IN socklen_t addrLen, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketPollParams *pollParams, // IN: optional int *outError) // OUT: optional { AsyncTCPSocket *asock = AsyncTCPSocketInit(addr->ss_family, pollParams, outError); if (asock != NULL) { if (AsyncTCPSocketBind(asock, addr, addrLen, outError) && AsyncTCPSocketListen(asock, connectFn, clientData, outError)) { return asock; } } return NULL; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketListenerCreateImpl -- * * Listens on specified address and/or port for resolved/requested socket * family and accepts new connections. Fires the connect callback with * new AsyncTCPSocket object for each connection. * * Results: * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket, binds and listens. * *---------------------------------------------------------------------------- */ static AsyncTCPSocket * AsyncTCPSocketListenerCreateImpl( const char *addrStr, // IN: optional unsigned int port, // IN: optional int socketFamily, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { AsyncTCPSocket *asock = NULL; struct sockaddr_storage addr; socklen_t addrLen; char *ipString = NULL; int tempError = ASOCKERR_SUCCESS; int getaddrinfoError = AsyncTCPSocketResolveAddr(addrStr, port, socketFamily, TRUE, &addr, &addrLen, &ipString); if (getaddrinfoError == 0) { asock = AsyncTCPSocketListenImpl(&addr, addrLen, connectFn, clientData, pollParams, &tempError); if (asock) { TCPSOCKLG0(asock, "Created new %s %s listener for (%s)\n", addr.ss_family == AF_INET ? "IPv4" : "IPv6", "socket", ipString); } else { Log(ASOCKPREFIX "Could not create %s listener socket, error %d: %s\n", addr.ss_family == AF_INET ? "IPv4" : "IPv6", tempError, AsyncSocket_Err2String(tempError)); } free(ipString); } else { Log(ASOCKPREFIX "Could not resolve listener socket address.\n"); tempError = ASOCKERR_ADDRUNRESV; } if (outError) { *outError = tempError; } return asock; } /* *---------------------------------------------------------------------------- * * AsyncSocket_Listen -- * * Listens on specified address and/or port for all resolved socket * families and accepts new connections. Fires the connect callback with * new AsyncTCPSocket object for each connection. * * If address string is present and that string is not the "localhost" * loopback, then we will listen on resolved address only. * * If address string is NULL or is "localhost" we will listen on all * address families that will resolve on the host. * * If port requested is 0, we will let the system assign the first * available port. * * If address string is NULL and port requested is not 0, we will listen * on any address for all resolved protocols for the port requested. * * If address string is "localhost" and port is 0, we will use the first * port we are given if the host supports multiple address families. * If by chance we try to bind on a port that is available for one * protocol and not the other, we will attempt a second time with the * order of address families reversed. * * If address string is NULL, port cannot be 0. * * Results: * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket/s, binds and listens. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_Listen(const char *addrStr, // IN: optional unsigned int port, // IN: optional AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { if (addrStr != NULL && *addrStr != '\0' && Str_Strcmp(addrStr, "localhost")) { AsyncTCPSocket *asock; asock = AsyncTCPSocketListenerCreateImpl(addrStr, port, AF_UNSPEC, connectFn, clientData, pollParams, outError); return BaseSocket(asock); } else { Bool localhost = addrStr != NULL && !Str_Strcmp(addrStr, "localhost"); unsigned int tempPort = port; AsyncTCPSocket *asock6 = NULL; AsyncTCPSocket *asock4 = NULL; int tempError4; int tempError6; asock6 = AsyncTCPSocketListenerCreateImpl(addrStr, port, AF_INET6, connectFn, clientData, pollParams, &tempError6); if (localhost && port == 0) { tempPort = AsyncSocket_GetPort(BaseSocket(asock6)); if (tempPort == MAX_UINT32) { Log(ASOCKPREFIX "Could not resolve IPv6 listener socket port number.\n"); tempPort = port; } } asock4 = AsyncTCPSocketListenerCreateImpl(addrStr, tempPort, AF_INET, connectFn, clientData, pollParams, &tempError4); if (localhost && port == 0 && tempError4 == ASOCKERR_BINDADDRINUSE) { Log(ASOCKPREFIX "Failed to reuse IPv6 localhost port number for IPv4 " "listener socket.\n"); AsyncSocket_Close(BaseSocket(asock6)); tempError4 = ASOCKERR_SUCCESS; asock4 = AsyncTCPSocketListenerCreateImpl(addrStr, port, AF_INET, connectFn, clientData, pollParams, &tempError4); tempPort = AsyncSocket_GetPort(BaseSocket(asock4)); if (tempPort == MAX_UINT32) { Log(ASOCKPREFIX "Could not resolve IPv4 listener socket port number.\n"); tempPort = port; } tempError6 = ASOCKERR_SUCCESS; asock6 = AsyncTCPSocketListenerCreateImpl(addrStr, tempPort, AF_INET6, connectFn, clientData, pollParams, &tempError6); if (!asock6 && tempError6 == ASOCKERR_BINDADDRINUSE) { Log(ASOCKPREFIX "Failed to reuse IPv4 localhost port number for " "IPv6 listener socket.\n"); AsyncSocket_Close(BaseSocket(asock4)); } } if (asock6 && asock4) { AsyncTCPSocket *asock; asock = AsyncTCPSocketCreate(pollParams); AsyncTCPSocketSetState(asock, AsyncSocketListening); asock->listenAsock6 = asock6; asock->listenAsock4 = asock4; AsyncSocket_SetErrorFn(BaseSocket(asock4), AsyncTCPSocketListenerError, asock); AsyncSocket_SetErrorFn(BaseSocket(asock6), AsyncTCPSocketListenerError, asock); return BaseSocket(asock); } else if (asock6) { return BaseSocket(asock6); } else if (asock4) { return BaseSocket(asock4); } if (outError) { /* Client only gets one error and the one for IPv6 is favored. */ if (!asock6) { *outError = tempError6; } else if (!asock4) { *outError = tempError4; } else { *outError = ASOCKERR_LISTEN; } } return NULL; } } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketListenerCreateLoopback -- * * Listens on loopback interface and port for all resolved socket * families and accepts new connections. Fires the connect callback with * new AsyncTCPSocket object for each connection. * * Results: * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket/s, binds and listens. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_ListenLoopback(unsigned int port, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { AsyncTCPSocket *asock6 = NULL; AsyncTCPSocket *asock4 = NULL; int tempError4; int tempError6; /* * "localhost6" does not work on Windows. "localhost" does * not work for IPv6 on old Linux versions like 2.6.18. So, * using IP address for both the cases to be consistent. */ asock6 = AsyncTCPSocketListenerCreateImpl("::1", port, AF_INET6, connectFn, clientData, pollParams, &tempError6); asock4 = AsyncTCPSocketListenerCreateImpl("127.0.0.1", port, AF_INET, connectFn, clientData, pollParams, &tempError4); if (asock6 && asock4) { AsyncTCPSocket *asock; asock = AsyncTCPSocketCreate(pollParams); AsyncTCPSocketSetState(asock, AsyncSocketListening); asock->listenAsock6 = asock6; asock->listenAsock4 = asock4; return BaseSocket(asock); } else if (asock6) { return BaseSocket(asock6); } else if (asock4) { return BaseSocket(asock4); } if (outError) { /* Client only gets one error and the one for IPv6 is favored. */ if (!asock6) { *outError = tempError6; } else if (!asock4) { *outError = tempError4; } else { *outError = ASOCKERR_LISTEN; } } return NULL; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocket_ListenVMCI -- * * Listens on the specified port and accepts new connections. Fires the * connect callback with new AsyncTCPSocket object for each connection. * * Results: * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket, binds and listens. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_ListenVMCI(unsigned int cid, // IN unsigned int port, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { struct sockaddr_vm addr; AsyncTCPSocket *asock; int vsockDev = -1; int tempError = ASOCKERR_SUCCESS; memset(&addr, 0, sizeof addr); addr.svm_family = VMCISock_GetAFValueFd(&vsockDev); addr.svm_cid = cid; addr.svm_port = port; asock = AsyncTCPSocketListenImpl((struct sockaddr_storage *)&addr, sizeof addr, connectFn, clientData, pollParams, &tempError); if (outError) { *outError = tempError; } VMCISock_ReleaseAFValueFd(vsockDev); return BaseSocket(asock); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketInit -- * * This is an internal routine that sets up a SOCK_STREAM (TCP) socket. * * Results: * New AsyncTCPSocket or NULL on error. * * Side effects: * Creates new socket. * *---------------------------------------------------------------------------- */ static AsyncTCPSocket * AsyncTCPSocketInit(int socketFamily, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT { AsyncTCPSocket *asock = NULL; int error = ASOCKERR_GENERIC; int sysErr; int fd; /* * Create a new socket */ if ((fd = socket(socketFamily, SOCK_STREAM, 0)) == -1) { sysErr = ASOCK_LASTERROR(); Warning(ASOCKPREFIX "could not create new socket, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); goto errorNoFd; } /* * Wrap it with an asock object */ if ((asock = AsyncTCPSocketAttachToFd(fd, pollParams, &error)) == NULL) { goto error; } return asock; error: SSLGeneric_close(fd); errorNoFd: if (outError) { *outError = error; } return NULL; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetPortFromAddr -- * * This is an internal routine that gets a port given an address. The * address must be in either AF_INET, AF_INET6 or AF_VMCI format. * * Results: * Port number (in host byte order for INET). * * Side effects: * None. * *---------------------------------------------------------------------------- */ static unsigned int AsyncTCPSocketGetPortFromAddr(struct sockaddr_storage *addr) // IN { ASSERT(NULL != addr); if (AF_INET == addr->ss_family) { return ntohs(((struct sockaddr_in *)addr)->sin_port); } else if (AF_INET6 == addr->ss_family) { return ntohs(((struct sockaddr_in6 *)addr)->sin6_port); #ifndef _WIN32 } else if (AF_UNIX == addr->ss_family) { return MAX_UINT32; // Not applicable #endif } else { #ifdef VMX86_DEBUG int vsockDev = -1; ASSERT(VMCISock_GetAFValueFd(&vsockDev) == addr->ss_family); VMCISock_ReleaseAFValueFd(vsockDev); #endif return ((struct sockaddr_vm *)addr)->svm_port; } } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetPort -- * * Given an AsyncTCPSocket object, returns the port number associated with * the requested address family's file descriptor if available. * * Results: * Port number in host byte order. MAX_UINT32 on error. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static unsigned int AsyncTCPSocketGetPort(AsyncSocket *base) // IN { AsyncTCPSocket *asock = TCPSocket(base); AsyncTCPSocket *tempAsock; struct sockaddr_storage addr; socklen_t addrLen = sizeof addr; unsigned int ret = MAX_UINT32; if (asock->fd != -1) { tempAsock = asock; } else if (asock->listenAsock6 && asock->listenAsock6->fd != -1) { tempAsock = asock->listenAsock6; } else if (asock->listenAsock4 && asock->listenAsock4->fd != -1) { tempAsock = asock->listenAsock4; } else { return ret; } ASSERT(AsyncTCPSocketIsLocked(asock)); ASSERT(AsyncTCPSocketIsLocked(tempAsock)); if (AsyncTCPSocketGetAddr(tempAsock, AF_UNSPEC, &addr, &addrLen) == ASOCKERR_SUCCESS) { return AsyncTCPSocketGetPortFromAddr(&addr); } else { return MAX_UINT32; } return ret; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketOSVersionSupportsV4Mapped -- * * Determine if runtime environment supports IPv4-mapped IPv6 addressed * and all the functionality needed to deal with this scenario. * * Results: * Returns TRUE if supported. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static Bool AsyncTCPSocketOSVersionSupportsV4Mapped(void) { #if defined(_WIN32) && !defined(VM_WIN_UWP) OSVERSIONINFOW osvi = {sizeof(OSVERSIONINFOW)}; /* * Starting with msvc-12.0 / SDK v8.1 GetVersionEx is deprecated. * Bug 1259185 tracks switching to VerifyVersionInfo. */ #pragma warning(suppress : 4996) // 'function': was declared deprecated GetVersionExW(&osvi); /* Windows version is at least Vista or higher */ return osvi.dwMajorVersion >= 6; #else return TRUE; #endif } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketBind -- * * This is an internal routine that binds a socket to a port. * * Results: * Returns TRUE upon success, FALSE upon failure. * * Side effects: * Socket is bound to a particular port. * *---------------------------------------------------------------------------- */ static Bool AsyncTCPSocketBind(AsyncTCPSocket *asock, // IN struct sockaddr_storage *addr, // IN socklen_t addrLen, // IN int *outError) // OUT { int sysErr; unsigned int port; ASSERT(NULL != asock); ASSERT(NULL != asock->sslSock); ASSERT(NULL != addr); port = AsyncTCPSocketGetPortFromAddr(addr); TCPSOCKLG0(asock, "creating new listening socket on port %d\n", port); #ifndef _WIN32 /* * Don't ever use SO_REUSEADDR on Windows; it doesn't mean what you think * it means. */ if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6) { int reuse = port != 0; if (setsockopt(asock->fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(reuse)) != 0) { sysErr = ASOCK_LASTERROR(); Warning(ASOCKPREFIX "could not set SO_REUSEADDR, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); } } #else /* * Always set SO_EXCLUSIVEADDRUSE on Windows, to prevent other applications * from stealing this socket. (Yes, Windows is that stupid). */ { int exclusive = 1; if (setsockopt(asock->fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const void *) &exclusive, sizeof(exclusive)) != 0) { sysErr = ASOCK_LASTERROR(); Warning(ASOCKPREFIX "could not set SO_EXCLUSIVEADDRUSE, error %d: " "%s\n", sysErr, Err_Errno2String(sysErr)); } } #endif #if defined(IPV6_V6ONLY) /* * WINDOWS: By default V4MAPPED was not supported until Windows Vista. * IPV6_V6ONLY was disabled by default until Windows 7. So if we are binding * to a AF_INET6 socket and IPV6_V6ONLY existed, we need to turn it on no * matter what the setting is to disable V4 mapping. * * MAC OSX: Support for IPV6_V6ONLY can be found in 10.5+. * * LINUX: IPV6_V6ONLY was released after V4MAPPED was implemented. There is * no way to turn V4MAPPED off on those systems. The default behavior * differs from distro-to-distro so attempt to turn V4MAPPED off on all * systems that have IPV6_V6ONLY define. There is no good solution for the * case where we cannot enable IPV6_V6ONLY, if we error in this case and do * not have a IPv4 option then we render the application useless. * See AsyncTCPSocketAcceptInternal for the IN6_IS_ADDR_V4MAPPED validation * for incomming addresses to close this loophole. */ if (addr->ss_family == AF_INET6 && AsyncTCPSocketOSVersionSupportsV4Mapped()) { int on = 1; if (setsockopt(asock->fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *) &on, sizeof(on)) != 0) { Warning(ASOCKPREFIX "Cannot set IPV6_V6ONLY socket option.\n"); } } #else #error No compiler definition for IPV6_V6ONLY #endif /* * Bind to a port */ if (bind(asock->fd, (struct sockaddr *)addr, addrLen) != 0) { sysErr = ASOCK_LASTERROR(); if (sysErr == ASOCK_EADDRINUSE) { *outError = ASOCKERR_BINDADDRINUSE; } Warning(ASOCKPREFIX "Could not bind socket, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); goto error; } return TRUE; error: SSL_Shutdown(asock->sslSock); free(asock); return FALSE; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketListen -- * * This is an internal routine that calls listen() on a socket. * * Results: * Returns TRUE upon success, FALSE upon failure. * * Side effects: * Socket is in listening state. * *---------------------------------------------------------------------------- */ static Bool AsyncTCPSocketListen(AsyncTCPSocket *asock, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN int *outError) // OUT { VMwareStatus pollStatus; ASSERT(NULL != asock); ASSERT(NULL != asock->sslSock); if (!connectFn) { Warning(ASOCKPREFIX "invalid arguments to listen!\n"); *outError = ASOCKERR_INVAL; goto error; } /* * Listen on the socket */ if (listen(asock->fd, 5) != 0) { int sysErr = ASOCK_LASTERROR(); Warning(ASOCKPREFIX "could not listen on socket, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); *outError = ASOCKERR_LISTEN; goto error; } /* * Register a read callback to fire each time the socket * is ready for accept. */ AsyncTCPSocketLock(asock); pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_READ | POLL_FLAG_PERIODIC, AsyncTCPSocketAcceptCallback); if (pollStatus != VMWARE_STATUS_SUCCESS) { TCPSOCKWARN(asock, "could not register accept callback!\n"); *outError = ASOCKERR_POLL; AsyncTCPSocketUnlock(asock); goto error; } AsyncTCPSocketSetState(asock, AsyncSocketListening); asock->connectFn = connectFn; asock->clientData = clientData; AsyncTCPSocketUnlock(asock); return TRUE; error: SSL_Shutdown(asock->sslSock); free(asock); return FALSE; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketConnectImpl -- * * AsyncTCPSocket AF_INET/AF_INET6 connect. * * NOTE: This function can block. * * Results: * AsyncTCPSocket * on success and NULL on failure. * On failure, error is returned in *outError. * * Side effects: * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ static AsyncTCPSocket * AsyncTCPSocketConnectImpl(int socketFamily, // IN const char *hostname, // IN unsigned int port, // IN int tcpSocketFd, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketConnectFlags flags, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { struct sockaddr_storage addr; int getaddrinfoError; int error; AsyncTCPSocket *asock; char *ipString = NULL; socklen_t addrLen; /* * Resolve the hostname. Handles dotted decimal strings, too. */ getaddrinfoError = AsyncTCPSocketResolveAddr(hostname, port, socketFamily, FALSE, &addr, &addrLen, &ipString); if (0 != getaddrinfoError) { Log(ASOCKPREFIX "Failed to resolve %s address '%s' and port %u\n", socketFamily == AF_INET ? "IPv4" : "IPv6", hostname, port); error = ASOCKERR_ADDRUNRESV; goto error; } Log(ASOCKPREFIX "creating new %s socket, connecting to %s (%s)\n", socketFamily == AF_INET ? "IPv4" : "IPv6", ipString, hostname); free(ipString); asock = AsyncTCPSocketConnect(&addr, addrLen, tcpSocketFd, connectFn, clientData, flags, pollParams, &error); if (!asock) { Warning(ASOCKPREFIX "%s connection attempt failed: %s\n", socketFamily == AF_INET ? "IPv4" : "IPv6", AsyncSocket_MsgError(error)); goto error; } return asock; error: if (outError) { *outError = error; } return NULL; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocket_Connect -- * * AsyncTCPSocket connect. Connection is attempted with AF_INET socket * family, when that fails AF_INET6 is attempted. * * NOTE: This function can block. * * Results: * AsyncTCPSocket * on success and NULL on failure. * On failure, error is returned in *outError. * * Side effects: * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_Connect(const char *hostname, // IN unsigned int port, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketConnectFlags flags, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { return AsyncSocket_ConnectWithFd(hostname, port, -1, connectFn, clientData, flags, pollParams, outError); } /* *---------------------------------------------------------------------------- * * AsyncSocket_ConnectWithFd -- * * AsyncTCPSocket connect using an existing socket descriptor. * Connection is attempted with AF_INET socket * family, when that fails AF_INET6 is attempted. * * Limitation: The ConnectWithFd functionality is currently Windows only. * Non-Windows platforms & windows-UWP are not supported. * * Results: * AsyncTCPSocket * on success and NULL on failure. * On failure, error is returned in *outError. * * Side effects: * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_ConnectWithFd(const char *hostname, // IN unsigned int port, // IN int tcpSocketFd, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketConnectFlags flags, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { int error = ASOCKERR_CONNECT; AsyncTCPSocket *asock = NULL; if (!connectFn || !hostname) { error = ASOCKERR_INVAL; Warning(ASOCKPREFIX "invalid arguments to connect!\n"); goto error; } asock = AsyncTCPSocketConnectImpl(AF_INET, hostname, port, tcpSocketFd, connectFn, clientData, flags, pollParams, &error); if (!asock) { asock = AsyncTCPSocketConnectImpl(AF_INET6, hostname, port, tcpSocketFd, connectFn, clientData, flags, pollParams, &error); } error: if (!asock && outError) { *outError = error; } return BaseSocket(asock); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocket_ConnectVMCI -- * * AsyncTCPSocket AF_VMCI constructor. Connects to the specified cid:port, * and passes the caller a valid asock via the callback once the * connection has been established. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_ConnectVMCI(unsigned int cid, // IN unsigned int port, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketConnectFlags flags, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { int vsockDev = -1; struct sockaddr_vm addr; AsyncTCPSocket *asock; memset(&addr, 0, sizeof addr); addr.svm_family = VMCISock_GetAFValueFd(&vsockDev); addr.svm_cid = cid; addr.svm_port = port; Log(ASOCKPREFIX "creating new socket, connecting to %u:%u\n", cid, port); asock = AsyncTCPSocketConnect((struct sockaddr_storage *)&addr, sizeof addr, -1, connectFn, clientData, flags, pollParams, outError); VMCISock_ReleaseAFValueFd(vsockDev); return BaseSocket(asock); } #ifndef _WIN32 /* *---------------------------------------------------------------------------- * * AsyncSocket_ConnectUnixDomain -- * * AsyncTCPSocket AF_UNIX constructor. Connects to the specified unix socket, * and passes the caller a valid asock via the callback once the * connection has been established. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_ConnectUnixDomain(const char *path, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketConnectFlags flags, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT { struct sockaddr_un addr; AsyncTCPSocket *asock; memset(&addr, 0, sizeof addr); addr.sun_family = AF_UNIX; if (strlen(path) + 1 > sizeof addr.sun_path) { Warning(ASOCKPREFIX "Path '%s' is too long for a unix domain socket!\n", path); return NULL; } Str_Strcpy(addr.sun_path, path, sizeof addr.sun_path); Log(ASOCKPREFIX "creating new socket, connecting to %s\n", path); asock = AsyncTCPSocketConnect((struct sockaddr_storage *)&addr, sizeof addr, -1, connectFn, clientData, flags, pollParams, outError); return asock ? BaseSocket(asock) : NULL; } #endif /* *---------------------------------------------------------------------------- * * AsyncTCPSocketConnectErrorCheck -- * * Check for error on a connecting socket and fire the connect callback * is any error is found. This is only used on Windows. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketConnectErrorCheck(void *data) // IN: AsyncTCPSocket * { AsyncTCPSocket *asock = data; Bool removed; PollerFunction func = NULL; ASSERT(AsyncTCPSocketIsLocked(asock)); if (AsyncTCPSocketGetState(asock) == AsyncSocketConnecting) { int sockErr = 0; int sockErrLen = sizeof sockErr; if (getsockopt(asock->fd, SOL_SOCKET, SO_ERROR, (void *)&sockErr, (void *)&sockErrLen) == 0) { if (sockErr == 0) { /* There is no error; keep waiting. */ return; } asock->genericErrno = sockErr; } else { asock->genericErrno = ASOCK_LASTERROR(); } TCPSOCKLG0(asock, "Connection failed: %s\n", Err_Errno2String(asock->genericErrno)); /* Remove connect callback. */ removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, asock->internalConnectFn); ASSERT(removed); func = asock->internalConnectFn; } /* Remove this callback. */ removed = AsyncTCPSocketPollRemove(asock, FALSE, POLL_FLAG_PERIODIC, AsyncTCPSocketConnectErrorCheck); ASSERT(removed); asock->internalConnectFn = NULL; if (func) { func(asock); } } /* *---------------------------------------------------------------------------- * * SocketProtocolAndTypeMatches -- * * Discover whether a given socket has the specified protocol family * (PF_INET, PF_INET6, ...) and data transfer type (SOCK_STREAM, * SOCK_DGRAM, ...). * * For now, this is supported only on non-UWP Windows platforms. * Other platforms always receive a FALSE result. * * Results: * True if the socket has the specified family and type, false * otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static Bool SocketProtocolAndTypeMatches(int socketFd, // IN int protocol, // IN int type) // IN { #if defined( _WIN32) && !defined(VM_WIN_UWP) int ret; WSAPROTOCOL_INFO protocolInfo; int protocolInfoLen = sizeof protocolInfo; ret = getsockopt(socketFd, SOL_SOCKET, SO_PROTOCOL_INFO, (void*)&protocolInfo, &protocolInfoLen); if (ret != 0) { Warning(ASOCKPREFIX "SO_PROTOCOL_INFO failed on sockFd %d, ", "error 0x%x\n", socketFd, ASOCK_LASTERROR()); return FALSE; } /* * Windows is confused about protocol families (the "domain" of the * socket, passed as the first argument to the socket() call) and * address families (specified in the xx_family member of a sockaddr_xx * argument passed to bind()). The protocol family of the socket is * reported in the iAddressFamily of the WSAPROTOCOL_INFO structure. */ return ((protocol == protocolInfo.iAddressFamily) && (type == protocolInfo.iSocketType)); #else /* * If we need to implement this for other platforms then we can use * getsockopt(SO_TYPE) to retrieve the socket type, and on Linux we can * use getsockopt(SO_DOMAIN) to retrieve the protocol family, but other * platforms might not have SO_DOMAIN. On those platforms we might be * able to infer the protocol family by attempting sockopt calls that * only work on certain families. * * BTW, Linux has thrown in the towel on the distinction between * protocol families and address families. Its socket() man page shows * AF_* literals being used for the 'domain' argument instead of PF_* * literals. This works because AF_XX is defined to have the same * numeric value as PF_XX for all values of XX. */ Warning(ASOCKPREFIX "discovery of socket protocol and type is " "not implemented on this platform\n"); NOT_IMPLEMENTED(); #endif // defined(_WIN32) } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketConnect -- * * Internal AsyncTCPSocket constructor. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ static AsyncTCPSocket * AsyncTCPSocketConnect(struct sockaddr_storage *addr, // IN socklen_t addrLen, // IN int socketFd, // IN: optional AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketConnectFlags flags, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT { int fd; VMwareStatus pollStatus; AsyncTCPSocket *asock = NULL; int error = ASOCKERR_GENERIC; int sysErr; ASSERT(addr); if (!connectFn) { error = ASOCKERR_INVAL; Warning(ASOCKPREFIX "invalid arguments to connect!\n"); goto error; } /* * If we were given a socket, verify that it is of the required * protocol family and type before using it. If no socket was given, * create a new socket of the appropriate family. (For the sockets * we care about, the required protocol family is numerically the * same as the address family provided in the given destination * sockaddr, so we can use addr->ss_family whenever we need to * specify a protocol family.) * * For now, passing in a socket is supported only on non-UWP Windows * platforms. The SocketProtocolAndTypeMatches() call will fail on * other platforms. */ if (-1 != socketFd) { int protocolFamily = addr->ss_family; // XXX Logging here is excessive, remove after testing if (SocketProtocolAndTypeMatches(socketFd, protocolFamily, SOCK_STREAM)) { Warning(ASOCKPREFIX "using passed-in socket, family %d\n", protocolFamily); fd = socketFd; } else { Warning(ASOCKPREFIX "rejecting passed-in socket, wanted family %d\n", protocolFamily); error = ASOCKERR_INVAL; goto error; } } else if ((fd = socket(addr->ss_family, SOCK_STREAM, 0)) == -1) { sysErr = ASOCK_LASTERROR(); Warning(ASOCKPREFIX "failed to create socket, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); error = ASOCKERR_CONNECT; goto error; } /* * Wrap it with an asock */ if ((asock = AsyncTCPSocketAttachToFd(fd, pollParams, &error)) == NULL) { SSLGeneric_close(fd); goto error; } /* * Call connect(), which can either succeed immediately or return an error * indicating that the connection is in progress. In the latter case, we * can poll the fd for write to find out when the connection attempt * has succeeded (or failed). In either case, we want to invoke the * caller's connect callback from Poll rather than directly, so if the * connection succeeds immediately, we just schedule the connect callback * as a one-time (RTime) callback instead. */ AsyncTCPSocketLock(asock); if (connect(asock->fd, (struct sockaddr *)addr, addrLen) != 0) { if (ASOCK_LASTERROR() == ASOCK_ECONNECTING) { TCPSOCKLOG(1, asock, "registering write callback for socket connect\n"); pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_WRITE, AsyncTCPSocketConnectCallback); if (vmx86_win32 && pollStatus == VMWARE_STATUS_SUCCESS && AsyncTCPSocketPollParams(asock)->iPoll == NULL) { /* * Work around WSAPoll's bug of not reporting failed connection * by periodically (500 ms) checking for error. */ pollStatus = AsyncTCPSocketPollAdd(asock, FALSE, POLL_FLAG_PERIODIC, AsyncTCPSocketConnectErrorCheck, 500 * 1000); if (pollStatus == VMWARE_STATUS_SUCCESS) { asock->internalConnectFn = AsyncTCPSocketConnectCallback; } else { TCPSOCKLG0(asock, "failed to register periodic error check\n"); AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, AsyncTCPSocketConnectCallback); } } } else { sysErr = ASOCK_LASTERROR(); Log(ASOCKPREFIX "connect failed, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); /* * If "network unreachable" or "No route to host" * errors happens, explicitly propogate * the error to trigger the reconnection if possible. */ error = (sysErr == ASOCK_ENETUNREACH || sysErr == ASOCK_EHOSTUNREACH) ? ASOCKERR_NETUNREACH : ASOCKERR_CONNECT; goto errorHaveAsock; } } else { TCPSOCKLOG(2, asock, "socket connected, registering RTime callback for connect\n"); pollStatus = AsyncTCPSocketPollAdd(asock, FALSE, 0, AsyncTCPSocketConnectCallback, 0); } if (pollStatus != VMWARE_STATUS_SUCCESS) { TCPSOCKWARN(asock, "failed to register callback in connect!\n"); error = ASOCKERR_POLL; goto errorHaveAsock; } AsyncTCPSocketSetState(asock, AsyncSocketConnecting); asock->connectFn = connectFn; asock->clientData = clientData; /* Store a copy of the sockaddr_storage so we can look it up later. */ memcpy(&(asock->remoteAddr), addr, addrLen); asock->remoteAddrLen = addrLen; AsyncTCPSocketUnlock(asock); return asock; errorHaveAsock: SSL_Shutdown(asock->sslSock); AsyncTCPSocketUnlock(asock); free(asock); error: if (outError) { *outError = error; } return NULL; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketCreate -- * * AsyncSocket constructor for fields common to all TCP-based * AsyncSocket types. * * Results: * New AsyncSocket object. * * Side effects: * Allocates memory. * *---------------------------------------------------------------------------- */ static AsyncTCPSocket * AsyncTCPSocketCreate(AsyncSocketPollParams *pollParams) // IN { AsyncTCPSocket *s; s = Util_SafeCalloc(1, sizeof *s); AsyncSocketInitSocket(BaseSocket(s), pollParams, &asyncTCPSocketVTable); s->fd = -1; s->inRecvLoop = FALSE; s->sendBufFull = FALSE; s->sendBufTail = &(s->sendBufList); s->passFd.fd = -1; if (pollParams && pollParams->iPoll) { s->internalSendFn = AsyncTCPSocketIPollSendCallback; s->internalRecvFn = AsyncTCPSocketIPollRecvCallback; } else { s->internalSendFn = AsyncTCPSocketSendCallback; s->internalRecvFn = AsyncTCPSocketRecvCallback; } return s; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketAttachToSSLSock -- * * AsyncTCPSocket constructor. Wraps an existing SSLSock object with an * AsyncTCPSocket and returns the latter. * * Results: * New AsyncTCPSocket object or NULL on error. * * Side effects: * Allocates memory, makes the underlying fd for the socket non-blocking. * *---------------------------------------------------------------------------- */ static AsyncTCPSocket * AsyncTCPSocketAttachToSSLSock(SSLSock sslSock, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT { AsyncTCPSocket *s; int fd; int error; ASSERT(sslSock); fd = SSL_GetFd(sslSock); if ((AsyncTCPSocketMakeNonBlocking(fd)) != ASOCKERR_SUCCESS) { int sysErr = ASOCK_LASTERROR(); Warning(ASOCKPREFIX "failed to make fd %d non-blocking!: %d, %s\n", fd, sysErr, Err_Errno2String(sysErr)); error = ASOCKERR_GENERIC; goto error; } s = AsyncTCPSocketCreate(pollParams); AsyncTCPSocketSetState(s, AsyncSocketConnected); s->sslSock = sslSock; s->fd = fd; /* From now on socket is ours. */ SSL_SetCloseOnShutdownFlag(sslSock); TCPSOCKLOG(1, s, "new asock id %u attached to fd %d\n", s->base.id, s->fd); return s; error: if (outError) { *outError = error; } return NULL; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketAttachToFd -- * * AsyncTCPSocket constructor. Wraps a valid socket fd with an * AsyncTCPSocket object. * * Results: * New AsyncTCPSocket or NULL on error. * * Side effects: * If function succeeds, fd is owned by AsyncTCPSocket and should not be * used (f.e. closed) anymore. * *---------------------------------------------------------------------------- */ static AsyncTCPSocket * AsyncTCPSocketAttachToFd(int fd, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT { SSLSock sslSock; AsyncTCPSocket *asock; /* * Create a new SSL socket object with the current socket */ if (!(sslSock = SSL_New(fd, FALSE))) { if (outError) { *outError = ENOMEM; } LOG(0, ASOCKPREFIX "failed to create SSL socket object\n"); return NULL; } asock = AsyncTCPSocketAttachToSSLSock(sslSock, pollParams, outError); if (asock) { return asock; } SSL_Shutdown(sslSock); return NULL; } /* *---------------------------------------------------------------------------- * * AsyncSocket_AttachToFd -- * * Wrap a pre-existing file descriptor in an AsyncSocket entity. * * Results: * New AsyncSocket or NULL on error. * * Side effects: * If function succeeds, fd is owned by AsyncSocket and should not be * used (f.e. closed) anymore. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_AttachToFd(int fd, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT { AsyncTCPSocket *asock; asock = AsyncTCPSocketAttachToFd(fd, pollParams, outError); return BaseSocket(asock); } /* *---------------------------------------------------------------------------- * * AsyncSocket_AttachToSSLSock -- * * Wrap a pre-existing SSLSock in an AsyncSocket entity. * * Results: * New AsyncSocket or NULL on error. * * Side effects: * If function succeeds, fd is owned by AsyncSocket and should not be * used (f.e. closed) anymore. * *---------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_AttachToSSLSock(SSLSock sslSock, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT { AsyncTCPSocket *asock; asock = AsyncTCPSocketAttachToSSLSock(sslSock, pollParams, outError); return BaseSocket(asock); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketRegisterRecvCb -- * * Register poll callbacks as required to be notified when data is ready * following a AsyncTCPSocket_Recv call. * * Results: * ASOCKERR_*. * * Side effects: * Could register poll callback. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketRegisterRecvCb(AsyncTCPSocket *asock) // IN: { int retVal = ASOCKERR_SUCCESS; Bool peek = asock->flags & ASOCK_FLAG_PEEK; if (!asock->recvCb) { VMwareStatus pollStatus; /* * Register the Poll callback */ TCPSOCKLOG(3, asock, "installing %s periodic poll callback\n", peek ? "peek" : "recv"); pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_READ | POLL_FLAG_PERIODIC, asock->internalRecvFn); if (pollStatus != VMWARE_STATUS_SUCCESS) { TCPSOCKWARN(asock, "failed to install %s callback!\n", peek ? "peek" : "recv"); retVal = ASOCKERR_POLL; goto out; } asock->recvCb = TRUE; } /* * !peek comes before other checks because SSL may not be initialized for * peeks, and also because peek ignores data buffered in SSL. */ if (!peek && AsyncTCPSocketHasDataPending(asock) && !asock->inRecvLoop) { TCPSOCKLOG(0, asock, "installing recv RTime poll callback\n"); if (AsyncTCPSocketPollAdd(asock, FALSE, 0, asock->internalRecvFn, 0) != VMWARE_STATUS_SUCCESS) { retVal = ASOCKERR_POLL; goto out; } asock->recvCbTimer = TRUE; } out: return retVal; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocket_Recv -- * * Registers a callback that will fire once the specified amount of data * has been received on the socket. * * In the case of AsyncTCPSocket_RecvPartial, the callback is fired * once all or part of the data has been received on the socket. * * Data that was not retrieved at the last call of SSL_read() could still * be buffered inside the SSL layer and will be retrieved on the next * call to SSL_read(). However poll/select might not mark the socket as * for reading since there might not be any data in the underlying network * socket layer. Hence in the read callback, we keep spinning until all * all the data buffered inside the SSL layer is retrieved before * returning to the poll loop (See AsyncTCPSocketFillRecvBuffer()). * * However, we might not have come out of Poll in the first place, e.g. * if this is the first call to AsyncTCPSocket_Recv() after creating a new * connection. In this situation, if there is buffered SSL data pending, * we have to schedule an RTTime callback to force retrieval of the data. * This could also happen if the client calls AsyncTCPSocket_RecvBlocking, * some data is left in the SSL layer, and the client then calls * AsyncTCPSocket_Recv. We use the inRecvLoop variable to detect and handle * this condition, i.e., if inRecvLoop is FALSE, we need to schedule the * RTime callback. * * TCP usage: * AsyncTCPSocket_Recv(AsyncTCPSocket *asock, * void *buf, * int len, * AsyncSocketRecvFn recvFn, * void *clientData) * * Results: * ASOCKERR_*. * * Side effects: * Could register poll callback. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketRecv(AsyncSocket *base, // IN: void *buf, // IN: unused int len, // IN: unused Bool fireOnPartial, // IN: void *cb, // IN: void *cbData) // IN: { AsyncTCPSocket *asock = TCPSocket(base); int retVal; if (!asock->base.errorFn) { TCPSOCKWARN(asock, "%s: no registered error handler!\n", __FUNCTION__); return ASOCKERR_INVAL; } /* * XXX We might want to allow passing NULL for the recvFn, to indicate that * the client is no longer interested in reading from the socket. This * would be useful e.g. for HTTP, where the client sends a request and * then the client->server half of the connection is closed. */ if (!buf || !cb || len <= 0) { Warning(ASOCKPREFIX "Recv called with invalid arguments!\n"); return ASOCKERR_INVAL; } ASSERT(AsyncTCPSocketIsLocked(asock)); if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) { TCPSOCKWARN(asock, "recv called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } if (asock->inBlockingRecv && !asock->inRecvLoop) { TCPSOCKWARN(asock, "Recv called while a blocking recv is pending.\n"); return ASOCKERR_INVAL; } /* * Reset peek flag which may be set from previous peek(), to stop peeking. * This is the only place we need to reset it. */ asock->flags &= ~ASOCK_FLAG_PEEK; retVal = AsyncTCPSocketRegisterRecvCb(asock); if (retVal != ASOCKERR_SUCCESS) { return retVal; } AsyncSocketSetRecvBuf(BaseSocket(asock), buf, len, fireOnPartial, cb, cbData); return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketRecvPassedFd -- * * See AsyncTCPSocket_Recv. Besides that it allows for receiving one * file descriptor... * * Results: * ASOCKERR_*. * * Side effects: * Could register poll callback. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketRecvPassedFd(AsyncSocket *base, // IN/OUT: socket void *buf, // OUT: buffer with data int len, // IN: length void *cb, // IN: completion calback void *cbData) // IN: callback's data { AsyncTCPSocket *asock = TCPSocket(base); int err; if (!asock->base.errorFn) { TCPSOCKWARN(asock, "%s: no registered error handler!\n", __FUNCTION__); return ASOCKERR_INVAL; } ASSERT(AsyncTCPSocketIsLocked(asock)); if (asock->passFd.fd != -1) { SSLGeneric_close(asock->passFd.fd); asock->passFd.fd = -1; } asock->passFd.expected = TRUE; err = AsyncTCPSocketRecv(BaseSocket(asock), buf, len, FALSE, cb, cbData); if (err != ASOCKERR_SUCCESS) { asock->passFd.expected = FALSE; } return err; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketPeek -- * * Peek into the socket buffer. Similar to AsyncTCPSocketRecv except that * this routine does not assume SSL state is initialized for the socket. * Unlike recv, peek does not consider data buffered in the SSL layer. So * peek() is only useful pre-SSL. This is in contrast to tcp asyncsocket * recv() that only does SSL_Read; hence recv() is only suitable post-SSL. * * ASOCK_FLAG_PEEK flag is reset in recv() prior to callback registration. * * Results: * ASOCKERR_*. * * Side effects: * Could register poll callback. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketPeek(AsyncSocket *base, // IN: void *buf, // IN: unused int len, // IN: unused void *cb, // IN: void *cbData) // IN: { AsyncTCPSocket *asock = TCPSocket(base); int retVal; ASSERT(AsyncTCPSocketIsLocked(asock)); // Disallow peek with pending blocking recv if (UNLIKELY(asock->inBlockingRecv && !asock->inRecvLoop)) { TCPSOCKWARN(asock, "%s: Cannot peek due to blocking recv\n", __FUNCTION__); return ASOCKERR_BUSY; } /* * Disallow peek while in recv callback. We can support this if needed in * future just like we allow the reverse today (recv from peek callback). */ if (asock->inRecvLoop && !ASOCK_PEEK(asock)) { TCPSOCKWARN(asock, "%s: Cannot peek from recv callback\n", __FUNCTION__); return ASOCKERR_BUSY; } if (base->pollParams.iPoll != NULL) { Warning(ASOCKPREFIX "Peek not supported for IVmdbPoll!\n"); return ASOCKERR_INVAL; } if (buf == NULL || cb == NULL || len <= 0) { Warning(ASOCKPREFIX "Peek called with invalid arguments!\n"); return ASOCKERR_INVAL; } if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) { TCPSOCKWARN(asock, "peek called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } /* * Set ASOCK_FLAG_PEEK flag to differentiate peek from recv in the common * callback. The flag will be reset on next recv in AsyncTCPSocketRecv. */ asock->flags |= ASOCK_FLAG_PEEK; retVal = AsyncTCPSocketRegisterRecvCb(asock); if (retVal == ASOCKERR_SUCCESS) { AsyncSocketSetRecvBuf(BaseSocket(asock), buf, len, TRUE, cb, cbData); } else { TCPSOCKWARN(asock, "%s: Peek failed with error %d: %s \n", __FUNCTION__, retVal, Err_Errno2String(retVal)); asock->flags &= ~ASOCK_FLAG_PEEK; } return retVal; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketPollWork -- * * Blocks on the specified sockets until there's data pending or a * timeout occurs. * * If the asyncsocket is a dual stack listener, parentSock will not be * NULL, and the asock array will contain the IPv4 and v6 sockets. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call * failures * ASOCKERR_TIMEOUT if we just didn't receive enough data. * * Side effects: * None. *---------------------------------------------------------------------------- */ static int AsyncTCPSocketPollWork(AsyncTCPSocket **asock, // IN: size_t numSock, // IN: void *p, // IN: Bool read, // IN: int timeoutMS, // IN: AsyncTCPSocket *parentSock, // IN: AsyncTCPSocket **outAsock) // OUT: { AsyncTCPSocket *warnSock = parentSock ? parentSock : asock[0]; #ifndef _WIN32 struct pollfd *pfd = (struct pollfd *)p; #else /* * We use select() to do this on Windows, since there ain't no poll(). * Fortunately, select() doesn't have the 1024 fd value limit. */ struct timeval tv; struct fd_set rwfds; struct fd_set exceptfds; #endif size_t i; int retval; ASSERT(outAsock != NULL && *outAsock == NULL && asock != NULL && numSock != 0); for (i = 0; i < numSock; i++) { if (read && SSL_Pending(asock[i]->sslSock)) { *outAsock = asock[i]; return ASOCKERR_SUCCESS; } } while (1) { #ifndef _WIN32 for (i = 0; i < numSock; i++) { pfd[i].fd = asock[i]->fd; pfd[i].events = read ? POLLIN : POLLOUT; } if (parentSock != NULL) { AsyncTCPSocketUnlock(parentSock); retval = poll(pfd, numSock, timeoutMS); AsyncTCPSocketLock(parentSock); } else { for (i = numSock; i-- > 0; ) { AsyncTCPSocketUnlock(asock[i]); } retval = poll(pfd, numSock, timeoutMS); for (i = 0; i < numSock; i++) { AsyncTCPSocketLock(asock[i]); } } #else tv.tv_sec = timeoutMS / 1000; tv.tv_usec = (timeoutMS % 1000) * 1000; FD_ZERO(&rwfds); FD_ZERO(&exceptfds); for (i = 0; i < numSock; i++) { FD_SET(asock[i]->fd, &rwfds); FD_SET(asock[i]->fd, &exceptfds); } if (parentSock != NULL) { AsyncTCPSocketUnlock(parentSock); retval = select(1, read ? &rwfds : NULL, read ? NULL : &rwfds, &exceptfds, timeoutMS >= 0 ? &tv : NULL); AsyncTCPSocketLock(parentSock); } else { for (i = numSock; i-- > 0; ) { AsyncTCPSocketUnlock(asock[i]); } retval = select(1, read ? &rwfds : NULL, read ? NULL : &rwfds, &exceptfds, timeoutMS >= 0 ? &tv : NULL); for (i = 0; i < numSock; i++) { AsyncTCPSocketLock(asock[i]); } } #endif switch (retval) { case 0: /* * No sockets were ready within the specified time. */ TCPSOCKLG0(warnSock, "%s: Timeout waiting for a ready socket.\n", __FUNCTION__); return ASOCKERR_TIMEOUT; case -1: { int sysErr = ASOCK_LASTERROR(); if (sysErr == EINTR) { /* * We were somehow interrupted by signal. Let's loop and retry. * XXX: update the timeout by the amount we had previously waited. */ TCPSOCKLG0(warnSock, "%s: Socket interrupted by a signal.\n", __FUNCTION__); continue; } if (parentSock != NULL) { parentSock->genericErrno = sysErr; } else { for (i = 0; i < numSock; i++) { asock[i]->genericErrno = sysErr; } } TCPSOCKLG0(warnSock, "%s: Failed with error %d: %s\n", __FUNCTION__, sysErr, Err_Errno2String(sysErr)); return ASOCKERR_GENERIC; } default: { Bool failed = FALSE; #ifndef _WIN32 for (i = 0; i < numSock; i++) { if (pfd[i].revents & (POLLERR | POLLNVAL)) { failed = TRUE; } } #else for (i = 0; i < numSock; i++) { if (FD_ISSET(asock[i]->fd, &exceptfds)) { failed = TRUE; } } #endif if (failed) { int sockErr = 0; int sysErr; int sockErrLen = sizeof sockErr; for (i = 0; i < numSock; i++) { if (getsockopt(asock[i]->fd, SOL_SOCKET, SO_ERROR, (void *) &sockErr, (void *) &sockErrLen) == 0) { if (sockErr) { asock[i]->genericErrno = sockErr; TCPSOCKLG0(asock[i], "%s: Socket error lookup returned %d: %s\n", __FUNCTION__, sockErr, Err_Errno2String(sockErr)); } } else { sysErr = ASOCK_LASTERROR(); asock[i]->genericErrno = sysErr; TCPSOCKLG0(asock[i], "%s: Last socket error %d: %s\n", __FUNCTION__, sysErr, Err_Errno2String(sysErr)); } } return ASOCKERR_GENERIC; } /* * If one socket is ready, and it wasn't in an exception state, * everything is ok. The socket is ready for reading/writing. */ #ifndef _WIN32 for (i = 0; i < numSock; i++) { if (pfd[i].revents & (read ? POLLIN : POLLOUT)) { *outAsock = asock[i]; return ASOCKERR_SUCCESS; } } #else for (i = 0; i < numSock; i++) { if (FD_ISSET(asock[i]->fd, &rwfds)) { *outAsock = asock[i]; return ASOCKERR_SUCCESS; } } #endif TCPSOCKWARN(warnSock, "%s: Failed to return a ready socket.\n", __FUNCTION__); return ASOCKERR_GENERIC; } } } } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketPoll -- * * Blocks on the specified socket until there's data pending or a * timeout occurs. * * If the specified socket is a dual stack listener, we will poll on all * listening sockets and will return when one is ready with data for a * connection. If both socket families happen to race with connect data, * we will favor IPv6 for the return. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call * failures * ASOCKERR_TIMEOUT if we just didn't receive enough data. * * Side effects: * None. *---------------------------------------------------------------------------- */ static int AsyncTCPSocketPoll(AsyncTCPSocket *s, // IN: Bool read, // IN: int timeoutMS, // IN: AsyncTCPSocket **outAsock) // OUT: { AsyncTCPSocket *asock[2]; #ifndef _WIN32 struct pollfd p[2]; #else void *p = NULL; #endif size_t numSock = 0; if (read && s->fd == -1) { if (!s->listenAsock4 && !s->listenAsock6) { TCPSOCKLG0(s, "%s: Failed to find listener socket.\n", __FUNCTION__); return ASOCKERR_GENERIC; } if (s->listenAsock6 && s->listenAsock6->fd != -1) { asock[numSock++] = s->listenAsock6; } if (s->listenAsock4 && s->listenAsock4->fd != -1) { asock[numSock++] = s->listenAsock4; } } else { asock[numSock++] = s; } return AsyncTCPSocketPollWork(asock, numSock, p, read, timeoutMS, s, outAsock); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketWaitForReadMultiple -- * * Blocks on the list of sockets until there's data readable or a * timeout occurs. * * Please see the comment in asyncSocketInterface.c for more * information about using this function. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call * failures * ASOCKERR_TIMEOUT if no sockets were ready with readable data. * * Side effects: * None. *---------------------------------------------------------------------------- */ static int AsyncTCPSocketWaitForReadMultiple(AsyncSocket **asock, // IN: size_t numSock, // IN: int timeoutMS, // IN: int *outIdx) // OUT: { size_t i; int err; AsyncTCPSocket *outAsock = NULL; #ifndef _WIN32 struct pollfd *p = Util_SafeCalloc(numSock, sizeof *p); #else void *p = NULL; #endif for (i = 0; i < numSock; i++) { ASSERT(AsyncTCPSocketIsLocked(TCPSocket(asock[i]))); } err = AsyncTCPSocketPollWork((AsyncTCPSocket **)asock, numSock, p, TRUE, timeoutMS, NULL, &outAsock); for (i = numSock; i-- > 0; ) { AsyncTCPSocket *tcpAsock = TCPSocket(asock[i]); if (outAsock == tcpAsock) { *outIdx = i; } } free(p); return err; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketRecvBlocking -- * AsyncTCPSocketRecvPartialBlocking -- * AsyncTCPSocketSendBlocking -- * * Implement "blocking + timeout" operations on the socket. These are * simple wrappers around the AsyncTCPSocketBlockingWork function, which * operates on the actual non-blocking socket, using poll to determine * when it's ok to keep reading/writing. If we can't finish within the * specified time, we give up and return the ASOCKERR_TIMEOUT error. * * Note that if these are called from a callback and a lock is being * used (pollParams.lock), the whole blocking operation takes place * with that lock held. Regardless, it is the caller's responsibility * to make sure the synchronous and asynchronous operations do not mix. * * Results: * ASOCKERR_SUCCESS if we finished the operation, ASOCKERR_* error codes * otherwise. * * Side effects: * Reads/writes the socket. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketRecvBlocking(AsyncSocket *base, // IN void *buf, // OUT int len, // IN int *received, // OUT int timeoutMS) // IN { AsyncTCPSocket *s = TCPSocket(base); return AsyncTCPSocketBlockingWork(s, TRUE, buf, len, received, timeoutMS, FALSE); } static int AsyncTCPSocketRecvPartialBlocking(AsyncSocket *base, // IN void *buf, // OUT int len, // IN int *received, // OUT int timeoutMS) // IN { AsyncTCPSocket *s = TCPSocket(base); return AsyncTCPSocketBlockingWork(s, TRUE, buf, len, received, timeoutMS, TRUE); } static int AsyncTCPSocketSendBlocking(AsyncSocket *base, // IN void *buf, // OUT int len, // IN int *sent, // OUT int timeoutMS) // IN { AsyncTCPSocket *s = TCPSocket(base); return AsyncTCPSocketBlockingWork(s, FALSE, buf, len, sent, timeoutMS, FALSE); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketBlockingWork -- * * Try to complete the specified read/write operation within the * specified time. * * Results: * ASOCKERR_*. * * Side effects: * None. *---------------------------------------------------------------------------- */ static int AsyncTCPSocketBlockingWork(AsyncTCPSocket *s, // IN: Bool read, // IN: void *buf, // IN/OUT: int len, // IN: int *completed, // OUT: int timeoutMS, // IN: Bool partial) // IN: { VmTimeType now, done; int sysErr; if (s == NULL || buf == NULL || len <= 0) { Warning(ASOCKPREFIX "Recv called with invalid arguments!\n"); return ASOCKERR_INVAL; } if (AsyncTCPSocketGetState(s) != AsyncSocketConnected && /* Allow AsyncSocketConnectedRdOnly iff we are reading */ (AsyncTCPSocketGetState(s) != AsyncSocketConnectedRdOnly || !read)) { TCPSOCKWARN(s, "recv called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } if (completed) { *completed = 0; } now = Hostinfo_SystemTimerUS() / 1000; done = now + timeoutMS; do { int numBytes, error; AsyncTCPSocket *asock = NULL; if ((numBytes = read ? SSL_Read(s->sslSock, buf, len) : SSL_Write(s->sslSock, buf, len)) > 0) { if (completed) { *completed += numBytes; } len -= numBytes; if (len == 0 || partial) { return ASOCKERR_SUCCESS; } buf = (uint8*)buf + numBytes; } else if (numBytes == 0) { TCPSOCKLG0(s, "blocking %s detected peer closed connection\n", read ? "recv" : "send"); return ASOCKERR_REMOTE_DISCONNECT; } else if ((sysErr = ASOCK_LASTERROR()) != ASOCK_EWOULDBLOCK) { s->genericErrno = sysErr; TCPSOCKWARN(s, "blocking %s error %d: %s\n", read ? "recv" : "send", sysErr, Err_Errno2String(sysErr)); return ASOCKERR_GENERIC; } now = Hostinfo_SystemTimerUS() / 1000; if (now >= done && timeoutMS >= 0) { return ASOCKERR_TIMEOUT; } /* * Only call in to Poll if we weren't able to send/recv directly * off the socket. But always make sure that the call to Poll() * is followed by a read/send. */ error = AsyncTCPSocketPoll(s, read, done - now, &asock); if (error != ASOCKERR_SUCCESS) { return error; } ASSERT(asock == s); } while (TRUE); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketSend -- * * Queues the provided data for sending on the socket. If a send callback * is provided, the callback is fired after the data has been written to * the socket. Note that this only guarantees that the data has been * copied to the transmit buffer, we make no promises about whether it * has actually been transmitted, or received by the client, when the * callback is fired. * * Send callbacks should also be able to deal with being called if none * or only some of the queued buffer has been transmitted, since the send * callbacks for any remaining buffers are fired by AsyncSocket_Close(). * This condition can be detected by checking the len parameter passed to * the send callback. * * Results: * ASOCKERR_*. * * Side effects: * May register poll callback or perform I/O. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketSend(AsyncSocket *asock, // IN void *buf, // IN int len, // IN AsyncSocketSendFn sendFn, // IN void *clientData) // IN { return AsyncTCPSocketSendWithFd(asock, buf, len, -1, sendFn, clientData); } /* *---------------------------------------------------------------------------- * * AsyncSocket_SendWithFd -- * * Like the regular AsyncSocket_Send, with the addition of passing a * file descriptor to the recipient. * * Results: * ASOCKERR_*. * * Side effects: * May register poll callback or perform I/O. * *---------------------------------------------------------------------------- */ int AsyncSocket_SendWithFd(AsyncSocket *asock, // IN: void *buf, // IN: int len, // IN: int passFd, // IN: AsyncSocketSendFn sendFn, // IN: void *clientData) // IN: { int ret; AsyncSocketLock(asock); ret = AsyncTCPSocketSendWithFd(asock, buf, len, passFd, sendFn, clientData); AsyncSocketUnlock(asock); return ret; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketSendWithFd -- * * The meat of queueing a packet to send, optionally also passing a * file descriptor. * * Results: * ASOCKERR_*. * * Side effects: * See callers. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketSendWithFd(AsyncSocket *base, // IN: void *buf, // IN: int len, // IN: int passFd, // IN: AsyncSocketSendFn sendFn, // IN: void *clientData) // IN: { AsyncTCPSocket *asock = TCPSocket(base); int retVal; Bool bufferListWasEmpty = FALSE; SendBufList **pcur; SendBufList *newBuf; ASSERT(base->vt == &asyncTCPSocketVTable); /* * Note: I think it should be fine to send with a length of zero and a * buffer of NULL or any other garbage value. However the code * downstream of here is unprepared for it (silently misbehaves). Hence * the <= zero check instead of just a < zero check. --Jeremy. */ if (!buf || len <= 0) { Warning(ASOCKPREFIX "Send called with invalid arguments!" "buffer: %p length: %d\n", buf, len); return ASOCKERR_INVAL; } LOG(2, "%s: sending %d bytes\n", __FUNCTION__, len); ASSERT(AsyncTCPSocketIsLocked(asock)); /* * In low-latency mode, we want to guard against recursive calls to * Send from within the send callback, as these have the capacity * to blow up the stack. However some operations generate implicit * sends (such as Close on a websocket) seem like they should be * legal from the send callback. So, allow a small degree of * recursive use of the send callback to accomodate these internal * paths. */ ASSERT(asock->inLowLatencySendCb < 2); if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { TCPSOCKWARN(asock, "send called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } /* * Allocate and initialize new send buffer entry */ newBuf = Util_SafeCalloc(1, sizeof *newBuf); newBuf->buf = buf; newBuf->len = len; newBuf->passFd = -1; if (passFd == -1) { newBuf->sendFn = sendFn; newBuf->clientData = clientData; } else { SendBufList *fdBuf = Util_SafeCalloc(1, sizeof *fdBuf); fdBuf->passFd = passFd; /* Fire callback after both are sent. */ fdBuf->len = len; fdBuf->sendFn = sendFn; fdBuf->clientData = clientData; newBuf->next = fdBuf; } /* * Append new send buffer to the tail of list. */ *asock->sendBufTail = newBuf; asock->sendBufTail = passFd == -1 ? &(newBuf->next) : &(newBuf->next->next); bufferListWasEmpty = (asock->sendBufList == newBuf); if (bufferListWasEmpty && !asock->sendCb) { if (asock->sendLowLatency) { /* * For low-latency sockets, call the callback directly from * this thread. It is non-blocking and will schedule device * callbacks if necessary to complete the operation. * * Unfortunately we can't make this the default as current * consumers of asyncsocket are not expecting the completion * callback to be invoked prior to the call to * AsyncTCPSocket_Send() returning. * * Add and release asock reference around the send callback * since asock may be closed by a callback invoked during * the send workflow. */ AsyncTCPSocketAddRef(asock); asock->inLowLatencySendCb++; asock->internalSendFn((void *)asock); /* * Coverity warns that asock->internalSendFn may free asock. This is a * false positive because this is a reference counted object and we've * added a reference a few lines above. */ /* coverity[deref_after_free:FALSE] */ asock->inLowLatencySendCb--; AsyncTCPSocketRelease(asock); } else { #ifdef _WIN32 /* * If the send buffer list was empty, we schedule a one-time * callback to "prime" the output. This is necessary to * support the FD_WRITE network event semantic for sockets on * Windows (see WSAEventSelect documentation). The event * won't signal unless a previous write() on the socket * failed with WSAEWOULDBLOCK, so we have to perform at least * one partial write before we can start polling for write. * * XXX: This can be a device callback once all poll * implementations know to get around this Windows quirk. * Both PollVMX and PollDefault already make 0-byte send() to * force WSAEWOULDBLOCK. */ if (AsyncTCPSocketPollAdd(asock, FALSE, 0, asock->internalSendFn, AsyncTCPSocketPollParams(asock)->iPoll != NULL ? 1 : 0) != VMWARE_STATUS_SUCCESS) { retVal = ASOCKERR_POLL; TCPSOCKLOG(1, asock, "Failed to register poll callback for send\n"); goto outUndoAppend; } asock->sendCbTimer = TRUE; asock->sendCb = TRUE; #else if (AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_WRITE, asock->internalSendFn) != VMWARE_STATUS_SUCCESS) { retVal = ASOCKERR_POLL; TCPSOCKLOG(1, asock, "Failed to register poll callback for send\n"); goto outUndoAppend; } asock->sendCb = TRUE; #endif } } return ASOCKERR_SUCCESS; outUndoAppend: /* * Remove the appended buffer from the sendBufList. We always append the * buffer to the tail of the list. */ pcur = &asock->sendBufList; if (*pcur != NULL) { if (!bufferListWasEmpty) { do { pcur = &((*pcur)->next); } while ((*pcur)->next != NULL && (*pcur)->buf != buf); } if ((*pcur)->buf == buf) { if (passFd != -1) { /* Free the entry for the fd being passed. */ free((*pcur)->next); } free(*pcur); *pcur = NULL; asock->sendBufTail = pcur; } } return retVal; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketResolveAddr -- * * Resolves a hostname and port. * * Results: * Zero upon success. This returns whatever getaddrinfo() returns. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketResolveAddr(const char *hostname, // IN unsigned int port, // IN int family, // IN Bool passive, // IN struct sockaddr_storage *addr, // OUT socklen_t *addrLen, // OUT char **addrString) // OUT { struct addrinfo hints; struct addrinfo *aiTop = NULL; struct addrinfo *aiIterator = NULL; int getaddrinfoError = 0; char portString[PORT_STRING_LEN]; ASSERT(NULL != addr); if (port > MAX_UINT16) { Log(ASOCKPREFIX "port number requested (%d) is out of range.\n", port); return EAI_SERVICE; } Str_Sprintf(portString, sizeof(portString), "%d", port); memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; if (passive) { hints.ai_flags = AI_PASSIVE; } getaddrinfoError = Posix_GetAddrInfo(hostname, portString, &hints, &aiTop); if (0 != getaddrinfoError) { Log(ASOCKPREFIX "getaddrinfo failed for host %s: %s\n", hostname, gai_strerror(getaddrinfoError)); goto bye; } for (aiIterator = aiTop; NULL != aiIterator ; aiIterator = aiIterator->ai_next) { if ((family == AF_UNSPEC && (aiIterator->ai_family == AF_INET || aiIterator->ai_family == AF_INET6)) || family == aiIterator->ai_family) { if (addrString != NULL) { char tempAddrString[ADDR_STRING_LEN]; static char unknownAddr[] = "(Unknown)"; #if defined(_WIN32) DWORD len = ARRAYSIZE(tempAddrString); if (WSAAddressToStringA(aiIterator->ai_addr, aiIterator->ai_addrlen, NULL, tempAddrString, &len)) { *addrString = Util_SafeStrdup(unknownAddr); } else { *addrString = Util_SafeStrdup(tempAddrString); } #else if (aiIterator->ai_family == AF_INET && !inet_ntop(aiIterator->ai_family, &(((struct sockaddr_in *)aiIterator->ai_addr)->sin_addr), tempAddrString, INET6_ADDRSTRLEN)) { *addrString = Util_SafeStrdup(unknownAddr); } else if (aiIterator->ai_family == AF_INET6 && !inet_ntop(aiIterator->ai_family, &(((struct sockaddr_in6 *)aiIterator->ai_addr)->sin6_addr), tempAddrString, INET6_ADDRSTRLEN)) { *addrString = Util_SafeStrdup(unknownAddr); } else { *addrString = Str_SafeAsprintf(NULL, aiIterator->ai_family == AF_INET6 ? "[%s]:%u" : "%s:%u", tempAddrString, port); } #endif } memcpy(addr, aiIterator->ai_addr, aiIterator->ai_addrlen); *addrLen = aiIterator->ai_addrlen; break; } } bye: if (NULL != aiTop) { Posix_FreeAddrInfo(aiTop); } return getaddrinfoError; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketFillRecvBuffer -- * * Called when an asock has data ready to be read via the poll callback. * * Results: * ASOCKERR_SUCCESS if everything worked, * ASOCKERR_REMOTE_DISCONNECT if peer closed connection gracefully, * ASOCKERR_CLOSED if trying to read from a closed socket. * ASOCKERR_GENERIC for other errors. * * Side effects: * Reads data, could fire recv completion or trigger socket destruction. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketFillRecvBuffer(AsyncTCPSocket *s) // IN { int recvd; int needed; int sysErr = 0; int result; int pending = 0; ASSERT(AsyncTCPSocketIsLocked(s)); ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); /* * When a socket has received all its desired content and FillRecvBuffer is * called again for the same socket, just return ASOCKERR_SUCCESS. The * reason we need this hack is that if a client which registered a receive * callback asynchronously later changes its mind to do it synchronously, * (e.g. aioMgr wait function), then FillRecvBuffer can be potentially be * called twice for the same receive event. */ needed = s->base.recvLen - s->base.recvPos; if (!s->base.recvBuf && needed == 0) { return ASOCKERR_SUCCESS; } ASSERT(needed > 0); AsyncTCPSocketAddRef(s); /* * See comment in AsyncTCPSocket_Recv */ s->inRecvLoop = TRUE; do { /* * Try to read the remaining bytes to complete the current recv request. */ if (s->passFd.expected) { int fd; recvd = SSL_RecvDataAndFd(s->sslSock, (uint8 *) s->base.recvBuf + s->base.recvPos, needed, &fd); if (fd != -1) { s->passFd.fd = fd; s->passFd.expected = FALSE; } } else { recvd = SSL_Read(s->sslSock, (uint8 *) s->base.recvBuf + s->base.recvPos, needed); } /* * Do NOT make any system call directly or indirectly here * unless you can preserve the system error number */ if (recvd > 0) { TCPSOCKLOG(3, s, "need\t%d\trecv\t%d\tremain\t%d\n", needed, recvd, needed - recvd); s->sslConnected = TRUE; s->base.recvPos += recvd; if (AsyncSocketCheckAndDispatchRecv(&s->base, &result)) { goto exit; } } else if (recvd == 0) { TCPSOCKLG0(s, "recv detected remote shutdown\n"); /* * We treat this as an error so that the owner can detect orderly * shutdown (or half-close) by peer (via the error handler callback). */ result = ASOCKERR_REMOTE_DISCONNECT; goto exit; } else if ((sysErr = ASOCK_LASTERROR()) == ASOCK_EWOULDBLOCK) { TCPSOCKLOG(4, s, "recv would block\n"); break; } else { TCPSOCKLG0(s, "recv error %d: %s\n", sysErr, Err_Errno2String(sysErr)); s->genericErrno = sysErr; result = ASOCKERR_GENERIC; goto exit; } /* * At this point, s->recvFoo have been updated to point to the * next chained Recv buffer. By default we're done at this * point, but we may want to continue if the SSL socket has data * buffered in userspace already (SSL_Pending). */ needed = s->base.recvLen - s->base.recvPos; ASSERT(needed > 0); pending = SSL_Pending(s->sslSock); needed = MIN(needed, pending); } while (needed); /* * Reach this point only when previous SSL_Pending returns 0 or * error is ASOCK_EWOULDBLOCK */ ASSERT(pending == 0 || sysErr == ASOCK_EWOULDBLOCK); /* * Both a spurious wakeup and receiving any data even if it wasn't enough * to fire the callback are both success. We were ready and now * presumably we aren't ready anymore. */ result = ASOCKERR_SUCCESS; exit: s->inRecvLoop = FALSE; AsyncTCPSocketRelease(s); return result; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketFillPeekBuffer -- * * Called when asock has data ready to peek via the poll callback. * Internally calls recv system call with MSG_PEEK flag. * * Similar to AsyncTCPSocketFillRecvBuffer with key differences: * * - peek does non-SSL (clear-text pre-SSL or encrypted) retrieval from the * socket, whereas TCPSocketFillRecvBuffer does an SSL_Read. peek does * not take into account any data buffered at the SSL layer, so only * makes sense prior to SSL setup. * * - peek reads from the head of socket buffer, but does not drain it so * subsequent recv/peek will still read the same data. * * - if peek and recv async requests overlap, the latest requests * implicitly cancels the existing one. * * - nested peeks of same or lesser length into the same buffer are * pointless and dropped. Nested recv() transition to recv callback. * * Results: * Same as AsyncTCPSocketFillRecvBuffer(). * * Side effects: * Reads data but does not remove it from the socket buffer, could fire * recv completion or trigger socket destruction. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketFillPeekBuffer(AsyncTCPSocket *s, // IN Bool *retry) // OUT { int recvd; int needed; int result; int sysErr; int length; void *buffer; int loopCount = 0; #define MAX_NESTED_PEEKS 8 ASSERT(AsyncTCPSocketIsLocked(s)); ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); ASSERT(s->flags & ASOCK_FLAG_PEEK); needed = s->base.recvLen - s->base.recvPos; if (!s->base.recvBuf && needed == 0) { s->flags &= ~ASOCK_FLAG_PEEK; return ASOCKERR_SUCCESS; } ASSERT(needed > 0); AsyncTCPSocketAddRef(s); s->inRecvLoop = TRUE; // peek loop to service nested peeks do { TCPSOCKLOG(1, s, "peeking for %d bytes\n", needed); length = s->base.recvLen; buffer = s->base.recvBuf; // recv() with MSG_PEEK recvd = recv(SSL_GetFd(s->sslSock), (uint8 *) s->base.recvBuf + s->base.recvPos, needed, MSG_PEEK); TCPSOCKLOG(0, s, "peek fetched %d of %d bytes requested\n", recvd, needed); if (recvd > 0) { s->base.recvPos += recvd; if (AsyncSocketCheckAndDispatchRecv(&s->base, &result)) { goto exit; } ASSERT(s->base.recvPos == 0); } else if (recvd == 0) { TCPSOCKLG0(s, "peek detected remote shutdown\n"); /* * We treat this as an error so that the owner can detect orderly * shutdown (or half-close) by peer (via the error handler callback). */ result = ASOCKERR_REMOTE_DISCONNECT; goto exit; } else if ((sysErr = ASOCK_LASTERROR()) == ASOCK_EWOULDBLOCK) { TCPSOCKLOG(4, s, "peek would block\n"); result = ASOCKERR_SUCCESS; break; } else { TCPSOCKLG0(s, "peek error %d: %s\n", sysErr, Err_Errno2String(sysErr)); s->genericErrno = sysErr; result = ASOCKERR_GENERIC; goto exit; } needed = s->base.recvLen - s->base.recvPos; // Handle recv from peek callback using retry loop of the caller if (!ASOCK_PEEK(s)) { TCPSOCKLOG(0, s, "recv during peek, retry recv callback"); *retry = TRUE; break; } /* * Nested peeks for same or lesser lengths into the same buffer are * pointless and unexpected, so we use it as a terminating condition to * break the loop and also unregister peek callback. */ if (s->base.recvLen <= length && s->base.recvBuf == buffer) { TCPSOCKLG0(s, "cancelling one-shot peek op"); s->flags &= ~ASOCK_FLAG_PEEK; AsyncTCPSocketCancelRecvCb(s); break; } } while (needed && (++loopCount < MAX_NESTED_PEEKS)); // flag heavy peek nesting ASSERT(loopCount < MAX_NESTED_PEEKS); result = ASOCKERR_SUCCESS; exit: s->inRecvLoop = FALSE; AsyncTCPSocketRelease(s); return result; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketDispatchSentBuffer -- * * Pop off the head of the send buffer list and call its callback. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketDispatchSentBuffer(AsyncTCPSocket *s) // IN { int result = ASOCKERR_SUCCESS; /* * We're done with the current buffer, so pop it off and nuke it. * We do the list management *first*, so that the list is in a * consistent state. */ SendBufList *head = s->sendBufList; SendBufList tmp = *head; s->sendBufList = head->next; if (s->sendBufList == NULL) { s->sendBufTail = &(s->sendBufList); } s->sendPos = 0; free(head); if (tmp.sendFn) { /* * Firing the send completion cannot trigger immediate * destruction of the socket because we hold a refCount across * this and all other application callbacks. If the socket is * closed, however, we need to bubble the information up to the * caller in the same way as we do in the Recv callback case. */ ASSERT(s->base.refCount > 1); tmp.sendFn(tmp.buf, tmp.len, BaseSocket(s), tmp.clientData); if (AsyncTCPSocketGetState(s) == AsyncSocketClosed) { TCPSOCKLG0(s, "owner closed connection in send callback\n"); result = ASOCKERR_CLOSED; } } return result; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketPassFd -- * * Send a file descriptor on the TCP socket. * * Results: * 1 if successful, -1 if not. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketPassFd(int socket, // IN: int passFd) // IN: { #ifndef _WIN32 static unsigned char byte = 0; union { struct cmsghdr cmsghdr; char cbuf[CMSG_SPACE(sizeof passFd)]; } cbuf_un; struct msghdr msghdr = {0}; struct cmsghdr *cmsghdr; struct iovec iov[1]; int ret; iov[0].iov_base = &byte; iov[0].iov_len = sizeof byte; msghdr.msg_control = cbuf_un.cbuf; msghdr.msg_controllen = sizeof cbuf_un.cbuf; msghdr.msg_iov = iov; msghdr.msg_iovlen = 1; cmsghdr = CMSG_FIRSTHDR(&msghdr); cmsghdr->cmsg_len = CMSG_LEN(sizeof passFd); cmsghdr->cmsg_level = SOL_SOCKET; cmsghdr->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsghdr) = passFd; ret = sendmsg(socket, &msghdr, 0); return ret > 0 ? 1 : -1; #else NOT_IMPLEMENTED(); #endif } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketWriteBuffers -- * * The meat of AsyncTCPSocket's sending functionality. This function * actually writes to the wire assuming there's space in the buffers * for the socket. * * Results: * ASOCKERR_SUCCESS if everything worked, else ASOCKERR_GENERIC. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketWriteBuffers(AsyncTCPSocket *s) // IN { int result; ASSERT(AsyncTCPSocketIsLocked(s)); if (s->sendBufList == NULL) { return ASOCKERR_SUCCESS; /* Vacuously true */ } if (AsyncTCPSocketGetState(s) != AsyncSocketConnected) { TCPSOCKWARN(s, "write buffers on a disconnected or rdonly socket!\n"); return ASOCKERR_GENERIC; } AsyncTCPSocketAddRef(s); while (s->sendBufList && AsyncTCPSocketGetState(s) == AsyncSocketConnected) { SendBufList *head = s->sendBufList; int error = 0; int sent = 0; int left = head->len - s->sendPos; int sizeToSend = head->len; if (head->passFd == -1) { sent = SSL_Write(s->sslSock, (uint8 *) head->buf + s->sendPos, left); } else { sizeToSend = 1; sent = AsyncTCPSocketPassFd(s->fd, head->passFd); } /* * Do NOT make any system call directly or indirectly here * unless you can preserve the system error number */ if (sent > 0) { TCPSOCKLOG(3, s, "left\t%d\tsent\t%d\tremain\t%d\n", left, sent, left - sent); s->sendBufFull = FALSE; s->sslConnected = TRUE; if ((s->sendPos += sent) == sizeToSend) { result = AsyncTCPSocketDispatchSentBuffer(s); if (result != ASOCKERR_SUCCESS) { goto exit; } } } else if (sent == 0) { TCPSOCKLG0(s, "socket write() should never return 0.\n"); NOT_REACHED(); } else if ((error = ASOCK_LASTERROR()) != ASOCK_EWOULDBLOCK) { TCPSOCKLG0(s, "send error %d: %s\n", error, Err_Errno2String(error)); s->genericErrno = error; if (error == ASOCK_EPIPE || error == ASOCK_ECONNRESET) { result = ASOCKERR_REMOTE_DISCONNECT; } else { result = ASOCKERR_GENERIC; } goto exit; } else { /* * Ran out of space to send. This is actually successful completion * (our contract obligates us to send as much data as space allows * and we fulfilled that). * * Indicate send buffer is full. */ s->sendBufFull = TRUE; break; } } result = ASOCKERR_SUCCESS; exit: AsyncTCPSocketRelease(s); return result; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketAcceptInternal -- * * The meat of 'accept'. This function can be invoked either via a * poll callback or blocking. We call accept to get the new socket fd, * create a new asock, and call the newFn callback previously supplied * by the call to AsyncTCPSocket_Listen. * * Results: * ASOCKERR_SUCCESS if everything works, else an error code. * ASOCKERR_GENERIC is returned to hide accept() system call's * nitty-gritty, it implies that we should try accept() again and not * report error to client. * ASOCKERR_ACCEPT to report accept operation's error to client. * * Side effects: * Accepts on listening fd, creates new asock. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketAcceptInternal(AsyncTCPSocket *s) // IN { AsyncTCPSocket *newsock; int sysErr; int fd; struct sockaddr_storage remoteAddr; socklen_t remoteAddrLen = sizeof remoteAddr; ASSERT(AsyncTCPSocketIsLocked(s)); ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketListening); if ((fd = accept(s->fd, (struct sockaddr *)&remoteAddr, &remoteAddrLen)) == -1) { sysErr = ASOCK_LASTERROR(); s->genericErrno = sysErr; if (sysErr == ASOCK_EWOULDBLOCK) { TCPSOCKWARN(s, "spurious accept notification\n"); #if TARGET_OS_IPHONE /* * For iOS, while the app is suspended and device's screen is locked, * system will reclaim resources from underneath socket(see Apple * Technical Note TN2277), the callback function AsyncTCPSocketAcceptCallback() * will be invoked repeatedly, to deal with this issue, we need to * handle error EWOULDBLOCK. */ return ASOCKERR_ACCEPT; #else return ASOCKERR_GENERIC; #endif #ifndef _WIN32 /* * Linux accept() can return ECONNABORTED for connections * that closed before we got to actually call accept(), but Windows * just ignores this case. So we have to special case for Linux here. * We return ASOCKERR_GENERIC here because we still want to continue * accepting new connections. */ } else if (sysErr == ECONNABORTED) { TCPSOCKLG0(s, "accept: new connection was canceled.\n"); return ASOCKERR_GENERIC; #endif } else { TCPSOCKWARN(s, "accept failed on fd %d, error %d: %s\n", s->fd, sysErr, Err_Errno2String(sysErr)); return ASOCKERR_ACCEPT; } } if (remoteAddr.ss_family == AF_INET6 && AsyncTCPSocketOSVersionSupportsV4Mapped()) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&remoteAddr; /* * Remote address should not be a V4MAPPED address. Validate for the rare * case that IPV6_V6ONLY is not defined and V4MAPPED is enabled by * default when setting up socket listener. */ if (IN6_IS_ADDR_V4MAPPED(&(addr6->sin6_addr))) { TCPSOCKWARN(s, "accept rejected on fd %d due to a IPv4-mapped IPv6 " "remote connection address.\n", s->fd); SSLGeneric_close(fd); return ASOCKERR_ACCEPT; } } newsock = AsyncTCPSocketAttachToFd(fd, AsyncTCPSocketPollParams(s), NULL); if (!newsock) { SSLGeneric_close(fd); return ASOCKERR_ACCEPT; } newsock->remoteAddr = remoteAddr; newsock->remoteAddrLen = remoteAddrLen; AsyncTCPSocketSetState(newsock, AsyncSocketConnected); newsock->internalRecvFn = s->internalRecvFn; newsock->internalSendFn = s->internalSendFn; /* * Fire the connect callback: */ s->connectFn(BaseSocket(newsock), s->clientData); return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketConnectInternal -- * * The meat of connect. This function is invoked either via a poll * callback or the blocking API and verifies that connect() succeeded * or reports is failure. On success we call the registered 'new * connection' function. * * Results: * ASOCKERR_SUCCESS if it all worked out or ASOCKERR_GENERIC. * * Side effects: * Creates new asock, fires newFn callback. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketConnectInternal(AsyncTCPSocket *s) // IN { int optval = 0, optlen = sizeof optval, sysErr; ASSERT(AsyncTCPSocketIsLocked(s)); ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnecting); /* Remove when bug 859728 is fixed */ if (vmx86_server && s->remoteAddr.ss_family == AF_UNIX) { goto done; } if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &optval, (void *)&optlen) != 0) { sysErr = ASOCK_LASTERROR(); s->genericErrno = sysErr; Warning(ASOCKPREFIX "getsockopt for connect on fd %d failed with " "error %d : %s\n", s->fd, sysErr, Err_Errno2String(sysErr)); return ASOCKERR_GENERIC; } if (optval != 0) { s->genericErrno = optval; TCPSOCKLOG(1, s, "connection SO_ERROR: %s\n", Err_Errno2String(optval)); if (optval == ASOCK_ENETUNREACH || optval == ASOCK_EHOSTUNREACH) { return ASOCKERR_NETUNREACH; } else { return ASOCKERR_CONNECT; } } s->localAddrLen = sizeof s->localAddr; if (getsockname(s->fd, (struct sockaddr *)&s->localAddr, &s->localAddrLen) != 0) { sysErr = ASOCK_LASTERROR(); s->genericErrno = sysErr; Warning(ASOCKPREFIX "getsockname for connect on fd %d failed with " "error %d: %s\n", s->fd, sysErr, Err_Errno2String(sysErr)); return ASOCKERR_GENERIC; } done: AsyncTCPSocketSetState(s, AsyncSocketConnected); s->connectFn(BaseSocket(s), s->clientData); return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetGenericErrno -- * * Used when an ASOCKERR_GENERIC is returned due to a system error. * The errno that was returned by the system is stored in the asock * struct and returned to the user in this function. * * XXX: This function is not thread-safe. The errno should be returned * in a parameter to any function that can return ASOCKERR_GENERIC. * * Results: * int error code * * Side effects: * None * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetGenericErrno(AsyncSocket *base) // IN: { AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); return asock->genericErrno; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketWaitForConnection -- * * Spins a socket currently listening or connecting until the * connection completes or the allowed time elapses. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on failures, and * ASOCKERR_TIMEOUT if nothing happened in the allotted time. * * Side effects: * None. *---------------------------------------------------------------------------- */ static int AsyncTCPSocketWaitForConnection(AsyncSocket *base, // IN: int timeoutMS) // IN: { AsyncTCPSocket *s = TCPSocket(base); Bool read = FALSE; int error; VmTimeType now, done; Bool removed = FALSE; ASSERT(AsyncTCPSocketIsLocked(s)); if (AsyncTCPSocketGetState(s) == AsyncSocketConnected || AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly) { return ASOCKERR_SUCCESS; } if (AsyncTCPSocketGetState(s) != AsyncSocketListening && AsyncTCPSocketGetState(s) != AsyncSocketConnecting) { return ASOCKERR_GENERIC; } read = AsyncTCPSocketGetState(s) == AsyncSocketListening; /* * For listening sockets, unregister AsyncTCPSocketAcceptCallback before * starting polling and re-register before returning. * * ConnectCallback() is either registered as a device or rtime callback * depending on the prior return value of connect(). So we try to remove it * from both. */ if (read) { if (s->fd == -1) { if (s->listenAsock4) { ASSERT(AsyncTCPSocketIsLocked(s->listenAsock4)); AsyncTCPSocketCancelListenCb(s->listenAsock4); } if (s->listenAsock6) { ASSERT(AsyncTCPSocketIsLocked(s->listenAsock6)); AsyncTCPSocketCancelListenCb(s->listenAsock6); } } else { AsyncTCPSocketCancelListenCb(s); } removed = TRUE; } else { removed = (AsyncTCPSocketPollRemove(s, TRUE, POLL_FLAG_WRITE, AsyncTCPSocketConnectCallback) || AsyncTCPSocketPollRemove(s, FALSE, 0, AsyncTCPSocketConnectCallback)); ASSERT(removed); if (s->internalConnectFn) { removed = AsyncTCPSocketPollRemove(s, FALSE, POLL_FLAG_PERIODIC, AsyncTCPSocketConnectErrorCheck); ASSERT(removed); s->internalConnectFn = NULL; } } now = Hostinfo_SystemTimerUS() / 1000; done = now + timeoutMS; do { AsyncTCPSocket *asock = NULL; error = AsyncTCPSocketPoll(s, read, done - now, &asock); if (error != ASOCKERR_SUCCESS) { goto out; } now = Hostinfo_SystemTimerUS() / 1000; if (read) { if (AsyncTCPSocketAcceptInternal(asock) != ASOCKERR_SUCCESS) { TCPSOCKLG0(s, "wait for connection: accept failed\n"); /* * Just fall through, we'll loop and try again as long as we still * have time remaining. */ } else { error = ASOCKERR_SUCCESS; goto out; } } else { error = AsyncTCPSocketConnectInternal(asock); goto out; } } while ((now < done && timeoutMS > 0) || (timeoutMS < 0)); error = ASOCKERR_TIMEOUT; out: if (read && removed) { if (s->fd == -1) { if (s->listenAsock4 && AsyncTCPSocketGetState(s->listenAsock4) != AsyncSocketClosed) { if (!AsyncTCPSocketAddListenCb(s->listenAsock4)) { error = ASOCKERR_POLL; } } if (s->listenAsock6 && AsyncTCPSocketGetState(s->listenAsock6) != AsyncSocketClosed) { if (!AsyncTCPSocketAddListenCb(s->listenAsock6)) { error = ASOCKERR_POLL; } } } else if (AsyncTCPSocketGetState(s) != AsyncSocketClosed) { if (!AsyncTCPSocketAddListenCb(s)) { error = ASOCKERR_POLL; } } } return error; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketDoOneMsg -- * * Spins a socket until the specified amount of time has elapsed or * data has arrived / been sent. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call * failures * ASOCKERR_BUSY if another thread is in the read callback. * ASOCKERR_TIMEOUT if nothing happened in the allotted time. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketDoOneMsg(AsyncSocket *base, // IN Bool read, // IN int timeoutMS) // IN { AsyncTCPSocket *s = TCPSocket(base); AsyncTCPSocket *asock = NULL; int retVal; ASSERT(AsyncTCPSocketIsLocked(s)); ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || (AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly && read)); if (read) { if (s->inRecvLoop) { /* * The recv loop would read the data if there is any and it is * not safe to proceed and race with the recv loop. */ TCPSOCKLG0(s, "busy: another thread in recv loop\n"); return ASOCKERR_BUSY; } /* * Bug 158571: There could other threads polling on the same asyncsocket. * If two threads land up polling on the same socket at the same time, * the first thread to be scheduled reads the data from the socket, * while the second one blocks infinitely. This hangs the VM. To prevent * this, we temporarily remove the poll callback and then reinstate it * after reading the data. */ ASSERT(s->recvCb); /* We are supposed to call someone... */ AsyncTCPSocketAddRef(s); AsyncTCPSocketCancelRecvCb(s); s->recvCb = TRUE; /* We need to know if the callback cancel recv. */ s->inBlockingRecv++; retVal = AsyncTCPSocketPoll(s, read, timeoutMS, &asock); if (retVal != ASOCKERR_SUCCESS) { if (retVal == ASOCKERR_GENERIC) { TCPSOCKWARN(s, "%s: failed to poll on the socket during read.\n", __FUNCTION__); } } else { ASSERT(asock == s); retVal = AsyncTCPSocketFillRecvBuffer(s); } s->inBlockingRecv--; /* * If socket got closed in AsyncTCPSocketFillRecvBuffer, we * cannot add poll callback - AsyncSocket_Close() would remove * it if we would not remove it above. */ if (AsyncTCPSocketGetState(s) != AsyncSocketClosed && s->recvCb) { ASSERT(s->base.refCount > 1); /* We shouldn't be last user of socket. */ ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); /* * If AsyncTCPSocketPoll or AsyncTCPSocketFillRecvBuffer fails, do not * add the recv callback as it may never fire. */ s->recvCb = FALSE; /* For re-registering the poll callback. */ if (retVal == ASOCKERR_SUCCESS || retVal == ASOCKERR_TIMEOUT) { int ret = AsyncTCPSocketRegisterRecvCb(s); Log("SOCKET reregister recvCb after DoOneMsg (ref %d)\n", BaseSocket(s)->refCount); if (ret != ASOCKERR_SUCCESS) { s->base.recvBuf = NULL; retVal = ret; } } } AsyncTCPSocketRelease(s); } else { AsyncTCPSocketAddRef(s); retVal = AsyncTCPSocketPoll(s, read, timeoutMS, &asock); if (retVal != ASOCKERR_SUCCESS) { if (retVal == ASOCKERR_GENERIC) { TCPSOCKWARN(s, "%s: failed to poll on the socket during write.\n", __FUNCTION__); } } else { ASSERT(asock == s); retVal = AsyncTCPSocketWriteBuffers(s); } AsyncTCPSocketRelease(s); } return retVal; } /* *---------------------------------------------------------------------------- * * AsyncSocket_TCPDrainRecv -- * * This function can be used to drain all the messages from a socket * disconnected on the remote end. It spins a socket until the specified * amount of time has elapsed or an error is encountered, with backoff * between read attempts if there is a conflict with another thread. The * recv callback is restored at the end of this only if not all the * messages have been read, the socket is still connected and recv callack * has not been cancelled. * * Results: * ASOCKERR_SUCCESS if all messages are have been read, or if the callback * has canceled the recv, or if the socket is closed * ASOCKERR_GENERIC on system call failures * ASOCKERR_TIMEOUT if there may still be unread messages at the end of * the speccified time. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int AsyncSocket_TCPDrainRecv(AsyncSocket *base, // IN int timeoutMS) // IN { AsyncTCPSocket *s = TCPSocket(base); int retVal; Bool cbRemoved = FALSE; Bool releaseLock = FALSE; unsigned count = 0; VmTimeType startMS = Hostinfo_SystemTimerMS(); VmTimeType nowMS; ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); ASSERT(s->recvCb); /* We are supposed to call someone... */ if (!AsyncTCPSocketIsLocked(s) || !Poll_LockingEnabled()) { AsyncTCPSocketLock(s); releaseLock = TRUE; } AsyncTCPSocketAddRef(s); while (TRUE) { AsyncTCPSocket *asock = NULL; count++; if (s->inRecvLoop) { /* * The recv loop would read the data if there is any and it is * not safe to proceed and race with the recv loop. */ TCPSOCKLG0(s, "busy: another thread in recv loop\n"); retVal = ASOCKERR_BUSY; /* Add a bit of backoff. */ AsyncTCPSocketUnlock(s); Util_Usleep(MIN(100 << (mssb32(count) / 2), timeoutMS)); AsyncTCPSocketLock(s); goto retry; } if (!cbRemoved) { /* * Cancel the recv callback, but pretend that it is still registered * so we know if the callback cancel recv. */ AsyncTCPSocketCancelRecvCb(s); s->recvCb = TRUE; cbRemoved = TRUE; } s->inBlockingRecv++; retVal = AsyncTCPSocketPoll(s, TRUE, 0, &asock); if (retVal != ASOCKERR_SUCCESS) { if (retVal == ASOCKERR_GENERIC) { TCPSOCKWARN(s, "%s: failed to poll on the socket during read.\n", __FUNCTION__); } } else if (AsyncTCPSocketGetState(s) == AsyncSocketConnected || AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly) { ASSERT(asock == s); retVal = AsyncTCPSocketFillRecvBuffer(s); } s->inBlockingRecv--; retry: if (retVal == ASOCKERR_REMOTE_DISCONNECT || AsyncTCPSocketGetState(s) == AsyncSocketClosed || !s->recvCb) { /* No more messages to recv. */ retVal = ASOCKERR_SUCCESS; break; } if (retVal == ASOCKERR_GENERIC) { break; } nowMS = Hostinfo_SystemTimerMS(); if (nowMS >= startMS + timeoutMS) { retVal = ASOCKERR_TIMEOUT; break; } timeoutMS -= nowMS - startMS; startMS = nowMS; ASSERT((AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly || AsyncTCPSocketGetState(s) == AsyncSocketConnected) && s->recvCb); } if (cbRemoved) { s->recvCb = FALSE; /* * If AsyncTCPSocketPoll or AsyncTCPSocketFillRecvBuffer fails, do not * add the recv callback as it may never fire. */ if (retVal == ASOCKERR_TIMEOUT) { ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); ASSERT(s->base.refCount > 1); /* We better not be the last user */ retVal = AsyncTCPSocketRegisterRecvCb(s); Log("SOCKET reregister recvCb after DrainRecv (ref %d)\n", BaseSocket(s)->refCount); } } if (!s->recvCb) { s->base.recvBuf = NULL; } AsyncTCPSocketRelease(s); if (releaseLock) { AsyncTCPSocketUnlock(s); } return retVal; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketFlush -- * * Try to send any pending out buffers until we run out of buffers, or * the timeout expires. * * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call * failures, and ASOCKERR_TIMEOUT if we couldn't send enough data * before the timeout expired. * * Side effects: * None. *---------------------------------------------------------------------------- */ static int AsyncTCPSocketFlush(AsyncSocket *base, // IN int timeoutMS) // IN { AsyncTCPSocket *s = TCPSocket(base); VmTimeType now, done; int retVal; if (s == NULL) { Warning(ASOCKPREFIX "Flush called with invalid arguments!\n"); return ASOCKERR_INVAL; } ASSERT(AsyncTCPSocketIsLocked(s)); AsyncTCPSocketAddRef(s); if (AsyncTCPSocketGetState(s) != AsyncSocketConnected) { TCPSOCKWARN(s, "flush called but state is rdonly or disconnected!\n"); retVal = ASOCKERR_INVAL; goto outHaveLock; } now = Hostinfo_SystemTimerUS() / 1000; done = now + timeoutMS; while (s->sendBufList) { AsyncTCPSocket *asock = NULL; retVal = AsyncTCPSocketPoll(s, FALSE, done - now, &asock); if (retVal != ASOCKERR_SUCCESS) { TCPSOCKWARN(s, "flush failed\n"); goto outHaveLock; } ASSERT(asock == s); if ((retVal = AsyncTCPSocketWriteBuffers(s)) != ASOCKERR_SUCCESS) { goto outHaveLock; } ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); /* Setting timeoutMS to -1 means never timeout. */ if (timeoutMS >= 0) { now = Hostinfo_SystemTimerUS() / 1000; /* Don't timeout if you've sent everything */ if (now > done && s->sendBufList) { TCPSOCKWARN(s, "flush timed out\n"); retVal = ASOCKERR_TIMEOUT; goto outHaveLock; } } } retVal = ASOCKERR_SUCCESS; outHaveLock: AsyncTCPSocketRelease(s); return retVal; } /* *---------------------------------------------------------------------------- * * AsyncSocketCancelListenCbSocket -- * * Socket specific code for canceling callbacks for a listening socket. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketCancelListenCb(AsyncTCPSocket *asock) // IN: { Bool removed; ASSERT(AsyncTCPSocketIsLocked(asock)); removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_READ | POLL_FLAG_PERIODIC, AsyncTCPSocketAcceptCallback); ASSERT(removed); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketAddListenCb -- * * Socket specific code for adding callbacks for a listening socket. * * Results: * TRUE if Poll callback successfully added. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static Bool AsyncTCPSocketAddListenCb(AsyncTCPSocket *asock) // IN: { VMwareStatus pollStatus; ASSERT(AsyncTCPSocketIsLocked(asock)); pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_READ | POLL_FLAG_PERIODIC, AsyncTCPSocketAcceptCallback); if (pollStatus != VMWARE_STATUS_SUCCESS) { TCPSOCKWARN(asock, "failed to install listen accept callback!\n"); } return pollStatus == VMWARE_STATUS_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketCancelRecvCb -- * * Socket specific code for canceling callbacks when a receive * request is being canceled. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketCancelRecvCb(AsyncTCPSocket *asock) // IN: { ASSERT(AsyncTCPSocketIsLocked(asock)); /* * We could fire the current recv completion callback here, but in * practice clients won't want to know about partial reads since it just * complicates the common case (i.e. every read callback would need to * check the len parameter). */ if (asock->recvCbTimer) { AsyncTCPSocketPollRemove(asock, FALSE, 0, asock->internalRecvFn); asock->recvCbTimer = FALSE; } if (asock->recvCb) { Bool removed; TCPSOCKLOG(1, asock, "Removing poll recv callback while cancelling recv.\n"); removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_READ | POLL_FLAG_PERIODIC, asock->internalRecvFn); /* * A recv callback registered on a bad FD can be deleted by * PollHandleInvalidFd if POLL_FLAG_ACCEPT_INVALID_FDS flag * is added to asyncsocket. */ ASSERT(removed || AsyncTCPSocketPollParams(asock)->iPoll || (AsyncTCPSocketPollParams(asock)->flags & POLL_FLAG_ACCEPT_INVALID_FDS) != 0); asock->recvCb = FALSE; } } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketCancelSendCb -- * * Socket specific code for canceling callbacks when a send * request is being canceled. * * This function assumes the caller has done AsyncTCPSocketAddRef, * since the sendFn callback registered might close the socket. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketCancelSendCb(AsyncTCPSocket *asock) // IN: { if (asock->sendCb) { Bool removed; TCPSOCKLOG(1, asock, "sendBufList is non-NULL, removing send callback\n"); /* * The send callback could be either a device or RTime callback, so * we check the latter if it wasn't the former. */ if (asock->sendCbTimer) { removed = AsyncTCPSocketPollRemove(asock, FALSE, 0, asock->internalSendFn); } else { removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, asock->internalSendFn); } ASSERT(removed || AsyncTCPSocketPollParams(asock)->iPoll); asock->sendCb = FALSE; asock->sendCbTimer = FALSE; } /* * Go through any send buffers on the list and fire their * callbacks, reflecting back how much of each buffer has been * submitted to the kernel. For the first buffer in the list that * may be non-zero, for subsequent buffers it will be zero. * * Unlike AsyncTCPSocketCancelRecvCb, the argument of firing callbacks * here is that the common case for writes is "fire and forget", e.g. * send this buffer and free it. Firing the triggers at close time * simplifies client code, since the clients aren't forced to keep track * of send buffers themselves. Clients can figure out how much data was * actually transmitted (if they care) by checking the len parameter * passed to the send callback. * * A modification suggested by Jeremy is to pass a list of unsent * buffers and their completion callbacks to the error handler if one is * registered, and only fire the callbacks here if there was no error * handler invoked. */ while (asock->sendBufList) { /* * Pop each remaining buffer and fire its completion callback. */ SendBufList *cur = asock->sendBufList; int pos = asock->sendPos; asock->sendBufList = asock->sendBufList->next; asock->sendPos = 0; if (cur->sendFn) { cur->sendFn(cur->buf, pos, BaseSocket(asock), cur->clientData); } free(cur); } } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketCancelCbForClose -- * * Cancel future asynchronous send and recv by unregistering * their Poll callbacks, and change the socket state to * AsyncTCPSocketCBCancelled if the socket state is AsyncTCPSocketConnected. * * The function can be called in a send/recv error handler before * actually closing the socket in a separate thread, to prevent other * code calling AsyncTCPSocket_Send/Recv from re-registering the * callbacks again. The next operation should be just AsyncSocket_Close(). * This helps to avoid unnecessary send/recv callbacks before the * socket is closed. * * Results: * ASOCKERR_*. * * Side effects: * Unregisters send/recv Poll callbacks, and fires the send * triggers for any remaining output buffers. May also change * the socket state. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketCancelCbForClose(AsyncSocket *base) // IN: { AsyncTCPSocket *asock = TCPSocket(base); Bool removed; ASSERT(AsyncTCPSocketIsLocked(asock)); if (AsyncTCPSocketGetState(asock) == AsyncSocketConnected || AsyncTCPSocketGetState(asock) == AsyncSocketConnectedRdOnly) { AsyncTCPSocketSetState(asock, AsyncSocketCBCancelled); } /* Remove the read callback. Similar to AsyncTCPSocketCancelRecvCb */ ASSERT(!asock->base.recvBuf || asock->base.recvFn); if (asock->recvCbTimer) { AsyncTCPSocketPollRemove(asock, FALSE, 0, asock->internalRecvFn); asock->recvCbTimer = FALSE; } if (asock->recvCb) { TCPSOCKLOG(1, asock, "recvCb is non-NULL, removing recv callback\n"); removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_READ | POLL_FLAG_PERIODIC, asock->internalRecvFn); /* Callback might be temporarily removed in AsyncSocket_DoOneMsg. */ ASSERT_NOT_TESTED(removed || asock->inBlockingRecv || AsyncTCPSocketPollParams(asock)->iPoll); asock->recvCb = FALSE; asock->base.recvBuf = NULL; } /* Remove the write callback. */ AsyncTCPSocketAddRef(asock); AsyncTCPSocketCancelSendCb(asock); AsyncTCPSocketRelease(asock); return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketCancelCbForConnectingClose -- * * Cancels outstanding connect requests for a socket that is going * away. * * Results: * TRUE on callback removed. FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static Bool AsyncTCPSocketCancelCbForConnectingClose(AsyncTCPSocket *asock) // IN { return (AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, AsyncTCPSocketConnectCallback) || AsyncTCPSocketPollRemove(asock, FALSE, 0, AsyncTCPSocketConnectCallback)); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketSetCloseOptions -- * * Enables optional behavior for AsyncSocket_Close(): * * - If flushEnabledMaxWaitMsec is non-zero, the output stream * will be flushed synchronously before the socket is closed. * (default is zero: close socket right away without flushing) * * - If closeCb is set, the callback will be called asynchronously * when the socket is actually destroyed. * (default is NULL: no callback) * * Results: * ASOCKERR_*. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketSetCloseOptions(AsyncSocket *base, // IN int flushEnabledMaxWaitMsec, // IN AsyncSocketCloseFn closeCb) // IN { AsyncTCPSocket *asock = TCPSocket(base); asock->flushEnabledMaxWaitMsec = flushEnabledMaxWaitMsec; asock->closeCb = closeCb; VERIFY(closeCb == NULL); return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketCloseWrite -- * * Close the write side of AsyncTCPSocket. * * Results: * ASOCKERR_*. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketCloseWrite(AsyncSocket *base) // IN: { #ifdef VMX86_TOOLS /* For tools, don't support closeWrite for now */ return ASOCKERR_INVAL; #else AsyncTCPSocket *asock = TCPSocket(base); int ret; ASSERT(AsyncTCPSocketIsLocked(asock)); if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { return ASOCKERR_INVAL; } if (SSL_IsEncrypted(asock->sslSock)) { /* SSL doesn't support half-close */ return ASOCKERR_INVAL; } ASSERT(asock->listenAsock4 == NULL); ASSERT(asock->listenAsock6 == NULL); if (asock->flushEnabledMaxWaitMsec && !asock->base.errorSeen) { int ret = AsyncTCPSocketFlush(BaseSocket(asock), asock->flushEnabledMaxWaitMsec); if (ret != ASOCKERR_SUCCESS) { TCPSOCKWARN(asock, "AsyncTCPSocket_Flush failed: %s. (ignored).\n", AsyncSocket_Err2String(ret)); } } AsyncTCPSocketSetState(asock, AsyncSocketConnectedRdOnly); AsyncTCPSocketAddRef(asock); AsyncTCPSocketCancelSendCb(asock); ret = SSLGeneric_shutdown(SSL_GetFd(asock->sslSock)); if (ret < 0) { asock->genericErrno = ASOCK_LASTERROR(); TCPSOCKWARN(asock, "shutdown error %d: %s\n", asock->genericErrno, Err_Errno2String(asock->genericErrno)); ret = ASOCKERR_GENERIC; goto out; } ret = ASOCKERR_SUCCESS; out: AsyncTCPSocketRelease(asock); return ret; #endif } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketClose -- * * AsyncTCPSocket destructor. The destructor should be safe to call at any * time. It's invoked automatically for I/O errors on slots that have no * error handler set, and should be called manually by the error handler * as necessary. It could also be called as part of the normal program * flow. * * Results: * ASOCKERR_*. * * Side effects: * Closes the socket fd, unregisters all Poll callbacks, and fires the * send triggers for any remaining output buffers. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketClose(AsyncSocket *base) // IN { AsyncTCPSocket *asock = TCPSocket(base); ASSERT(AsyncTCPSocketIsLocked(asock)); if (AsyncTCPSocketGetState(asock) == AsyncSocketClosed) { Warning("%s() called on already closed asock!\n", __FUNCTION__); return ASOCKERR_CLOSED; } if (asock->listenAsock4 || asock->listenAsock6) { if (asock->listenAsock4) { AsyncSocket_Close(BaseSocket(asock->listenAsock4)); } if (asock->listenAsock6) { AsyncSocket_Close(BaseSocket(asock->listenAsock6)); } } else { Bool removed; AsyncSocketState oldState; /* Flush output if requested via AsyncTCPSocket_SetCloseOptions(). */ if (asock->flushEnabledMaxWaitMsec && AsyncTCPSocketGetState(asock) == AsyncSocketConnected && !asock->base.errorSeen) { int ret = AsyncTCPSocketFlush(base, asock->flushEnabledMaxWaitMsec); if (ret != ASOCKERR_SUCCESS) { TCPSOCKWARN(asock, "AsyncTCPSocket_Flush failed: %s. Closing now.\n", AsyncSocket_Err2String(ret)); } } /* * Set the new state to closed, and then check the old state and do the * right thing accordingly */ TCPSOCKLOG(1, asock, "closing socket\n"); oldState = AsyncTCPSocketGetState(asock); AsyncTCPSocketSetState(asock, AsyncSocketClosed); switch(oldState) { case AsyncSocketListening: TCPSOCKLOG(1, asock, "old state was listening, removing accept callback\n"); AsyncTCPSocketCancelListenCb(asock); break; case AsyncSocketConnecting: TCPSOCKLOG(1, asock, "old state was connecting, removing connect callback\n"); removed = AsyncTCPSocketCancelCbForConnectingClose(asock); if (!removed) { TCPSOCKLOG(1, asock, "connect callback is not present in the poll list.\n"); } break; case AsyncSocketConnected: case AsyncSocketConnectedRdOnly: TCPSOCKLOG(1, asock, "old state was connected/rdonly\n"); AsyncTCPSocketCancelCbForClose(BaseSocket(asock)); break; case AsyncSocketCBCancelled: TCPSOCKLOG(1, asock, "old state was CB-cancelled\n"); break; default: NOT_REACHED(); } if (asock->internalConnectFn) { removed = AsyncTCPSocketPollRemove(asock, FALSE, POLL_FLAG_PERIODIC, AsyncTCPSocketConnectErrorCheck); ASSERT(removed); asock->internalConnectFn = NULL; } if (asock->sslConnectFn && asock->sslPollFlags > 0) { removed = AsyncTCPSocketPollRemove(asock, TRUE, asock->sslPollFlags, AsyncTCPSocketSslConnectCallback); ASSERT(removed); } if (asock->sslAcceptFn && asock->sslPollFlags > 0) { removed = AsyncTCPSocketPollRemove(asock, TRUE, asock->sslPollFlags, AsyncTCPSocketSslAcceptCallback); ASSERT(removed); } asock->sslPollFlags = 0; /* * Close the underlying SSL sockets. */ SSL_Shutdown(asock->sslSock); if (asock->passFd.fd != -1) { SSLGeneric_close(asock->passFd.fd); } } AsyncSocketTeardownSocket(base); return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketIsSendBufferFull -- * * Indicate if socket send buffer is full. Note that unless this is * called from a callback function, the return value should be treated * as transient. * * Results: * 0: send space probably available, * 1: send has reached maximum, * ASOCKERR_GENERIC: null socket. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketIsSendBufferFull(AsyncSocket *base) // IN { AsyncTCPSocket *asock = TCPSocket(base); return asock->sendBufFull; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketHasDataPending -- * * Determine if SSL has any pending/unread data. * * Results: * TRUE if this socket has pending data. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static Bool AsyncTCPSocketHasDataPending(AsyncTCPSocket *asock) // IN: { return SSL_Pending(asock->sslSock); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketMakeNonBlocking -- * * Make the specified socket non-blocking if it isn't already. * * Results: * ASOCKERR_SUCCESS if the operation succeeded, ASOCKERR_GENERIC otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketMakeNonBlocking(int fd) // IN { #ifdef _WIN32 int retval; u_long argp = 1; /* non-zero => enable non-blocking mode */ retval = ioctlsocket(fd, FIONBIO, &argp); if (retval != 0) { ASSERT(retval == SOCKET_ERROR); return ASOCKERR_GENERIC; } #elif defined(__APPLE__) int argp = 1; if (ioctl(fd, FIONBIO, &argp) < 0) { return ASOCKERR_GENERIC; } #else int flags; if ((flags = fcntl(fd, F_GETFL)) < 0) { return ASOCKERR_GENERIC; } if (!(flags & O_NONBLOCK) && (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) { return ASOCKERR_GENERIC; } #endif return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncSocketAcceptCallback -- * * Poll callback for listening fd waiting to complete an accept * operation. We call accept to get the new socket fd, create a new * asock, and call the newFn callback previously supplied by the call to * AsyncTCPSocket_Listen. * * Results: * None. * * Side effects: * Accepts on listening fd, creates new asock. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketAcceptCallback(void *clientData) // IN { AsyncTCPSocket *asock = clientData; int retval; ASSERT(asock); ASSERT(AsyncTCPSocketPollParams(asock)->iPoll == NULL); ASSERT(AsyncTCPSocketIsLocked(asock)); AsyncTCPSocketAddRef(asock); retval = AsyncTCPSocketAcceptInternal(asock); /* * See comment for return value of AsyncTCPSocketAcceptInternal(). */ if (retval == ASOCKERR_ACCEPT) { AsyncTCPSocketHandleError(asock, retval); } AsyncTCPSocketRelease(asock); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketConnectCallback -- * * Poll callback for connecting fd. Calls through to * AsyncTCPSocketConnectInternal to do the real work. * * Results: * None. * * Side effects: * Creates new asock, fires newFn callback. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketConnectCallback(void *clientData) // IN { AsyncTCPSocket *asock = clientData; int retval; ASSERT(asock); ASSERT(AsyncTCPSocketPollParams(asock)->iPoll == NULL); ASSERT(AsyncTCPSocketIsLocked(asock)); AsyncTCPSocketAddRef(asock); retval = AsyncTCPSocketConnectInternal(asock); if (retval != ASOCKERR_SUCCESS) { ASSERT(retval == ASOCKERR_GENERIC || retval == ASOCKERR_NETUNREACH || retval == ASOCKERR_CONNECT); AsyncTCPSocketHandleError(asock, retval); } if (vmx86_win32 && asock->internalConnectFn != NULL) { Bool removed; removed = AsyncTCPSocketPollRemove(asock, FALSE, POLL_FLAG_PERIODIC, AsyncTCPSocketConnectErrorCheck); ASSERT(removed); asock->internalConnectFn = NULL; } AsyncTCPSocketRelease(asock); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketRecvCallback -- * * Poll callback for input waiting on the socket. We try to pull off the * remaining data requested by the current receive function. * * Results: * None. * * Side effects: * Reads data, could fire recv completion or trigger socket destruction. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketRecvCallback(void *clientData) // IN { AsyncTCPSocket *asock = clientData; int error = ASOCKERR_SUCCESS; Bool recv = TRUE; ASSERT(asock); ASSERT(AsyncTCPSocketIsLocked(asock)); AsyncTCPSocketAddRef(asock); if (UNLIKELY(ASOCK_PEEK(asock))) { recv = FALSE; error = AsyncTCPSocketFillPeekBuffer(asock, &recv); } if (LIKELY(recv)) { error = AsyncTCPSocketFillRecvBuffer(asock); } if (error == ASOCKERR_GENERIC || error == ASOCKERR_REMOTE_DISCONNECT) { AsyncTCPSocketHandleError(asock, error); } AsyncTCPSocketRelease(asock); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketIPollRecvCallback -- * * Poll callback for input waiting on the socket. IVmdbPoll does not * handle callback locks, so this function first locks the asyncsocket * and verify that the recv callback has not been cancelled before * calling AsyncTCPSocketFillRecvBuffer to do the real work. * * Results: * None. * * Side effects: * Reads data, could fire recv completion or trigger socket destruction. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketIPollRecvCallback(void *clientData) // IN: { #ifdef VMX86_TOOLS NOT_IMPLEMENTED(); #else AsyncTCPSocket *asock = clientData; MXUserRecLock *lock; ASSERT(asock); ASSERT(AsyncTCPSocketPollParams(asock)->lock == NULL || !MXUser_IsCurThreadHoldingRecLock( AsyncTCPSocketPollParams(asock)->lock)); /* * peek() has not been needed for IVmdbPoll so it is not tested/supported * in this callback, unlike the regular socket poll recv callback * (AsyncTCPSocketRecvCallback). ASSERT added for caution. */ ASSERT(!(asock->flags & ASOCK_FLAG_PEEK)); AsyncTCPSocketLock(asock); if (asock->recvCbTimer) { /* IVmdbPoll only has periodic timer callbacks. */ AsyncTCPSocketIPollRemove(asock, FALSE, 0, asock->internalRecvFn); asock->recvCbTimer = FALSE; } lock = AsyncTCPSocketPollParams(asock)->lock; if (asock->recvCb && asock->inBlockingRecv == 0) { asock->inIPollCb |= IN_IPOLL_RECV; AsyncTCPSocketRecvCallback(clientData); asock->inIPollCb &= ~IN_IPOLL_RECV; /* * Re-register the callback if it has not been canceled. Lock may have * been dropped to fire recv callback so re-check inBlockingRecv. */ if (asock->recvCb && asock->inBlockingRecv == 0) { AsyncTCPSocketIPollAdd(asock, TRUE, POLL_FLAG_READ, asock->internalRecvFn, asock->fd); } } else { TCPSOCKLG0(asock, "Skip recv because %s\n", asock->recvCb ? "blocking recv is in progress" : "recv callback is cancelled"); } /* This is a one-shot callback so we always release the reference taken. */ AsyncTCPSocketRelease(asock); AsyncTCPSocketUnlock(asock); if (lock != NULL) { MXUser_DecRefRecLock(lock); } #endif } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketSendCallback -- * * Poll callback for output socket buffer space available (socket is * writable). We iterate over all the remaining buffers in our queue, * writing as much as we can until we fill the socket buffer again. If we * don't finish, we register ourselves as a device write callback. * * Results: * None. * * Side effects: * Writes data, could trigger write completion or socket destruction. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketSendCallback(void *clientData) // IN { AsyncTCPSocket *s = clientData; int retval; ASSERT(s); ASSERT(AsyncTCPSocketIsLocked(s)); AsyncTCPSocketAddRef(s); s->sendCb = FALSE; /* AsyncTCPSocketSendCallback is never periodic */ s->sendCbTimer = FALSE; retval = AsyncTCPSocketWriteBuffers(s); if (retval != ASOCKERR_SUCCESS && retval != ASOCKERR_CLOSED) { AsyncTCPSocketHandleError(s, retval); } else if (s->sendBufList && !s->sendCb) { VMwareStatus pollStatus; /* * We didn't finish, so we need to reschedule the Poll callback (the * write callback is *not* periodic). */ #ifdef _WIN32 /* * If any data has been sent out or read in from the sslSock, * SSL has finished the handshaking. Otherwise, * we have to schedule a realtime callback for write. See bug 37147 */ if (!s->sslConnected) { pollStatus = AsyncTCPSocketPollAdd(s, FALSE, 0, s->internalSendFn, 100000); VERIFY(pollStatus == VMWARE_STATUS_SUCCESS); s->sendCbTimer = TRUE; } else #endif { pollStatus = AsyncTCPSocketPollAdd(s, TRUE, POLL_FLAG_WRITE, s->internalSendFn); VERIFY(pollStatus == VMWARE_STATUS_SUCCESS); } s->sendCb = TRUE; } AsyncTCPSocketRelease(s); } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketIPollSendCallback -- * * IVmdbPoll callback for output socket buffer space available. IVmdbPoll * does not handle callback locks, so this function first locks the * asyncsocket and verify that the send callback has not been cancelled. * IVmdbPoll only has periodic callbacks, so this function unregisters * itself before calling AsyncTCPSocketSendCallback to do the real work. * * Results: * None. * * Side effects: * Writes data, could trigger write completion or socket destruction. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketIPollSendCallback(void *clientData) // IN: { #ifdef VMX86_TOOLS NOT_IMPLEMENTED(); #else AsyncTCPSocket *s = clientData; MXUserRecLock *lock; ASSERT(s); AsyncTCPSocketLock(s); s->inIPollCb |= IN_IPOLL_SEND; lock = AsyncTCPSocketPollParams(s)->lock; if (s->sendCbTimer) { /* IVmdbPoll only has periodic timer callback. */ AsyncTCPSocketIPollRemove(s, FALSE, 0, AsyncTCPSocketIPollSendCallback); s->sendCbTimer = FALSE; } if (s->sendCb) { AsyncTCPSocketSendCallback(s); } else { TCPSOCKLG0(s, "cancelled send callback fired\n"); } s->inIPollCb &= ~IN_IPOLL_SEND; AsyncTCPSocketRelease(s); AsyncTCPSocketUnlock(s); if (lock != NULL) { MXUser_DecRefRecLock(lock); } #endif } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketPollAdd -- * * Add a poll callback. Wrapper for Poll_Callback since we always call * it in one of two basic forms. * * If socket is FALSE, user has to pass in the timeout value * * Results: * VMwareStatus result code from Poll_Callback * * Side effects: * Only the obvious. * *----------------------------------------------------------------------------- */ static VMwareStatus AsyncTCPSocketPollAdd(AsyncTCPSocket *asock, // IN Bool socket, // IN int flags, // IN PollerFunction callback, // IN ...) // IN { int type, info; if (socket) { ASSERT(asock->fd != -1); type = POLL_DEVICE; flags |= POLL_FLAG_SOCKET; info = asock->fd; } else { va_list marker; va_start(marker, callback); type = POLL_REALTIME; info = va_arg(marker, int); va_end(marker); } if (AsyncTCPSocketPollParams(asock)->iPoll != NULL) { return AsyncTCPSocketIPollAdd(asock, socket, flags, callback, info); } return Poll_Callback(AsyncTCPSocketPollParams(asock)->pollClass, flags | AsyncTCPSocketPollParams(asock)->flags, callback, asock, type, info, AsyncTCPSocketPollParams(asock)->lock); } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketPollRemove -- * * Remove a poll callback. Wrapper for Poll_CallbackRemove since we * always call it in one of two basic forms. * * Results: * TRUE if removed, FALSE if not found. * * Side effects: * Only the obvious. * *----------------------------------------------------------------------------- */ static Bool AsyncTCPSocketPollRemove(AsyncTCPSocket *asock, // IN Bool socket, // IN int flags, // IN PollerFunction callback) // IN { int type; if (AsyncTCPSocketPollParams(asock)->iPoll != NULL) { return AsyncTCPSocketIPollRemove(asock, socket, flags, callback); } if (socket) { ASSERT(asock->fd != -1); type = POLL_DEVICE; flags |= POLL_FLAG_SOCKET; } else { type = POLL_REALTIME; } return Poll_CallbackRemove(AsyncTCPSocketPollParams(asock)->pollClass, flags | AsyncTCPSocketPollParams(asock)->flags, callback, asock, type); } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketIPollAdd -- * * Add a poll callback. Wrapper for IVmdbPoll.Register[Timer]. * * If socket is FALSE, user has to pass in the timeout value * * Results: * VMwareStatus result code. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static VMwareStatus AsyncTCPSocketIPollAdd(AsyncTCPSocket *asock, // IN Bool socket, // IN int flags, // IN PollerFunction callback, // IN int info) // IN { #ifdef VMX86_TOOLS return VMWARE_STATUS_ERROR; #else VMwareStatus status = VMWARE_STATUS_SUCCESS; VmdbRet ret; IVmdbPoll *poll; ASSERT(AsyncTCPSocketPollParams(asock)->iPoll); ASSERT(AsyncTCPSocketIsLocked(asock)); /* Protect asyncsocket and lock from disappearing */ AsyncTCPSocketAddRef(asock); if (AsyncTCPSocketPollParams(asock)->lock != NULL) { MXUser_IncRefRecLock(AsyncTCPSocketPollParams(asock)->lock); } poll = AsyncTCPSocketPollParams(asock)->iPoll; if (socket) { int pollFlags = VMDB_PRF_ONE_SHOT | ((flags & POLL_FLAG_READ) != 0 ? VMDB_PRF_READ : VMDB_PRF_WRITE); ret = poll->Register(poll, pollFlags, callback, asock, info); } else { ret = poll->RegisterTimer(poll, callback, asock, info); } if (ret != VMDB_S_OK) { Log(ASOCKPREFIX "failed to register callback (%s %d): error %d\n", socket ? "socket" : "delay", info, ret); if (AsyncTCPSocketPollParams(asock)->lock != NULL) { MXUser_DecRefRecLock(AsyncTCPSocketPollParams(asock)->lock); } AsyncTCPSocketRelease(asock); status = VMWARE_STATUS_ERROR; } return status; #endif } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketIPollRemove -- * * Remove a poll callback. Wrapper for IVmdbPoll.Unregister[Timer]. * * Results: * TRUE if the callback was registered and has been cancelled successfully. * FALSE if the callback was not registered, or the callback is already * scheduled to fire (and is guaranteed to fire). * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool AsyncTCPSocketIPollRemove(AsyncTCPSocket *asock, // IN Bool socket, // IN int flags, // IN PollerFunction callback) // IN { #ifdef VMX86_TOOLS return FALSE; #else IVmdbPoll *poll; Bool ret; ASSERT(AsyncTCPSocketPollParams(asock)->iPoll); ASSERT(AsyncTCPSocketIsLocked(asock)); poll = AsyncTCPSocketPollParams(asock)->iPoll; if (socket) { int pollFlags = VMDB_PRF_ONE_SHOT | ((flags & POLL_FLAG_READ) != 0 ? VMDB_PRF_READ : VMDB_PRF_WRITE); ret = poll->Unregister(poll, pollFlags, callback, asock); } else { ret = poll->UnregisterTimer(poll, callback, asock); } if (ret && !((asock->inIPollCb & IN_IPOLL_RECV) != 0 && callback == asock->internalRecvFn) && !((asock->inIPollCb & IN_IPOLL_SEND) != 0 && callback == asock->internalSendFn)) { MXUserRecLock *lock = AsyncTCPSocketPollParams(asock)->lock; /* * As the callback has been unregistered and we are not currently in * the callback being removed, we can safely release the reference taken * when registering the callback. */ AsyncTCPSocketRelease(asock); if (lock != NULL) { MXUser_DecRefRecLock(lock); } } return ret; #endif } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketCancelRecv -- * * Call this function if you know what you are doing. This should be * called if you want to synchronously receive the outstanding data on * the socket. It removes the recv poll callback. It also returns number of * partially read bytes (if any). A partially read response may exist as * AsyncTCPSocketRecvCallback calls the recv callback only when all the data * has been received. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_INVAL. * * Side effects: * Subsequent client call to AsyncTCPSocket_Recv can reinstate async behaviour. * *----------------------------------------------------------------------------- */ static int AsyncTCPSocketCancelRecv(AsyncSocket *base, // IN int *partialRecvd, // OUT void **recvBuf, // OUT void **recvFn, // OUT Bool cancelOnSend) // IN { AsyncTCPSocket *asock = TCPSocket(base); ASSERT(AsyncTCPSocketIsLocked(asock)); if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) { Warning(ASOCKPREFIX "Failed to cancel request on disconnected socket!\n"); return ASOCKERR_INVAL; } if (asock->inBlockingRecv && !asock->inRecvLoop) { Warning(ASOCKPREFIX "Cannot cancel request while a blocking recv is " "pending.\n"); return ASOCKERR_INVAL; } if (!cancelOnSend && (asock->sendBufList || asock->sendCb)) { Warning(ASOCKPREFIX "Can't cancel request as socket has send operation " "pending.\n"); return ASOCKERR_INVAL; } AsyncTCPSocketCancelRecvCb(asock); AsyncSocketCancelRecv(BaseSocket(asock), partialRecvd, recvBuf, recvFn); if (asock->passFd.fd != -1) { SSLGeneric_close(asock->passFd.fd); asock->passFd.fd = -1; } asock->passFd.expected = FALSE; return ASOCKERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketGetReceivedFd -- * * Retrieve received file descriptor from socket. * * Results: * File descriptor. Or -1 if none was received. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int AsyncTCPSocketGetReceivedFd(AsyncSocket *base) // IN { AsyncTCPSocket *asock = TCPSocket(base); int fd; ASSERT(AsyncTCPSocketIsLocked(asock)); if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) { Warning(ASOCKPREFIX "Failed to receive fd on disconnected socket!\n"); return -1; } fd = asock->passFd.fd; asock->passFd.fd = -1; asock->passFd.expected = FALSE; return fd; } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketConnectSSL -- * * Initialize the socket's SSL object, by calling SSL_ConnectAndVerify. * NOTE: This call is blocking. * * Results: * TRUE if SSL_ConnectAndVerify succeeded, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool AsyncTCPSocketConnectSSL(AsyncSocket *base, // IN SSLVerifyParam *verifyParam, // IN/OPT const char *hostname, // IN/OPT void *sslContext) // IN/OPT { #ifndef USE_SSL_DIRECT AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); if (sslContext == NULL) { sslContext = SSL_DefaultClientContext(); } return SSL_ConnectAndVerifyWithContext(asock->sslSock, verifyParam, hostname, sslContext); #else return FALSE; #endif } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketAcceptSSL -- * * Initialize the socket's SSL object, by calling SSL_Accept or * SSL_AcceptWithContext. * * Results: * TRUE if SSL_Accept/SSL_AcceptWithContext succeeded, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool AsyncTCPSocketAcceptSSL(AsyncSocket *base, // IN void *sslCtx) // IN: optional { #ifndef USE_SSL_DIRECT AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); if (sslCtx) { return SSL_AcceptWithContext(asock->sslSock, sslCtx); } else { return SSL_Accept(asock->sslSock); } #else return FALSE; #endif } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketSslConnectCallback -- * * Poll callback to redrive an outstanding ssl connect operation. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketSslConnectCallback(void *clientData) // IN { #ifndef USE_SSL_DIRECT int sslOpCode; VMwareStatus pollStatus; AsyncTCPSocket *asock = clientData; ASSERT(asock); ASSERT(AsyncTCPSocketPollParams(asock)->iPoll == NULL); ASSERT(AsyncTCPSocketIsLocked(asock)); AsyncTCPSocketAddRef(asock); /* Only set if poll callback is registered */ asock->sslPollFlags = 0; sslOpCode = SSL_TryCompleteConnect(asock->sslSock); if (sslOpCode > 0) { (*asock->sslConnectFn)(TRUE, BaseSocket(asock), asock->clientData); } else if (sslOpCode < 0) { (*asock->sslConnectFn)(FALSE, BaseSocket(asock), asock->clientData); } else { asock->sslPollFlags = SSL_WantRead(asock->sslSock) ? POLL_FLAG_READ : POLL_FLAG_WRITE; /* register the poll callback to redrive the SSL connect */ pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, asock->sslPollFlags, AsyncTCPSocketSslConnectCallback); if (pollStatus != VMWARE_STATUS_SUCCESS) { TCPSOCKWARN(asock, "failed to reinstall ssl connect callback!\n"); asock->sslPollFlags = 0; (*asock->sslConnectFn)(FALSE, BaseSocket(asock), asock->clientData); } } AsyncTCPSocketRelease(asock); #else NOT_IMPLEMENTED(); #endif } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketStartSslConnect -- * * Start an asynchronous SSL connect operation. * * The supplied callback function is called when the operation is complete * or an error occurs. * * Note: The client callback could be invoked from this function or * from a poll callback. If there is any requirement to always * invoke the client callback from outside this function, consider * changing this code to use a poll timer callback with timeout * set to zero. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_*. * Errors during async processing are reported using the callback supplied. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int AsyncTCPSocketStartSslConnect(AsyncSocket *base, // IN SSLVerifyParam *verifyParam, // IN/OPT const char *hostname, // IN/OPT void *sslCtx, // IN AsyncSocketSslConnectFn sslConnectFn, // IN void *clientData) // IN { #ifndef USE_SSL_DIRECT AsyncTCPSocket *asock = TCPSocket(base); Bool ok; ASSERT(asock); ASSERT(sslConnectFn); ASSERT(AsyncTCPSocketIsLocked(asock)); if (asock->sslConnectFn || asock->sslAcceptFn) { TCPSOCKWARN(asock, "An SSL operation was already initiated.\n"); return ASOCKERR_GENERIC; } ok = SSL_SetupConnectAndVerifyWithContext(asock->sslSock, verifyParam, hostname, sslCtx); if (!ok) { /* Something went wrong already */ (*sslConnectFn)(FALSE, BaseSocket(asock), clientData); return ASOCKERR_GENERIC; } asock->sslConnectFn = sslConnectFn; asock->clientData = clientData; AsyncTCPSocketSslConnectCallback(asock); return ASOCKERR_SUCCESS; #else return ASOCKERR_INVAL; #endif } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketSslAcceptCallback -- * * Poll callback for redrive an outstanding ssl accept operation * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void AsyncTCPSocketSslAcceptCallback(void *clientData) // IN { int sslOpCode; AsyncTCPSocket *asock = clientData; VMwareStatus pollStatus; ASSERT(asock); ASSERT(AsyncTCPSocketPollParams(asock)->iPoll == NULL); ASSERT(AsyncTCPSocketIsLocked(asock)); AsyncTCPSocketAddRef(asock); /* Only set if poll callback is registered */ asock->sslPollFlags = 0; sslOpCode = SSL_TryCompleteAccept(asock->sslSock); if (sslOpCode > 0) { (*asock->sslAcceptFn)(TRUE, BaseSocket(asock), asock->clientData); } else if (sslOpCode < 0) { (*asock->sslAcceptFn)(FALSE, BaseSocket(asock), asock->clientData); } else { asock->sslPollFlags = SSL_WantRead(asock->sslSock) ? POLL_FLAG_READ : POLL_FLAG_WRITE; /* register the poll callback to redrive the SSL accept */ pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, asock->sslPollFlags, AsyncTCPSocketSslAcceptCallback); if (pollStatus != VMWARE_STATUS_SUCCESS) { TCPSOCKWARN(asock, "failed to reinstall ssl accept callback!\n"); asock->sslPollFlags = 0; (*asock->sslAcceptFn)(FALSE, BaseSocket(asock), asock->clientData); } } AsyncTCPSocketRelease(asock); } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketStartSslAccept -- * * Start an asynchronous SSL accept operation. * * The supplied callback function is called when the operation is complete * or an error occurs. * * Note: The client callback could be invoked from this function or * from a poll callback. If there is any requirement to always * invoke the client callback from outside this function, consider * changing this code to use a poll timer callback with timeout * set to zero. * * Note: sslCtx is typed as void *, so that the async socket code does * not have to include the openssl header. This is in sync with * SSL_AcceptWithContext(), where the sslCtx param is typed as void * * Results: * ASOCKERR_SUCCESS or ASOCKERR_*. * Errors during async processing reported using the callback supplied. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int AsyncTCPSocketStartSslAccept(AsyncSocket *base, // IN void *sslCtx, // IN AsyncSocketSslAcceptFn sslAcceptFn, // IN void *clientData) // IN { AsyncTCPSocket *asock = TCPSocket(base); Bool ok; ASSERT(asock); ASSERT(sslAcceptFn); ASSERT(AsyncTCPSocketIsLocked(asock)); if (asock->sslAcceptFn || asock->sslConnectFn) { TCPSOCKWARN(asock, "An SSL operation was already initiated.\n"); return ASOCKERR_GENERIC; } ok = SSL_SetupAcceptWithContext(asock->sslSock, sslCtx); if (!ok) { /* Something went wrong already */ (*sslAcceptFn)(FALSE, BaseSocket(asock), clientData); return ASOCKERR_GENERIC; } asock->sslAcceptFn = sslAcceptFn; asock->clientData = clientData; AsyncTCPSocketSslAcceptCallback(asock); return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketSetOption -- * * This implementation of ->setOption() supports the following * options. Exact behavior of each cited optID is documented in the * comment header for that enum value declaration (for non-native options), * or `man setsockopt`/equivalent (for native options). * * - layer = SOL_SOCKET, optID = * SO_SNDBUF, SO_RCVBUF. * * - layer = IPPROTO_TCP, optID = * TCP_NODELAY, TCP_KEEPINTVL, TCP_KEEPIDLE, TCP_KEEPCNT. * * - layer = ASYNC_SOCKET_OPTS_LAYER_BASE, optID (type) = * ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE (Bool). * * Results: * ASOCKERR_SUCCESS on success, ASOCKERR_* otherwise. * Invalid option+layer yields ASOCKERR_INVAL. * Failure to set a native OS option yields ASOCKERR_GENERIC. * inBufLen being wrong (for the given option) yields undefined behavior. * * Side effects: * Depends on option. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketSetOption(AsyncSocket *asyncSocket, // IN/OUT AsyncSocketOpts_Layer layer, // IN AsyncSocketOpts_ID optID, // IN const void *valuePtr, // IN socklen_t inBufLen) // IN { /* Maintenance: Keep this in sync with ...GetOption(). */ AsyncTCPSocket *tcpSocket = TCPSocket(asyncSocket); Bool isSupported; switch ((int)layer) { case SOL_SOCKET: case IPPROTO_TCP: case ASYNC_SOCKET_OPTS_LAYER_BASE: break; default: TCPSOCKLG0(tcpSocket, "%s: Option layer [%d] (option [%d]) is not " "supported for TCP socket.\n", __FUNCTION__, (int)layer, optID); return ASOCKERR_INVAL; } /* * layer is supported. * Handle non-native options first. */ if (layer == ASYNC_SOCKET_OPTS_LAYER_BASE) { switch (optID) { case ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE: ASSERT(inBufLen == sizeof(Bool)); tcpSocket->sendLowLatency = *((const Bool *)valuePtr); TCPSOCKLG0(tcpSocket, "%s: sendLowLatencyMode set to [%d].\n", __FUNCTION__, (int)tcpSocket->sendLowLatency); return ASOCKERR_SUCCESS; default: TCPSOCKLG0(tcpSocket, "%s: could not set non-native option [%d]" " for TCP socket -- option not supported.\n", __FUNCTION__, (int)optID); return ASOCKERR_INVAL; } } /* * Handle native (setsockopt()) options from this point on. * * We need the level and option_name arguments for that call. * Our design dictates that, for native options, simply option_name=optID. * So just determine level from our layer enum (for native layers, the enum's * ordinal value is set to the corresponding int level value). Therefore, * level=layer. * * level and option_name are known. However, we only allow the setting of * certain specific options. Anything else is an error. */ isSupported = FALSE; if (layer == SOL_SOCKET) { switch (optID) { case SO_SNDBUF: case SO_RCVBUF: isSupported = TRUE; } } else { ASSERT((int)layer == IPPROTO_TCP); switch (optID) { /* * Note: All but TCP_KEEPIDLE are available in Mac OS X (at least * 10.11). iOS and Android are TBD. For now, let's keep it simple and * make all these available in the two known OS where all 3 exist * together, as they're typically often set as a group. * TODO: Possibly enable for other OS in more fine-grained fashion. */ #if defined(__linux__) || defined(VMX86_SERVER) case TCP_KEEPIDLE: case TCP_KEEPINTVL: case TCP_KEEPCNT: #endif case TCP_NODELAY: isSupported = TRUE; } } if (!isSupported) { TCPSOCKLG0(tcpSocket, "%s: Option layer/level [%d], option/name [%d]: " "could not set OS option for TCP socket; " "option not supported.\n", __FUNCTION__, (int)layer, optID); return ASOCKERR_INVAL; } /* All good. Ready to actually set the OS option. */ if (setsockopt(tcpSocket->fd, layer, optID, valuePtr, inBufLen) != 0) { tcpSocket->genericErrno = Err_Errno(); TCPSOCKLG0(tcpSocket, "%s: Option layer/level [%d], option/name [%d]: " "could not set OS option for TCP socket; " "error [%d: %s].\n", __FUNCTION__, (int)layer, optID, tcpSocket->genericErrno, Err_Errno2String(tcpSocket->genericErrno)); return ASOCKERR_GENERIC; } TCPSOCKLG0(tcpSocket, "%s: Option layer/level [%d], option/name [%d]: successfully " "set OS option for TCP socket.\n", __FUNCTION__, (int)layer, optID); return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * * AsyncTCPSocketGetOption -- * * This is the reverse of AsyncTCPSocketSetOption(). * * Results: * ASOCKERR_SUCCESS on success, ASOCKERR_* otherwise. * Invalid option+layer yields ASOCKERR_INVAL. * Failure to get a native OS option yields ASOCKERR_GENERIC. * *outBufLen being wrong (for the given option) at entry to function * yields undefined behavior. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static int AsyncTCPSocketGetOption(AsyncSocket *asyncSocket, // IN/OUT AsyncSocketOpts_Layer layer, // IN AsyncSocketOpts_ID optID, // IN void *valuePtr, // OUT socklen_t *outBufLen) // IN/OUT { /* * Maintenance: Keep this in sync with ...GetOption(). * Substantive comments are kept light to avoid redundancy (refer to the * other function). */ AsyncTCPSocket *tcpSocket = TCPSocket(asyncSocket); Bool isSupported; switch ((int)layer) { case SOL_SOCKET: case IPPROTO_TCP: case ASYNC_SOCKET_OPTS_LAYER_BASE: break; default: TCPSOCKLG0(tcpSocket, "%s: Option layer [%d] (option [%d]) is not " "supported for TCP socket.\n", __FUNCTION__, (int)layer, optID); return ASOCKERR_INVAL; } if ((layer == ASYNC_SOCKET_OPTS_LAYER_BASE) && (optID == ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE)) { ASSERT(*outBufLen >= sizeof(Bool)); *outBufLen = sizeof(Bool); *((Bool *)valuePtr) = tcpSocket->sendLowLatency; TCPSOCKLG0(tcpSocket, "%s: sendLowLatencyMode is [%d].\n", __FUNCTION__, (int)tcpSocket->sendLowLatency); return ASOCKERR_SUCCESS; } isSupported = FALSE; if (layer == SOL_SOCKET) { switch (optID) { case SO_SNDBUF: case SO_RCVBUF: isSupported = TRUE; } } else { ASSERT((int)layer == IPPROTO_TCP); switch (optID) { #ifdef __linux__ case TCP_KEEPIDLE: case TCP_KEEPINTVL: case TCP_KEEPCNT: #endif case TCP_NODELAY: isSupported = TRUE; } } if (!isSupported) { TCPSOCKLG0(tcpSocket, "%s: Option layer/level [%d], option/name [%d]: " "could not get OS option for TCP socket; " "option not supported.\n", __FUNCTION__, (int)layer, optID); return ASOCKERR_INVAL; } if (getsockopt(tcpSocket->fd, layer, optID, valuePtr, outBufLen) != 0) { tcpSocket->genericErrno = Err_Errno(); TCPSOCKLG0(tcpSocket, "%s: Option layer/level [%d], option/name [%d]: " "could not get OS option for TCP socket; " "error [%d: %s].\n", __FUNCTION__, (int)layer, optID, tcpSocket->genericErrno, Err_Errno2String(tcpSocket->genericErrno)); return ASOCKERR_GENERIC; } TCPSOCKLG0(tcpSocket, "%s: Option layer/level [%d], option/name [%d]: successfully " "got OS option for TCP socket.\n", __FUNCTION__, (int)layer, optID); return ASOCKERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * AsyncTCPSocketDestroy -- * * Free the AsyncTCPSocket struct and all of its child storage. * * Result * None * * Side-effects * Releases memory. * *----------------------------------------------------------------------------- */ static void AsyncTCPSocketDestroy(AsyncSocket *base) // IN/OUT { free(base); } #ifndef _WIN32 /* *----------------------------------------------------------------------------- * * AsyncSocket_ListenSocketUDS -- * * Listens on the specified unix domain socket, and accepts new * socket connections. Fires the connect callback with new * AsyncTCPSocket object for each connection. * * Results: * New AsyncTCPSocket in listening state or NULL on error * * Side effects: * Creates new Unix domain socket, binds and listens. * *----------------------------------------------------------------------------- */ AsyncSocket * AsyncSocket_ListenSocketUDS(const char *pipeName, // IN AsyncSocketConnectFn connectFn, // IN void *clientData, // IN AsyncSocketPollParams *pollParams, // IN int *outError) // OUT: optional { struct sockaddr_un addr; AsyncTCPSocket *asock; int tempError = ASOCKERR_SUCCESS; memset(&addr, 0, sizeof addr); addr.sun_family = AF_UNIX; Str_Strcpy(addr.sun_path, pipeName, sizeof addr.sun_path); asock = AsyncTCPSocketListenImpl((struct sockaddr_storage *)&addr, sizeof addr, connectFn, clientData, pollParams, &tempError); if (outError) { *outError = tempError; } return BaseSocket(asock); } #endif /* *----------------------------------------------------------------------------- * * AsyncTCPSocketListenerError -- * * Call the error handler from parent AsyncSocket object. The passed in * parameter clientData is the parent AsyncSocket object. * * Result * None * * Side-effects * None * *----------------------------------------------------------------------------- */ static void AsyncTCPSocketListenerError(int error, // IN AsyncSocket *asock, // IN void *clientData) // IN { AsyncSocket *s = clientData; ASSERT(s); AsyncSocketHandleError(s, error); } /* *----------------------------------------------------------------------------- * * AsyncSocket_SetKeepAlive -- * * Set keep-alive socket option. * * Results: * TRUE if successful. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool AsyncSocket_SetKeepAlive(AsyncSocket *asock, // IN int keepIdle) // IN { int fd; fd = AsyncSocket_GetFd(asock); if (fd < 0) { Log(ASOCKPREFIX "(%p) is not valid.\n", asock); return FALSE; } #ifdef WIN32 { struct tcp_keepalive keepalive = { 1, keepIdle * 1000, keepIdle * 10 }; DWORD ret; if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &keepalive, sizeof keepalive, NULL, 0, &ret, NULL, NULL)) { Err_Number sysErr = ASOCK_LASTERROR(); ASOCKLG0(asock, "Could not set keepalive options, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); } } #else { static const int keepAlive = 1; if (keepIdle) { # ifdef TCP_KEEPIDLE # define VMTCP_KEEPIDLE TCP_KEEPIDLE # else # define VMTCP_KEEPIDLE TCP_KEEPALIVE # endif if (setsockopt(fd, IPPROTO_TCP, VMTCP_KEEPIDLE, (const char *)&keepIdle, sizeof keepIdle) != 0) { Err_Number sysErr = ASOCK_LASTERROR(); ASOCKLG0(asock, "Could not set TCP_KEEPIDLE, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); return FALSE; } # ifndef __APPLE__ { /* * Default TCP setting is 7200 sec idle, and 75 interval. So let's * divide keepIdle by 100 to get an interval. For our 300 seconds * default that is 3 seconds keepIdle. */ int keepIntvl = keepIdle / 100; if (keepIntvl < 1) { keepIntvl = 1; } if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, (const char *)&keepIntvl, sizeof keepIntvl) != 0) { Err_Number sysErr = ASOCK_LASTERROR(); ASOCKLG0(asock, "Could not set TCP_KEEPIDLE, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); return FALSE; } } # endif /* __APPLE__ */ } if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&keepAlive, sizeof keepAlive) != 0) { Err_Number sysErr = ASOCK_LASTERROR(); ASOCKLG0(asock, "Could not set TCP_KEEPIDLE, error %d: %s\n", sysErr, Err_Errno2String(sysErr)); return FALSE; } } #endif /* WIN32 */ return TRUE; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/auth/000077500000000000000000000000001470176644300220305ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/auth/Makefile.am000066400000000000000000000017671470176644300240770ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libAuth.la libAuth_la_SOURCES = libAuth_la_SOURCES += authPosix.c AM_CFLAGS = @LIB_AUTH_CPPFLAGS@ open-vm-tools-stable-12.5.0/open-vm-tools/lib/auth/authPosix.c000066400000000000000000000330271470176644300241650ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #include #include #include #include #include // for access, crypt, etc. #if !defined USE_PAM && !defined __APPLE__ #include #endif #include "vmware.h" #include "vm_product.h" #include "codeset.h" #include "posix.h" #include "auth.h" #include "str.h" #include "log.h" #ifdef USE_PAM # include "file.h" # include "config.h" # include "localconfig.h" # include # include #endif #if defined(HAVE_CONFIG_H) || defined(sun) # include #endif #define LOGLEVEL_MODULE auth #include "loglevel_user.h" typedef struct { struct passwd pwd; /* must be first member */ size_t bufSize; uint8 buf[]; } AuthTokenInternal; #ifdef USE_PAM #if defined(sun) #define CURRENT_PAM_LIBRARY "libpam.so.1" #elif defined(__FreeBSD__) #define CURRENT_PAM_LIBRARY "libpam.so" #elif defined(__APPLE__) #define CURRENT_PAM_LIBRARY "libpam.dylib" #else #define CURRENT_PAM_LIBRARY "libpam.so.0" #endif static typeof(&pam_start) dlpam_start; static typeof(&pam_end) dlpam_end; static typeof(&pam_authenticate) dlpam_authenticate; static typeof(&pam_setcred) dlpam_setcred; static typeof(&pam_acct_mgmt) dlpam_acct_mgmt; static typeof(&pam_strerror) dlpam_strerror; #if 0 /* These three functions are not used yet */ static typeof(&pam_open_session) dlpam_open_session; static typeof(&pam_close_session) dlpam_close_session; static typeof(&pam_chauthtok) dlpam_chauthtok; #endif static struct { void **procaddr; const char *procname; } authPAMImported[] = { #define IMPORT_SYMBOL(x) { (void **)&dl##x, #x } IMPORT_SYMBOL(pam_start), IMPORT_SYMBOL(pam_end), IMPORT_SYMBOL(pam_authenticate), IMPORT_SYMBOL(pam_setcred), IMPORT_SYMBOL(pam_acct_mgmt), IMPORT_SYMBOL(pam_strerror), #undef IMPORT_SYMBOL }; static void *authPamLibraryHandle = NULL; /* *---------------------------------------------------------------------- * * AuthLoadPAM -- * * Attempt to load and initialize PAM library. * * Results: * FALSE if load and/or initialization failed. * TRUE if initialization succeeded. * * Side effects: * libpam loaded. We never unload - some libpam modules use * syslog() function, and glibc does not survive when arguments * specified to openlog() are freeed from memory. * *---------------------------------------------------------------------- */ static Bool AuthLoadPAM(void) { void *pam_library; int i; if (authPamLibraryHandle) { return TRUE; } pam_library = Posix_Dlopen(CURRENT_PAM_LIBRARY, RTLD_LAZY | RTLD_GLOBAL); if (!pam_library) { #if defined(VMX86_TOOLS) /* * XXX do we even try to configure the pam libraries? * potential nightmare on all the possible guest OSes */ Log("System PAM libraries are unusable: %s\n", dlerror()); return FALSE; #else char *liblocation; char *libdir; libdir = LocalConfig_GetPathName(DEFAULT_LIBDIRECTORY, CONFIG_VMWAREDIR); if (!libdir) { Log("System PAM library unusable and bundled one not found.\n"); return FALSE; } liblocation = Str_SafeAsprintf(NULL, "%s/lib/%s/%s", libdir, CURRENT_PAM_LIBRARY, CURRENT_PAM_LIBRARY); free(libdir); pam_library = Posix_Dlopen(liblocation, RTLD_LAZY | RTLD_GLOBAL); if (!pam_library) { Log("Neither system nor bundled (%s) PAM libraries usable: %s\n", liblocation, dlerror()); free(liblocation); return FALSE; } free(liblocation); #endif } for (i = 0; i < ARRAYSIZE(authPAMImported); i++) { void *symbol = dlsym(pam_library, authPAMImported[i].procname); if (!symbol) { Log("PAM library does not contain required function: %s\n", dlerror()); dlclose(pam_library); return FALSE; } *(authPAMImported[i].procaddr) = symbol; } authPamLibraryHandle = pam_library; Log("PAM up and running.\n"); return TRUE; } static const char *PAM_username; static const char *PAM_password; #if defined(sun) static int PAM_conv (int num_msg, // IN: struct pam_message **msg, // IN: struct pam_response **resp, // OUT: void *appdata_ptr) // IN: #else static int PAM_conv (int num_msg, // IN: const struct pam_message **msg, // IN: struct pam_response **resp, // OUT: void *appdata_ptr) // IN: #endif { int count; struct pam_response *reply = calloc(num_msg, sizeof *reply); if (!reply) { return PAM_CONV_ERR; } for (count = 0; count < num_msg; count++) { switch (msg[count]->msg_style) { case PAM_PROMPT_ECHO_ON: reply[count].resp_retcode = PAM_SUCCESS; reply[count].resp = PAM_username ? strdup(PAM_username) : NULL; /* PAM frees resp */ break; case PAM_PROMPT_ECHO_OFF: reply[count].resp_retcode = PAM_SUCCESS; reply[count].resp = PAM_password ? strdup(PAM_password) : NULL; /* PAM frees resp */ break; case PAM_TEXT_INFO: reply[count].resp_retcode = PAM_SUCCESS; reply[count].resp = NULL; /* ignore it... */ break; case PAM_ERROR_MSG: reply[count].resp_retcode = PAM_SUCCESS; reply[count].resp = NULL; /* Must be an error of some sort... */ default: while (--count >= 0) { free(reply[count].resp); } free(reply); return PAM_CONV_ERR; } } *resp = reply; return PAM_SUCCESS; } static struct pam_conv PAM_conversation = { &PAM_conv, NULL }; #endif /* USE_PAM */ /* *---------------------------------------------------------------------- * * AuthAllocateToken -- * * Allocates an AuthTokenInternal structure, plus helper buffer * large enough for the Posix_Get*_r calls. * * Side effects: * None. * * Results: * An AuthTokenInternal pointer. Free with Auth_CloseToken. * *---------------------------------------------------------------------- */ static AuthTokenInternal * AuthAllocateToken(void) { long bufSize; AuthTokenInternal *ati; /* * We need to get the maximum size buffer needed by getpwuid_r from * sysconf. Multiply by 4 to compensate for the conversion to UTF-8 * by the Posix_Get*_r() wrappers. */ errno = 0; bufSize = sysconf(_SC_GETPW_R_SIZE_MAX); if ((errno != 0) || (bufSize <= 0)) { bufSize = 16 * 1024; // Unlimited; pick something reasonable } bufSize *= 4; ati = Util_SafeMalloc(sizeof *ati + (size_t) bufSize); ati->bufSize = bufSize; return ati; } /* *---------------------------------------------------------------------- * * Auth_GetPwnam -- * * Wrapper aroung Posix_Getpwnam_r. * * Side effects: * None. * * Results: * An AuthToken. Free with Auth_CloseToken. * *---------------------------------------------------------------------- */ AuthToken Auth_GetPwnam(const char *user) // IN { AuthTokenInternal *ati; int res; struct passwd *ppwd; ASSERT(user); ati = AuthAllocateToken(); res = Posix_Getpwnam_r(user, &ati->pwd, ati->buf, ati->bufSize, &ppwd); if ((0 != res) || (ppwd == NULL)) { Auth_CloseToken((AuthToken) ati); return NULL; } ASSERT(ppwd == &ati->pwd); return (AuthToken) ati; } /* *---------------------------------------------------------------------- * * Auth_AuthenticateSelf -- * * Authenticate as the current user. * * Side effects: * None. * * Results: * An AuthToken. Free with Auth_CloseToken. * *---------------------------------------------------------------------- */ AuthToken Auth_AuthenticateSelf(void) // IN { AuthTokenInternal *ati; int res; struct passwd *ppwd; ati = AuthAllocateToken(); res = Posix_Getpwuid_r(getuid(), &ati->pwd, ati->buf, ati->bufSize, &ppwd); if ((0 != res) || (ppwd == NULL)) { Auth_CloseToken((AuthToken) ati); return NULL; } ASSERT(ppwd == &ati->pwd); return (AuthToken) ati; } /* *---------------------------------------------------------------------- * * Auth_AuthenticateUserPAM -- * * Accept username/password, and service and verfiy it with PAM * * Side effects: * None. * * Results: * * The vmauthToken for the authenticated user, or NULL if * authentication failed. * *---------------------------------------------------------------------- */ AuthToken Auth_AuthenticateUserPAM(const char *user, // IN: const char *pass, // IN: const char *service) // IN: { #ifndef USE_PAM return NULL; #else pam_handle_t *pamh; int pam_error; Bool success = FALSE; AuthTokenInternal *ati = NULL; ASSERT(service); if (!CodeSet_Validate(user, strlen(user), "UTF-8")) { Log("User not in UTF-8\n"); goto exit; } if (!CodeSet_Validate(pass, strlen(pass), "UTF-8")) { Log("Password not in UTF-8\n"); goto exit; } if (!AuthLoadPAM()) { goto exit; } /* * XXX PAM can blow away our syslog level settings so we need * to call Log_InitEx() again before doing any more Log()s */ #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \ Log_Error("%s:%d: PAM failure - %s (%d)\n", \ __FUNCTION__, __LINE__, \ dlpam_strerror(pamh, pam_error), pam_error); \ dlpam_end(pamh, pam_error); \ goto exit; \ } PAM_username = user; PAM_password = pass; pam_error = dlpam_start(service, PAM_username, &PAM_conversation, &pamh); if (pam_error != PAM_SUCCESS) { Log("Failed to start PAM (error = %d).\n", pam_error); goto exit; } pam_error = dlpam_authenticate(pamh, 0); PAM_BAIL; pam_error = dlpam_acct_mgmt(pamh, 0); PAM_BAIL; pam_error = dlpam_setcred(pamh, PAM_ESTABLISH_CRED); PAM_BAIL; dlpam_end(pamh, PAM_SUCCESS); #undef PAM_BAIL /* If this point is reached, the user has been authenticated. */ ati = (AuthTokenInternal *) Auth_GetPwnam(user); success = TRUE; exit: if (success) { return (AuthToken) ati; } else { Auth_CloseToken((AuthToken) ati); return NULL; } #endif // USE_PAM } /* *---------------------------------------------------------------------- * * Auth_AuthenticateUser -- * * Accept username/password And verfiy it * * Side effects: * None. * * Results: * * The vmauthToken for the authenticated user, or NULL if * authentication failed. * *---------------------------------------------------------------------- */ AuthToken Auth_AuthenticateUser(const char *user, // IN: const char *pass) // IN: { #ifdef USE_PAM #if defined(VMX86_TOOLS) return Auth_AuthenticateUserPAM(user, pass, "vmtoolsd"); #else return Auth_AuthenticateUserPAM(user, pass, "vmware-authd"); #endif #else /* !USE_PAM */ Bool success = FALSE; AuthTokenInternal *ati = NULL; if (!CodeSet_Validate(user, strlen(user), "UTF-8")) { Log("User not in UTF-8\n"); goto exit; } if (!CodeSet_Validate(pass, strlen(pass), "UTF-8")) { Log("Password not in UTF-8\n"); goto exit; } /* All of the following issues are dealt with in the PAM configuration file, so put all authentication/priviledge checks before the corresponding #endif below. */ ati = (AuthTokenInternal *) Auth_GetPwnam(user); if (ati == NULL) { goto exit; } if (*ati->pwd.pw_passwd != '\0') { const char *pw = ati->pwd.pw_passwd; const char *namep; #if !defined __APPLE__ // support shadow passwords: if (strcmp(pw, "x") == 0) { struct spwd *sp = getspnam(user); if (sp) { pw = sp->sp_pwdp; } } #endif namep = crypt(pass, pw); if (namep == NULL || strcmp(namep, pw) != 0) { // Incorrect password goto exit; } // Clear out crypt()'s internal state, too. crypt("glurp", pw); } success = TRUE; exit: if (success) { return (AuthToken) ati; } else { Auth_CloseToken((AuthToken) ati); return NULL; } #endif /* !USE_PAM */ } /* *---------------------------------------------------------------------- * * Auth_CloseToken -- * * Free the token allocated in Auth_AuthenticateUser. * * Side effects: * None * * Results: * None * *---------------------------------------------------------------------- */ void Auth_CloseToken(AuthToken token) // IN (OPT): { free((void *) token); } open-vm-tools-stable-12.5.0/open-vm-tools/lib/backdoor/000077500000000000000000000000001470176644300226535ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/backdoor/Makefile.am000066400000000000000000000022541470176644300247120ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016,2019 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libBackdoor.la libBackdoor_la_SOURCES = libBackdoor_la_SOURCES += backdoor.c if ARCH_X32 libBackdoor_la_SOURCES += backdoorGcc32.c endif if ARCH_X64 libBackdoor_la_SOURCES += backdoorGcc64.c endif if ARCH_ARM64 libBackdoor_la_SOURCES += backdoorGcc64_arm64.c endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/backdoor/backdoor.c000066400000000000000000000311511470176644300246040ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1999-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * backdoor.c -- * * First layer of the internal communication channel between guest * applications and vmware * * This is the backdoor. By using special ports of the virtual I/O space, * and the virtual CPU registers, a guest application can send a * synchroneous basic request to vmware, and vmware can reply to it. */ #ifdef __cplusplus extern "C" { #endif #include "backdoor_def.h" #include "backdoor.h" #include "backdoorInt.h" #if defined(USE_HYPERCALL) #include "vm_assert.h" #include "x86cpuid.h" #include "x86cpuid_asm.h" #endif #ifdef USE_VALGRIND /* * When running under valgrind, we need to ensure we have the correct register * state when poking the backdoor. The VALGRIND_NON_SIMD_CALLx macros are used * to escape from the valgrind emulated CPU to the physical CPU. */ #include "vm_valgrind.h" #endif #if defined(BACKDOOR_DEBUG) && defined(USERLEVEL) #if defined(__KERNEL__) || defined(_KERNEL) #else # include "debug.h" #endif # include # define BACKDOOR_LOG(...) Debug(__VA_ARGS__) # define BACKDOOR_LOG_PROTO_STRUCT(x) BackdoorPrintProtoStruct((x)) # define BACKDOOR_LOG_HB_PROTO_STRUCT(x) BackdoorPrintHbProtoStruct((x)) /* *---------------------------------------------------------------------------- * * BackdoorPrintProtoStruct -- * BackdoorPrintHbProtoStruct -- * * Print the contents of the specified backdoor protocol structure via * printf. * * Results: * None. * * Side effects: * Output to stdout. * *---------------------------------------------------------------------------- */ void BackdoorPrintProtoStruct(Backdoor_proto *myBp) { Debug("magic 0x%08x, command %d, size %"FMTSZ"u, port %d\n", myBp->in.ax.word, myBp->in.cx.halfs.low, myBp->in.size, myBp->in.dx.halfs.low); #ifndef VM_X86_64 Debug("ax %#x, " "bx %#x, " "cx %#x, " "dx %#x, " "si %#x, " "di %#x\n", myBp->out.ax.word, myBp->out.bx.word, myBp->out.cx.word, myBp->out.dx.word, myBp->out.si.word, myBp->out.di.word); #else Debug("ax %#"FMT64"x, " "bx %#"FMT64"x, " "cx %#"FMT64"x, " "dx %#"FMT64"x, " "si %#"FMT64"x, " "di %#"FMT64"x\n", myBp->out.ax.quad, myBp->out.bx.quad, myBp->out.cx.quad, myBp->out.dx.quad, myBp->out.si.quad, myBp->out.di.quad); #endif } void BackdoorPrintHbProtoStruct(Backdoor_proto_hb *myBp) { Debug("magic 0x%08x, command %d, size %"FMTSZ"u, port %d, " "srcAddr %"FMTSZ"u, dstAddr %"FMTSZ"u\n", myBp->in.ax.word, myBp->in.bx.halfs.low, myBp->in.size, myBp->in.dx.halfs.low, myBp->in.srcAddr, myBp->in.dstAddr); #ifndef VM_X86_64 Debug("ax %#x, " "bx %#x, " "cx %#x, " "dx %#x, " "si %#x, " "di %#x, " "bp %#x\n", myBp->out.ax.word, myBp->out.bx.word, myBp->out.cx.word, myBp->out.dx.word, myBp->out.si.word, myBp->out.di.word, myBp->out.bp.word); #else Debug("ax %#"FMT64"x, " "bx %#"FMT64"x, " "cx %#"FMT64"x, " "dx %#"FMT64"x, " "si %#"FMT64"x, " "di %#"FMT64"x, " "bp %#"FMT64"x\n", myBp->out.ax.quad, myBp->out.bx.quad, myBp->out.cx.quad, myBp->out.dx.quad, myBp->out.si.quad, myBp->out.di.quad, myBp->out.bp.quad); #endif } #else # define BACKDOOR_LOG(...) # define BACKDOOR_LOG_PROTO_STRUCT(x) # define BACKDOOR_LOG_HB_PROTO_STRUCT(x) #endif #if defined(USE_HYPERCALL) /* Setting 'backdoorInterface' is idempotent, no atomic access is required. */ static BackdoorInterface backdoorInterface = BACKDOOR_INTERFACE_NONE; static BackdoorInterface BackdoorGetInterface(void) { if (UNLIKELY(backdoorInterface == BACKDOOR_INTERFACE_NONE)) { CPUIDRegs regs; /* Check whether we're on a VMware hypervisor that supports vmmcall. */ __GET_CPUID(1, ®s); if (CPUID_ISSET(1, ECX, HYPERVISOR, regs.ecx)) { __GET_CPUID(CPUID_HYPERVISOR_LEVEL_0, ®s); if (CPUID_IsRawVendor(®s, CPUID_VMWARE_HYPERVISOR_VENDOR_STRING)) { if (__GET_EAX_FROM_CPUID(CPUID_HYPERVISOR_LEVEL_0) >= CPUID_VMW_FEATURES) { uint32 features = __GET_ECX_FROM_CPUID(CPUID_VMW_FEATURES); if (CPUID_ISSET(CPUID_VMW_FEATURES, ECX, VMCALL_BACKDOOR, features)) { backdoorInterface = BACKDOOR_INTERFACE_VMCALL; BACKDOOR_LOG("Backdoor interface: vmcall\n"); } else if (CPUID_ISSET(CPUID_VMW_FEATURES, ECX, VMMCALL_BACKDOOR, features)) { backdoorInterface = BACKDOOR_INTERFACE_VMMCALL; BACKDOOR_LOG("Backdoor interface: vmmcall\n"); } } } } if (backdoorInterface == BACKDOOR_INTERFACE_NONE) { backdoorInterface = BACKDOOR_INTERFACE_IO; BACKDOOR_LOG("Backdoor interface: I/O port\n"); } } return backdoorInterface; } #else static BackdoorInterface BackdoorGetInterface(void) { return BACKDOOR_INTERFACE_IO; } #endif /* *----------------------------------------------------------------------------- * * Backdoor_ForceLegacy -- * * In some cases, it may be desirable to use the legacy IO interface to * access the backdoor, even if CPUID reports support for the VMCALL/VMMCALL * interface. * * Params: * force Set to TRUE to force the library to use the legacy IO interface * for dispatching backdoor calls; set to FALSE to use the * autodetected interface. * * Side-effects: * Changes the interface used to access the backdoor. * *----------------------------------------------------------------------------- */ #if defined(USE_HYPERCALL) void Backdoor_ForceLegacy(Bool force) { if (force) { backdoorInterface = BACKDOOR_INTERFACE_IO; } else { backdoorInterface = BACKDOOR_INTERFACE_NONE; BackdoorGetInterface(); } } #endif /* *----------------------------------------------------------------------------- * * Backdoor -- * * Send a low-bandwidth basic request (16 bytes) to vmware, and return its * reply (24 bytes). * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ #ifdef USE_VALGRIND static void BackdoorInOutValgrind(uint16 tid, Backdoor_proto *myBp) { Backdoor_InOut(myBp); } static void BackdoorHbInValgrind(uint16 tid, Backdoor_proto_hb *myBp) { BackdoorHbIn(myBp); } static void BackdoorHbOutValgrind(uint16 tid, Backdoor_proto_hb *myBp) { BackdoorHbOut(myBp); } #if defined(USE_HYPERCALL) static void BackdoorVmcallValgrind(uint16 tid, Backdoor_proto *myBp) { Backdoor_Vmcall(myBp); } static void BackdoorVmmcallValgrind(uint16 tid, Backdoor_proto *myBp) { Backdoor_Vmmcall(myBp); } static void BackdoorHbVmcallValgrind(uint16 tid, Backdoor_proto_hb *myBp) { BackdoorHbVmcall(myBp); } static void BackdoorHbVmmcallValgrind(uint16 tid, Backdoor_proto_hb *myBp) { BackdoorHbVmmcall(myBp); } #endif #endif void Backdoor(Backdoor_proto *myBp) // IN/OUT { BackdoorInterface interface = BackdoorGetInterface(); ASSERT(myBp); myBp->in.ax.word = BDOOR_MAGIC; switch (interface) { case BACKDOOR_INTERFACE_IO: myBp->in.dx.halfs.low = BDOOR_PORT; break; #if defined(USE_HYPERCALL) case BACKDOOR_INTERFACE_VMCALL: // Fall through. case BACKDOOR_INTERFACE_VMMCALL: myBp->in.dx.halfs.low = BDOOR_FLAGS_LB | BDOOR_FLAGS_READ; break; #endif default: ASSERT(FALSE); break; } BACKDOOR_LOG("Backdoor: before "); BACKDOOR_LOG_PROTO_STRUCT(myBp); switch (interface) { case BACKDOOR_INTERFACE_IO: #ifdef USE_VALGRIND VALGRIND_NON_SIMD_CALL1(BackdoorInOutValgrind, myBp); #else Backdoor_InOut(myBp); #endif break; #if defined(USE_HYPERCALL) case BACKDOOR_INTERFACE_VMCALL: #ifdef USE_VALGRIND VALGRIND_NON_SIMD_CALL1(BackdoorVmcallValgrind, myBp); #else Backdoor_Vmcall(myBp); #endif break; case BACKDOOR_INTERFACE_VMMCALL: #ifdef USE_VALGRIND VALGRIND_NON_SIMD_CALL1(BackdoorVmmcallValgrind, myBp); #else Backdoor_Vmmcall(myBp); #endif break; #endif // defined(USE_HYPERCALL) default: ASSERT(FALSE); break; } BACKDOOR_LOG("Backdoor: after "); BACKDOOR_LOG_PROTO_STRUCT(myBp); } void BackdoorHb(Backdoor_proto_hb *myBp, // IN/OUT Bool outbound) // IN { BackdoorInterface interface = BackdoorGetInterface(); ASSERT(myBp); myBp->in.ax.word = BDOOR_MAGIC; switch (interface) { case BACKDOOR_INTERFACE_IO: myBp->in.dx.halfs.low = BDOORHB_PORT; break; #if defined(USE_HYPERCALL) case BACKDOOR_INTERFACE_VMCALL: // Fall through. case BACKDOOR_INTERFACE_VMMCALL: myBp->in.dx.halfs.low = BDOOR_FLAGS_HB; if (outbound) { myBp->in.dx.halfs.low |= BDOOR_FLAGS_WRITE; } else { myBp->in.dx.halfs.low |= BDOOR_FLAGS_READ; } break; #endif default: ASSERT(FALSE); break; } BACKDOOR_LOG("BackdoorHb: before "); BACKDOOR_LOG_HB_PROTO_STRUCT(myBp); switch (interface) { case BACKDOOR_INTERFACE_IO: if (outbound) { #ifdef USE_VALGRIND VALGRIND_NON_SIMD_CALL1(BackdoorHbOutValgrind, myBp); #else BackdoorHbOut(myBp); #endif } else { #ifdef USE_VALGRIND VALGRIND_NON_SIMD_CALL1(BackdoorHbInValgrind, myBp); #else BackdoorHbIn(myBp); #endif } break; #if defined(USE_HYPERCALL) case BACKDOOR_INTERFACE_VMCALL: #ifdef USE_VALGRIND VALGRIND_NON_SIMD_CALL1(BackdoorHbVmcallValgrind, myBp); #else BackdoorHbVmcall(myBp); #endif break; case BACKDOOR_INTERFACE_VMMCALL: #ifdef USE_VALGRIND VALGRIND_NON_SIMD_CALL1(BackdoorHbVmmcallValgrind, myBp); #else BackdoorHbVmmcall(myBp); #endif break; #endif default: ASSERT(FALSE); break; } BACKDOOR_LOG("BackdoorHb: after "); BACKDOOR_LOG_HB_PROTO_STRUCT(myBp); } /* *----------------------------------------------------------------------------- * * Backdoor_HbOut -- * * Send a high-bandwidth basic request to vmware, and return its * reply. * * Result: * The host-side response is returned via the IN/OUT parameter. * * Side-effects: * Pokes the high-bandwidth backdoor. * *----------------------------------------------------------------------------- */ void Backdoor_HbOut(Backdoor_proto_hb *myBp) // IN/OUT { ASSERT(myBp); BackdoorHb(myBp, TRUE); } /* *----------------------------------------------------------------------------- * * Backdoor_HbIn -- * * Send a basic request to vmware, and return its high-bandwidth * reply * * Result: * Host-side response returned via the IN/OUT parameter. * * Side-effects: * Pokes the high-bandwidth backdoor. * *----------------------------------------------------------------------------- */ void Backdoor_HbIn(Backdoor_proto_hb *myBp) // IN/OUT { ASSERT(myBp); BackdoorHb(myBp, FALSE); } #ifdef __cplusplus } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/backdoor/backdoorGcc32.c000066400000000000000000000263361470176644300253770ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2005-2016, 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * backdoorGcc32.c -- * * Implements the real work for guest-side backdoor for GCC, 32-bit * target (supports inline ASM, GAS syntax). The asm sections are marked * volatile since vmware can change the registers content without the * compiler knowing it. * * XXX * I tried to write this more cleanly, but: * - There is no way to specify an "ebp" constraint * - "ebp" is ignored when specified as cloberred register * - gas barfs when there is more than 10 operands * - gas 2.7.2.3, depending on the order of the operands, can * mis-assemble without any warning * --hpreg * * Note that the problems with gas noted above might longer be relevant * now that we've upgraded most of our compiler versions. * --rrdharan */ #ifdef __cplusplus extern "C" { #endif #include "backdoor.h" #include "backdoorInt.h" /* *---------------------------------------------------------------------------- * * Backdoor_InOut -- * * Send a low-bandwidth basic request (16 bytes) to vmware, and return its * reply (24 bytes). * * Results: * Host-side response returned in bp IN/OUT parameter. * * Side effects: * Pokes the backdoor. * *---------------------------------------------------------------------------- */ void Backdoor_InOut(Backdoor_proto *myBp) // IN/OUT { uint32 dummy; __asm__ __volatile__( #ifdef __PIC__ "pushl %%ebx" "\n\t" #endif "pushl %%eax" "\n\t" "movl 20(%%eax), %%edi" "\n\t" "movl 16(%%eax), %%esi" "\n\t" "movl 12(%%eax), %%edx" "\n\t" "movl 8(%%eax), %%ecx" "\n\t" "movl 4(%%eax), %%ebx" "\n\t" "movl (%%eax), %%eax" "\n\t" "inl %%dx, %%eax" "\n\t" "xchgl %%eax, (%%esp)" "\n\t" "movl %%edi, 20(%%eax)" "\n\t" "movl %%esi, 16(%%eax)" "\n\t" "movl %%edx, 12(%%eax)" "\n\t" "movl %%ecx, 8(%%eax)" "\n\t" "movl %%ebx, 4(%%eax)" "\n\t" "popl (%%eax)" "\n\t" #ifdef __PIC__ "popl %%ebx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. So far it does not modify EFLAGS. --hpreg */ : #ifndef __PIC__ "ebx", #endif "ecx", "edx", "esi", "edi", "memory" ); } #if defined(USE_HYPERCALL) void Backdoor_Vmcall(Backdoor_proto *myBp) // IN/OUT { uint32 dummy; __asm__ __volatile__( #ifdef __PIC__ "pushl %%ebx" "\n\t" #endif "pushl %%eax" "\n\t" "movl 20(%%eax), %%edi" "\n\t" "movl 16(%%eax), %%esi" "\n\t" "movl 12(%%eax), %%edx" "\n\t" "movl 8(%%eax), %%ecx" "\n\t" "movl 4(%%eax), %%ebx" "\n\t" "movl (%%eax), %%eax" "\n\t" "vmcall" "\n\t" "xchgl %%eax, (%%esp)" "\n\t" "movl %%edi, 20(%%eax)" "\n\t" "movl %%esi, 16(%%eax)" "\n\t" "movl %%edx, 12(%%eax)" "\n\t" "movl %%ecx, 8(%%eax)" "\n\t" "movl %%ebx, 4(%%eax)" "\n\t" "popl (%%eax)" "\n\t" #ifdef __PIC__ "popl %%ebx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. So far it does not modify EFLAGS. --hpreg */ : #ifndef __PIC__ "ebx", #endif "ecx", "edx", "esi", "edi", "memory" ); } void Backdoor_Vmmcall(Backdoor_proto *myBp) // IN/OUT { uint32 dummy; __asm__ __volatile__( #ifdef __PIC__ "pushl %%ebx" "\n\t" #endif "pushl %%eax" "\n\t" "movl 20(%%eax), %%edi" "\n\t" "movl 16(%%eax), %%esi" "\n\t" "movl 12(%%eax), %%edx" "\n\t" "movl 8(%%eax), %%ecx" "\n\t" "movl 4(%%eax), %%ebx" "\n\t" "movl (%%eax), %%eax" "\n\t" "vmmcall" "\n\t" "xchgl %%eax, (%%esp)" "\n\t" "movl %%edi, 20(%%eax)" "\n\t" "movl %%esi, 16(%%eax)" "\n\t" "movl %%edx, 12(%%eax)" "\n\t" "movl %%ecx, 8(%%eax)" "\n\t" "movl %%ebx, 4(%%eax)" "\n\t" "popl (%%eax)" "\n\t" #ifdef __PIC__ "popl %%ebx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. So far it does not modify EFLAGS. --hpreg */ : #ifndef __PIC__ "ebx", #endif "ecx", "edx", "esi", "edi", "memory" ); } #endif /* *----------------------------------------------------------------------------- * * BackdoorHbIn -- * BackdoorHbOut -- * * Send a high-bandwidth basic request to vmware, and return its * reply. * * Results: * Host-side response returned in bp IN/OUT parameter. * * Side-effects: * Pokes the high-bandwidth backdoor port. * *----------------------------------------------------------------------------- */ void BackdoorHbIn(Backdoor_proto_hb *myBp) // IN/OUT { uint32 dummy; __asm__ __volatile__( #ifdef __PIC__ "pushl %%ebx" "\n\t" #endif "pushl %%ebp" "\n\t" "pushl %%eax" "\n\t" "movl 24(%%eax), %%ebp" "\n\t" "movl 20(%%eax), %%edi" "\n\t" "movl 16(%%eax), %%esi" "\n\t" "movl 12(%%eax), %%edx" "\n\t" "movl 8(%%eax), %%ecx" "\n\t" "movl 4(%%eax), %%ebx" "\n\t" "movl (%%eax), %%eax" "\n\t" "cld" "\n\t" "rep; insb" "\n\t" "xchgl %%eax, (%%esp)" "\n\t" "movl %%ebp, 24(%%eax)" "\n\t" "movl %%edi, 20(%%eax)" "\n\t" "movl %%esi, 16(%%eax)" "\n\t" "movl %%edx, 12(%%eax)" "\n\t" "movl %%ecx, 8(%%eax)" "\n\t" "movl %%ebx, 4(%%eax)" "\n\t" "popl (%%eax)" "\n\t" "popl %%ebp" "\n\t" #ifdef __PIC__ "popl %%ebx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. --hpreg */ : #ifndef __PIC__ "ebx", #endif "ecx", "edx", "esi", "edi", "memory", "cc" ); } void BackdoorHbOut(Backdoor_proto_hb *myBp) // IN/OUT { uint32 dummy; __asm__ __volatile__( #ifdef __PIC__ "pushl %%ebx" "\n\t" #endif "pushl %%ebp" "\n\t" "pushl %%eax" "\n\t" "movl 24(%%eax), %%ebp" "\n\t" "movl 20(%%eax), %%edi" "\n\t" "movl 16(%%eax), %%esi" "\n\t" "movl 12(%%eax), %%edx" "\n\t" "movl 8(%%eax), %%ecx" "\n\t" "movl 4(%%eax), %%ebx" "\n\t" "movl (%%eax), %%eax" "\n\t" "cld" "\n\t" "rep; outsb" "\n\t" "xchgl %%eax, (%%esp)" "\n\t" "movl %%ebp, 24(%%eax)" "\n\t" "movl %%edi, 20(%%eax)" "\n\t" "movl %%esi, 16(%%eax)" "\n\t" "movl %%edx, 12(%%eax)" "\n\t" "movl %%ecx, 8(%%eax)" "\n\t" "movl %%ebx, 4(%%eax)" "\n\t" "popl (%%eax)" "\n\t" "popl %%ebp" "\n\t" #ifdef __PIC__ "popl %%ebx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) : #ifndef __PIC__ "ebx", #endif "ecx", "edx", "esi", "edi", "memory", "cc" ); } #if defined(USE_HYPERCALL) void BackdoorHbVmcall(Backdoor_proto_hb *myBp) // IN/OUT { uint32 dummy; __asm__ __volatile__( #ifdef __PIC__ "pushl %%ebx" "\n\t" #endif "pushl %%ebp" "\n\t" "pushl %%eax" "\n\t" "movl 24(%%eax), %%ebp" "\n\t" "movl 20(%%eax), %%edi" "\n\t" "movl 16(%%eax), %%esi" "\n\t" "movl 12(%%eax), %%edx" "\n\t" "movl 8(%%eax), %%ecx" "\n\t" "movl 4(%%eax), %%ebx" "\n\t" "movl (%%eax), %%eax" "\n\t" "vmcall" "\n\t" "xchgl %%eax, (%%esp)" "\n\t" "movl %%ebp, 24(%%eax)" "\n\t" "movl %%edi, 20(%%eax)" "\n\t" "movl %%esi, 16(%%eax)" "\n\t" "movl %%edx, 12(%%eax)" "\n\t" "movl %%ecx, 8(%%eax)" "\n\t" "movl %%ebx, 4(%%eax)" "\n\t" "popl (%%eax)" "\n\t" "popl %%ebp" "\n\t" #ifdef __PIC__ "popl %%ebx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. --hpreg */ : #ifndef __PIC__ "ebx", #endif "ecx", "edx", "esi", "edi", "memory", "cc" ); } void BackdoorHbVmmcall(Backdoor_proto_hb *myBp) // IN/OUT { uint32 dummy; __asm__ __volatile__( #ifdef __PIC__ "pushl %%ebx" "\n\t" #endif "pushl %%ebp" "\n\t" "pushl %%eax" "\n\t" "movl 24(%%eax), %%ebp" "\n\t" "movl 20(%%eax), %%edi" "\n\t" "movl 16(%%eax), %%esi" "\n\t" "movl 12(%%eax), %%edx" "\n\t" "movl 8(%%eax), %%ecx" "\n\t" "movl 4(%%eax), %%ebx" "\n\t" "movl (%%eax), %%eax" "\n\t" "vmmcall" "\n\t" "xchgl %%eax, (%%esp)" "\n\t" "movl %%ebp, 24(%%eax)" "\n\t" "movl %%edi, 20(%%eax)" "\n\t" "movl %%esi, 16(%%eax)" "\n\t" "movl %%edx, 12(%%eax)" "\n\t" "movl %%ecx, 8(%%eax)" "\n\t" "movl %%ebx, 4(%%eax)" "\n\t" "popl (%%eax)" "\n\t" "popl %%ebp" "\n\t" #ifdef __PIC__ "popl %%ebx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. --hpreg */ : #ifndef __PIC__ "ebx", #endif "ecx", "edx", "esi", "edi", "memory", "cc" ); } #endif #ifdef __cplusplus } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/backdoor/backdoorGcc64.c000066400000000000000000000316361470176644300254030ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2005-2016, 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * backdoorGcc64.c -- * * Implements the real work for guest-side backdoor for GCC, 64-bit * target (supports inline ASM, GAS syntax). The asm sections are marked * volatile since vmware can change the registers content without the * compiler knowing it. * * See backdoorGCC32.c (from which this code was mostly copied) for * details on why the ASM is written this way. Also note that it might be * possible to write the asm blocks using the symbolic operand specifiers * in such a way that the same asm would generate correct code for both * 32-bit and 64-bit targets, but I'm too lazy to figure it all out. * --rrdharan */ #ifdef __cplusplus extern "C" { #endif #include "backdoor.h" #include "backdoorInt.h" /* *---------------------------------------------------------------------------- * * Backdoor_InOut -- * * Send a low-bandwidth basic request (16 bytes) to vmware, and return its * reply (24 bytes). * * Results: * Host-side response returned in bp IN/OUT parameter. * * Side effects: * Pokes the backdoor. * *---------------------------------------------------------------------------- */ void Backdoor_InOut(Backdoor_proto *myBp) // IN/OUT { uint64 dummy; __asm__ __volatile__( #ifdef __APPLE__ /* * Save %rbx on the stack because the Mac OS GCC doesn't want us to * clobber it - it erroneously thinks %rbx is the PIC register. * (Radar bug 7304232) */ "pushq %%rbx" "\n\t" #endif "pushq %%rax" "\n\t" "movq 40(%%rax), %%rdi" "\n\t" "movq 32(%%rax), %%rsi" "\n\t" "movq 24(%%rax), %%rdx" "\n\t" "movq 16(%%rax), %%rcx" "\n\t" "movq 8(%%rax), %%rbx" "\n\t" "movq (%%rax), %%rax" "\n\t" "inl %%dx, %%eax" "\n\t" /* NB: There is no inq instruction */ "xchgq %%rax, (%%rsp)" "\n\t" "movq %%rdi, 40(%%rax)" "\n\t" "movq %%rsi, 32(%%rax)" "\n\t" "movq %%rdx, 24(%%rax)" "\n\t" "movq %%rcx, 16(%%rax)" "\n\t" "movq %%rbx, 8(%%rax)" "\n\t" "popq (%%rax)" "\n\t" #ifdef __APPLE__ "popq %%rbx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. So far it does not modify EFLAGS. --hpreg */ : #ifndef __APPLE__ /* %rbx is unchanged at the end of the function on Mac OS. */ "rbx", #endif "rcx", "rdx", "rsi", "rdi", "memory" ); } #if defined(USE_HYPERCALL) void Backdoor_Vmcall(Backdoor_proto *myBp) // IN/OUT { uint64 dummy; __asm__ __volatile__( #ifdef __APPLE__ /* * Save %rbx on the stack because the Mac OS GCC doesn't want us to * clobber it - it erroneously thinks %rbx is the PIC register. * (Radar bug 7304232) */ "pushq %%rbx" "\n\t" #endif "pushq %%rax" "\n\t" "movq 40(%%rax), %%rdi" "\n\t" "movq 32(%%rax), %%rsi" "\n\t" "movq 24(%%rax), %%rdx" "\n\t" "movq 16(%%rax), %%rcx" "\n\t" "movq 8(%%rax), %%rbx" "\n\t" "movq (%%rax), %%rax" "\n\t" "vmcall" "\n\t" "xchgq %%rax, (%%rsp)" "\n\t" "movq %%rdi, 40(%%rax)" "\n\t" "movq %%rsi, 32(%%rax)" "\n\t" "movq %%rdx, 24(%%rax)" "\n\t" "movq %%rcx, 16(%%rax)" "\n\t" "movq %%rbx, 8(%%rax)" "\n\t" "popq (%%rax)" "\n\t" #ifdef __APPLE__ "popq %%rbx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. So far it does not modify EFLAGS. --hpreg */ : #ifndef __APPLE__ /* %rbx is unchanged at the end of the function on Mac OS. */ "rbx", #endif "rcx", "rdx", "rsi", "rdi", "memory" ); } void Backdoor_Vmmcall(Backdoor_proto *myBp) // IN/OUT { uint64 dummy; __asm__ __volatile__( #ifdef __APPLE__ /* * Save %rbx on the stack because the Mac OS GCC doesn't want us to * clobber it - it erroneously thinks %rbx is the PIC register. * (Radar bug 7304232) */ "pushq %%rbx" "\n\t" #endif "pushq %%rax" "\n\t" "movq 40(%%rax), %%rdi" "\n\t" "movq 32(%%rax), %%rsi" "\n\t" "movq 24(%%rax), %%rdx" "\n\t" "movq 16(%%rax), %%rcx" "\n\t" "movq 8(%%rax), %%rbx" "\n\t" "movq (%%rax), %%rax" "\n\t" "vmmcall" "\n\t" "xchgq %%rax, (%%rsp)" "\n\t" "movq %%rdi, 40(%%rax)" "\n\t" "movq %%rsi, 32(%%rax)" "\n\t" "movq %%rdx, 24(%%rax)" "\n\t" "movq %%rcx, 16(%%rax)" "\n\t" "movq %%rbx, 8(%%rax)" "\n\t" "popq (%%rax)" "\n\t" #ifdef __APPLE__ "popq %%rbx" "\n\t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. So far it does not modify EFLAGS. --hpreg */ : #ifndef __APPLE__ /* %rbx is unchanged at the end of the function on Mac OS. */ "rbx", #endif "rcx", "rdx", "rsi", "rdi", "memory" ); } #endif /* *----------------------------------------------------------------------------- * * BackdoorHbIn -- * BackdoorHbOut -- * * Send a high-bandwidth basic request to vmware, and return its * reply. * * Results: * Host-side response returned in bp IN/OUT parameter. * * Side-effects: * Pokes the high-bandwidth backdoor port. * *----------------------------------------------------------------------------- */ void BackdoorHbIn(Backdoor_proto_hb *myBp) // IN/OUT { uint64 dummy; __asm__ __volatile__( "pushq %%rbp" "\n\t" #ifdef __APPLE__ /* * Save %rbx on the stack because the Mac OS GCC doesn't want us to * clobber it - it erroneously thinks %rbx is the PIC register. * (Radar bug 7304232) */ "pushq %%rbx" "\n\t" #endif "pushq %%rax" "\n\t" "movq 48(%%rax), %%rbp" "\n\t" "movq 40(%%rax), %%rdi" "\n\t" "movq 32(%%rax), %%rsi" "\n\t" "movq 24(%%rax), %%rdx" "\n\t" "movq 16(%%rax), %%rcx" "\n\t" "movq 8(%%rax), %%rbx" "\n\t" "movq (%%rax), %%rax" "\n\t" "cld" "\n\t" "rep; insb" "\n\t" "xchgq %%rax, (%%rsp)" "\n\t" "movq %%rbp, 48(%%rax)" "\n\t" "movq %%rdi, 40(%%rax)" "\n\t" "movq %%rsi, 32(%%rax)" "\n\t" "movq %%rdx, 24(%%rax)" "\n\t" "movq %%rcx, 16(%%rax)" "\n\t" "movq %%rbx, 8(%%rax)" "\n\t" "popq (%%rax)" "\n\t" #ifdef __APPLE__ "popq %%rbx" "\n\t" #endif "popq %%rbp" : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. --hpreg */ : #ifndef __APPLE__ /* %rbx is unchanged at the end of the function on Mac OS. */ "rbx", #endif "rcx", "rdx", "rsi", "rdi", "memory", "cc" ); } void BackdoorHbOut(Backdoor_proto_hb *myBp) // IN/OUT { uint64 dummy; __asm__ __volatile__( "pushq %%rbp" "\n\t" #ifdef __APPLE__ /* * Save %rbx on the stack because the Mac OS GCC doesn't want us to * clobber it - it erroneously thinks %rbx is the PIC register. * (Radar bug 7304232) */ "pushq %%rbx" "\n\t" #endif "pushq %%rax" "\n\t" "movq 48(%%rax), %%rbp" "\n\t" "movq 40(%%rax), %%rdi" "\n\t" "movq 32(%%rax), %%rsi" "\n\t" "movq 24(%%rax), %%rdx" "\n\t" "movq 16(%%rax), %%rcx" "\n\t" "movq 8(%%rax), %%rbx" "\n\t" "movq (%%rax), %%rax" "\n\t" "cld" "\n\t" "rep; outsb" "\n\t" "xchgq %%rax, (%%rsp)" "\n\t" "movq %%rbp, 48(%%rax)" "\n\t" "movq %%rdi, 40(%%rax)" "\n\t" "movq %%rsi, 32(%%rax)" "\n\t" "movq %%rdx, 24(%%rax)" "\n\t" "movq %%rcx, 16(%%rax)" "\n\t" "movq %%rbx, 8(%%rax)" "\n\t" "popq (%%rax)" "\n\t" #ifdef __APPLE__ "popq %%rbx" "\n\t" #endif "popq %%rbp" : "=a" (dummy) : "0" (myBp) : #ifndef __APPLE__ /* %rbx is unchanged at the end of the function on Mac OS. */ "rbx", #endif "rcx", "rdx", "rsi", "rdi", "memory", "cc" ); } #if defined(USE_HYPERCALL) void BackdoorHbVmcall(Backdoor_proto_hb *myBp) // IN/OUT { uint64 dummy; __asm__ __volatile__( "pushq %%rbp" "\n\t" #ifdef __APPLE__ /* * Save %rbx on the stack because the Mac OS GCC doesn't want us to * clobber it - it erroneously thinks %rbx is the PIC register. * (Radar bug 7304232) */ "pushq %%rbx" "\n\t" #endif "pushq %%rax" "\n\t" "movq 48(%%rax), %%rbp" "\n\t" "movq 40(%%rax), %%rdi" "\n\t" "movq 32(%%rax), %%rsi" "\n\t" "movq 24(%%rax), %%rdx" "\n\t" "movq 16(%%rax), %%rcx" "\n\t" "movq 8(%%rax), %%rbx" "\n\t" "movq (%%rax), %%rax" "\n\t" "vmcall" "\n\t" "xchgq %%rax, (%%rsp)" "\n\t" "movq %%rbp, 48(%%rax)" "\n\t" "movq %%rdi, 40(%%rax)" "\n\t" "movq %%rsi, 32(%%rax)" "\n\t" "movq %%rdx, 24(%%rax)" "\n\t" "movq %%rcx, 16(%%rax)" "\n\t" "movq %%rbx, 8(%%rax)" "\n\t" "popq (%%rax)" "\n\t" #ifdef __APPLE__ "popq %%rbx" "\n\t" #endif "popq %%rbp" : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. --hpreg */ : #ifndef __APPLE__ /* %rbx is unchanged at the end of the function on Mac OS. */ "rbx", #endif "rcx", "rdx", "rsi", "rdi", "memory", "cc" ); } void BackdoorHbVmmcall(Backdoor_proto_hb *myBp) // IN/OUT { uint64 dummy; __asm__ __volatile__( "pushq %%rbp" "\n\t" #ifdef __APPLE__ /* * Save %rbx on the stack because the Mac OS GCC doesn't want us to * clobber it - it erroneously thinks %rbx is the PIC register. * (Radar bug 7304232) */ "pushq %%rbx" "\n\t" #endif "pushq %%rax" "\n\t" "movq 48(%%rax), %%rbp" "\n\t" "movq 40(%%rax), %%rdi" "\n\t" "movq 32(%%rax), %%rsi" "\n\t" "movq 24(%%rax), %%rdx" "\n\t" "movq 16(%%rax), %%rcx" "\n\t" "movq 8(%%rax), %%rbx" "\n\t" "movq (%%rax), %%rax" "\n\t" "vmmcall" "\n\t" "xchgq %%rax, (%%rsp)" "\n\t" "movq %%rbp, 48(%%rax)" "\n\t" "movq %%rdi, 40(%%rax)" "\n\t" "movq %%rsi, 32(%%rax)" "\n\t" "movq %%rdx, 24(%%rax)" "\n\t" "movq %%rcx, 16(%%rax)" "\n\t" "movq %%rbx, 8(%%rax)" "\n\t" "popq (%%rax)" "\n\t" #ifdef __APPLE__ "popq %%rbx" "\n\t" #endif "popq %%rbp" : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. --hpreg */ : #ifndef __APPLE__ /* %rbx is unchanged at the end of the function on Mac OS. */ "rbx", #endif "rcx", "rdx", "rsi", "rdi", "memory", "cc" ); } #endif #ifdef __cplusplus } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/backdoor/backdoorGcc64_arm64.c000066400000000000000000000135031470176644300264050ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2015-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * backdoorGcc64_arm64.c -- * * Implements the real work for guest-side backdoor for GCC, 64-bit * target (supports inline ASM, GAS syntax). The asm sections are marked * volatile since vmware can change the registers content without the * compiler knowing it. * * See backdoor_def.h for implementation details. * */ #ifdef __cplusplus extern "C" { #endif #include "backdoor.h" #include "backdoor_def.h" #include "backdoorInt.h" /* *---------------------------------------------------------------------------- * * Backdoor_InOut -- * * Send a low-bandwidth basic request (16 bytes) to vmware, and return its * reply (24 bytes). * * Results: * Host-side response returned in bp IN/OUT parameter. * * Side effects: * Pokes the backdoor. * *---------------------------------------------------------------------------- */ void Backdoor_InOut(Backdoor_proto *myBp) // IN/OUT { /* * The low-bandwidth backdoor call has the following effects: * o The VM can modify the calling vCPU's registers x0, x1, x2, x3, x4 * and x5. * o The VM can modify arbitrary guest memory. * So far the VM does not modify the calling vCPU's conditional flags. */ __asm__ __volatile__( "ldp x4, x5, [%0, 8 * 4] \n\t" "ldp x2, x3, [%0, 8 * 2] \n\t" "ldp x0, x1, [%0 ] \n\t" "mov x7, %1 \n\t" "movk x7, %2, lsl #32 \n\t" "mrs xzr, mdccsr_el0 \n\t" "stp x4, x5, [%0, 8 * 4] \n\t" "stp x2, x3, [%0, 8 * 2] \n\t" "stp x0, x1, [%0 ] " : : "r" (myBp), "M" (X86_IO_W7_WITH | X86_IO_W7_DIR | 2 << X86_IO_W7_SIZE_SHIFT), "i" (X86_IO_MAGIC) : "x0", "x1", "x2", "x3", "x4", "x5", "x7", "memory" ); } /* *----------------------------------------------------------------------------- * * BackdoorHbIn -- * BackdoorHbOut -- * * Send a high-bandwidth basic request to vmware, and return its * reply. * * Results: * Host-side response returned in bp IN/OUT parameter. * * Side-effects: * Pokes the high-bandwidth backdoor port. * *----------------------------------------------------------------------------- */ #define _BACKDOOR_HB(myBp, w7dir) \ __asm__ __volatile__( \ "ldp x5, x6, [%0, 8 * 5] \n\t" \ "ldp x3, x4, [%0, 8 * 3] \n\t" \ "ldp x1, x2, [%0, 8 * 1] \n\t" \ "ldr x0, [%0 ] \n\t" \ "mov x7, %1 \n\t" \ "movk x7, %2, lsl #32 \n\t" \ "mrs xzr, mdccsr_el0 \n\t" \ "stp x5, x6, [%0, 8 * 5] \n\t" \ "stp x3, x4, [%0, 8 * 3] \n\t" \ "stp x1, x2, [%0, 8 * 1] \n\t" \ "str x0, [%0 ] " \ : \ : "r" (myBp), \ "M" (X86_IO_W7_STR | X86_IO_W7_WITH | w7dir), \ "i" (X86_IO_MAGIC) \ : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "memory" \ ) void BackdoorHbIn(Backdoor_proto_hb *myBp) // IN/OUT { /* * The high-bandwidth backdoor call has the following effects: * o The VM can modify the calling vCPU's registers x0, x1, x2, x3, x4, x5 * and x6. * o The VM can modify arbitrary guest memory. * So far the VM does not modify the calling vCPU's conditional flags. */ _BACKDOOR_HB(myBp, X86_IO_W7_DIR); } void BackdoorHbOut(Backdoor_proto_hb *myBp) // IN/OUT { /* * The high-bandwidth backdoor call has the following effects: * o The VM can modify the calling vCPU's registers x0, x1, x2, x3, x4, x5 * and x6. * o The VM can modify arbitrary guest memory. * So far the VM does not modify the calling vCPU's conditional flags. */ _BACKDOOR_HB(myBp, 0); } #undef _BACKDOOR_HB #ifdef __cplusplus } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/backdoor/backdoorInt.h000066400000000000000000000042231470176644300252640ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2005-2016, 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * backdoorInt.h -- * * Internal function prototypes for the real backdoor work. */ void BackdoorHbIn(Backdoor_proto_hb *bp); void BackdoorHbOut(Backdoor_proto_hb *bp); void BackdoorHb(Backdoor_proto_hb *myBp, Bool outbound); /* * Are vmcall/vmmcall hypercall instructions available in the assembler? * Use the compiler version as a proxy. */ #if defined(__linux__) && defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 + \ __GNUC_MINOR__ * 100 + \ __GNUC_PATCHLEVEL__) #if GCC_VERSION > 40803 && !defined(__aarch64__) #define USE_HYPERCALL #endif #endif #if defined(USE_HYPERCALL) void BackdoorHbVmcall(Backdoor_proto_hb *bp); void BackdoorHbVmmcall(Backdoor_proto_hb *bp); #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/dataMap/000077500000000000000000000000001470176644300224365ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/dataMap/Makefile.am000066400000000000000000000017351470176644300245000ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2013-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libDataMap.la libDataMap_la_SOURCES = libDataMap_la_SOURCES += dataMap.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/dataMap/dataMap.c000066400000000000000000001742021470176644300241570ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2012-2017,2019, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #include #include #include #ifdef _WIN32 #include #else #include #endif #include "vm_basic_types.h" #include "str.h" #include "dataMap.h" #include "vm_ctype.h" /* * A union for all kinds of data fields types. */ typedef union { struct { int64 val; } number; struct { int32 length; char *str; } string; struct { int32 length; int64 *numbers; } numList; struct { char **strings; /* a list of string pointers, the last elment is NULL */ int32 *lengths; /* a list of lengths for strings in strings. */ } strList; } DMFieldValue; typedef struct { DMFieldType type; DMFieldValue value; } DataMapEntry; /* structure used in hashMap iteration callback */ typedef struct { DataMap *map; ErrorCode result; /* store the previous callback function result value */ /* the followings are used during serialization, deserialization and * pretty print. */ char *buffer; uint32 buffLen; /* available buffer size */ uint32 maxNumElems; /* this limits the number of elements for list print. */ uint32 maxStrLen; /* max number of bytes to print for each string */ FieldIdNameEntry *fieldIdList; /* array for field ID to name mapping */ uint32 fieldIdListLen; /* fieldIdList size */ } ClientData; static const uint64 magic_cookie = 0x4d41474943ULL; /* 'MAGIC' */ /* *----------------------------------------------------------------------------- * * AddEntry_Int64 -- * * - low level helper function to add a numeric type entry to the map * * Result: * 0 on success * error code otherwise * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode AddEntry_Int64(DataMap *that, // IN/OUT DMKeyType key, // IN int64 value) // IN { DataMapEntry *entry = (DataMapEntry *)malloc(sizeof(DataMapEntry)); if (entry == NULL) { return DMERR_INSUFFICIENT_MEM; } entry->type = DMFIELDTYPE_INT64; entry->value.number.val = value; if (!HashMap_Put(that->map, &key, &entry)) { return DMERR_INSUFFICIENT_MEM; } return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * AddEntry_String -- * * Low level helper function to add a string type entry to the map. * - 'str': ownership of the str pointer is passed to the map on success. * * Result: * 0 on success * error code otherwise * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode AddEntry_String(DataMap *that, // IN/OUT DMKeyType key, // IN char *str, // IN int32 strLen) // IN { DataMapEntry *entry = (DataMapEntry *)malloc(sizeof(DataMapEntry)); if (entry == NULL) { return DMERR_INSUFFICIENT_MEM; } entry->type = DMFIELDTYPE_STRING; entry->value.string.str = str; entry->value.string.length = strLen; if (!HashMap_Put(that->map, &key, &entry)) { return DMERR_INSUFFICIENT_MEM; } return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * AddEntry_Int64List -- * * Low level helper function to add a list of numbers to the map * - 'numbers': ownership of this pointer is passed to the map on success. * - 'listLen': the number of integers in the list of 'numbers'. * * Result: * 0 on success * error code otherwise * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode AddEntry_Int64List(DataMap *that, // IN/OUT DMKeyType key, // IN int64 *numbers, // IN int32 listLen) // IN { DataMapEntry *entry = (DataMapEntry *)malloc(sizeof(DataMapEntry)); if (entry == NULL) { return DMERR_INSUFFICIENT_MEM; } entry->type = DMFIELDTYPE_INT64LIST; entry->value.numList.numbers = numbers; entry->value.numList.length = listLen; if (!HashMap_Put(that->map, &key, &entry)) { return DMERR_INSUFFICIENT_MEM; } return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * AddEntry_StringList -- * * Low level helper function to add a list of trings to the map * - 'strList': this pointer points to an array of pointers which points to * strings. Upon success, the ownership of this array is passed to the * map, no copy of strings is made. The last element in this array * pointer must be NULL. * - 'strLens': this is an array of integers which indicating the length of * cooresponding string in strList. the ownership is passed to the map * as well on success. * * Result: * 0 on success * error code otherwise * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode AddEntry_StringList(DataMap *that, // IN/OUT DMKeyType key, // IN char **strList, // IN int32 *strLens) // IN { DataMapEntry *entry = (DataMapEntry *)malloc(sizeof(DataMapEntry)); if (entry == NULL) { return DMERR_INSUFFICIENT_MEM; } entry->type = DMFIELDTYPE_STRINGLIST; entry->value.strList.strings = strList; entry->value.strList.lengths = strLens; if (!HashMap_Put(that->map, &key, &entry)) { return DMERR_INSUFFICIENT_MEM; } return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * FreeStringList -- * * Low level helper function to free a list of strings. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void FreeStringList(char **strList, // IN int32 *strLens) // IN { if (*strList != NULL) { char **ptr; for (ptr = strList; *ptr != NULL; ptr++) { free(*ptr); } } free(strLens); free(strList); } /* *----------------------------------------------------------------------------- * * FreeEntryPayload -- * * - low level helper function to free entry payload only * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void FreeEntryPayload(DataMapEntry *entry) // IN { if (entry == NULL) { return; } switch(entry->type) { case DMFIELDTYPE_INT64: break; case DMFIELDTYPE_STRING: free(entry->value.string.str); break; case DMFIELDTYPE_INT64LIST: free(entry->value.numList.numbers); break; case DMFIELDTYPE_STRINGLIST: FreeStringList(entry->value.strList.strings, entry->value.strList.lengths); break; default: ASSERT(0); /* we do not expect this to happen */ } } /* *----------------------------------------------------------------------------- * * EncodeInt32 -- * * Low level helper function to encode an int32 into a byte buffer. * - 'buf': *buf points to the output buffer, *buf is advanced properly. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void EncodeInt32(char **buf, // IN/OUT int32 num) // IN { uint32 netVal = htonl((uint32)num); *((uint32 *)(*buf)) = netVal; (*buf) += sizeof(int32); } /* *----------------------------------------------------------------------------- * * DecodeInt32 -- * * Low level helper function to decode an int32 from a byte buffer * - 'buf': *buf points to the input buffer. *buf is advanced accordingly * on success. * - 'left': indicates number of bytes left in the input buffer, *left is * updated accordingly on success. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode DecodeInt32(char **buf, // IN/OUT int32 *left, // IN/OUT int32 *num) // OUT { uint32 val; if (*left < sizeof(int32)) { return DMERR_TRUNCATED_DATA; } val = ntohl(*((uint32 *)(*buf))); *num = (int32) val; *buf += sizeof(int32); *left -= sizeof(int32); return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * EncodeInt64 -- * * Low level helper function to encode an int64 into a byte buffer * - 'buf': *buf points to the output buffer, *buf is advanced properly. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void EncodeInt64(char **buf, // IN/OUT int64 num) // IN { EncodeInt32(buf, (uint32)num); EncodeInt32(buf, (uint32)(num >> 32)); } /* *----------------------------------------------------------------------------- * * DecodeInt64 -- * * Low level helper function to decode an int64 from a byte buffer * - 'buf': *buf points to the input buffer. *buf is advanced accordingly * on success. * - 'left': indicates number of bytes left in the input buffer, *left is * updated accordingly on success. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode DecodeInt64(char **buf, // IN/OUT int32 *left, // IN/OUT int64 *num) // OUT { ErrorCode res; uint32 low; uint32 high; res = DecodeInt32(buf, left, &low); if (res == DMERR_SUCCESS) { res = DecodeInt32(buf, left, &high); if (res == DMERR_SUCCESS) { *num = (int64)(((((uint64)high)<< 32) | low)); } } return res; } /* *----------------------------------------------------------------------------- * * EncodeString -- * * Low level helper function to encode a string into a byte buffer * - 'buf': *buf points to the output buffer, *buf is advanced properly. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void EncodeString(char **buf, // IN/OUT const char *str, // IN int32 strLen) // IN { EncodeInt32(buf, strLen); memcpy(*buf, str, strLen); (*buf) += strLen; } /* *----------------------------------------------------------------------------- * * DecodeString -- * * - low level helper function to decode a string from a byte buffer * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode DecodeString(char **buf, // IN/OUT int32 *left, // IN/OUT char **str, // OUT int32 *strLen) // OUT { ErrorCode res; res = DecodeInt32(buf, left, strLen); if (res != DMERR_SUCCESS) { return res; } if (*strLen <= 0) { return DMERR_BAD_DATA; } if (*left < *strLen) { return DMERR_TRUNCATED_DATA; } *str = (char *)malloc(*strLen); if (*str == NULL) { return DMERR_INSUFFICIENT_MEM; } memcpy(*str, *buf, *strLen); *buf += *strLen; *left -= *strLen; return res; } /* *----------------------------------------------------------------------------- * * EncodeInt64List -- * * Low level helper function to encode an int64 list into a byte buffer * - 'buf': *buf points to the output buffer, *buf is advanced properly. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void EncodeInt64List(char **buf, // IN/OUT int64 *numList, // IN int32 listLen) // IN { int32 i; EncodeInt32(buf, (uint32)listLen); for(i = 0; i< listLen; i++) { EncodeInt64(buf, numList[i]); } } /* *----------------------------------------------------------------------------- * * DecodeInt64List -- * * Low level helper function to decode an int64 list from a byte buffer * - 'buf': *buf points to the input buffer. *buf is advanced accordingly * on success. * - 'left': indicates number of bytes left in the input buffer, *left is * updated accordingly on success. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode DecodeInt64List(char **buf, // IN/OUT int32 *left, // IN/OUT DMKeyType fieldId, // IN DataMap *that) // OUT { int32 listLen; int64 *numList = NULL; ErrorCode res; int32 i; res = DecodeInt32(buf, left, &listLen); if (res != DMERR_SUCCESS) { return res; } if (listLen < 0 || listLen > *left / sizeof(int64)) { /* listLen can be zero to support an empty list */ return DMERR_BAD_DATA; } if (listLen) { numList = (int64 *)malloc(sizeof(int64) * listLen); if (numList == NULL) { return DMERR_INSUFFICIENT_MEM; } for(i = 0; i< listLen; i++) { res = DecodeInt64(buf, left, numList + i); if (res != DMERR_SUCCESS) { break; } } } if (res == DMERR_SUCCESS) { res = AddEntry_Int64List(that, fieldId, numList, listLen); } if (res != DMERR_SUCCESS) { /* clean up memory */ free(numList); } return res; } /* *----------------------------------------------------------------------------- * * FreeEntry -- * * - low level helper function to free an entry. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void FreeEntry(DataMapEntry *entry) // IN { FreeEntryPayload(entry); free(entry); } /* *----------------------------------------------------------------------------- * * LookupEntry -- * * - helper function to lookup an entry in the data map. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static DataMapEntry * LookupEntry(const DataMap *that, // IN DMKeyType fieldId) // IN { if ((that != NULL) && (that->map != NULL)) { void *rv = HashMap_Get(that->map, &fieldId); if (rv == NULL) { return NULL; /* key not found */ } return *((DataMapEntry **)rv); } else { return NULL; } } /* *----------------------------------------------------------------------------- * * DataMap_GetType -- * * Get the value type for a given fieldID. * * Result: * - DMFIELDTYPE_EMPTY is returned if entry does not exist. * - One of other values in DMFieldType otherwise. * * * Side-effects: * None * *----------------------------------------------------------------------------- */ DMFieldType DataMap_GetType(const DataMap *that, // IN DMKeyType fieldId) // IN { DataMapEntry *entry; ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { return DMFIELDTYPE_EMPTY; } else { return entry->type; } } /* *----------------------------------------------------------------------------- * * DataMap_Create -- * * - Initialize an Empty DataMap using the DataMap storage pointed * by that. * - The memory pointed by that may be allocated from heap or stack. * - This function may allocate additional memory from the heap to * initialize the DataMap object. * * Result: * 0(DMERR_SUCCESS) on success. * error code on failures. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_Create(DataMap *that) // IN/OUT { if (that == NULL) { return DMERR_INVALID_ARGS; } that->map = HashMap_AllocMap(16, sizeof(DMKeyType), sizeof(DataMapEntry *)); if (that->map != NULL) { that->cookie = magic_cookie; return DMERR_SUCCESS; } return DMERR_INSUFFICIENT_MEM; } /* *----------------------------------------------------------------------------- * * ToBufferUpdate -- * * Update result, advance buffer pointer, and adjust buffer left size etc * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void ToBufferUpdate(ClientData *clientData, // IN/OUT uint32 len) { if (len >= clientData->buffLen) { clientData->result = DMERR_BUFFER_TOO_SMALL; clientData->buffer += clientData->buffLen; clientData->buffLen = 0; } else { clientData->buffer += len; clientData->buffLen -= len; } } /* *----------------------------------------------------------------------------- * * ToBufferString -- * * Copy a string to a buffer. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void ToBufferString(ClientData *clientData, // IN/OUT const char *str) // IN { int32 len; if (clientData->result != DMERR_SUCCESS) { /* an error occurred already, so stop. */ return; } ASSERT(clientData->buffLen > 0); len = snprintf(clientData->buffer, clientData->buffLen, "%s", str); ToBufferUpdate(clientData, len); } /* *----------------------------------------------------------------------------- * * ToBufferStringN -- * * Copy N bytes from a string to a buffer. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void ToBufferStringN(ClientData *clientData, // IN/OUT const char *str, // IN uint32 len) // IN { uint32 copyLen = len; if (clientData->result != DMERR_SUCCESS) { /* an error occurred already, so stop. */ return; } ASSERT(clientData->buffLen > 0); if (copyLen >= clientData->buffLen) { copyLen = clientData->buffLen - 1; } memcpy(clientData->buffer, str, copyLen); clientData->buffer[copyLen] = '\0'; ToBufferUpdate(clientData, len); } /* *----------------------------------------------------------------------------- * * GetLimit -- * * Get the limit from the given max and actual length. * * Result: * Returns the limit * * Side-effects: * None * *----------------------------------------------------------------------------- */ static int32 GetLimit(int32 max, // IN: -1 means no limit int32 length) // IN { if (max < 0) { return length; } return max < length ? max : length; } /* *----------------------------------------------------------------------------- * * ToBufferInt64 -- * * Copy an int64 to a buffer. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void ToBufferInt64(ClientData *clientData, // IN/OUT int64 num) // IN { uint32 len; if (clientData->result != DMERR_SUCCESS) { /* an error occurred already, so stop. */ return; } ASSERT(clientData->buffLen > 0); len = snprintf(clientData->buffer, clientData->buffLen, "%"FMT64"d", num); ToBufferUpdate(clientData, len); } /* *----------------------------------------------------------------------------- * * ToBufferIdType -- * * Convert the ID, name and type to a string. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void ToBufferIdType(ClientData *clientData, // IN/OUT const char *idName, // IN DMKeyType fieldId, // IN const char *type) // IN { uint32 len; if (clientData->result != DMERR_SUCCESS) { /* an error occurred already, so stop. */ return; } ASSERT(clientData->buffLen > 0); len = snprintf(clientData->buffer, clientData->buffLen, "--> FIELD_%s(%d, %s): [", idName, fieldId, type); ToBufferUpdate(clientData, len); } /* *----------------------------------------------------------------------------- * * ToBufferEndLine -- * * Print to end the current line * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void ToBufferEndLine(ClientData *clientData) // IN/OUT { ToBufferString(clientData, "]\n"); } /* *----------------------------------------------------------------------------- * * IsPrintable -- * * Check is a string is printable or not. * - 'len': if printable, *len is the printable length, '\0' is excluded. * * Result: * TRUE if yes, FALSE otherwise * * Side-effects: * None * *----------------------------------------------------------------------------- */ static Bool IsPrintable(const char *str, // IN int32 strLen, // IN int32 *len) // OUT { Bool printable = TRUE; int32 cc; for (cc = 0; cc < strLen; cc ++) { /* isprint crashes with negative value in windows debug mode */ if ((!CType_IsPrint(str[cc])) && (!CType_IsSpace(str[cc]))) { printable = FALSE; break; } } if (printable) { *len = strLen; } else { /* if only the last char is not printable and is '\0', * make it printable */ if ((cc == strLen - 1) && (str[cc] == '\0')) { printable = TRUE; *len = strLen - 1; } } return printable; } /* *----------------------------------------------------------------------------- * * ToBufferHexString -- * * Print a string into a buffer, the string may be in binary format. * - 'strLen': is the length of str. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void ToBufferHexString(ClientData *clientData, // IN/OUT const char *str, // IN uint32 strLen) // IN { Bool printable; int32 len; /* the number of printable chars */ int32 maxLen = clientData->maxStrLen; /* -1 means no limit */ if (clientData->result != DMERR_SUCCESS) { /* an error occurred already, so stop. */ return; } ASSERT(clientData->buffLen > 0); maxLen = GetLimit(maxLen, strLen); printable = IsPrintable(str, maxLen, &len); if (printable) { ToBufferString(clientData, "\""); ToBufferStringN(clientData, str, len); if (maxLen < strLen) { ToBufferString(clientData, "..."); /* to indicate partial print */ } ToBufferString(clientData, "\""); } else { int i; /* print the string in hex */ ToBufferString(clientData, "("); for (i = 0; i < maxLen; i++) { char hexStr[3]; if (i) { ToBufferString(clientData, ","); /* separator */ } snprintf(hexStr, sizeof(hexStr), "%02x", (unsigned char)(str[i])); ToBufferString(clientData, hexStr); if (clientData->result != DMERR_SUCCESS) { break; } } if (maxLen < strLen) { /* "..." to indicate partial print*/ ToBufferString(clientData, ",..."); } ToBufferString(clientData, ")"); } } /* *----------------------------------------------------------------------------- * * HashMapToStringEntryCb -- * * Convert to an entry to a string. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void HashMapToStringEntryCb(void *key, // IN void *data, // IN void *userData) // IN/OUT { DataMapEntry *entry = *((DataMapEntry **)data); ClientData *clientData = (ClientData *)userData; DMKeyType fieldId = *((DMKeyType *)key); const char *idName = NULL; /* field ID name */ if (clientData->result != DMERR_SUCCESS) { /* A previous error has occurred, so stop. */ return; } if (clientData->fieldIdList!= NULL) { int32 cc; for (cc = 0; cc < clientData->fieldIdListLen; cc ++) { if (fieldId == clientData->fieldIdList[cc].fieldId) { idName = clientData->fieldIdList[cc].fieldName; break; } } } if (idName == NULL) { idName = ""; } switch(entry->type) { case DMFIELDTYPE_INT64: { ToBufferIdType(clientData, idName, fieldId, "int64"); ToBufferInt64(clientData, entry->value.number.val); ToBufferEndLine(clientData); break; } case DMFIELDTYPE_STRING: { ToBufferIdType(clientData, idName, fieldId, "string"); ToBufferHexString(clientData, entry->value.string.str, entry->value.string.length); ToBufferEndLine(clientData); break; } case DMFIELDTYPE_INT64LIST: { int32 cc; int32 max = GetLimit(clientData->maxNumElems, entry->value.numList.length); ToBufferIdType(clientData, idName, fieldId, "int64List"); for (cc = 0; cc < max; cc++) { if (cc != 0) { ToBufferString(clientData, ","); /* add a separator */ } ToBufferInt64(clientData, entry->value.numList.numbers[cc]); } if (max < entry->value.numList.length) { /* to indicate partial print*/ ToBufferString(clientData, ",..."); } ToBufferEndLine(clientData); break; } case DMFIELDTYPE_STRINGLIST: { char **strPtr = entry->value.strList.strings; int32 *lenPtr = entry->value.strList.lengths; int32 cc = 0; int32 max = clientData->maxNumElems; ToBufferIdType(clientData, idName, fieldId, "stringList"); for (; *strPtr != NULL; strPtr++, lenPtr++, cc++) { if ((max >= 0) && (cc >= max)) { break; } if (cc > 0) { ToBufferString(clientData, ","); /* add a separator */ } ToBufferHexString(clientData, *strPtr, *lenPtr); if (clientData->result != DMERR_SUCCESS) { return; } } if (*strPtr != NULL) { /* to indicate partial print*/ ToBufferString(clientData, ",..."); } ToBufferEndLine(clientData); break; } default: { clientData->result = DMERR_UNKNOWN_TYPE; return; } } } /* *----------------------------------------------------------------------------- * * HashMapCalcEntrySizeCb -- * * - calculate how much space is needed to encode an entry * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void HashMapCalcEntrySizeCb(void *key, // IN void *data, // IN void *userData) // IN/OUT { DataMapEntry *entry = *((DataMapEntry **)data); ClientData *clientData = (ClientData *)userData; uint32 oldLen = clientData->buffLen; uint32 *buffLen = &(clientData->buffLen); if (clientData->result != DMERR_SUCCESS) { /* a previous error has occurred, so stop. */ return; } switch(entry->type) { case DMFIELDTYPE_INT64: { *buffLen += sizeof(int32); /* type */ *buffLen += sizeof(DMKeyType); /* fieldId */ *buffLen += sizeof(int64); /* int value */ break; } case DMFIELDTYPE_STRING: { *buffLen += sizeof(int32); /* type */ *buffLen += sizeof(DMKeyType); /* fieldId */ *buffLen += sizeof(int32); /* string length */ *buffLen += entry->value.string.length; /* string payload */ break; } case DMFIELDTYPE_INT64LIST: { *buffLen += sizeof(int32); /* type */ *buffLen += sizeof(DMKeyType); /* fieldId */ *buffLen += sizeof(int32); /* list size */ *buffLen += sizeof(int64) * entry->value.numList.length; break; } case DMFIELDTYPE_STRINGLIST: { char **strPtr = entry->value.strList.strings; int32 *lenPtr = entry->value.strList.lengths; *buffLen += sizeof(int32); /* type */ *buffLen += sizeof(DMKeyType); /* fieldId */ *buffLen += sizeof(int32); /* list size */ for (; *strPtr != NULL; strPtr++, lenPtr++) { if (*buffLen < oldLen) { clientData->result = DMERR_INTEGER_OVERFLOW; return; } *buffLen += sizeof(int32); /* string length */ *buffLen += *lenPtr; /* string payload */ } break; } default: { clientData->result = DMERR_UNKNOWN_TYPE; return; } } if (*buffLen < oldLen) { clientData->result = DMERR_INTEGER_OVERFLOW; return; } } /* *----------------------------------------------------------------------------- * * HashMapSerializeEntryCb -- * * - serialize each entry into a byte buffer * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void HashMapSerializeEntryCb(void *key, // IN void *data, // IN void *userData) // OUT { DataMapEntry *entry = *((DataMapEntry **)data); ClientData *clientData = (ClientData *)userData; char **buffPtr = &(clientData->buffer); char *buffPtrOrig = clientData->buffer; EncodeInt32(buffPtr, entry->type); /* encode type */ EncodeInt32(buffPtr, *((DMKeyType *)key)); /* encode field id*/ switch(entry->type) { case DMFIELDTYPE_INT64: EncodeInt64(buffPtr, entry->value.number.val); break; case DMFIELDTYPE_STRING: EncodeString(buffPtr, entry->value.string.str, entry->value.string.length); break; case DMFIELDTYPE_INT64LIST: EncodeInt64List(buffPtr, entry->value.numList.numbers, entry->value.numList.length); break; case DMFIELDTYPE_STRINGLIST: { char **strPtr = entry->value.strList.strings; int32 *lenPtr = entry->value.strList.lengths; int32 listSize = 0; char *listSizePtr = *buffPtr; /*reserve the space for list size, we will update later*/ *buffPtr += sizeof(int32); for (; *strPtr != NULL; strPtr++, lenPtr++) { EncodeString(buffPtr, *strPtr, *lenPtr); listSize ++; } EncodeInt32(&listSizePtr, listSize); /* now update the list size */ break; } default: ASSERT(0); /* we do not expect this to happen */ } /* Update left buffer size so we can do a confidence check at the end. */ clientData->buffLen -= (clientData->buffer - buffPtrOrig); } /* *----------------------------------------------------------------------------- * * DecodeStringList -- * * Decode a string list entry and add to the dataMap * - 'buf': *buf points to the input buffer. *buf is advanced accordingly * on success. * - 'left': indicates number of bytes left in the input buffer, *left is * updated accordingly on success. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode DecodeStringList(char **buf, // IN int32 *left, // IN DMKeyType fieldId, // IN DataMap *that) // OUT { ErrorCode res; int32 listSize; char **strList; int32 *strLens; int32 i; res = DecodeInt32(buf, left, &listSize); if (res != DMERR_SUCCESS) { return res; } if (listSize < 0 || listSize > *left / sizeof(int32)) { /* listSize can be zero to support an empty list */ return DMERR_BAD_DATA; } strList = (char **)calloc(listSize + 1, sizeof(char *)); if (strList == NULL) { return DMERR_INSUFFICIENT_MEM; } if (listSize) { strLens = (int32 *)malloc(sizeof(int32) * listSize); if (strLens == NULL) { FreeStringList(strList, strLens); return DMERR_INSUFFICIENT_MEM; } } else { strLens = NULL; } for (i = 0; i < listSize; i++) { res = DecodeString(buf, left, &strList[i], &strLens[i]); if (res != DMERR_SUCCESS) { break; } } if (res == DMERR_SUCCESS) { res = AddEntry_StringList(that, fieldId, strList, strLens); } if (res != DMERR_SUCCESS) { FreeStringList(strList, strLens); } return res; } /* *----------------------------------------------------------------------------- * * CopyStringList -- * * - copy string list entry into another map * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static ErrorCode CopyStringListEntry(DMKeyType fieldId, // IN const DataMapEntry *entry, // IN DataMap *dst) // OUT { char **oldList = entry->value.strList.strings; int32 *lenPtr = entry->value.strList.lengths; char **newList; int32 *newLens; int32 listSize = 0; char **ptr = oldList; ErrorCode res = DMERR_SUCCESS; int32 i; /* get the list Size */ for (; *ptr != NULL; ptr++) { listSize ++; } newList = (char **)calloc(listSize + 1, sizeof(char *)); if (newList == NULL) { return DMERR_INSUFFICIENT_MEM; } newLens = (int32 *)malloc(sizeof(int32) * listSize); if (newLens == NULL) { free(newList); return DMERR_INSUFFICIENT_MEM; } /* copy the length vector */ memcpy(newLens, lenPtr, listSize * sizeof(int32)); /* copy string one by one */ for (i = 0; i < listSize; i++) { newList[i] = (char *)malloc(newLens[i]); if (newList[i] == NULL) { res = DMERR_INSUFFICIENT_MEM; break; } memcpy(newList[i], oldList[i], newLens[i]); } if (res == DMERR_SUCCESS) { res = AddEntry_StringList(dst, fieldId, newList, newLens); } if (res != DMERR_SUCCESS) { FreeStringList(newList, newLens); } return res; } /* *----------------------------------------------------------------------------- * * HashMapCopyEntryCb -- * * - Call back function to copy a dataMap entry. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void HashMapCopyEntryCb(void *key, // IN void *data, // IN void *userData) // IN/OUT { DMKeyType fieldId = *((DMKeyType *)key); DataMapEntry *entry = *((DataMapEntry **)data); ClientData *clientData = (ClientData *)userData; DataMap *dst = clientData->map; ErrorCode res = DMERR_SUCCESS; if (clientData->result != DMERR_SUCCESS) { /* previous calls have encountered error, so stop */ return; } switch(entry->type) { case DMFIELDTYPE_INT64: res = AddEntry_Int64(dst, fieldId, entry->value.number.val); break; case DMFIELDTYPE_STRING: { char *str = (char *)malloc(entry->value.string.length); if (str == NULL) { res = DMERR_INSUFFICIENT_MEM; break; } memcpy(str, entry->value.string.str, entry->value.string.length); res = AddEntry_String(dst, fieldId, str, entry->value.string.length); if (res != DMERR_SUCCESS) { free(str); } break; } case DMFIELDTYPE_INT64LIST: { int64 *numList; numList = (int64 *)malloc(sizeof(int64) * (entry->value.numList.length)); if (numList == NULL) { res = DMERR_INSUFFICIENT_MEM; } else { res = AddEntry_Int64List(dst, fieldId, numList, entry->value.numList.length); if (res != DMERR_SUCCESS) { free(numList); } } break; } case DMFIELDTYPE_STRINGLIST: res = CopyStringListEntry(fieldId, entry, dst); break; default: ASSERT(0); /* we do not expect this to happen */ break; } clientData->result = res; } /* *----------------------------------------------------------------------------- * * HashMapFreeEntryCb -- * * - call back function is called to free all entries in the hashMap. * * Result: * None * * Side-effects: * None * *----------------------------------------------------------------------------- */ static void HashMapFreeEntryCb(void *key, void *data, void *userData) { DataMapEntry *entry = *((DataMapEntry **)data); FreeEntry(entry); } /* *----------------------------------------------------------------------------- * * DataMap_Destroy -- * * Destroy the DataMap object pointed by that. Frees all the internal * pointers in the object. However the memory pointed by that is not * freed. * * Result: * 0 on success. * error code on failures. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_Destroy(DataMap *that) // IN/OUT { if (that == NULL) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); HashMap_Iterate(that->map, HashMapFreeEntryCb, TRUE, NULL); HashMap_DestroyMap(that->map); that->map = NULL; that->cookie = 0; return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * DataMap_Copy -- * * Copy a DataMap, a deep copy. * - 'dst': dst should *NOT* be initialized via DataMap_Create. * the caller *MUST* call DataMap_Destroy to detroy dst upon success. * * Result: * 0 on success. * error code on failures. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_Copy(const DataMap *src, // IN DataMap *dst) // OUT { ClientData clientData; ErrorCode res; if (src == NULL || dst == NULL) { return DMERR_INVALID_ARGS; } ASSERT(src->map != NULL); ASSERT(src->cookie == magic_cookie); /* init dst map */ res = DataMap_Create(dst); if (res != DMERR_SUCCESS) { return res; } clientData.map = dst; clientData.result = DMERR_SUCCESS; HashMap_Iterate(src->map, HashMapCopyEntryCb, FALSE, &clientData); if (clientData.result != DMERR_SUCCESS) { DataMap_Destroy(dst); } return clientData.result; } /* *----------------------------------------------------------------------------- * * DataMap_Serialize -- * * Serialize a DataMap to a buffer. * - 'buf': on success, this points to the allocated serialize buffer. * The caller *MUST* free this buffer to avoid memory leak. * - 'bufLen': on success, this indicates the length of the allocated * buffer. * * Result: * 0 on success * error code on failures. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_Serialize(const DataMap *that, // IN char **buf, // OUT uint32 *bufLen) // OUT { ClientData clientData; if (that == NULL || buf == NULL || bufLen == NULL) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); /* get the buffer size first */ memset(&clientData, 0, sizeof clientData); HashMap_Iterate(that->map, HashMapCalcEntrySizeCb, FALSE, &clientData); if (clientData.result != DMERR_SUCCESS) { return clientData.result; } /* 4 bytes is payload length */ *bufLen = clientData.buffLen + sizeof(uint32); if (*bufLen < clientData.buffLen) { return DMERR_INTEGER_OVERFLOW; } *buf = (char *)malloc(*bufLen); if (*buf == NULL) { return DMERR_INSUFFICIENT_MEM; } /* now serialize the map into the buffer */ clientData.map = (DataMap *)that; clientData.result = DMERR_SUCCESS; clientData.buffer = *buf; /* Encode the payload size */ EncodeInt32(&(clientData.buffer), clientData.buffLen); HashMap_Iterate(that->map, HashMapSerializeEntryCb, FALSE, &clientData); /* confidence check, make sure the buffer size is just used up. */ ASSERT(clientData.buffLen == 0); if (clientData.result != DMERR_SUCCESS) { free(*buf); *buf = NULL; *bufLen = 0; } return clientData.result; } /* *----------------------------------------------------------------------------- * * DataMap_Deserialize -- * * Initialize an empty DataMap from a buffer. * - 'that': the given map should *NOT* be initialized by the caller. * On success, the caller needs to call DataMap_Destropy on 'that' to * avoid any memory leak. * * Result: * - 0 on success * - error code on failures. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_Deserialize(const char *bufIn , // IN const int32 bufLen, // IN DataMap *that) // OUT { ErrorCode res; int32 left = bufLen; /* number of bytes undecoded */ int32 len; char *buf = (char *)bufIn; if (that == NULL || bufIn == NULL || bufLen < 0) { return DMERR_INVALID_ARGS; } /* decode the encoded buffer length */ res = DecodeInt32(&buf, &left, &len); if (res != DMERR_SUCCESS) { return res; } if (len > bufLen - sizeof(int32)) { return DMERR_TRUNCATED_DATA; } left = len; return DataMap_DeserializeContent(buf, left, that); } /* *----------------------------------------------------------------------------- * * DataMap_DeserializeContent -- * * Initialize an empty DataMap from the content of the data map buffer * - 'that': the given map should *NOT* be initialized by the caller. * On success, the caller needs to call DataMap_Destropy on 'that' to * avoid any memory leak. * * Result: * - 0 on success * - error code on failures. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_DeserializeContent(const char *content, // IN const int32 contentLen, // IN DataMap *that) // OUT { ErrorCode res; int32 left = contentLen; /* number of bytes undecoded */ char *buf = (char *)content; res = DataMap_Create(that); /* init the map */ if (res != DMERR_SUCCESS) { return res; } while ((left> 0) && (res == DMERR_SUCCESS)) { DMFieldType type; DMKeyType fieldId; int32 val; res = DecodeInt32(&buf, &left, &val); /* decode entry type */ if (res != DMERR_SUCCESS) { goto out; } if (val >= DMFIELDTYPE_MAX) { res = DMERR_UNKNOWN_TYPE; goto out; } type = (DMFieldType)val; res = DecodeInt32(&buf, &left, &fieldId); /* decode filedID */ if (res != DMERR_SUCCESS) { goto out; } if (LookupEntry(that, fieldId) != NULL) { res = DMERR_DUPLICATED_FIELD_IDS; goto out; } /* decode individual entry */ switch(type) { case DMFIELDTYPE_INT64: { int64 val; res = DecodeInt64(&buf, &left, &val); if (res != DMERR_SUCCESS) { goto out; } res = AddEntry_Int64(that, fieldId, val); break; } case DMFIELDTYPE_STRING: { char *str; int32 strLen; res = DecodeString(&buf, &left, &str, &strLen); if (res != DMERR_SUCCESS) { goto out; } res = AddEntry_String(that, fieldId, str, strLen); if (res != DMERR_SUCCESS) { /* clean up memory */ free(str); } break; } case DMFIELDTYPE_INT64LIST: { res = DecodeInt64List(&buf, &left, fieldId, that); break; } case DMFIELDTYPE_STRINGLIST: { res = DecodeStringList(&buf, &left, fieldId, that); break; } default: res = DMERR_UNKNOWN_TYPE; break; } } if (res != DMERR_SUCCESS) { goto out; } return DMERR_SUCCESS; out: DataMap_Destroy(that); return res; } /* *----------------------------------------------------------------------------- * * DataMap_SetInt64 -- * * Set an integer value to the map by given field id. * - 'replace': when an entry with the same fieldID exists, if replace is * true, error will be returned, otherwise, the existing entry will be * replaced. * * Result: * 0 on success * Otherwise, corresponding error code is returned. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_SetInt64(DataMap *that, // IN/OUT DMKeyType fieldId, // IN int64 value, // IN Bool replace) // IN { DataMapEntry *entry; if (that == NULL) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { /* need to add a new entry */ return AddEntry_Int64(that, fieldId, value); } else if (!replace){ return DMERR_ALREADY_EXIST; } else { if ((entry->type != DMFIELDTYPE_INT64)) { FreeEntryPayload(entry); entry->type = DMFIELDTYPE_INT64; } /* simple update */ entry->value.number.val = value; return DMERR_SUCCESS; } } /* *----------------------------------------------------------------------------- * * DataMap_SetString -- * * Set a string field to a map. * - 'str': the ownership of buffer pointed by str is passed to the map * on success. * - 'strLen': length of str, -1 means str is null terminated. * - 'replace': when an entry with the same fieldID exists, if replace is * true, error will be returned, otherwise, the existing entry will be * replaced. * * Result: * 0 on success * error code otherwise. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_SetString(DataMap *that, // IN/OUT DMKeyType fieldId, // IN char *str, // IN int32 strLen, // IN Bool replace) // IN { DataMapEntry *entry; if (that == NULL || str == NULL || (strLen < 0 && strLen != -1)) { return DMERR_INVALID_ARGS; } if (strLen == -1) { strLen = strlen(str); } ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { return AddEntry_String(that, fieldId, str, strLen); } else if (!replace){ return DMERR_ALREADY_EXIST; } else { FreeEntryPayload(entry); entry->type = DMFIELDTYPE_STRING; entry->value.string.str = str; entry->value.string.length = strLen; return DMERR_SUCCESS; } } /* *----------------------------------------------------------------------------- * * DataMap_SetInt64List -- * * Set an integer value array to the map by given field id. * - 'numList': the ownership of this list will be passed to the map on * success, no copy of the list numbers is made. * - 'replace': when an entry with the same fieldID exists, if replace is * true, error will be returned, otherwise, the existing entry will be * replaced. * * Result: * 0 on success * Otherwise, corresponding error code is returned. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_SetInt64List(DataMap *that, // IN/OUT DMKeyType fieldId, // IN int64 *numList, // IN int32 listLen, // IN Bool replace) // IN { DataMapEntry *entry; if (that == NULL || numList == NULL || listLen < 0) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { /* need to add a new entry */ return AddEntry_Int64List(that, fieldId, numList, listLen); } else if (!replace){ return DMERR_ALREADY_EXIST; } else { FreeEntryPayload(entry); entry->type = DMFIELDTYPE_INT64LIST; entry->value.numList.numbers = numList; entry->value.numList.length = listLen; return DMERR_SUCCESS; } } /* *----------------------------------------------------------------------------- * * DataMap_SetStringList -- * * Set a string list field to a map. * - 'strList': this pointer points to an array of string pointers. * Upon success, the ownership of this array is passed to the * map, no copy of strings is made. The last element in this array * pointer must be NULL. * - 'strLens': this is an array of integers which indicating the length of * cooresponding string in strList. the ownership is passed to the map * as well on success. * - 'replace': when an entry with the same fieldID exists, if replace is * true, error will be returned, otherwise, the existing entry will be * replaced. * * Result: * 0 on success * error code otherwise. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_SetStringList(DataMap *that, // IN/OUT DMKeyType fieldId, // IN char **strList, // IN int32 *strLens, // IN Bool replace) // IN { DataMapEntry *entry; if (that == NULL || strList == NULL || strLens == NULL) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { /* need to add a new entry */ return AddEntry_StringList(that, fieldId, strList, strLens); } else if (!replace){ return DMERR_ALREADY_EXIST; } else { FreeEntryPayload(entry); entry->type = DMFIELDTYPE_STRINGLIST; entry->value.strList.strings = strList; entry->value.strList.lengths = strLens; return DMERR_SUCCESS; } } /* *----------------------------------------------------------------------------- * * DataMap_GetInt64 -- * * - Get an integer value from the map by given field id. * * Result: * - DMERR_SUCCESS: *value has the value. * - DMERR_NOT_FOUND: no data is found * - DMERR_TYPE_MISMATCH: the entry in the map has other type. * - Otherwise, corresponding error code is returned. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_GetInt64(const DataMap *that, // IN DMKeyType fieldId, // IN int64 *value) // OUT { DataMapEntry *entry; if (that == NULL || value == NULL) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { return DMERR_NOT_FOUND; } if (entry->type != DMFIELDTYPE_INT64) { return DMERR_TYPE_MISMATCH; } *value = entry->value.number.val; return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * DataMap_GetString -- * * Get a string value from the map by given fieldId. * - 'str': upon success, *str is a string pointer which points to internal * map structures, and should not be modified. * - 'strLen': upon success, *strLen indicates the length of str. * * Result: * - DMERR_SUCCESS: *str points to the string field in the map, *strLen has * the string length. * - DMERR_NOT_FOUND: no data is found * - DMERR_TYPE_MISMATCH: the entry in the map has other type. * - Otherwise, corresponding error code is returned. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_GetString(const DataMap *that, // IN DMKeyType fieldId, // IN char **str, // OUT int32 *strLen) // OUT { DataMapEntry *entry; if (that == NULL || str == NULL || strLen == NULL) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { return DMERR_NOT_FOUND; } if (entry->type != DMFIELDTYPE_STRING) { return DMERR_TYPE_MISMATCH; } *str = entry->value.string.str; *strLen = entry->value.string.length; return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * DataMap_GetInt64List -- * * Get an integer value list from the map by given field id. * - 'numList': on success, *numList points data structures in the map, * and should not be modified. *numList is an array of int64. * - 'listLen': on success, *listLen indicates number of elements in * numList. * * Result: * - DMERR_SUCCESS: *numbers points to the list of numbers in the map, * *listLen has the list length. * - DMERR_NOT_FOUND: no data is found * - DMERR_TYPE_MISMATCH: the entry in the map has other type. * - Otherwise, corresponding error code is returned. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_GetInt64List(const DataMap *that, // IN DMKeyType fieldId, // IN int64 **numList, // OUT int32 *listLen) // OUT { DataMapEntry *entry; if (that == NULL || numList == NULL || listLen == NULL) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { return DMERR_NOT_FOUND; } if (entry->type != DMFIELDTYPE_INT64LIST) { return DMERR_TYPE_MISMATCH; } *numList = entry->value.numList.numbers; *listLen = entry->value.numList.length; return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * DataMap_GetStringList -- * * Get a string list from the map by given fieldId. * - 'strList': on success, *strList points to an array of strings which * is owned by the map, and should not be modified. * The last element in the array is NULL. * - 'strLen': on success, *strLen is an array of numbers indicates the * length of corresponding string in strList. * This should not be modified either. * * Result: * - DMERR_SUCCESS: *strList points to the list of strings in the map, * *strLens has the length for each string. * - DMERR_NOT_FOUND: no data is found * - DMERR_TYPE_MISMATCH: the entry in the map has other type. * - Otherwise, corresponding error code is returned. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_GetStringList(const DataMap *that, // IN DMKeyType fieldId, // IN char ***strList, // OUT int32 **strLens) // OUT { DataMapEntry *entry; if (that == NULL || strList == NULL || strLens == NULL) { return DMERR_INVALID_ARGS; } ASSERT(that->cookie == magic_cookie); entry = LookupEntry(that, fieldId); if (entry == NULL) { return DMERR_NOT_FOUND; } if (entry->type != DMFIELDTYPE_STRINGLIST) { return DMERR_TYPE_MISMATCH; } *strList = entry->value.strList.strings; *strLens = entry->value.strList.lengths; return DMERR_SUCCESS; } /* *----------------------------------------------------------------------------- * * DataMap_ToString -- * * Dump the content of the whole map into a user supplied buffer. * - 'fieldIdList': this is an array of FieldIdNameEntry. * - 'fieldIdListLen': the size of of feildIdList array. * - 'maxNumElements': for list elements, this is the max number of * elemenents we print. -1 means no limit. * - 'maxStrLen': max number of bytes to print for a string, -1 no limit. * - 'buf': *buf is a null terminated output string buffer, the caller * *MUST* free this buffer later to avoid memory leak. * * Result: * DMERR_SUCCESS on success. * error code on failures. * * Side-effects: * None * *----------------------------------------------------------------------------- */ ErrorCode DataMap_ToString(const DataMap *that, // IN FieldIdNameEntry *fieldIdList, // IN int32 fieldIdListLen, // IN int32 maxNumElements, // IN int32 maxStrLen, // IN char **buf) // OUT { ClientData clientData; char *buffPtr; /* This API is for debugging only, so we use hard coded buffer size */ const int32 maxBuffSize = 10 * 1024; if (that == NULL || buf == NULL || (maxNumElements < 0 && maxNumElements != -1) || (maxStrLen < 0 && maxStrLen != -1)) { return DMERR_INVALID_ARGS; } *buf = NULL; ASSERT(that->cookie == magic_cookie); /* get the buffer size first */ memset(&clientData, 0, sizeof clientData); clientData.map = (DataMap *)that; clientData.fieldIdList = fieldIdList; clientData.fieldIdListLen = fieldIdListLen; clientData.maxNumElems = maxNumElements; clientData.maxStrLen = maxStrLen; clientData.buffLen = maxBuffSize; buffPtr = (char *)malloc(maxBuffSize); if (buffPtr == NULL) { return DMERR_INSUFFICIENT_MEM; } *buf = buffPtr; clientData.buffer = buffPtr; ToBufferString(&clientData, "--> Begin\n"); /* output each entry in the map */ HashMap_Iterate(that->map, HashMapToStringEntryCb, FALSE, &clientData); ToBufferString(&clientData, "--> End.\n"); /* confidence check, make sure the buffer is not overflown. */ ASSERT(clientData.buffLen >= 0); ASSERT(buffPtr + maxBuffSize >= clientData.buffer); if (clientData.result == DMERR_BUFFER_TOO_SMALL) { const char truncStr[] = " DATA TRUNCATED!!!\n"; ASSERT(maxBuffSize > strlen(truncStr)); Str_Strcpy(buffPtr + maxBuffSize - strlen(truncStr) - 1, truncStr, strlen(truncStr) + 1); return DMERR_SUCCESS; } else if (clientData.result != DMERR_SUCCESS) { *buf = NULL; free(buffPtr); return clientData.result; } else { clientData.buffer[0] = '\0'; return DMERR_SUCCESS; } } open-vm-tools-stable-12.5.0/open-vm-tools/lib/dict/000077500000000000000000000000001470176644300220125ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/dict/Makefile.am000066400000000000000000000017231470176644300240510ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libDict.la libDict_la_SOURCES = libDict_la_SOURCES += dictll.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/dict/dictll.c000066400000000000000000000367221470176644300234430ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * dictll.c -- * * Low-level dictionary format --hpreg */ #include #include #include #include #include "vmware.h" #include "vmstdio.h" #include "escape.h" #include "dictll.h" #include "util.h" #define UTF8_BOM "\xEF\xBB\xBF" /* Duplicate a buffer --hpreg. The result is NUL-terminated */ static void * BufDup(void const * const bufIn, // IN: buffer to duplicate unsigned int const sizeIn) // IN: buffer size in bytes { char *bufOut; ASSERT(bufIn); bufOut = Util_SafeMalloc(sizeIn + 1); memcpy(bufOut, bufIn, sizeIn); bufOut[sizeIn] = '\0'; return bufOut; } /* *----------------------------------------------------------------------------- * * Walk -- * * While 'bufIn' points to a byte in 'sentinel', increment it --hpreg * * Note: * If your 'bufIn' is a NUL-terminated C string, you should rather make sure * that the NUL byte is not in your 'sentinel' * * Results: * The new 'buf' * * Side effects: * None * *----------------------------------------------------------------------------- */ static void const * Walk(void const * const bufIn, // IN int const * const sentinel) // IN { char const *buf; buf = (char const *)bufIn; ASSERT(buf); /* Unsigned does matter --hpreg */ while (sentinel[(unsigned char)*buf]) { buf++; } return buf; } /* * XXX Document the escaping/unescaping process: rationale for which chars we * escape, and how we escape --hpreg * * The dictionary line format: * * = * or * = " " * or * = (Implied value of empty string) * or * * * where * does not contain any whitespace or = or # * does not contain any double-quote or # * does not contain any double-quote * begins with # and ends at the end of the line * is a sequence spaces and/or tabs * and are optional */ /* *----------------------------------------------------------------------------- * * DictLL_UnmarshalLine -- * * Reads a line from the bufSize-byte buffer buf, which holds one or more * new-line delimited lines. The buffer is not necessarily * NUL-terminated. * * Results: * The beginning of the next line if a line was successfully parsed. In * that case, '*line' is the allocated line. If the line is well-formed, * then '*name' and '*value' are allocated strings. Otherwise they are * both NULL. * * A null pointer at the end of the buffer, in which case *line, *name, * and *value are set to null pointers. * * Side effects: * Advances *buf to the beginning of the next line. * *----------------------------------------------------------------------------- */ const char * DictLL_UnmarshalLine(const char *buf, // IN: buffer to parse size_t bufSize, // IN: buffer size in bytes char **line, // OUT: malloc()'d entire line char **name, // OUT: malloc()'d name or NULL char **value) // OUT: malloc()'d value or NULL { /* Space and tab --hpreg */ static int const ws_in[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; /* Everything but NUL, space, tab and pound --hpreg */ static int const wsp_out[] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; /* Everything but NUL, space, tab, pound and equal --hpreg */ static int const wspe_out[] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; /* Everything but NUL and double quote --hpreg */ static int const q_out[] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; char const *nBegin; char const *nEnd; char const *vBegin; char const *vEnd; char const *tmp; char *myLine; char *myName; char *myValue; const char *lineEnd; const char *nextLine; ASSERT(buf); ASSERT(line); ASSERT(name); ASSERT(value); /* Check for end of buffer. */ if (bufSize == 0) { *line = NULL; *name = NULL; *value = NULL; return NULL; } /* Find end of this line, beginning of next. */ lineEnd = memchr(buf, '\n', bufSize); if (lineEnd != NULL) { nextLine = lineEnd + 1; } else { nextLine = lineEnd = buf + bufSize; } /* Make local copy of line. */ myLine = BufDup(buf, lineEnd - buf); /* Check if the line is well-formed --hpreg */ nBegin = Walk(myLine, ws_in); nEnd = Walk(nBegin, wspe_out); tmp = Walk(nEnd, ws_in); if (nBegin == nEnd || *tmp != '=') { goto weird; } tmp++; tmp = Walk(tmp, ws_in); if (*tmp == '"') { tmp++; vBegin = tmp; vEnd = Walk(vBegin, q_out); tmp = vEnd; if (*tmp != '"') { goto weird; } tmp++; } else { vBegin = tmp; vEnd = Walk(vBegin, wsp_out); tmp = vEnd; } tmp = Walk(tmp, ws_in); if (*tmp != '\0' && *tmp != '#') { goto weird; } /* The line is well-formed. Extract the name and value --hpreg */ myName = BufDup(nBegin, nEnd - nBegin); myValue = Escape_Undo('|', vBegin, vEnd - vBegin, NULL); VERIFY(myValue); *line = myLine; *name = myName; *value = myValue; return nextLine; weird: /* The line is not well-formed. Let the upper layers handle it --hpreg */ *line = myLine; *name = NULL; *value = NULL; return nextLine; } /* *----------------------------------------------------------------------------- * * DictLL_ReadLine -- * * Read the next line from a dictionary file --hpreg * * Results: * 2 on success: '*line' is the allocated line * If the line is well-formed, then '*name' and '*value' are * allocated strings. Otherwise they are both NULL. * 1 if there is no next line (end of stream) * 0 on failure: errno is set accordingly * * Side effects: * None * *----------------------------------------------------------------------------- */ int DictLL_ReadLine(FILE *stream, // IN: stream to read char **line, // OUT: malloc()'d line or null pointer char **name, // OUT: malloc()'d name or null pointer char **value) // OUT: malloc()'d value or null pointer { char *myLine; size_t myLineLen; ASSERT(stream); ASSERT(line); ASSERT(name); ASSERT(value); *line = NULL; *name = NULL; *value = NULL; switch (StdIO_ReadNextLine(stream, &myLine, 0, &myLineLen)) { case StdIO_Error: return 0; case StdIO_EOF: return 1; case StdIO_Success: if (DictLL_UnmarshalLine(myLine, myLineLen, line, name, value) == NULL) { *line = BufDup("", 0); } free(myLine); return 2; default: NOT_IMPLEMENTED(); } NOT_REACHED(); } /* *----------------------------------------------------------------------------- * * DictLL_MarshalLine -- * * Marshals a line, appending the data to a DynBuf. If 'name' is NULL, * '*value' contains the whole line to write verbatim. Otherwise a proper * name/value pair is written. * * Results: * TRUE on success, FALSE on failure (caused by memory allocation failure). * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool DictLL_MarshalLine(DynBuf *output, // IN/OUT: output buffer char const *name, // IN/OPT: name to marshal char const *value) // IN: value to marshal { size_t size; if (name) { /* * Double quote, pipe, 0x7F, and all control characters but * tab --hpreg * 0x80 to 0xff are unescaped so characters in encodings * like UTF-8 will be displayed normally. */ static int const toEscape[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; char *evalue; /* Write a well-formed line --hpreg */ evalue = Escape_Do('|', toEscape, value, (uint32)strlen(value), &size); if ( !DynBuf_Append(output, name, (uint32)strlen(name)) || !DynBuf_Append(output, " = \"", 4) || (size && !DynBuf_Append(output, evalue, size)) || !DynBuf_Append(output, "\"", 1)) { free(evalue); return FALSE; } free(evalue); } else { /* Write the line as passed from the upper layers --hpreg */ size = (uint32)strlen(value); if (size && !DynBuf_Append(output, value, size)) { return FALSE; } } /* * Win32 takes care of adding the \r (XXX this assumes that the stream * is opened in ascii mode) --hpreg */ if (!DynBuf_Append(output, "\n", 1)) { return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * DictLL_WriteLine -- * * Marshals a line, writing the data to a file. If 'name' is NULL, '*value' * contains the whole line to write verbatim. Otherwise a proper name/value * pair is written. * * Results: * TRUE on success * FALSE on failure: errno is set accordingly * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool DictLL_WriteLine(FILE *stream, // IN: stream to write char const *name, // IN: name to write char const *value) // IN: value to write { DynBuf buf; DynBuf_Init(&buf); if (!DictLL_MarshalLine(&buf, name, value)) { DynBuf_Destroy(&buf); errno = ENOMEM; return FALSE; } if (fwrite(DynBuf_Get(&buf), DynBuf_GetSize(&buf), 1, stream) != 1) { DynBuf_Destroy(&buf); return FALSE; } DynBuf_Destroy(&buf); return TRUE; } /* *----------------------------------------------------------------------------- * * DictLL_ReadUTF8BOM -- * * Reads a UTF-8 BOM from a file. * * Results: * If successful, returns TRUE and updates the file position. * Returns FALSE if a UTF-8 BOM was not found. * * Side effects: * Might clears the error indicator of the file stream. * *----------------------------------------------------------------------------- */ Bool DictLL_ReadUTF8BOM(FILE *file) // IN/OUT { Bool found; // sizeof on a string literal counts NUL. Exclude it. char buf[sizeof UTF8_BOM - 1] = { 0 }; if (file == stdin) { return FALSE; } found = fread(buf, sizeof buf, 1, file) == 1 && memcmp(UTF8_BOM, buf, sizeof buf) == 0; if (!found) { rewind(file); } return found; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/dynxdr/000077500000000000000000000000001470176644300223775ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/dynxdr/Makefile.am000066400000000000000000000021661470176644300244400ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2008-2018 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libDynxdr.la libDynxdr_la_SOURCES = libDynxdr_la_SOURCES += dynxdr.c libDynxdr_la_SOURCES += xdrutil.c libDynxdr_la_CPPFLAGS = libDynxdr_la_CPPFLAGS += @XDR_CPPFLAGS@ libDynxdr_la_LIBADD = libDynxdr_la_LIBADD += @XDR_LIBS@ open-vm-tools-stable-12.5.0/open-vm-tools/lib/dynxdr/dynxdr.c000066400000000000000000000267231470176644300240650ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2018, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #include #if defined(_WIN32) # include #else # include # include # include # include #endif #include "dynxdr.h" #include "dynbuf.h" #include "util.h" /* * dynxdr.c -- * * Implements an XDR stream backed by a DynBuf. */ typedef struct DynXdrData { DynBuf data; Bool freeMe; } DynXdrData; /* * Solaris does not declare some parameters as "const". */ #if defined(sun) # define DYNXDR_CONST #else # define DYNXDR_CONST const #endif /* * Mac OS X, FreeBSD and Solaris don't take a const parameter to the * "x_getpostn" function. */ #if defined(__APPLE__) || defined(__FreeBSD__) || defined(sun) || defined(USE_TIRPC) # define DYNXDR_GETPOS_CONST #else # define DYNXDR_GETPOS_CONST const #endif /* * Solaris defines the parameter to "x_putbytes" as an int. */ #if defined(sun) # define DYNXDR_SIZE_T int #else # define DYNXDR_SIZE_T u_int #endif /* * Mac OS 64-bit defines the parameter to "x_putlong" as an int. */ #if defined __APPLE__ && defined __LP64__ # define DYNXDR_LONG int #else # define DYNXDR_LONG long #endif #if defined(sun) # define DYNXDR_INLINE_T rpc_inline_t # define DYNXDR_INLINE_LEN_T int #else # define DYNXDR_INLINE_T int32_t # define DYNXDR_INLINE_LEN_T u_int #endif /* *----------------------------------------------------------------------------- * * DynXdrPutBytes -- * * Writes a byte array into the XDR stream. * * Results: * TRUE: all ok * FALSE: failed to add data do dynbuf. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static bool_t DynXdrPutBytes(XDR *xdrs, // IN/OUT DYNXDR_CONST char *data, // IN DYNXDR_SIZE_T len) // IN { DynXdrData *priv = (DynXdrData *) xdrs->x_private; return DynBuf_Append(&priv->data, data, len); } /* *----------------------------------------------------------------------------- * * DynXdrGetPos -- * * Returns the current position of the buffer, which is the same as * the current buffer size. * * XXX: The Mac OS X headers don't expect a "const" argument. * * Results: * The size of the underlying buffer. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static u_int DynXdrGetPos(DYNXDR_GETPOS_CONST XDR *xdrs) // IN { DynXdrData *priv = (DynXdrData *) xdrs->x_private; return (u_int) DynBuf_GetSize(&priv->data); } /* *----------------------------------------------------------------------------- * * DynXdrSetPos -- * * Sets the position of the XDR stream. The current data in the buffer is * not affected, just the pointer to the current position. * * Results: * TRUE if pos is within the bounds of the backing buffer. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static bool_t DynXdrSetPos(XDR *xdrs, // IN u_int pos) // IN { DynXdrData *priv = (DynXdrData *) xdrs->x_private; if (pos <= DynBuf_GetAllocatedSize(&priv->data)) { DynBuf_SetSize(&priv->data, (size_t) pos); return TRUE; } return FALSE; } #if !defined(USE_TIRPC) && \ defined(__GLIBC__) || \ (defined(sun) && \ (defined(_LP64) || \ defined(_KERNEL))) /* *----------------------------------------------------------------------------- * * DynXdrPutInt32 -- * * Writes a 32-bit int to the XDR stream. * * XXX: This seems to be a glibc-only extenstion. It's present since at * least glibc 2.1, according to their CVS. * * XXX: Investigate this further. This XDR operation exists in Solaris * since at least Solaris 9. * * Results: * TRUE: all ok * FALSE: failed to add data do dynbuf. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static bool_t DynXdrPutInt32(XDR *xdrs, // IN/OUT DYNXDR_CONST int32_t *ip) // IN { int32_t out = htonl(*ip); DynXdrData *priv = (DynXdrData *) xdrs->x_private; return DynBuf_Append(&priv->data, &out, sizeof out); } #endif /* *----------------------------------------------------------------------------- * * DynXdrPutLong -- * * Writes a 32-bit int to the XDR stream. * * Results: * TRUE: all ok * FALSE: failed to add data do dynbuf. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static bool_t DynXdrPutLong(XDR *xdrs, // IN/OUT DYNXDR_CONST DYNXDR_LONG *lp) // IN { int32 out; DynXdrData *priv = (DynXdrData *) xdrs->x_private; #ifdef __APPLE__ ASSERT_ON_COMPILE(sizeof *lp <= sizeof (int32)); #endif out = htonl((int32)*lp); return DynBuf_Append(&priv->data, &out, sizeof out); } /* *----------------------------------------------------------------------------- * * DynXdrInline -- * * Return a pointer to a contiguous buffer of len bytes. On XDR_ENCODE, * is used to preallocate chunks of the backing buffer such that the caller * may set bulk 4-byte members w/o reallocating each time. * * Results: * Valid pointer on success, NULL on failure. * * Side effects: * Backing DynBuf may be enlarged. * *----------------------------------------------------------------------------- */ static DYNXDR_INLINE_T * DynXdrInline(XDR *xdrs, // IN/OUT DYNXDR_INLINE_LEN_T len) // IN { DynXdrData *priv = (DynXdrData *)xdrs->x_private; DynBuf *buf = &priv->data; DYNXDR_INLINE_T *retAddr; ASSERT(len >= 0); ASSERT(xdrs->x_op == XDR_ENCODE); if (len == 0) { return (DYNXDR_INLINE_T *)&buf->data[buf->size]; } if (buf->allocated - buf->size < len) { /* DynBuf too small. Grow it. */ if (!DynBuf_Enlarge(buf, buf->size + len)) { return NULL; } } retAddr = (DYNXDR_INLINE_T *)&buf->data[buf->size]; buf->size += len; return retAddr; } /* *----------------------------------------------------------------------------- * * DynXdr_Create -- * * Creates a new XDR struct backed by a DynBuf. The XDR stream is created * in XDR_ENCODE mode. The "in" argument is optional - if NULL, a new XDR * structure will be allocated. * * Results: * The XDR struct, or NULL on failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ XDR * DynXdr_Create(XDR *in) // IN { static struct xdr_ops dynXdrOps = { /* * Yes, these macros are a little redundant, but I figure it helps with * readability to group the sun/_KERNEL bits together. */ #if !defined(sun) || (defined(sun) && !defined(_KERNEL)) NULL, /* x_getlong */ DynXdrPutLong, /* x_putlong */ #endif NULL, /* x_getbytes */ DynXdrPutBytes, /* x_putbytes */ DynXdrGetPos, /* x_getpostn */ DynXdrSetPos, /* x_setpostn */ DynXdrInline, /* x_inline */ NULL, /* x_destroy */ #if defined(__APPLE__) || defined(USE_TIRPC) NULL, /* x_control */ #elif defined(__GLIBC__) NULL, /* x_getint32 */ DynXdrPutInt32, /* x_putint32 */ #elif defined(sun) && (defined(_LP64) || defined(_KERNEL)) NULL, /* x_control */ NULL, /* x_getint32 */ DynXdrPutInt32, /* x_putint32 */ #endif }; XDR *ret; DynXdrData *priv; if (in == NULL) { ret = malloc(sizeof *ret); if (ret == NULL) { goto error; } } else { ret = in; } priv = malloc(sizeof *priv); if (priv == NULL) { goto error; } priv->freeMe = (in == NULL); DynBuf_Init(&priv->data); ret->x_op = XDR_ENCODE; ret->x_public = NULL; ret->x_private = (char *) priv; ret->x_base = 0; ret->x_ops = &dynXdrOps; return ret; error: if (in == NULL) { free(ret); } return NULL; } /* *----------------------------------------------------------------------------- * * DynXdr_AppendRaw -- * * Appends some raw bytes to the XDR stream's internal dynbuf. This is * useful when non-XDR data may need to be added to the buffer, avoiding * the need to create another buffer and copying the existing data. * * Results: * Whether appending the data was successful. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool DynXdr_AppendRaw(XDR *xdrs, // IN const void *buf, // IN size_t len) // IN { DynBuf *intbuf = &((DynXdrData *) xdrs->x_private)->data; return DynBuf_Append(intbuf, buf, len); } /* *----------------------------------------------------------------------------- * * DynXdr_GetData -- * * Returns a copy of the current data in the XDR buffer. Caller is * responsible for freeing the data. * * Results: * The current data in the buffer, or NULL if there's no data, or failed * to allocate data. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void * DynXdr_AllocGet(XDR *xdrs) // IN { DynBuf *buf = &((DynXdrData *) xdrs->x_private)->data; return Util_Memdup(DynBuf_Get(buf), DynBuf_GetSize(buf)); } /* *----------------------------------------------------------------------------- * * DynXdr_Get -- * * Returns the current data in the XDR buffer. * * Results: * The current data in the buffer, or NULL if there's no data. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void * DynXdr_Get(XDR *xdrs) // IN { DynBuf *buf = &((DynXdrData *) xdrs->x_private)->data; return DynBuf_Get(buf); } /* *----------------------------------------------------------------------------- * * DynXdr_Destroy -- * * Frees data in the XDR stream, optionally destroying the underlying * DynBuf (if "release" is TRUE). If the XDR stream was dynamically * allocated by DynXdr_Create(), it will be freed. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void DynXdr_Destroy(XDR *xdrs, // IN Bool release) // IN { if (xdrs) { DynXdrData *priv = (DynXdrData *) xdrs->x_private; if (release) { DynBuf_Destroy(&priv->data); } if (priv->freeMe) { free(xdrs); } free(priv); } } open-vm-tools-stable-12.5.0/open-vm-tools/lib/dynxdr/xdrutil.c000066400000000000000000000057461470176644300242520ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * xdrutil.c -- * * Utility functions for code that uses XDR to encode/decode data. */ #include #include #include "vm_assert.h" #include "vmxrpc.h" #include "xdrutil.h" /* *----------------------------------------------------------------------------- * * XdrUtil_ArrayAppend -- * * Appends 'cnt' new elements of size 'sz' at the end of the given array. * If successful, len will contain the count of elements in the new * array. * * The newly allocated memory is zeroed out. * * Results: * NULL on allocation failure, pointer to the first new element otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void * XdrUtil_ArrayAppend(void **array, // IN/OUT u_int *arrayLen, // IN/OUT size_t elemSz, // IN u_int elemCnt) // IN { void *ret = NULL; void *newarray; newarray = realloc(*array, (*arrayLen + elemCnt) * elemSz); if (newarray != NULL) { ret = &((char *)newarray)[*arrayLen * elemSz]; memset(ret, 0, elemSz * elemCnt); *array = newarray; *arrayLen = *arrayLen + elemCnt; } return ret; } /* *----------------------------------------------------------------------------- * * XdrUtil_Deserialize -- * * Deserializes the given data into the provided destination, using the * given XDR function. * * Results: * Whether deserialization was successful. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool XdrUtil_Deserialize(const void *data, // IN size_t dataLen, // IN void *xdrProc, // IN void *dest) // IN { Bool ret; xdrproc_t proc = xdrProc; XDR xdrs; ASSERT(data != NULL); ASSERT(xdrProc != NULL); ASSERT(dest != NULL); xdrmem_create(&xdrs, (char *) data, dataLen, XDR_DECODE); ret = (Bool) proc(&xdrs, dest, 0); xdr_destroy(&xdrs); if (!ret) { VMX_XDR_FREE(proc, dest); } return ret; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/err/000077500000000000000000000000001470176644300216575ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/err/Makefile.am000066400000000000000000000017551470176644300237230ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libErr.la libErr_la_SOURCES = libErr_la_SOURCES += err.c libErr_la_SOURCES += errPosix.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/err/err.c000066400000000000000000000210011470176644300226050ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016,2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * err.c -- * * General error handling library * */ #include "vmware.h" #include "errInt.h" #include "str.h" #include "vm_atomic.h" #include "hashTable.h" #include "util.h" #include "codeset.h" /* * Constants */ #define HASHTABLE_SIZE 2048 /* * Types */ typedef struct ErrInfo { Err_Number number; char *string; } ErrInfo; /* * Variables */ /* * We statically link lib/err in several libraries. This means that a * single binary may have several copies of lib/err. These pointers are * not static so that we have one copy across the entire binary. */ Atomic_Ptr errNumTable; Atomic_Ptr errPtrTable; #if defined VMX86_DEBUG && defined __linux__ Atomic_Ptr errStrTable; #endif #define NUMTABLE() HashTable_AllocOnce(&errNumTable, HASHTABLE_SIZE, \ HASH_INT_KEY | HASH_FLAG_ATOMIC, \ ErrFreeErrInfo) #define PTRTABLE() HashTable_AllocOnce(&errPtrTable, HASHTABLE_SIZE, \ HASH_INT_KEY | HASH_FLAG_ATOMIC, NULL) #if defined VMX86_DEBUG && defined __linux__ #define STRTABLE() HashTable_AllocOnce(&errStrTable, HASHTABLE_SIZE, \ HASH_STRING_KEY | HASH_FLAG_ATOMIC, \ NULL) #endif /* *---------------------------------------------------------------------- * * ErrFreeErrInfo -- * * HashTableFreeEntryFn helper function to free ErrInfo struct. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void ErrFreeErrInfo(void *pErrInfo) // IN { ErrInfo *errInfo = pErrInfo; if (errInfo) { free(errInfo->string); free(errInfo); } } /* *---------------------------------------------------------------------- * * Err_ErrString -- * * Returns a string that corresponds to the last error message. * The error number used is that which is native to the platform, * errno on POSIXen and GetLastError on Windows. * * Results: * Error message string. * * Side effects: * None. * Current error number is preserved. * *---------------------------------------------------------------------- */ const char * Err_ErrString(void) { return Err_Errno2String(Err_Errno()); } /* *---------------------------------------------------------------------- * * Err_Errno2String -- * * Return a string that corresponds to the passed error number. * The error number used is that which is native to the platform, * errno on POSIXen and GetLastError on Windows. * * The string is in English in UTF-8, has indefinite lifetime, * and need not be freed. * * Results: * Error message string in UTF-8. * * Side effects: * None. * Current error number is preserved. * *---------------------------------------------------------------------- */ const char * Err_Errno2String(Err_Number errorNumber) // IN { HashTable *numTable; HashTable *ptrTable; ErrInfo *info; ErrInfo *oldInfo; Err_Number oldErrno = Err_Errno(); ASSERT(errorNumber != ERR_INVALID); /* * Look up the error in numTable. * Or insert it if it's not there. */ numTable = NUMTABLE(); if (!HashTable_Lookup(numTable, (void *) (uintptr_t) errorNumber, (void **) &info)) { char buf[2048]; const char *p; size_t n; /* * Convert number to string and build the info structure. */ p = ErrErrno2String(errorNumber, buf, sizeof buf); info = Util_SafeMalloc(sizeof *info); info->number = errorNumber; info->string = Util_SafeStrdup(p); /* * To be safe, make sure the end of the string is at * a UTF-8 boundary, but we can only do this when the * string is in our buffer (it may not be). */ n = strlen(info->string); n = CodeSet_Utf8FindCodePointBoundary(info->string, n); info->string[n] = '\0'; /* * Try to insert new info into numTable. * If that fails, then we must have lost out to someone else. * Use theirs in that case. */ oldInfo = HashTable_LookupOrInsert(numTable, (void *) (uintptr_t) errorNumber, info); if (oldInfo != info) { ASSERT(oldInfo->number == info->number); ASSERT(Str_Strcmp(oldInfo->string, info->string) == 0); free(info->string); free(info); info = oldInfo; } } /* * Try to insert info into ptrTable. * We need to do it even if we didn't create this entry, * because we may get here before the other guy (who created * the entry and inserted it into numTable). */ ptrTable = PTRTABLE(); oldInfo = HashTable_LookupOrInsert(ptrTable, info->string, info); ASSERT(oldInfo == info); #if defined VMX86_DEBUG && defined __linux__ { HashTable *strTable = STRTABLE(); ErrInfo *i = HashTable_LookupOrInsert(strTable, info->string, info); ASSERT(i == info); } #endif Err_SetErrno(oldErrno); return info->string; } /* *---------------------------------------------------------------------- * * Err_String2Errno -- * * Return an error number that corresponds to the passed string. * The error number used is that which is native to the platform, * errno on POSIXen and GetLastError on Windows. * * To be recognized, the string must be one previously returned * by Err_Errno2String. Any other string (even a copy of * a valid error string) returns ERR_INVALID. * * Results: * Error number or ERR_INVALID. * * Side effects: * None. * *---------------------------------------------------------------------- */ Err_Number Err_String2Errno(const char *string) // IN { HashTable *ptrTable = PTRTABLE(); ErrInfo *info; if (!HashTable_Lookup(ptrTable, string, (void **) &info)) { return ERR_INVALID; } ASSERT(info->string == string); ASSERT(info->number != ERR_INVALID); return info->number; } /* *---------------------------------------------------------------------- * * Err_Exit -- * * Reclaim memory. Useful for avoiding leaks at exit being * reported by valgrind / Memory Validator. * * Assumes that no other threads are calling into bora/lib/err. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Err_Exit(void) // IN { HashTable *numTable = NUMTABLE(); HashTable *ptrTable = PTRTABLE(); #if defined VMX86_DEBUG && defined __linux__ HashTable *strTable = STRTABLE(); HashTable_FreeUnsafe(strTable); #endif HashTable_FreeUnsafe(ptrTable); HashTable_FreeUnsafe(numTable); } #ifdef VMX86_DEBUG /* *---------------------------------------------------------------------- * * Err_String2ErrnoDebug -- * * Return an error number that corresponds to the passed string. * * This is the debug version that uses the whole string as key, * instead of just the address. * * Results: * Error number or ERR_INVALID. * * Side effects: * None. * *---------------------------------------------------------------------- */ Err_Number Err_String2ErrnoDebug(const char *string) // IN { #ifdef __linux__ HashTable *strTable = STRTABLE(); ErrInfo *info; if (!HashTable_Lookup(strTable, string, (void **) &info)) { return ERR_INVALID; } ASSERT(Str_Strcmp(info->string, string) == 0); ASSERT(info->number != ERR_INVALID); if (info->string != string) { Log("%s: errno %d, string \"%s\" at %p, originally at %p.\n", __FUNCTION__, info->number, string, string, info->string); } return info->number; #else return ERR_INVALID; #endif } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/err/errInt.h000066400000000000000000000023171470176644300232760ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * errInt.h -- * * Internal definitions for the Err module. */ #ifndef _ERRINT_H_ #define _ERRINT_H_ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #include "err.h" const char *ErrErrno2String(Err_Number errorNumber, char *buf, size_t bufSize); #endif // ifndef _ERRINT_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/err/errPosix.c000066400000000000000000000036271470176644300236460ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * errPosix.c -- * * Posix error handling library * */ #if defined __linux__ /* Force GNU strerror_r prototype instead of Posix prototype */ # define _GNU_SOURCE #endif #include #include #include #include "vmware.h" #include "errInt.h" #include "util.h" #include "str.h" /* *---------------------------------------------------------------------- * * ErrErrno2String -- * * Convert an error number to a string in English. * The returned string may use the supplied buffer or may be * a static string. * * Results: * The error string. * * Side effects: * None. * *---------------------------------------------------------------------- */ const char * ErrErrno2String(Err_Number errorNumber, // IN char *buf, // OUT: return buffer size_t bufSize) // IN: size of buffer { char *p; #if defined(__linux__) && !defined(__ANDROID__) p = strerror_r(errorNumber, buf, bufSize); #else p = strerror(errorNumber); #endif ASSERT(p != NULL); return p; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/000077500000000000000000000000001470176644300220065ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/Makefile.am000066400000000000000000000023651470176644300240500ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libFile.la libFile_la_SOURCES = libFile_la_SOURCES += file.c libFile_la_SOURCES += fileStandAlone.c libFile_la_SOURCES += filePosix.c libFile_la_SOURCES += fileIO.c libFile_la_SOURCES += fileIOPosix.c libFile_la_SOURCES += fileLockPrimitive.c libFile_la_SOURCES += fileLockPosix.c libFile_la_SOURCES += fileTempPosix.c libFile_la_SOURCES += fileTemp.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/file.c000066400000000000000000002144421470176644300231000ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * file.c -- * * Interface to host file system. See also filePosix.c, * fileWin32.c, etc. * * If a function can be implemented such that it has no dependencies * outside of lib/misc, place the function in fileStandAlone.c, NOT * here. */ #if defined(_WIN32) #include #endif #include #include #include #include #if defined(_WIN32) #include #define S_IXUSR 0100 #define S_IWUSR 0200 #else #include #endif #include #include #include #include #include "vmware.h" #include "util.h" #include "str.h" #include "msg.h" #include "log.h" #include "random.h" #include "uuid.h" #include "config.h" #include "posix.h" #include "file.h" #include "fileIO.h" #include "util.h" #include "fileInt.h" #include "dynbuf.h" #include "base64.h" #include "timeutil.h" #include "hostinfo.h" #include "hostType.h" #include "vm_atomic.h" #include "vm_basic_asm.h" #include "fileLock.h" #include "userlock.h" #include "strutil.h" #include "unicodeOperations.h" /* *---------------------------------------------------------------------- * * File_Exists -- * * Check if a file is accessible with the process' real user ID * * XXX - This function invokes access(), which uses the real uid, * not the effective uid, so it probably does not do what you * expect. Instead it should use Posix_EuidAccess(), which * uses the effective uid, but it's too risky to fix right now. * See PR 459242. * * Errno/GetLastError is available upon failure. * * Results: * TRUE file is accessible with the process' real uid * FALSE file doesn't exist or an error occured * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_Exists(const char *pathName) // IN: May be NULL. { return FileIO_IsSuccess(FileIO_Access(pathName, FILEIO_ACCESS_EXISTS)); } /* *---------------------------------------------------------------------- * * File_UnlinkIfExists -- * * If the given file exists, unlink it. * * Errno/GetLastError is available upon failure. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * May unlink the file. * *---------------------------------------------------------------------- */ int File_UnlinkIfExists(const char *pathName) // IN: { errno = FileDeletion(pathName, TRUE); if (errno == ENOENT) { errno = 0; } return errno; } /* *----------------------------------------------------------------------------- * * File_SupportsMandatoryLock -- * * Determines if the underlying filesystem for a particular location * can support mandatory locking. Mandatory locking is used within * FileLock to make the advisory FileLock self-cleaning in the event * of host failure. * * Results: * TRUE if FILEIO_OPEN_EXCLUSIVE_LOCK will work, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool File_SupportsMandatoryLock(const char *pathName) // IN: file to be locked { /* * For now, "know" that all ESX filesystems support mandatory locks * and no non-ESX filesystems support mandatory locks. */ return HostType_OSIsVMK(); } /* *---------------------------------------------------------------------- * * File_IsDirectory -- * * Check if specified file is a directory or not. * * Errno/GetLastError is available upon failure. * * Results: * TRUE is a directory * FALSE is not a directory or an error occured * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_IsDirectory(const char *pathName) // IN: { FileData fileData; return (FileAttributes(pathName, &fileData) == 0) && (fileData.fileType == FILE_TYPE_DIRECTORY); } /* *----------------------------------------------------------------------------- * * File_GetFilePermissions -- * * Return the read / write / execute permissions of a file. * * Errno/GetLastError is available upon failure. * * Results: * TRUE if success, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool File_GetFilePermissions(const char *pathName, // IN: int *mode) // OUT: file mode { FileData fileData; ASSERT(mode != NULL); if (FileAttributes(pathName, &fileData) != 0) { return FALSE; } *mode = fileData.fileMode; #if defined(_WIN32) /* * On Win32 implementation of FileAttributes does not return execution * bit. */ if (FileIO_Access(pathName, FILEIO_ACCESS_EXEC) == FILEIO_SUCCESS) { *mode |= S_IXUSR; } #endif return TRUE; } /* *---------------------------------------------------------------------- * * File_Unlink -- * * Unlink the file. * * POSIX: If name is a symbolic link, then unlink the the file the link * refers to as well as the link itself. Only one level of links are * followed. * WINDOWS: No symbolic links so no link following. * * Errno/GetLastError is available upon failure. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * The file is removed. * *---------------------------------------------------------------------- */ int File_Unlink(const char *pathName) // IN: { errno = FileDeletion(pathName, TRUE); return errno; } /* *---------------------------------------------------------------------- * * File_UnlinkNoFollow -- * * Unlink the file (do not follow symbolic links). * On Windows, there are no symbolic links so this is the same as * File_Unlink * * Errno/GetLastError is available upon failure. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * The file is removed. * *---------------------------------------------------------------------- */ int File_UnlinkNoFollow(const char *pathName) // IN: { errno = FileDeletion(pathName, FALSE); return errno; } /* *---------------------------------------------------------------------- * * File_UnlinkRetry -- * * Unlink the file, retrying on EBUSY on ESX, up to given timeout. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * The file is removed. * *---------------------------------------------------------------------- */ int File_UnlinkRetry(const char *pathName, // IN: uint32 maxWaitTimeMilliSec) // IN: { if (vmx86_server) { uint32 const unlinkWait = 300; uint32 waitMilliSec = 0; do { errno = FileDeletion(pathName, TRUE); if (errno != EBUSY || waitMilliSec >= maxWaitTimeMilliSec) { break; } Log(LGPFX" %s: %s after %u ms\n", __FUNCTION__, pathName, unlinkWait); Util_Usleep(unlinkWait * 1000); waitMilliSec += unlinkWait; } while (TRUE); } else { errno = FileDeletion(pathName, TRUE); } return errno; } /* *---------------------------------------------------------------------- * * File_CreateDirectoryEx -- * * Creates the specified directory with the specified permissions. * * Errno/GetLastError is available upon failure. * * Results: * TRUE Directory was created * FALSE Directory creation failed. * See File_EnsureDirectoryEx for dealing with directories that * may exist. * * Side effects: * Creates the directory on disk. * *---------------------------------------------------------------------- */ Bool File_CreateDirectoryEx(const char *pathName, // IN: int mode) // IN: { int err = FileCreateDirectory(pathName, mode); return err == 0; } /* *---------------------------------------------------------------------- * * File_CreateDirectory -- * * Creates the specified directory with 0777 permissions. * * Errno/GetLastError is available upon failure. * * Results: * TRUE Directory was created * FALSE Directory creation failed. * See File_EnsureDirectory for dealing with directories that * may exist. * * Side effects: * Creates the directory on disk. * *---------------------------------------------------------------------- */ Bool File_CreateDirectory(const char *pathName) // IN: { int err = FileCreateDirectory(pathName, 0777); return err == 0; } /* *---------------------------------------------------------------------- * * File_EnsureDirectoryEx -- * * If the directory doesn't exist, creates it. If the directory * already exists, do nothing and succeed. * * Errno/GetLastError is available upon failure. * * Results: * See above. * * Side effects: * May create a directory on disk. * *---------------------------------------------------------------------- */ Bool File_EnsureDirectoryEx(const char *pathName, // IN: int mode) // IN: { int err = FileCreateDirectory(pathName, mode); if (err == EEXIST) { FileData fileData; err = FileAttributes(pathName, &fileData); if (err == 0) { if (fileData.fileType != FILE_TYPE_DIRECTORY) { err = ENOTDIR; errno = ENOTDIR; #if defined(_WIN32) SetLastError(ERROR_DIRECTORY); #endif } } } return err == 0; } /* *---------------------------------------------------------------------- * * File_EnsureDirectory -- * * If the directory doesn't exist, creates it. If the directory * already exists, do nothing and succeed. * * Errno/GetLastError is available upon failure. * * Results: * See above. * * Side effects: * May create a directory on disk. * *---------------------------------------------------------------------- */ Bool File_EnsureDirectory(const char *pathName) // IN: { return File_EnsureDirectoryEx(pathName, 0777); } /* *---------------------------------------------------------------------- * * File_DeleteEmptyDirectory -- * * Deletes the specified directory if it is empty. * * Results: * True if the directory is successfully deleted, false otherwise. * * Side effects: * Deletes the directory from disk. * *---------------------------------------------------------------------- */ Bool File_DeleteEmptyDirectory(const char *pathName) // IN: { Bool returnValue = TRUE; if (FileRemoveDirectory(pathName) != 0) { #if defined(_WIN32) /* * Directory may have read-only bit set. Unset the * read-only bit and try deleting one more time. */ if (File_SetFilePermissions(pathName, S_IWUSR)) { if (FileRemoveDirectory(pathName) != 0) { returnValue = FALSE; } } else { returnValue = FALSE; } #else returnValue = FALSE; #endif } return returnValue; } /* *---------------------------------------------------------------------- * * GetOldMachineID -- * * Return the old machineID, the one based on Hostinfo_MachineID. * * Results: * The machineID is returned. It should not be freed. * * Side effects: * Memory allocated for the machineID is never freed, however the * memory is cached - there is no memory leak. * *---------------------------------------------------------------------- */ static const char * GetOldMachineID(void) { static Atomic_Ptr atomic; /* Implicitly initialized to NULL. --mbellon */ const char *machineID; machineID = Atomic_ReadPtr(&atomic); if (machineID == NULL) { char *p; uint32 hashValue; uint64 hardwareID; char encodedMachineID[16 + 1]; char rawMachineID[sizeof hashValue + sizeof hardwareID]; Hostinfo_MachineID(&hashValue, &hardwareID); /* Build the raw machineID */ memcpy(rawMachineID, &hashValue, sizeof hashValue); memcpy(&rawMachineID[sizeof hashValue], &hardwareID, sizeof hardwareID); /* Base 64 encode the binary data to obtain printable characters */ /* coverity[check_return] */ Base64_Encode(rawMachineID, sizeof rawMachineID, encodedMachineID, sizeof encodedMachineID, NULL); /* remove '/' from the encoding; no problem using it for a file name */ for (p = encodedMachineID; *p; p++) { if (*p == '/') { *p = '-'; } } p = Util_SafeStrdup(encodedMachineID); if (Atomic_ReadIfEqualWritePtr(&atomic, NULL, p)) { Posix_Free(p); } machineID = Atomic_ReadPtr(&atomic); ASSERT(machineID != NULL); } return machineID; } /* *---------------------------------------------------------------------- * * FileLockGetMachineID -- * * Return the machineID, a "universally unique" identification of * of the system that calls this routine. * * An attempt is first made to use the host machine's UUID. If that * fails drop back to the older machineID method. * * Results: * The machineID is returned. It should not be freed. * * Side effects: * Memory allocated for the machineID is never freed, however the * memory is cached - there is no memory leak. * *---------------------------------------------------------------------- */ const char * FileLockGetMachineID(void) { static Atomic_Ptr atomic; /* Implicitly initialized to NULL. --mbellon */ const char *machineID; machineID = Atomic_ReadPtr(&atomic); if (machineID == NULL) { char *p; char *q; /* * UUID_GetHostRealUUID is fine on Windows. * * UUID_GetHostUUID is fine on Macs because the UUID can't be found * in /dev/mem even if it can be accessed. Macs always use the MAC * address from en0 to provide a UUID. * * UUID_GetHostUUID is problematic on Linux so it is not acceptable for * locking purposes - it accesses /dev/mem to obtain the SMBIOS UUID * and that can fail when the calling process is not priviledged. * */ #if defined(_WIN32) q = UUID_GetRealHostUUID(); #elif defined(__APPLE__) || defined(VMX86_SERVER) q = UUID_GetHostUUID(); #else q = NULL; #endif if (q == NULL) { p = Util_SafeStrdup(GetOldMachineID()); } else { /* * Coverity flags this as dead code on Non-Windows, non-Apple * Platforms, since q will be NULL and this code not reached. */ /* coverity[dead_error_begin] */ p = Str_SafeAsprintf(NULL, "uuid=%s", q); Posix_Free(q); /* Surpress any whitespace. */ for (q = p; *q; q++) { if (isspace((int) *q)) { *q = '-'; } } } if (Atomic_ReadIfEqualWritePtr(&atomic, NULL, p)) { Posix_Free(p); } machineID = Atomic_ReadPtr(&atomic); ASSERT(machineID != NULL); } return machineID; } /* *----------------------------------------------------------------------------- * * OldMachineIDMatch -- * * Do the old-style MachineIDs match? * * Results: * TRUE Yes * FALSE No * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool OldMachineIDMatch(const char *first, // IN: const char *second) // IN: { #if defined(__APPLE__) || defined(__linux__) /* Ignore the host name hash */ char *p; char *q; size_t len; Bool result; uint8 rawMachineID_1[12]; uint8 rawMachineID_2[12]; for (p = Util_SafeStrdup(first), q = p; *p; p++) { if (*p == '-') { *p = '/'; } } result = Base64_Decode(q, rawMachineID_1, sizeof rawMachineID_1, &len); Posix_Free(q); if ((result == FALSE) || (len != 12)) { Warning("%s: unexpected decode problem #1 (%s)\n", __FUNCTION__, first); return FALSE; } for (p = Util_SafeStrdup(second), q = p; *p; p++) { if (*p == '-') { *p = '/'; } } result = Base64_Decode(q, rawMachineID_2, sizeof rawMachineID_2, &len); Posix_Free(q); if ((result == FALSE) || (len != 12)) { Warning("%s: unexpected decode problem #2 (%s)\n", __FUNCTION__, second); return FALSE; } return memcmp(&rawMachineID_1[4], &rawMachineID_2[4], 8) == 0 ? TRUE : FALSE; #else return strcmp(first, second) == 0 ? TRUE : FALSE; #endif } /* *----------------------------------------------------------------------------- * * FileLockMachineIDMatch -- * * Do the MachineIDs match? * * Results: * TRUE Yes * FALSE No * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool FileLockMachineIDMatch(const char *hostMachineID, // IN: const char *otherMachineID) // IN: { if (strncmp(hostMachineID, "uuid=", 5) == 0) { if (strncmp(otherMachineID, "uuid=", 5) == 0) { return strcmp(hostMachineID + 5, otherMachineID + 5) == 0 ? TRUE : FALSE; } else { return OldMachineIDMatch(GetOldMachineID(), otherMachineID); } } else { if (strncmp(otherMachineID, "uuid=", 5) == 0) { return FALSE; } else { return strcmp(hostMachineID, otherMachineID) == 0 ? TRUE : FALSE; } } } /* *---------------------------------------------------------------------------- * * File_IsEmptyDirectory -- * * Check if specified file is a directory and contains no files. * * Results: * Bool - TRUE -> is an empty directory, FALSE -> not an empty directory * * Side effects: * None * *---------------------------------------------------------------------------- */ Bool File_IsEmptyDirectory(const char *pathName) // IN: { int numFiles; if (!File_IsDirectory(pathName)) { return FALSE; } numFiles = File_ListDirectory(pathName, NULL); if (numFiles < 0) { return FALSE; } return numFiles == 0; } /* *---------------------------------------------------------------------------- * * File_IsOsfsVolumeEmpty -- * * Check if specified OSFS volume contains no files. * This method ignore hidden .sf files. *.sf files are VMFS * metadata files. * * OSFS based volumes are considered empty even if they * contain vmfs metadata files. This emptiness can not be * checked by File_IsEmptyDirectory API (PR 1050328). * * Results: * Bool - TRUE -> is vmfs empty directory, FALSE -> not an vmfs * empty directory * * Side effects: * None * *---------------------------------------------------------------------------- */ Bool File_IsOsfsVolumeEmpty(const char *pathName) // IN: { int i, numFiles; char **fileList = NULL; static const char vmfsSystemFilesuffix[] = ".sf"; Bool onlyVmfsSystemFilesFound = TRUE; numFiles = File_ListDirectory(pathName, &fileList); if (numFiles == -1) { return FALSE; } for (i = 0; i < numFiles; i++) { if (!Unicode_EndsWith(fileList[i], vmfsSystemFilesuffix)) { onlyVmfsSystemFilesFound = FALSE; break; } } Util_FreeStringList(fileList, numFiles); return onlyVmfsSystemFilesFound; } /* *---------------------------------------------------------------------- * * File_IsFile -- * * Check if specified file is a regular file. * * Results: * TRUE is a regular file * FALSE is not a regular file or an error occured. * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_IsFile(const char *pathName) // IN: { FileData fileData; return (FileAttributes(pathName, &fileData) == 0) && (fileData.fileType == FILE_TYPE_REGULAR); } /* *---------------------------------------------------------------------- * * File_CopyFromFdToFd -- * * Write all data between the current position in the 'src' file and the * end of the 'src' file to the current position in the 'dst' file * * Results: * TRUE success * FALSE failure * * Side effects: * The current position in the 'src' file and the 'dst' file are modified * *---------------------------------------------------------------------- */ Bool File_CopyFromFdToFd(FileIODescriptor src, // IN: FileIODescriptor dst) // IN: { Err_Number err; FileIOResult fretR; do { unsigned char buf[8 * 1024]; size_t actual; FileIOResult fretW; fretR = FileIO_Read(&src, buf, sizeof buf, &actual); if (!FileIO_IsSuccess(fretR) && (fretR != FILEIO_READ_ERROR_EOF)) { err = Err_Errno(); Msg_Append(MSGID(File.CopyFromFdToFd.read.failure) "Read error: %s.\n\n", FileIO_MsgError(fretR)); Err_SetErrno(err); return FALSE; } fretW = FileIO_Write(&dst, buf, actual, NULL); if (!FileIO_IsSuccess(fretW)) { err = Err_Errno(); Msg_Append(MSGID(File.CopyFromFdToFd.write.failure) "Write error: %s.\n\n", FileIO_MsgError(fretW)); Err_SetErrno(err); return FALSE; } } while (fretR != FILEIO_READ_ERROR_EOF); return TRUE; } /* *----------------------------------------------------------------------------- * * FileCopyTree -- * * Recursively copies all files from a source path to a destination, * optionally overwriting any files. This does the actual work * for File_CopyTree. * * Results: * TRUE Success. * FALSE Failure. Error messages appended * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool FileCopyTree(const char *srcName, // IN: const char *dstName, // IN: Bool overwriteExisting, // IN: Bool followSymlinks) // IN: { int err; Bool success = TRUE; int numFiles; int i; char **fileList = NULL; numFiles = File_ListDirectory(srcName, &fileList); if (numFiles == -1) { err = Err_Errno(); Msg_Append(MSGID(File.CopyTree.walk.failure) "Unable to access '%s' when copying files.\n\n", srcName); Err_SetErrno(err); return FALSE; } File_EnsureDirectory(dstName); for (i = 0; i < numFiles && success; i++) { struct stat sb; char *srcFilename; srcFilename = File_PathJoin(srcName, fileList[i]); if (followSymlinks) { success = (Posix_Stat(srcFilename, &sb) == 0); } else { success = (Posix_Lstat(srcFilename, &sb) == 0); } if (success) { char *dstFilename = File_PathJoin(dstName, fileList[i]); switch (sb.st_mode & S_IFMT) { case S_IFDIR: success = FileCopyTree(srcFilename, dstFilename, overwriteExisting, followSymlinks); break; #if !defined(_WIN32) case S_IFLNK: if (Posix_Symlink(Posix_ReadLink(srcFilename), dstFilename) != 0) { err = Err_Errno(); Msg_Append(MSGID(File.CopyTree.symlink.failure) "Unable to symlink '%s' to '%s': %s\n\n", Posix_ReadLink(srcFilename), dstFilename, Err_Errno2String(err)); Err_SetErrno(err); success = FALSE; } break; #endif default: if (!File_Copy(srcFilename, dstFilename, overwriteExisting)) { err = Err_Errno(); Msg_Append(MSGID(File.CopyTree.copy.failure) "Unable to copy '%s' to '%s': %s\n\n", srcFilename, dstFilename, Err_Errno2String(err)); Err_SetErrno(err); success = FALSE; } break; } Posix_Free(dstFilename); } else { err = Err_Errno(); Msg_Append(MSGID(File.CopyTree.stat.failure) "Unable to get information on '%s' when copying files.\n\n", srcFilename); Err_SetErrno(err); } Posix_Free(srcFilename); } Util_FreeStringList(fileList, numFiles); return success; } /* *----------------------------------------------------------------------------- * * File_CopyTree -- * * Recursively copies all files from a source path to a destination, * optionally overwriting any files. * * Results: * TRUE Success. * FALSE Failure. Error messages appended * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool File_CopyTree(const char *srcName, // IN: const char *dstName, // IN: Bool overwriteExisting, // IN: Bool followSymlinks) // IN: { int err; ASSERT(srcName != NULL); ASSERT(dstName != NULL); if (!File_IsDirectory(srcName)) { err = Err_Errno(); Msg_Append(MSGID(File.CopyTree.source.notDirectory) "Source path '%s' is not a directory.", srcName); Err_SetErrno(err); return FALSE; } if (!File_IsDirectory(dstName)) { err = Err_Errno(); Msg_Append(MSGID(File.CopyTree.dest.notDirectory) "Destination path '%s' is not a directory.", dstName); Err_SetErrno(err); return FALSE; } return FileCopyTree(srcName, dstName, overwriteExisting, followSymlinks); } /* *---------------------------------------------------------------------- * * File_CopyFromFd -- * * Copy the 'src' file to 'dstName'. * If the 'dstName' file already exists, 'overwriteExisting' * decides whether to overwrite the existing file or not. * * Results: * TRUE Success. * FALSE Failure. Error messages appended * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_CopyFromFd(FileIODescriptor src, // IN: const char *dstName, // IN: Bool overwriteExisting) // IN: { Bool success; Err_Number err; FileIOResult fret; FileIODescriptor dst; FileIOOpenAction action; ASSERT(dstName != NULL); FileIO_Invalidate(&dst); action = overwriteExisting ? FILEIO_OPEN_CREATE_EMPTY : FILEIO_OPEN_CREATE_SAFE; fret = FileIO_Open(&dst, dstName, FILEIO_OPEN_ACCESS_WRITE, action); if (!FileIO_IsSuccess(fret)) { err = Err_Errno(); Msg_Append(MSGID(File.CopyFromFdToName.create.failure) "Unable to create a new '%s' file: %s.\n\n", dstName, FileIO_MsgError(fret)); Err_SetErrno(err); return FALSE; } success = File_CopyFromFdToFd(src, dst); err = Err_Errno(); if (!FileIO_IsSuccess(FileIO_Close(&dst))) { if (success) { // Report close failure when there isn't another error err = Err_Errno(); } Msg_Append(MSGID(File.CopyFromFdToName.close.failure) "Unable to close the '%s' file: %s.\n\n", dstName, Msg_ErrString()); success = FALSE; } if (!success) { /* The copy failed: ensure the destination file is removed */ File_Unlink(dstName); } Err_SetErrno(err); return success; } /* *---------------------------------------------------------------------- * * File_Copy -- * * Copy the 'srcName' file to 'dstName'. * If 'srcName' doesn't exist, an error is reported * If the 'dstName' file already exists, 'overwriteExisting' * decides whether to overwrite the existing file or not. * * Results: * TRUE Success. * FALSE Failure. Error messages appended * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_Copy(const char *srcName, // IN: const char *dstName, // IN: Bool overwriteExisting) // IN: { Bool success; Err_Number err; FileIOResult fret; FileIODescriptor src; ASSERT(srcName != NULL); ASSERT(dstName != NULL); FileIO_Invalidate(&src); fret = FileIO_Open(&src, srcName, FILEIO_OPEN_ACCESS_READ, FILEIO_OPEN); if (!FileIO_IsSuccess(fret)) { err = Err_Errno(); Msg_Append(MSGID(File.Copy.open.failure) "Unable to open the '%s' file for read access: %s.\n\n", srcName, FileIO_MsgError(fret)); Err_SetErrno(err); return FALSE; } success = File_CopyFromFd(src, dstName, overwriteExisting); err = Err_Errno(); if (!FileIO_IsSuccess(FileIO_Close(&src))) { if (success) { // Report close failure when there isn't another error err = Err_Errno(); } Msg_Append(MSGID(File.Copy.close.failure) "Unable to close the '%s' file: %s.\n\n", srcName, Msg_ErrString()); success = FALSE; } Err_SetErrno(err); return success; } /* *---------------------------------------------------------------------- * * File_Move -- * * Moves a file from one place to the other as efficiently as possible. * This can be used to rename a file but, since file copying may be * necessary, there is no assurance of atomicity. For efficiency * purposes copying only results if the native rename ability fails. * * Results: * TRUE success * FALSE otherwise * * Side effects: * src file is no more, but dst file exists * *---------------------------------------------------------------------- */ Bool File_Move(const char *oldFile, // IN: const char *newFile, // IN: Bool *asRename) // OUT/OPT: result occurred due to rename/copy { Bool ret; Bool duringRename; if (File_Rename(oldFile, newFile) == 0) { duringRename = TRUE; ret = TRUE; Err_SetErrno(0); } else { duringRename = FALSE; if (File_Copy(oldFile, newFile, TRUE)) { // Allow overwrite File_Unlink(oldFile); // Explicitly ignore errors ret = TRUE; Err_SetErrno(0); } else { ret = FALSE; } } if (asRename != NULL) { *asRename = duringRename; } return ret; } /* *----------------------------------------------------------------------------- * * File_MoveTree -- * * Moves a directory from one place to the other. * - If dstName indicates a path that does not exist a directory will be * created with that path filled with the contents from srcName. * - If dstName is an existing directory then the contents will be moved * into that directory. * - If dstName indicates a file then File_MoveTree fails. * * First we'll attempt to rename the directory, failing that we copy the * contents from src->destination and unlink the src. If the copy is * succesful then we will report success even if the unlink fails for some * reason. In that event we will append error messages. * * Results: * TRUE Success. * FALSE Failure. Error messages appended * * Side effects: * - Deletes the originating directory * - In the event of a failed copy we'll leave the new directory in an * undefined state. Calling File_DeleteDirectoryContent would be a * good idea. * *----------------------------------------------------------------------------- */ Bool File_MoveTree(const char *srcName, // IN: const char *dstName, // IN: Bool overwriteExisting, // IN: Bool *asMove) // OUT/OPT: { Bool ret = FALSE; Bool createdDir = FALSE; ASSERT(srcName != NULL); ASSERT(dstName != NULL); if (asMove != NULL) { *asMove = FALSE; } if (!File_IsDirectory(srcName)) { Msg_Append(MSGID(File.MoveTree.source.notDirectory) "Source path '%s' is not a directory.", srcName); return FALSE; } if (File_Rename(srcName, dstName) == 0) { if (asMove != NULL) { *asMove = TRUE; } ret = TRUE; } else { struct stat statbuf; if (Posix_Stat(dstName, &statbuf) == -1) { int err = Err_Errno(); if (err == ENOENT) { if (!File_CreateDirectoryHierarchy(dstName, NULL)) { Msg_Append(MSGID(File.MoveTree.dst.couldntCreate) "Could not create '%s'.\n\n", dstName); return FALSE; } createdDir = TRUE; } else { Msg_Append(MSGID(File.MoveTree.statFailed) "%d:Failed to stat destination '%s'.\n\n", err, dstName); return FALSE; } } else { if (!File_IsDirectory(dstName)) { Msg_Append(MSGID(File.MoveTree.dest.notDirectory) "The destination path '%s' is not a directory.\n\n", dstName); return FALSE; } } #if !defined(__FreeBSD__) && !defined(sun) /* * File_GetFreeSpace is not defined for FreeBSD */ if (createdDir) { /* * Check for free space on destination filesystem. We only check for * free space if the destination directory did not exist. In this * case, we will not be overwriting any existing paths, so we need as * much space as srcName. */ int64 srcSize = File_GetSizeEx(srcName); int64 freeSpace = File_GetFreeSpace(dstName, TRUE); if (freeSpace < srcSize) { char *spaceStr = Msg_FormatSizeInBytes(srcSize); Msg_Append(MSGID(File.MoveTree.dst.insufficientSpace) "There is not enough space in the file system to " "move the directory tree. Free %s and try again.", spaceStr); Posix_Free(spaceStr); return FALSE; } } #endif if (File_CopyTree(srcName, dstName, overwriteExisting, FALSE)) { ret = TRUE; if (!File_DeleteDirectoryTree(srcName)) { Msg_Append(MSGID(File.MoveTree.cleanupFailed) "Forced to copy '%s' into '%s' but unable to remove " "source directory.\n\n", srcName, dstName); } } else { ret = FALSE; Msg_Append(MSGID(File.MoveTree.copyFailed) "Could not rename and failed to copy source directory " "'%s'.\n\n", srcName); if (createdDir) { /* * Only clean up if we created the directory. Not attempting to * clean up partial failures. */ /* coverity[check_return] */ File_DeleteDirectoryTree(dstName); } } } return ret; } /* *---------------------------------------------------------------------- * * File_GetModTimeString -- * * Returns a human-readable string denoting the last modification * time of a file. * ctime() returns string terminated with newline, which we replace * with a '\0'. * * Results: * Last modification time string on success, NULL on error. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * File_GetModTimeString(const char *pathName) // IN: { int64 modTime = File_GetModTime(pathName); return (modTime == -1) ? NULL : TimeUtil_GetTimeFormat(modTime, TRUE, TRUE); } /* *---------------------------------------------------------------------------- * * File_GetSize -- * * Get size of file. Try File_GetSizeEx to get size of directory/symlink. * * For performance reasons, whenever a file grows, many file systems elect * to not update the on-storage inode information until close or when * forced to write a dirty page. This is done to avoid wasting I/O * throughput. * * The only way to determine the exact, up-to-date size of a file is to * open it and query the file size. * * Results: * Size of file or -1. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int64 File_GetSize(const char *pathName) // IN: { int64 ret; if (pathName == NULL) { ret = -1; } else { FileIODescriptor fd; FileIOResult res; FileIO_Invalidate(&fd); res = FileIO_Open(&fd, pathName, FILEIO_OPEN_ACCESS_READ, FILEIO_OPEN); if (FileIO_IsSuccess(res)) { ret = FileIO_GetSize(&fd); FileIO_Close(&fd); } else { ret = -1; } } return ret; } /* *---------------------------------------------------------------------- * * File_SupportsLargeFiles -- * * Check if the given file is on an FS that supports 4GB files. * Require 4GB support so we rule out FAT filesystems, which * support 4GB-1 on both Linux and Windows. * * Results: * TRUE if FS supports files over 4GB. * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_SupportsLargeFiles(const char *pathName) // IN: { return File_SupportsFileSize(pathName, CONST64U(0x100000000)); } /* *---------------------------------------------------------------------------- * * File_GetSizeEx -- * * Get size of file or directory or symlink. File_GetSize can only get * size of file. * * Results: * Size of file/directory/symlink or -1. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int64 File_GetSizeEx(const char *pathName) // IN: { int i; int numFiles; int64 totalSize = 0; char **fileList = NULL; if (pathName == NULL) { return -1; } if (!File_IsDirectory(pathName)) { return File_GetSize(pathName); } numFiles = File_ListDirectory(pathName, &fileList); if (numFiles == -1) { return -1; } for (i = 0; i < numFiles; i++) { char *fileName = File_PathJoin(pathName, fileList[i]); int64 fileSize = File_GetSizeEx(fileName); Posix_Free(fileName); if (fileSize != -1) { totalSize += fileSize; } } Util_FreeStringList(fileList, numFiles); return totalSize; } /* *---------------------------------------------------------------------------- * * File_GetSizeByPath -- * * Get size of a file without opening it. * * Results: * Size of file or -1. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int64 File_GetSizeByPath(const char *pathName) // IN: { return (pathName == NULL) ? -1 : FileIO_GetSizeByPath(pathName); } /* *---------------------------------------------------------------------- * * FileFirstSlashIndex -- * * Finds the first pathname slash index in a path (both slashes count * for Win32, only forward slash for Unix). * * Results: * As described. * * Side effects: * None. * *---------------------------------------------------------------------- */ static UnicodeIndex FileFirstSlashIndex(const char *pathName, // IN: UnicodeIndex startIndex) // IN: { UnicodeIndex firstFS; #if defined(_WIN32) UnicodeIndex firstBS; #endif ASSERT(pathName != NULL); firstFS = Unicode_FindSubstrInRange(pathName, startIndex, -1, "/", 0, 1); #if defined(_WIN32) firstBS = Unicode_FindSubstrInRange(pathName, startIndex, -1, "\\", 0, 1); if ((firstFS != UNICODE_INDEX_NOT_FOUND) && (firstBS != UNICODE_INDEX_NOT_FOUND)) { return MIN(firstFS, firstBS); } else { return (firstFS == UNICODE_INDEX_NOT_FOUND) ? firstBS : firstFS; } #else return firstFS; #endif } /* *----------------------------------------------------------------------------- * * File_CreateDirectoryHierarchyEx -- * * Create a directory including any parents that don't already exist. * All the created directories are tagged with the specified permission. * Returns the topmost directory which was created, to allow calling code * to remove it after in case later operations fail. * * Results: * TRUE Success. * FALSE Failure. * * If topmostCreated is not NULL, it returns the result of the hierarchy * creation. If no directory was created, *topmostCreated is set to NULL. * Otherwise *topmostCreated is set to the topmost directory which was * created. *topmostCreated is set even in case of failure. * * The caller most free the resulting string. * * Side effects: * Only the obvious. * *----------------------------------------------------------------------------- */ Bool File_CreateDirectoryHierarchyEx(const char *pathName, // IN: int mode, // IN: char **topmostCreated) // OUT/OPT: { char *volume; UnicodeIndex index; UnicodeIndex length; if (topmostCreated != NULL) { *topmostCreated = NULL; } if (pathName == NULL) { return TRUE; } length = Unicode_LengthInCodePoints(pathName); if (length == 0) { return TRUE; } /* * Skip past any volume/share. */ File_SplitName(pathName, &volume, NULL, NULL); index = Unicode_LengthInCodePoints(volume); Posix_Free(volume); if (index >= length) { return File_IsDirectory(pathName); } /* * Iterate directory path, creating directories as necessary. */ while (TRUE) { int err; char *temp; index = FileFirstSlashIndex(pathName, index + 1); temp = Unicode_Substr(pathName, 0, (index == UNICODE_INDEX_NOT_FOUND) ? -1 : index); /* * If we check if the directory already exists and then we create it, * there is a race between these two operations. Any failure can be * confusing. We avoid this by attempting to create the directory before * checking the type. */ err = FileCreateDirectory(temp, mode); if (err == 0) { if (topmostCreated != NULL && *topmostCreated == NULL) { *topmostCreated = temp; temp = NULL; } } else { /* * For DELL thinOS, calling `mkdir' for an existing directory in a * path which we do not have write permission will return with EACCES * instead of EEXIST. Here we test again using `euidaccess' to work * around this. */ if (err == EACCES && Posix_EuidAccess(temp, F_OK) == 0) { err = EEXIST; } if (err == EEXIST) { FileData fileData; err = FileAttributes(temp, &fileData); if (err == 0) { if (fileData.fileType != FILE_TYPE_DIRECTORY) { err = ENOTDIR; errno = err; #if defined(_WIN32) SetLastError(ERROR_DIRECTORY); #endif } } } } if (err != 0) { Log(LGPFX" %s: Failure on '%s'. Error = %d\n", __FUNCTION__, temp, err); } Posix_Free(temp); if (err != 0) { return FALSE; } if (index == UNICODE_INDEX_NOT_FOUND) { break; } } return TRUE; } /* *----------------------------------------------------------------------------- * * File_CreateDirectoryHierarchy -- * * Create a directory including any parents that don't already exist. * All the created directories are tagged with 0777 permissions. * Returns the topmost directory which was created, to allow calling code * to remove it after in case later operations fail. * * Results: * TRUE on success, FALSE on failure. * * If topmostCreated is not NULL, it returns the result of the hierarchy * creation. If no directory was created, *topmostCreated is set to NULL. * Otherwise *topmostCreated is set to the topmost directory which was * created. *topmostCreated is set even in case of failure. * * The caller most free the resulting string. * * Side effects: * Only the obvious. * *----------------------------------------------------------------------------- */ Bool File_CreateDirectoryHierarchy(const char *pathName, // IN: char **topmostCreated) // OUT/OPT: { return File_CreateDirectoryHierarchyEx(pathName, 0777, topmostCreated); } /* *---------------------------------------------------------------------- * * FileDeleteDirectoryTree -- * * Deletes the specified directory tree. If filesystem errors are * encountered along the way, the function will continue to delete what * it can but will return FALSE. If contentOnly is TRUE it does not * delete the directory itself. * * Results: * TRUE the entire tree was deleted or didn't exist * FALSE otherwise. * * Side effects: * Deletes the directory tree from disk. * *---------------------------------------------------------------------- */ static INLINE Bool FileDeleteDirectoryTree(const char *pathName, // IN: directory to delete Bool contentOnly) // IN: Content only or not { int i; int numFiles; int err = 0; char *base; char **fileList = NULL; Err_Number fileError = 0; if (Posix_EuidAccess(pathName, F_OK) != 0) { /* * If Posix_EuidAccess failed with errno == ENOSYS, then fall back * to FileAttributes. */ if (errno == ENOSYS) { /* FileAttributes returns the error code instead of setting errno. */ err = FileAttributes(pathName, NULL); } else { /* Use the error value that was set by Posix_EuidAccess. */ err = errno; } } switch (err) { case ENOENT: case ENOTDIR: /* path does not exist or is inaccessible */ return TRUE; default: break; } /* get list of files in current directory */ numFiles = File_ListDirectory(pathName, &fileList); if (numFiles == -1) { return FALSE; } /* delete everything in the directory */ base = Unicode_Append(pathName, DIRSEPS); for (i = 0; i < numFiles; i++) { char *curPath; struct stat statbuf; curPath = Unicode_Append(base, fileList[i]); if (Posix_Lstat(curPath, &statbuf) == 0) { switch (statbuf.st_mode & S_IFMT) { case S_IFDIR: /* Directory, recurse */ if (!FileDeleteDirectoryTree(curPath, FALSE)) { fileError = Err_Errno(); } break; #if !defined(_WIN32) case S_IFLNK: /* Delete symlink, not what it points to */ err = FileDeletion(curPath, FALSE); if ((err != 0) && (err != ENOENT)) { fileError = Err_Errno(); } break; #endif default: err = FileDeletion(curPath, FALSE); if ((err != 0) && (err != ENOENT)) { #if defined(_WIN32) if (File_SetFilePermissions(curPath, S_IWUSR)) { err = FileDeletion(curPath, FALSE); if ((err != 0) && (err != ENOENT)) { fileError = Err_Errno(); } } else { fileError = Err_Errno(); } #else fileError = Err_Errno(); #endif } break; } } else { if (errno != ENOENT) { fileError = Err_Errno(); Log(LGPFX" %s: Lstat of '%s' failed, errno = %d\n", __FUNCTION__, curPath, errno); } } Posix_Free(curPath); } Posix_Free(base); if (!contentOnly) { /* * Call File_DeleteEmptyDirectory() only if there is no prior error * while deleting the children. */ if (fileError == 0 && !File_DeleteEmptyDirectory(pathName)) { fileError = Err_Errno(); } } Util_FreeStringList(fileList, numFiles); Err_SetErrno(fileError); return fileError == 0; } /* *---------------------------------------------------------------------- * * File_DeleteDirectoryContent -- * * Deletes the specified directory content. If filesystem errors are * encountered along the way, the function will continue to delete what * it can but will return FALSE. * * Results: * TRUE the entire contents were deleted or there were no files and the * directory was empty * FALSE otherwise * * Side effects: * Deletes the directory content from disk. * *---------------------------------------------------------------------- */ Bool File_DeleteDirectoryContent(const char *pathName) // IN: directory to delete { return FileDeleteDirectoryTree(pathName, TRUE); } /* *---------------------------------------------------------------------- * * File_DeleteDirectoryTree -- * * Deletes the specified directory tree. If filesystem errors are * encountered along the way, the function will continue to delete what * it can but will return FALSE. * * Results: * TRUE the entire tree was deleted or didn't exist * FALSE otherwise. * * Side effects: * Deletes the directory tree from disk. * *---------------------------------------------------------------------- */ Bool File_DeleteDirectoryTree(const char *pathName) // IN: directory to delete { return FileDeleteDirectoryTree(pathName, FALSE); } /* *----------------------------------------------------------------------------- * * File_FindFileInSearchPath -- * * Search all the directories in searchPath for a filename. * If searchPath has a relative path take it with respect to cwd. * searchPath must be ';' delimited. * * Results: * TRUE file was found * FALSE otherwise. * * Side effects: * If result is non Null allocate a string for the filename found. * *----------------------------------------------------------------------------- */ Bool File_FindFileInSearchPath(const char *fileIn, // IN: const char *searchPath, // IN: const char *cwd, // IN: char **result) // OUT/OPT: { char *cur; char *tok; Bool found; Bool full; char *saveptr = NULL; char *sp = NULL; char *dir = NULL; char *file = NULL; ASSERT(fileIn != NULL); ASSERT(searchPath != NULL); ASSERT(cwd != NULL); /* * First check the usual places - the fullpath or the cwd. */ full = File_IsFullPath(fileIn); if (full) { cur = Util_SafeStrdup(fileIn); } else { cur = Str_SafeAsprintf(NULL, "%s%s%s", cwd, DIRSEPS, fileIn); } if (Posix_EuidAccess(cur, F_OK) == 0) { goto done; } if (errno == ENOSYS && FileAttributes(cur, NULL) == 0) { goto done; } Posix_Free(cur); cur = NULL; if (full) { goto done; } File_GetPathName(fileIn, &dir, &file); /* * Search path applies only if filename is simple basename. */ if (Unicode_LengthInCodePoints(dir) != 0) { goto done; } /* * Didn't find it in the usual places so strip it to its bare minimum and * start searching. */ sp = Util_SafeStrdup(searchPath); tok = strtok_r(sp, FILE_SEARCHPATHTOKEN, &saveptr); while (tok != NULL) { if (File_IsFullPath(tok)) { /* Fully Qualified Path. Use it. */ cur = Str_SafeAsprintf(NULL, "%s%s%s", tok, DIRSEPS, file); } else { /* Relative Path. Prepend the cwd. */ if (Str_Strcasecmp(tok, ".") == 0) { /* Don't append "." */ cur = Str_SafeAsprintf(NULL, "%s%s%s", cwd, DIRSEPS, file); } else { cur = Str_SafeAsprintf(NULL, "%s%s%s%s%s", cwd, DIRSEPS, tok, DIRSEPS, file); } } if (Posix_EuidAccess(cur, F_OK) == 0) { break; } if ((errno == ENOSYS) && (FileAttributes(cur, NULL) == 0)) { break; } Posix_Free(cur); cur = NULL; tok = strtok_r(NULL, FILE_SEARCHPATHTOKEN, &saveptr); } done: if (cur != NULL) { found = TRUE; if (result) { *result = File_FullPath(cur); if (*result == NULL) { found = FALSE; } } Posix_Free(cur); } else { found = FALSE; } Posix_Free(sp); Posix_Free(dir); Posix_Free(file); return found; } /* *---------------------------------------------------------------------- * * File_ExpandAndCheckDir -- * * Expand any environment variables in the given path and check that * the named directory is writeable. * * Results: * NULL error * !NULL the expanded path otherwise. * * Side effects: * The result is allocated. * *---------------------------------------------------------------------- */ char * File_ExpandAndCheckDir(const char *dirName) // IN: { if (dirName != NULL) { char *edirName = Util_ExpandString(dirName); if ((edirName != NULL) && FileIsWritableDir(edirName)) { size_t len = strlen(edirName) - 1; if (edirName[len] == DIRSEPC) { edirName[len] = '\0'; } return edirName; } free(edirName); } return NULL; } /* *----------------------------------------------------------------------------- * * FileSimpleRandom -- * * Return a random number in the range of 0 and 2^32-1. * * Results: * Random number is returned. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ uint32 FileSimpleRandom(void) { uint32 result; static rqContext *context = NULL; static Atomic_uint32 spinLock = { 0 }; /* * Use a spin lock here since: * * The chance we'll spin in tiny. * The time spent under the spin lock is miniscule. * The time spent under the spin lock is not highly variable. * We can't get stuck under the spin lock. * The overhead of a mutex is larger than the time spent under the spin lock. * It uses much less memory than a mutex. */ while (Atomic_ReadWrite(&spinLock, 1)) { PAUSE(); } if (UNLIKELY(context == NULL)) { uint32 value; #if defined(_WIN32) value = GetCurrentProcessId(); #else value = getpid(); #endif context = Random_QuickSeed(value); ASSERT(context != NULL); } result = Random_Quick(context); Atomic_Write(&spinLock, 0); return result; } /* *---------------------------------------------------------------------- * * FileSleeper * * Sleep for a random amount of time, no less than the specified minimum * and no more than the specified maximum. This often proves useful to * "jitter" retries such that multiple threads don't easily get into * resonance performing necessary actions (e.g. retries). * * Results: * Somnambulistic behavior; the amount of time slept is returned. * * Side effects: * None * *---------------------------------------------------------------------- */ uint32 FileSleeper(uint32 minSleepTimeMsec, // IN: uint32 maxSleepTimeMsec) // IN: { uint32 variance; uint32 actualSleepTimeMsec; #if defined(_WIN32) uint32 totalSleepTimeMsec; #endif ASSERT(minSleepTimeMsec <= maxSleepTimeMsec); variance = maxSleepTimeMsec - minSleepTimeMsec; if (variance == 0) { actualSleepTimeMsec = minSleepTimeMsec; } else { float fpRand = ((float) FileSimpleRandom()) / ((float) ~((uint32) 0)); actualSleepTimeMsec = minSleepTimeMsec + (uint32) (fpRand * variance); } #if defined(_WIN32) /* Clamp individual sleeps to avoid Windows issues */ totalSleepTimeMsec = actualSleepTimeMsec; while (totalSleepTimeMsec > 0) { uint32 sleepTimeMsec = (totalSleepTimeMsec > 900) ? 900 : totalSleepTimeMsec; Util_Usleep(1000 * sleepTimeMsec); totalSleepTimeMsec -= sleepTimeMsec; } #else Util_Usleep(1000 * actualSleepTimeMsec); #endif return actualSleepTimeMsec; } /* *---------------------------------------------------------------------- * * FileRotateByRename -- * * The oldest indexed file should be removed so that the consequent * rename succeeds. * * The last dst is 'fileName' and should not be deleted. * * Results: * If newFileName is non-NULL: the new path is returned to *newFileName * if the rotation succeeded, otherwise NULL is returned in *newFileName. * The caller is responsible for freeing the string returned in * *newFileName. * * Side effects: * Rename backup old files kept so far. * *---------------------------------------------------------------------- */ static void FileRotateByRename(const char *fileName, // IN: full path to file const char *baseName, // IN: filename w/o extension. const char *ext, // IN: extension int n, // IN: number of old files to keep char **newFileName) // OUT/OPT: new path to file { char *src = NULL; char *dst = NULL; int i; int result; if (newFileName != NULL) { *newFileName = NULL; } for (i = n; i >= 0; i--) { src = (i == 0) ? (char *) fileName : Str_SafeAsprintf(NULL, "%s-%d%s", baseName, i - 1, ext); if (dst == NULL) { result = FileDeletion(src, FALSE); // Don't follow a symlink! if ((result != 0) && (result != ENOENT)) { Log(LGPFX" %s: failed to remove %s: %s\n", __FUNCTION__, src, Err_Errno2String(Err_Errno())); } } else { result = File_Rename(src, dst); if ((result != 0) && (result != ENOENT)) { Log(LGPFX" %s: rename of %s -> %s failed: %s\n", src, dst, __FUNCTION__, Err_Errno2String(Err_Errno())); } } if ((src == fileName) && (newFileName != NULL) && (result == 0)) { *newFileName = Util_SafeStrdup(dst); } ASSERT(dst != fileName); Posix_Free(dst); /* coverity[use_after_free] */ dst = src; } } /* *---------------------------------------------------------------------- * * FileNumberCompare -- * * Helper function for comparing the contents of two * uint32 pointers a and b, suitable for use by qsort * to order an array of file numbers. * * Results: * The contents of 'a' minus the contents of 'b'. * * Side effects: * None. */ static int FileNumberCompare(const void *a, // IN: const void *b) // IN: { return *(uint32 *) a - *(uint32 *) b; } /* *---------------------------------------------------------------------- * * FileRotateByRenumber -- * * File rotation scheme optimized for vmfs: * 1) Find highest numbered file (maxNr) * 2) Rename . to -. * Should maxNr hit MAX_UINT32, file names are "fixed up". * 3) Delete (nFound - numToKeep) lowest numbered files. * * Results: * If newFilePath is non-NULL: the new path is returned to *newFilePath * if the rotation succeeded, otherwise NULL is returned in *newFilePath. * The caller is responsible for freeing the string returned in * *newFilePath. * * Side effects: * Files renamed / deleted. * *---------------------------------------------------------------------- */ static void FileRotateByRenumber(const char *filePath, // IN: full path to file const char *filePathNoExt, // IN: filename w/o extension. const char *ext, // IN: extension int n, // IN: number old files to keep char **newFilePath) // OUT/OPT: new path to file { uint32 i; char *tmp; int result; int nrFiles; size_t extLen; size_t baseNameLen; uint32 maxNr = 0; uint32 nFound = 0; char *baseDir = NULL; char *baseName = NULL; char **fileList = NULL; char *fullPathNoExt = NULL; uint32 *fileNumbers = NULL; if (newFilePath != NULL) { *newFilePath = NULL; } fullPathNoExt = File_FullPath(filePathNoExt); if (fullPathNoExt == NULL) { Log(LGPFX" %s: failed to get full path for '%s'.\n", __FUNCTION__, filePathNoExt); goto cleanup; } File_GetPathName(fullPathNoExt, &baseDir, &baseName); if ((baseDir == NULL) || (*baseDir == '\0')) { free(baseDir); baseDir = Unicode_Duplicate(DIRSEPS); } if ((baseName == NULL) || (*baseName == '\0')) { Log(LGPFX" %s: failed to get base name for path '%s'.\n", __FUNCTION__, filePathNoExt); goto cleanup; } baseNameLen = strlen(baseName); nrFiles = File_ListDirectory(baseDir, &fileList); if (nrFiles == -1) { Log(LGPFX" %s: failed to read the directory '%s'.\n", __FUNCTION__, baseDir); goto cleanup; } fileNumbers = Util_SafeCalloc(nrFiles, sizeof(uint32)); /* * Make sure the whole file name precisely matches what we expect before * including in the list to be considered. */ extLen = strlen(ext); for (i = 0; i < nrFiles; i++) { size_t fileNameLen = strlen(fileList[i]); if ((fileNameLen >= (baseNameLen + 1 /* dash */ + 1 /* digit */ + extLen)) && (memcmp(fileList[i], baseName, baseNameLen) == 0) && (fileList[i][baseNameLen] == '-') && (memcmp(fileList[i] + fileNameLen - extLen, ext, extLen) == 0)) { const char *nr = fileList[i] + baseNameLen + 1; /* No leading zeros; zero is invalid; must be a valid ASCII digit */ if ((nr[0] >= '1') && (nr[0] <= '9')) { uint32 curNr; char *endNr = NULL; errno = 0; curNr = strtoul(nr, &endNr, 10); if ((errno == 0) && (endNr == fileList[i] + fileNameLen - extLen) && (curNr <= MAX_UINT32)) { fileNumbers[nFound++] = curNr; } } } Posix_Free(fileList[i]); } if (nFound > 0) { qsort(fileNumbers, nFound, sizeof(uint32), FileNumberCompare); maxNr = fileNumbers[nFound - 1]; /* * If the maximum file number maxes out the uint32 used, rename all of the * files, packing them down to the beginning of the rotation sequence. * * After MAX_UINT32 file rotations we can afford some extra time and I/O * operations to handle the wrapping case nicely. */ if (maxNr == MAX_UINT32) { for (i = 0; i < nFound; i++) { char *to = Str_SafeAsprintf(NULL, "%s/%s-%u%s", baseDir, baseName, i + 1, ext); char *from = Str_SafeAsprintf(NULL, "%s/%s-%u%s", baseDir, baseName, fileNumbers[i], ext); result = File_Rename(from, to); if (result != 0) { Log(LGPFX" %s: rename of %s -> %s failed: %s\n", __FUNCTION__, from, to, Err_Errno2String(Err_Errno())); } free(to); free(from); fileNumbers[i] = i + 1; } maxNr = nFound; } } /* Rename the existing file to the next number */ tmp = Str_SafeAsprintf(NULL, "%s/%s-%u%s", baseDir, baseName, maxNr + 1, ext); result = File_Rename(filePath, tmp); if ((result != 0) && (result != ENOENT)) { Log(LGPFX" %s: rename of %s -> %s failed: %s\n", __FUNCTION__, filePath, tmp, Err_Errno2String(Err_Errno())); } if (newFilePath == NULL || result != 0) { Posix_Free(tmp); } else { *newFilePath = tmp; } if (nFound >= n) { /* Delete the extra files. */ for (i = 0; i <= nFound - n; i++) { tmp = Str_SafeAsprintf(NULL, "%s/%s-%u%s", baseDir, baseName, fileNumbers[i], ext); result = FileDeletion(tmp, FALSE); // Don't follow a symlink! if (result != 0) { Log(LGPFX" %s: failed to remove %s: %s\n", __FUNCTION__, tmp, Err_Errno2String(Err_Errno())); } Posix_Free(tmp); } } cleanup: Posix_Free(fileNumbers); Posix_Free(fileList); Posix_Free(baseDir); Posix_Free(baseName); Posix_Free(fullPathNoExt); } /* *---------------------------------------------------------------------- * * File_Rotate -- * * Rotate old files. The 'noRename' option is useful for filesystems * where rename is hideously expensive (*cough* vmfs). * * Results: * If newFileName is non-NULL: the new path is returned to * *newFileName if the rotation succeeded, otherwise NULL * is returned in *newFileName. The caller is responsible * for freeing the string returned in *newFileName. * * Side effects: * Files are renamed / deleted. * *---------------------------------------------------------------------- */ void File_Rotate(const char *fileName, // IN: original file int n, // IN: number of backup files Bool noRename, // IN: don't rename all files char **newFileName) // OUT/OPT: new path to file { const char *ext; size_t baseLen; char *baseName; ASSERT(fileName != NULL); if ((ext = Str_Strrchr(fileName, '.')) == NULL) { ext = fileName + strlen(fileName); } baseLen = ext - fileName; /* * Backup base of file name. * * Since the Str_Asprintf(...) doesn't like format of %.*s and crashes * in Windows 2000. (Daniel Liu) */ baseName = Util_SafeStrdup(fileName); baseName[baseLen] = '\0'; if (noRename) { FileRotateByRenumber(fileName, baseName, ext, n, newFileName); } else { FileRotateByRename(fileName, baseName, ext, n, newFileName); } Posix_Free(baseName); } /* *----------------------------------------------------------------------------- * * File_GetFSMountInfo -- * * Platform-independent wrapper around File_GetVMFSMountInfo * * Results: * On failure return -1. Otherwise, return fsType, version, * remoteIP, remoteMountPoint, and localMountPoint. * * Side effects: * None * *----------------------------------------------------------------------------- */ int File_GetFSMountInfo(const char *pathName, char **fsType, uint32 *version, char **remoteIP, char **remoteMountPoint, char **localMountPoint) { #if defined VMX86_SERVER return File_GetVMFSMountInfo(pathName, fsType, version, remoteIP, remoteMountPoint, localMountPoint); #else return -1; #endif } /* *---------------------------------------------------------------------- * * File_ContainSymLink -- * * Check if the specified file path contains symbolic link. * * Results: * TRUE pathName contains a symlink, * FALSE pathName is not a symlink nor contains a symlink, or error. * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_ContainSymLink(const char *pathName) // IN: { char *path = NULL; char *base = NULL; Bool retValue = FALSE; if (File_IsSymLink(pathName)) { return TRUE; } File_GetPathName(pathName, &path, &base); if ((path != NULL) && (base != NULL) && (strcmp(path, "") != 0) && (strcmp(base, "") != 0)) { if (File_ContainSymLink(path)) { retValue = TRUE; } } Posix_Free(path); Posix_Free(base); return retValue; } /* *---------------------------------------------------------------------------- * * File_IsSubPathOf -- * * Check if the argument path is a sub path for argument base. * The argument path will be converted to canonical path which doesn't * contain ".." and then check if this canonical path is a sub path for * argument base. * So, this function can correctly recognize that a path like * "/tmp/dir1/dir2/../../../bin/" is not a sub path for "/tmp/". * * Results: * True if the argument path is a sub path for argument base. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool File_IsSubPathOf(const char *base, // IN: the base path to test against. const char *path) // IN: the possible subpath to test. { char *fullBase = File_FullPath(base); char *fullPath = File_FullPath(path); Bool isSubPath = TRUE; ASSERT(fullBase != NULL); ASSERT(fullPath != NULL); if (fullPath == NULL || fullBase == NULL || strncmp(fullPath, fullBase, strlen(fullBase)) != 0) { isSubPath = FALSE; } free(fullBase); free(fullPath); return isSubPath; } #if !defined(VMX86_SERVER) /* *--------------------------------------------------------------------------- * * File_DoesVolumeSupportConvertBlocks -- * * Does the volume support the new convert block allocation * IOCTL? (Always FALSE for now on non-VMFS.) * * Results: * TRUE Yes * FALSE No * * Side effects: * None * *--------------------------------------------------------------------------- */ Bool File_DoesVolumeSupportConvertBlocks(const char *pathName) // IN: { UNUSED_VARIABLE(pathName); return FALSE; } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/fileIO.c000066400000000000000000000744351470176644300233360ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * fileIO.c -- * * Basic (non internationalized) implementation of error messages for the * Files library. * * File locking/unlocking routines. * */ #include #include #include #include "vmware.h" #include "util.h" #include "fileIO.h" #include "fileLock.h" #include "fileInt.h" #include "msg.h" #include "unicodeOperations.h" #include "hostType.h" #if defined(_WIN32) #include #else #include #include #include #include #include #endif #if defined(VMX86_SERVER) #include "config.h" #include "fs_public.h" #endif /* *---------------------------------------------------------------------- * * FileIO_ErrorEnglish -- * * Return the message associated with a status code * * Results: * The message * * Side effects: * None * *---------------------------------------------------------------------- */ const char * FileIO_ErrorEnglish(FileIOResult status) // IN: { return Msg_StripMSGID(FileIO_MsgError(status)); } /* *---------------------------------------------------------------------- * * FileIO_MsgError -- * * Return the message associated with a status code * * Results: * The message. * * Side effects: * None. * *---------------------------------------------------------------------- */ const char * FileIO_MsgError(FileIOResult status) // IN: { const char *result = NULL; switch (status) { case FILEIO_SUCCESS: /* * Most of the time, you don't call this function with this value * because there is no error */ result = MSGID(fileio.success) "Success"; break; case FILEIO_CANCELLED: /* * Most of the time, you don't call this function with this value * because you don't want to display error messages after a user has * cancelled an operation. */ result = MSGID(fileio.cancel) "The operation was cancelled by the user"; break; case FILEIO_ERROR: /* * Most of the time, you don't call this function with this value * because you can call your native function to retrieve a more * accurate message. */ result = MSGID(fileio.generic) "Error"; break; case FILEIO_OPEN_ERROR_EXIST: result = MSGID(fileio.exists) "The file already exists"; break; case FILEIO_LOCK_FAILED: result = MSGID(fileio.lock) "Failed to lock the file"; break; case FILEIO_READ_ERROR_EOF: result = MSGID(fileio.eof) "Tried to read beyond the end of the file"; break; case FILEIO_FILE_NOT_FOUND: result = MSGID(fileio.notfound) "Could not find the file"; break; case FILEIO_NO_PERMISSION: result = MSGID(fileio.noPerm) "Insufficient permission to access the file"; break; case FILEIO_FILE_NAME_TOO_LONG: result = MSGID(fileio.namelong) "The file name is too long"; break; case FILEIO_WRITE_ERROR_FBIG: result = MSGID(fileio.fBig) "The file is too large"; break; case FILEIO_WRITE_ERROR_NOSPC: result = MSGID(fileio.noSpc) "There is no space left on the device"; break; case FILEIO_WRITE_ERROR_DQUOT: result = MSGID(fileio.dQuot) "There is no space left on the device"; break; case FILEIO_ERROR_LAST: NOT_IMPLEMENTED(); break; /* * We do not provide a default case on purpose, so that the compiler can * detect changes in the error set and reminds us to implement the * associated messages --hpreg */ } if (!result) { Warning("%s: bad code %d\n", __FUNCTION__, status); ASSERT(0); result = MSGID(fileio.unknown) "Unknown error"; } return result; } /* *---------------------------------------------------------------------- * * FileIO_Init -- * * Initialize invalid FileIODescriptor. Expects that caller * prepared structure with FileIO_Invalidate. * * Results: * None. * * Side effects: * None * *---------------------------------------------------------------------- */ void FileIO_Init(FileIODescriptor *fd, // IN/OUT: const char *pathName) // IN: { ASSERT(fd != NULL); ASSERT(pathName != NULL); fd->fileName = Unicode_Duplicate(pathName); } /* *---------------------------------------------------------------------- * * FileIO_Cleanup -- * * Undo resource allocation done by FileIO_Init. You do not want to * call this function directly, you most probably want FileIO_Close. * * Results: * None. * * Side effects: * None * *---------------------------------------------------------------------- */ void FileIO_Cleanup(FileIODescriptor *fd) // IN/OUT: { ASSERT(fd != NULL); if (fd->fileName) { Posix_Free(fd->fileName); fd->fileName = NULL; } } /* *---------------------------------------------------------------------- * * FileIOResolveLockBits -- * * Resolve the multitude of lock bits from historical public names * to newer internal names. * * Input flags: FILEIO_OPEN_LOCKED a.k.a. FILEIO_OPEN_LOCK_BEST, * FILEIO_OPEN_EXCLUSIVE_LOCK * Output flags: FILEIO_OPEN_LOCK_MANDATORY, FILEIO_OPEN_LOCK_ADVISORY * * Results: * None * * Side effects: * Only output flags are set in *access. * *---------------------------------------------------------------------- */ void FileIOResolveLockBits(int *access) // IN/OUT: FILEIO_OPEN_* bits { /* * Lock types: * none: no locking at all * advisory: open() ignores lock, FileIO_ respects lock. * mandatory: open() and FileIO_ respect lock. * "best": downgrades to advisory or mandatory based on OS support */ if ((*access & FILEIO_OPEN_EXCLUSIVE_LOCK) != 0) { *access &= ~FILEIO_OPEN_EXCLUSIVE_LOCK; *access |= FILEIO_OPEN_LOCK_MANDATORY; } if ((*access & FILEIO_OPEN_LOCK_BEST) != 0) { /* "Best effort" bit: mandatory if OS supports, advisory otherwise */ *access &= ~FILEIO_OPEN_LOCK_BEST; if (HostType_OSIsVMK()) { *access |= FILEIO_OPEN_LOCK_MANDATORY; } else { *access |= FILEIO_OPEN_LOCK_ADVISORY; } } /* Only one lock type (or none at all) allowed */ ASSERT(((*access & FILEIO_OPEN_LOCK_ADVISORY) == 0) || ((*access & FILEIO_OPEN_LOCK_MANDATORY) == 0)); } /* *---------------------------------------------------------------------- * * FileIO_Lock -- * * Call the FileLock module to lock the given file. * * Results: * FILEIO_ERROR A serious error occured. * FILEIO_SUCCESS All is well * FILEIO_LOCK_FAILED Requested lock on file was not acquired * FILEIO_FILE_NOT_FOUND Unable to find the specified file * FILEIO_NO_PERMISSION Permissions issues * FILEIO_FILE_NAME_TOO_LONG The path name is too long * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Lock(FileIODescriptor *file, // IN/OUT: int access) // IN: { FileIOResult ret = FILEIO_SUCCESS; /* * Lock the file if necessary. */ ASSERT(file != NULL); ASSERT(file->lockToken == NULL); FileIOResolveLockBits(&access); ASSERT((access & FILEIO_OPEN_LOCKED) == 0); #if !defined(__FreeBSD__) && !defined(sun) if ((access & FILEIO_OPEN_LOCK_MANDATORY) != 0) { /* Mandatory file locks are available only when opening a file */ ret = FILEIO_LOCK_FAILED; } else if ((access & FILEIO_OPEN_LOCK_ADVISORY) != 0) { int err = 0; file->lockToken = FileLock_Lock(file->fileName, (access & FILEIO_OPEN_ACCESS_WRITE) == 0, FILELOCK_DEFAULT_WAIT, &err, NULL); if (file->lockToken == NULL) { /* Describe the lock not acquired situation in detail */ Warning(LGPFX" %s on '%s' failed: %s\n", __FUNCTION__, file->fileName, (err == 0) ? "Lock timed out" : Err_Errno2String(err)); /* Return a serious failure status if the locking code did */ switch (err) { case 0: // File is currently locked case EROFS: // Attempt to lock for write on RO FS ret = FILEIO_LOCK_FAILED; break; case ENAMETOOLONG: // Path is too long ret = FILEIO_FILE_NAME_TOO_LONG; break; case ENOENT: // No such file or directory ret = FILEIO_FILE_NOT_FOUND; break; case EACCES: // Permissions issues ret = FILEIO_NO_PERMISSION; break; default: // Some sort of locking error ret = FILEIO_ERROR; } } } #endif // !__FreeBSD__ && !sun return ret; } /* *---------------------------------------------------------------------- * * FileIO_UnLock -- * * Call the FileLock module to unlock the given file. * * Results: * FILEIO_SUCCESS All is well * FILEIO_ERROR A serious error occured. * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Unlock(FileIODescriptor *file) // IN/OUT: { FileIOResult ret = FILEIO_SUCCESS; ASSERT(file != NULL); #if !defined(__FreeBSD__) && !defined(sun) if (file->lockToken != NULL) { int err = 0; if (!FileLock_Unlock(file->lockToken, &err, NULL)) { Warning(LGPFX" %s on '%s' failed: %s\n", __FUNCTION__, file->fileName, Err_Errno2String(err)); ret = FILEIO_ERROR; } file->lockToken = NULL; } #else ASSERT(file->lockToken == NULL); #endif // !__FreeBSD__ && !sun return ret; } /* *---------------------------------------------------------------------- * * FileIO_GetSize -- * * Get size of file. * * Results: * Size of file or -1. * * Side effects: * errno is set on error. * *---------------------------------------------------------------------- */ int64 FileIO_GetSize(const FileIODescriptor *fd) // IN: { int64 logicalBytes; return (FileIO_GetAllocSize(fd, &logicalBytes, NULL) != FILEIO_SUCCESS) ? -1 : logicalBytes; } /* *---------------------------------------------------------------------- * * FileIO_GetSizeByPath -- * * Get size of a file specified by path. * * Results: * Size of file or -1. * * Side effects: * errno is set on error * *---------------------------------------------------------------------- */ int64 FileIO_GetSizeByPath(const char *pathName) // IN: { int64 logicalBytes; return (FileIO_GetAllocSizeByPath(pathName, &logicalBytes, NULL) != FILEIO_SUCCESS) ? -1 : logicalBytes; } /* *---------------------------------------------------------------------- * * FileIO_Filename -- * * Returns the filename that was used to open a FileIODescriptor * * Results: * Filename. You DON'T own the memory - use Unicode_Duplicate if * you want to keep it for yourself. In particular, if the file * gets closed the string will almost certainly become invalid. * * Side effects: * None. * *---------------------------------------------------------------------- */ const char * FileIO_Filename(FileIODescriptor *fd) // IN: { ASSERT(fd != NULL); return fd->fileName; } /* *---------------------------------------------------------------------- * * FileIO_CloseAndUnlink * * Closes and unlinks the file associated with a FileIODescriptor. * * Results: * FILEIO_SUCCESS: The file was closed and unlinked. The FileIODescriptor * is no longer valid. * FILEIO_ERROR: An error occurred. * * Side effects: * File is probably closed and unlinked. * *---------------------------------------------------------------------- */ FileIOResult FileIO_CloseAndUnlink(FileIODescriptor *fd) // IN: { char *path; FileIOResult ret; ASSERT(fd != NULL); ASSERT(FileIO_IsValid(fd)); path = Unicode_Duplicate(fd->fileName); ret = FileIO_Close(fd); if ((File_UnlinkIfExists(path) != 0) && FileIO_IsSuccess(ret)) { ret = FILEIO_ERROR; } Posix_Free(path); return ret; } #if defined(_WIN32) || defined(__linux__) || defined(__APPLE__) || \ defined(__FreeBSD__) || defined(sun) /* *---------------------------------------------------------------------- * * FileIO_Pread -- * * Reads from a file starting at a specified offset. * * Note: This function may update the file pointer so you will need to * call FileIO_Seek before calling FileIO_Read/Write afterwards. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Pread(FileIODescriptor *fd, // IN: File descriptor void *buf, // IN: Buffer to read into size_t len, // IN: Length of the buffer uint64 offset) // IN: Offset to start reading { struct iovec iov; ASSERT(fd != NULL); iov.iov_base = buf; iov.iov_len = len; return FileIO_Preadv(fd, &iov, 1, offset, len, NULL); } /* *---------------------------------------------------------------------- * * FileIO_Pwrite -- * * Writes to a file starting at a specified offset. * * Note: This function may update the file pointer so you will need to * call FileIO_Seek before calling FileIO_Read/Write afterwards. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Pwrite(FileIODescriptor *fd, // IN: File descriptor void const *buf, // IN: Buffer to write from size_t len, // IN: Length of the buffer uint64 offset) // IN: Offset to start writing { struct iovec iov; ASSERT(fd != NULL); /* The cast is safe because FileIO_Pwritev() will not write to '*buf'. */ iov.iov_base = (void *)buf; iov.iov_len = len; return FileIO_Pwritev(fd, &iov, 1, offset, len, NULL); } #endif #if defined(sun) && __GNUC__ < 3 /* *----------------------------------------------------------------------------- * * FileIO_IsSuccess -- * * XXX: See comment in fileIO.h. For reasonable compilers, this * function is implemented as "static inline" in fileIO.h; for * unreasonable compilers, it can't be static so we implement it here. * * Results: * TRUE if the input indicates success. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool FileIO_IsSuccess(FileIOResult res) // IN: { return res == FILEIO_SUCCESS; } #endif /* *----------------------------------------------------------------------------- * * FileIO_AtomicTempPath * * Return a temp path name in the same directory as the argument path. * The path is the full path of the source file with a '~' appended. * The caller must free the path when done. * * Results: * UTF8 path if successful, NULL on failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ char * FileIO_AtomicTempPath(const char *path) // IN: { char *srcPath; char *retPath; srcPath = File_FullPath(path); if (srcPath == NULL) { Log("%s: File_FullPath of '%s' failed.\n", __FUNCTION__, path); return NULL; } retPath = Unicode_Join(srcPath, "~", NULL); Posix_Free(srcPath); return retPath; } /* *----------------------------------------------------------------------------- * * FileIO_AtomicTempFile * * Create a temp file in the same directory as the argument file. * On non-Windows attempts to create the temp file with the same * permissions and owner/group as the argument file. * * Results: * FileIOResult of call that failed or FILEIO_SUCCESS * * Side effects: * Creates a new file. * *----------------------------------------------------------------------------- */ FileIOResult FileIO_AtomicTempFile(FileIODescriptor *fileFD, // IN: FileIODescriptor *tempFD) // OUT: { char *tempPath; int permissions; FileIOResult status; #if !defined(_WIN32) int ret; struct stat stbuf; #endif ASSERT(FileIO_IsValid(fileFD)); ASSERT(tempFD && !FileIO_IsValid(tempFD)); tempPath = FileIO_AtomicTempPath(FileIO_Filename(fileFD)); if (tempPath == NULL) { status = FILEIO_ERROR; goto bail; } #if defined(_WIN32) permissions = 0; File_UnlinkIfExists(tempPath); #else if (fstat(fileFD->posix, &stbuf)) { Log("%s: Failed to fstat '%s', errno: %d.\n", __FUNCTION__, FileIO_Filename(fileFD), errno); status = FILEIO_ERROR; goto bail; } permissions = stbuf.st_mode; /* Clean up a previously created temp file; if one exists. */ ret = Posix_Unlink(tempPath); if (ret != 0 && errno != ENOENT) { Log("%s: Failed to unlink temporary file, errno: %d\n", __FUNCTION__, errno); /* Fall through; FileIO_Create will report the actual error. */ } #endif status = FileIO_Create(tempFD, tempPath, FILEIO_ACCESS_READ | FILEIO_ACCESS_WRITE, FILEIO_OPEN_CREATE_SAFE, permissions); if (!FileIO_IsSuccess(status)) { Log("%s: Failed to create temporary file, %s (%d). errno: %d\n", __FUNCTION__, FileIO_ErrorEnglish(status), status, Err_Errno()); goto bail; } #if !defined(_WIN32) /* * On ESX we always use the vmkernel atomic file swap primitive, so * there's no need to set the permissions and owner of the temp file. * * XXX this comment is not true for NFS on ESX -- we use rename rather * than "vmkernel atomic file swap primitive" -- but we do not care * because files are always owned by root. Sigh. Bug 839283. */ if (!HostType_OSIsVMK()) { if (fchmod(tempFD->posix, stbuf.st_mode)) { Log("%s: Failed to chmod temporary file, errno: %d\n", __FUNCTION__, errno); status = FILEIO_ERROR; goto bail; } if (fchown(tempFD->posix, stbuf.st_uid, stbuf.st_gid)) { Log("%s: Failed to chown temporary file, errno: %d\n", __FUNCTION__, errno); status = FILEIO_ERROR; goto bail; } } #endif Posix_Free(tempPath); return FILEIO_SUCCESS; bail: ASSERT(!FileIO_IsSuccess(status)); if (FileIO_IsValid(tempFD)) { FileIO_Close(tempFD); #if defined(_WIN32) File_UnlinkIfExists(tempPath); #else ret = Posix_Unlink(tempPath); if (ret != 0) { Log("%s: Failed to clean up temporary file, errno: %d\n", __FUNCTION__, errno); } ASSERT(ret == 0); #endif } Posix_Free(tempPath); return status; } /* *----------------------------------------------------------------------------- * * FileIO_AtomicUpdateEx -- * * On ESX when the target files reside on vmfs, exchanges the contents * of two files using code modeled from VmkfsLib_SwapFiles. Both "curr" * and "new" are left open. * * On hosted products, uses rename to swap files, so "new" becomes "curr", * and path to "new" no longer exists on success. * * On ESX on NFS: * * If renameOnNFS is TRUE, use rename, like on hosted. * * If renameOnNFS is FALSE, returns -1 rather than trying to use * rename, to avoid various bugs in the vmkernel client... (PR * 839283, PR 1671787, etc). * * On success the caller must call FileIO_IsValid on newFD to verify it * is still open before using it again. * * Results: * 1 if successful, 0 on failure, -1 if not supported on this filesystem. * errno is preserved. * * Side effects: * Disk I/O. * *----------------------------------------------------------------------------- */ int FileIO_AtomicUpdateEx(FileIODescriptor *newFD, // IN/OUT: file IO descriptor FileIODescriptor *currFD, // IN/OUT: file IO descriptor Bool renameOnNFS) // IN: fall back to rename on NFS { char *currPath = NULL; char *newPath = NULL; #if defined(_WIN32) uint32 currAccess; uint32 newAccess; FileIOResult status; FileIODescriptor tmpFD; #endif int savedErrno = 0; int ret = 0; ASSERT(FileIO_IsValid(newFD)); ASSERT(FileIO_IsValid(currFD)); if (HostType_OSIsVMK()) { #if defined(VMX86_SERVER) FS_SwapFilesArgsUW args = { 0 }; char *dirName = NULL; char *fileName = NULL; char *dstDirName = NULL; char *dstFileName = NULL; Bool isSame; currPath = File_FullPath(FileIO_Filename(currFD)); if (currPath == NULL) { savedErrno = errno; Log("%s: File_FullPath of '%s' failed.\n", __FUNCTION__, FileIO_Filename(currFD)); goto swapdone; } newPath = File_FullPath(FileIO_Filename(newFD)); if (newPath == NULL) { savedErrno = errno; Log("%s: File_FullPath of '%s' failed.\n", __FUNCTION__, FileIO_Filename(newFD)); goto swapdone; } File_GetPathName(newPath, &dirName, &fileName); File_GetPathName(currPath, &dstDirName, &dstFileName); ASSERT(dirName != NULL); ASSERT(fileName != NULL && *fileName != '\0'); ASSERT(dstDirName != NULL); ASSERT(dstFileName != NULL && *dstFileName != '\0'); errno = 0; isSame = File_IsSameFile(dirName, dstDirName); if (errno == 0) { ASSERT(isSame); } else { savedErrno = errno; Log("%s: File_IsSameFile of ('%s', '%s') failed: %d\n", __FUNCTION__, dirName, dstDirName, errno); goto swapdone; } args.fd = currFD->posix; if (ioctl(newFD->posix, IOCTLCMD_VMFS_SWAP_FILES, &args) != 0) { savedErrno = errno; if (errno != ENOSYS && errno != ENOTTY) { Log("%s: ioctl failed %d.\n", __FUNCTION__, errno); ASSERT(errno != EBUSY); /* #615124. */ } } else { ret = 1; } /* * Did we fail because we are on a file system that does not * support the IOCTLCMD_VMFS_SWAP_FILES ioctl? If so fallback to * using rename. * * Check for both ENOSYS and ENOTTY. PR 957695 */ if (savedErrno == ENOSYS || savedErrno == ENOTTY) { if (renameOnNFS) { int fd; /* * NFS allows renames of locked files, even if both files * are locked. The file lock follows the file handle, not * the name, so after the rename we can swap the underlying * file descriptors instead of closing and reopening the * target file. * * This is different than the hosted path below because * ESX uses native file locks and hosted does not. * * We assume that all ESX file systems that support rename * have the same file lock semantics as NFS. */ if (File_Rename(newPath, currPath)) { Log("%s: rename of '%s' to '%s' failed %d.\n", __FUNCTION__, newPath, currPath, errno); savedErrno = errno; goto swapdone; } ret = 1; fd = newFD->posix; newFD->posix = currFD->posix; currFD->posix = fd; FileIO_Close(newFD); } else { ret = -1; } } swapdone: Posix_Free(dirName); Posix_Free(fileName); Posix_Free(dstDirName); Posix_Free(dstFileName); Posix_Free(currPath); Posix_Free(newPath); errno = savedErrno; return ret; #else NOT_REACHED(); #endif } #if defined(_WIN32) currPath = Unicode_Duplicate(FileIO_Filename(currFD)); newPath = Unicode_Duplicate(FileIO_Filename(newFD)); newAccess = newFD->flags; currAccess = currFD->flags; FileIO_Close(newFD); /* * The current file needs to be closed and reopened, * but we don't want to drop the file lock by calling * FileIO_Close() on it. Instead, use native close primitives. * We'll reopen it later with FileIO_Open. Set the * descriptor/handle to an invalid value while we're in the * middle of transferring ownership. */ CloseHandle(currFD->win32); currFD->win32 = INVALID_HANDLE_VALUE; if (File_RenameRetry(newPath, currPath, 10) == 0) { ret = TRUE; } else { savedErrno = errno; ASSERT(!ret); } FileIO_Invalidate(&tmpFD); /* * Clear the locking bits from the requested access so that reopening * the file ignores the advisory lock. */ ASSERT((currAccess & FILEIO_OPEN_LOCK_MANDATORY) == 0); currAccess &= ~(FILEIO_OPEN_LOCK_MANDATORY | FILEIO_OPEN_LOCK_ADVISORY | FILEIO_OPEN_LOCK_BEST | FILEIO_OPEN_LOCKED); status = FileIO_Open(&tmpFD, currPath, currAccess, FILEIO_OPEN); if (!FileIO_IsSuccess(status)) { Panic("Failed to reopen dictionary after renaming " "\"%s\" to \"%s\": %s (%d)\n", newPath, currPath, FileIO_ErrorEnglish(status), status); } ASSERT(tmpFD.lockToken == NULL); currFD->win32 = tmpFD.win32; FileIO_Cleanup(&tmpFD); Posix_Free(currPath); Posix_Free(newPath); errno = savedErrno; return ret; #else currPath = (char *)FileIO_Filename(currFD); newPath = (char *)FileIO_Filename(newFD); if (File_Rename(newPath, currPath)) { Log("%s: rename of '%s' to '%s' failed %d.\n", __FUNCTION__, newPath, currPath, errno); savedErrno = errno; } else { int fd; ret = TRUE; fd = newFD->posix; newFD->posix = currFD->posix; currFD->posix = fd; FileIO_Close(newFD); } errno = savedErrno; return ret; #endif } /* *----------------------------------------------------------------------------- * * FileIO_AtomicUpdate -- * * Wrapper around FileIO_AtomicUpdateEx that defaults 'renameOnNFS' to * TRUE. * * Results: * TRUE if successful, FALSE otherwise. * * Side effects: * See FileIO_AtomicUpdateEx. * *----------------------------------------------------------------------------- */ Bool FileIO_AtomicUpdate(FileIODescriptor *newFD, // IN/OUT: file IO descriptor FileIODescriptor *currFD) // IN/OUT: file IO descriptor { return FileIO_AtomicUpdateEx(newFD, currFD, TRUE) == 1; } /* *----------------------------------------------------------------------------- * * FileIOGetChoiceOnConfig -- * * Get the choice based on the "answer.msg.%s.file.open" in config file. * If it's not set, will return the default 0x20. * * Results: * The first character of the value or 0x20 by default. * * Side effects: * None * *----------------------------------------------------------------------------- */ static char FileIOGetChoiceOnConfig(const char *device, // IN: device name const char *pathName) // IN: file path { char choice = 0x20; #if defined(VMX86_SERVER) char *answer = Config_GetString(NULL, "answer.msg.%s.file.open", device); if (answer == NULL) { Log("Appending %s output to %s. Use answer.msg.%s.file.open=\"replace\" " "to replace file instead.", device, pathName, device); } else { const char *opt = answer; while (*opt == '_') { opt++; } choice = *opt | 0x20; // tolower() for ascii free(answer); } #endif return choice; } /* *----------------------------------------------------------------------------- * * FileIO_CreateDeviceFileNoPrompt -- * * If file does not exist, new file is created. If file does exist, * configuration option answer.msg..file.open is consulted to * decide whether to truncate file (replace), append data at the end of * the file (append, the default), or fail open (cancel). * * Results: * FileIOResult of call: FILEIO_SUCCESS or FILEIO_CANCELLED or other value. * * Side effects: * None * *----------------------------------------------------------------------------- */ FileIOResult FileIO_CreateDeviceFileNoPrompt(FileIODescriptor *fd, // IN: file IO description const char *pathName, // IN: file path int openMode, // IN: FileIOOpenAction action,// IN: int perms, // IN: const char *device) // IN: { FileIOResult fret; char choice = '\0'; int time = 0; ASSERT(fd != NULL); ASSERT(pathName != NULL); ASSERT(device != NULL); while ((fret = FileIO_Create(fd, pathName, openMode, action, perms)) == FILEIO_OPEN_ERROR_EXIST) { if (choice == '\0') { choice = FileIOGetChoiceOnConfig(device, pathName); switch (choice) { case 'c': // Cancel fret = FILEIO_CANCELLED; break; case 'r': // Replace case 'o': // Overwrite action = FILEIO_OPEN_CREATE_EMPTY; break; default: // Append, nothing, empty string action = FILEIO_OPEN_CREATE; break; } } if (fret == FILEIO_CANCELLED || time++ == 3) { break; } } return fret; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/fileIOPosix.c000066400000000000000000002255741470176644300243630ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * fileIOPosix.c -- * * Implementation of the file library host specific functions for linux. */ #if defined(__linux__) # if !defined(VMX86_TOOLS) && !defined(__ANDROID__) # define FILEIO_SUPPORT_ODIRECT # define _GNU_SOURCE # endif # include #endif #include #include #include #include #if defined __ANDROID__ #include // for __NR_SYSCALL_BASE #endif #include #include #include #include #if defined(__linux__) #ifdef __ANDROID__ # include #else # include #endif #endif #include #include "su.h" #if defined(__APPLE__) #include #include #include #include #include #include #include #include #include #include #include #include #else #if defined(__FreeBSD__) #include #include #else #include #if !defined(__sun__) #include #include #endif #endif #endif /* Check for non-matching prototypes */ #include "vmware.h" #include "str.h" #include "err.h" #include "posix.h" #include "file.h" #include "fileIO.h" #include "fileInt.h" #include "config.h" #include "util.h" #include "iovector.h" #include "hostType.h" #include "unicodeOperations.h" #include "memaligned.h" #include "userlock.h" #include "hostinfo.h" #if defined(__APPLE__) #include #include #endif #ifdef VMX86_SERVER #include "fs_public.h" #include #endif /* * fallocate() is only supported since the glibc-2.8 and * linux kernel-2.6.23. Presently the glibc in our toolchain is 2.3. */ #if defined(__linux__) #if !defined(SYS_fallocate) #if defined(__i386__) #define SYS_fallocate 324 #elif __x86_64__ #define SYS_fallocate 285 #elif __arm__ #define SYS_fallocate (__NR_SYSCALL_BASE+352) // newer glibc value #endif #endif #if !defined(FALLOC_FL_KEEP_SIZE) #define FALLOC_FL_KEEP_SIZE 1 #endif #endif static const unsigned int FileIO_SeekOrigins[] = { SEEK_SET, SEEK_CUR, SEEK_END, }; static const int FileIO_OpenActions[] = { 0, O_TRUNC, O_CREAT, O_CREAT | O_EXCL, O_CREAT | O_TRUNC, }; #ifdef __APPLE__ static FileIOPrivilegedOpener *privilegedOpenerFunc = NULL; #endif /* * Options for FileCoalescing performance optimization */ typedef struct FilePosixOptions { Bool initialized; Bool aligned; Bool enabled; int countThreshold; int sizeThreshold; int aioNumThreads; ssize_t maxIOVec; } FilePosixOptions; static FilePosixOptions filePosixOptions; /* * Data structures for FileIOAligned_* functions; only used on * hosted (see fileInt.h for rationale). */ #if !defined(VMX86_TOOLS) && !defined(VMX86_SERVER) #define ALIGNEDPOOL_FREELIST_SIZE 30 #define ALIGNEDPOOL_BUFSZ (1024 * 1024) #define ALIGNEDPOOL_OLD_AGE ((VmTimeType)1000 * 1000 * 1000) /* nanoseconds */ typedef struct AlignedPool { MXUserExclLock *lock; /* * list: Array of allocated buffers. * 0 .. numBusy-1 : busy buffers (in use by a caller). * numBusy .. numAlloc-1 : allocated but not busy. * numAlloc .. SIZE-1 : unused. */ void *list[ALIGNEDPOOL_FREELIST_SIZE]; /* * timestamp: Array of release timestamps. * 0 .. numBusy-1 : unused. * numBusy .. numAlloc-1 : last time we had N buffers outstanding. * numAlloc .. SIZE-1 : unused. */ VmTimeType timestamp[ALIGNEDPOOL_FREELIST_SIZE]; /* invariant: 0 <= numBusy <= numAlloc <= ALIGNEDPOOL_FREELIST_SIZE */ unsigned numAlloc; unsigned numBusy; } AlignedPool; static Atomic_Ptr alignedPoolLockStorage; static AlignedPool alignedPool; #endif /* * Although, support for preadv()/pwrite() first appeared in Linux 2.6.30, * library support was added in glibc 2.10. Hence these functions * are not available in any header file. */ #if defined(__linux__) && !defined(__ANDROID__) #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64) /* * We want preadv/pwritev. But due to FOB=64, the symbols are -64. * TODO: when the baseline bumps to XOPEN=700, link directly to * the symbols (and anyone building XOPEN<700 gets nothing). */ extern ssize_t preadv64(int fd, const struct iovec *iov, int iovcnt, __off64_t offset) __attribute__ ((weak)); extern ssize_t pwritev64(int fd, const struct iovec *iov, int iovcnt, __off64_t offset) __attribute__ ((weak)); #else #error "Large file support is unavailable." #endif #endif /* defined(__linux__) */ /* *----------------------------------------------------------------------------- * * FileIOErrno2Result -- * * Convert a POSIX errno to a FileIOResult code. * * Results: * The FileIOResult corresponding to the errno, FILEIO_ERROR by default. * * Side effects: * None * *----------------------------------------------------------------------------- */ static FileIOResult FileIOErrno2Result(int error) // IN: errno to convert { switch (error) { case EIO: return FILEIO_ERROR; case EEXIST: return FILEIO_OPEN_ERROR_EXIST; case ENOENT: return FILEIO_FILE_NOT_FOUND; case EACCES: return FILEIO_NO_PERMISSION; case ENAMETOOLONG: return FILEIO_FILE_NAME_TOO_LONG; case ENOSPC: return FILEIO_WRITE_ERROR_NOSPC; case EFBIG: return FILEIO_WRITE_ERROR_FBIG; #if defined(VMX86_SERVER) case EBUSY: return FILEIO_LOCK_FAILED; #endif #if defined(EDQUOT) case EDQUOT: return FILEIO_WRITE_ERROR_DQUOT; #endif default: return FILEIO_ERROR; } } /* *---------------------------------------------------------------------- * * FileIO_OptionalSafeInitialize -- * * Initialize global state. If this module is called from a * thread other than the VMX or VCPU threads, like an aioGeneric worker * thread, then we cannot do things like call config. Do that sort * of initialization here, which is called from a safe thread. * * This routine is OPTIONAL if you do not call this module from a * worker thread. The same initialization can be done lazily when * a read/write routine is called. * * Results: * None * * Side effects: * None * *---------------------------------------------------------------------- */ INLINE void FileIO_OptionalSafeInitialize(void) { if (!filePosixOptions.initialized) { filePosixOptions.enabled = Config_GetBool(TRUE, "filePosix.coalesce.enable"); /* * Aligned malloc starts failing to allocate memory during heavy I/O on * Linux. We're not sure why -- maybe we are running out of mmaps? * Turn it off by default for now. */ filePosixOptions.aligned = Config_GetBool(FALSE, "filePosix.coalesce.aligned"); filePosixOptions.countThreshold = Config_GetLong(5, "filePosix.coalesce.count"); filePosixOptions.sizeThreshold = Config_GetLong(16*1024, "filePosix.coalesce.size"); filePosixOptions.aioNumThreads = Config_GetLong(0, "aiomgr.numThreads"); #if defined(__linux__) filePosixOptions.maxIOVec = sysconf(_SC_IOV_MAX); /* Assume unlimited unless sysconf says otherwise. */ if (filePosixOptions.maxIOVec < 0) { filePosixOptions.maxIOVec = MAX_INT32; } #elif defined(__APPLE__) /* * There appears to be no way to determine the iovec size limit at * runtime. If Apple ever changes this, we lose binary compatibility. * On the bright side, Apple has not changed this value for at least as * long as they've produced Intel Macs. */ filePosixOptions.maxIOVec = 1024; #else filePosixOptions.maxIOVec = MAX_INT32; #endif filePosixOptions.initialized = TRUE; FileIOAligned_PoolInit(); } } /* *---------------------------------------------------------------------- * * FileIO_Invalidate -- * * Initialize a FileIODescriptor with an invalid value * * Results: * None * * Side effects: * None * *---------------------------------------------------------------------- */ void FileIO_Invalidate(FileIODescriptor *fd) // OUT: { ASSERT(fd != NULL); (memset)(fd, 0, sizeof *fd); fd->posix = -1; } /* *---------------------------------------------------------------------- * * FileIO_IsValid -- * * Check whether a FileIODescriptor is valid. * * Results: * True if valid. * * Side effects: * None * *---------------------------------------------------------------------- */ Bool FileIO_IsValid(const FileIODescriptor *fd) // IN: { ASSERT(fd != NULL); return fd->posix != -1; } /* *---------------------------------------------------------------------- * * FileIO_CreateFDPosix -- * * This function is for specific needs: for example, when you need * to create a FileIODescriptor from an already open fd. Use only * FileIO_* library functions on the FileIODescriptor from that point on. * * Because FileIODescriptor struct is different on two platforms, * this function is the only one in the file library that's * platform-specific. * * Results: * FileIODescriptor * * Side effects: * None * *---------------------------------------------------------------------- */ FileIODescriptor FileIO_CreateFDPosix(int posix, // IN: UNIX file descriptor int flags) // IN: UNIX access flags { FileIODescriptor fd; FileIO_Invalidate(&fd); switch (flags & O_ACCMODE) { case O_RDWR: fd.flags |= (FILEIO_OPEN_ACCESS_READ | FILEIO_OPEN_ACCESS_WRITE); break; case O_WRONLY: fd.flags |= FILEIO_OPEN_ACCESS_WRITE; break; default: ASSERT(FALSE); /* FALLTHRU */ case O_RDONLY: fd.flags |= FILEIO_OPEN_ACCESS_READ; break; } #if defined(O_SYNC) // Not available in FreeBSD tools build if (flags & O_SYNC) { fd.flags |= FILEIO_OPEN_SYNC; } #endif if (flags & O_APPEND) { fd.flags |= FILEIO_OPEN_APPEND; } #if defined(__linux__) && defined(O_CLOEXEC) if (flags & O_CLOEXEC) { fd.flags |= FILEIO_OPEN_CLOSE_ON_EXEC; } #endif fd.posix = posix; return fd; } #if defined(__APPLE__) /* *---------------------------------------------------------------------- * * FileIO_SetPrivilegedOpener -- * * Set the function to be used when opening files with privilege, * overriding the default behavior. See FileIO_PrivilegedPosixOpen. * * Setting the privileged opener to NULL will restore default * behavior. * * This function is not thread safe. * * Results: * None * * Side effects: * None * *---------------------------------------------------------------------- */ void FileIO_SetPrivilegedOpener(FileIOPrivilegedOpener *opener) // IN { ASSERT(privilegedOpenerFunc == NULL || opener == NULL); privilegedOpenerFunc = opener; } #endif /* *---------------------------------------------------------------------- * * FileIOCreateRetry -- * * Open/create a file; specify creation mode * May perform retries to deal with certain OS conditions * * Results: * FILEIO_SUCCESS on success: 'file' is set * FILEIO_OPEN_ERROR_EXIST if the file already exists * FILEIO_FILE_NOT_FOUND if the file is not present * FILEIO_ERROR for other errors * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIOCreateRetry(FileIODescriptor *file, // OUT: const char *pathName, // IN: int access, // IN: FileIOOpenAction action, // IN: int mode, // IN: mode_t for creation uint32 maxWaitTimeMsec) // IN: Ignored { int fd = -1; int flags = 0; int error; FileIOResult ret; ASSERT(file != NULL); if (pathName == NULL) { errno = EFAULT; return FILEIO_ERROR; } ASSERT(!FileIO_IsValid(file)); ASSERT(file->lockToken == NULL); ASSERT_ON_COMPILE(FILEIO_ERROR_LAST < 16); /* See comment in fileIO.h */ FileIOResolveLockBits(&access); ASSERT((access & FILEIO_OPEN_LOCKED) == 0 && (access & FILEIO_OPEN_EXCLUSIVE_LOCK) == 0); /* Only ESX implements mandatory locking */ ASSERT((access & FILEIO_OPEN_LOCK_MANDATORY) == 0 || File_SupportsMandatoryLock(pathName)); #if defined(__APPLE__) if (access & FILEIO_OPEN_EXCLUSIVE_LOCK_MACOS) { flags |= O_EXLOCK; } #elif defined(__linux__) if (HostType_OSIsVMK()) { if ((access & FILEIO_OPEN_SWMR_LOCK) != 0) { flags |= O_SWMR_LOCK; } else if ((access & FILEIO_OPEN_MULTIWRITER_LOCK) != 0) { flags |= O_MULTIWRITER_LOCK; } else if ((access & FILEIO_OPEN_LOCK_MANDATORY) != 0) { flags |= O_EXCLUSIVE_LOCK; } else if ((access & FILEIO_OPEN_OPTIMISTIC_LOCK) != 0) { flags |= O_OPTIMISTIC_LOCK; } } #endif /* * Locking implementation note: this can be recursive. On ESX: * FileIOCreateRetry("foo", ...ADVISORY...) * -> FileIO_Lock("foo", ...ADVISORY...) * -> FileLock_Lock("foo", ...ADVISORY...) * -> FileIOCreateRetry("foo.lck", ...MANDATORY...) * -> open("foo.lck", ...O_EXCLUSIVE_LOCK...) */ FileIO_Init(file, pathName); /* Mandatory file locks are only available at open() itself */ if ((access & FILEIO_OPEN_LOCK_ADVISORY) != 0) { ret = FileIO_Lock(file, access); if (!FileIO_IsSuccess(ret)) { goto error; } } if ((access & (FILEIO_OPEN_ACCESS_READ | FILEIO_OPEN_ACCESS_WRITE)) == (FILEIO_OPEN_ACCESS_READ | FILEIO_OPEN_ACCESS_WRITE)) { flags |= O_RDWR; } else if (access & FILEIO_OPEN_ACCESS_WRITE) { flags |= O_WRONLY; } else if (access & FILEIO_OPEN_ACCESS_READ) { flags |= O_RDONLY; } if (access & FILEIO_OPEN_EXCLUSIVE_READ && access & FILEIO_OPEN_EXCLUSIVE_WRITE) { flags |= O_EXCL; } if (access & FILEIO_OPEN_UNBUFFERED) { #if defined(FILEIO_SUPPORT_ODIRECT) flags |= O_DIRECT; #elif !defined(__APPLE__) // Mac hosts need this access flag after opening. access &= ~FILEIO_OPEN_UNBUFFERED; LOG_ONCE(LGPFX" %s reverting to buffered IO on %s.\n", __FUNCTION__, pathName); #endif } if (access & FILEIO_OPEN_NONBLOCK) { flags |= O_NONBLOCK; } if (access & FILEIO_OPEN_APPEND) { flags |= O_APPEND; } #if defined(O_NOFOLLOW) if (access & FILEIO_OPEN_ACCESS_NOFOLLOW) { flags |= O_NOFOLLOW; } #endif #if defined(__linux__) if (access & FILEIO_OPEN_SYNC) { flags |= O_SYNC; } #endif #if defined(O_NOFOLLOW) if (access & FILEIO_OPEN_ACCESS_NOFOLLOW) { flags |= O_NOFOLLOW; } #endif #if defined(__linux__) && defined(O_CLOEXEC) if (access & FILEIO_OPEN_CLOSE_ON_EXEC) { flags |= O_CLOEXEC; } #endif flags |= FileIO_OpenActions[action]; file->flags = access; #if defined(__APPLE__) if (access & FILEIO_OPEN_PRIVILEGED) { // We only support privileged opens, not creates or truncations. if ((flags & (O_CREAT | O_TRUNC)) != 0) { fd = -1; errno = EACCES; } else { fd = FileIO_PrivilegedPosixOpen(pathName, flags); } } else { fd = Posix_Open(pathName, flags, mode); } #else { uid_t uid = -1; if (access & FILEIO_OPEN_PRIVILEGED) { uid = Id_BeginSuperUser(); } fd = Posix_Open(pathName, flags, mode); error = errno; if (access & FILEIO_OPEN_PRIVILEGED) { Id_EndSuperUser(uid); } errno = error; } #endif if (fd == -1) { ret = FileIOErrno2Result(errno); if (ret == FILEIO_ERROR) { Log(LGPFX "open error on %s: %s\n", pathName, Err_Errno2String(errno)); } goto error; } #if defined(__APPLE__) if (access & (FILEIO_OPEN_UNBUFFERED | FILEIO_OPEN_SYNC)) { error = fcntl(fd, F_NOCACHE, 1); if (error == -1) { ret = FileIOErrno2Result(errno); if (ret == FILEIO_ERROR) { Log(LGPFX "fcntl error on %s: %s\n", pathName, Err_Errno2String(errno)); } goto error; } if (!(access & FILEIO_OPEN_SYNC)) { error = fcntl(fd, F_NODIRECT, 1); if (error == -1) { ret = FileIOErrno2Result(errno); if (ret == FILEIO_ERROR) { Log(LGPFX "fcntl error on %s: %s\n", pathName, Err_Errno2String(errno)); } goto error; } } } #endif if (access & FILEIO_OPEN_DELETE_ASAP) { /* * Remove the name from the name space. The file remains laid out on the * disk and accessible through the file descriptor until it is closed. */ if (Posix_Unlink(pathName) == -1) { ret = FileIOErrno2Result(errno); if (ret == FILEIO_ERROR) { Log(LGPFX "unlink error on %s: %s\n", pathName, Err_Errno2String(errno)); } goto error; } } file->posix = fd; return FILEIO_SUCCESS; error: error = errno; if (fd != -1) { close(fd); } FileIO_Unlock(file); FileIO_Cleanup(file); FileIO_Invalidate(file); errno = error; return ret; } /* *---------------------------------------------------------------------- * * FileIO_CreateRetry -- * * Open/create a file; specify creation mode * * Results: * FILEIO_SUCCESS on success: 'file' is set * FILEIO_OPEN_ERROR_EXIST if the file already exists * FILEIO_FILE_NOT_FOUND if the file is not present * FILEIO_ERROR for other errors * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_CreateRetry(FileIODescriptor *file, // OUT: const char *pathName, // IN: int access, // IN: FileIOOpenAction action, // IN: int mode, // IN: mode_t for creation uint32 maxWaitTimeMsec) // IN: { return FileIOCreateRetry(file, pathName, access, action, mode, maxWaitTimeMsec); } /* *---------------------------------------------------------------------- * * FileIO_Create -- * * Open/create a file; specify creation mode * * Results: * FILEIO_SUCCESS on success: 'file' is set * FILEIO_OPEN_ERROR_EXIST if the file already exists * FILEIO_FILE_NOT_FOUND if the file is not present * FILEIO_ERROR for other errors * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Create(FileIODescriptor *file, // OUT: const char *pathName, // IN: int access, // IN: FileIOOpenAction action, // IN: int mode) // IN: mode_t for creation { return FileIOCreateRetry(file, pathName, access, action, mode, 0); } /* *---------------------------------------------------------------------- * * FileIO_OpenRetry -- * * Open/create a file. * May perform retries to deal with certain OS conditions. * * Results: * FILEIO_SUCCESS on success: 'file' is set * FILEIO_OPEN_ERROR_EXIST if the file already exists * FILEIO_FILE_NOT_FOUND if the file is not present * FILEIO_ERROR for other errors * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_OpenRetry(FileIODescriptor *file, // OUT: const char *pathName, // IN: int access, // IN: FileIOOpenAction action, // IN: uint32 maxWaitTimeMsec) // IN: { #if defined(VMX86_SERVER) FileIOResult res; uint32 waitTimeMsec = 0; uint32 maxLoopTimeMsec = 3000; // 3 seconds /* * Workaround the ESX NFS client bug as seen in PR 1341775. * Since ESX NFS client can sometimes *wrongly* return ESTALE for a * legitimate file open case, we retry for some time in hopes that the * problem will resolve itself. */ while (TRUE) { res = FileIOCreateRetry(file, pathName, access, action, S_IRUSR | S_IWUSR, maxWaitTimeMsec); if (res == FILEIO_ERROR && Err_Errno() == ESTALE && waitTimeMsec < maxLoopTimeMsec) { Log(LGPFX "FileIOCreateRetry (%s) failed with ESTALE, retrying.\n", pathName); waitTimeMsec += FileSleeper(100, 300); } else { break; } } return res; #else return FileIOCreateRetry(file, pathName, access, action, S_IRUSR | S_IWUSR, maxWaitTimeMsec); #endif } /* *---------------------------------------------------------------------- * * FileIO_Open -- * * Open/create a file. * * Results: * FILEIO_SUCCESS on success: 'file' is set * FILEIO_OPEN_ERROR_EXIST if the file already exists * FILEIO_FILE_NOT_FOUND if the file is not present * FILEIO_ERROR for other errors * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Open(FileIODescriptor *file, // OUT: const char *pathName, // IN: int access, // IN: FileIOOpenAction action) // IN: { return FileIO_OpenRetry(file, pathName, access, action, 0); } /* *---------------------------------------------------------------------- * * FileIO_Seek -- * * Change the current position in a file * * Results: * On success: the new current position in bytes from the beginning of * the file * * On failure: -1 * * Side effects: * None * *---------------------------------------------------------------------- */ uint64 FileIO_Seek(const FileIODescriptor *file, // IN: int64 distance, // IN: FileIOSeekOrigin origin) // IN: { ASSERT(file != NULL); #if defined(__ANDROID__) /* * Android doesn't implement _FILE_OFFSET_BITS=64, but always has lseek64. */ return lseek64(file->posix, distance, FileIO_SeekOrigins[origin]); #else /* * Require 64-bit file API support via _FILE_OFFSET_BITS=64 or * operating system default. */ ASSERT_ON_COMPILE(sizeof(off_t) == 8); return lseek(file->posix, distance, FileIO_SeekOrigins[origin]); #endif } /* *---------------------------------------------------------------------- * * FileIO_Write -- * * Write to a file * * Results: * FILEIO_SUCCESS on success: '*actual_count' = 'requested' bytes have * been written. * FILEIO_WRITE_ERROR_FBIG for the attempt to write file that exceeds * maximum file size. * FILEIO_WRITE_ERROR_NOSPC when the device containing the file has no * room for the data. * FILEIO_WRITE_ERROR_DQUOT for attempts to write file that exceeds * user's disk quota. * FILEIO_ERROR for other errors: only '*actual_count' bytes have been * written for sure. * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Write(FileIODescriptor *fd, // IN: const void *bufIn, // IN: size_t requested, // IN: size_t *actual) // OUT: { const uint8 *buf = (const uint8 *)bufIn; size_t initial_requested; FileIOResult fret = FILEIO_SUCCESS; ASSERT(fd != NULL); VERIFY(requested < 0x80000000); initial_requested = requested; while (requested > 0) { ssize_t res; res = write(fd->posix, buf, requested); if (res == -1) { int error = errno; if (error == EINTR) { continue; } fret = FileIOErrno2Result(error); break; } buf += res; requested -= res; } if (actual) { *actual = initial_requested - requested; } return fret; } /* *---------------------------------------------------------------------- * * FileIO_Read -- * * Read from a file * * Results: * FILEIO_SUCCESS on success: '*actual_count' = 'requested' bytes have * been read. * FILEIO_READ_ERROR_EOF if the end of the file was reached: only * '*actual_count' bytes have been read for sure. * FILEIO_ERROR for other errors: only '*actual_count' bytes have been * read for sure. * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Read(FileIODescriptor *fd, // IN: void *bufIn, // OUT: size_t requested, // IN: size_t *actual) // OUT: { uint8 *buf = (uint8 *) bufIn; size_t initial_requested; FileIOResult fret = FILEIO_SUCCESS; ASSERT(fd != NULL); VERIFY(requested < 0x80000000); initial_requested = requested; while (requested > 0) { ssize_t res; res = read(fd->posix, buf, requested); if (res == -1) { if (errno == EINTR) { continue; } fret = FileIOErrno2Result(errno); break; } if (res == 0) { fret = FILEIO_READ_ERROR_EOF; break; } buf += res; requested -= res; } if (actual) { *actual = initial_requested - requested; } return fret; } /* *---------------------------------------------------------------------- * * FileIO_Truncate -- * * Truncates file to a given length * * Results: * Bool - TRUE on success, FALSE on failure * * Side effects: * None * *---------------------------------------------------------------------- */ Bool FileIO_Truncate(FileIODescriptor *file, // IN: uint64 newLength) // IN: { ASSERT(file != NULL); return ftruncate(file->posix, newLength) == 0; } /* *---------------------------------------------------------------------- * * FileIO_Close -- * * Close a file * * Results: * FILEIO_SUCCESS: The file was closed and unlinked. The FileIODescriptor * is no longer valid. * FILEIO_ERROR: An error occurred. * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Close(FileIODescriptor *file) // IN: { int err; ASSERT(file != NULL); err = (close(file->posix) == -1) ? errno : 0; /* Unlock the file if it was locked */ FileIO_Unlock(file); FileIO_Cleanup(file); FileIO_Invalidate(file); if (err) { errno = err; } return (err == 0) ? FILEIO_SUCCESS : FILEIO_ERROR; } /* *---------------------------------------------------------------------- * * FileIO_Sync -- * * Synchronize the disk state of a file with its memory state * * Results: * On success: FILEIO_SUCCESS * On failure: FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Sync(const FileIODescriptor *file) // IN: { ASSERT(file != NULL); return (fsync(file->posix) == -1) ? FILEIO_ERROR : FILEIO_SUCCESS; } /* *----------------------------------------------------------------------------- * * FileIOCoalesce -- * * Linux 2.2 does a fairly braindead thing with ioVec's. It simply issues * reads and writes internal to the kernel in serial * (linux/fs/read_write.c:do_readv_writev()). We optimize here for the * case of many small chunks. The cost of the extra copy in this case * is made up for by the decreased number of separate I/Os the kernel * issues internally. Note that linux 2.4 seems to be smarter with respect * to this problem. * * Results: * Bool - Whether or not coalescing was done. If it was done, * FileIODecoalesce *MUST* be called. * * Side effects: * FileIOCoalesce will malloc *outVec if coalescing is performed * *----------------------------------------------------------------------------- */ static Bool FileIOCoalesce( struct iovec const *inVec, // IN: Vector to coalesce from int inCount, // IN: count for inVec size_t inTotalSize, // IN: totalSize (bytes) in inVec Bool isWrite, // IN: coalesce for writing (or reading) Bool forceCoalesce, // IN: if TRUE always coalesce int flags, // IN: fileIO open flags struct iovec *outVec) // OUT: Coalesced (1-entry) iovec { uint8 *cBuf; ASSERT(inVec != NULL); ASSERT(outVec != NULL); FileIO_OptionalSafeInitialize(); /* simple case: no need to coalesce */ if (inCount == 1) { return FALSE; } /* * Only coalesce when the number of entries is above our count threshold * and the average size of an entry is less than our size threshold */ if (!forceCoalesce && (!filePosixOptions.enabled || inCount <= filePosixOptions.countThreshold || inTotalSize / inCount >= filePosixOptions.sizeThreshold)) { return FALSE; } // XXX: Wouldn't it be nice if we could log from here! //LOG(5, "FILE: Coalescing %s of %d elements and %d size\n", // isWrite ? "write" : "read", inCount, inTotalSize); if (filePosixOptions.aligned || flags & FILEIO_OPEN_UNBUFFERED) { cBuf = FileIOAligned_Malloc(sizeof(uint8) * inTotalSize); } else { cBuf = Util_SafeMalloc(sizeof(uint8) * inTotalSize); } if (!cBuf) { return FALSE; } if (isWrite) { IOV_WriteIovToBuf(inVec, inCount, cBuf, inTotalSize); } outVec->iov_base = cBuf; outVec->iov_len = inTotalSize; return TRUE; } /* *----------------------------------------------------------------------------- * * FileIODecoalesce -- * * Inverse of the coalesce optimization. For writes, its a NOOP, but * for reads, it copies the data back into the original buffer. * It also frees the memory allocated by FileIOCoalesce. * * Results: * void * * Side effects: * None * *----------------------------------------------------------------------------- */ static void FileIODecoalesce( struct iovec *coVec, // IN: Coalesced (1-entry) vector struct iovec const *origVec, // IN: Original vector int origVecCount, // IN: count for origVec size_t actualSize, // IN: # bytes to transfer back to origVec Bool isWrite, // IN: decoalesce for writing (or reading) int flags) // IN: fileIO open flags { ASSERT(coVec != NULL); ASSERT(origVec != NULL); ASSERT(actualSize <= coVec->iov_len); ASSERT_NOT_TESTED(actualSize == coVec->iov_len); if (!isWrite) { IOV_WriteBufToIov(coVec->iov_base, actualSize, origVec, origVecCount); } if (filePosixOptions.aligned || flags & FILEIO_OPEN_UNBUFFERED) { FileIOAligned_Free(coVec->iov_base); } else { Posix_Free(coVec->iov_base); } } /* *---------------------------------------------------------------------- * * FileIO_Readv -- * * Wrapper for readv. In linux, we can issue a readv directly. * But the readv is not atomic, i.e, the read can succeed * on the first N vectors, and return a positive value in spite * of the fact that there was an error on the N+1st vector. There * is no way to query the exact error that happened. So, we retry * in a loop (for a max of MAX_RWV_RETRIES). * XXX: If we retried MAX_RWV_RETRIES times and gave up, we will * return FILEIO_ERROR even if errno is undefined. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR, FILEIO_READ_ERROR_EOF * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Readv(FileIODescriptor *fd, // IN: struct iovec const *v, // IN: int numEntries, // IN: size_t totalSize, // IN: size_t *actual) // OUT: { size_t bytesRead = 0, sum = 0; FileIOResult fret = FILEIO_ERROR; int nRetries = 0, maxRetries = numEntries; struct iovec coV; struct iovec const *vPtr; Bool didCoalesce; int numVec; ASSERT(fd != NULL); didCoalesce = FileIOCoalesce(v, numEntries, totalSize, FALSE, FALSE, fd->flags, &coV); VERIFY(totalSize < 0x80000000); numVec = didCoalesce ? 1 : numEntries; vPtr = didCoalesce ? &coV : v; while (nRetries < maxRetries) { ssize_t retval; int tempVec = MIN(filePosixOptions.maxIOVec, numVec); ASSERT(tempVec > 0); retval = readv(fd->posix, vPtr, tempVec); if (retval == -1) { if (errno == EINTR) { continue; } fret = FileIOErrno2Result(errno); break; } bytesRead += retval; if (bytesRead == totalSize) { fret = FILEIO_SUCCESS; break; } if (retval == 0) { fret = FILEIO_READ_ERROR_EOF; break; } /* * Ambigous case. Stupid Linux. If the bytesRead matches an * exact iovector boundary, we need to retry from the next * iovec. 2) If it does not match, EOF is the only error possible. * NOTE: If Linux Readv implementation changes, this * ambiguity handling may need to change. * --Ganesh, 08/15/2001. */ for (; sum < bytesRead; vPtr++, numVec--) { sum += vPtr->iov_len; /* * In each syscall, we will process atleast one iovec * or get an error back. We will therefore retry atmost * count times. If multiple iovecs were processed before * an error hit, we will retry a lesser number of times. */ nRetries++; } if (sum > bytesRead) { // A partially filled iovec can ONLY mean EOF fret = FILEIO_READ_ERROR_EOF; break; } } if (didCoalesce) { FileIODecoalesce(&coV, v, numEntries, bytesRead, FALSE, fd->flags); } if (actual) { *actual = bytesRead; } return fret; } /* *---------------------------------------------------------------------- * * FileIO_Writev -- * * Wrapper for writev. In linux, we can issue a writev directly. * But the writev is not atomic, i.e, the write can succeed * on the first N vectors, and return a positive value in spite * of the fact that there was an error on the N+1st vector. There * is no way to query the exact error that happened. So, we retry * in a loop (for a max of MAX_RWV_RETRIES). * XXX: If we retried MAX_RWV_RETRIES times and gave up, we will * return FILEIO_ERROR even if errno is undefined. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Writev(FileIODescriptor *fd, // IN: struct iovec const *v, // IN: int numEntries, // IN: size_t totalSize, // IN: size_t *actual) // OUT: { size_t bytesWritten = 0, sum = 0; FileIOResult fret = FILEIO_ERROR; int nRetries = 0, maxRetries = numEntries; struct iovec coV; struct iovec const *vPtr; Bool didCoalesce; int numVec; ASSERT(fd != NULL); didCoalesce = FileIOCoalesce(v, numEntries, totalSize, TRUE, FALSE, fd->flags, &coV); VERIFY(totalSize < 0x80000000); numVec = didCoalesce ? 1 : numEntries; vPtr = didCoalesce ? &coV : v; while (nRetries < maxRetries) { ssize_t retval; int tempVec = MIN(filePosixOptions.maxIOVec, numVec); ASSERT(tempVec > 0); retval = writev(fd->posix, vPtr, tempVec); if (retval == -1) { if (errno == EINTR) { continue; } fret = FileIOErrno2Result(errno); break; } bytesWritten += retval; if (bytesWritten == totalSize) { fret = FILEIO_SUCCESS; break; } for (; sum < bytesWritten; vPtr++, numVec--) { sum += vPtr->iov_len; nRetries++; } /* * writev only seems to produce a partial iovec when the disk is * out of space. Just call it an error. --probin */ if (sum != bytesWritten) { fret = FILEIO_WRITE_ERROR_NOSPC; break; } } if (didCoalesce) { FileIODecoalesce(&coV, v, numEntries, bytesWritten, TRUE, fd->flags); } if (actual) { *actual = bytesWritten; } return fret; } #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||\ defined(__sun__) /* *---------------------------------------------------------------------- * * FileIOPreadvCoalesced -- * * This function implements vector pread for platforms that do not * support the preadv system call. The incoming vectors are * coalesced to a single buffer to issue only one pread() * system call which reads from a specified offset. The * vectors are then decoalesced before return. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ static FileIOResult FileIOPreadvCoalesced( FileIODescriptor *fd, // IN: File descriptor struct iovec const *entries, // IN: Vector to read into int numEntries, // IN: Number of vector entries uint64 offset, // IN: Offset to start reading size_t totalSize, // IN: totalSize(bytes) in entries size_t *actual) // OUT: number of bytes read { struct iovec const *vPtr; struct iovec coV; int count; uint64 fileOffset; FileIOResult fret; Bool didCoalesce; size_t sum = 0; didCoalesce = FileIOCoalesce(entries, numEntries, totalSize, FALSE, TRUE /* force coalescing */, fd->flags, &coV); count = didCoalesce ? 1 : numEntries; vPtr = didCoalesce ? &coV : entries; fileOffset = offset; while (count > 0) { size_t leftToRead = vPtr->iov_len; uint8 *buf = (uint8 *) vPtr->iov_base; while (leftToRead > 0) { ssize_t retval = pread(fd->posix, buf, leftToRead, fileOffset); if (retval == -1) { if (errno == EINTR) { continue; } fret = FileIOErrno2Result(errno); goto exit; } if (retval == 0) { fret = FILEIO_READ_ERROR_EOF; goto exit; } buf += retval; leftToRead -= retval; sum += retval; fileOffset += retval; } count--; vPtr++; } fret = FILEIO_SUCCESS; exit: if (didCoalesce) { FileIODecoalesce(&coV, entries, numEntries, sum, FALSE, fd->flags); } if (actual) { *actual = sum; } return fret; } /* *---------------------------------------------------------------------- * * FileIOPwritevCoalesced -- * * This function implements vector pwrite for platforms that do not * support the pwritev system call. The incoming vectors are * coalesced to a single buffer to issue only one pwrite() * system call which writes from a specified offset. The * vectors are then decoalesced before return. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ static FileIOResult FileIOPwritevCoalesced( FileIODescriptor *fd, // IN: File descriptor struct iovec const *entries, // IN: Vector to write from int numEntries, // IN: Number of vector entries uint64 offset, // IN: Offset to start writing size_t totalSize, // IN: Total size(bytes) size_t *actual) // OUT: number of bytes written { struct iovec coV; Bool didCoalesce; struct iovec const *vPtr; int count; uint64 fileOffset; FileIOResult fret; size_t sum = 0; didCoalesce = FileIOCoalesce(entries, numEntries, totalSize, TRUE, TRUE /* force coalescing */, fd->flags, &coV); count = didCoalesce ? 1 : numEntries; vPtr = didCoalesce ? &coV : entries; fileOffset = offset; while (count > 0) { size_t leftToWrite = vPtr->iov_len; uint8 *buf = (uint8 *)vPtr->iov_base; while (leftToWrite > 0) { ssize_t retval = pwrite(fd->posix, buf, leftToWrite, fileOffset); if (retval == -1) { if (errno == EINTR) { continue; } fret = FileIOErrno2Result(errno); goto exit; } if (retval == 0) { NOT_TESTED(); fret = FILEIO_WRITE_ERROR_NOSPC; goto exit; } if (retval < leftToWrite) { /* * Using %zd on Android generated a warning about * expecting a "signed size_t" argument; casting retval to * "signed size_t" generated an error, though. We've * already checked for retval == -1 above, so the cast * below should be OK. Refer to bug 817761. */ LOG_ONCE(LGPFX" %s wrote %"FMTSZ"u out of %"FMTSZ"u bytes.\n", __FUNCTION__, (size_t)retval, leftToWrite); } buf += retval; leftToWrite -= retval; sum += retval; fileOffset += retval; } count--; vPtr++; } fret = FILEIO_SUCCESS; exit: if (didCoalesce) { FileIODecoalesce(&coV, entries, numEntries, sum, TRUE, fd->flags); } if (actual) { *actual = sum; } return fret; } #endif /* defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__) */ #if defined(__linux__) && !defined(__ANDROID__) /* *---------------------------------------------------------------------- * * FileIOPreadvInternal -- * * This function implements vector pread for linux builds. Although, * support for preadv() first appeared in Linux 2.6.30, * library support was added in glibc 2.10. * Hence using weak linkage technique, we try to call the more * optimized preadv system call. If the system does not support * this, we fall back to earlier unoptimized technique. * * Note that in linux, preadv can succeed on the first N vectors, * and return a positive value in spite of the fact that there was * an error on the N+1st vector. There is no way to query the exact * error that happened. So, we retry in a loop (for a max of * MAX_RWV_RETRIES), same as FileIO_Readv(). * * XXX: If we retried MAX_RWV_RETRIES times and gave up, we will * return FILEIO_ERROR even if errno is undefined. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ static FileIOResult FileIOPreadvInternal( FileIODescriptor *fd, // IN: File descriptor struct iovec const *entries, // IN: Vector to read into int numEntries, // IN: Number of vector entries uint64 offset, // IN: Offset to start reading size_t totalSize, // IN: totalSize(bytes) in entries size_t *actual) // OUT: number of bytes read { struct iovec const *vPtr; int numVec; size_t partialBytes = 0; size_t bytesRead = 0; size_t sum = 0; int nRetries = 0; int maxRetries = numEntries; FileIOResult fret = FILEIO_ERROR; FileIO_OptionalSafeInitialize(); numVec = numEntries; vPtr = entries; while (nRetries < maxRetries) { ssize_t retval = 0; ASSERT(numVec > 0); /* * This is needed to deal with old libraries. Once we're over * the library horizon this can go away. */ /* coverity[func_conv] */ if (preadv64 == NULL) { fret = FileIOPreadvCoalesced(fd, entries, numEntries, offset, totalSize, &bytesRead); break; } else { int tempVec = MIN(filePosixOptions.maxIOVec, numVec); retval = preadv64(fd->posix, vPtr, tempVec, offset); } if (retval == -1) { if (errno == EINTR) { continue; } if (errno == ENOSYS || errno == EINVAL || errno == ENOMEM) { /* * ENOSYS is returned when the kernel does not support preadv and * will be returned the first time we ever call preadv. So, we * can assume that we are not reading partial requests here. * ENOMEM can be due to system call failure and EINVAL is when file * was opened with the O_DIRECT flag and memory is not suitably * aligned. Let's try to read the remaining vectors using the * unoptimized function and hope we don't encounter another error. */ size_t remSize = totalSize - bytesRead; uint64 tempOffset = offset + bytesRead; partialBytes = 0; fret = FileIOPreadvCoalesced(fd, vPtr, numVec, tempOffset, remSize, &partialBytes); break; } fret = FileIOErrno2Result(errno); break; } bytesRead += retval; if (bytesRead == totalSize) { fret = FILEIO_SUCCESS; break; } if (retval == 0) { fret = FILEIO_READ_ERROR_EOF; break; } /* * This is an ambiguous case in linux preadv implementation. * If the bytesRead matches an exact iovector boundary, we need * to retry from the next iovec. However, if it does not match, * EOF is the only error possible. Linux 3.4.4 continues to have * this behaviour. * NOTE: If Linux preadv implementation changes, this * ambiguity handling may need to change. */ for (; sum < bytesRead; vPtr++, numVec--) { sum += vPtr->iov_len; offset += vPtr->iov_len; /* * In each syscall, we will process atleast one iovec * or get an error back. We will therefore retry at most * count times. If multiple iovecs were processed before * an error hit, we will retry a lesser number of times. */ nRetries++; } if (sum > bytesRead) { // A partially filled iovec can ONLY mean EOF fret = FILEIO_READ_ERROR_EOF; break; } } if (actual) { *actual = bytesRead + partialBytes; } return fret; } /* *---------------------------------------------------------------------- * * FileIOPwritevInternal -- * * This function implements vector pwrite for linux builds. Although, * support for pwritev() first appeared in Linux 2.6.30, library * support was added in glibc 2.10. * Hence using weak linkage technique, we try to call the more * optimized pwritev system call. If the system does not support * this, we fall back to earlier unoptimized technique. * * Note that in linux, pwritev can succeed on the first N vectors, * and return a positive value in spite of the fact that there was * an error on the N+1st vector. There is no way to query the exact * error that happened. So, we retry in a loop (for a max of * MAX_RWV_RETRIES), same as FileIO_Writev(). * * XXX: If we retried MAX_RWV_RETRIES times and gave up, we will * return FILEIO_ERROR even if errno is undefined. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ static FileIOResult FileIOPwritevInternal( FileIODescriptor *fd, // IN: File descriptor struct iovec const *entries, // IN: Vector to write from int numEntries, // IN: Number of vector entries uint64 offset, // IN: Offset to start writing size_t totalSize, // IN: Total size(bytes)in entries size_t *actual) // OUT: number of bytes written { struct iovec const *vPtr; int numVec; size_t partialBytes = 0; size_t bytesWritten = 0; size_t sum = 0; int nRetries = 0; int maxRetries = numEntries; FileIOResult fret = FILEIO_ERROR; FileIO_OptionalSafeInitialize(); numVec = numEntries; vPtr = entries; while (nRetries < maxRetries) { ssize_t retval = 0; ASSERT(numVec > 0); /* * This is needed to deal with old libraries. Once we're over * the library horizon this can go away. */ /* coverity[func_conv] */ if (pwritev64 == NULL) { fret = FileIOPwritevCoalesced(fd, entries, numEntries, offset, totalSize, &bytesWritten); break; } else { int tempVec = MIN(filePosixOptions.maxIOVec, numVec); retval = pwritev64(fd->posix, vPtr, tempVec, offset); } if (retval == -1) { if (errno == EINTR) { continue; } if (errno == ENOSYS || errno == EINVAL || errno == ENOMEM) { /* * ENOSYS is returned when the kernel does not support pwritev and * will be returned the first time we ever call pwritev. So, we * can assume that we are not writing partial requests here. * ENOMEM can be due to system call failure and EINVAL is when file * was opened with the O_DIRECT flag and memory is not suitably * aligned. Let's try writing the remaining vectors using the * unoptimized function and hope we don't encounter another error. */ size_t remSize = totalSize - bytesWritten; uint64 tempOffset = offset + bytesWritten; partialBytes = 0; fret = FileIOPwritevCoalesced(fd, vPtr, numVec, tempOffset, remSize, &partialBytes); break; } fret = FileIOErrno2Result(errno); break; } bytesWritten += retval; if (bytesWritten == totalSize) { fret = FILEIO_SUCCESS; break; } for (; sum < bytesWritten; vPtr++, numVec--) { sum += vPtr->iov_len; offset += vPtr->iov_len; nRetries++; } /* * pwritev produces a partial iovec when the disk is * out of space. Just call it an error. */ if (sum != bytesWritten) { fret = FILEIO_WRITE_ERROR_NOSPC; break; } } if (actual) { *actual = bytesWritten + partialBytes; } return fret; } #endif /* defined(__linux__) && !defined(__ANDROID__) */ #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||\ defined(__sun__) /* *---------------------------------------------------------------------- * * FileIO_Preadv -- * * Implementation of vector pread. The function checks for the support * of system call preadv with the version of glibc and calls the * optimized system call. If the system call is not supported, * we fall back to the earlier technique of coalescing the vectors * and calling a single pread and decoalescing again. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Preadv(FileIODescriptor *fd, // IN: File descriptor struct iovec const *entries, // IN: Vector to read into int numEntries, // IN: Number of vector entries uint64 offset, // IN: Offset to start reading size_t totalSize, // IN: totalSize (bytes) in entries size_t *actual) // OUT: number of bytes read { FileIOResult fret; ASSERT(fd != NULL); ASSERT(entries != NULL); ASSERT(!(fd->flags & FILEIO_ASYNCHRONOUS)); VERIFY(totalSize < 0x80000000); #if defined(__linux__) && !defined(__ANDROID__) fret = FileIOPreadvInternal(fd, entries, numEntries, offset, totalSize, actual); #else fret = FileIOPreadvCoalesced(fd, entries, numEntries, offset, totalSize, actual); #endif /* defined(__linux__ ) && !defined(__ANDROID__) */ return fret; } /* *---------------------------------------------------------------------- * * FileIO_Pwritev -- * * Implementation of vector pwrite. The function checks for the support * of system call pwritev with the version of glibc and calls the * optimized system call. If the system call is not supported, * we fall back to the earlier technique of coalescing the vectors and * calling a single pread and decoalescing again. * * Results: * FILEIO_SUCCESS, FILEIO_ERROR * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_Pwritev(FileIODescriptor *fd, // IN: File descriptor struct iovec const *entries, // IN: Vector to write from int numEntries, // IN: Number of vector entries uint64 offset, // IN: Offset to start writing size_t totalSize, // IN: Total size (bytes) in entries size_t *actual) // OUT: number of bytes written { FileIOResult fret; ASSERT(fd != NULL); ASSERT(entries != NULL); ASSERT(!(fd->flags & FILEIO_ASYNCHRONOUS)); VERIFY(totalSize < 0x80000000); #if defined(__linux__) && !defined(__ANDROID__) fret = FileIOPwritevInternal(fd, entries, numEntries, offset, totalSize, actual); #else fret = FileIOPwritevCoalesced(fd, entries, numEntries, offset, totalSize, actual); #endif /* defined(__linux__ ) && !defined(__ANDROID__) */ return fret; } #endif /* defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__) */ /* *---------------------------------------------------------------------- * * FileIO_GetAllocSize -- * * Get logcial and alloced size of a file. * * Results: * FileIOResult. * * Side effects: * None * *---------------------------------------------------------------------- */ FileIOResult FileIO_GetAllocSize(const FileIODescriptor *fd, // IN: uint64 *logicalBytes, // OUT: uint64 *allocedBytes) // OUT: { struct stat statBuf; ASSERT(fd != NULL); if (fstat(fd->posix, &statBuf) == -1) { return FileIOErrno2Result(errno); } if (logicalBytes) { *logicalBytes = statBuf.st_size; } if (allocedBytes) { /* * If you don't like the magic number 512, yell at the people * who wrote sys/stat.h and tell them to add a #define for it. */ *allocedBytes = statBuf.st_blocks * 512; } return FILEIO_SUCCESS; } /* *---------------------------------------------------------------------- * * FileIO_SetAllocSize -- * * Set allocated size of file, allocating new blocks if needed. * It is an error for size to be less than the current size. * * Results: * TRUE on success. Sets errno on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool FileIO_SetAllocSize(const FileIODescriptor *fd, // IN: uint64 size) // IN: { #if defined(__APPLE__) || defined(__linux__) FileIOResult fret; uint64 curSize; uint64 preallocLen; #if defined(__APPLE__) fstore_t prealloc; #endif fret = FileIO_GetAllocSize(fd, NULL, &curSize); if (!FileIO_IsSuccess(fret)) { return FALSE; } if (curSize > size) { errno = EINVAL; return FALSE; } preallocLen = size - curSize; #if defined(__APPLE__) prealloc.fst_flags = 0; prealloc.fst_posmode = F_PEOFPOSMODE; prealloc.fst_offset = 0; prealloc.fst_length = preallocLen; prealloc.fst_bytesalloc = 0; return fcntl(fd->posix, F_PREALLOCATE, &prealloc) != -1; #elif __linux__ return syscall(SYS_fallocate, fd->posix, FALLOC_FL_KEEP_SIZE, curSize, preallocLen) == 0; #endif #else errno = ENOSYS; return FALSE; #endif } /* *---------------------------------------------------------------------- * * FileIO_GetAllocSizeByPath -- * * Get the logcial and alloced size of a file specified by path. * * Results: * FileIOResult. * * Side effects: * errno is set on error * *---------------------------------------------------------------------- */ FileIOResult FileIO_GetAllocSizeByPath(const char *pathName, // IN: uint64 *logicalBytes, // OUT: uint64 *allocedBytes) // OUT: { struct stat statBuf; if (Posix_Stat(pathName, &statBuf) == -1) { return FileIOErrno2Result(errno); } if (logicalBytes) { *logicalBytes = statBuf.st_size; } if (allocedBytes) { /* * If you don't like the magic number 512, yell at the people * who wrote sys/stat.h and tell them to add a #define for it. */ *allocedBytes = statBuf.st_blocks * 512; } return FILEIO_SUCCESS; } /* *---------------------------------------------------------------------- * * FileIO_Access -- * * Wrapper for access syscall. We return FILEIO_SUCCESS if the file * is accessible with the specified mode. If not, we will return * FILEIO_ERROR. * * Results: * FILEIO_SUCCESS or FILEIO_ERROR. * * Side effects: * errno is set on error * *---------------------------------------------------------------------- */ FileIOResult FileIO_Access(const char *pathName, // IN: Path name. May be NULL. int accessMode) // IN: Access modes to be asserted { int mode = 0; if (pathName == NULL) { errno = EFAULT; return FILEIO_ERROR; } if (accessMode & FILEIO_ACCESS_READ) { mode |= R_OK; } if (accessMode & FILEIO_ACCESS_WRITE) { mode |= W_OK; } if (accessMode & FILEIO_ACCESS_EXEC) { mode |= X_OK; } if (accessMode & FILEIO_ACCESS_EXISTS) { mode |= F_OK; } return (Posix_Access(pathName, mode) == -1) ? FILEIO_ERROR : FILEIO_SUCCESS; } /* *---------------------------------------------------------------------- * * FileIO_GetFlags -- * * Accessor for fd->flags; * * Results: * fd->flags * * Side Effects: * None * *---------------------------------------------------------------------- */ uint32 FileIO_GetFlags(FileIODescriptor *fd) // IN: { ASSERT(fd != NULL); ASSERT(FileIO_IsValid(fd)); return fd->flags; } /* *---------------------------------------------------------------------- * * FileIO_SupportsFileSize -- * * Test whether underlying filesystem supports specified file size. * * Results: * Return TRUE if such file size is supported, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool FileIO_SupportsFileSize(const FileIODescriptor *fd, // IN: uint64 requestedSize) // IN: { #ifdef VMX86_SERVER // PR 93215: Use VMkernel-specific logic. uint64 maxFileSize; if (ioctl(fd->posix, IOCTLCMD_VMFS_GET_MAX_FILE_SIZE, &maxFileSize) == -1) { Log(LGPFX" %s: Could not get max file size for fd: %d, error: %s\n", __func__, fd->posix, Err_Errno2String(errno)); return FALSE; } return requestedSize <= maxFileSize; #elif defined(__linux__) /* * Linux makes test on seek(), so we can do simple non-intrusive test. * Verified to work on 2.2.x, 2.4.x and 2.6.x, with ext2, ext3, smbfs, * cifs, nfs and ncpfs. Always got some reasonable value. */ Bool supported = FALSE; uint64 oldPos; ASSERT(FileIO_IsValid(fd)); oldPos = FileIO_Seek(fd, 0, FILEIO_SEEK_CURRENT); if (oldPos != (uint64)-1) { uint64 newPos; if (FileIO_Seek(fd, requestedSize, FILEIO_SEEK_BEGIN) == requestedSize) { supported = TRUE; } newPos = FileIO_Seek(fd, oldPos, FILEIO_SEEK_BEGIN); VERIFY(oldPos == newPos); } return supported; #elif defined(__APPLE__) struct statfs buf; if (fstatfs(fd->posix, &buf) == -1) { Log(LGPFX" %s fstatfs failure: %s\n", __FUNCTION__, Err_Errno2String(errno)); /* Be optimistic despite failure */ return TRUE; } /* Check for FAT and UFS file systems */ if ((Str_Strcasecmp(buf.f_fstypename, "msdos") == 0) || (Str_Strcasecmp(buf.f_fstypename, "ufs") == 0)) { /* 4 GB limit */ return requestedSize > CONST64U(0xFFFFFFFF) ? FALSE : TRUE; } /* Be optimistic... */ return TRUE; #else /* Be optimistic on FreeBSD and Solaris... */ return TRUE; #endif } /* *---------------------------------------------------------------------- * * FileIO_GetModTime -- * * Retrieve last modification time. * * Results: * Return POSIX epoch time or -1 on error. * * Side effects: * None. * *---------------------------------------------------------------------- */ int64 FileIO_GetModTime(const FileIODescriptor *fd) // IN: { struct stat statbuf; if (fstat(fd->posix, &statbuf) == 0) { return statbuf.st_mtime; } else { return -1; } } /* *---------------------------------------------------------------------- * * FileIO_PrivilegedPosixOpen -- * * Opens file with elevated privileges. * * Results: * Opened file descriptor, or -1 on failure (errno contains error code). * * Side effects: * None. * *---------------------------------------------------------------------- */ int FileIO_PrivilegedPosixOpen(const char *pathName, // IN: int flags) // IN: { int fd; if (pathName == NULL) { errno = EFAULT; return -1; } /* * I've said *opens*. I want you really think twice before creating files * with elevated privileges, so for them you have to use Id_BeginSuperUser() * yourself. */ ASSERT((flags & (O_CREAT | O_TRUNC)) == 0); #if defined(__APPLE__) if (privilegedOpenerFunc != NULL) { fd = (*privilegedOpenerFunc)(pathName, flags); } else #endif { Bool suDone; uid_t uid = -1; if (Id_IsSuperUser()) { suDone = FALSE; } else { uid = Id_BeginSuperUser(); suDone = TRUE; } fd = Posix_Open(pathName, flags, 0); if (suDone) { int error = errno; Id_EndSuperUser(uid); errno = error; } } return fd; } /* *----------------------------------------------------------------------------- * * FileIO_DescriptorToStream * * Return a FILE * stream equivalent to the given FileIODescriptor. * This is the logical equivalent of Posix dup() then fdopen(). * * Caller should fclose the returned descriptor when finished. * * Results: * !NULL A FILE * associated with the file associated with the fd * NULL Failure * * Side effects: * New fd allocated. * *----------------------------------------------------------------------------- */ FILE * FileIO_DescriptorToStream(FileIODescriptor *fdesc, // IN: Bool textMode) // IN: unused { int dupFD; const char *mode; int tmpFlags; FILE *stream; dupFD = dup(fdesc->posix); if (dupFD == -1) { return NULL; } /* The file you pass us should be valid and opened for *something* */ ASSERT(FileIO_IsValid(fdesc)); ASSERT((fdesc->flags & (FILEIO_OPEN_ACCESS_READ | FILEIO_OPEN_ACCESS_WRITE)) != 0); tmpFlags = fdesc->flags & (FILEIO_OPEN_ACCESS_READ | FILEIO_OPEN_ACCESS_WRITE); if (tmpFlags == (FILEIO_OPEN_ACCESS_READ | FILEIO_OPEN_ACCESS_WRITE)) { mode = "r+"; } else if (tmpFlags == FILEIO_OPEN_ACCESS_WRITE) { mode = "w"; } else { /* therefore (tmpFlags == FILEIO_OPEN_ACCESS_READ) */ mode = "r"; } stream = fdopen(dupFD, mode); if (stream == NULL) { close(dupFD); } return stream; } #if defined(__APPLE__) /* *---------------------------------------------------------------------- * * HostSupportsPrealloc -- * * Returns TRUE if the host OS is new enough to support F_PREALLOCATE * without data loss bugs. On OSX, this has been verified fixed * on 10.6 build with kern.osrelease 10.0.0d6. * * Results: * TRUE if the current host OS is new enough. * FALSE if it is not or we can't tell because of an error. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Bool HostSupportsPrealloc(void) { static Atomic_uint32 supported = { 0 }; enum { PREALLOC_UNKNOWN = 0, PREALLOC_YES, PREALLOC_NO } val; char curRel[32]; char type; unsigned static const int req[] = { 10, 0, 0, 6 }; unsigned int cur[4], i; int num; size_t len = sizeof curRel; Bool ret = FALSE; val = Atomic_Read(&supported); if (val != PREALLOC_UNKNOWN) { return val == PREALLOC_YES; } if (sysctlbyname("kern.osrelease", (void *) &curRel, &len, NULL, 0) == -1) { goto exit; } curRel[31] = '\0'; Log("Current OS Release is %s\n", curRel); /* * Apple's osversion is in the format X.Y.Z which maps to the public * OSX version 10.X-4.Y, and Z is incremented for each publicly * released build. The Z part is of the form AB, where a and * B are version numbers and is either d (devel), a (alpha), * b (beta), rc, or fc. If the B is missing, then its a GA build. * * Since we're checking for 10.0.0d6, we can just say anything without * a type or with a type other than d is higher. For d, we compare * the last number. */ num = sscanf(curRel, "%u.%u.%u%c%u", &cur[0], &cur[1], &cur[2], &type, &cur[3]); if (num < 3) { goto exit; } for (i = 0; i < 3; i++) { if (req[i] > cur[i]) { goto exit; } else if (req[i] < cur[i]) { ret = TRUE; goto exit; } } if (num == 5 && type == 'd') { ret = req[3] <= cur[3]; goto exit; } /* * If we get a type with no letter (num == 4), thats odd. * Consider it mal-formatted and fail. */ ret = num != 4; exit: if (!ret && filePosixOptions.initialized && filePosixOptions.aioNumThreads == 1) { ret = TRUE; } Atomic_Write(&supported, ret ? PREALLOC_YES : PREALLOC_NO); return ret; } #else /* *---------------------------------------------------------------------- * * HostSupportsPrealloc -- * * fallocate() is supported for ext4 and xfs since 2.6.23 kernels * * Results: * TRUE if the current host is linux and kernel is >= 2.6.23. * FALSE if it is not . * * Side effects: * None. * *---------------------------------------------------------------------- */ static Bool HostSupportsPrealloc(void) { #if (defined(__linux__ ) && !defined(VMX86_SERVER)) if (Hostinfo_OSVersion(0) >=2 && Hostinfo_OSVersion(1) >=6 && Hostinfo_OSVersion(2) >=23) { return TRUE; } #endif return FALSE; } #endif /* *---------------------------------------------------------------------------- * * FileIO_SupportsPrealloc -- * * Checks if the HostOS/filesystem supports preallocation. * * Results: * TRUE if supported by the Host OS/filesystem. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool FileIO_SupportsPrealloc(const char *pathName, // IN: Bool fsCheck) // IN: { Bool ret = TRUE; if (!HostSupportsPrealloc()) { return FALSE; } if (!fsCheck) { return ret; } #if (defined( __linux__) && !defined(VMX86_SERVER)) { struct statfs statBuf; char *fullPath; ret = FALSE; if (!pathName) { return ret; } fullPath = File_FullPath(pathName); if (!fullPath) { return ret; } if (Posix_Statfs(fullPath, &statBuf) == 0 && statBuf.f_type == EXT4_SUPER_MAGIC) { ret = TRUE; } Posix_Free(fullPath); } #endif return ret; } /* * The FileIOAligned_* functions are only used on * hosted (see fileInt.h for rationale). */ #if !defined(VMX86_TOOLS) && !defined(VMX86_SERVER) /* *--------------------------------------------------------------------------- * * FileIOAligned_PoolInit -- * * Initialize alignedPool. Must be called before FileIOAligned_PoolMalloc. * * Result: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void FileIOAligned_PoolInit(void) { alignedPool.lock = MXUser_CreateSingletonExclLock(&alignedPoolLockStorage, "alignedPoolLock", RANK_LEAF); } /* *--------------------------------------------------------------------------- * * FileIOAligned_PoolExit -- * * Tear down alignedPool. Afterwards, PoolInit can be called again if * desired. * * Result: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void FileIOAligned_PoolExit(void) { if (!alignedPool.lock) { LOG_ONCE("%s called without FileIOAligned_Pool lock\n", __FUNCTION__); return; } MXUser_AcquireExclLock(alignedPool.lock); if (alignedPool.numBusy > 0) { LOG_ONCE("%s: %d busy buffers! Proceeding with trepidation.\n", __FUNCTION__, alignedPool.numBusy); } while (alignedPool.numAlloc > 0) { alignedPool.numAlloc--; Aligned_Free(alignedPool.list[alignedPool.numAlloc]); } MXUser_ReleaseExclLock(alignedPool.lock); MXUser_DestroyExclLock(alignedPool.lock); memset(&alignedPool, 0, sizeof alignedPool); } /* *--------------------------------------------------------------------------- * * FileIOAligned_PoolMalloc -- * * Alloc a chunk of memory aligned on a page boundary using a memory * pool. Result needs to be freed with FileIOAligned_PoolFree. Returns * NULL if the pool is full or the requested size cannot be satisfied from * the pool. * * Result: * A pointer. NULL if requested size is too large, or on out of memory * condition. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void * FileIOAligned_PoolMalloc(size_t size) // IN: { void *buf = NULL; if (!alignedPool.lock) { LOG_ONCE("%s called without FileIOAligned_Pool lock\n", __FUNCTION__); return NULL; } if (size > ALIGNEDPOOL_BUFSZ) { return NULL; } MXUser_AcquireExclLock(alignedPool.lock); ASSERT(alignedPool.numBusy <= ARRAYSIZE(alignedPool.list)); ASSERT(alignedPool.numAlloc <= ARRAYSIZE(alignedPool.list)); ASSERT(alignedPool.numBusy <= alignedPool.numAlloc); if (alignedPool.numBusy == ARRAYSIZE(alignedPool.list)) { goto done; } if (alignedPool.numBusy == alignedPool.numAlloc) { buf = Aligned_UnsafeMalloc(ALIGNEDPOOL_BUFSZ); /* If allocation fails, just bail. */ if (buf) { alignedPool.list[alignedPool.numAlloc] = buf; alignedPool.numBusy = ++alignedPool.numAlloc; } goto done; } buf = alignedPool.list[alignedPool.numBusy]; alignedPool.numBusy++; done: MXUser_ReleaseExclLock(alignedPool.lock); return buf; } /* *--------------------------------------------------------------------------- * * FileIOAligned_PoolFree -- * * Test if a pointer was allocated from alignedPool, and if so, free it. * * Result: * TRUE if ptr was allocated from alignedPool. ptr is returned to pool. * FALSE otherwise. * * Side effects: * Might Aligned_Free() some entries from alignedPool if the timestamp[] * entries indicate that we have not needed them for a while. * *--------------------------------------------------------------------------- */ Bool FileIOAligned_PoolFree(void *ptr) // IN: { unsigned i; Bool ret = FALSE; VmTimeType now; if (!alignedPool.lock) { LOG_ONCE("%s called without FileIOAligned_Pool lock\n", __FUNCTION__); return FALSE; } MXUser_AcquireExclLock(alignedPool.lock); ASSERT(alignedPool.numBusy <= ARRAYSIZE(alignedPool.list)); ASSERT(alignedPool.numAlloc <= ARRAYSIZE(alignedPool.list)); ASSERT(alignedPool.numBusy <= alignedPool.numAlloc); for (i = 0; i < alignedPool.numBusy; i++) { if (alignedPool.list[i] == ptr) { break; } } if (i == alignedPool.numBusy) { /* The pointer wasn't allocated from our pool. */ goto done; } alignedPool.numBusy--; /* * At this point either i points to the "top" busy item, or i points to an * earlier busy item. If i points to the top, we're done, and the following * "swap" is a noop. If i points somewhere further down the busy list, we * can simply move the newly freed item to the top of the free list by * swapping its place with the not-freed item at list[numBusy]. */ alignedPool.list[i] = alignedPool.list[alignedPool.numBusy]; alignedPool.list[alignedPool.numBusy] = ptr; now = Hostinfo_SystemTimerNS(); alignedPool.timestamp[alignedPool.numBusy] = now; while (alignedPool.numAlloc > alignedPool.numBusy && now - alignedPool.timestamp[alignedPool.numAlloc - 1] > ALIGNEDPOOL_OLD_AGE) { alignedPool.numAlloc--; Aligned_Free(alignedPool.list[alignedPool.numAlloc]); alignedPool.list[alignedPool.numAlloc] = NULL; } ret = TRUE; done: MXUser_ReleaseExclLock(alignedPool.lock); return ret; } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/fileInt.h000066400000000000000000000232421470176644300235540ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2019, 2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * fileInt.h -- * * Things internal to the file library. */ #if !defined(__FILE_INTERNAL_H__) #define __FILE_INTERNAL_H__ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #include "err.h" #include "posix.h" #include "file.h" #include "fileIO.h" #include "fileLock.h" #include "unicodeTypes.h" #include "memaligned.h" /* * Max supported file size is 64 TB. */ #define MAX_SUPPORTED_FILE_SIZE CONST64U(0x400000000000) #if defined __linux__ /* * These magic constants are used only for parsing Linux statfs data. * So they make sense only for Linux build. If you need them on other OSes, * think once more. */ #define HFSPLUS_SUPER_MAGIC 0x482B #if !defined(__ANDROID__) #define ADFS_SUPER_MAGIC 0xadf5 #define AFFS_SUPER_MAGIC 0xADFF #define EXT_SUPER_MAGIC 0x137D #define EXT2_OLD_SUPER_MAGIC 0xEF51 #define EXT2_SUPER_MAGIC 0xEF53 #define EXT3_SUPER_MAGIC 0xEF53 #define EXT4_SUPER_MAGIC 0xEF53 #define NFS_SUPER_MAGIC 0x6969 #define SMB_SUPER_MAGIC 0x517B #define ISOFS_SUPER_MAGIC 0x9660 #define JFFS2_SUPER_MAGIC 0x72b6 #define PROC_SUPER_MAGIC 0x9fa0 #define OPENPROM_SUPER_MAGIC 0x9fa1 #define USBDEVICE_SUPER_MAGIC 0x9fa2 #define AUTOFS_SUPER_MAGIC 0x0187 #endif #if !defined(MSDOS_SUPER_MAGIC) #define MSDOS_SUPER_MAGIC 0x4D44 #endif #define XENIX_SUPER_MAGIC 0x012FF7B4 #define SYSV4_SUPER_MAGIC 0x012FF7B5 #define SYSV2_SUPER_MAGIC 0x012FF7B6 #define COH_SUPER_MAGIC 0x012FF7B7 #define UFS_SUPER_MAGIC 0x00011954 #define XFS_SUPER_MAGIC 0x58465342 #define VMFS_SUPER_MAGIC 0x2fABF15E #define TMPFS_SUPER_MAGIC 0x01021994 #define JFS_SUPER_MAGIC 0x3153464a #define AFS_SUPER_MAGIC 0x5346414F #define CIFS_SUPER_MAGIC 0xFF534D42 #if !defined(REISERFS_SUPER_MAGIC) #define REISERFS_SUPER_MAGIC 0x52654973 #endif #endif // linux #define LGPFX "FILE:" #define FILE_TYPE_REGULAR 0 #define FILE_TYPE_DIRECTORY 1 #define FILE_TYPE_BLOCKDEVICE 2 #define FILE_TYPE_CHARDEVICE 3 #define FILE_TYPE_SYMLINK 4 #define FILE_TYPE_FIFO 5 #define FILE_TYPE_SOCKET 6 #define FILE_TYPE_UNCERTAIN 7 typedef struct FileData { uint64 fileAccessTime; uint64 fileCreationTime; uint64 fileModificationTime; uint64 fileSize; int fileType; int fileMode; int fileOwner; int fileGroup; } FileData; #define FILE_MAX_WAIT_TIME_MS 2000 // maximum wait time in milliseconds void FileIOResolveLockBits(int *access); #if defined(_WIN32) int FileMapErrorToErrno(const char *functionName, Err_Number status); Bool FileRetryThisError(DWORD error, uint32 numCodes, DWORD *codes); int FileAttributesRetry(const char *pathName, uint32 maxWaitTimeMsec, FileData *fileData); int FileDeletionRetry(const char *pathName, Bool handleLink, uint32 maxWaitTimeMsec); int FileCreateDirectoryRetry(const char *pathName, int mask, uint32 maxWaitTimeMsec); int FileRemoveDirectoryRetry(const char *pathName, uint32 maxWaitTimeMsec); int FileListDirectoryRetry(const char *pathName, uint32 maxWaitTimeMsec, char ***ids); #define FileAttributes(a, b) FileAttributesRetry((a), 0, (b)) #define FileDeletion(a, b) FileDeletionRetry((a), (b), 0) #define FileCreateDirectory(a, b) FileCreateDirectoryRetry((a), (b), 0) #define FileRemoveDirectory(a) FileRemoveDirectoryRetry((a), 0) #define FileListDirectoryRobust(a, b) \ FileListDirectoryRetry((a), FILE_MAX_WAIT_TIME_MS, (b)) #define FileAttributesRobust(a, b) \ FileAttributesRetry((a), FILE_MAX_WAIT_TIME_MS, (b)) #define FileRenameRobust(a, b) \ File_RenameRetry((a), (b), FILE_MAX_WAIT_TIME_MS) #define FileDeletionRobust(a, b) \ FileDeletionRetry((a), (b), FILE_MAX_WAIT_TIME_MS) #define FileCreateDirectoryRobust(a, b) \ FileCreateDirectoryRetry((a), (b), FILE_MAX_WAIT_TIME_MS) #define FileRemoveDirectoryRobust(a) \ FileRemoveDirectoryRetry((a), FILE_MAX_WAIT_TIME_MS) #else static INLINE int FileMapErrorToErrno(const char *functionName, Err_Number status) { return status; } char *FilePosixGetBlockDevice(char const *path); int FileAttributes(const char *pathName, FileData *fileData); int FileDeletion(const char *pathName, Bool handleLink); int FileCreateDirectory(const char *pathName, int mask); int FileRemoveDirectory(const char *pathName); #define FileListDirectoryRobust(a, b) File_ListDirectory((a), (b)) #define FileAttributesRobust(a, b) FileAttributes((a), (b)) #define FileRenameRobust(a, b) File_Rename((a), (b)) #define FileDeletionRobust(a, b) FileDeletion((a), (b)) #define FileCreateDirectoryRobust(a, b) FileCreateDirectory((a), (b)) #define FileRemoveDirectoryRobust(a) FileRemoveDirectory((a)) #endif typedef struct active_lock { struct active_lock *next; uint32 age; Bool marked; char *dirName; } ActiveLock; typedef struct lock_values { char *machineID; char *executionID; const char *lockType; char *locationChecksum; char *memberName; unsigned int lamportNumber; Bool exclusivity; VmTimeType startTimeMsec; uint32 maxWaitTimeMsec; ActiveLock *lockList; } LockValues; #include "file_extensions.h" #define FILELOCK_SUFFIX "." LOCK_FILE_EXTENSION #define FILELOCK_DATA_SIZE 512 uint32 FileSleeper(uint32 minSleepTimeMsec, uint32 maxSleepTimeMsec); uint32 FileSimpleRandom(void); const char *FileLockGetMachineID(void); char *FileLockGetExecutionID(void); Bool FileLockMachineIDMatch(const char *host, const char *second); int FileLockMemberValues(const char *lockDir, const char *fileName, char *buffer, size_t size, LockValues *memberValues); FileLockToken *FileLockIntrinsic(const char *filePathName, Bool exclusivity, uint32 maxWaitTimeMsec, int *err); int FileUnlockIntrinsic(FileLockToken *tokenPtr); Bool FileLockIsLocked(const char *filePath, int *err); Bool FileLockValidExecutionID(const char *executionID); Bool FileLockValidName(const char *fileName); void FileLockAppendMessage(MsgList **msgs, int err); Bool FileIsWritableDir(const char *dirName); FileIOResult FileIOCreateRetry(FileIODescriptor *fd, const char *pathName, int access, FileIOOpenAction action, int mode, uint32 maxWaitTimeMsec); /* * FileIOAligned_* are useful on hosted platforms where malloc/memalign/valloc * for "large buffers" (in the range 64 KiB - 1 MiB) will generally fall * through to mmap/munmap, which is expensive due to page table modifications * and the attendant TLB flushing (which requires IPIs and possibly world * switches) on other threads running in the same address space. In particular, * on Mac OS 10.6.6 on a Westmere-class Mac Pro, mmap + memcpy + munmap adds * around a millisecond of CPU time and a hundred IPIs to a 512 KiB write. See * PR#685845. * * This isn't applicable to ESX because * 1. we don't use this path for disk IO * 2. we don't want to do extra large allocations * 3. we don't have the same alignment constraints * so simply define it away to nothing. * * Tools is another case, we can use this path for IO but we don't want to add * MXUserExclLock dependencies. */ #if defined(VMX86_TOOLS) || defined(VMX86_SERVER) #define FileIOAligned_PoolInit() /* nothing */ #define FileIOAligned_PoolExit() /* nothing */ #define FileIOAligned_PoolMalloc(sz) NULL #define FileIOAligned_PoolFree(ptr) FALSE #else void FileIOAligned_PoolInit(void); void FileIOAligned_PoolExit(void); void *FileIOAligned_PoolMalloc(size_t); Bool FileIOAligned_PoolFree(void *); #endif static INLINE void * FileIOAligned_Malloc(size_t sz) // IN: { void *buf = FileIOAligned_PoolMalloc(sz); if (!buf) { buf = Aligned_Malloc(sz); } return buf; } static INLINE void FileIOAligned_Free(void *ptr) // IN: { if (!FileIOAligned_PoolFree(ptr)) { Aligned_Free(ptr); } } #if defined(__APPLE__) int PosixFileOpener(const char *pathName, int flags, mode_t mode); #else #define PosixFileOpener(a, b, c) Posix_Open(a, b, c); #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/fileLockPosix.c000066400000000000000000000452771470176644300247440ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2006-2019,2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * fileLockPosix.c -- * * Interface to host-specific file locking functions for POSIX hosts. */ #include #include #include #include #include #include #include #if defined(__APPLE__) #include #endif #include "vmware.h" #include "posix.h" #include "file.h" #include "fileLock.h" #include "fileInt.h" #include "util.h" #include "str.h" #include "err.h" #include "hostinfo.h" #include "unicodeOperations.h" #define LOGLEVEL_MODULE main #include "loglevel_user.h" #define LOG_MAX_PROC_NAME 64 /* * XXX * Most of these warnings must be turned back into Msg_Appends, or the * equivalent. They were changed from Msg_Appends to Warnings to facilitate * integration in the disklib library, but many of the warnings are very * important, and should be presented directly to the user, not go silently * into the log file. */ /* *---------------------------------------------------------------------- * * FileLockIsValidProcess -- * * Determine if the process, via its pid, is valid (alive). * * Results: * TRUE Yes * FALSE No * * Side effects: * None. * *---------------------------------------------------------------------- */ static Bool FileLockIsValidProcess(int pid) // IN: { HostinfoProcessQuery value = Hostinfo_QueryProcessExistence(pid); if (value == HOSTINFO_PROCESS_QUERY_UNKNOWN) { return TRUE; // Err on the side of caution } return (value == HOSTINFO_PROCESS_QUERY_ALIVE) ? TRUE : FALSE; } /* *---------------------------------------------------------------------- * * FileLockAppendMessage -- * * Append a detailed error message to the MsgList. * * Results: * As above * * Side effects: * Memory is allocated * *---------------------------------------------------------------------- */ void FileLockAppendMessage(MsgList **msgs, // IN/OUT/OPT: int err) // IN: errno { #if defined(VMX86_TOOLS) Log(LGPFX "A file locking error (%d) has occurred: %s.", err, Err_Errno2String(err)); #else MsgList_Append(msgs, MSGID(fileLock.posix) "A file locking error (%d) has occurred: %s.", err, Err_Errno2String(err)); #endif } #if defined(__linux__) /* *---------------------------------------------------------------------- * * FileReadSlashProc -- * * Read the data in a /proc file * * Results: * 0 Data is available * !0 Error (errno) * * Side effects: * None. * *---------------------------------------------------------------------- */ static int FileReadSlashProc(const char *procPath, // IN: char *buffer, // OUT: size_t bufferSize) // IN: { int fd; int err; char *p; size_t len; ASSERT(procPath != NULL); ASSERT(buffer != NULL); ASSERT(bufferSize > 0); fd = Posix_Open(procPath, O_RDONLY, 0); if (fd == -1) { return errno; } len = read(fd, buffer, bufferSize - 1); err = errno; close(fd); if (len == -1) { return err; } buffer[len] = '\0'; p = strchr(buffer, '\n'); if (p != NULL) { *p = '\0'; } return 0; } /* *--------------------------------------------------------------------------- * * FileLockProcessDescriptor -- * * Returns the process descriptor of the specified process. * * The format of a process descriptor is as follows: * * processID-processCreationTime(processName) * * where the processName and processCreationTime information * may be independently optional. * * Results: * NULL The process does not exist. * !NULL The process descriptor is returned. It is the callers * responsibility to free the dynamically allocated memory. * * Side Effects: * None * *--------------------------------------------------------------------------- */ static char * FileLockProcessDescriptor(pid_t pid) // IN: { char path[64]; char buffer[1024]; char *descriptor = NULL; if (!FileLockIsValidProcess(pid)) { return NULL; } Str_Sprintf(path, sizeof path, "/proc/%d/stat", pid); if (FileReadSlashProc(path, buffer, sizeof buffer) == 0) { char *p; char *q; char *rest; uint32 argc; char *argv[22]; char *savePtr = NULL; /* * You are in a maze of twisty little fields, (virtually) all alike... * * The process creation time, in 64-bit jiffies is "out there". * * A "man 5 proc" will provide illumination concerning all of the * fields found on this line of text. We code for the worst case * and ensure that file names containing spaces or parens are * properly handled. */ /* coverity[string_null] */ p = strchr(buffer, '('); if ((p == NULL) || (p == buffer) || (*(p - 1) != ' ')) { goto bail; } *(p - 1) = '\0'; q = strrchr(p + 1, ')'); if (q == NULL) { goto bail; } rest = q + 1; if (*rest != ' ') { goto bail; } *rest++ = '\0'; argv[0] = strtok_r(buffer, " ", &savePtr); // ensure no trailing spaces argv[1] = p; /* Map spaces in the process name to something benign */ q = p; while ((q = strchr(q, ' ')) != NULL) { *q = '_'; } if (strlen(p) > LOG_MAX_PROC_NAME) { p[LOG_MAX_PROC_NAME - 1] = ')'; p[LOG_MAX_PROC_NAME] = '\0'; } for (argc = 2; argc < 22; argc++) { argv[argc] = strtok_r((argc == 2) ? rest : NULL, " ", &savePtr); if (argv[argc] == NULL) { break; } } if (argc == 22) { descriptor = Str_SafeAsprintf(NULL, "%s-%s%s", argv[0], argv[21], argv[1]); } } bail: if (descriptor == NULL) { /* * Accessing /proc failed in some way. Emit a valid string that also * provides a clue that there is/was a problem. */ descriptor = Str_SafeAsprintf(NULL, "%d-0", pid); } return descriptor; } #elif defined(__APPLE__) /* *--------------------------------------------------------------------------- * * FileLockProcessCreationTime -- * * Returns the process creation time of the specified process. * * Results: * TRUE Done! * FALSE Process doesn't exist * * Side effects: * None * *--------------------------------------------------------------------------- */ static Bool FileLockProcessCreationTime(pid_t pid, // IN: uint64 *procCreationTime) // OUT: { int err; int mib[4]; size_t size; struct kinfo_proc info; ASSERT(procCreationTime != NULL); /* Request information about the specified process */ mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; memset(&info, 0, sizeof info); size = sizeof info; err = sysctl(mib, ARRAYSIZE(mib), &info, &size, NULL, 0); if (err == -1) { return FALSE; } *procCreationTime = (info.kp_proc.p_starttime.tv_sec * CONST64U(1000000)) + info.kp_proc.p_starttime.tv_usec; return TRUE; } /* *--------------------------------------------------------------------------- * * FileLockProcessDescriptor -- * * Returns the process descriptor of the specified process. * * The format of a process descriptor is as follows: * * processID-processCreationTime(processName) * * where the processName and processCreationTime information * may be independently optional. * * Results: * NULL The process does not exist. * !NULL The process descriptor is returned. It is the callers * responsibility to free the dynamically allocated memory. * * Side effects: * None * *--------------------------------------------------------------------------- */ static char * FileLockProcessDescriptor(pid_t pid) // IN: { uint64 procCreationTime; if (!FileLockIsValidProcess(pid)) { return NULL; } if (!FileLockProcessCreationTime(pid, &procCreationTime)) { return NULL; } return Str_SafeAsprintf(NULL, "%d-%"FMT64"u", pid, procCreationTime); } #else /* *--------------------------------------------------------------------------- * * FileLockProcessDescriptor -- * * Returns the process descriptor of the specified process. * * The format of a process descriptor is as follows: * * processID-processCreationTime(processName) * * where the processName and processCreationTime information * may be independently optional. * * Results: * NULL The process does not exist. * !NULL The process descriptor is returned. It is the callers * responsibility to free the dynamically allocated memory. * * Side effects: * None * *--------------------------------------------------------------------------- */ static char * FileLockProcessDescriptor(pid_t pid) // IN: { char *value; if (FileLockIsValidProcess(pid)) { value = Str_SafeAsprintf(NULL, "%u-0", (uint32) pid); } else { value = NULL; } return value; } #endif /* *--------------------------------------------------------------------------- * * FileLockGetExecutionID -- * * Returns the executionID of the caller. * * Results: * The executionID of the caller. This is a dynamically allocated string; * the caller is responsible for its disposal. * * Side effects: * The executionID of the caller is not thread safe. Locking is currently * done at the process level - all threads of a process are treated * identically. * *--------------------------------------------------------------------------- */ char * FileLockGetExecutionID(void) { char *descriptor = FileLockProcessDescriptor(getpid()); ASSERT(descriptor != NULL); // Must be able to describe ourselves! return descriptor; } /* *--------------------------------------------------------------------------- * * FileLockParseProcessDescriptor -- * * Attempt to parse the specified process descriptor. Return the * pieces requested. * * Results: * TRUE Process descriptor is valid. * FALSE Process descriptor is invalid. * * Side effects: * None * *--------------------------------------------------------------------------- */ static Bool FileLockParseProcessDescriptor(const char *procDescriptor, // IN: pid_t *pid, // OUT: uint64 *procCreationTime) // OUT: { uint32 tmp; ASSERT(procDescriptor != NULL); ASSERT(pid != NULL); ASSERT(procCreationTime != NULL); if (sscanf(procDescriptor, "%u-%"FMT64"u", &tmp, procCreationTime) != 2) { if (sscanf(procDescriptor, "%d", &tmp) == 1) { *procCreationTime = 0ULL; } else { return FALSE; } } *pid = tmp; return *pid >= 0; } /* *---------------------------------------------------------------------- * * FileLockValidExecutionID -- * * Validate the execution ID. * * Results: * TRUE Yes * FALSE No * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool FileLockValidExecutionID(const char *executionID) // IN: { pid_t filePID; pid_t procPID; Bool gotFileData; Bool gotProcData; char *procDescriptor; uint64 fileCreationTime; uint64 procCreationTime; gotFileData = FileLockParseProcessDescriptor(executionID, &filePID, &fileCreationTime); if (!gotFileData) { Warning(LGPFX" %s parse error on '%s'. Assuming valid.\n", __FUNCTION__, executionID); return TRUE; // Assume TRUE - preserve a lock - on parse error } procDescriptor = FileLockProcessDescriptor(filePID); if (procDescriptor == NULL) { return FALSE; // process doesn't exist } gotProcData = FileLockParseProcessDescriptor(procDescriptor, &procPID, &procCreationTime); ASSERT(gotProcData); // We built it; it had better be good ASSERT(procPID == filePID); // This better match what we started with... Posix_Free(procDescriptor); if ((fileCreationTime != 0) && (procCreationTime != 0) && (fileCreationTime != procCreationTime)) { return FALSE; // The process no longer exists } else { return TRUE; // Looks valid... } } /* *--------------------------------------------------------------------------- * * FileLockNormalizePath * * Normalize the path of the file being locked. Locking a symbolic * link should place the lock next to the link, not where the link * points to. * * Results: * The normalized path or NULL on error * * Side effects: * None * *--------------------------------------------------------------------------- */ static char * FileLockNormalizePath(const char *filePath) // IN: { char *result; char *dirName = NULL; char *fileName = NULL; /* * If the file to be locked is a symbolic link the lock file belongs next * to the symbolic link, not "off" where the symbolic link points to. * Translation: Don't "full path" the entire path of the file to be locked; * "full path" the dirName of the path, leaving the fileName alone. */ File_GetPathName(filePath, &dirName, &fileName); /* * Handle filePath - "xxx", "./xxx", "/xxx", and "/a/b/c". */ if (*dirName == '\0') { if (File_IsFullPath(filePath)) { result = Unicode_Join(DIRSEPS, fileName, NULL); } else { result = Unicode_Join(".", DIRSEPS, fileName, NULL); } } else { char *fullPath = File_FullPath(dirName); result = (fullPath == NULL) ? NULL : Unicode_Join(fullPath, DIRSEPS, fileName, NULL); Posix_Free(fullPath); } Posix_Free(dirName); Posix_Free(fileName); return result; } /* *---------------------------------------------------------------------- * * FileLock_Lock -- * * Obtain a lock on a file; shared or exclusive access. Also specify * how long to wait on lock acquisition - maxWaitTimeMsec * * maxWaitTimeMsec specifies the maximum amount of time, in * milliseconds, to wait for the lock before returning the "not * acquired" status. A value of FILELOCK_TRYLOCK_WAIT is the * equivalent of a "try lock" - the lock will be acquired only if * there is no contention. A value of FILELOCK_INFINITE_WAIT * specifies "waiting forever" to acquire the lock. * * Results: * NULL Lock not acquired * errno to *err, msg to **msgs - when appropriate * !NULL Lock Acquired. This is the "lockToken" for an unlock. * * Side effects: * Changes the host file system. * *---------------------------------------------------------------------- */ FileLockToken * FileLock_Lock(const char *filePath, // IN: const Bool readOnly, // IN: const uint32 maxWaitTimeMsec, // IN: int *err, // OUT/OPT: returns errno MsgList **msgs) // IN/OUT/OPT: add error message { int res = 0; char *normalizedPath; FileLockToken *tokenPtr; ASSERT(filePath != NULL); normalizedPath = FileLockNormalizePath(filePath); if (normalizedPath == NULL) { res = EINVAL; tokenPtr = NULL; } else { tokenPtr = FileLockIntrinsic(normalizedPath, !readOnly, maxWaitTimeMsec, &res); Posix_Free(normalizedPath); } if (tokenPtr == NULL) { if (res == 0) { res = EAGAIN; // Thank you for playing; try again /* Failed to acquire the lock; another has possession of it */ } FileLockAppendMessage(msgs, res); } if (err != NULL) { *err = res; } return tokenPtr; } /* *---------------------------------------------------------------------- * * FileLock_IsLocked -- * * Is a file currently locked (at the time of the call)? * * Results: * TRUE YES * FALSE Failure (errno to *err, msg to **msgs - when appropriate) * *---------------------------------------------------------------------- */ Bool FileLock_IsLocked(const char *filePath, // IN: int *err, // OUT/OPT: returns errno MsgList **msgs) // IN/OUT/OPT: add error message { int res = 0; Bool isLocked; char *normalizedPath; ASSERT(filePath != NULL); normalizedPath = FileLockNormalizePath(filePath); if (normalizedPath == NULL) { res = EINVAL; isLocked = FALSE; } else { isLocked = FileLockIsLocked(normalizedPath, &res); Posix_Free(normalizedPath); } if (err != NULL) { *err = res; } if (res != 0) { FileLockAppendMessage(msgs, res); } return isLocked; } /* *---------------------------------------------------------------------- * * FileLock_Unlock -- * * Release the lock held on the specified file. * * Results: * TRUE Success * FALSE Failure (errno to *err, msg to **msgs - when appropriate) * * Side effects: * Changes the host file system. * *---------------------------------------------------------------------- */ Bool FileLock_Unlock(const FileLockToken *lockToken, // IN: int *err, // OUT/OPT: returns errno MsgList **msgs) // IN/OUT/OPT: error messages { int res; ASSERT(lockToken != NULL); res = FileUnlockIntrinsic((FileLockToken *) lockToken); if (err != NULL) { *err = res; } if (res != 0) { FileLockAppendMessage(msgs, res); } return (res == 0); } open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/fileLockPrimitive.c000066400000000000000000001600771470176644300256060ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2007-2021,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * fileLockPrimitive.c -- * * Portable file locking via Lamport's Bakery algorithm. * * This implementation relies upon a remove directory operation failing * if the directory contains any files. */ #define _GNU_SOURCE /* For O_NOFOLLOW */ #include #include #include #include #include #include #include #if defined(_WIN32) #include #include #include #else #include #include #endif #include "vmware.h" #include "hostinfo.h" #include "util.h" #include "err.h" #include "log.h" #include "str.h" #include "fileIO.h" #include "fileLock.h" #include "fileInt.h" #include "random.h" #include "vm_atomic.h" #include "util.h" #include "hostType.h" #include "unicodeOperations.h" #define LOGLEVEL_MODULE main #include "loglevel_user.h" #define LOCK_SHARED "S" #define LOCK_EXCLUSIVE "X" #define FILELOCK_PROGRESS_DEARTH 8000 // Dearth of progress time in milliseconds #define FILELOCK_PROGRESS_SAMPLE 200 // Progress sampling time in milliseconds static char implicitReadToken; #define PARSE_TABLE_UINT 0 #define PARSE_TABLE_STRING 1 typedef struct parse_table { int type; const char *name; void *valuePtr; } ParseTable; /* * The lock token. This is returned by the lock operation and must be sent * to the unlock operation. */ #define FILELOCK_TOKEN_SIGNATURE 0x4B434C46 // 'FLCK' in memory struct FileLockToken { uint32 signature; Bool portable; char *pathName; union { struct { FileIODescriptor lockFd; } mandatory; struct { char *lockFilePath; // &implicitReadToken for implicit read locks } portable; } u; }; /* *----------------------------------------------------------------------------- * * FileLockSleeper -- * * Have the calling thread sleep "for a while". The duration of the * sleep is determined by the count that is passed in. Checks are * also done for exceeding the maximum wait time. * * Results: * 0 slept * EAGAIN maximum sleep time exceeded * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int FileLockSleeper(LockValues *myValues) // IN/OUT: { VmTimeType ageMsec; uint32 maxSleepTimeMsec; if (myValues->maxWaitTimeMsec == FILELOCK_TRYLOCK_WAIT) { return EAGAIN; } ageMsec = Hostinfo_SystemTimerMS() - myValues->startTimeMsec; if ((myValues->maxWaitTimeMsec != FILELOCK_INFINITE_WAIT) && (ageMsec >= myValues->maxWaitTimeMsec)) { return EAGAIN; } if (ageMsec <= 2000) { /* Most locks are "short" */ maxSleepTimeMsec = 100; } else { /* * The lock has been around a while; use a continuously increasing back * off with an upper bound. */ maxSleepTimeMsec = MIN(ageMsec / 10, 2000); } /* * Randomize the time slept. This will prevent any potential cadence issues * (thundering herds). */ (void) FileSleeper(maxSleepTimeMsec / 2, maxSleepTimeMsec); return 0; } /* *----------------------------------------------------------------------------- * * FileLockRemoveLockingFile -- * * Remove the specified file. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int FileLockRemoveLockingFile(const char *lockDir, // IN: const char *fileName) // IN: { int err; char *path; ASSERT(lockDir != NULL); ASSERT(fileName != NULL); path = Unicode_Join(lockDir, DIRSEPS, fileName, NULL); err = FileDeletionRobust(path, FALSE); if (err != 0) { if (err == ENOENT) { /* Not there anymore; locker unlocked or timed out */ err = 0; } else { Warning(LGPFX" %s of '%s' failed: %s\n", __FUNCTION__, path, Err_Errno2String(err)); } } Posix_Free(path); return err; } /* *----------------------------------------------------------------------------- * * FileLockParseArgs -- * * Parse the property list arguments of a lock file. The ParseTable * contains names of properies that are interesting to the caller; * only those values associated with the interesting names will be * extracted, the others will be ignored. * * Results: * TRUE An error was detected * FALSE All is well * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool FileLockParseArgs(char *argv[], // IN: uint32 argCount, // IN: ParseTable *table, // IN: uint32 tableSize) // IN: { uint32 argPos = 5; // The property list always starts with this argument while (argCount) { uint32 i; char *p = strchr(argv[argPos], '='); /* Validate the "name=value" form */ if ((p == NULL) || (p == argv[argPos]) || (p[1] == '\0')) { return TRUE; } *p = '\0'; /* Unknown names are ignored without error */ for (i = 0; i < tableSize; i++) { if (strcmp(argv[argPos], table[i].name) == 0) { switch (table[i].type) { case PARSE_TABLE_UINT: if (sscanf(&p[1], "%u", (uint32 *) table[i].valuePtr) != 1) { return TRUE; } break; case PARSE_TABLE_STRING: *((char **) table[i].valuePtr) = &p[1]; break; } } } *p = '='; argPos++; argCount--; } return FALSE; } /* *----------------------------------------------------------------------------- * * FileLockMemberValues -- * * Returns the values associated with lock directory file. * * Results: * 0 Valid lock file; values have been returned * > 0 Lock file problem (errno); values have not been returned * * Side effects: * The lock file may be deleted if it is invalid * *----------------------------------------------------------------------------- */ #define FL_MAX_ARGS 16 int FileLockMemberValues(const char *lockDir, // IN: const char *fileName, // IN: char *buffer, // OUT: size_t requiredSize, // IN: LockValues *memberValues) // OUT: { size_t len; int access; char *path; FileData fileData; FileIOResult result; FileIODescriptor desc; char *argv[FL_MAX_ARGS]; int err = 0; uint32 argc = 0; char *saveptr = NULL; ParseTable table[] = { { PARSE_TABLE_STRING, "lc", (void *) &memberValues->locationChecksum } }; ASSERT(lockDir != NULL); ASSERT(fileName != NULL); path = Unicode_Join(lockDir, DIRSEPS, fileName, NULL); FileIO_Invalidate(&desc); access = FILEIO_OPEN_ACCESS_READ; #if defined(_WIN32) access |= FILEIO_OPEN_SHARE_DELETE; #endif result = FileIOCreateRetry(&desc, path, access, FILEIO_OPEN, 0444, FILE_MAX_WAIT_TIME_MS); if (!FileIO_IsSuccess(result)) { err = FileMapErrorToErrno(__FUNCTION__, Err_Errno()); /* * A member file may "disappear" if is deleted (unlinked on POSIXen) * due to an unlock immediately after a directory scan but before the * scan is processed. Since this is a "normal" thing, ENOENT will be * suppressed. */ if (err != ENOENT) { Warning(LGPFX" %s open failure on '%s': %s\n", __FUNCTION__, path, Err_Errno2String(err)); } goto bail; } /* Attempt to obtain the lock file attributes now that it is opened */ err = FileAttributesRobust(path, &fileData); if (err != 0) { /* * A member file may "disappear" if is deleted (unlinked on POSIXen) * due to an unlock immediately after a directory scan but before the * scan is processed. Since this is a "normal" thing, ENOENT will be * suppressed. */ if (err != ENOENT) { Warning(LGPFX" %s file size failure on '%s': %s\n", __FUNCTION__, path, Err_Errno2String(err)); } FileIO_Close(&desc); goto bail; } /* Complain if the lock file is not the proper size */ if (fileData.fileSize != requiredSize) { Warning(LGPFX" %s file '%s': size %"FMT64"u, required size %"FMTSZ"d\n", __FUNCTION__, path, fileData.fileSize, requiredSize); FileIO_Close(&desc); goto corrupt; } /* Attempt to read the lock file data and validate how much was read. */ result = FileIO_Read(&desc, buffer, requiredSize, &len); FileIO_Close(&desc); if (!FileIO_IsSuccess(result)) { err = FileMapErrorToErrno(__FUNCTION__, Err_Errno()); Warning(LGPFX" %s read failure on '%s': %s\n", __FUNCTION__, path, Err_Errno2String(err)); goto bail; } if (len != requiredSize) { Warning(LGPFX" %s read length issue on '%s': %"FMTSZ"d and %"FMTSZ"d\n", __FUNCTION__, path, len, requiredSize); err = EIO; goto bail; } fixedUp: /* Extract and validate the lock file data. */ for (argc = 0; argc < FL_MAX_ARGS; argc++) { argv[argc] = strtok_r((argc == 0) ? buffer : NULL, " ", &saveptr); if (argv[argc] == NULL) { break; } } /* * Lock file arguments are space separated. There is a minimum of 5 * arguments - machineID, executionID, Lamport number, lock type * and process creation time. The maximum number of arguments is * FL_MAX_ARGS. * * Additional arguments, if present, form a property list - one or more * "name=value" pairs. * * Here is picture of valid forms: * * 0 1 2 3 4 5 6 Comment *------------------------- * A B C D E No property list * A B C D E x One property * A B C D E x y Two properties */ memberValues->locationChecksum = NULL; if ((argc < 5) || ((argc == FL_MAX_ARGS) && (strtok_r(NULL, " ", &saveptr) != NULL))) { goto corrupt; } if ((argc > 5) && FileLockParseArgs(argv, argc - 5, table, ARRAYSIZE(table))) { goto corrupt; } /* * Check for an old style lock file; if found, upgrade it (internally). * * The new style lock always has an executionID that is minimally * processID-processCreationTime (the '-' is the critical difference). */ if ((strchr(argv[1], '-') == NULL) && (strchr(argv[1], '(') == NULL) && (strchr(argv[1], ')') == NULL) && (argc == 6) && !FileLockParseArgs(argv, argc - 5, table, ARRAYSIZE(table))) { char *newBuffer; newBuffer = Str_SafeAsprintf(NULL, "%s %s-%s %s %s %s %s", argv[0], argv[1], argv[4], argv[2], argv[3], argv[4], argv[5]); Str_Strcpy(buffer, newBuffer, requiredSize); Posix_Free(newBuffer); goto fixedUp; } if (sscanf(argv[2], "%u", &memberValues->lamportNumber) != 1) { goto corrupt; } if ((strcmp(argv[3], LOCK_SHARED) != 0) && (strcmp(argv[3], LOCK_EXCLUSIVE) != 0)) { goto corrupt; } memberValues->machineID = argv[0]; memberValues->executionID = argv[1]; memberValues->lockType = argv[3]; memberValues->memberName = Unicode_Duplicate(fileName); Posix_Free(path); return 0; corrupt: Warning(LGPFX" %s removing problematic lock file '%s'\n", __FUNCTION__, path); if (argc) { uint32 i; Log(LGPFX" %s '%s' contents are:\n", __FUNCTION__, fileName); for (i = 0; i < argc; i++) { Log(LGPFX" %s %s argv[%u]: '%s'\n", __FUNCTION__, fileName, i, argv[i]); } } /* Remove the lock file and behave like it has disappeared */ err = FileDeletionRobust(path, FALSE); if (err == 0) { err = ENOENT; } bail: Posix_Free(path); return err; } /* *----------------------------------------------------------------------------- * * FileLockValidName -- * * Validate the format of the file name. * * Results: * TRUE Yes * FALSE No * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool FileLockValidName(const char *fileName) // IN: { uint32 i; ASSERT(fileName != NULL); /* The fileName must start with the ASCII character, 'M', 'D' or 'E' */ if (Unicode_FindSubstrInRange("MDE", 0, -1, fileName, 0, 1) == UNICODE_INDEX_NOT_FOUND) { return FALSE; } /* The fileName must contain 5 ASCII digits after the initial character */ for (i = 0; i < 5; i++) { if (Unicode_FindSubstrInRange("0123456789", 0, -1, fileName, i + 1, 1) == UNICODE_INDEX_NOT_FOUND) { return FALSE; } } /* The fileName must terminate with the appropriate suffix string */ return Unicode_EndsWith(fileName, FILELOCK_SUFFIX); } /* *----------------------------------------------------------------------------- * * FileLockActivateList * * Insure a lock list entry exists for the lock directory. * * Results: * 0 success * > 0 error (errno) * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int FileLockActivateList(const char *dirName, // IN: LockValues *myValues) // IN: { ActiveLock *ptr; ASSERT(dirName != NULL); ASSERT(*dirName == 'D'); /* Search the list for a matching entry */ for (ptr = myValues->lockList; ptr != NULL; ptr = ptr->next) { if (Unicode_Compare(ptr->dirName, dirName) == 0) { break; } } /* No entry? Attempt to add one. */ if (ptr == NULL) { ptr = Util_SafeMalloc(sizeof *ptr); ptr->next = myValues->lockList; myValues->lockList = ptr; ptr->age = 0; ptr->dirName = Unicode_Duplicate(dirName); } /* Mark the entry (exists) */ ptr->marked = TRUE; return 0; } /* *----------------------------------------------------------------------------- * * FileLockLocationChecksum -- * * Compute the location checksum of the argument path. * * Results: * The location checksum as dynamically allocated string. * * Side effects: * None * *----------------------------------------------------------------------------- */ static char * FileLockLocationChecksum(const char *path) // IN: { int c; uint32 hash = 5381; #if defined(_WIN32) char *p; char *value = Unicode_Duplicate(path); /* Don't get fooled by mixed case; "normalize" */ Str_ToLower(value); p = value; #else char *p = (char *) path; #endif /* DBJ2 hash... good enough? */ while ((c = *p++)) { hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ } #if defined(_WIN32) Posix_Free(value); #endif return Str_SafeAsprintf(NULL, "%u", hash); } /* *----------------------------------------------------------------------------- * * FileLockScanDirectory -- * * Call the specified function for each member file found in the * specified directory. * * Results: * 0 success * > 0 failure * * Side effects: * Anything that this not a valid locking file is deleted. * *----------------------------------------------------------------------------- */ static int FileLockScanDirectory(const char *lockDir, // IN: int (*func)( // IN: const char *lockDir, const char *fileName, LockValues *memberValues, LockValues *myValues ), LockValues *myValues, // IN: Bool cleanUp) // IN: { uint32 i; int err; int numEntries; char **fileList = NULL; char *myExecutionID = NULL; char *locationChecksum = NULL; ASSERT(lockDir != NULL); numEntries = FileListDirectoryRobust(lockDir, &fileList); if (numEntries == -1) { Log(LGPFX" %s: Could not read the directory '%s': %d\n", __FUNCTION__, lockDir, Err_Errno()); return EDOM; // out of my domain } /* Pass 1: Validate entries and handle any 'D' entries */ for (i = 0, err = 0; i < numEntries; i++) { /* Remove any non-locking files */ if (!FileLockValidName(fileList[i])) { Log(LGPFX" %s discarding %s from %s'; invalid file name.\n", __FUNCTION__, fileList[i], lockDir); err = FileLockRemoveLockingFile(lockDir, fileList[i]); if (err != 0) { goto bail; } Posix_Free(fileList[i]); fileList[i] = NULL; continue; } /* * Any lockers appear to be entering? * * This should be rather rare. If a locker dies while entering * this will cleaned-up. */ if (*fileList[i] == 'D') { if (cleanUp) { err = FileLockActivateList(fileList[i], myValues); if (err != 0) { goto bail; } } Posix_Free(fileList[i]); fileList[i] = NULL; } } if (myValues->lockList != NULL) { goto bail; } myExecutionID = FileLockGetExecutionID(); locationChecksum = FileLockLocationChecksum(lockDir); /* Pass 2: Handle the 'M' entries */ for (i = 0, err = 0; i < numEntries; i++) { LockValues *ptr; Bool myLockFile; LockValues memberValues; char buffer[FILELOCK_DATA_SIZE]; // Must be near memberValues, // as it will be pointed by it if ((fileList[i] == NULL) || (*fileList[i] == 'E')) { continue; } myLockFile = (Unicode_Compare(fileList[i], myValues->memberName) == 0) ? TRUE : FALSE; if (myLockFile) { /* It's me! No need to read or validate anything. */ ptr = myValues; } else { /* It's not me! Attempt to extract the member values. */ err = FileLockMemberValues(lockDir, fileList[i], buffer, FILELOCK_DATA_SIZE, &memberValues); if (err != 0) { if (err == ENOENT) { err = 0; /* Not there anymore; locker unlocked or timed out */ continue; } break; } /* Remove any stale locking files */ if (FileLockMachineIDMatch(myValues->machineID, memberValues.machineID)) { char *dispose = NULL; if (FileLockValidExecutionID(memberValues.executionID)) { /* If it's mine it better still be where I put it! */ if ((strcmp(myExecutionID, memberValues.executionID) == 0) && ((memberValues.locationChecksum != NULL) && (strcmp(memberValues.locationChecksum, locationChecksum) != 0))) { dispose = Unicode_Duplicate("lock file has been moved."); } } else { dispose = Str_SafeAsprintf(NULL, "invalid executionID %s.", memberValues.executionID); } if (dispose) { Log(LGPFX" %s discarding %s from %s': %s\n", __FUNCTION__, fileList[i], lockDir, dispose); Posix_Free(dispose); Posix_Free(memberValues.memberName); err = FileLockRemoveLockingFile(lockDir, fileList[i]); if (err != 0) { break; } continue; } } ptr = &memberValues; } /* Locking file looks good; see what happens */ err = (*func)(lockDir, fileList[i], ptr, myValues); if (ptr == &memberValues) { Posix_Free(memberValues.memberName); } if (err != 0) { break; } } bail: Util_FreeStringList(fileList, numEntries); Posix_Free(locationChecksum); Posix_Free(myExecutionID); return err; } /* *----------------------------------------------------------------------------- * * FileLockScanner -- * * Call the specified function for each member file found in the * specified directory. If a rescan is necessary check the list * of outstanding locks and handle removing stale locks. * * Results: * 0 success * > 0 failure * * Side effects: * None * *----------------------------------------------------------------------------- */ static int FileLockScanner(const char *lockDir, // IN: int (*func)( // IN: const char *lockDir, const char *fileName, LockValues *memberValues, LockValues *myValues ), LockValues *myValues, // IN: Bool cleanUp) // IN: { int err; ActiveLock *ptr; ASSERT(lockDir != NULL); myValues->lockList = NULL; while (TRUE) { ActiveLock *prev; err = FileLockScanDirectory(lockDir, func, myValues, cleanUp); if ((err > 0) || ((err == 0) && (myValues->lockList == NULL))) { break; } prev = NULL; ptr = myValues->lockList; /* * Some 'D' entries have persisted. Age them and remove those that * have not progressed. Remove those that have disappeared. */ while (ptr != NULL) { Bool remove; if (ptr->marked) { if (ptr->age > FILELOCK_PROGRESS_DEARTH) { char *temp; char *path; UnicodeIndex index; ASSERT(*ptr->dirName == 'D'); Log(LGPFX" %s discarding %s data from '%s'.\n", __FUNCTION__, ptr->dirName, lockDir); path = Unicode_Join(lockDir, DIRSEPS, ptr->dirName, NULL); index = Unicode_FindLast(path, "D"); ASSERT(index != UNICODE_INDEX_NOT_FOUND); temp = Unicode_Replace(path, index, 1, "M"); FileDeletionRobust(temp, FALSE); Posix_Free(temp); temp = Unicode_Replace(path, index, 1, "E"); FileDeletionRobust(temp, FALSE); Posix_Free(temp); FileRemoveDirectoryRobust(path); Posix_Free(path); remove = TRUE; } else { ptr->marked = FALSE; ptr->age += FILELOCK_PROGRESS_SAMPLE; remove = FALSE; } } else { remove = TRUE; } if (remove) { ActiveLock *temp = ptr; ptr = ptr->next; Posix_Free(temp->dirName); Posix_Free(temp); if (prev == NULL) { myValues->lockList = ptr; } else { prev->next = ptr; } } else { prev = ptr; ptr = ptr->next; } } FileSleeper(FILELOCK_PROGRESS_SAMPLE, FILELOCK_PROGRESS_SAMPLE); // relax } /* Clean up anything still on the list; they are no longer important */ while (myValues->lockList != NULL) { ptr = myValues->lockList; myValues->lockList = ptr->next; Posix_Free(ptr->dirName); Posix_Free(ptr); } return err; } /* *----------------------------------------------------------------------------- * * FileUnlockIntrinsic -- * * Release a lock on a file. * * Results: * 0 unlocked * > 0 errno * * Side effects: * None. * *----------------------------------------------------------------------------- */ int FileUnlockIntrinsic(FileLockToken *tokenPtr) // IN: { int err = 0; ASSERT(tokenPtr && (tokenPtr->signature == FILELOCK_TOKEN_SIGNATURE)); LOG(1, "Requesting unlock on %s\n", tokenPtr->pathName); if (tokenPtr->portable) { /* * If the lockFilePath (a pointer) is the fixed-address token representing * an implicit read lock, there is no lock file and the token can simply * be discarded. */ if (tokenPtr->u.portable.lockFilePath != &implicitReadToken) { char *lockDir; /* The lock directory path */ lockDir = Unicode_Append(tokenPtr->pathName, FILELOCK_SUFFIX); /* * TODO: under vmx86_debug validate the contents of the lock file as * matching the machineID and executionID. */ err = FileDeletionRobust(tokenPtr->u.portable.lockFilePath, FALSE); FileRemoveDirectoryRobust(lockDir); // just in case we can clean up if (err && vmx86_debug) { Log(LGPFX" %s failed for '%s': %s\n", __FUNCTION__, tokenPtr->u.portable.lockFilePath, Err_Errno2String(err)); } Posix_Free(lockDir); Posix_Free(tokenPtr->u.portable.lockFilePath); } tokenPtr->u.portable.lockFilePath = NULL; // Just in case... } else { ASSERT(FileIO_IsValid(&tokenPtr->u.mandatory.lockFd)); if (!FileIO_IsSuccess(FileIO_CloseAndUnlink(&tokenPtr->u.mandatory.lockFd))) { /* * Should succeed, but there is an unavoidable race: * close() must precede unlink(), but another thread could touch * the file between close() and unlink(). We only worry about other * FileLock-like manipulations; the advisory lock file should not * experience any name collisions. Treat races as success. * Specific errors: * EBUSY: other locked file * ENOENT: other locked + unlocked (w/ implicit unlink) file */ if (Err_Errno() == EBUSY || Err_Errno() == ENOENT) { LOG(0, "Tolerating %s on unlink of advisory lock at %s\n", Err_Errno() == EBUSY ? "EBUSY" : "ENOENT", tokenPtr->pathName); } else { err = Err_Errno(); if (vmx86_debug) { Log(LGPFX" %s failed for advisory lock '%s': %s\n", __FUNCTION__, tokenPtr->pathName, Err_Errno2String(err)); } } } } Posix_Free(tokenPtr->pathName); tokenPtr->signature = 0; // Just in case... tokenPtr->pathName = NULL; // Just in case... Posix_Free(tokenPtr); return err; } /* *----------------------------------------------------------------------------- * * FileLockWaitForPossession -- * * Wait until the caller has a higher priority towards taking * possession of a lock than the specified file. * * Results: * 0 success * > 0 error (errno) * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int FileLockWaitForPossession(const char *lockDir, // IN: const char *fileName, // IN: LockValues *memberValues, // IN: LockValues *myValues) // IN: { int err = 0; ASSERT(lockDir != NULL); ASSERT(fileName != NULL); /* "Win" or wait? */ if (((memberValues->lamportNumber < myValues->lamportNumber) || ((memberValues->lamportNumber == myValues->lamportNumber) && (Unicode_Compare(memberValues->memberName, myValues->memberName) < 0))) && ((strcmp(memberValues->lockType, LOCK_EXCLUSIVE) == 0) || (strcmp(myValues->lockType, LOCK_EXCLUSIVE) == 0))) { Bool thisMachine = FileLockMachineIDMatch(myValues->machineID, memberValues->machineID); char *path = Unicode_Join(lockDir, DIRSEPS, fileName, NULL); while ((err = FileLockSleeper(myValues)) == 0) { /* still there? */ err = FileAttributesRobust(path, NULL); if (err != 0) { if (err == ENOENT) { /* Not there anymore; locker unlocked or timed out */ err = 0; } break; } /* still valid? */ if (thisMachine && !FileLockValidExecutionID(memberValues->executionID)) { /* Invalid Execution ID; remove the member file */ Warning(LGPFX" %s discarding file '%s'; invalid executionID.\n", __FUNCTION__, path); err = FileLockRemoveLockingFile(lockDir, fileName); break; } } /* * Log the disposition of each timeout for all non "try lock" locking * attempts. This can assist in debugging locking problems. */ if ((myValues->maxWaitTimeMsec != FILELOCK_TRYLOCK_WAIT) && (err == EAGAIN)) { if (thisMachine) { Log(LGPFX" %s timeout on '%s' due to a local process '%s'\n", __FUNCTION__, path, memberValues->executionID); } else { Log(LGPFX" %s timeout on '%s' due to another machine '%s'\n", __FUNCTION__, path, memberValues->machineID); } } Posix_Free(path); } return err; } /* *----------------------------------------------------------------------------- * * FileLockNumberScan -- * * Determine the maxmimum number value within the current locking set. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int FileLockNumberScan(const char *lockDir, // IN: const char *fileName, // IN: LockValues *memberValues, // IN: LockValues *myValues) // IN/OUT: { ASSERT(lockDir != NULL); ASSERT(fileName != NULL); if (memberValues->lamportNumber > myValues->lamportNumber) { myValues->lamportNumber = memberValues->lamportNumber; } return 0; } /* *----------------------------------------------------------------------------- * * FileLockMakeDirectory -- * * Create a directory. * * Results: * 0 success * > 0 failure (errno) * * Side Effects: * File system may be modified. * *----------------------------------------------------------------------------- */ static int FileLockMakeDirectory(const char *pathName) // IN: { int err; #if !defined(_WIN32) mode_t save; save = umask(0); #endif ASSERT(pathName != NULL); err = FileCreateDirectoryRobust(pathName, 0777); #if !defined(_WIN32) umask(save); #endif return err; } /* *----------------------------------------------------------------------------- * * FileLockCreateEntryDirectory -- * * Create an entry directory in the specified locking directory. * * Due to FileLock_Unlock() attempting to remove the locking * directory on an unlock operation (to "clean up" and remove the * locking directory when it is no longer needed), this routine * must carefully handle a number of race conditions to insure the * the locking directory exists and the entry directory is created * within. * * Results: * 0 success * > 0 failure (errno) * * Side Effects: * On success returns the number identifying the entry directory and * the entry directory path name. * *----------------------------------------------------------------------------- */ static int FileLockCreateEntryDirectory(const char *lockDir, // IN: char **entryDirectory, // OUT: char **entryFilePath, // OUT: char **memberFilePath, // OUT: char **memberName) // OUT: { int err; VmTimeType startTimeMsec; ASSERT(lockDir != NULL); *entryDirectory = NULL; *entryFilePath = NULL; *memberFilePath = NULL; *memberName = NULL; /* Fun at the races */ startTimeMsec = Hostinfo_SystemTimerMS(); while (TRUE) { char *temp; FileData fileData; VmTimeType ageMsec; uint32 randomNumber; err = FileAttributesRobust(lockDir, &fileData); if (err == 0) { /* The name exists. Deal with it... */ if (fileData.fileType != FILE_TYPE_DIRECTORY) { /* * Locks are implemented via directories. Ancient hosted locks and * lock files imported alongsize an ESXi VM are implemented as * files. It's safe to remove these. The ESXi lock files are * meaningless and the ancient hosted lock files have been dead * for over a decade (at the time of writing this comment). */ err = FileDeletionRobust(lockDir, FALSE); if (err == 0) { Warning(LGPFX" %s: '%s' is not a directory. Removed.\n", __FUNCTION__, lockDir); } else { Warning(LGPFX" %s: an attempt to remove '%s' failed: %s\n", __FUNCTION__, lockDir, Err_Errno2String(err)); break; } continue; } } else { if (err == ENOENT) { /* Not there anymore; locker unlocked or timed out */ err = FileLockMakeDirectory(lockDir); if ((err != 0) && (err != EEXIST)) { Warning(LGPFX" %s creation failure on '%s': %s\n", __FUNCTION__, lockDir, Err_Errno2String(err)); break; } } else { Warning(LGPFX" %s stat failure on '%s': %s\n", __FUNCTION__, lockDir, Err_Errno2String(err)); break; } } /* There is a small chance of collision/failure; grab stings now */ randomNumber = (FileSimpleRandom() >> 8) & 0xFFFF; *memberName = Unicode_Format("M%05u%s", randomNumber, FILELOCK_SUFFIX); temp = Unicode_Format("D%05u%s", randomNumber, FILELOCK_SUFFIX); *entryDirectory = Unicode_Join(lockDir, DIRSEPS, temp, NULL); Posix_Free(temp); temp = Unicode_Format("E%05u%s", randomNumber, FILELOCK_SUFFIX); *entryFilePath = Unicode_Join(lockDir, DIRSEPS, temp, NULL); Posix_Free(temp); *memberFilePath = Unicode_Join(lockDir, DIRSEPS, *memberName, NULL); err = FileLockMakeDirectory(*entryDirectory); if (err == 0) { /* * The entry directory was safely created. See if a member file * is in use (the entry directory is removed once the member file * is created). If a member file is in use, choose another number, * otherwise the use of the this number is OK. * * Err on the side of caution... don't want to trash perfectly * good member files. */ err = FileAttributesRobust(*memberFilePath, NULL); if (err != 0) { if (err == ENOENT) { err = 0; break; } if (vmx86_debug) { Log(LGPFX" %s stat failure on '%s': %s\n", __FUNCTION__, *memberFilePath, Err_Errno2String(err)); } } err = FileRemoveDirectoryRobust(*entryDirectory); if (err != 0) { Warning(LGPFX" %s unable to remove '%s': %s\n", __FUNCTION__, *entryDirectory, Err_Errno2String(err)); break; } } else { if ((err != EEXIST) && // Another process/thread created it... (err != ENOENT)) { // lockDir is gone... Warning(LGPFX" %s creation failure on '%s': %s\n", __FUNCTION__, *entryDirectory, Err_Errno2String(err)); break; } } Posix_Free(*entryDirectory); Posix_Free(*entryFilePath); Posix_Free(*memberFilePath); Posix_Free(*memberName); *entryDirectory = NULL; *entryFilePath = NULL; *memberFilePath = NULL; *memberName = NULL; /* * If we've been trying to get the locking started for a unacceptable * amount of time, bail. Something is seriously wrong, probably the * file system or networking. Nothing we can do about it. */ ageMsec = Hostinfo_SystemTimerMS() - startTimeMsec; if (ageMsec > FILELOCK_PROGRESS_DEARTH) { Warning(LGPFX" %s lack of progress on '%s'\n", __FUNCTION__, lockDir); err = EBUSY; break; } } if (err != 0) { Posix_Free(*entryDirectory); Posix_Free(*entryFilePath); Posix_Free(*memberFilePath); Posix_Free(*memberName); *entryDirectory = NULL; *entryFilePath = NULL; *memberFilePath = NULL; *memberName = NULL; } return err; } /* *----------------------------------------------------------------------------- * * FileLockCreateMemberFile -- * * Create the member file. * * Results: * 0 success * > 0 failure (errno) * * Side Effects: * None * *----------------------------------------------------------------------------- */ static int FileLockCreateMemberFile(FileIODescriptor *desc, // IN: const LockValues *myValues, // IN: const char *entryFilePath, // IN: const char *memberFilePath) // IN: { int cnt; int pid; size_t len; FileIOResult result; uint64 processCreationTime; int err = 0; char buffer[FILELOCK_DATA_SIZE] = { 0 }; ASSERT(entryFilePath != NULL); ASSERT(memberFilePath != NULL); /* * Populate the buffer with appropriate data * * Lock file arguments are space separated. There is a minimum of 5 * arguments - machineID, executionID, Lamport number, lock type * and process creation time. The maximum number of arguments is * FL_MAX_ARGS. * * Additional arguments, if present, form a property list - one or more * "name=value" pairs. * * Yes, the process creation time is redundently encoded. This is necessary * to maintain backwards compatibility. Should an older code pick up a * newer lock file and there is lock contention, the older code will log * the name of the process causing the contention - it's also encoded * into the executionID. */ cnt = sscanf(myValues->executionID, "%d-%"FMT64"u", &pid, &processCreationTime); ASSERT(cnt == 2); // ensure new format executionID Str_Sprintf(buffer, sizeof buffer, "%s %s %u %s %"FMT64"u lc=%s", myValues->machineID, myValues->executionID, myValues->lamportNumber, myValues->lockType, processCreationTime, myValues->locationChecksum); /* Attempt to write the data */ result = FileIO_Write(desc, buffer, sizeof buffer, &len); if (!FileIO_IsSuccess(result)) { err = FileMapErrorToErrno(__FUNCTION__, Err_Errno()); Warning(LGPFX" %s write of '%s' failed: %s\n", __FUNCTION__, entryFilePath, Err_Errno2String(err)); FileIO_Close(desc); return err; } if (!FileIO_IsSuccess(FileIO_Close(desc))) { err = FileMapErrorToErrno(__FUNCTION__, Err_Errno()); Warning(LGPFX" %s close of '%s' failed: %s\n", __FUNCTION__, entryFilePath, Err_Errno2String(err)); return err; } if (len != sizeof buffer) { Warning(LGPFX" %s write length issue on '%s': %"FMTSZ"d and %"FMTSZ"d\n", __FUNCTION__, entryFilePath, len, sizeof buffer); return EIO; } err = File_Rename(entryFilePath, memberFilePath); if (err != 0) { Warning(LGPFX" %s FileRename of '%s' to '%s' failed: %s\n", __FUNCTION__, entryFilePath, memberFilePath, Err_Errno2String(err)); if (vmx86_debug) { Log(LGPFX" %s FileLockFileType() of '%s': %s\n", __FUNCTION__, entryFilePath, Err_Errno2String(FileAttributesRobust(entryFilePath, NULL))); Log(LGPFX" %s FileLockFileType() of '%s': %s\n", __FUNCTION__, memberFilePath, Err_Errno2String(FileAttributesRobust(memberFilePath, NULL))); } return err; } return 0; } /* *----------------------------------------------------------------------------- * * FileLockIntrinsicMandatory -- * * Obtain a lock on a file; shared or exclusive access. * * This implementation uses the FILEIO_OPEN_LOCK_MANDATORY flag, * which requires kernel support for mandatory locking. Such locks * are automatically broken if the host holding the lock fails. * * maxWaitTimeMsec specifies the maximum amount of time, in * milliseconds, to wait for the lock before returning the "not * acquired" status. A value of FILELOCK_TRYLOCK_WAIT is the * equivalent of a "try lock" - the lock will be acquired only if * there is no contention. A value of FILELOCK_INFINITE_WAIT * specifies "waiting forever" to acquire the lock. * * Results: * NULL Lock not acquired. Check err. * err 0 Lock Timed Out * err > 0 errno * !NULL Lock Acquired. This is the "lockToken" for an unlock. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static FileLockToken * FileLockIntrinsicMandatory(const char *pathName, // IN: const char *lockFile, // IN: LockValues *myValues, // IN/OUT: int *err) // OUT: { int access; int errnum; FileIOResult result; FileLockToken *tokenPtr = Util_SafeMalloc(sizeof *tokenPtr); tokenPtr->signature = FILELOCK_TOKEN_SIGNATURE; tokenPtr->portable = FALSE; tokenPtr->pathName = Unicode_Duplicate(pathName); FileIO_Invalidate(&tokenPtr->u.mandatory.lockFd); access = myValues->exclusivity ? FILEIO_OPEN_ACCESS_WRITE : FILEIO_OPEN_ACCESS_READ; access |= FILEIO_OPEN_EXCLUSIVE_LOCK; do { result = FileIOCreateRetry(&tokenPtr->u.mandatory.lockFd, lockFile, access, FILEIO_OPEN_CREATE, 0600, 0); errnum = Err_Errno(); if (result != FILEIO_LOCK_FAILED) { break; } } while (FileLockSleeper(myValues) == 0); if (FileIO_IsSuccess(result)) { ASSERT(FileIO_IsValid(&tokenPtr->u.mandatory.lockFd)); *err = 0; return tokenPtr; } else { if (result == FILEIO_LOCK_FAILED) { *err = 0; } else { *err = FileMapErrorToErrno(__FUNCTION__, errnum); } Posix_Free(tokenPtr->pathName); ASSERT(!FileIO_IsValid(&tokenPtr->u.mandatory.lockFd)); Posix_Free(tokenPtr); return NULL; } } /* *----------------------------------------------------------------------------- * * FileLockIntrinsicPortable -- * * Obtain a lock on a file; shared or exclusive access. * * This implementation uses a HIGHLY portable directory-namespace + * Lamport bakery scheme that works on all filesystems that provide * atomicity of the directory namespace (That is, all known filesystems). * The various files involved are hidden within a "pathName.lck/" * subdirectory. * * The lock can be broken by removing the subdirectory. The lock * is self-cleaning on the same host (e.g. will detect a dead process * and will break the lock), but NOT self-cleaning across hosts. The * lock does not require any sort of time-based leases or heartbeats. * * Results: * NULL Lock not acquired. Check err. * err 0 Lock Timed Out * err > 0 errno * !NULL Lock Acquired. This is the "lockToken" for an unlock. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static FileLockToken * FileLockIntrinsicPortable(const char *pathName, // IN: const char *lockDir, // IN: LockValues *myValues, // IN/OUT: int *err) // OUT: { int access; FileIOResult result; FileIODescriptor desc; FileLockToken *tokenPtr; char *entryFilePath = NULL; char *memberFilePath = NULL; char *entryDirectory = NULL; ASSERT(pathName != NULL); ASSERT(err != NULL); /* * Attempt to create the locking and entry directories; obtain the * entry and member path names. */ *err = FileLockCreateEntryDirectory(lockDir, &entryDirectory, &entryFilePath, &memberFilePath, &myValues->memberName); switch (*err) { case 0: break; case EROFS: /* FALL THROUGH */ case EACCES: if (!myValues->exclusivity) { /* * Lock is for read/shared access however the lock directory could * not be created. Grant an implicit read lock whenever possible. * The address of a private variable will be used for the lock token. */ Warning(LGPFX" %s implicit %s lock succeeded on '%s'.\n", __FUNCTION__, LOCK_SHARED, pathName); *err = 0; memberFilePath = &implicitReadToken; } /* FALL THROUGH */ default: goto bail; } ASSERT(Unicode_LengthInCodeUnits(memberFilePath) - Unicode_LengthInCodeUnits(pathName) <= FILELOCK_OVERHEAD); /* Attempt to create the entry file */ access = FILEIO_OPEN_ACCESS_WRITE; #if defined(_WIN32) access |= FILEIO_OPEN_SHARE_DELETE; #else access |= FILEIO_OPEN_ACCESS_NOFOLLOW; #endif FileIO_Invalidate(&desc); result = FileIOCreateRetry(&desc, entryFilePath, access, FILEIO_OPEN_CREATE_SAFE, 0644, FILE_MAX_WAIT_TIME_MS); if (!FileIO_IsSuccess(result)) { *err = FileMapErrorToErrno(__FUNCTION__, Err_Errno()); /* clean up */ FileRemoveDirectoryRobust(entryDirectory); FileRemoveDirectoryRobust(lockDir); goto bail; } /* What is max(Number[1]... Number[all lockers])? */ *err = FileLockScanner(lockDir, FileLockNumberScan, myValues, FALSE); if (*err != 0) { /* clean up */ FileIO_Close(&desc); FileDeletionRobust(entryFilePath, FALSE); FileRemoveDirectoryRobust(entryDirectory); FileRemoveDirectoryRobust(lockDir); goto bail; } /* Number[i] = 1 + max([Number[1]... Number[all lockers]) */ myValues->lamportNumber++; /* Attempt to create the member file */ *err = FileLockCreateMemberFile(&desc, myValues, entryFilePath, memberFilePath); /* Remove entry directory; it has done its job */ if (*err == 0) { *err = FileRemoveDirectoryRobust(entryDirectory); } if (*err != 0) { /* clean up */ FileDeletionRobust(entryFilePath, FALSE); FileDeletionRobust(memberFilePath, FALSE); FileRemoveDirectoryRobust(lockDir); goto bail; } /* Attempt to acquire the lock */ *err = FileLockScanner(lockDir, FileLockWaitForPossession, myValues, TRUE); switch (*err) { case 0: break; case EAGAIN: /* clean up */ FileDeletionRobust(memberFilePath, FALSE); FileRemoveDirectoryRobust(lockDir); /* FALL THROUGH */ default: break; } bail: Posix_Free(entryDirectory); Posix_Free(entryFilePath); if (*err == 0) { tokenPtr = Util_SafeMalloc(sizeof *tokenPtr); tokenPtr->signature = FILELOCK_TOKEN_SIGNATURE; tokenPtr->portable = TRUE; tokenPtr->pathName = Unicode_Duplicate(pathName); tokenPtr->u.portable.lockFilePath = memberFilePath; } else { Posix_Free(memberFilePath); tokenPtr = NULL; if (*err == EAGAIN) { *err = 0; // lock not acquired } } return tokenPtr; } /* *----------------------------------------------------------------------------- * * FileLockIntrinsic -- * * Obtain a lock on a file; shared or exclusive access. * * All FileLock_-based locks are advisory locks (i.e. the * lock is maintained separately from the file so only FileLock_ * callers experience locking). Advisory locks have an inherent problem * that they are difficult to break in the event one of the cooperating * entities fails, particularly across distributed filesystems. * * This wrapper function will adaptively switch between a scheme * implemented via mandatory locks and a more portable scheme depending * on host OS support. * * maxWaitTimeMsec specifies the maximum amount of time, in * milliseconds, to wait for the lock before returning the "not * acquired" status. A value of FILELOCK_TRYLOCK_WAIT is the * equivalent of a "try lock" - the lock will be acquired only if * there is no contention. A value of FILELOCK_INFINITE_WAIT * specifies "waiting forever" to acquire the lock. * * Results: * NULL Lock not acquired. Check err. * err 0 Lock Timed Out * err > 0 errno * !NULL Lock Acquired. This is the "lockToken" for an unlock. * * Side effects: * None. * *----------------------------------------------------------------------------- */ FileLockToken * FileLockIntrinsic(const char *pathName, // IN: Bool exclusivity, // IN: uint32 maxWaitTimeMsec, // IN: int *err) // OUT: { char *lockBase; LockValues myValues = { 0 }; FileLockToken *tokenPtr; /* Construct the locking directory path */ lockBase = Unicode_Append(pathName, FILELOCK_SUFFIX); myValues.lockType = exclusivity ? LOCK_EXCLUSIVE : LOCK_SHARED; myValues.exclusivity = exclusivity; myValues.startTimeMsec = Hostinfo_SystemTimerMS(); myValues.maxWaitTimeMsec = maxWaitTimeMsec; if (File_SupportsMandatoryLock(pathName)) { LOG(1, "Requesting %s lock on %s (mandatory, %u).\n", myValues.lockType, pathName, myValues.maxWaitTimeMsec); tokenPtr = FileLockIntrinsicMandatory(pathName, lockBase, &myValues, err); } else { myValues.machineID = (char *) FileLockGetMachineID(); // don't free this! myValues.executionID = FileLockGetExecutionID(); // free this! myValues.lamportNumber = 0; myValues.locationChecksum = FileLockLocationChecksum(lockBase); // free this! myValues.memberName = NULL; LOG(1, "Requesting %s lock on %s (%s, %s, %u).\n", myValues.lockType, pathName, myValues.machineID, myValues.executionID, myValues.maxWaitTimeMsec); tokenPtr = FileLockIntrinsicPortable(pathName, lockBase, &myValues, err); Posix_Free(myValues.memberName); Posix_Free(myValues.locationChecksum); Posix_Free(myValues.executionID); } Posix_Free(lockBase); return tokenPtr; } /* *----------------------------------------------------------------------------- * * FileLockIsLockedMandatory -- * * Is a file currently locked (at the time of the call)? * * The only way to check for a mandatory lock is to try opening * the file (and quickly closing it again). If the lock is held, * attempting to open the file will return FILEIO_LOCK_FAILED. * * Results: * TRUE YES * FALSE NO; if err is not NULL may check *err for an error * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool FileLockIsLockedMandatory(const char *lockFile, // IN: int *err) // OUT/OPT: { int access; FileIOResult result; FileIODescriptor desc; FileIO_Invalidate(&desc); /* * Check for lock by actually locking file, and dropping * lock quickly if open was successful. */ access = FILEIO_OPEN_ACCESS_READ | FILEIO_OPEN_ACCESS_WRITE | FILEIO_OPEN_EXCLUSIVE_LOCK; result = FileIOCreateRetry(&desc, lockFile, access, FILEIO_OPEN, 0644, 0); if (FileIO_IsSuccess(result)) { Bool success; success = FileIO_IsSuccess(FileIO_Close(&desc)); ASSERT(success); return FALSE; } else if (result == FILEIO_LOCK_FAILED) { return TRUE; // locked } else if (result == FILEIO_FILE_NOT_FOUND) { return FALSE; // no lock file means unlocked } else { if (err != NULL) { *err = FileMapErrorToErrno(__FUNCTION__, Err_Errno()); } return FALSE; } } /* *----------------------------------------------------------------------------- * * FileLockIsLockedPortable -- * * Is a file currently locked (at the time of the call)? * * The "portable" lock is held if the lock directory exists and * there are any "M" entries (representing held locks). * * FileLocks implemented via mandatory locking are reported * as held locks (errno == ENOTDIR). * * Results: * TRUE YES * FALSE NO; if err is not NULL may check *err for an error * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool FileLockIsLockedPortable(const char *lockDir, // IN: int *err) // OUT/OPT: { uint32 i; int numEntries; Bool isLocked = FALSE; char **fileList = NULL; numEntries = FileListDirectoryRobust(lockDir, &fileList); if (numEntries == -1) { /* * If the lock directory doesn't exist, we should not count this * as an error. This is expected if the file isn't locked. */ if (err != NULL) { *err = (errno == ENOENT) ? 0 : errno; } return FALSE; } for (i = 0; i < numEntries; i++) { if (*fileList[i] == 'M') { isLocked = TRUE; break; } } Util_FreeStringList(fileList, numEntries); return isLocked; } /* *----------------------------------------------------------------------------- * * FileLockIsLocked -- * * Is a file currently locked (at the time of the call)? * * Results: * TRUE YES * FALSE NO; if err is not NULL may check *err for an error * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool FileLockIsLocked(const char *pathName, // IN: int *err) // OUT/OPT: { Bool isLocked; char *lockBase; ASSERT(pathName != NULL); lockBase = Unicode_Append(pathName, FILELOCK_SUFFIX); if (File_SupportsMandatoryLock(pathName)) { isLocked = FileLockIsLockedMandatory(lockBase, err); } else { isLocked = FileLockIsLockedPortable(lockBase, err); } Posix_Free(lockBase); return isLocked; } /* *---------------------------------------------------------------------- * * FileLock_TokenPathName -- * * Return the path name associated with a lock (token). The path name * is returned as a dynamically allocated string the caller is * responsible for. * * Results: * As above * * Side effects: * None. * *---------------------------------------------------------------------- */ char * FileLock_TokenPathName(const FileLockToken *lockToken) // IN: { ASSERT(lockToken && (lockToken->signature == FILELOCK_TOKEN_SIGNATURE)); return Unicode_Duplicate(lockToken->pathName); } open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/filePosix.c000066400000000000000000002665701470176644300241340ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2006-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * filePosix.c -- * * Interface to Posix-specific file functions. */ #include /* Needed before sys/vfs.h with glibc 2.0 --hpreg */ #if defined(__FreeBSD__) # include # include #else # if !defined(__APPLE__) # include # endif # include # include /* Needed before sys/mnttab.h in Solaris */ # if defined(sun) # include # elif __APPLE__ # include # else # include # endif #include #endif #include #include #include #if !defined(__USE_ATFILE) #define __USE_ATFILE #endif #include /* Definition of AT_* constants */ #include #include #include #if defined(__linux__) # include #endif #if defined(__APPLE__) #include #endif #include "vmware.h" #include "posix.h" #include "codeset.h" #include "file.h" #include "fileInt.h" #include "msg.h" #include "util.h" #include "str.h" #include "util.h" #include "timeutil.h" #include "dynbuf.h" #include "hostType.h" #include "vmfs.h" #include "hashTable.h" #include "hostinfo.h" #include "log.h" #ifdef VMX86_SERVER #include "fs_public.h" #include "fs3Layout.h" #endif #define LOGLEVEL_MODULE main #include "loglevel_user.h" #include "unicodeOperations.h" #if !defined(__FreeBSD__) && !defined(sun) #if !defined(__APPLE__) static char *FilePosixLookupMountPoint(char const *canPath, Bool *bind); #endif static char *FilePosixNearestExistingAncestor(char const *path); #if defined(VMX86_SERVER) #define VMFS3CONST 256 #include "hostType.h" /* Needed for VMFS implementation of File_GetFreeSpace() */ # include # endif #endif #if defined(VMX86_SERVER) #include "fs_user.h" #endif struct WalkDirContextImpl { char *dirName; DIR *dir; HashTable *hash; }; /* A string for NFS on ESX file system type */ #define FS_NFS_PREFIX_LEN 3 #define FS_NFS_ON_ESX "NFS" /* A string for VMFS on ESX file system type */ #define FS_VMFS_ON_ESX "VMFS" /* A string for vsanD on ESX file system type */ #define FS_VSAND_ON_ESX "vsanD" #define FS_VSAN_URI_PREFIX "vsan:" #if defined __ANDROID__ /* * Android doesn't support setmntent(), endmntent() or MOUNTED. */ #define NO_SETMNTENT #define NO_ENDMNTENT #endif /* Long path chunk growth size */ #define FILE_PATH_GROW_SIZE 1024 /* *----------------------------------------------------------------------------- * * FileRemoveDirectory -- * * Delete a directory. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * May change the host file system. * *----------------------------------------------------------------------------- */ int FileRemoveDirectory(const char *pathName) // IN: { return (Posix_Rmdir(pathName) == -1) ? errno : 0; } /* *----------------------------------------------------------------------------- * * File_Rename -- * * Rename a file. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * May change the host file system. * *----------------------------------------------------------------------------- */ int File_Rename(const char *oldName, // IN: const char *newName) // IN: { return (Posix_Rename(oldName, newName) == -1) ? errno : 0; } int File_RenameRetry(const char *oldFile, // IN: const char *newFile, // IN: uint32 maxWaitTimeMsec) // IN: Unused. { return File_Rename(oldFile, newFile); } /* *---------------------------------------------------------------------- * * FileDeletion -- * Delete the specified file. A NULL pathName will result in an error * and errno will be set to EFAULT. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * May change the host file system. errno may be set. * *---------------------------------------------------------------------- */ int FileDeletion(const char *pathName, // IN: const Bool handleLink) // IN: { int err; if (pathName == NULL) { errno = EFAULT; return errno; } if (handleLink) { char *linkPath = Posix_ReadLink(pathName); if (linkPath == NULL) { /* If there is no link involved, continue */ err = errno; if (err != EINVAL) { goto bail; } } else { err = (Posix_Unlink(linkPath) == -1) ? errno : 0; Posix_Free(linkPath); /* Ignore a file that has already disappeared */ if (err != ENOENT) { goto bail; } } } err = (Posix_Unlink(pathName) == -1) ? errno : 0; bail: return err; } /* *----------------------------------------------------------------------------- * * File_UnlinkDelayed -- * * Same as File_Unlink for POSIX systems since we can unlink anytime. * * Results: * Return 0 if the unlink is successful. Otherwise, returns -1. * * Side effects: * None. * *----------------------------------------------------------------------------- */ int File_UnlinkDelayed(const char *pathName) // IN: { return (FileDeletion(pathName, TRUE) == 0) ? 0 : -1; } /* *----------------------------------------------------------------------------- * * FileAttributes -- * * Return the attributes of a file. Time units are in OS native time. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * None * *----------------------------------------------------------------------------- */ int FileAttributes(const char *pathName, // IN: FileData *fileData) // OUT: { int err; struct stat statbuf; if (Posix_Stat(pathName, &statbuf) == -1) { err = errno; } else { if (fileData != NULL) { fileData->fileCreationTime = statbuf.st_ctime; fileData->fileModificationTime = statbuf.st_mtime; fileData->fileAccessTime = statbuf.st_atime; fileData->fileSize = statbuf.st_size; switch (statbuf.st_mode & S_IFMT) { case S_IFREG: fileData->fileType = FILE_TYPE_REGULAR; break; case S_IFDIR: fileData->fileType = FILE_TYPE_DIRECTORY; break; case S_IFBLK: fileData->fileType = FILE_TYPE_BLOCKDEVICE; break; case S_IFCHR: fileData->fileType = FILE_TYPE_CHARDEVICE; break; case S_IFLNK: fileData->fileType = FILE_TYPE_SYMLINK; break; default: fileData->fileType = FILE_TYPE_UNCERTAIN; break; } fileData->fileMode = statbuf.st_mode; fileData->fileOwner = statbuf.st_uid; fileData->fileGroup = statbuf.st_gid; } err = 0; } return err; } /* *---------------------------------------------------------------------- * * File_IsRemote -- * * Determine whether a file is on a remote filesystem. * * On ESX all files are treated as local files, as all * callers of this function wants to do is to post message * that performance will be degraded on remote filesystems. * On ESX (a) performance should be acceptable with remote * files, and (b) even if it is not, we should not ask users * whether they are aware that it is poor. ESX has * performance monitoring which can notify user if something * is wrong. * * On hosted platform we report remote files as faithfully * as we can because having mainmem file on NFS is known * to badly affect VM consistency when NFS filesystem gets * reconnected. Due to that we are conservative, and report * filesystem as remote if there was some problem with * determining file remoteness. * * Results: * The answer. * * Side effects: * None * *---------------------------------------------------------------------- */ #if !defined(__FreeBSD__) && !defined(sun) Bool File_IsRemote(const char *pathName) // IN: Path name { if (HostType_OSIsVMK()) { /* * All files and file systems are treated as "directly attached" * on ESX. See bug 158284. */ return FALSE; } else { struct statfs sfbuf; if (Posix_Statfs(pathName, &sfbuf) == -1) { Log(LGPFX" %s: statfs(%s) failed: %s\n", __func__, pathName, Err_Errno2String(errno)); return TRUE; } #if defined(__APPLE__) return sfbuf.f_flags & MNT_LOCAL ? FALSE : TRUE; #else if (NFS_SUPER_MAGIC == sfbuf.f_type) { return TRUE; } if (SMB_SUPER_MAGIC == sfbuf.f_type) { return TRUE; } if (CIFS_SUPER_MAGIC == sfbuf.f_type) { return TRUE; } return FALSE; #endif } } #endif /* !FreeBSD && !sun */ /* *---------------------------------------------------------------------- * * File_IsSymLink -- * * Check if the specified file is a symbolic link or not * * Results: * Bool - TRUE -> is a symlink, FALSE -> not a symlink or error * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_IsSymLink(const char *pathName) // IN: { struct stat statbuf; return (Posix_Lstat(pathName, &statbuf) == 0) && S_ISLNK(statbuf.st_mode); } /* *---------------------------------------------------------------------- * * File_Cwd -- * * Find the current directory on drive DRIVE. DRIVE is either NULL * (current drive) or a string starting with [A-Za-z]. * * Results: * NULL if error. * * Side effects: * The result is allocated * *---------------------------------------------------------------------- */ char * File_Cwd(const char *drive) // IN: { size_t size; char *buffer; char *path; if ((drive != NULL) && !Unicode_IsEmpty(drive)) { Warning(LGPFX" %s: Drive letter %s on Linux?\n", __FUNCTION__, drive); } size = FILE_PATH_GROW_SIZE; buffer = Util_SafeMalloc(size); while (TRUE) { if (getcwd(buffer, size) != NULL) { break; } Posix_Free(buffer); buffer = NULL; if (errno != ERANGE) { break; } size += FILE_PATH_GROW_SIZE; buffer = Util_SafeMalloc(size); } if (buffer == NULL) { Msg_Append(MSGID(filePosix.getcwd) "Unable to retrieve the current working directory: %s. " "Check if the directory has been deleted or unmounted.\n", Msg_ErrString()); Warning(LGPFX" %s: getcwd() failed: %s\n", __FUNCTION__, Msg_ErrString()); return NULL; } path = Unicode_Alloc(buffer, STRING_ENCODING_DEFAULT); Posix_Free(buffer); return path; } /* *---------------------------------------------------------------------- * * File_StripFwdSlashes -- * * Returns a new string with the extraneous forward slashes ("/") removed. * * Results: * As documented. * * Side effects: * None * *---------------------------------------------------------------------- */ char * File_StripFwdSlashes(const char *pathName) // IN: { char *ptr; char *path; char *cptr; char *prev; char *result; ASSERT(pathName != NULL); path = Unicode_GetAllocBytes(pathName, STRING_ENCODING_UTF8); ASSERT(path != NULL); ptr = path; cptr = path; prev = NULL; /* * Copy over if not DIRSEPC. If yes, copy over only if previous * character was not DIRSEPC. */ while (*ptr != '\0') { if (*ptr == DIRSEPC) { if (prev != ptr - 1) { *cptr++ = *ptr; } prev = ptr; } else { *cptr++ = *ptr; } ptr++; } *cptr = '\0'; result = Unicode_AllocWithUTF8(path); Posix_Free(path); return result; } /* *---------------------------------------------------------------------- * * File_FullPath -- * * This routine computes the canonical path from a supplied path. * The supplied path could be an absolute path name or a relative * one, with our without symlinks and /./ /../ separators. A * canonical representation of a path is defined as an absolute * path without symlinks and /./ /../ separators. The canonical * path of "." is the current working directory, ".." is parent * directory and so on. If the path is NULL or "", this routine * returns the current working directory. * * On FreeBSD and Sun platforms, this routine will only work if * the path exists, or when we are about to create a child in an * existing parent directory. This is because on these platforms, * we cannot rely on finding existing ancestor and such because * those functions are not compiled. * * Results: * NULL if error (reported to the user) * * Side effects: * The result is allocated * *---------------------------------------------------------------------- */ char * File_FullPath(const char *pathName) // IN: { char *cwd; char *ret; if ((pathName != NULL) && File_IsFullPath(pathName)) { cwd = NULL; } else { cwd = File_Cwd(NULL); if (cwd == NULL) { return NULL; } } if ((pathName == NULL) || Unicode_IsEmpty(pathName)) { ret = Unicode_Duplicate(cwd); } else { char *path; if (File_IsFullPath(pathName)) { path = Unicode_Duplicate(pathName); } else { path = Unicode_Join(cwd, DIRSEPS, pathName, NULL); } ret = Posix_RealPath(path); if (ret == NULL) { char *dir; char *file; #if defined(__FreeBSD__) || defined(sun) char *realDir; #else char *ancestorPath; char *ancestorRealPath; #endif File_GetPathName(path, &dir, &file); #if defined(__FreeBSD__) || defined(sun) realDir = Posix_RealPath(dir); if (realDir == NULL) { realDir = File_StripFwdSlashes(dir); } ret = Unicode_Join(realDir, DIRSEPS, file, NULL); Posix_Free(realDir); #else ancestorPath = FilePosixNearestExistingAncestor(dir); ancestorRealPath = Posix_RealPath(ancestorPath); /* * Check if the ancestor was deleted before we could compute its * realPath */ if (ancestorRealPath == NULL) { ret = File_StripFwdSlashes(path); } else { ret = File_PathJoin(ancestorRealPath, path + strlen(ancestorPath)); Posix_Free(ancestorRealPath); } Posix_Free(ancestorPath); #endif Posix_Free(dir); Posix_Free(file); } Posix_Free(path); } Posix_Free(cwd); return ret; } /* *---------------------------------------------------------------------- * * File_IsFullPath -- * * Is this a full path? * * Results: * TRUE if full path. * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool File_IsFullPath(const char *pathName) // IN: { /* start with a slash? */ return pathName != NULL && pathName[0] == DIRSEPC; } /* *---------------------------------------------------------------------- * * File_GetTimes -- * * Get the date and time that a file was created, last accessed, * last modified and last attribute changed. * * Results: * TRUE if succeed or FALSE if error. * * Side effects: * If a particular time is not available, -1 will be returned for * that time. * *---------------------------------------------------------------------- */ Bool File_GetTimes(const char *pathName, // IN: VmTimeType *createTime, // OUT: Windows NT time format VmTimeType *accessTime, // OUT: Windows NT time format VmTimeType *writeTime, // OUT: Windows NT time format VmTimeType *attrChangeTime) // OUT: Windows NT time format { struct stat statBuf; ASSERT(createTime && accessTime && writeTime && attrChangeTime); *createTime = -1; *accessTime = -1; *writeTime = -1; *attrChangeTime = -1; if (Posix_Lstat(pathName, &statBuf) == -1) { Log(LGPFX" %s: error stating file \"%s\": %s\n", __FUNCTION__, pathName, Err_Errno2String(errno)); return FALSE; } /* * XXX We should probably use the MIN of all Unix times for the creation * time, so that at least times are never inconsistent in the * cross-platform format. Maybe atime is always that MIN. We should * check and change the code if it is not. * * XXX atime is almost always MAX. */ #if defined(__FreeBSD__) /* * FreeBSD: All supported versions have timestamps with nanosecond * resolution. */ *createTime = TimeUtil_UnixTimeToNtTime(statBuf.st_birthtimespec); *accessTime = TimeUtil_UnixTimeToNtTime(statBuf.st_atimespec); *writeTime = TimeUtil_UnixTimeToNtTime(statBuf.st_mtimespec); *attrChangeTime = TimeUtil_UnixTimeToNtTime(statBuf.st_ctimespec); #elif defined(__linux__) /* * Linux: Glibc 2.3+ has st_Xtim. Glibc 2.1/2.2 has st_Xtime/__unusedX on * same place (see below). We do not support Glibc 2.0 or older. */ # if (__GLIBC__ == 2) && (__GLIBC_MINOR__ < 3) && !defined(__UCLIBC__) { /* * stat structure is same between glibc 2.3 and older glibcs, just * these __unused fields are always zero. If we'll use __unused* * instead of zeroes, we get automatically nanosecond timestamps * when running on host which provides them. */ struct timespec timeBuf; timeBuf.tv_sec = statBuf.st_atime; timeBuf.tv_nsec = statBuf.__unused1; *accessTime = TimeUtil_UnixTimeToNtTime(timeBuf); timeBuf.tv_sec = statBuf.st_mtime; timeBuf.tv_nsec = statBuf.__unused2; *writeTime = TimeUtil_UnixTimeToNtTime(timeBuf); timeBuf.tv_sec = statBuf.st_ctime; timeBuf.tv_nsec = statBuf.__unused3; *attrChangeTime = TimeUtil_UnixTimeToNtTime(timeBuf); } # elif defined(__ANDROID__) { struct timespec timeBuf; timeBuf.tv_sec = statBuf.st_atime; timeBuf.tv_nsec = statBuf.st_atime_nsec; *accessTime = TimeUtil_UnixTimeToNtTime(timeBuf); timeBuf.tv_sec = statBuf.st_mtime; timeBuf.tv_nsec = statBuf.st_mtime_nsec; *writeTime = TimeUtil_UnixTimeToNtTime(timeBuf); timeBuf.tv_sec = statBuf.st_ctime; timeBuf.tv_nsec = statBuf.st_ctime_nsec; *attrChangeTime = TimeUtil_UnixTimeToNtTime(timeBuf); } # else *accessTime = TimeUtil_UnixTimeToNtTime(statBuf.st_atim); *writeTime = TimeUtil_UnixTimeToNtTime(statBuf.st_mtim); *attrChangeTime = TimeUtil_UnixTimeToNtTime(statBuf.st_ctim); # endif #elif defined(__APPLE__) /* Mac: No file create timestamp. */ *accessTime = TimeUtil_UnixTimeToNtTime(statBuf.st_atimespec); *writeTime = TimeUtil_UnixTimeToNtTime(statBuf.st_mtimespec); *attrChangeTime = TimeUtil_UnixTimeToNtTime(statBuf.st_ctimespec); #else { /* Solaris: No nanosecond timestamps, no file create timestamp. */ struct timespec timeBuf; timeBuf.tv_nsec = 0; timeBuf.tv_sec = statBuf.st_atime; *accessTime = TimeUtil_UnixTimeToNtTime(timeBuf); timeBuf.tv_sec = statBuf.st_mtime; *writeTime = TimeUtil_UnixTimeToNtTime(timeBuf); timeBuf.tv_sec = statBuf.st_ctime; *attrChangeTime = TimeUtil_UnixTimeToNtTime(timeBuf); } #endif return TRUE; } /* *---------------------------------------------------------------------- * * FileSetTimes -- * * Set the date and time that a file was last accessed or last * modified. * * Results: * TRUE Success * FALSE Failure * * Side effects: * If fileName is a symlink, target's timestamps will be updated. * Symlink itself's timestamps will not be changed. * *---------------------------------------------------------------------- */ static Bool FileSetTimes(const char *path, // IN: VmTimeType accessTime, // IN: Windows NT time format VmTimeType writeTime) // IN: Windows NT time format #if defined(UTIME_NOW) && defined(UTIME_OMIT) { struct timespec times[2]; if (accessTime > 0) { TimeUtil_NtTimeToUnixTime(×[0], accessTime); } else { times[0].tv_sec = 0; times[0].tv_nsec = UTIME_OMIT; } if (writeTime > 0) { TimeUtil_NtTimeToUnixTime(×[1], writeTime); } else { times[1].tv_sec = 0; times[1].tv_nsec = UTIME_OMIT; } return utimensat(0, path, times, 0) == 0 ? TRUE : FALSE; } #else { struct stat statBuf; struct timeval times[2]; struct timeval *aTime, *wTime; int err = (lstat(path, &statBuf) == -1) ? errno : 0; if (err != 0) { Log(LGPFX" %s: error stating file \"%s\": %s\n", __FUNCTION__, path, Err_Errno2String(err)); return FALSE; } aTime = ×[0]; wTime = ×[1]; /* * Preserve old times if new time <= 0. * XXX Need a better implementation to preserve tv_usec. */ aTime->tv_sec = statBuf.st_atime; aTime->tv_usec = 0; wTime->tv_sec = statBuf.st_mtime; wTime->tv_usec = 0; if (accessTime > 0) { struct timespec ts; TimeUtil_NtTimeToUnixTime(&ts, accessTime); aTime->tv_sec = ts.tv_sec; aTime->tv_usec = ts.tv_nsec / 1000; } if (writeTime > 0) { struct timespec ts; TimeUtil_NtTimeToUnixTime(&ts, writeTime); wTime->tv_sec = ts.tv_sec; wTime->tv_usec = ts.tv_nsec / 1000; } err = (utimes(path, times) == -1) ? errno : 0; if (err != 0) { Log(LGPFX" %s: utimes error on file \"%s\": %s\n", __FUNCTION__, path, Err_Errno2String(err)); return FALSE; } return TRUE; } #endif /* *---------------------------------------------------------------------- * * File_SetTimes -- * * Set the date and time that a file was last accessed or last * modified. * * Results: * TRUE Success * FALSE Failure * * Side effects: * If fileName is a symlink, target's timestamps will be updated. * Symlink itself's timestamps will not be changed. * *---------------------------------------------------------------------- */ Bool File_SetTimes(const char *pathName, // IN: VmTimeType createTime, // IN: ignored VmTimeType accessTime, // IN: Windows NT time format VmTimeType writeTime, // IN: Windows NT time format VmTimeType attrChangeTime) // IN: ignored { char *path; Bool success; char *fullPath; if (pathName == NULL) { errno = EINVAL; // Invalid parameter return FALSE; } if ((accessTime == 0) && (writeTime == 0)) { return TRUE; } fullPath = File_FullPath(pathName); if (fullPath == NULL) { return FALSE; } path = Unicode_GetAllocBytes(fullPath, STRING_ENCODING_DEFAULT); Posix_Free(fullPath); if (path == NULL) { Log(LGPFX" %s: failed to convert \"%s\" to current encoding\n", __FUNCTION__, pathName); return FALSE; } success = FileSetTimes(path, accessTime, writeTime); Posix_Free(path); return success; } /* *---------------------------------------------------------------------- * * File_SetFilePermissions -- * * Set file permissions. * * Results: * TRUE if succeed or FALSE if error. * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool File_SetFilePermissions(const char *pathName, // IN: int perms) // IN: permissions { ASSERT(pathName != NULL); if (Posix_Chmod(pathName, perms) == -1) { /* The error is not critical, just log it. */ Log(LGPFX" %s: failed to change permissions on file \"%s\": %s\n", __FUNCTION__, pathName, Err_Errno2String(errno)); return FALSE; } return TRUE; } #if !defined(__FreeBSD__) && !defined(sun) /* *----------------------------------------------------------------------------- * * FilePosixGetParent -- * * The input buffer is a canonical path name. Change it in place to the * canonical path name of its parent directory. * * Although this code is quite simple, we encapsulate it in a function * because it is easy to get it wrong. * * Results: * TRUE The input buffer was (and remains) the root directory. * FALSE The input buffer was not the root directory and was changed in * place to its parent directory. * * Example: "/foo/bar" -> "/foo" FALSE * "/foo" -> "/" FALSE * "/" -> "/" TRUE * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool FilePosixGetParent(char **canPath) // IN/OUT: Canonical file path { char *pathName; char *baseName; ASSERT(canPath != NULL); ASSERT(File_IsFullPath(*canPath)); if (Unicode_Compare(*canPath, DIRSEPS) == 0) { return TRUE; } File_GetPathName(*canPath, &pathName, &baseName); Posix_Free(*canPath); if (Unicode_IsEmpty(pathName)) { /* empty string which denotes "/" */ Posix_Free(pathName); *canPath = Unicode_Duplicate("/"); } else { if (Unicode_IsEmpty(baseName)) { // Directory File_GetPathName(pathName, canPath, NULL); Posix_Free(pathName); } else { // File *canPath = pathName; } } Posix_Free(baseName); return FALSE; } /* *----------------------------------------------------------------------------- * * File_GetParent -- * * The input buffer is a canonical path name. Change it in place to the * canonical path name of its parent directory. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool File_GetParent(char **canPath) // IN/OUT: Canonical file path { return FilePosixGetParent(canPath); } #if !defined(__APPLE__) || TARGET_OS_IPHONE /* *---------------------------------------------------------------------- * * FileGetStats -- * * Calls statfs on a full path (eg. something returned from File_FullPath). * If doNotAscend is FALSE, climb up the directory chain and call statfs * on each level until it succeeds. * * Results: * TRUE statfs succeeded * FALSE unable to statfs anything along the path * * Side effects: * None * *---------------------------------------------------------------------- */ Bool FileGetStats(const char *pathName, // IN: Bool doNotAscend, // IN: struct statfs *pstatfsbuf) // OUT: { Bool retval = TRUE; char *dupPath = NULL; while (Posix_Statfs(dupPath ? dupPath : pathName, pstatfsbuf) == -1) { if (errno != ENOENT || doNotAscend) { retval = FALSE; break; } if (dupPath == NULL) { /* Dup fullPath, so as not to modify input parameters */ dupPath = Unicode_Duplicate(pathName); } FilePosixGetParent(&dupPath); } Posix_Free(dupPath); return retval; } /* *---------------------------------------------------------------------- * * File_GetFreeSpace -- * * Return the free space (in bytes) available to the user on a disk where * a file is or would be. If doNotAscend is FALSE, the helper function * ascends the directory chain on system call errors in order to obtain * the file system information. * * Results: * -1 if error (reported to the user) * * Side effects: * None * *---------------------------------------------------------------------- */ uint64 File_GetFreeSpace(const char *pathName, // IN: File name Bool doNotAscend) // IN: Do not ascend dir chain { uint64 ret; char *fullPath; struct statfs statfsbuf; fullPath = File_FullPath(pathName); if (fullPath == NULL) { return -1; } if (FileGetStats(fullPath, doNotAscend, &statfsbuf)) { ret = (uint64) statfsbuf.f_bavail * statfsbuf.f_bsize; // available space } else { Warning("%s: Couldn't statfs %s\n", __func__, fullPath); ret = -1; } Posix_Free(fullPath); return ret; } #endif #if defined(VMX86_SERVER) /* *---------------------------------------------------------------------- * * File_GetVMFSAttributes -- * * Acquire the attributes for a given file or directory on a VMFS volume. * * Results: * Integer return value and populated FS_PartitionListResult * * Side effects: * Will fail if file is not on VMFS or not enough memory for partition * query results * *---------------------------------------------------------------------- */ int File_GetVMFSAttributes(const char *pathName, // IN: File/dir to test FS_PartitionListResult **fsAttrs) // IN/OUT: VMFS Info { int fd; int ret; char *fullPath; char *directory = NULL; fullPath = File_FullPath(pathName); if (fullPath == NULL) { ret = -1; goto bail; } if (File_IsDirectory(fullPath)) { directory = Unicode_Duplicate(fullPath); } else { File_SplitName(fullPath, NULL, &directory, NULL); } if (!HostType_OSIsVMK()) { Log(LGPFX" %s: File %s not on VMFS volume\n", __func__, pathName); ret = -1; goto bail; } *fsAttrs = Util_SafeMalloc(FS_PARTITION_ARR_SIZE(FS_PLIST_DEF_MAX_PARTITIONS)); memset(*fsAttrs, 0, FS_PARTITION_ARR_SIZE(FS_PLIST_DEF_MAX_PARTITIONS)); (*fsAttrs)->ioctlAttr.maxPartitions = FS_PLIST_DEF_MAX_PARTITIONS; (*fsAttrs)->ioctlAttr.getAttrSpec = FS_ATTR_SPEC_BASIC; fd = Posix_Open(directory, O_RDONLY, 0); if (fd == -1) { Log(LGPFX" %s: could not open %s: %s\n", __func__, pathName, Err_Errno2String(errno)); ret = -1; Posix_Free(*fsAttrs); *fsAttrs = NULL; goto bail; } ret = ioctl(fd, IOCTLCMD_VMFS_FS_GET_ATTR, (char *) *fsAttrs); if (ret == -1) { Log(LGPFX" %s: Could not get volume attributes (ret = %d): %s\n", __func__, ret, Err_Errno2String(errno)); Posix_Free(*fsAttrs); *fsAttrs = NULL; } close(fd); bail: Posix_Free(fullPath); Posix_Free(directory); return ret; } /* *---------------------------------------------------------------------- * * File_GetVMFSFSType -- * * Get the filesystem type number of the file system on which the * given file/directory resides. * * Callers can specify either a pathname, or an already opened fd, * of the file/dir whose filesystem they want to determine. * 'fd' takes precedence over 'pathName', so 'pathName' is used only * if 'fd' is -1. * * Results: * On success : return value 0 and file type number in 'fsTypeNum'. * On failure : return value -1 (errno will be set appropriately). * * Side effects: * On failure errno will be set. * *---------------------------------------------------------------------- */ int File_GetVMFSFSType(const char *pathName, // IN: File name to test int fd, // IN: fd of an already opened file uint16 *fsTypeNum) // OUT: Filesystem type number { int ret, savedErrno; Bool fdArg = (fd >= 0); /* fd or pathname ? */ if (!fsTypeNum || (!fdArg && !pathName)) { savedErrno = EINVAL; goto exit; } if (!fdArg) { fd = Posix_Open(pathName, O_RDONLY, 0); if (fd < 0) { savedErrno = errno; Log(LGPFX" %s : Could not open %s : %s\n", __func__, pathName, Err_Errno2String(savedErrno)); goto exit; } } ret = ioctl(fd, IOCTLCMD_VMFS_GET_FSTYPE, fsTypeNum); /* * Save errno to avoid close() affecting it. */ savedErrno = errno; if (!fdArg) { close(fd); } if (ret == -1) { Log(LGPFX" %s : Could not get filesystem type for %s (fd %d) : %s\n", __func__, (!fdArg ? pathName : "__na__"), fd, Err_Errno2String(savedErrno)); goto exit; } return 0; exit: errno = savedErrno; ASSERT(errno != 0); return -1; } /* *---------------------------------------------------------------------- * * File_GetVMFSVersion -- * * Get the version number of the VMFS file system on which the * given file resides. * * Results: * Integer return value and version number. * * Side effects: * Will fail if file is not on VMFS or not enough memory for partition * query results. * *---------------------------------------------------------------------- */ int File_GetVMFSVersion(const char *pathName, // IN: File name to test uint32 *versionNum) // OUT: Version number { int ret = -1; FS_PartitionListResult *fsAttrs = NULL; if (versionNum == NULL) { errno = EINVAL; goto exit; } ret = File_GetVMFSAttributes(pathName, &fsAttrs); if (ret < 0) { Log(LGPFX" %s: File_GetVMFSAttributes failed\n", __func__); } else { *versionNum = fsAttrs->versionNumber; } if (fsAttrs) { Posix_Free(fsAttrs); } exit: return ret; } /* *---------------------------------------------------------------------- * * File_GetVMFSBlockSize -- * * Acquire the blocksize for a given file on a VMFS file system. * * Results: * Integer return value and block size * * Side effects: * Will fail if file is not on VMFS or not enough memory for partition * query results * *---------------------------------------------------------------------- */ int File_GetVMFSBlockSize(const char *pathName, // IN: File name to test uint32 *blockSize) // IN/OUT: VMFS block size { int ret = -1; FS_PartitionListResult *fsAttrs = NULL; if (blockSize == NULL) { errno = EINVAL; goto exit; } ret = File_GetVMFSAttributes(pathName, &fsAttrs); if (ret < 0) { Log(LGPFX" %s: File_GetVMFSAttributes failed\n", __func__); } else { *blockSize = fsAttrs->fileBlockSize; } if (fsAttrs) { Posix_Free(fsAttrs); } exit: return ret; } /* *---------------------------------------------------------------------- * * File_GetVMFSMountInfo -- * * Acquire the FS mount point info such as fsType, major version, * local mount point (/vmfs/volumes/xyz), and for NFS, * remote IP and remote mount point for a given file. * * Results: * Integer return value and allocated data * * Side effects: * Only implemented on ESX. Will fail on other platforms. * remoteIP and remoteMountPoint are only populated for files on NFS. * *---------------------------------------------------------------------- */ int File_GetVMFSMountInfo(const char *pathName, // IN: char **fsType, // OUT: uint32 *version, // OUT: char **remoteIP, // OUT: char **remoteMountPoint, // OUT: char **localMountPoint) // OUT: { int ret; FS_PartitionListResult *fsAttrs = NULL; *localMountPoint = File_GetUniqueFileSystemID(pathName); if (*localMountPoint == NULL) { return -1; } /* Get file IP and mount point */ ret = File_GetVMFSAttributes(pathName, &fsAttrs); if (ret >= 0 && fsAttrs) { *version = fsAttrs->versionNumber; *fsType = Util_SafeStrdup(fsAttrs->fsType); /* * We only compare the first 3 characters 'NFS'xx. * This will cover both NFSv3 and NFSv4.1. */ if (strncmp(fsAttrs->fsType, FS_NFS_ON_ESX, FS_NFS_PREFIX_LEN) == 0) { char *sep = strchr(fsAttrs->logicalDevice, ' '); if (sep) { *sep++ = 0; *remoteIP = Util_SafeStrdup(fsAttrs->logicalDevice); *remoteMountPoint = Util_SafeStrdup(sep); } else { *remoteIP = NULL; *remoteMountPoint = NULL; } } else { *remoteIP = NULL; *remoteMountPoint = NULL; } Posix_Free(fsAttrs); } return ret; } /* *---------------------------------------------------------------------- * * File_GetVMFSLockInfo -- * * Get lock information about a file that has probably caused a * locking conflict. * * If the file is locked by a process local to the current host, * FS open flags, world ID, and world name will be returned (or * 0/NULL if not). * * If the file is on VMFS, the owner MAC address and lock mode of * the on-disk lock will be provided (or 0/NULL if not). * * (It's possible for a file to be on a non-VMFS shared datastore * like NFS/VVol/VSAN and be locked by another host. In that * case, this function might not return any information.) * * Results: * 0 on success (and see above), -1 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int File_GetVMFSLockInfo(const char *path, // IN uint32 *outOpenFlags, // OUT: uint32 *outWorldID, // OUT: char **outWorldName, // OUT: char **outVMFSMacAddr, // OUT: uint32 *outVMFSLockMode) // OUT: { int ret = -1; int ioctlRet; int fd = -1; FS_GetFileLockInfoArgs lockArgs; FS_DumpFDData dumpArgs; char *dir = NULL; char *fileName = NULL; *outOpenFlags = 0; *outWorldID = INVALID_WORLD_ID; *outWorldName = NULL; *outVMFSMacAddr = NULL; *outVMFSLockMode = 0; memset(&lockArgs, 0, sizeof lockArgs); memset(&dumpArgs, 0, sizeof dumpArgs); File_SplitName(path, NULL, &dir, &fileName); fd = Posix_Open(dir, O_RDONLY, 0); if (fd == -1) { Log(LGPFX" %s: could not open directory \"%s\": %s\n", __FUNCTION__, dir, Err_Errno2String(errno)); goto exit; } Str_Strncpy(lockArgs.fileName, sizeof lockArgs.fileName, fileName, strlen(fileName)); ioctlRet = ioctl(fd, IOCTLCMD_GETFILELOCKINFO, (char *)&lockArgs); /* If this fails, it might be open only on another machine. */ if (ioctlRet != -1) { *outOpenFlags = lockArgs.openFlags; *outWorldID = lockArgs.worldID; *outWorldName = Util_SafeStrdup(lockArgs.worldName); } Str_Strncpy(dumpArgs.args.fileName, sizeof dumpArgs.args.fileName, fileName, strlen(fileName)); ioctlRet = ioctl(fd, IOCTLCMD_VMFS_DUMP_METADATA, (char *)&dumpArgs); /* If this fails, it probably isn't on VMFS. */ if (ioctlRet != -1) { FS3_FileDescriptor *fileDesc = (FS3_FileDescriptor *)&dumpArgs.result.descriptor; FS3_DiskLock *diskLock = FS3_DISKLOCK(&fileDesc->lockBlock); const UUID *theOwner; if (dumpArgs.result.descriptorLength < sizeof(FS3_FileDescriptor)) { /* This should not happen. */ Log(LGPFX" %s: VMFS file descriptor size %u too small (need " "%"FMTSZ"u) for file \"%s\"\n", __FUNCTION__, dumpArgs.result.descriptorLength, sizeof(FS3_FileDescriptor), path); goto exit; } *outVMFSLockMode = diskLock->mode; if (diskLock->mode != FS3_LC_FREE && diskLock->mode != FS3_LC_EXCLUSIVE) { /* * This is a non-exclusive lock. Thus it can have multiple holders. * For now, return only the first. */ if (diskLock->numHolders > FS3_MAX_LOCK_HOLDERS) { Log(LGPFX" %s: Corrupt VMFS disk lock found for file \"%s\", " "invalid number of holders %u.\n", __FUNCTION__, path, diskLock->numHolders); goto exit; } if (diskLock->numHolders == 0) { theOwner = &diskLock->owner; } else { theOwner = &diskLock->holders[0].uid; } } else { /* Exclusive lock, so there is only one owner. */ theOwner = &diskLock->owner; } *outVMFSMacAddr = Str_SafeAsprintf(NULL, "%02x:%02x:%02x:%02x:%02x:%02x", theOwner->macAddr[0], theOwner->macAddr[1], theOwner->macAddr[2], theOwner->macAddr[3], theOwner->macAddr[4], theOwner->macAddr[5]); } ret = 0; exit: if (fd != -1) { close(fd); } free(dir); free(fileName); return ret; } /* *--------------------------------------------------------------------------- * * File_DoesVolumeSupportConvertBlocks -- * * Does the volume support the new convert block allocation * IOCTL? (Always FALSE for now on non-VMFS.) * * Results: * TRUE Yes * FALSE No * * Side effects: * None * *--------------------------------------------------------------------------- */ Bool File_DoesVolumeSupportConvertBlocks(const char *pathName) // IN: { Bool supports; FS_PartitionListResult *fsAttrs = NULL; int ret = File_GetVMFSAttributes(pathName, &fsAttrs); if (ret < 0) { /* Probably not VMFS. */ return FALSE; } /* * Only regular VMFS (no VMFS-L, VMFSOS, or other oddities) and * only version 6 and above. Also, no VMFS on VSAN/VVol objects. */ supports = Str_Strcmp(fsAttrs->fsType, FS_VMFS_ON_ESX) == 0 && fsAttrs->versionNumber >= 6 && strcmp(fsAttrs->driverType, "vsan") != 0 && strcmp(fsAttrs->driverType, "vvol") != 0; Posix_Free(fsAttrs); return supports; } #endif // VMX86_SERVER /* *---------------------------------------------------------------------- * * FileIsVMFS -- * * Is the given file on a filesystem that supports vmfs-specific * features like zeroed-thick and multiwriter files? * * Results: * TRUE if we're on VMFS. * * Side effects: * None * *---------------------------------------------------------------------- */ static Bool FileIsVMFS(const char *pathName) // IN: { Bool result = FALSE; #if defined(VMX86_SERVER) /* Right now only VMFS supports zeroedThick and multiWriter. */ FS_PartitionListResult *fsAttrs = NULL; if (File_GetVMFSAttributes(pathName, &fsAttrs) >= 0) { /* We want to match anything that starts with VMFS */ result = strncmp(fsAttrs->fsType, FS_VMFS_ON_ESX, strlen(FS_VMFS_ON_ESX)) == 0; if (!result) { result = strncmp(fsAttrs->fsType, FS_VSAND_ON_ESX, strlen(FS_VSAND_ON_ESX)) == 0; } } else { Log(LGPFX" %s: File_GetVMFSAttributes failed\n", __func__); } if (fsAttrs) { Posix_Free(fsAttrs); } #endif return result; } /* *---------------------------------------------------------------------- * * File_SupportsZeroedThick -- * * Check if the given file is on an FS supports creation of * the zeroed-thick files. * Currently only VMFS on ESX does support zeroed-thick files, but * this may change in the future. * * Results: * TRUE if FS supports creation of the zeroed-thick files. * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_SupportsZeroedThick(const char *pathName) // IN: { return FileIsVMFS(pathName); } /* *---------------------------------------------------------------------- * * File_SupportsMultiWriter -- * * Check if the given file is on an FS supports opening files * in multi-writer mode. * Currently only VMFS on ESX supports multi-writer mode, but * this may change in the future. * * Results: * TRUE if FS supports opening files in multi-writer mode. * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_SupportsMultiWriter(const char *pathName) // IN: { return FileIsVMFS(pathName); } /* *---------------------------------------------------------------------- * * File_SupportsOptimisticLock -- * * Return TRUE if the given file is on an FS that supports the * FILEIO_OPEN_OPTIMISTIC_LOCK flag (only VMFS). * * Results: * See above. * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool File_SupportsOptimisticLock(const char *pathName) // IN: { #ifdef VMX86_SERVER uint16 fsTypeNum; char *dir; char *tempPath = NULL; const char *fullPath; int res; /* * File_GetVMFSFSType works much faster on directories, so get the * directory. */ if (File_IsFullPath(pathName)) { fullPath = pathName; } else { tempPath = File_FullPath(pathName); fullPath = tempPath; } File_GetPathName(fullPath, &dir, NULL); res = File_GetVMFSFSType(dir, -1, &fsTypeNum); Posix_Free(tempPath); Posix_Free(dir); return (res == 0) ? IS_VMFS_FSTYPENUM(fsTypeNum) : FALSE; #else return FALSE; #endif } #if !defined(__APPLE__) || TARGET_OS_IPHONE /* *---------------------------------------------------------------------- * * File_GetCapacity -- * * Return the total capacity (in bytes) of the file system that the * specified file resides on. This is not be confused with the * amount of free space available in the file system the specified * file resides on. * * Results: * -1 if error (reported to the user) * * Side effects: * None * *---------------------------------------------------------------------- */ uint64 File_GetCapacity(const char *pathName) // IN: Path name { uint64 ret; char *fullPath; struct statfs statfsbuf; fullPath = File_FullPath(pathName); if (fullPath == NULL) { return -1; } if (FileGetStats(fullPath, FALSE, &statfsbuf)) { ret = (uint64) statfsbuf.f_blocks * statfsbuf.f_bsize; // FS size } else { Warning(LGPFX" %s: Couldn't statfs\n", __func__); ret = -1; } Posix_Free(fullPath); return ret; } #endif /* *----------------------------------------------------------------------------- * * File_GetUniqueFileSystemID -- * * Returns a string which uniquely identifies the underlying filesystem * for a given path. * * 'path' can be relative (including empty) or absolute, and any number * of non-existing components at the end of 'path' are simply ignored. * * XXX: On POSIX systems, we choose the underlying device's name as the * unique ID. I make no claim that this is 100% unique so if you * need this functionality to be 100% perfect, I suggest you think * about it more deeply than I did. -meccleston * * Results: * On success: Allocated and NUL-terminated filesystem ID. * On failure: NULL. * * Side effects: * None * *----------------------------------------------------------------------------- */ char * File_GetUniqueFileSystemID(char const *path) // IN: File path { #ifdef VMX86_SERVER char vmfsVolumeName[FILE_MAXPATH]; char *existPath; char *canPath; existPath = FilePosixNearestExistingAncestor(path); canPath = Posix_RealPath(existPath); /* * Returns "/vmfs/devices" for DEVFS. Since /vmfs/devices is symbol linker, * We don't use realpath here. */ if (strncmp(existPath, DEVFS_MOUNT_POINT, strlen(DEVFS_MOUNT_POINT)) == 0) { char devfsName[FILE_MAXPATH]; if (sscanf(existPath, DEVFS_MOUNT_PATH "%[^/]%*s", devfsName) == 1) { Posix_Free(existPath); Posix_Free(canPath); return Str_SafeAsprintf(NULL, "%s/%s", DEVFS_MOUNT_POINT, devfsName); } } Posix_Free(existPath); if (canPath == NULL) { return NULL; } /* * VCFS doesn't have real mount points, so the mount point lookup below * returns "/vmfs", instead of the VCFS mount point. * * See bug 61646 for why we care. */ if (strncmp(canPath, VCFS_MOUNT_POINT, strlen(VCFS_MOUNT_POINT)) != 0 || sscanf(canPath, VCFS_MOUNT_PATH "%[^/]%*s", vmfsVolumeName) != 1) { Posix_Free(canPath); goto exit; } /* * If the path points to a file or directory that is on a vsan datastore, * we have to determine which namespace object is involved. */ if (strncmp(vmfsVolumeName, FS_VSAN_URI_PREFIX, strlen(FS_VSAN_URI_PREFIX)) == 0) { FS_PartitionListResult *fsAttrs = NULL; int res; res = File_GetVMFSAttributes(canPath, &fsAttrs); if (res >= 0 && fsAttrs != NULL && strncmp(fsAttrs->fsType, FS_VMFS_ON_ESX, strlen(FS_VMFS_ON_ESX)) == 0) { char *unique; unique = Str_SafeAsprintf(NULL, "%s/%s/%s", VCFS_MOUNT_POINT, vmfsVolumeName, fsAttrs->name); Posix_Free(fsAttrs); Posix_Free(canPath); return unique; } Posix_Free(fsAttrs); } Posix_Free(canPath); return Str_SafeAsprintf(NULL, "%s/%s", VCFS_MOUNT_POINT, vmfsVolumeName); exit: #endif return FilePosixGetBlockDevice(path); } #if !defined(__APPLE__) /* *----------------------------------------------------------------------------- * * FilePosixLookupMountPoint -- * * Looks up passed in canonical file path in list of mount points. * If there is a match, it returns the underlying device name of the * mount point along with a flag indicating whether the mount point is * mounted with the "--[r]bind" option. * * Results: * On success: The allocated, NUL-terminated mounted "device". * On failure: NULL. * * Side effects: * None * *----------------------------------------------------------------------------- */ static char * FilePosixLookupMountPoint(char const *canPath, // IN: Canonical file path Bool *bind) // OUT: Mounted with --[r]bind? { #if defined NO_SETMNTENT || defined NO_ENDMNTENT NOT_IMPLEMENTED(); errno = ENOSYS; return NULL; #else FILE *f; struct mntent mnt; char *buf; size_t size; size_t used; char *ret = NULL; ASSERT(canPath != NULL); ASSERT(bind != NULL); size = 4 * FILE_MAXPATH; // Should suffice for most locales retry: f = setmntent(MOUNTED, "r"); if (f == NULL) { return NULL; } buf = Util_SafeMalloc(size); while (Posix_Getmntent_r(f, &mnt, buf, size) != NULL) { /* * Our Posix_Getmntent_r graciously sets errno when the buffer * is too small, but on UTF-8 based platforms Posix_Getmntent_r * is #defined to the system's getmntent_r, which can simply * truncate the strings with no other indication. See how much * space it used and increase the buffer size if needed. Note * that if some of the strings are empty, they may share a * common nul in the buffer, and the resulting size calculation * will be a little over-zealous. */ used = 0; if (mnt.mnt_fsname) { used += strlen(mnt.mnt_fsname) + 1; } if (mnt.mnt_dir) { used += strlen(mnt.mnt_dir) + 1; } if (mnt.mnt_type) { used += strlen(mnt.mnt_type) + 1; } if (mnt.mnt_opts) { used += strlen(mnt.mnt_opts) + 1; } if (used >= size || !mnt.mnt_fsname || !mnt.mnt_dir || !mnt.mnt_type || !mnt.mnt_opts) { size += 4 * FILE_MAXPATH; ASSERT(size <= 32 * FILE_MAXPATH); Posix_Free(buf); endmntent(f); goto retry; } /* * NB: A call to realpath is not needed as getmntent() already * returns it in canonical form. Additionally, it is bad * to call realpath() as often a mount point is down, and * realpath calls stat which can block trying to stat * a filesystem that the caller of the function is not at * all expecting. */ if (strcmp(mnt.mnt_dir, canPath) == 0) { /* * The --bind and --rbind options behave differently. See * FilePosixGetBlockDevice() for details. * * Sadly (I blame a bug in 'mount'), there is no way to tell them * apart in /etc/mtab: the option recorded there is, in both cases, * always "bind". */ *bind = strstr(mnt.mnt_opts, "bind") != NULL; ret = Util_SafeStrdup(mnt.mnt_fsname); break; } } // 'canPath' is not a mount point. endmntent(f); Posix_Free(buf); return ret; #endif } #endif /* *----------------------------------------------------------------------------- * * FilePosixGetBlockDevice -- * * Retrieve the block device that backs file path 'path'. * * 'path' can be relative (including empty) or absolute, and any number of * non-existing components at the end of 'path' are simply ignored. * * Results: * On success: The allocated, NUL-terminated block device absolute path. * On failure: NULL. * * Side effects: * None * *----------------------------------------------------------------------------- */ char * FilePosixGetBlockDevice(char const *path) // IN: File path { char *existPath; Bool failed; #if defined(__APPLE__) struct statfs buf; #else char canPath[FILE_MAXPATH]; char canPath2[FILE_MAXPATH]; unsigned int retries = 0; char *realPath; #endif existPath = FilePosixNearestExistingAncestor(path); #if defined(__APPLE__) failed = statfs(existPath, &buf) == -1; Posix_Free(existPath); if (failed) { return NULL; } return Util_SafeStrdup(buf.f_mntfromname); #else realPath = Posix_RealPath(existPath); Posix_Free(existPath); if (realPath == NULL) { return NULL; } Str_Strcpy(canPath, realPath, sizeof canPath); Posix_Free(realPath); retry: Str_Strcpy(canPath2, canPath, sizeof canPath2); /* Find the nearest ancestor of 'canPath' that is a mount point. */ for (;;) { char *x; Bool bind = FALSE; char *ptr; ptr = FilePosixLookupMountPoint(canPath, &bind); if (ptr) { if (bind) { /* * 'canPath' is a mount point mounted with --[r]bind. This is the * mount equivalent of a hard link. Follow the rabbit... * * --bind and --rbind behave differently. Consider this mount * table: * * /dev/sda1 / ext3 * exit14:/vol/vol0/home /exit14/home nfs * / /bind (mounted with --bind) * / /rbind (mounted with --rbind) * * then what we _should_ return for these paths is: * * /bind/exit14/home -> /dev/sda1 * /rbind/exit14/home -> exit14:/vol/vol0/home * * XXX but currently because we cannot easily tell the difference, * we always assume --rbind and we return: * * /bind/exit14/home -> exit14:/vol/vol0/home * /rbind/exit14/home -> exit14:/vol/vol0/home */ Bool rbind = TRUE; if (rbind) { /* * Compute 'canPath = ptr + (canPath2 - canPath)' using and * preserving the structural properties of all canonical * paths involved in the expression. */ size_t canPathLen = strlen(canPath); char const *diff = canPath2 + (canPathLen > 1 ? canPathLen : 0); if (*diff != '\0') { Str_Sprintf(canPath, sizeof canPath, "%s%s", strlen(ptr) > 1 ? ptr : "", diff); } else { Str_Strcpy(canPath, ptr, sizeof canPath); } } else { /* * This is coded as it is in order to document clearly that * the function does not handle bind mount correctly (it * always assumes rbind). */ /* coverity[dead_error_line] */ Str_Strcpy(canPath, ptr, sizeof canPath); } Posix_Free(ptr); /* * There could be a series of these chained together. It is * possible for the mounts to get into a loop, so limit the total * number of retries to something reasonable like 10. */ retries++; if (retries > 10) { Warning(LGPFX" %s: The --[r]bind mount count exceeds %u. Giving " "up.\n", __func__, 10); return NULL; } goto retry; } return ptr; } /* XXX temporary work-around until this function is Unicoded. */ x = Util_SafeStrdup(canPath); failed = FilePosixGetParent(&x); Str_Strcpy(canPath, x, sizeof canPath); Posix_Free(x); /* * Prevent an infinite loop in case FilePosixLookupMountPoint() even * fails on "/". */ if (failed) { return NULL; } } #endif } /* *----------------------------------------------------------------------------- * * FilePosixNearestExistingAncestor -- * * Find the nearest existing ancestor of 'path'. * * 'path' can be relative (including empty) or absolute, and 'path' can * have any number of non-existing components at its end. * * Results: * The allocated, NUL-terminated, non-empty path of the * nearest existing ancestor. * * Side effects: * None * *----------------------------------------------------------------------------- */ static char * FilePosixNearestExistingAncestor(char const *path) // IN: File path { size_t resultSize; char *result; struct stat statbuf; resultSize = MAX(strlen(path), 1) + 1; result = Util_SafeMalloc(resultSize); Str_Strcpy(result, path, resultSize); for (;;) { char *ptr; if (*result == '\0') { Str_Strcpy(result, *path == DIRSEPC ? "/" : ".", resultSize); break; } if (Posix_Stat(result, &statbuf) == 0) { break; } ptr = strrchr(result, DIRSEPC); if (ptr == NULL) { ptr = result; } *ptr = '\0'; } return result; } #endif /* !FreeBSD && !sun */ /* *---------------------------------------------------------------------------- * * File_IsSameFile -- * * Determine whether both paths point to the same file. * * Caveats - While local files are matched based on inode and device * ID, some older versions of NFS return buggy device IDs, so the * determination cannot be done with 100% confidence across NFS. * Paths that traverse NFS mounts are matched based on device, inode * and all of the fields of the stat structure except for times. * This introduces a race condition in that if the target files are not * locked, they can change out from underneath this function yielding * false negative results. Cloned files sytems mounted across an old * version of NFS may yield a false positive. * * Results: * TRUE if both paths point to the same file, FALSE otherwise. * * Side effects: * Changes errno, maybe. * *---------------------------------------------------------------------------- */ Bool File_IsSameFile(const char *path1, // IN: const char *path2) // IN: { struct stat st1; struct stat st2; #if !defined(sun) // Solaris does not have statfs struct statfs stfs1; struct statfs stfs2; #endif ASSERT(path1 != NULL); ASSERT(path2 != NULL); /* * First take care of the easy checks. If the paths are identical, or if * the inode numbers or resident devices don't match, we're done. */ if (Unicode_Compare(path1, path2) == 0) { return TRUE; } if (Posix_Stat(path1, &st1) == -1) { return FALSE; } if (Posix_Stat(path2, &st2) == -1) { return FALSE; } if (st1.st_ino != st2.st_ino) { return FALSE; } if (st1.st_dev != st2.st_dev) { return FALSE; } if (HostType_OSIsVMK()) { /* * On ESX, post change 1074635 the st_dev field of the stat structure * is valid and differentiates between resident devices or NFS file * systems - no need to use statfs to obtain file system information. */ return TRUE; } #if !defined(sun) // Solaris does not have statfs if (Posix_Statfs(path1, &stfs1) != 0) { return FALSE; } if (Posix_Statfs(path2, &stfs2) != 0) { return FALSE; } #if defined(__APPLE__) || defined(__FreeBSD__) if ((stfs1.f_flags & MNT_LOCAL) && (stfs2.f_flags & MNT_LOCAL)) { return TRUE; } #else if ((stfs1.f_type != NFS_SUPER_MAGIC) && (stfs2.f_type != NFS_SUPER_MAGIC)) { return TRUE; } #endif #endif /* * At least one of the paths traverses NFS and some older NFS * implementations can set st_dev incorrectly. Do some extra checks of the * stat structure to increase our confidence. Since the st_ino numbers had * to match to get this far, the overwhelming odds are the two files are * the same. * * If another process was actively writing or otherwise modifying the file * while we stat'd it, then the following test could fail and we could * return a false negative. On the other hand, if NFS lies about st_dev * and the paths point to a cloned file system, then the we will return a * false positive. */ if ((st1.st_mode == st2.st_mode) && (st1.st_nlink == st2.st_nlink) && (st1.st_uid == st2.st_uid) && (st1.st_gid == st2.st_gid) && (st1.st_rdev == st2.st_rdev) && (st1.st_size == st2.st_size) && (st1.st_blksize == st2.st_blksize) && (st1.st_blocks == st2.st_blocks)) { return TRUE; } return FALSE; } /* *----------------------------------------------------------------------------- * * File_Replace -- * * Replace old file (destination) with new file (source), and attempt to * reproduce file permissions. A NULL value for either the oldName or * newName will result in failure and errno will be set to EFAULT. * * Results: * TRUE on success. * * Side effects: * errno may be set. * *----------------------------------------------------------------------------- */ Bool File_Replace(const char *oldName, // IN: old file const char *newName) // IN: new file { int status = 0; Bool result = FALSE; char *newPath = NULL; char *oldPath = NULL; struct stat st; if (newName == NULL) { status = EFAULT; goto bail; } else if ((newPath = Unicode_GetAllocBytes(newName, STRING_ENCODING_DEFAULT)) == NULL) { status = UNICODE_CONVERSION_ERRNO; Msg_Append(MSGID(filePosix.replaceConversionFailed) "Failed to convert file path \"%s\" to current encoding\n", newName); goto bail; } if (oldName == NULL) { status = EFAULT; goto bail; } else if ((oldPath = Unicode_GetAllocBytes(oldName, STRING_ENCODING_DEFAULT)) == NULL) { status = UNICODE_CONVERSION_ERRNO; Msg_Append(MSGID(filePosix.replaceConversionFailed) "Failed to convert file path \"%s\" to current encoding\n", oldName); goto bail; } if ((stat(oldPath, &st) == 0) && (chmod(newPath, st.st_mode) == -1)) { status = errno; Msg_Append(MSGID(filePosix.replaceChmodFailed) "Failed to duplicate file permissions from " "\"%s\" to \"%s\": %s\n", oldName, newName, Msg_ErrString()); goto bail; } if (rename(newPath, oldPath) < 0) { status = errno; Msg_Append(MSGID(filePosix.replaceRenameFailed) "Failed to rename \"%s\" to \"%s\": %s\n", newName, oldName, Msg_ErrString()); goto bail; } result = TRUE; bail: Posix_Free(newPath); Posix_Free(oldPath); errno = status; return result; } /* *---------------------------------------------------------------------- * * FilePosixGetMaxOrSupportsFileSize -- * * Given a file descriptor to a file on a volume, either find out the * max file size for the volume on which the file is located or check * if the volume supports the given file size. * If getMaxFileSize is set then find out the max file size and store it * in *maxFileSize on success, otherwise figure out if *fileSize is * supported. * * Results: * If getMaxFileSize was set: * TRUE with max file size stored in *fileSize. * Otherwise: * TRUE fileSize is supported. * FALSE fileSize not supported or could not figure out the answer. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Bool FilePosixGetMaxOrSupportsFileSize(FileIODescriptor *fd, // IN: uint64 *fileSize, // IN/OUT: Bool getMaxFileSize) // IN: { uint64 value = 0; uint64 mask; ASSERT(fd != NULL); ASSERT(fileSize != NULL); if (!getMaxFileSize) { return FileIO_SupportsFileSize(fd, *fileSize); } /* * Try to do a binary search and figure out the max supported file size. */ for (mask = (1ULL << 62); mask != 0; mask >>= 1) { if (FileIO_SupportsFileSize(fd, value | mask)) { value |= mask; } } *fileSize = value; return TRUE; } /* *---------------------------------------------------------------------- * * FilePosixCreateTestGetMaxOrSupportsFileSize -- * * Given a path to a dir on a volume, either find out the max file size * for the volume on which the dir is located or check if the volume * supports the given file size. * If getMaxFileSize is set then find out the max file size and store it * in *maxFileSize on success, otherwise figure out if *fileSize is * supported. * * Results: * If getMaxFileSize was set: * TRUE if figured out the max file size. * FALSE failed to figure out the max file size. * Otherwise: * TRUE fileSize is supported. * FALSE fileSize not supported or could not figure out the answer. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Bool FilePosixCreateTestGetMaxOrSupportsFileSize(const char *dirName, // IN: test dir uint64 *fileSize, // IN/OUT: Bool getMaxFileSize) // IN: { Bool retVal; int posixFD; char *temp; char *path; FileIODescriptor fd; ASSERT(fileSize != NULL); temp = Unicode_Append(dirName, "/.vmBigFileTest"); posixFD = File_MakeSafeTemp(temp, &path); Posix_Free(temp); if (posixFD == -1) { Log(LGPFX" %s: Failed to create temporary file in dir: %s\n", __func__, dirName); return FALSE; } fd = FileIO_CreateFDPosix(posixFD, O_RDWR); retVal = FilePosixGetMaxOrSupportsFileSize(&fd, fileSize, getMaxFileSize); /* Eventually perform destructive tests here... */ FileIO_Close(&fd); File_Unlink(path); Posix_Free(path); return retVal; } #ifdef VMX86_SERVER /* *---------------------------------------------------------------------- * * FileVMKGetMaxFileSize -- * * Given a path to a file on a volume, find out the max file size for * the volume on which the file is located. * Max file size gets stored in *maxFileSize on success. * * Results: * TRUE if figured out the max file size. * FALSE failed to figure out the max file size. * * Side effects: * None * *---------------------------------------------------------------------- */ static Bool FileVMKGetMaxFileSize(const char *pathName, // IN: uint64 *maxFileSize) // OUT: { int fd; Bool retval = TRUE; char *fullPath; char *dirPath = NULL; ASSERT(maxFileSize != NULL); fullPath = File_FullPath(pathName); if (fullPath == NULL) { Log(LGPFX" %s: Failed to get the full path for %s\n", __func__, pathName); retval = FALSE; goto bail; } if (File_IsDirectory(fullPath)) { dirPath = Unicode_Duplicate(fullPath); } else { dirPath = NULL; File_SplitName(fullPath, NULL, &dirPath, NULL); } /* * We always try to open the dir in order to avoid any contention on VMDK * descriptor file with those threads which already have descriptor file * opened for writing. */ fd = Posix_Open(dirPath, O_RDONLY, 0); if (fd == -1) { Log(LGPFX" %s: could not open %s: %s\n", __func__, dirPath, Err_Errno2String(errno)); retval = FALSE; goto bail; } if (ioctl(fd, IOCTLCMD_VMFS_GET_MAX_FILE_SIZE, maxFileSize) == -1) { Log(LGPFX" %s: Could not get max file size for path: %s, error: %s\n", __func__, pathName, Err_Errno2String(errno)); retval = FALSE; } close(fd); bail: Posix_Free(fullPath); Posix_Free(dirPath); return retval; } #endif /* *---------------------------------------------------------------------- * * FileVMKGetMaxOrSupportsFileSize -- * * Given a path to a file on a volume, either find out the max file size * for the volume on which the file is located or check if the volume * supports the given file size. * If getMaxFileSize is set then find out the max file size and store it * in *maxFileSize on success, otherwise figure out if *fileSize is * supported. * * Results: * If getMaxFileSize was set: * TRUE if figured out the max file size. * FALSE failed to figure out the max file size. * Otherwise: * TRUE fileSize is supported. * FALSE fileSize not supported or could not figure out the answer. * * Side effects: * None * *---------------------------------------------------------------------- */ static Bool FileVMKGetMaxOrSupportsFileSize(const char *pathName, // IN: uint64 *fileSize, // IN/OUT: Bool getMaxFileSize) // IN: { #if defined(VMX86_SERVER) FS_PartitionListResult *fsAttrs = NULL; uint64 maxFileSize; /* * Let's first try IOCTL to figure out max file size. */ if (FileVMKGetMaxFileSize(pathName, &maxFileSize)) { if (getMaxFileSize) { *fileSize = maxFileSize; return TRUE; } return (*fileSize <= maxFileSize); } /* * Try the old way if IOCTL failed. */ LOG(0, LGPFX" %s: Failed to figure out max file size via " "IOCTLCMD_VMFS_GET_MAX_FILE_SIZE. Falling back to old method.\n", __func__); maxFileSize = -1; if (File_GetVMFSAttributes(pathName, &fsAttrs) < 0) { Log(LGPFX" %s: File_GetVMFSAttributes Failed\n", __func__); return FALSE; } if (strcmp(fsAttrs->fsType, FS_VMFS_ON_ESX) == 0) { if (fsAttrs->versionNumber == 3) { maxFileSize = (VMFS3CONST * (uint64) fsAttrs->fileBlockSize * 1024); } else if (fsAttrs->versionNumber >= 5) { /* Get ready for 64 TB on VMFS5 and perform confidence check on version */ maxFileSize = (uint64) 0x400000000000ULL; } else { Log(LGPFX" %s: Unsupported filesystem version, %u\n", __func__, fsAttrs->versionNumber); Posix_Free(fsAttrs); return FALSE; } Posix_Free(fsAttrs); if (maxFileSize == -1) { Log(LGPFX" %s: Failed to figure out the max file size for %s\n", __func__, pathName); return FALSE; } if (getMaxFileSize) { *fileSize = maxFileSize; return TRUE; } else { return *fileSize <= maxFileSize; } } else { char *fullPath; char *parentPath; Bool supported; Log(LGPFX" %s: Trying create file and seek approach.\n", __func__); fullPath = File_FullPath(pathName); if (fullPath == NULL) { Log(LGPFX" %s: Error acquiring full path\n", __func__); Posix_Free(fsAttrs); return FALSE; } File_GetPathName(fullPath, &parentPath, NULL); supported = FilePosixCreateTestGetMaxOrSupportsFileSize(parentPath, fileSize, getMaxFileSize); Posix_Free(fsAttrs); Posix_Free(fullPath); Posix_Free(parentPath); return supported; } #endif Log(LGPFX" %s: did not execute properly\n", __func__); return FALSE; /* happy compiler */ } /* *---------------------------------------------------------------------- * * FileGetMaxOrSupportsFileSize -- * * Given a path to a file on a volume, either find out the max file size * for the volume on which the file is located or check if the volume * supports the given file size. * If getMaxFileSize is set then find out the max file size and store it * in *maxFileSize on success, otherwise figure out if *fileSize is * supported. * * Results: * If getMaxFileSize was set: * TRUE if figured out the max file size. * FALSE failed to figure out the max file size. * Otherwise: * TRUE fileSize is supported. * FALSE fileSize not supported or could not figure out the answer. * * Side effects: * None * *---------------------------------------------------------------------- */ Bool FileGetMaxOrSupportsFileSize(const char *pathName, // IN: uint64 *fileSize, // IN/OUT: Bool getMaxFileSize) // IN: { char *fullPath; char *folderPath; Bool retval = FALSE; ASSERT(pathName != NULL); ASSERT(fileSize != NULL); /* * We acquire the full path name for testing in * FilePosixCreateTestGetMaxOrSupportsFileSize(). This is also done in the * event that a user tries to create a virtual disk in the directory that * they want a vmdk created in (setting filePath only to the disk name, * not the entire path.). */ fullPath = File_FullPath(pathName); if (fullPath == NULL) { Log(LGPFX" %s: Error acquiring full path for path: %s.\n", __func__, pathName); goto out; } if (HostType_OSIsVMK()) { retval = FileVMKGetMaxOrSupportsFileSize(fullPath, fileSize, getMaxFileSize); goto out; } if (File_IsFile(fullPath)) { FileIOResult res; FileIODescriptor fd; FileIO_Invalidate(&fd); res = FileIO_Open(&fd, fullPath, FILEIO_OPEN_ACCESS_READ, FILEIO_OPEN); if (FileIO_IsSuccess(res)) { retval = FilePosixGetMaxOrSupportsFileSize(&fd, fileSize, getMaxFileSize); FileIO_Close(&fd); goto out; } } /* * On unknown filesystems create a temporary file in the argument file's * parent directory and use it as a test. */ if (File_IsDirectory(pathName)) { folderPath = Unicode_Duplicate(fullPath); } else { folderPath = NULL; File_SplitName(fullPath, NULL, &folderPath, NULL); } retval = FilePosixCreateTestGetMaxOrSupportsFileSize(folderPath, fileSize, getMaxFileSize); Posix_Free(folderPath); out: Posix_Free(fullPath); return retval; } /* *---------------------------------------------------------------------- * * File_GetMaxFileSize -- * * Given a path to a file on a volume, return the max file size for that * volume. The max file size is stored on *maxFileSize on success. * The function caps the max file size to be MAX_SUPPORTED_FILE_SIZE on * any type of FS. * * Results: * TRUE on success. * FALSE failed to figure out max file size due to some reasons. * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_GetMaxFileSize(const char *pathName, // IN: uint64 *maxFileSize) // OUT: { Bool result; if (maxFileSize == NULL) { Log(LGPFX" %s: maxFileSize passed as NULL.\n", __func__); return FALSE; } result = FileGetMaxOrSupportsFileSize(pathName, maxFileSize, TRUE); if (result) { /* * Cap the max supported file size at MAX_SUPPORTED_FILE_SIZE. */ if (*maxFileSize > MAX_SUPPORTED_FILE_SIZE) { *maxFileSize = MAX_SUPPORTED_FILE_SIZE; } } return result; } /* *---------------------------------------------------------------------- * * File_SupportsFileSize -- * * Check if the given file is on an FS that supports such file size. * The function caps the max supported file size to be * MAX_SUPPORTED_FILE_SIZE on any type of FS. * * Results: * TRUE if FS supports such file size. * FALSE otherwise (file size not supported, invalid path, read-only, ...) * * Side effects: * None * *---------------------------------------------------------------------- */ Bool File_SupportsFileSize(const char *pathName, // IN: uint64 fileSize) // IN: { /* * All supported filesystems can hold at least 2GB-1 bytes files. */ if (fileSize <= 0x7FFFFFFF) { return TRUE; } /* * Cap the max supported file size at MAX_SUPPORTED_FILE_SIZE. */ if (fileSize > MAX_SUPPORTED_FILE_SIZE) { return FALSE; } return FileGetMaxOrSupportsFileSize(pathName, &fileSize, FALSE); } /* *----------------------------------------------------------------------------- * * FileCreateDirectory -- * * Create a directory. The umask is honored. * * Results: * 0 success * > 0 failure (errno) * * Side effects: * May change the host file system. * *----------------------------------------------------------------------------- */ int FileCreateDirectory(const char *pathName, // IN: int mask) // IN: { int err; if (pathName == NULL) { err = errno = EFAULT; } else { err = (Posix_Mkdir(pathName, mask) == -1) ? errno : 0; } return err; } /* *---------------------------------------------------------------------- * * File_ListDirectory -- * * Gets the list of files (and directories) in a directory. * * Results: * Returns the number of files returned or -1 on failure. * * Side effects: * If ids is provided and the function succeeds, memory is * allocated for both the unicode strings and the array itself * and must be freed. (See Util_FreeStringList.) * The memory allocated for the array may be larger than necessary. * The caller may trim it with realloc() if it cares. * * A file name that cannot be represented in the default encoding * will appear as a string of three UTF8 substitution characters. * *---------------------------------------------------------------------- */ typedef struct { char **fileNames; uint32 pos; } ListParams; static int FileNameArray(const char *key, // IN: void *value, // IN: void *clientData) // IN/OUT: ListParams pointer { ListParams *params = clientData; ASSERT(value == NULL); params->fileNames[params->pos++] = Util_SafeStrdup(key); return 0; } int File_ListDirectory(const char *dirName, // IN: char ***ids) // OUT: relative paths { int count = -1; WalkDirContext context = File_WalkDirectoryStart(dirName); if (context != NULL) { int err; while (File_WalkDirectoryNext(context, NULL)) ; err = errno; if (err == 0) { count = HashTable_GetNumElements(context->hash); if (ids) { if (count == 0) { *ids = NULL; } else { ListParams params; params.fileNames = Util_SafeCalloc(count, sizeof(char *)); params.pos = 0; HashTable_ForEach(context->hash, FileNameArray, ¶ms); *ids = params.fileNames; } } } File_WalkDirectoryEnd(context); errno = err; } return count; } /* *----------------------------------------------------------------------------- * * File_WalkDirectoryEnd -- * * End the directory traversal. * * Results: * None * * Side effects: * The context is now invalid. * *----------------------------------------------------------------------------- */ static int FileKeyDispose(const char *key, // IN: void *value, // IN: void *clientData) // IN: { Posix_Free((void *) key); return 0; } void File_WalkDirectoryEnd(WalkDirContext context) // IN: { if (context != NULL) { if (context->dir != NULL) { closedir(context->dir); } HashTable_ForEach(context->hash, FileKeyDispose, NULL); HashTable_Free(context->hash); Posix_Free(context->dirName); Posix_Free(context); } } /* *----------------------------------------------------------------------------- * * File_WalkDirectoryStart -- * * Start a directory tree walk at 'parentPath'. * * To read each entry, repeatedly pass the returned context to * File_WalkDirectoryNext() until that function returns FALSE. * * We assume no thread will change the working directory between the calls * to File_WalkDirectoryStart and File_WalkDirectoryEnd. * * Results: * A context used in subsequent calls to File_WalkDirectoryNext() or NULL * if an error is encountered. * * Side effects: * None * *----------------------------------------------------------------------------- */ WalkDirContext File_WalkDirectoryStart(const char *dirName) // IN: { WalkDirContextImpl *context; ASSERT(dirName != NULL); context = Util_SafeMalloc(sizeof *context); context->dirName = Util_SafeStrdup(dirName); context->hash = HashTable_Alloc(2048, HASH_STRING_KEY, NULL); context->dir = Posix_OpenDir(dirName); if (context->dir == NULL) { int err = errno; File_WalkDirectoryEnd(context); errno = err; context = NULL; } return context; } /* *----------------------------------------------------------------------------- * * File_WalkDirectoryNext -- * * Get the next file name during a directory traversal started with * File_WalkDirectoryStart. * * Results: * TRUE Traversal hasn't completed yet. If *fileName is not NULL, * an allocated string of the file name found is returned. * The caller must free the string. * FALSE The traversal has completed. Check errno; if it is zero (0), * the walk completed sucessfully. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool File_WalkDirectoryNext(WalkDirContext context, // IN: char **fileName) // OUT/OPT: { int err = 0; Bool callAgain = FALSE; ASSERT(context != NULL); while (TRUE) { char *allocName; struct dirent *entry; errno = 0; entry = readdir(context->dir); if (entry == NULL) { err = errno; break; } /* Strip out undesirable paths. No one ever cares about these. */ if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) { continue; } /* * It is possible for a directory operation to change the contents * of a directory while this routine is running. If the OS decides * to physically rearrange the contents of the directory it is * possible for readdir to report a file more than once. Only add * a file to the return data if it is unique within the return * data. */ #if defined(VMX86_SERVER) || defined(__APPLE__) // UTF8 native platforms if (CodeSet_IsStringValidUTF8(entry->d_name)) { allocName = Util_SafeStrdup(entry->d_name); #else if (Unicode_IsBufferValid(entry->d_name, -1, STRING_ENCODING_DEFAULT)) { allocName = Unicode_Alloc(entry->d_name, STRING_ENCODING_DEFAULT); #endif } else { char *id = Unicode_EscapeBuffer(entry->d_name, -1, STRING_ENCODING_DEFAULT); Warning("%s: file '%s' in directory '%s' cannot be converted to " "UTF8\n", __FUNCTION__, context->dirName, id); Posix_Free(id); allocName = Unicode_Duplicate(UNICODE_SUBSTITUTION_CHAR UNICODE_SUBSTITUTION_CHAR UNICODE_SUBSTITUTION_CHAR); } if (HashTable_Insert(context->hash, allocName, NULL)) { // Unique - good if (fileName != NULL) { *fileName = Util_SafeStrdup(allocName); } callAgain = TRUE; break; } else { // Duplicate - ignore free(allocName); continue; } } errno = err; return callAgain; } /* *---------------------------------------------------------------------- * * FileIsGroupsMember -- * * Determine if a gid is in the gid list of the current process * * Results: * FALSE if error (reported to the user) * * Side effects: * None * *---------------------------------------------------------------------- */ static Bool FileIsGroupsMember(gid_t gid) // IN: { int nr_members; gid_t *members; int res; int ret; members = NULL; nr_members = 0; for (;;) { gid_t *new; res = getgroups(nr_members, members); if (res == -1) { Warning(LGPFX" %s: Couldn't getgroups\n", __FUNCTION__); ret = FALSE; goto end; } if (res == nr_members) { break; } /* Was bug 17760 --hpreg */ new = realloc(members, res * sizeof *members); if (new == NULL) { Warning(LGPFX" %s: Couldn't realloc\n", __FUNCTION__); ret = FALSE; goto end; } members = new; nr_members = res; } for (res = 0; res < nr_members; res++) { if (members[res] == gid) { ret = TRUE; goto end; } } ret = FALSE; end: Posix_Free(members); return ret; } /* *---------------------------------------------------------------------- * * FileIsWritableDir -- * * Determine in a non-intrusive way if the user can create a file in a * directory * * Results: * FALSE if error (reported to the user) * * Side effects: * None * * Bug: * It would be cleaner to use the POSIX access(2), which deals well * with read-only filesystems. Unfortunately, access(2) doesn't deal with * the effective [u|g]ids. * *---------------------------------------------------------------------- */ Bool FileIsWritableDir(const char *dirName) // IN: { int err; uid_t euid; FileData fileData; err = FileAttributes(dirName, &fileData); if ((err != 0) || (fileData.fileType != FILE_TYPE_DIRECTORY)) { return FALSE; } euid = geteuid(); if (euid == 0) { /* Root can read or write any file. Well... This is not completely true because of read-only filesystems and NFS root squashing... What a nightmare --hpreg */ return TRUE; } if (fileData.fileOwner == euid) { fileData.fileMode >>= 6; } else if (FileIsGroupsMember(fileData.fileGroup)) { fileData.fileMode >>= 3; } /* Check for Read and Execute permissions */ return (fileData.fileMode & 3) == 3; } /* *---------------------------------------------------------------------- * * File_MakeCfgFileExecutable -- * * Make a .vmx file executable. This is sometimes necessary * to enable MKS access to the VM. * * Owner always gets rwx. Group/other get x where r is set. * * Results: * FALSE if error * * Side effects: * errno is set on error * *---------------------------------------------------------------------- */ Bool File_MakeCfgFileExecutable(const char *pathName) // IN: { struct stat s; if (Posix_Stat(pathName, &s) == 0) { mode_t newMode = s.st_mode; newMode |= S_IRUSR | S_IWUSR | S_IXUSR; ASSERT_ON_COMPILE(S_IRGRP >> 2 == S_IXGRP && S_IROTH >> 2 == S_IXOTH); newMode |= ((newMode & (S_IRGRP | S_IROTH)) >> 2); return newMode == s.st_mode || Posix_Chmod(pathName, newMode); } return FALSE; } /* *---------------------------------------------------------------------------- * * File_GetSizeAlternate -- * * An alternate way to determine the filesize. Useful for finding * problems with files on remote fileservers, such as described in bug * 19036. However, in Linux we do not have an alternate way, yet, to * determine the problem, so we call back into the regular getSize * function. * * Results: * Size of file or -1. * * Side effects: * None * *---------------------------------------------------------------------------- */ int64 File_GetSizeAlternate(const char *pathName) // IN: { return File_GetSize(pathName); } /* *---------------------------------------------------------------------------- * * File_IsCharDevice -- * * This function checks whether the given file is a char device * and return TRUE in such case. This is often useful on Windows * where files like COM?, LPT? must be differentiated from "normal" * disk files. * * Results: * TRUE is a character device * FALSE is not a character device or error * * Side effects: * None * *---------------------------------------------------------------------------- */ Bool File_IsCharDevice(const char *pathName) // IN: { FileData fileData; return (FileAttributes(pathName, &fileData) == 0) && (fileData.fileType == FILE_TYPE_CHARDEVICE); } /* *---------------------------------------------------------------------------- * * File_GetMountPath -- * * This function translates the path for a symlink to the physical path. * If checkEntirePath is TRUE, this function will try to translate * every parent directory to physical path. * Caller must free the returned buffer if valid path is returned. * * Results: * return valid physical path if successfully. * return NULL if error. * * Side effects: * The result is allocated. * *---------------------------------------------------------------------------- */ char * File_GetMountPath(const char *pathName, // IN: Bool checkEntirePath) // IN: { char *mountPath; if (pathName == NULL) { return NULL; } if (checkEntirePath) { return Posix_RealPath(pathName); } mountPath = Posix_ReadLink(pathName); if (mountPath != NULL) { return mountPath; } if (!Posix_Access(pathName, F_OK)) { return Util_SafeStrdup(pathName); } return NULL; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/fileStandAlone.c000066400000000000000000000463151470176644300250530ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * fileStandAlone.c -- * * This file contains lib/file routines which are unentangled - they do * not depend on other libraries besides lib/misc and its dependencies. */ #if defined(_WIN32) #include #endif #include #include #include #include #if !defined(_WIN32) #include #endif #include #include #include #include #include "vmware.h" #include "util.h" #include "str.h" #include "strutil.h" #include "posix.h" #include "file.h" #include "unicodeOperations.h" /* *---------------------------------------------------------------------- * * File_GetModTime -- * * Get the last modification time of a file and return it. The time * unit is seconds since the POSIX/UNIX/Linux epoch. * * Results: * Last modification time of file or -1 if error. * * Side effects: * None. * *---------------------------------------------------------------------- */ int64 File_GetModTime(const char *pathName) // IN: { int64 theTime; struct stat statbuf; if (Posix_Stat(pathName, &statbuf) == 0) { theTime = statbuf.st_mtime; } else { theTime = -1; } return theTime; } #if defined(_WIN32) /* *--------------------------------------------------------------------------- * * FileFindFirstDirsep -- * * Return a pointer to the first directory separator. * * Results: * NULL No directory separator found * !NULL Pointer to the last directory separator * * Side effects: * None * *--------------------------------------------------------------------------- */ static char * FileFindFirstDirsep(const char *pathName) // IN: { char *p; ASSERT(pathName != NULL); p = (char *) pathName; while (*p != '\0') { if (File_IsDirsep(*p)) { return p; } p++; } return NULL; } #endif /* *--------------------------------------------------------------------------- * * FileFindLastDirsep -- * * Return a pointer to the last directory separator. * * Results: * NULL No directory separator found * !NULL Pointer to the last directory separator * * Side effects: * None * *--------------------------------------------------------------------------- */ static char * FileFindLastDirsep(const char *pathName, // IN: size_t len) // IN: { char *p; ASSERT(pathName != NULL); p = (char *) pathName + len; while (p-- != pathName) { if (File_IsDirsep(*p)) { return p; } } return NULL; } /* *---------------------------------------------------------------------- * * File_SplitName -- * * Split a file name into three components: VOLUME, DIRECTORY, * BASE. The return values must be freed. * * VOLUME is empty for an empty string or a UNIX-style path, the * drive letter and colon for a Win32 drive-letter path, or the * construction "\\server\share" for a Win32 UNC path. * * BASE is the longest string at the end that begins after the * volume string and after the last directory separator. * * DIRECTORY is everything in-between VOLUME and BASE. * * The concatenation of VOLUME, DIRECTORY, and BASE produces the * original string, so any of those strings may be empty. * * A NULL pointer may be passed for one or more OUT parameters, in * which case that parameter is not returned. * * Able to handle both UNC and drive-letter paths on Windows. * * Results: * As described. * * Side effects: * None. * *---------------------------------------------------------------------- */ void File_SplitName(const char *pathName, // IN: char **volume, // OUT/OPT: char **directory, // OUT/OPT: char **base) // OUT/OPT: { char *vol; char *dir; char *bas; size_t len; char *baseBegin; char *volEnd; int volLen, dirLen; ASSERT(pathName != NULL); len = strlen(pathName); /* * Get volume. */ volEnd = (char *) pathName; #ifdef WIN32 if ((len > 2) && (!Str_Strncmp("\\\\", pathName, 2) || !Str_Strncmp("//", pathName, 2))) { /* UNC path */ volEnd = FileFindFirstDirsep(volEnd + 2); if (volEnd != NULL) { volEnd = FileFindFirstDirsep(volEnd + 1); if (volEnd == NULL) { /* We have \\foo\bar, which is legal */ volEnd = (char *) pathName + len; } } else { /* We have \\foo, which is just bogus */ volEnd = (char *) pathName; } } else if ((len >= 2) && (pathName[1] == ':')) { // drive-letter path volEnd = (char *) pathName + 2; } #endif /* WIN32 */ volLen = volEnd - pathName; vol = Util_SafeMalloc(volLen + 1); memcpy(vol, pathName, volLen); vol[volLen] = '\0'; /* * Get base. */ baseBegin = FileFindLastDirsep(pathName, len); baseBegin = (baseBegin == NULL) ? (char *) pathName : baseBegin + 1; if (baseBegin < volEnd) { baseBegin = (char *) pathName + len; } bas = Util_SafeStrdup(baseBegin); /* * Get dir. */ dirLen = baseBegin - volEnd; dir = Util_SafeMalloc(dirLen + 1); memcpy(dir, volEnd, dirLen); dir[dirLen] = '\0'; /* * Return what needs to be returned. */ if (volume == NULL) { free(vol); } else { *volume = vol; } if (directory == NULL) { free(dir); } else { *directory = dir; } if (base == NULL) { free(bas); } else { *base = bas; } } /* *--------------------------------------------------------------------------- * * File_PathJoin -- * * Join the dirName and baseName together to create a (full) path. * * This code concatenates two strings together and omits a redundant * directory separator between the two. * * On Windows, the 'baseName' argument may not be a fully qualified path. * That is, it may not be an absolute path containing a drive letter nor * may it be a UNC path. * * Examples: * File_PathJoin("", "b") -> "/b" * File_PathJoin("/", "b") -> "/b" * File_PathJoin("a", "b") -> "a/b" * File_PathJoin("a/", "b") -> "a/b" * File_PathJoin("a/////", "b") -> "a/b" * File_PathJoin("a", "") -> "a/" * File_PathJoin("a", "/") -> "a/" * File_PathJoin("a", "/b") -> "a/b" * File_PathJoin("a", "/////b") -> "a/b" (only posix) * File_PathJoin("a/", "/b") -> "a/b" * File_PathJoin("a/////", "/////b") -> "a/b" (only posix) * * Results: * The constructed path which must be freed by the caller. * * Side effects: * None * *--------------------------------------------------------------------------- */ char * File_PathJoin(const char *dirName, // IN: const char *baseName) // IN: See above. { char *result; char *newDir = NULL; ASSERT(dirName); ASSERT(baseName); /* * Remove ALL directory separators from baseName begin. */ #if defined(_WIN32) { const char *oldBaseName = baseName; /* * Reject drive letters in baseName. */ ASSERT(Unicode_LengthInCodePoints(baseName) < 2 || Unicode_FindSubstrInRange(baseName, 1, 1, ":", 0, 1) == UNICODE_INDEX_NOT_FOUND); while (*baseName == '/' || *baseName == '\\') { baseName++; } /* * Reject UNC paths for baseName. */ ASSERT(baseName - oldBaseName < 2); } #else while (*baseName == '/') { baseName++; } #endif /* * Remove ALL directory separators from dirName end. */ newDir = File_StripSlashes(dirName); result = Unicode_Join(newDir, DIRSEPS, baseName, NULL); Posix_Free(newDir); return result; } /* *--------------------------------------------------------------------------- * * File_GetPathName -- * * Behaves like File_SplitName by splitting the fullpath into * pathname & filename components. * * The trailing directory separator [\|/] is stripped off the * pathname component. This in turn means that on Linux the root * directory will be returned as the empty string "". On Windows * it will be returned as X: where X is the drive letter. It is * important that callers of this functions are aware that the "" * on Linux means root "/". * * A NULL pointer may be passed for one or more OUT parameters, * in which case that parameter is not returned. * * Results: * As described. * * Side effects: * The return values must be freed. * *--------------------------------------------------------------------------- */ void File_GetPathName(const char *fullPath, // IN: char **pathName, // OUT/OPT: char **baseName) // OUT/OPT: { char *p; char *pName; char *bName; ASSERT(fullPath); p = FileFindLastDirsep(fullPath, strlen(fullPath)); if (p == NULL) { pName = Util_SafeStrdup(""); bName = Util_SafeStrdup(fullPath); } else { bName = Util_SafeStrdup(&fullPath[p - fullPath + 1]); pName = Util_SafeStrdup(fullPath); pName[p - fullPath] = '\0'; p = &pName[p - fullPath]; while (p-- != pName) { if (File_IsDirsep(*p)) { *p = '\0'; } else { break; } } } if (pathName == NULL) { free(pName); } else { *pathName = pName; } if (baseName == NULL) { free(bName); } else { *baseName = bName; } } /* *---------------------------------------------------------------------- * * File_StripSlashes -- * * Strip trailing slashes from the end of a path. * * Results: * The stripped filename. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * File_StripSlashes(const char *path) // IN: { char *result; char *volume; char *dir; char *base; /* * SplitName handles all drive letter/UNC/whatever cases, all we * have to do is make sure the dir part is stripped of slashes if * there isn't a base part. */ File_SplitName(path, &volume, &dir, &base); if (!Unicode_IsEmpty(dir) && Unicode_IsEmpty(base)) { char *dir2 = Unicode_GetAllocBytes(dir, STRING_ENCODING_UTF8); size_t i = strlen(dir2); /* * Don't strip first slash on Windows, since we want at least * one slash to trail a drive letter/colon or UNC specifier. */ #if defined(_WIN32) while ((i > 1) && File_IsDirsep(dir2[i - 1])) { #else while ((i > 0) && File_IsDirsep(dir2[i - 1])) { #endif i--; } Posix_Free(dir); dir = Unicode_AllocWithLength(dir2, i, STRING_ENCODING_UTF8); Posix_Free(dir2); } result = Unicode_Join(volume, dir, base, NULL); Posix_Free(volume); Posix_Free(dir); Posix_Free(base); return result; } /* *----------------------------------------------------------------------------- * * File_MapPathPrefix -- * * Given a path and a newPrefix -> oldPrefix mapping, transform * oldPath according to the mapping. * * Results: * The new path, or NULL if there is no mapping. * * Side effects: * The returned string is allocated, free it. * *----------------------------------------------------------------------------- */ char * File_MapPathPrefix(const char *oldPath, // IN: const char **oldPrefixes, // IN: const char **newPrefixes, // IN: size_t numPrefixes) // IN: { int i; size_t oldPathLen = strlen(oldPath); for (i = 0; i < numPrefixes; i++) { char *oldPrefix; char *newPrefix; size_t oldPrefixLen; oldPrefix = File_StripSlashes(oldPrefixes[i]); newPrefix = File_StripSlashes(newPrefixes[i]); oldPrefixLen = strlen(oldPrefix); /* * If the prefix matches on a DIRSEPS boundary, or the prefix is the * whole string, replace it. * * If we don't insist on matching a whole directory name, we could * mess things of if one directory is a substring of another. * * Perform a case-insensitive compare on Windows. (There are * case-insensitive filesystems on MacOS also, but the problem * is more acute with Windows because of frequent drive-letter * case mismatches. So in lieu of actually asking the * filesystem, let's just go with a simple ifdef for now.) */ if ((oldPathLen >= oldPrefixLen) && #ifdef _WIN32 (Str_Strncasecmp(oldPath, oldPrefix, oldPrefixLen) == 0) && #else (Str_Strncmp(oldPath, oldPrefix, oldPrefixLen) == 0) && #endif (strchr(VALID_DIRSEPS, oldPath[oldPrefixLen]) || (oldPath[oldPrefixLen] == '\0'))) { size_t newPrefixLen = strlen(newPrefix); size_t newPathLen = (oldPathLen - oldPrefixLen) + newPrefixLen; char *newPath; ASSERT(newPathLen > 0); ASSERT(oldPathLen >= oldPrefixLen); newPath = Util_SafeMalloc((newPathLen + 1) * sizeof(char)); memcpy(newPath, newPrefix, newPrefixLen); memcpy(newPath + newPrefixLen, oldPath + oldPrefixLen, oldPathLen - oldPrefixLen + 1); /* * It should only match once. Weird self-referencing mappings * aren't allowed. */ Posix_Free(oldPrefix); Posix_Free(newPrefix); return newPath; } Posix_Free(oldPrefix); Posix_Free(newPrefix); } return NULL; } /* *----------------------------------------------------------------------------- * * File_PrependToPath -- * * This function checks if the elem is already present in the * searchPath, if it is then it is moved forward in the search path. * Otherwise it is prepended to the searchPath. * * Results: * Return file search path with elem in front. * * Side effects: * Caller must free returned string. * *----------------------------------------------------------------------------- */ char * File_PrependToPath(const char *searchPath, // IN: const char *elem) // IN: { const char sep = FILE_SEARCHPATHTOKEN[0]; char *newPath; char *path; size_t n; ASSERT(searchPath); ASSERT(elem); newPath = Str_SafeAsprintf(NULL, "%s%s%s", elem, FILE_SEARCHPATHTOKEN, searchPath); n = strlen(elem); path = newPath + n + 1; for (;;) { char *next = Str_Strchr(path, sep); size_t len = next ? next - path : strlen(path); if ((len == n) && (Str_Strncmp(path, elem, len) == 0)) { if (next) { memmove(path, next + 1, strlen(next + 1) + 1); } else { *--path = '\0'; } break; } if (!next) { break; } path = next + 1; } return newPath; } /* *----------------------------------------------------------------------------- * * File_ReplaceExtension -- * * Replaces the extension in input with newExtension. * * If the old extension exists in the list of extensions specified in ..., * truncate it before appending the new extension. * * If the extension is not found in the list, the newExtension is * just appended. * * If there isn't a list of extensions specified (numExtensions == 0), * truncate the old extension unconditionally. * * NB: newExtension and the extension list must have .'s. * * Results: * The name with newExtension added to it. The caller is responsible to * free it when they are done with it. * * Side effects: * None. * *----------------------------------------------------------------------------- */ char * File_ReplaceExtension(const char *pathName, // IN: const char *newExtension, // IN: uint32 numExtensions, // IN: ...) // IN: { char *p; char *place; char *result; size_t newExtLen; size_t resultLen; size_t pathNameLen; ASSERT(pathName); ASSERT(newExtension); ASSERT(*newExtension == '.'); pathNameLen = strlen(pathName); newExtLen = strlen(newExtension); resultLen = pathNameLen + newExtLen + 1; result = Util_SafeMalloc(resultLen); memcpy(result, pathName, pathNameLen + 1); p = FileFindLastDirsep(result, pathNameLen); if (p == NULL) { p = strrchr(result, '.'); } else { p = strrchr(p, '.'); } if (p == NULL) { /* No extension... just append */ place = &result[pathNameLen]; // The NUL } else if (numExtensions == 0) { /* Always truncate the old extension if extension list is empty. */ place = p; // The '.' } else { uint32 i; va_list arguments; /* * Only truncate the old extension if it exists in the valid * extensions list. */ place = &result[pathNameLen]; // The NUL va_start(arguments, numExtensions); for (i = 0; i < numExtensions ; i++) { const char *oldExtension = va_arg(arguments, const char *); ASSERT(*oldExtension == '.'); if (strcmp(p, oldExtension) == 0) { place = p; // The '.' break; } } va_end(arguments); } /* Add the new extension - in the appropriate place - to pathName */ memcpy(place, newExtension, newExtLen + 1); return result; } /* *----------------------------------------------------------------------------- * * File_RemoveExtension -- * * Return a copy of the given path name with the extension * removed. We ASSERT that the given path does have an extension. * * Results: * A newly allocated buffer with the modified string. The caller * is responsible to free it when they are done with it. * * Side effects: * None. * *----------------------------------------------------------------------------- */ char * File_RemoveExtension(const char *pathName) // IN: { char *p; char *result; ASSERT(pathName != NULL); result = Util_SafeStrdup(pathName); p = FileFindLastDirsep(result, strlen(pathName)); if (p == NULL) { p = strrchr(result, '.'); } else { p = strrchr(p, '.'); } ASSERT(p != NULL); if (p != NULL) { *p = '\0'; } return result; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/fileTemp.c000066400000000000000000000275251470176644300237320ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2011-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #if defined(_WIN32) #include #endif #include #include #include #include #include #include #include #include #include "vmware.h" #include "log.h" #include "file.h" #include "fileInt.h" #include "util.h" #include "unicodeOperations.h" #include "posix.h" #if !defined(O_BINARY) #define O_BINARY 0 #endif /* *---------------------------------------------------------------------- * * FileTempNum -- * * Compute a number to be used as an attachment to a base name. * In order to avoid race conditions, files and directories are * kept separate via enforced odd (file) and even (directory) * numberings. * * Regardless of the input value of *var, the output value will * be even or odd as determined by createTempFile. * * Results: * An odd number if createTempFile is TRUE. * An even number if createTempFile is FALSE. * * Side effects: * None * *---------------------------------------------------------------------- */ static void FileTempNum(Bool createTempFile, // IN: uint32 *var) // IN/OUT: { ASSERT(var != NULL); *var += (FileSimpleRandom() >> 8) & 0xFF; *var = (*var & ~0x1) | (createTempFile ? 1 : 0); } /* *---------------------------------------------------------------------- * * FileMakeTempEx2Work -- * * Create a temporary file or a directory. * * If a temporary file is created successfully, then return an open file * descriptor to that file. * * 'dir' specifies the directory in which to create the object. It * must not end in a slash. * * 'createTempFile', if TRUE, then a temporary file will be created. If * FALSE, then a temporary directory will be created. * * 'makeSubdirSafe', if TRUE, then if a directory is requested, * the directory will be made "safe". This also requires that * 'dir' already be safe (the code will check this). * * 'createNameFunc' specifies the user-specified callback function that * will be called to construct a fileName. 'createNameFuncData' will be * passed everytime 'createNameFunc' is called. 'createNameFunc' * should return the dynamically allocated, proper fileName. * * Check the documentation for File_MakeTempHelperFunc. * * Results: * if a temporary file is created, then Open file descriptor or -1; * if a temporary directory is created, then 0 or -1; * If successful then presult points to a dynamically allocated * string with the pathname of the temp object created. * * Side effects: * Creates the requested object when successful. Errno is set on error * * Files and directories are effectively in separate name spaces; * the numerical value attached via createNameFunc is odd for files * and even for directories. * *---------------------------------------------------------------------- */ static int FileMakeTempEx2Work(const char *dir, // IN: Bool createTempFile, // IN: Bool makeSubdirSafe, // IN: File_MakeTempCreateNameFunc *createNameFunc, // IN: void *createNameFuncData, // IN: char **presult) // OUT: { uint32 i; int fd; uint32 var = 0; ASSERT(presult != NULL); if ((dir == NULL) || (createNameFunc == NULL)) { errno = EFAULT; return -1; } *presult = NULL; for (i = 0; i < (MAX_INT32 / 2); i++) { char *objName; char *pathName; /* * Files and directories are kept separate (odd and even respectfully). * This way the available exclusion mechanisms work properly - O_EXCL * on files, mkdir on directories - and races are avoided. * * Not attempting an open on a directory is a good thing... */ FileTempNum(createTempFile, &var); objName = (*createNameFunc)(var, createNameFuncData); ASSERT(objName != NULL); if (createTempFile) { pathName = File_PathJoin(dir, objName); fd = Posix_Open(pathName, O_CREAT | O_EXCL | O_BINARY | O_RDWR, 0600); } else { if (makeSubdirSafe) { pathName = File_MakeSafeTempSubdir(dir, objName); fd = (pathName == NULL) ? -1 : 0; } else { pathName = File_PathJoin(dir, objName); fd = Posix_Mkdir(pathName, 0700); } } if (fd != -1) { *presult = pathName; Posix_Free(objName); break; } Posix_Free(pathName); if (errno != EEXIST) { Log(LGPFX" Failed to create temporary %s; dir \"%s\", " "objName \"%s\", errno %d\n", createTempFile ? "file" : "directory", dir, objName, errno); Posix_Free(objName); goto exit; } Posix_Free(objName); } if (fd == -1) { Warning(LGPFX" Failed to create temporary %s: " "The name space is full.\n", createTempFile ? "file" : "directory"); errno = EAGAIN; } exit: return fd; } /* *---------------------------------------------------------------------- * * File_MakeTempEx2 -- * * Same as FileMakeTempEx2Int, defaulting 'makeSubdirSafe' to * FALSE. * * Results: * See FileMakeTempEx2Int. * * Side effects: * See FileMakeTempEx2Int. * *---------------------------------------------------------------------- */ int File_MakeTempEx2(const char *dir, // IN: Bool createTempFile, // IN: File_MakeTempCreateNameFunc *createNameFunc, // IN: void *createNameFuncData, // IN: char **presult) // OUT: { return FileMakeTempEx2Work(dir, createTempFile, FALSE, createNameFunc, createNameFuncData, presult); } /* *---------------------------------------------------------------------------- * * FileMakeTempExCreateNameFunc -- * * This is a helper function designed for File_MakeTempEx function. * Everytime this function is called, this creates a fileName with the * format and returns back to the caller. * * 'num' specifies the nth time this function is called. * * 'data' specifies the payload that is specified when File_MakeTempEx2() * function is called. This points to a UTF8 string. * * Results: * if successful, a dynamically allocated string with the basename of * the temp file. NULL otherwise. * * Side effects: * None * *---------------------------------------------------------------------------- */ static char * FileMakeTempExCreateNameFunc(uint32 num, // IN: void *data) // IN: { if (data == NULL) { return NULL; } return Unicode_Format("%s%u", (char *) data, num); } /* *---------------------------------------------------------------------- * * File_MakeTempEx -- * * Create a temporary file and, if successful, return an open file * descriptor to that file. * * 'dir' specifies the directory in which to create the file. It * must not end in a slash. * * 'fileName' specifies the base filename of the created file. * * Results: * Open file descriptor or -1; if successful then presult points * to a dynamically allocated string with the pathname of the temp * file. * * Side effects: * Creates a file if successful. Errno is set on error * *---------------------------------------------------------------------- */ int File_MakeTempEx(const char *dir, // IN: const char *fileName, // IN: char **presult) // OUT: { return File_MakeTempEx2(dir, TRUE, FileMakeTempExCreateNameFunc, (void *) fileName, presult); } /* *---------------------------------------------------------------------- * * File_MakeSafeTempDir -- * * Create a temporary directory in a safe area. * * Optional argument 'prefix' specifies the name prefix of the * created directory. When not provided a default will be provided. * * Results: * NULL Failure * !NULL Path name of created directory * * Side effects: * Creates a directory if successful. Errno is set on error * *---------------------------------------------------------------------- */ char * File_MakeSafeTempDir(const char *prefix) // IN: { char *result = NULL; char *dir = File_GetSafeTmpDir(TRUE); if (dir != NULL) { const char *effectivePrefix = (prefix == NULL) ? "safeDir" : prefix; FileMakeTempEx2Work(dir, FALSE, TRUE, FileMakeTempExCreateNameFunc, (void *) effectivePrefix, &result); Posix_Free(dir); } return result; } /* *---------------------------------------------------------------------- * * File_MakeSafeTemp -- * * Exactly the same as File_MakeTempEx except uses a safe directory * as the default temporary directory. * * Results: * Open file descriptor or -1 * * Side effects: * Creates a file if successful. * *---------------------------------------------------------------------- */ int File_MakeSafeTemp(const char *tag, // IN (OPT): char **presult) // OUT: { int fd; char *dir = NULL; char *fileName = NULL; ASSERT(presult); *presult = NULL; if (tag && File_IsFullPath(tag)) { File_GetPathName(tag, &dir, &fileName); } else { dir = File_GetSafeTmpDir(TRUE); fileName = Unicode_Duplicate(tag ? tag : "vmware"); } fd = File_MakeTempEx(dir, fileName, presult); Posix_Free(dir); Posix_Free(fileName); return fd; } /* *----------------------------------------------------------------------------- * * File_DoesVolumeSupportAcls -- * * Determines if the volume that the pathname resides on supports * ACLs. * * Results: * TRUE it does * FALSE it doesn't * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool File_DoesVolumeSupportAcls(const char *path) // IN: { Bool succeeded = FALSE; #if defined(_WIN32) Bool res; char *vol; char *vol2; const utf16_t *vol2W; DWORD fsFlags; ASSERT(path); File_SplitName(path, &vol, NULL, NULL); vol2 = Unicode_Append(vol, DIRSEPS); vol2W = UNICODE_GET_UTF16(vol2); res = GetVolumeInformationW(vol2W, NULL, 0, NULL, NULL, &fsFlags, NULL, 0); UNICODE_RELEASE_UTF16(vol2W); if (res) { if ((fsFlags & FS_PERSISTENT_ACLS) == 0) { goto exit; } } else { Log(LGPFX" %s: GetVolumeInformation failed: %d\n", __FUNCTION__, GetLastError()); goto exit; } succeeded = TRUE; exit: Posix_Free(vol); Posix_Free(vol2); #endif return succeeded; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/file/fileTempPosix.c000066400000000000000000000476311470176644300247550ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2019, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(__FreeBSD__) && !defined(sun) # include #endif #if defined(__APPLE__) && defined(TARGET_MAC_OS) #include #endif #include "vmware.h" #include "file.h" #include "fileInt.h" #include "util.h" #include "su.h" #include "vm_atomic.h" #include "str.h" #include "vm_product.h" #include "random.h" #include "userlock.h" #include "unicodeOperations.h" #include "err.h" #include "posix.h" #include "mutexRankLib.h" #include "hostType.h" #include "localconfig.h" #define LOGLEVEL_MODULE util #include "loglevel_user.h" /* *---------------------------------------------------------------------- * * FileTryDir -- * * Check to see if the specified directory is actually a directory * and is writable by us. * * Results: * !NULL The expanded directory name (must be freed) * NULL Failure * * Side effects: * None * *---------------------------------------------------------------------- */ static char * FileTryDir(const char *dirName) // IN: Is this a writable directory? { if (dirName != NULL) { char *edirName = Util_ExpandString(dirName); if ((edirName != NULL) && FileIsWritableDir(edirName)) { return edirName; } Posix_Free(edirName); } return NULL; } #if defined(__APPLE__) && defined(TARGET_MAC_OS) /* *---------------------------------------------------------------------- * * FileExecutablePath -- * * Return the path of the executable running this code. * * Results: * !NULL Success. The executable path. Must be freed by caller. * NULL Failure * * Side effects: * None * *---------------------------------------------------------------------- */ static char * FileExecutablePath(void) { char *path = Util_SafeMalloc((size_t) PROC_PIDPATHINFO_MAXSIZE); if (proc_pidpath(getpid(), path, PROC_PIDPATHINFO_MAXSIZE) <= 0) { Warning("%s: proc_pidpath failure %d\n", __FUNCTION__, errno); free(path); path = NULL; } return path; } #endif /* *---------------------------------------------------------------------- * * FileTmpDirOk -- * * Is it OK to query the TMPDIR environment variable? * * Results: * TRUE Yes * FALSE No * * Side effects: * None * *---------------------------------------------------------------------- */ static Bool FileTmpDirOk(void) { #if defined(__APPLE__) && defined(TARGET_MAC_OS) /* No setuid on IOS, MacOS only */ int err; Bool ok; struct stat statBuf; char *path = FileExecutablePath(); if (path == NULL) { return FALSE; // Err on the side of caution } LOG_ONCE("%s: executable path '%s'\n", __FUNCTION__, path); err = Posix_Stat(path, &statBuf); free(path); if (err == -1) { Warning("%s: Stat failed on '%s'\n", __FUNCTION__, path); return FALSE; // Err on the side of caution } ok = ((statBuf.st_mode & S_ISUID) == 0); // Only when setuid not present LOG_ONCE("%s: TMPDIR ok %d\n", __FUNCTION__, ok); return ok; #else return TRUE; #endif } /* *---------------------------------------------------------------------- * * FileGetTmpDir -- * * Determine the best temporary directory. Unsafe since the returned * directory is generally going to be 0777, thus all sorts of denial * of service or symlink attacks are possible. * * Results: * !NULL The temp directory name (must be freed) * NULL Failure (reported to the user). * * Side effects: * None * *---------------------------------------------------------------------- */ static char * FileGetTmpDir(Bool useConf) // IN: Use the config file? { char *dirName; char *edirName; /* Make several attempts to find a good temporary directory candidate */ if (useConf) { dirName = (char *) LocalConfig_GetString(NULL, "tmpDirectory"); edirName = FileTryDir(dirName); Posix_Free(dirName); if (edirName != NULL) { return edirName; } } if (FileTmpDirOk()) { /* Posix_Getenv string must _not_ be freed */ edirName = FileTryDir(Posix_Getenv("TMPDIR")); if (edirName != NULL) { return edirName; } } /* P_tmpdir is usually defined in */ edirName = FileTryDir(P_tmpdir); if (edirName != NULL) { return edirName; } edirName = FileTryDir("/tmp"); if (edirName != NULL) { return edirName; } edirName = FileTryDir("~"); if (edirName != NULL) { return edirName; } dirName = File_Cwd(NULL); if (dirName != NULL) { edirName = FileTryDir(dirName); Posix_Free(dirName); if (edirName != NULL) { return edirName; } } edirName = FileTryDir("/"); if (edirName != NULL) { return edirName; } Warning("%s: Couldn't get a temporary directory\n", __FUNCTION__); return NULL; } #undef HOSTINFO_TRYDIR #if !defined(__FreeBSD__) && !defined(sun) /* *----------------------------------------------------------------------------- * * FileGetUserName -- * * Retrieve the name associated with the specified UID. Thread-safe * version. --hpreg * * Results: * !NULL The user name (must be freed) * NULL Failure * * Side effects: * None * *----------------------------------------------------------------------------- */ static char * FileGetUserName(uid_t uid) // IN: { char *memPool; long memPoolSize; struct passwd pw; struct passwd *pw_p; char *userName = NULL; #if defined(__APPLE__) memPoolSize = _PASSWORD_LEN; #else errno = 0; memPoolSize = sysconf(_SC_GETPW_R_SIZE_MAX); if ((errno != 0) || (memPoolSize == 0)) { Warning("%s: sysconf(_SC_GETPW_R_SIZE_MAX) failed.\n", __FUNCTION__); return NULL; } if (memPoolSize == -1) { // Unlimited; pick something reasonable memPoolSize = 16 * 1024; } #endif memPool = Util_SafeMalloc(memPoolSize); if ((Posix_Getpwuid_r(uid, &pw, memPool, memPoolSize, &pw_p) != 0) || pw_p == NULL) { Warning("%s: Unable to retrieve the user name associated with UID %u.\n", __FUNCTION__, uid); } else { userName = Util_SafeStrdup(pw_p->pw_name); } Posix_Free(memPool); return userName; } /* *----------------------------------------------------------------------------- * * FileGetUserIdentifier -- * * Attempt to obtain an user identification string. * * Results: * A dynamically allocated string containing the user identifier. * * Side effects: * None * *----------------------------------------------------------------------------- */ static char * FileGetUserIdentifier(uid_t uid, // IN: Bool addPid) // IN: { char *userName = FileGetUserName(uid); if (userName == NULL) { Warning("%s: Failed to get user name, using UID.\n", __FUNCTION__); /* Fallback on just using the uid as the user name. */ userName = Str_SafeAsprintf(NULL, "uid_%u", uid); } if (addPid) { char *pidToo = Str_SafeAsprintf(NULL, "%s_%u", userName, getpid()); Posix_Free(userName); userName = pidToo; } return userName; } /* *----------------------------------------------------------------------------- * * FileAcceptableSafeTmpDir -- * * Determines if the specified path is acceptable as a safe temp * directory. The directory must either be creatable with the appropriate * permissions and UID or it must already exist with those settings. * * Results: * TRUE Path is acceptible * FALSE Otherwise * * Side effects: * Directory may be created * *----------------------------------------------------------------------------- */ static Bool FileAcceptableSafeTmpDir(const char *dirName, // IN: uid_t uid) // IN: { Bool acceptable; static const mode_t mode = 0700; acceptable = (Posix_Mkdir(dirName, mode) == 0); if (!acceptable) { int error = errno; if (EEXIST == error) { struct stat st; /* * The name already exists. Check that it is what we want: a * directory owned by the current effective user with permissions * 'mode'. It is crucial to use lstat() instead of stat() here, * because we do not want the name to be a symlink (created by * another user) pointing to a directory owned by the current * effective user with permissions 'mode'. */ if (Posix_Lstat(dirName, &st) == 0) { /* * Our directory inherited S_ISGID if its parent had it. So it is * important to ignore that bit, and it is safe to do so because * that bit does not affect the owner's permissions. */ if (S_ISDIR(st.st_mode) && (st.st_uid == uid) && ((st.st_mode & 05777) == mode)) { acceptable = TRUE; } } } } return acceptable; } /* *----------------------------------------------------------------------------- * * FileFindExistingSafeTmpDir -- * * Searches baseTmpDir to see if any subdirectories are suitable to use * as a safe temp directory. The safe temp directory must have the correct * permissions and UID. * * Results: * !NULL Path to discovered safe temp directory (must be freed) * NULL No suitable directory was found * * Side effects: * None * *----------------------------------------------------------------------------- */ static char * FileFindExistingSafeTmpDir(const char *baseTmpDir, // IN: const char *userName, // IN: uid_t uid) // IN: { int i; int numFiles; char *pattern; char *tmpDir = NULL; char **fileList = NULL; /* * We always use the pattern PRODUCT-USER-xxxx when creating alternative * safe temp directories, so check for ones with those names and the * appropriate permissions. */ pattern = Unicode_Format("%s-%s-", PRODUCT_GENERIC_NAME_LOWER, userName); if (pattern == NULL) { return NULL; } numFiles = File_ListDirectory(baseTmpDir, &fileList); if (numFiles == -1) { Posix_Free(pattern); return NULL; } for (i = 0; i < numFiles; i++) { if (Unicode_StartsWith(fileList[i], pattern)) { char *path = Unicode_Join(baseTmpDir, DIRSEPS, fileList[i], NULL); if (File_IsDirectory(path) && FileAcceptableSafeTmpDir(path, uid)) { tmpDir = path; break; } Posix_Free(path); } } Util_FreeStringList(fileList, numFiles); Posix_Free(pattern); return tmpDir; } /* *----------------------------------------------------------------------------- * * FileCreateSafeTmpDir -- * * Creates a new directory within baseTmpDir with the correct permissions * and UID to ensure it is safe from symlink attacks. * * Results: * !NULL Path to created safe temp directory (must be freed) * NULL No suitable directory was found * * Side effects: * Directory may be created. * *----------------------------------------------------------------------------- */ static char * FileCreateSafeTmpDir(const char *baseTmpDir, // IN: const char *userName, // IN: uid_t uid) // IN: { int curDirIter = 0; char *tmpDir = NULL; static const int MAX_DIR_ITERS = 250; while (TRUE) { /* * We use a random number that makes it more likely that we will create * an unused name than if we had simply tried suffixes in numeric order. */ tmpDir = Str_SafeAsprintf(NULL, "%s%s%s-%s-%u", baseTmpDir, DIRSEPS, PRODUCT_GENERIC_NAME_LOWER, userName, FileSimpleRandom()); if (FileAcceptableSafeTmpDir(tmpDir, uid)) { break; } if (++curDirIter > MAX_DIR_ITERS) { Warning("%s: Failed to create a safe temporary directory, path " "\"%s\". The maximum number of attempts was exceeded.\n", __FUNCTION__, tmpDir); Posix_Free(tmpDir); tmpDir = NULL; break; } Posix_Free(tmpDir); } return tmpDir; } #endif // __linux__ /* *----------------------------------------------------------------------------- * * FileGetSafeTmpDir -- * * Return a safe temporary directory (i.e. a temporary directory which * is not prone to symlink attacks, because it is only writable with the * current set of credentials (EUID). * * Guaranteed to return the same directory for any EUID every time it is * called during the lifetime of the current process. (Barring the user * manually deleting or renaming the directory.) * * Optionally, add the PID to the user identifier for the cases where * the EUID may change during the lifetime of the calling process. * * Results: * !NULL Path to safe temp directory (must be freed) * NULL No suitable directory was found * * Side effects: * None. * *----------------------------------------------------------------------------- */ static char * FileGetSafeTmpDir(Bool useConf, // IN: Use configuration variables? Bool addPid) // IN: Add PID to userName? { char *tmpDir = NULL; #if defined(__FreeBSD__) || defined(sun) tmpDir = FileGetTmpDir(useConf); #else static Atomic_Ptr lckStorage; static char *cachedDir; static uid_t cachedEuid; static char *cachedPidDir; uid_t euid; char *testSafeDir; MXUserExclLock *lck; char *userName = NULL; char *baseTmpDir = NULL; /* Get and take lock for our safe dir. */ lck = MXUser_CreateSingletonExclLock(&lckStorage, "getSafeTmpDirLock", RANK_getSafeTmpDirLock); MXUser_AcquireExclLock(lck); /* * If a suitable temporary directory was cached for this EUID, use it... * as long as it is still acceptable. */ euid = geteuid(); testSafeDir = addPid ? cachedPidDir : cachedDir; /* * Detecting an EUID change without resorting to I/Os is an nice performance * improvement... particularly on ESXi where the operations are expensive. */ if ((euid == cachedEuid) && (testSafeDir != NULL) && FileAcceptableSafeTmpDir(testSafeDir, euid)) { tmpDir = Util_SafeStrdup(testSafeDir); goto exit; } /* We don't have a useable temporary dir, create one. */ baseTmpDir = FileGetTmpDir(useConf); if (baseTmpDir == NULL) { goto exit; } userName = FileGetUserIdentifier(euid, addPid); tmpDir = Str_SafeAsprintf(NULL, "%s%s%s-%s", baseTmpDir, DIRSEPS, PRODUCT_GENERIC_NAME_LOWER, userName); if (addPid || !FileAcceptableSafeTmpDir(tmpDir, euid)) { /* * Either we want a truely random temp directory or we didn't get our * first choice for the safe temp directory. Search through the unsafe * tmp directory to see if there is an acceptable one to use. */ Posix_Free(tmpDir); tmpDir = FileFindExistingSafeTmpDir(baseTmpDir, userName, euid); if (tmpDir == NULL) { /* * We didn't find any usable directories, so try to create one now. */ tmpDir = FileCreateSafeTmpDir(baseTmpDir, userName, euid); } } if (tmpDir != NULL) { char *newDir = Util_SafeStrdup(tmpDir); if (euid == cachedEuid) { if (addPid) { Posix_Free(cachedPidDir); cachedPidDir = newDir; } else { Posix_Free(cachedDir); cachedDir = newDir; } } else { Posix_Free(cachedPidDir); Posix_Free(cachedDir); if (addPid) { cachedPidDir = newDir; cachedDir = NULL; } else { cachedDir = newDir; cachedPidDir = NULL; } cachedEuid = euid; } } exit: MXUser_ReleaseExclLock(lck); Posix_Free(baseTmpDir); Posix_Free(userName); #endif return tmpDir; } /* *----------------------------------------------------------------------------- * * File_GetSafeTmpDir -- * * Return a safe temporary directory (i.e. a temporary directory which * is not prone to symlink attacks, because it is only writable with the * current set of credentials (EUID). * * Guaranteed to return the same directory for any EUID every time it is * called during the lifetime of the current process. (Barring the user * manually deleting or renaming the directory.) * * Results: * !NULL Path to safe temp directory (must be freed) * NULL No suitable directory was found * * Side effects: * None. * *----------------------------------------------------------------------------- */ char * File_GetSafeTmpDir(Bool useConf) // IN: { return FileGetSafeTmpDir(useConf, FALSE); } /* *----------------------------------------------------------------------------- * * File_GetSafeRandomTmpDir -- * * Return a safe, random temporary directory (i.e. a temporary directory * is not prone to symlink attacks, because it is only writable with the * current set of credentials (EUID). * * Guaranteed to return the same directory for any EUID every time it is * called during the lifetime of the current process. (Barring the user * manually deleting or renaming the directory.) * * Results: * !NULL Path to safe temp directory (must be freed). * NULL No suitable directory was found. * * Side effects: * None. * *----------------------------------------------------------------------------- */ char * File_GetSafeRandomTmpDir(Bool useConf) // IN: { return FileGetSafeTmpDir(useConf, TRUE); } /* *----------------------------------------------------------------------------- * * File_MakeSafeTempSubdir -- * * Given an existing safe directory, create a safe subdir of * the specified name in that directory. * * Results: * The allocated subdir path on success. * NULL on failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ char * File_MakeSafeTempSubdir(const char *safeDir, // IN const char *subdirName) // IN { #if defined(__FreeBSD__) || defined(sun) if (!File_Exists(safeDir)) { return NULL; } return File_PathJoin(safeDir, subdirName); #else uid_t userId = geteuid(); char *fullSafeSubdir; if (!File_Exists(safeDir) || !FileAcceptableSafeTmpDir(safeDir, userId)) { return NULL; } fullSafeSubdir = File_PathJoin(safeDir, subdirName); if (!FileAcceptableSafeTmpDir(fullSafeSubdir, userId)) { free(fullSafeSubdir); return NULL; } return fullSafeSubdir; #endif } open-vm-tools-stable-12.5.0/open-vm-tools/lib/foundryMsg/000077500000000000000000000000001470176644300232245ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/foundryMsg/Makefile.am000066400000000000000000000021311470176644300252550ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libFoundryMsg.la libFoundryMsg_la_SOURCES = libFoundryMsg_la_SOURCES += foundryMsg.c libFoundryMsg_la_SOURCES += foundryPropertyListCommon.c libFoundryMsg_la_SOURCES += vixTranslateErrOpenSource.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/foundryMsg/foundryMsg.c000066400000000000000000002352161470176644300255360ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2004-2016, 2019, 2021, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * foundryMsg.c -- * * This is a library for formatting and parsing the messages sent * between a foundry client and the VMX. It is a stand-alone library * so it can be used by the VMX tree without also linking in the * entire foundry client-side library. */ #include "vmware.h" #include "util.h" #include "str.h" #include "base64.h" #include "vixOpenSource.h" #include "vixCommands.h" #include "unicodeBase.h" static char PlainToObfuscatedCharMap[256]; static char ObfuscatedToPlainCharMap[256]; /* * An entry in the command info table. There is one VixCommandInfo per op * code, and each entry contains a description of the op code plus security- * related metadata. */ typedef struct VixCommandInfo { int opCode; const char *commandName; VixCommandSecurityCategory category; Bool used; // Is there an opcode for this entry? } VixCommandInfo; #define VIX_DEFINE_COMMAND_INFO(x, category) { x, #x, category, TRUE } #define VIX_DEFINE_UNUSED_COMMAND { 0, NULL, VIX_COMMAND_CATEGORY_UNKNOWN, FALSE } /* * Contains the information for every VIX command op code. This table is * organized to allow for direct look up, so it must be complete. Any index * that does not correspond to a valid VIX op code must be marked with * VIX_DEFINE_UNUSED_COMMAND. * * When you add or remove a command to vixCommands.h, this table needs to * be updated as well. When adding a new command, you need to give it a * security category. There are descriptions of the categories in vixCommands.h * where they are defined, but in general, if the command affects the host or * a VM (but not the guest), then the command should be CATEGORY_PRIVILEGED. * If the command is a guest command (a command the runs inside the guest * OS) than it should be CATEGORY_ALWAYS_ALLOWED. Also, if a command is * required to establish a connection with the VMX, it needs to be * CATEGORY_ALWAYS_ALLOWED. */ static const VixCommandInfo vixCommandInfoTable[] = { VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_UNKNOWN, VIX_COMMAND_CATEGORY_UNKNOWN), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VM_POWERON, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VM_POWEROFF, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VM_RESET, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VM_SUSPEND, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_RUN_PROGRAM, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_KEYSTROKES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_READ_REGISTRY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_WRITE_REGISTRY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_COPY_FILE_FROM_GUEST_TO_HOST, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_COPY_FILE_FROM_HOST_TO_GUEST, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_SNAPSHOT, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_SNAPSHOT, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REVERT_TO_SNAPSHOT, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VM_CLONE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_GUEST_FILE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GUEST_FILE_EXISTS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_FIND_VM, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CALL_PROCEDURE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REGISTRY_KEY_EXISTS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_WIN32_WINDOW_MESSAGE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CONSOLIDATE_SNAPSHOTS, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_INSTALL_TOOLS, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CANCEL_INSTALL_TOOLS, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_UPGRADE_VIRTUAL_HARDWARE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_RELOAD_VM, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_VM, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_WAIT_FOR_TOOLS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_RUNNING_VM_SNAPSHOT, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CONSOLIDATE_RUNNING_VM_SNAPSHOT, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_NUM_SHARED_FOLDERS, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_SHARED_FOLDER_STATE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_EDIT_SHARED_FOLDER_STATE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_SHARED_FOLDER, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_ADD_SHARED_FOLDER, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_RUN_SCRIPT_IN_GUEST, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_OPEN_VM, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, /* GET_HANDLE_STATE is needed for the initial handshake */ VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_HANDLE_STATE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_WORKING_COPY, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DISCARD_WORKING_COPY, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SAVE_WORKING_COPY, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CAPTURE_SCREEN, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_TOOLS_STATE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CHANGE_SCREEN_RESOLUTION, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DIRECTORY_EXISTS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_GUEST_REGISTRY_KEY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_GUEST_DIRECTORY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_GUEST_EMPTY_DIRECTORY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_TEMPORARY_FILE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_PROCESSES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_MOVE_GUEST_FILE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_DIRECTORY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CHECK_USER_ACCOUNT, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_DIRECTORY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REGISTER_VM, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_UNREGISTER_VM, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, /* CREATE_SESSION_KEY is needed for the initial handshake */ VIX_DEFINE_COMMAND_INFO(VIX_CREATE_SESSION_KEY_COMMAND, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VMXI_HGFS_SEND_PACKET_COMMAND, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_KILL_PROCESS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LOGOUT_IN_GUEST, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_READ_VARIABLE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_WRITE_VARIABLE, VIX_COMMAND_CATEGORY_MIXED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CONNECT_DEVICE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_IS_DEVICE_CONNECTED, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_FILE_INFO, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SET_FILE_INFO, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_MOUSE_EVENTS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_OPEN_TEAM, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_ANSWER_MESSAGE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_ENABLE_SHARED_FOLDERS, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_MOUNT_HGFS_FOLDERS, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_EXTEND_DISK, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CONNECT_HOST, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_LINKED_CLONE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, /* * HOWTO: Adding a new Vix Command. Step 2b. * Take the command you added to vixCommands.h, and add it to this * table. The command needs to go in the index that matches the command * ID as specified in the enum in vixCommands.h. */ VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SAMPLE_COMMAND, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_GUEST_NETWORKING_CONFIG, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SET_GUEST_NETWORKING_CONFIG, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VM_PAUSE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VM_UNPAUSE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_PERFORMANCE_DATA, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_SNAPSHOT_SCREENSHOT, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_WAIT_FOR_USER_ACTION_IN_GUEST, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CHANGE_VIRTUAL_HARDWARE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_PLUG_CPU, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_PLUG_MEMORY, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_ADD_DEVICE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_REMOVE_DEVICE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, /* GET_VMX_DEVICE_STATE is needed for the initial handshake. */ VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_VMX_DEVICE_STATE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SET_SNAPSHOT_INFO, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SNAPSHOT_SET_MRU, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LOGOUT_HOST, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_PLUG_BEGIN_BATCH, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_PLUG_COMMIT_BATCH, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_TRANSFER_CONNECTION, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_TRANSFER_REQUEST, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_TRANSFER_FINAL_DATA, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_UNUSED_COMMAND, VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_FILESYSTEMS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CHANGE_DISPLAY_TOPOLOGY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SUSPEND_AND_RESUME, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_BULK_SNAPSHOT, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_COPY_FILE_FROM_READER_TO_GUEST, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GENERATE_NONCE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CHANGE_DISPLAY_TOPOLOGY_MODES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_QUERY_CHILDREN, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_FILES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_DIRECTORY_EX, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_MOVE_GUEST_FILE_EX, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_MOVE_GUEST_DIRECTORY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_TEMPORARY_FILE_EX, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_TEMPORARY_DIRECTORY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SET_GUEST_FILE_ATTRIBUTES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_COPY_FILE_FROM_GUEST_TO_READER, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_START_PROGRAM, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_PROCESSES_EX, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_READ_ENV_VARIABLES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_INITIATE_FILE_TRANSFER_TO_GUEST, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_ACQUIRE_CREDENTIALS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_RELEASE_CREDENTIALS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_VALIDATE_CREDENTIALS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_TERMINATE_PROCESS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_GUEST_FILE_EX, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_GUEST_DIRECTORY_EX, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_CHANGE_MONITOR_TYPE, VIX_COMMAND_CATEGORY_PRIVILEGED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_ADD_AUTH_ALIAS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_AUTH_ALIAS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_AUTH_PROVIDER_ALIASES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_AUTH_MAPPED_ALIASES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CREATE_REGISTRY_KEY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_REGISTRY_KEYS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_REGISTRY_KEY, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SET_REGISTRY_VALUE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_REGISTRY_VALUES, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DELETE_REGISTRY_VALUE, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_AUTH_ALIAS_BY_CERT, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), }; static const VixCommandInfo *VixGetCommandInfoForOpCode(int opCode); static void VixMsgInitializeObfuscationMapping(void); static VixError VixMsgEncodeBuffer(const uint8 *buffer, size_t bufferLength, Bool includeEncodingId, char **result); static VixError VixMsgDecodeBuffer(const char *str, Bool nullTerminateResult, char **result, size_t *bufferLength); static VixError VMAutomationMsgParserInit(const char *caller, unsigned int line, VMAutomationMsgParser *state, const VixMsgHeader *msg, size_t headerLength, size_t fixedLength, size_t miscDataLength, const char *packetType); /* *---------------------------------------------------------------------------- * * VixMsg_AllocResponseMsg -- * * Allocate and initialize a response message. * * Results: * The message, with the headers properly initialized. * * Side effects: * None. * *---------------------------------------------------------------------------- */ VixCommandResponseHeader * VixMsg_AllocResponseMsg(const VixCommandRequestHeader *requestHeader, // IN VixError error, // IN uint32 additionalError, // IN size_t responseBodyLength, // IN const void *responseBody, // IN size_t *responseMsgLength) // OUT { char *responseBuffer = NULL; VixCommandResponseHeader *responseHeader; size_t totalMessageSize; ASSERT((NULL != responseBody) || (0 == responseBodyLength)); /* * We don't have scatter/gather, so copy everything into one buffer. */ totalMessageSize = sizeof(VixCommandResponseHeader) + responseBodyLength; if (totalMessageSize > VIX_COMMAND_MAX_SIZE) { /* * We don't want to allocate any responses larger than * VIX_COMMAND_MAX_SIZE, since the VMX will ignore them. * If we hit this ASSERT, we will need to either revise this * value, or start packetizing certain commands. */ ASSERT(0); return NULL; } responseBuffer = Util_SafeMalloc(totalMessageSize); responseHeader = (VixCommandResponseHeader *) responseBuffer; VixMsg_InitResponseMsg(responseHeader, requestHeader, error, additionalError, totalMessageSize); if ((responseBodyLength > 0) && (responseBody)) { memcpy(responseBuffer + sizeof(VixCommandResponseHeader), responseBody, responseBodyLength); } if (NULL != responseMsgLength) { *responseMsgLength = totalMessageSize; } return responseHeader; } // VixMsg_AllocResponseMsg /* *---------------------------------------------------------------------------- * * VixMsg_InitResponseMsg -- * * Initialize a response message. * * Results: * The message, with the headers properly initialized. * * Side effects: * None. * *---------------------------------------------------------------------------- */ void VixMsg_InitResponseMsg(VixCommandResponseHeader *responseHeader, // IN const VixCommandRequestHeader *requestHeader, // IN VixError error, // IN uint32 additionalError, // IN size_t totalMessageSize) // IN { size_t responseBodyLength; ASSERT(NULL != responseHeader); ASSERT(totalMessageSize >= sizeof(VixCommandResponseHeader)); responseBodyLength = totalMessageSize - sizeof(VixCommandResponseHeader); /* * Fill in the response header. */ responseHeader->commonHeader.magic = VIX_COMMAND_MAGIC_WORD; responseHeader->commonHeader.messageVersion = VIX_COMMAND_MESSAGE_VERSION; responseHeader->commonHeader.totalMessageLength = totalMessageSize; responseHeader->commonHeader.headerLength = sizeof(VixCommandResponseHeader); responseHeader->commonHeader.bodyLength = responseBodyLength; responseHeader->commonHeader.credentialLength = 0; responseHeader->commonHeader.commonFlags = 0; if (NULL != requestHeader) { responseHeader->requestCookie = requestHeader->cookie; } else { responseHeader->requestCookie = 0; } responseHeader->responseFlags = 0; responseHeader->duration = 0xFFFFFFFF; responseHeader->error = error; responseHeader->additionalError = additionalError; responseHeader->errorDataLength = 0; } // VixMsg_InitResponseMsg /* *----------------------------------------------------------------------------- * * VixMsg_AllocRequestMsg -- * * Allocate and initialize a request message. * * Results: * The message, with the headers properly initialized. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixCommandRequestHeader * VixMsg_AllocRequestMsg(size_t msgHeaderAndBodyLength, // IN int opCode, // IN uint64 cookie, // IN int credentialType, // IN const char *credential) // IN { size_t totalMessageSize; VixCommandRequestHeader *commandRequest = NULL; size_t providedCredentialLength = 0; size_t totalCredentialLength = 0; if ((VIX_USER_CREDENTIAL_NAME_PASSWORD == credentialType) || (VIX_USER_CREDENTIAL_HOST_CONFIG_SECRET == credentialType) || (VIX_USER_CREDENTIAL_HOST_CONFIG_HASHED_SECRET == credentialType) || (VIX_USER_CREDENTIAL_TICKETED_SESSION == credentialType) || (VIX_USER_CREDENTIAL_SSPI == credentialType) || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType) || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN_HOST_VERIFIED == credentialType)) { /* * All of these are optional. */ if (NULL != credential) { providedCredentialLength = strlen(credential); totalCredentialLength += providedCredentialLength; } /* * Add 1 to each string to include '\0' for the end of the string. */ totalCredentialLength += 1; } else { totalCredentialLength = 0; } totalMessageSize = msgHeaderAndBodyLength + totalCredentialLength; if (totalMessageSize > VIX_COMMAND_MAX_REQUEST_SIZE) { /* * We don't want to allocate any requests larger than * VIX_COMMAND_MAX_REQUEST_SIZE, since the VMX will ignore them. * If we hit this ASSERT, we will need to either revise this * value, or start packetizing certain commands. */ ASSERT(0); return NULL; } commandRequest = (VixCommandRequestHeader *) Util_SafeCalloc(1, totalMessageSize); commandRequest->commonHeader.magic = VIX_COMMAND_MAGIC_WORD; commandRequest->commonHeader.messageVersion = VIX_COMMAND_MESSAGE_VERSION; commandRequest->commonHeader.totalMessageLength = msgHeaderAndBodyLength + totalCredentialLength; commandRequest->commonHeader.headerLength = sizeof(VixCommandRequestHeader); commandRequest->commonHeader.bodyLength = msgHeaderAndBodyLength - sizeof(VixCommandRequestHeader); commandRequest->commonHeader.credentialLength = totalCredentialLength; commandRequest->commonHeader.commonFlags = VIX_COMMAND_REQUEST; commandRequest->opCode = opCode; commandRequest->cookie = cookie; commandRequest->timeOut = 0xFFFFFFFF; commandRequest->requestFlags = 0; commandRequest->userCredentialType = credentialType; if ((VIX_USER_CREDENTIAL_NAME_PASSWORD == credentialType) || (VIX_USER_CREDENTIAL_HOST_CONFIG_SECRET == credentialType) || (VIX_USER_CREDENTIAL_HOST_CONFIG_HASHED_SECRET == credentialType) || (VIX_USER_CREDENTIAL_TICKETED_SESSION == credentialType) || (VIX_USER_CREDENTIAL_SSPI == credentialType) || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType) || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN_HOST_VERIFIED == credentialType)) { char *destPtr = (char *) commandRequest; destPtr += commandRequest->commonHeader.headerLength; destPtr += commandRequest->commonHeader.bodyLength; if (NULL != credential) { Str_Strcpy(destPtr, credential, providedCredentialLength + 1); destPtr += providedCredentialLength; } *(destPtr++) = 0; } return commandRequest; } // VixMsg_AllocRequestMsg /* *----------------------------------------------------------------------------- * * VixMsg_ValidateMessage -- * * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_ValidateMessage(const void *vMsg, // IN size_t msgLength) // IN { const VixMsgHeader *message; if ((NULL == vMsg) || (msgLength < sizeof *message)) { return VIX_E_INVALID_MESSAGE_HEADER; } /* * Confidence check the header. * Some basic rules: All the length values in the VixMsgHeader * struct are uint32. The headerLength must be large enough to * accomodate the base header: VixMsgHeader. The bodyLength and * the credentialLength can be 0. * * We cannot compare message->totalMessageLength and msgLength. * When we first read just the header, message->totalMessageLength * is > msgLength. When we have read the whole message, then * message->totalMessageLength <= msgLength. So, it depends on * when we call this function. Instead, we just make sure the message * is internally consistent, and then rely on the higher level code to * decide how much to read and when it has read the whole message. */ message = vMsg; if ((VIX_COMMAND_MAGIC_WORD != message->magic) || (message->headerLength < sizeof(VixMsgHeader)) || (message->totalMessageLength < ((uint64)message->headerLength + message->bodyLength + message->credentialLength)) || (message->totalMessageLength > VIX_COMMAND_MAX_SIZE) || (VIX_COMMAND_MESSAGE_VERSION != message->messageVersion)) { return VIX_E_INVALID_MESSAGE_HEADER; } return VIX_OK; } // VixMsg_ValidateMessage /* *----------------------------------------------------------------------------- * * VixMsg_ValidateRequestMsg -- * * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_ValidateRequestMsg(const void *vMsg, // IN size_t msgLength) // IN { VixError err; const VixCommandRequestHeader *message; err = VixMsg_ValidateMessage(vMsg, msgLength); if (VIX_OK != err) { return(err); } /* * Confidence check the parts of the header that are specific to requests. */ message = vMsg; if (message->commonHeader.headerLength < sizeof(VixCommandRequestHeader)) { return VIX_E_INVALID_MESSAGE_HEADER; } if (message->commonHeader.totalMessageLength > VIX_COMMAND_MAX_REQUEST_SIZE) { return VIX_E_INVALID_MESSAGE_HEADER; } if (!(VIX_COMMAND_REQUEST & message->commonHeader.commonFlags)) { return VIX_E_INVALID_MESSAGE_HEADER; } if ((VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1 & message->requestFlags) && (message->commonHeader.totalMessageLength < (uint64)message->commonHeader.headerLength + message->commonHeader.bodyLength + message->commonHeader.credentialLength + sizeof (VixMsgAuthDataV1))) { return VIX_E_INVALID_MESSAGE_HEADER; } return VIX_OK; } // VixMsg_ValidateRequestMsg /* *----------------------------------------------------------------------------- * * VixMsg_ValidateResponseMsg -- * * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_ValidateResponseMsg(const void *vMsg, // IN size_t msgLength) // IN { VixError err; const VixCommandResponseHeader *message; if ((NULL == vMsg) || (msgLength < sizeof *message)) { return VIX_E_INVALID_MESSAGE_HEADER; } err = VixMsg_ValidateMessage(vMsg, msgLength); if (VIX_OK != err) { return(err); } /* * Confidence check the parts of the header that are specific to responses. */ message = vMsg; if (message->commonHeader.headerLength < sizeof(VixCommandResponseHeader)) { return VIX_E_INVALID_MESSAGE_HEADER; } if (VIX_COMMAND_REQUEST & message->commonHeader.commonFlags) { return VIX_E_INVALID_MESSAGE_HEADER; } return VIX_OK; } // VixMsg_ValidateResponseMsg /* *----------------------------------------------------------------------------- * * VixMsg_ParseWriteVariableRequest -- * * Extract the value's name and the value itself from the request * message, while validating message. * * The strings returned from this function just point to memory in * the message itself, so they must not be free()'d. * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_ParseWriteVariableRequest(VixMsgWriteVariableRequest *msg, // IN char **valueName, // OUT char **value) // OUT { VixError err; char *valueNameLocal = NULL; char *valueLocal = NULL; uint64 headerAndBodyLength; if ((NULL == msg) || (NULL == valueName) || (NULL == value)) { ASSERT(0); err = VIX_E_FAIL; goto quit; } *valueName = NULL; *value = NULL; /* * In most cases we will have already called VixMsg_ValidateResponseMsg() * on this request before, but call it here so that this function will * always be sufficient to validate the request. */ err = VixMsg_ValidateRequestMsg(msg, msg->header.commonHeader.totalMessageLength); if (VIX_OK != err) { goto quit; } if (msg->header.commonHeader.totalMessageLength < sizeof *msg) { err = VIX_E_INVALID_MESSAGE_BODY; goto quit; } headerAndBodyLength = (uint64) msg->header.commonHeader.headerLength + msg->header.commonHeader.bodyLength; if (headerAndBodyLength < ((uint64) sizeof *msg + msg->nameLength + 1 + msg->valueLength + 1)) { err = VIX_E_INVALID_MESSAGE_BODY; goto quit; } valueNameLocal = ((char *) msg) + sizeof(*msg); if ('\0' != valueNameLocal[msg->nameLength]) { err = VIX_E_INVALID_MESSAGE_BODY; goto quit; } valueLocal = valueNameLocal + msg->nameLength + 1; if ('\0' != valueLocal[msg->valueLength]) { err = VIX_E_INVALID_MESSAGE_BODY; goto quit; } *valueName = valueNameLocal; *value = valueLocal; err = VIX_OK; quit: return err; } // VixMsg_ParseWriteVariableRequest /* *----------------------------------------------------------------------------- * * VixMsgInitializeObfuscationMapping -- * * * Results: * None * * Side effects: * None. * *----------------------------------------------------------------------------- */ void VixMsgInitializeObfuscationMapping(void) { size_t charIndex; static Bool initializedTable = FALSE; if (initializedTable) { return; } for (charIndex = 0; charIndex < sizeof(PlainToObfuscatedCharMap); charIndex++) { PlainToObfuscatedCharMap[charIndex] = 0; ObfuscatedToPlainCharMap[charIndex] = 0; } PlainToObfuscatedCharMap['\\'] = '1'; PlainToObfuscatedCharMap['\''] = '2'; PlainToObfuscatedCharMap['\"'] = '3'; PlainToObfuscatedCharMap[' '] = '4'; PlainToObfuscatedCharMap['\r'] = '5'; PlainToObfuscatedCharMap['\n'] = '6'; PlainToObfuscatedCharMap['\t'] = '7'; ObfuscatedToPlainCharMap['1'] = '\\'; ObfuscatedToPlainCharMap['2'] = '\''; ObfuscatedToPlainCharMap['3'] = '\"'; ObfuscatedToPlainCharMap['4'] = ' '; ObfuscatedToPlainCharMap['5'] = '\r'; ObfuscatedToPlainCharMap['6'] = '\n'; ObfuscatedToPlainCharMap['7'] = '\t'; initializedTable = TRUE; } // VixMsgInitializeObfuscationMapping /* *----------------------------------------------------------------------------- * * VixMsg_ObfuscateNamePassword -- * * This is NOT ENCRYPTION. * * This function does 2 things: * * It removes spaces, quotes and other characters that may make * parsing params in a string difficult. The name and password is * passed from the VMX to the tools through the backdoor as a * string containing quoted parameters. * * * It means that somebody doing a trivial string search on * host memory won't see a name/password. * * This is used ONLY between the VMX and guest through the backdoor. * This is NOT secure. * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_ObfuscateNamePassword(const char *userName, // IN const char *password, // IN char **result) // OUT { VixError err = VIX_OK; char *packedBuffer = NULL; char *resultString = NULL; char *destPtr; size_t packedBufferLength = 0; size_t nameLength = 0; size_t passwordLength = 0; if (NULL != userName) { nameLength = strlen(userName); } if (NULL != password) { passwordLength = strlen(password); } /* * Leave space for null terminating characters. */ packedBufferLength = nameLength + 1 + passwordLength + 1; packedBuffer = VixMsg_MallocClientData(packedBufferLength); if (packedBuffer == NULL) { err = VIX_E_OUT_OF_MEMORY; goto quit; } destPtr = packedBuffer; if (NULL != userName) { Str_Strcpy(destPtr, userName, nameLength + 1); destPtr += nameLength; } *(destPtr++) = 0; if (NULL != password) { Str_Strcpy(destPtr, password, passwordLength + 1); destPtr += passwordLength; } *(destPtr++) = 0; err = VixMsgEncodeBuffer(packedBuffer, packedBufferLength, FALSE, &resultString); if (err != VIX_OK) { goto quit; } quit: Util_ZeroFree(packedBuffer, packedBufferLength); if (err == VIX_OK) { *result = resultString; } return err; } // VixMsg_ObfuscateNamePassword /* *----------------------------------------------------------------------------- * * VixMsg_DeObfuscateNamePassword -- * * This reverses VixMsg_ObfuscateNamePassword. * See the notes for that procedure. * * Results: * VixError. VIX_OK if successful. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_DeObfuscateNamePassword(const char *packagedName, // IN char **userNameResult, // OUT char **passwordResult) // OUT { VixError err; char *packedString = NULL; char *srcPtr; size_t packedStringLength; char *userName = NULL; char *passwd = NULL; err = VixMsgDecodeBuffer(packagedName, FALSE, &packedString, &packedStringLength); if (err != VIX_OK) { goto quit; } srcPtr = packedString; if (NULL != userNameResult) { Bool allocateFailed; userName = VixMsg_StrdupClientData(srcPtr, &allocateFailed); if (allocateFailed) { err = VIX_E_OUT_OF_MEMORY; goto quit; } } srcPtr = srcPtr + strlen(srcPtr); srcPtr++; if (NULL != passwordResult) { Bool allocateFailed; passwd = VixMsg_StrdupClientData(srcPtr, &allocateFailed); if (allocateFailed) { err = VIX_E_OUT_OF_MEMORY; goto quit; } } if (NULL != userNameResult) { *userNameResult = userName; userName = NULL; } if (NULL != passwordResult) { *passwordResult = passwd; passwd = NULL; } quit: Util_ZeroFree(packedString, packedStringLength); Util_ZeroFreeString(userName); Util_ZeroFreeString(passwd); return err; } // VixMsg_DeObfuscateNamePassword /* *----------------------------------------------------------------------------- * * VixMsg_EncodeString -- * * This makes a string safe to pass over a backdoor Tclo command as a * string. It base64 encodes a string, which removes quote, space, * backslash, and other characters. This will also allow us to pass * UTF-8 strings. * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_EncodeString(const char *str, // IN char **result) // OUT { if (NULL == str) { str = ""; } /* * Coverity flags this as a buffer overrun in the case where str is * assigned the empty string above, claiming that the underlying * Base64_Encode function directly indexes the array str at index 2; * however, that indexing is only done if the string length is greater * than 2, and clearly strlen("") is 0. */ /* coverity[overrun-buffer-val] */ return VixMsgEncodeBuffer(str, strlen(str), TRUE, result); } // VixMsg_EncodeString /* *----------------------------------------------------------------------------- * * VixMsgEncodeBuffer -- * * This makes a string safe to pass over a backdoor Tclo command as a * string. It base64 encodes a string, which removes quote, space, * backslash, and other characters. This will also allow us to pass * UTF-8 strings. * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsgEncodeBuffer(const uint8 *buffer, // IN size_t bufferLength, // IN Bool includeEncodingId, // IN: Add 'a' (ASCII) at start of output char ** result) // OUT { VixError err = VIX_OK; char *base64String = NULL; char *resultString = NULL; size_t resultBufferLength = 0; char *srcPtr; char *endSrcPtr; char *destPtr; size_t base64Length; base64Length = Base64_EncodedLength((uint8 const *) buffer, bufferLength); base64String = VixMsg_MallocClientData(base64Length); if (base64String == NULL) { err = VIX_E_OUT_OF_MEMORY; goto quit; } if (!(Base64_Encode((uint8 const *) buffer, bufferLength, base64String, base64Length, &base64Length))) { err = VIX_E_FAIL; goto quit; } VixMsgInitializeObfuscationMapping(); /* * Expand it to make space for escaping some characters. */ resultBufferLength = base64Length * 2; if (includeEncodingId) { resultBufferLength++; } resultString = VixMsg_MallocClientData(resultBufferLength + 1); if (resultString == NULL) { err = VIX_E_OUT_OF_MEMORY; goto quit; } destPtr = resultString; srcPtr = base64String; endSrcPtr = base64String + base64Length; if (includeEncodingId) { /* * Start with the character-set type. * 'a' means ASCII. */ *(destPtr++) = 'a'; } /* * Now, escape problematic characters. */ while (srcPtr < endSrcPtr) { if (PlainToObfuscatedCharMap[(unsigned int) (*srcPtr)]) { *(destPtr++) = '\\'; *(destPtr++) = PlainToObfuscatedCharMap[(unsigned int) (*srcPtr)]; } else { *(destPtr++) = *srcPtr; } srcPtr++; } VERIFY((destPtr - resultString) <= resultBufferLength); *destPtr = 0; quit: free(base64String); if (err == VIX_OK) { *result = resultString; } return err; } // VixMsgEncodeBuffer /* *----------------------------------------------------------------------------- * * VixMsg_DecodeString -- * * This reverses VixMsg_EncodeString. * See the notes for that procedure. * * Results: * VixError. VIX_OK if successful. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_DecodeString(const char *str, // IN char **result) // OUT { /* * Check the character set. * 'a' means ASCII. */ if ((NULL == str) || ('a' != *str)) { *result = NULL; return VIX_E_INVALID_ARG; } return VixMsgDecodeBuffer(str + 1, TRUE, result, NULL); } // VixMsg_DecodeString /* *----------------------------------------------------------------------------- * * VixMsgDecodeBuffer -- * * This reverses VixMsgEncodeBuffer. * See the notes for that procedure. * * Results: * VixError. VIX_OK if successful. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsgDecodeBuffer(const char *str, // IN Bool nullTerminateResult, // OUT char **result, // OUT size_t *bufferLength) // OUT: Optional { VixError err = VIX_OK; char *base64String = NULL; char *resultStr = NULL; char *srcPtr; char *destPtr; size_t resultStrAllocatedLength; size_t resultStrLogicalLength; Bool allocateFailed; if (NULL != bufferLength) { *bufferLength = 0; } /* * Remove escaped special characters. * Do this in a private copy because we will change the string in place. */ VixMsgInitializeObfuscationMapping(); base64String = VixMsg_StrdupClientData(str, &allocateFailed); if (allocateFailed) { err = VIX_E_OUT_OF_MEMORY; goto quit; } destPtr = base64String; srcPtr = base64String; while (*srcPtr) { if ('\\' == *srcPtr) { srcPtr++; /* * There should never be a null byte as part of an escape character or * an escape character than translates into a null byte. */ if ((0 == *srcPtr) || (0 == ObfuscatedToPlainCharMap[(unsigned int) (*srcPtr)])) { goto quit; } *(destPtr++) = ObfuscatedToPlainCharMap[(unsigned int) (*srcPtr)]; } else { *(destPtr++) = *srcPtr; } srcPtr++; } *destPtr = 0; /* * Add 1 to the Base64_DecodedLength(), since we base64 encoded the string * without the NUL terminator and need to add one. */ resultStrAllocatedLength = Base64_DecodedLength(base64String, destPtr - base64String); if (nullTerminateResult) { resultStrAllocatedLength += 1; } resultStr = Util_SafeMalloc(resultStrAllocatedLength); if (!Base64_Decode(base64String, resultStr, resultStrAllocatedLength, &resultStrLogicalLength) || (resultStrLogicalLength > resultStrAllocatedLength)) { free(resultStr); resultStr = NULL; goto quit; } if (nullTerminateResult) { VERIFY(resultStrLogicalLength < resultStrAllocatedLength); resultStr[resultStrLogicalLength] = 0; } if (NULL != bufferLength) { *bufferLength = resultStrLogicalLength; } quit: free(base64String); if (err == VIX_OK) { *result = resultStr; } return err; } // VixMsgDecodeBuffer /* *----------------------------------------------------------------------------- * * VixAsyncOp_ValidateCommandInfoTable -- * * Checks that the command info table is generally well-formed. * Makes sure that the table is big enough to contain all the * command op codes and that they are present in the right order. * * Results: * Bool * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool VixMsg_ValidateCommandInfoTable(void) { int i; /* * Check at compile time that there is as many entries in the * command info table as there are commands. We need the +1 since * VIX_COMMAND_UNKNOWN is in the table and its opcode is -1. * * If this has failed for you, you've probably added a new command to VIX * without adding it to the command info table above. */ ASSERT_ON_COMPILE(ARRAYSIZE(vixCommandInfoTable) == (VIX_COMMAND_LAST_NORMAL_COMMAND + 1)); /* * Iterated over all the elements in the command info table to make * sure that op code matches the index (they are shifted by one because * of VIX_COMMAND_UNKNOWN) and that every used entry has a non-NULL name. */ for (i = 0; i < ARRAYSIZE(vixCommandInfoTable); i++) { if (vixCommandInfoTable[i].used && ((vixCommandInfoTable[i].opCode != (i - 1)) || (NULL == vixCommandInfoTable[i].commandName))) { Warning("%s: Mismatch or NULL in command with op code %d at " "index %d.\n", __FUNCTION__, vixCommandInfoTable[i].opCode, i); return FALSE; } } return TRUE; } // VixMsg_ValidateCommandInfoTable /* *----------------------------------------------------------------------------- * * VixAsyncOp_GetDebugStrForOpCode -- * * Get a human readable string representing the given op code, or * "Unrecognized op" if the op code is invalid. * * Results: * const char * * * Side effects: * None * *----------------------------------------------------------------------------- */ const char * VixAsyncOp_GetDebugStrForOpCode(int opCode) // IN { const char *opName = "Unrecognized op"; const VixCommandInfo *commandInfo; commandInfo = VixGetCommandInfoForOpCode(opCode); if (NULL != commandInfo) { opName = commandInfo->commandName; ASSERT(NULL != opName); } return opName; } // VixAsyncOp_GetDebugStrForOpCode /* *----------------------------------------------------------------------------- * * VixMsg_GetCommandSecurityCategory -- * * Get the security category asociated with the given op code. * * Results: * VixCommandSecurityCategory: the security category for the op code, * or VIX_COMMAND_CATEGORY_UNKNOWN is the op code is invalid. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixCommandSecurityCategory VixMsg_GetCommandSecurityCategory(int opCode) // IN { VixCommandSecurityCategory category = VIX_COMMAND_CATEGORY_UNKNOWN; const VixCommandInfo *commandInfo; commandInfo = VixGetCommandInfoForOpCode(opCode); if (NULL != commandInfo) { category = commandInfo->category; } return category; } // VixMsg_GetCommandSecurityCategory /* *----------------------------------------------------------------------------- * * VixGetCommandInfoForOpCode -- * * Looks up the information for an opcode from the global op code table. * * Results: * A const pointer to the command info struct for the opCode, or NULL * if the op code is invalid. * * Side effects: * None * *----------------------------------------------------------------------------- */ static const VixCommandInfo * VixGetCommandInfoForOpCode(int opCode) // IN { const VixCommandInfo *commandInfo = NULL; if ((opCode >= VIX_COMMAND_UNKNOWN) && (opCode < VIX_COMMAND_LAST_NORMAL_COMMAND)) { /* Add 1 to the op code, since VIX_COMMAND_UNKNOWN is -1 */ if (vixCommandInfoTable[opCode + 1].used) { commandInfo = &vixCommandInfoTable[opCode + 1]; } } return commandInfo; } // VixGetCommandInfoForOpCode /* *----------------------------------------------------------------------------- * * VixMsg_AllocGenericRequestMsg -- * * Allocate and initialize a generic request message. * * Assumes the caller holds the lock to 'propertyList'. * * Results: * Returns VixError. * Upon retrun, *request will contain either the message with the * headers properly initialized or NULL. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_AllocGenericRequestMsg(int opCode, // IN uint64 cookie, // IN int credentialType, // IN const char *userNamePassword, // IN int options, // IN VixPropertyListImpl *propertyList, // IN VixCommandGenericRequest **request) // OUT { VixError err; VixCommandGenericRequest *requestLocal = NULL; size_t msgHeaderAndBodyLength; char *serializedBufferBody = NULL; size_t serializedBufferLength = 0; if (NULL == request) { ASSERT(0); err = VIX_E_FAIL; goto quit; } *request = NULL; if (NULL != propertyList) { err = VixPropertyList_Serialize(propertyList, FALSE, &serializedBufferLength, &serializedBufferBody); if (VIX_OK != err) { goto quit; } } msgHeaderAndBodyLength = sizeof(*requestLocal) + serializedBufferLength; requestLocal = (VixCommandGenericRequest *) VixMsg_AllocRequestMsg(msgHeaderAndBodyLength, opCode, cookie, credentialType, userNamePassword); if (NULL == requestLocal) { err = VIX_E_FAIL; goto quit; } requestLocal->options = options; requestLocal->propertyListSize = serializedBufferLength; if (NULL != serializedBufferBody) { char *dst = (char *)request + sizeof(*request); memcpy(dst, serializedBufferBody, serializedBufferLength); } *request = requestLocal; err = VIX_OK; quit: free(serializedBufferBody); return err; } // VixMsg_AllocGenericRequestMsg /* *----------------------------------------------------------------------------- * * VixMsg_ParseGenericRequestMsg -- * * Extract the options and property list from the request * message, while validating message. * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixMsg_ParseGenericRequestMsg(const VixCommandGenericRequest *request, // IN int *options, // OUT VixPropertyListImpl *propertyList) // OUT { VixError err; uint64 headerAndBodyLength; if ((NULL == request) || (NULL == options) || (NULL == propertyList)) { ASSERT(0); err = VIX_E_FAIL; goto quit; } *options = 0; VixPropertyList_Initialize(propertyList); /* * In most cases we will have already called VixMsg_ValidateResponseMsg() * on this request before, but call it here so that this function will * always be sufficient to validate the request. */ err = VixMsg_ValidateRequestMsg(request, request->header.commonHeader.totalMessageLength); if (VIX_OK != err) { goto quit; } if (request->header.commonHeader.totalMessageLength < sizeof *request) { err = VIX_E_INVALID_MESSAGE_BODY; goto quit; } headerAndBodyLength = (uint64) request->header.commonHeader.headerLength + request->header.commonHeader.bodyLength; if (headerAndBodyLength < ((uint64) sizeof *request + request->propertyListSize)) { err = VIX_E_INVALID_MESSAGE_BODY; goto quit; } if (request->propertyListSize > 0) { const char *serializedBuffer = (const char *) request + sizeof(*request); err = VixPropertyList_Deserialize(propertyList, serializedBuffer, request->propertyListSize, VIX_PROPERTY_LIST_BAD_ENCODING_ERROR); if (VIX_OK != err) { goto quit; } } *options = request->options; err = VIX_OK; quit: return err; } // VixMsg_ParseGenericRequestMsg /* *----------------------------------------------------------------------------- * * VixMsg_ParseSimpleResponseWithString -- * * Takes a response packet that consists of a VixCommandResponseHeader * followed by a string containing the response data, validates * the packet, and then passes out a pointer to that string. * * Results: * VixError * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixMsg_ParseSimpleResponseWithString(const VixCommandResponseHeader *response, // IN const char **result) // OUT { VixError err; VMAutomationMsgParser parser; err = VMAutomationMsgParserInitResponse(&parser, response, sizeof *response); if (VIX_OK != err) { goto quit; } err = VMAutomationMsgParserGetOptionalString(&parser, response->commonHeader.bodyLength, result); quit: return err; } /* *----------------------------------------------------------------------------- * * VixMsg_MallocClientData -- * * Allocates the memory needed to copy from a client-provided buffer. * * Results: * Pointer to allocated memory * * Side effects: * None. * *----------------------------------------------------------------------------- */ void * VixMsg_MallocClientData(size_t size) // IN { return malloc(size); } // VixMsg_MallocClientData /* *----------------------------------------------------------------------------- * * VixMsg_ReallocClientData -- * * Reallocates the memory needed to copy from a client-provided buffer. * * Results: * Pointer to allocated memory * * Side effects: * Frees memory pointed to by ptr. * *----------------------------------------------------------------------------- */ void * VixMsg_ReallocClientData(void *ptr, // IN size_t size) // IN { return realloc(ptr, size); } // VixMsg_ReallocClientData /* *----------------------------------------------------------------------------- * * VixMsg_StrdupClientData -- * * Allocates memory and copies client-provided string. * * Results: * Pointer to allocated string * * Side effects: * None. * *----------------------------------------------------------------------------- */ char * VixMsg_StrdupClientData(const char *s, // IN Bool *allocateFailed) // OUT { char* newString = NULL; ASSERT(allocateFailed); if (NULL == allocateFailed) { goto quit; } *allocateFailed = FALSE; if (NULL != s) { #if defined(_WIN32) newString = _strdup(s); #else newString = strdup(s); #endif if (NULL == newString) { *allocateFailed = TRUE; } } quit: return newString; } // VixMsg_StrdupClientData /* *----------------------------------------------------------------------------- * * __VMAutomationValidateString -- * * Verifies that string at specified address is NUL terminated within * specified number of bytes, and is valid UTF-8. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static VixError __VMAutomationValidateString(const char *caller, // IN unsigned int line, // IN const char *buffer, // IN size_t available) // IN { size_t stringLength; /* * NUL terminated string needs at least one byte - NUL one. */ if (available < 1) { Log("%s(%u): Message body too short to contain string.\n", caller, line); return VIX_E_INVALID_MESSAGE_BODY; } /* * Reject message if there is no NUL before request end. There must * be one... */ stringLength = Str_Strlen(buffer, available); if (stringLength >= available) { Log("%s(%u): Variable string is not NUL terminated " "before message end.\n", caller, line); return VIX_E_INVALID_MESSAGE_BODY; } /* * If string is shorter than expected, complain. Maybe it is too strict, * but clients seems to not send malformed messages, so keep doing this. */ if (stringLength + 1 != available) { Log("%s(%u): Retrieved fixed string \"%s\" with " "trailing garbage.\n", caller, line, buffer); return VIX_E_INVALID_MESSAGE_BODY; } /* * If string is not UTF-8, reject it. We do not want to pass non-UTF-8 * strings through vmx bowels - they could hit some ASSERT somewhere... */ if (!Unicode_IsBufferValid(buffer, stringLength, STRING_ENCODING_UTF8)) { Log("%s(%u): Variable string is not an UTF8 string.\n", caller, line); return VIX_E_INVALID_UTF8_STRING; } return VIX_OK; } /* *----------------------------------------------------------------------------- * * __VMAutomationValidateStringInBuffer -- * * Verifies that string at specified address is NUL terminated within * specified number of bytes, and is valid UTF-8. * String does not have to occupy the entire buffer. * * Results: * VixError. VIX_OK on success. * Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static VixError __VMAutomationValidateStringInBuffer(const char *caller, // IN unsigned int line, // IN const char *buffer, // IN size_t available, // IN size_t *strLen) // IN { size_t stringLength; /* * NUL terminated string needs at least one byte - NUL one. */ if (available < 1) { Log("%s(%u): Message body too short to contain string.\n", caller, line); return VIX_E_INVALID_MESSAGE_BODY; } /* * Reject message if there is no NUL before request end. There must * be one... */ stringLength = Str_Strlen(buffer, available); *strLen = stringLength; if (stringLength >= available) { Log("%s(%u): Variable string is not NUL terminated " "before message end.\n", caller, line); return VIX_E_INVALID_MESSAGE_BODY; } /* * If string is not UTF-8, reject it. We do not want to pass non-UTF-8 * strings through vmx bowels - they could hit some ASSERT somewhere... */ if (!Unicode_IsBufferValid(buffer, stringLength, STRING_ENCODING_UTF8)) { Log("%s(%u): Variable string is not an UTF8 string.\n", caller, line); return VIX_E_INVALID_UTF8_STRING; } return VIX_OK; } /* *----------------------------------------------------------------------------- * * __VMAutomationMsgParserInitRequest -- * VMAutomationMsgParserInitRequest -- * * Initializes request parser, and performs basic message validation * not performed elsewhere. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError __VMAutomationMsgParserInitRequest(const char *caller, // IN unsigned int line, // IN VMAutomationMsgParser *state, // OUT (opt) const VixCommandRequestHeader *msg, // IN size_t fixedLength) // IN { size_t miscDataLength = 0; /* * If the VM is encrypted, there is additional data factored into * the total message size that needs to be accounted for. */ if (VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1 & msg->requestFlags) { miscDataLength = sizeof(VixMsgAuthDataV1); } else { miscDataLength = 0; } return VMAutomationMsgParserInit(caller, line, state, &msg->commonHeader, sizeof *msg, fixedLength, miscDataLength, "request"); } /* *----------------------------------------------------------------------------- * * __VMAutomationMsgParserInitResponse -- * VMAutomationMsgParserInitResponse -- * * Initializes response parser, and performs basic message validation * not performed elsewhere. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError __VMAutomationMsgParserInitResponse(const char *caller, // IN unsigned int line, // IN VMAutomationMsgParser *state, // OUT (opt) const VixCommandResponseHeader *msg, // IN size_t fixedLength) // IN { return VMAutomationMsgParserInit(caller, line, state, &msg->commonHeader, sizeof *msg, fixedLength, 0, "response"); } /* *----------------------------------------------------------------------------- * * VMAutomationMsgParserInit -- * * Initializes message parser, and performs basic message validation * not performed elsewhere. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None * *----------------------------------------------------------------------------- */ static VixError VMAutomationMsgParserInit(const char *caller, // IN unsigned int line, // IN VMAutomationMsgParser *state, // OUT (opt) const VixMsgHeader *msg, // IN size_t headerLength, // IN size_t fixedLength, // IN size_t miscDataLength, // IN const char *packetType) // IN { uint32 headerAndBodyLength; // use int64 to prevent overflow int64 computedTotalLength = (int64)msg->headerLength + (int64)msg->bodyLength + (int64)msg->credentialLength + (int64)miscDataLength; int64 extBodySize = (int64)msg->headerLength + (int64)msg->bodyLength - (int64)fixedLength; if (computedTotalLength != (int64)msg->totalMessageLength) { Log("%s:%d, header information mismatch.\n", __FILE__, __LINE__); return VIX_E_INVALID_MESSAGE_HEADER; } if (extBodySize < 0) { Log("%s:%d, %s too short.\n", __FILE__, __LINE__, packetType); return VIX_E_INVALID_MESSAGE_HEADER; } /* * Protocol allows for headerLength expansion, but predefined structures * do not anticipate that even a bit. So give up if header length is * incompatible with our structures. */ if (msg->headerLength != headerLength) { Log("%s(%u): %s header length %u is not supported " "(%"FMTSZ"u is required).\n", caller, line, packetType, msg->headerLength, headerLength); return VIX_E_INVALID_MESSAGE_HEADER; } /* * Message looks reasonable. Skip over fixed part. */ headerAndBodyLength = msg->headerLength + msg->bodyLength; if (state) { state->currentPtr = (const char *)msg + fixedLength; state->endPtr = (const char *)msg + headerAndBodyLength; } return VIX_OK; } /* *----------------------------------------------------------------------------- * * VMAutomation_VerifyRequestLength -- * * Ensures that request contains at least fixedLength bytes in * header and body. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VMAutomation_VerifyRequestLength(const VixCommandRequestHeader *request, // IN size_t fixedLength) // IN { return VMAutomationMsgParserInitRequest(NULL, request, fixedLength); } /* *----------------------------------------------------------------------------- * * VMAutomationMsgParserGetRemainingData -- * * Fetches all data remaining in the request. * * Results: * Pointer to the data. * * Side effects: * None. * *----------------------------------------------------------------------------- */ const void * VMAutomationMsgParserGetRemainingData(VMAutomationMsgParser *state, // IN/OUT size_t *length) // OUT { const void *data; *length = state->endPtr - state->currentPtr; data = state->currentPtr; state->currentPtr = state->endPtr; return data; } /* *----------------------------------------------------------------------------- * * VMAutomationMsgParserGetData -- * __VMAutomationMsgParserGetData -- * * Fetches specified number of bytes. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError __VMAutomationMsgParserGetData(const char *caller, // IN unsigned int line, // IN VMAutomationMsgParser *state, // IN/OUT size_t length, // IN const char **result) // OUT (opt) { size_t available; available = state->endPtr - state->currentPtr; /* If message is too short, return an error. */ if (available < length) { Log("%s(%u): Message has only %"FMTSZ"u bytes available when " "looking for %"FMTSZ"u bytes od data.\n", caller, line, available, length); return VIX_E_INVALID_MESSAGE_BODY; } if (result) { *result = state->currentPtr; } state->currentPtr += length; return VIX_OK; } /* *----------------------------------------------------------------------------- * * VMAutomationMsgParserGetOptionalString -- * __VMAutomationMsgParserGetOptionalString -- * * Fetches string of specified length from the request. Length includes * terminating NUL byte, which must be present. Length of zero results * in NULL being returned. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError __VMAutomationMsgParserGetOptionalString(const char *caller, // IN unsigned int line, // IN VMAutomationMsgParser *state, // IN/OUT size_t length, // IN const char **result) // OUT { if (length) { VixError err; const char *string; err = __VMAutomationMsgParserGetData(caller, line, state, length, &string); if (VIX_OK != err) { return err; } err = __VMAutomationValidateString(caller, line, string, length); if (VIX_OK != err) { return err; } *result = string; } else { *result = NULL; } return VIX_OK; } /* *----------------------------------------------------------------------------- * * VMAutomationMsgParserGetOptionalStrings -- * __VMAutomationMsgParserGetOptionalStrings -- * * Fetches an array of strings from the request. Length includes the * terminating NUL byte of each string. * * Results: * VixError. VIX_OK on success. * Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError __VMAutomationMsgParserGetOptionalStrings(const char *caller, // IN unsigned int line, // IN VMAutomationMsgParser *state, // IN/OUT uint32 count, // IN size_t length, // IN const char **result) // OUT { VixError err = VIX_OK; const char *buffer; const char *theResult; int i; size_t strLen; if (0 == count) { *result = NULL; goto quit; } err = __VMAutomationMsgParserGetData(caller, line, state, length, &buffer); if (VIX_OK != err) { return err; } theResult = buffer; for (i = 0; i < count; ++i) { err = __VMAutomationValidateStringInBuffer(caller, line, buffer, length, &strLen); if (VIX_OK != err) { return err; } ASSERT(strLen < length); buffer += (strLen + 1); length -= (strLen + 1); } /* * If string is shorter than expected, complain. Maybe it is too strict, * but clients seems to not send malformed messages, so keep doing this. */ if (length != 0) { Log("%s(%u): Retrieved an array of string with trailing garbage.\n", caller, line); return VIX_E_INVALID_MESSAGE_BODY; } *result = theResult; quit: return err; } /* *----------------------------------------------------------------------------- * * VMAutomationMsgParserGetString -- * __VMAutomationMsgParserGetString -- * * Fetches string of specified length from the request. Length of * string is specified in number of usable characters: function consumes * length + 1 bytes from request, and first length bytes must be non-NUL, * while length+1st byte must be NUL. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError __VMAutomationMsgParserGetString(const char *caller, // IN unsigned int line, // IN VMAutomationMsgParser *state, // IN/OUT size_t length, // IN const char **result) // OUT { VixError err; const char *string; length++; if (!length) { Log("%s(%u): String is too long.\n", caller, line); return VIX_E_INVALID_ARG; } err = __VMAutomationMsgParserGetData(caller, line, state, length, &string); if (VIX_OK != err) { return err; } err = __VMAutomationValidateString(caller, line, string, length); if (VIX_OK != err) { return err; } *result = string; return VIX_OK; } /* *----------------------------------------------------------------------------- * * VMAutomationMsgParserGetPropertyList -- * __VMAutomationMsgParserGetPropertyList -- * * Fetches specified number of bytes. * * Results: * VixError. VIX_OK on success. Some other VIX_* code if message is malformed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError __VMAutomationMsgParserGetPropertyList(const char *caller, // IN unsigned int line, // IN VMAutomationMsgParser *state, // IN/OUT size_t length, // IN VixPropertyListImpl *propList) // IN/OUT { VixError err; err = VIX_OK; if (length) { const char *data; err = __VMAutomationMsgParserGetData(caller, line, state, length, &data); if (VIX_OK == err) { err = VixPropertyList_Deserialize(propList, data, length, VIX_PROPERTY_LIST_BAD_ENCODING_ERROR); } } return err; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/foundryMsg/foundryPropertyListCommon.c000066400000000000000000001534431470176644300306420ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2016, 2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * foundryPropertyListCommon.c -- * * Some utility functions for manipulating property lists. Property * lists are now used in both the client and the VMX. The VMX uses them * as part of the socket protocol with the client. As a result, these * functions have been factored out into the stand-alone message library * so it can be used by the VMX tree without also linking in the * entire foundry client-side library. */ #include "vmware.h" #include "util.h" #include "str.h" #include "unicode.h" #include "vixCommands.h" #include "vixOpenSource.h" /* * The length of the 'size' field is 4 bytes -- avoid the confusion * of size_t on 32 vs 64 bit platforms. */ #define PROPERTY_LENGTH_SIZE 4 /* * Lets not trust sizeof() */ #define PROPERTY_SIZE_INT32 4 #define PROPERTY_SIZE_INT64 8 #define PROPERTY_SIZE_BOOL 1 // The size may be different on different machines. // To be safe, we always use 8 bytes. #define PROPERTY_SIZE_POINTER 8 static VixError VixPropertyListDeserializeImpl(VixPropertyListImpl *propList, const char *buffer, size_t bufferSize, Bool clobber, VixPropertyListBadEncodingAction action); /* *----------------------------------------------------------------------------- * * VixPropertyList_Initialize -- * * Initialize a list to be empty. This is an internal function * that is used both when we allocate a property list that wil be passed * to the client as a handle, and when we allocate an internal property * list that was not allocated as a handle. * * Results: * None. * * Side effects: * *----------------------------------------------------------------------------- */ void VixPropertyList_Initialize(VixPropertyListImpl *propList) // IN { ASSERT(propList); propList->properties = NULL; } // VixPropertyList_Initialize /* *----------------------------------------------------------------------------- * * VixPropertyList_RemoveAllWithoutHandles -- * * Delete all properties in a list. This is an internal procedure * that takes a VixPropertyListImpl as a parameter. * * Results: * None * * Side effects: * The property list is empty. * *----------------------------------------------------------------------------- */ void VixPropertyList_RemoveAllWithoutHandles(VixPropertyListImpl *propList) // IN { VixPropertyValue *property; if (NULL == propList) { return; } while (NULL != propList->properties) { property = propList->properties; propList->properties = property->next; if (VIX_PROPERTYTYPE_STRING == property->type) { if (property->isSensitive) { Util_ZeroString(property->value.strValue); } free(property->value.strValue); } else if (VIX_PROPERTYTYPE_BLOB == property->type) { if (property->isSensitive) { Util_Zero(property->value.blobValue.blobContents, property->value.blobValue.blobSize); } free(property->value.blobValue.blobContents); } free(property); } } // VixPropertyList_RemoveAllWithoutHandles /* *----------------------------------------------------------------------------- * * VixPropertyList_MarkAllSensitive -- * * Mark all properties in a list sensitive. * * Results: * As above * * Side effects: * None * *----------------------------------------------------------------------------- */ void VixPropertyList_MarkAllSensitive(VixPropertyListImpl *propList) // IN/OUT: { if (NULL != propList) { VixPropertyValue *property = propList->properties; while (NULL != property) { property->isSensitive = TRUE; property = property->next; } } } // VixPropertyList_MarkAllSensitive /* *----------------------------------------------------------------------------- * * VixPropertyList_Serialize -- * * Serialize a property list to a buffer. The buffer is allocated by * this routine to be of the required size and should be freed by caller. * * This function should be modified to deal with the case of * properties of type VIX_PROPERTYTYPE_HANDLE. * * * Results: * VixError. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixPropertyList_Serialize(VixPropertyListImpl *propList, // IN: Bool dirtyOnly, // IN: size_t *resultSize, // OUT: char **resultBuffer) // OUT: { VixError err = VIX_OK; VixPropertyValue *property = NULL; char *serializeBuffer = NULL; int valueLength; size_t headerSize; size_t propertyIDSize; size_t propertyTypeSize; size_t propertyValueLengthSize; size_t bufferSize = 0; size_t pos = 0; ASSERT_ON_COMPILE(PROPERTY_LENGTH_SIZE == sizeof valueLength); if ((NULL == propList) || (NULL == resultSize) || (NULL == resultBuffer)) { err = VIX_E_INVALID_ARG; goto quit; } propertyIDSize = sizeof(property->propertyID); propertyTypeSize = sizeof(property->type); propertyValueLengthSize = PROPERTY_LENGTH_SIZE; headerSize = propertyIDSize + propertyTypeSize + propertyValueLengthSize; /* * Walk the property list to determine size of the needed buffer */ property = propList->properties; while (NULL != property) { /* * If only the dirty properties need to be serialized * then skip the unchanged ones. */ if (dirtyOnly && (!property->isDirty)) { property = property->next; continue; } bufferSize += headerSize; switch (property->type) { //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_INTEGER: bufferSize += PROPERTY_SIZE_INT32; break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_STRING: if (property->value.strValue) { valueLength = strlen(property->value.strValue) + 1; /* * The deserialization code rejects all non-UTF-8 strings. * There should not be any non-UTF-8 strings passing * through our code since we should have either converted * non-UTF-8 strings from system APIs to UTF-8, or validated * that any client-provided strings were UTF-8. But this * if we've missed something, this should hopefully catch the * offending code close to the act. */ if (!Unicode_IsBufferValid(property->value.strValue, valueLength, STRING_ENCODING_UTF8)) { Log("%s: attempted to send a non-UTF-8 string for " "property %d.\n", __FUNCTION__, property->propertyID); ASSERT(0); err = VIX_E_INVALID_UTF8_STRING; } bufferSize += valueLength; } else { err = VIX_E_INVALID_ARG; goto quit; } break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_BOOL: bufferSize += PROPERTY_SIZE_BOOL; break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_INT64: bufferSize += PROPERTY_SIZE_INT64; break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_BLOB: bufferSize += property->value.blobValue.blobSize; break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_POINTER: /* * We should not serialize any pointer. * Catch such programming errors. */ err = VIX_E_INVALID_ARG; Log("%s:%d, pointer properties cannot be serialized.\n", __FUNCTION__, __LINE__); goto quit; //////////////////////////////////////////////////////// default: err = VIX_E_UNRECOGNIZED_PROPERTY; goto quit; } property = property->next; } *resultBuffer = (char*) VixMsg_MallocClientData(bufferSize); if (NULL == *resultBuffer) { err = VIX_E_OUT_OF_MEMORY; goto quit; } serializeBuffer = *resultBuffer; pos = 0; property = propList->properties; /* * Write out the properties to the buffer in the following format: * PropertyID | PropertyType | DataLength | Data */ while (NULL != property) { /* * If only the dirty properties need to be serialized * then skip the unchanged ones. */ if (dirtyOnly && (!property->isDirty)) { property = property->next; continue; } memcpy(&(serializeBuffer[pos]), &(property->propertyID), propertyIDSize); pos += propertyIDSize; memcpy(&(serializeBuffer[pos]), &(property->type), propertyTypeSize); pos += propertyTypeSize; switch (property->type) { //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_INTEGER: valueLength = PROPERTY_SIZE_INT32; memcpy(&(serializeBuffer[pos]), &valueLength, propertyValueLengthSize); pos += propertyValueLengthSize; memcpy(&(serializeBuffer[pos]), &(property->value.intValue), valueLength); break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_STRING: valueLength = (int) strlen(property->value.strValue) + 1; memcpy(&(serializeBuffer[pos]), &valueLength, propertyValueLengthSize); pos += propertyValueLengthSize; Str_Strcpy(&(serializeBuffer[pos]), property->value.strValue, valueLength); break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_BOOL: valueLength = PROPERTY_SIZE_BOOL; memcpy(&(serializeBuffer[pos]), &valueLength, propertyValueLengthSize); pos += propertyValueLengthSize; memcpy(&(serializeBuffer[pos]), &(property->value.boolValue), valueLength); break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_INT64: valueLength = PROPERTY_SIZE_INT64; memcpy(&(serializeBuffer[pos]), &valueLength, propertyValueLengthSize); pos += propertyValueLengthSize; memcpy(&(serializeBuffer[pos]), &(property->value.int64Value), valueLength); break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_BLOB: if (property->value.blobValue.blobContents) { valueLength = property->value.blobValue.blobSize; memcpy(&(serializeBuffer[pos]), &valueLength, propertyValueLengthSize); pos += propertyValueLengthSize; memcpy(&(serializeBuffer[pos]), property->value.blobValue.blobContents, valueLength); } else { err = VIX_E_INVALID_ARG; goto quit; } break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_POINTER: NOT_IMPLEMENTED(); //////////////////////////////////////////////////////// default: err = VIX_E_UNRECOGNIZED_PROPERTY; goto quit; } pos += valueLength; property = property->next; } ASSERT(pos == bufferSize); *resultSize = bufferSize; quit: if (VIX_OK != err) { free(serializeBuffer); if (NULL != resultBuffer) { *resultBuffer = NULL; } if (NULL != resultSize) { *resultSize = 0; } } return err; } // FoundryPropertList_Serialize /* *----------------------------------------------------------------------------- * * VixPropertyList_Deserialize -- * * Deserialize a property list from a buffer. Repeated properties * are clobbered. * * Results: * VixError. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixPropertyList_Deserialize(VixPropertyListImpl *propList, // IN const char *buffer, // IN size_t bufferSize, // IN VixPropertyListBadEncodingAction action) // IN { return VixPropertyListDeserializeImpl(propList, buffer, bufferSize, TRUE, // clobber action); } // VixPropertyList_Deserialize /* *----------------------------------------------------------------------------- * * VixPropertyList_DeserializeNoClobber -- * * Deserialize a property list from a buffer. Repeated properties * are preserved. * * Results: * VixError. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixPropertyList_DeserializeNoClobber(VixPropertyListImpl *propList, // IN const char *buffer, // IN size_t bufferSize, // IN VixPropertyListBadEncodingAction action) // IN { return VixPropertyListDeserializeImpl(propList, buffer, bufferSize, FALSE, // clobber action); } // VixPropertyList_DeserializeNoClobber /* *----------------------------------------------------------------------------- * * VixPropertyListDeserializeImpl -- * * Deserialize a property list from a buffer. * * This function should be modified to deal with the case of * properties of type VIX_PROPERTYTYPE_HANDLE. * * Results: * VixError. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError VixPropertyListDeserializeImpl(VixPropertyListImpl *propList, // IN const char *buffer, // IN size_t bufferSize, // IN Bool clobber, // IN VixPropertyListBadEncodingAction action) // IN { VixError err = VIX_OK; VixPropertyValue *property = NULL; size_t pos = 0; char *strPtr; int *intPtr; Bool *boolPtr; int64 *int64Ptr; unsigned char* blobPtr; int *propertyIDPtr; int *lengthPtr; size_t propertyIDSize; size_t propertyTypeSize; size_t propertyValueLengthSize; size_t headerSize; VixPropertyType *propertyTypePtr; Bool allocateFailed; Bool needToEscape; if ((NULL == propList) || (NULL == buffer)) { err = VIX_E_INVALID_ARG; goto quit; } propertyIDSize = sizeof(*propertyIDPtr); propertyTypeSize = sizeof(*propertyTypePtr); propertyValueLengthSize = PROPERTY_LENGTH_SIZE; headerSize = propertyIDSize + propertyTypeSize + propertyValueLengthSize; /* * Read properties from the buffer and add them to the property list. */ while ((pos+headerSize) < bufferSize) { propertyIDPtr = (int*) &(buffer[pos]); pos += propertyIDSize; propertyTypePtr = (VixPropertyType*) &(buffer[pos]); pos += propertyTypeSize; lengthPtr = (int*) &(buffer[pos]); pos += propertyValueLengthSize; /* * Do not allow lengths of 0 or fewer bytes. Those do not make sense, * unless you can pass a NULL blob, which Serialize() does not allow. * Also, make sure the value is contained within the bounds of the buffer. */ if ((*lengthPtr < 1) || ((*lengthPtr + pos) > bufferSize)) { err = VIX_E_INVALID_SERIALIZED_DATA; goto quit; } /* * Create the property if missing */ if (clobber) { err = VixPropertyList_FindProperty(propList, *propertyIDPtr, *propertyTypePtr, 0, // index TRUE, //createIfMissing &property); } else { err = VixPropertyListAppendProperty(propList, *propertyIDPtr, *propertyTypePtr, &property); } if (VIX_OK != err) { goto quit; } /* * Initialize the property to the received value */ switch (*propertyTypePtr) { //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_INTEGER: if (PROPERTY_SIZE_INT32 != *lengthPtr) { err = VIX_E_INVALID_SERIALIZED_DATA; goto quit; } intPtr = (int*) &(buffer[pos]); property->value.intValue = *intPtr; break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_STRING: strPtr = (char*) &(buffer[pos]); /* * The length that Serialize() generates includes the terminating * NUL character. */ if (strPtr[*lengthPtr - 1] != '\0') { err = VIX_E_INVALID_SERIALIZED_DATA; goto quit; } needToEscape = FALSE; /* * Make sure the string is valid UTF-8 before copying it. We * expect all strings stored in the process to be UTF-8. */ if (!Unicode_IsBufferValid(strPtr, *lengthPtr, STRING_ENCODING_UTF8)) { Log("%s: non-UTF-8 string received for property %d.\n", __FUNCTION__, *propertyIDPtr); switch (action) { case VIX_PROPERTY_LIST_BAD_ENCODING_ERROR: err = VIX_E_INVALID_UTF8_STRING; goto quit; case VIX_PROPERTY_LIST_BAD_ENCODING_ESCAPE: needToEscape = TRUE; } } free(property->value.strValue); if (needToEscape) { property->value.strValue = Unicode_EscapeBuffer(strPtr, *lengthPtr, STRING_ENCODING_UTF8); if (NULL == property->value.strValue) { err = VIX_E_OUT_OF_MEMORY; goto quit; } } else { property->value.strValue = VixMsg_StrdupClientData(strPtr, &allocateFailed); if (allocateFailed) { err = VIX_E_OUT_OF_MEMORY; goto quit; } } break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_BOOL: if (PROPERTY_SIZE_BOOL != *lengthPtr) { err = VIX_E_INVALID_SERIALIZED_DATA; goto quit; } boolPtr = (Bool*) &(buffer[pos]); property->value.boolValue = *boolPtr; break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_INT64: if (PROPERTY_SIZE_INT64 != *lengthPtr) { err = VIX_E_INVALID_SERIALIZED_DATA; goto quit; } int64Ptr = (int64*) &(buffer[pos]); property->value.int64Value = *int64Ptr; break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_BLOB: blobPtr = (unsigned char*) &(buffer[pos]); property->value.blobValue.blobSize = *lengthPtr; /* * Use regular malloc() when allocating amounts specified by another * process. Admittedly we've already bounds checked it, but this is * pretty easy to handle. */ free(property->value.blobValue.blobContents); property->value.blobValue.blobContents = VixMsg_MallocClientData(*lengthPtr); if (NULL == property->value.blobValue.blobContents) { err = VIX_E_OUT_OF_MEMORY; goto quit; } memcpy(property->value.blobValue.blobContents, blobPtr, *lengthPtr); break; //////////////////////////////////////////////////////// case VIX_PROPERTYTYPE_POINTER: /* * Deserialize an pointer property should not be allowed. * An evil peer could send us such data. */ err = VIX_E_INVALID_SERIALIZED_DATA; Log("%s:%d, pointer properties cannot be serialized.\n", __FUNCTION__, __LINE__); goto quit; //////////////////////////////////////////////////////// default: err = VIX_E_UNRECOGNIZED_PROPERTY; goto quit; } pos += *lengthPtr; } quit: if ((VIX_OK != err) && (NULL != propList)) { VixPropertyList_RemoveAllWithoutHandles(propList); } return err; } // VixPropertyList_Deserialize /* *----------------------------------------------------------------------------- * * VixPropertyList_FindProperty -- * * This is an internal routine that finds a property in the list. * * If the property is found, then this also checks that the property * has an expected type; if the types mismatch thenit returns an error. * * It optionally creates a property if it is missing. * * Results: * VixError * * Side effects: * *----------------------------------------------------------------------------- */ VixError VixPropertyList_FindProperty(VixPropertyListImpl *propList, // IN int propertyID, // IN VixPropertyType type, // IN int index, // IN Bool createIfMissing, // IN VixPropertyValue **resultEntry) // OUT { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == resultEntry) { err = VIX_E_INVALID_ARG; goto quit; } *resultEntry = NULL; property = propList->properties; while (NULL != property) { if (propertyID == property->propertyID) { if (index > 0) { index--; } else { if ((VIX_PROPERTYTYPE_ANY != type) && (type != property->type)) { err = VIX_E_TYPE_MISMATCH; } *resultEntry = property; goto quit; } } // (propertyID == property->propertyID) property = property->next; } // while (NULL != property) /* * If we get to here, then the property doesn't exist. * Either create it or return an error. */ if (!createIfMissing) { err = VIX_E_UNRECOGNIZED_PROPERTY; goto quit; } err = VixPropertyListAppendProperty(propList, propertyID, type, resultEntry); quit: return err; } /* *----------------------------------------------------------------------------- * * VixPropertyListAppendProperty -- * * This is an internal routine that creates a property for the * append routines. * * Results: * VixError * * Side effects: * *----------------------------------------------------------------------------- */ VixError VixPropertyListAppendProperty(VixPropertyListImpl *propList, // IN int propertyID, // IN VixPropertyType type, // IN VixPropertyValue **resultEntry) // OUT { VixError err = VIX_OK; VixPropertyValue *lastProperty; VixPropertyValue *property = NULL; if (NULL == resultEntry) { err = VIX_E_INVALID_ARG; goto quit; } *resultEntry = NULL; property = (VixPropertyValue *) Util_SafeCalloc(1, sizeof(VixPropertyValue)); property->type = type; property->propertyID = propertyID; property->isDirty = TRUE; property->isSensitive = FALSE; /* * We only have to initialize the values that we release, so * we don't try to release an invalid reference. */ if (VIX_PROPERTYTYPE_STRING == property->type) { property->value.strValue = NULL; } else if (VIX_PROPERTYTYPE_BLOB == property->type) { property->value.blobValue.blobContents = NULL; } else if (VIX_PROPERTYTYPE_HANDLE == property->type) { property->value.handleValue = VIX_INVALID_HANDLE; } /* * Put the new property on the end of the list. Some property lists, * like a list of VMs or snapshots, assume the order is meaningful and * so it should be preserved. */ lastProperty = propList->properties; while ((NULL != lastProperty) && (NULL != lastProperty->next)) { lastProperty = lastProperty->next; } if (NULL == lastProperty) { propList->properties = property; } else { lastProperty->next = property; } property->next = NULL; *resultEntry = property; quit: return err; } // VixPropertyListAppendProperty /* *----------------------------------------------------------------------------- * * VixPropertyList_GetString -- * * Return a copy of a string property value. The value is identified * by the integer property ID. * * This fails if the value is not present, or if it is a different * type, or if the caller did not pass a valid out parameter to * receive the value. * * Results: * VixError. VIX_OK if the property was found. * VIX_E_UNRECOGNIZED_PROPERTY if the property was not found. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_GetString(VixPropertyListImpl *propList, // IN int propertyID, // IN int index, // IN char **resultValue) // OUT { VixError err = VIX_OK; VixPropertyValue *property = NULL; if ((NULL == propList) || (NULL == resultValue)) { err = VIX_E_INVALID_ARG; goto quit; } *resultValue = NULL; err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_STRING, index, FALSE, &property); if (VIX_OK != err) { goto quit; } if (NULL != property->value.strValue) { *resultValue = Util_SafeStrdup(property->value.strValue); } quit: return err; } // VixPropertyList_GetString /* *----------------------------------------------------------------------------- * * VixPropertyListSetStringImpl -- * * Saves a copy of a string property value. Sets sensitivity. * * Results: * As above * * Side effects: * None * *----------------------------------------------------------------------------- */ static void VixPropertyListSetStringImpl(VixPropertyValue *property, // IN: const char *value, // IN: Bool isSensitive) // IN: { if (NULL != property->value.strValue) { if (property->isSensitive) { Util_ZeroString(property->value.strValue); } free(property->value.strValue); property->value.strValue = NULL; } if (NULL != value) { property->value.strValue = Util_SafeStrdup(value); } property->isDirty = TRUE; property->isSensitive = isSensitive; } // VixPropertyListSetStringImpl /* *----------------------------------------------------------------------------- * * VixPropertyList_SetString -- * * Saves a copy of a string property value. The value is identified * by the integer property ID. * * Value names are unique within a single property list. * If a previous value with the same propertyID value already * existed in this property list, then it is replaced with the new * value. Otherwise, a new value is added. * * This fails if the value is present but has a different type. * * Results: * VixError * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_SetString(VixPropertyListImpl *propList, // IN: int propertyID, // IN: const char *value) // IN: { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == propList) { err = VIX_E_INVALID_ARG; goto quit; } /* * Find or create an entry for this property. */ err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_STRING, 0, TRUE, &property); if (VIX_OK == err) { VixPropertyListSetStringImpl(property, value, property->isSensitive); } quit: return err; } // VixPropertyList_SetString /* *----------------------------------------------------------------------------- * * VixPropertyList_SetStringSensitive -- * * Saves a copy of a string property value. The value is identified * by the integer property ID. Mark sensitive. * * Value names are unique within a single property list. * If a previous value with the same propertyID value already * existed in this property list, then it is replaced with the new * value. Otherwise, a new value is added. * * This fails if the value is present but has a different type. * * Results: * VixError * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_SetStringSensitive(VixPropertyListImpl *propList, // IN: int propertyID, // IN: const char *value) // IN: { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == propList) { err = VIX_E_INVALID_ARG; goto quit; } /* * Find or create an entry for this property. */ err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_STRING, 0, TRUE, &property); if (VIX_OK == err) { VixPropertyListSetStringImpl(property, value, TRUE); } quit: return err; } // VixPropertyList_SetString /* *----------------------------------------------------------------------------- * * VixPropertyList_GetInteger -- * * Return a copy of a integer property value. The value is identified * by the integer property ID. * * This fails if the value is not present, or if it is a different * type, or if the caller did not pass a valid out parameter to * receive the value. * * Results: * VixError. VIX_OK if the property was found. * VIX_E_UNRECOGNIZED_PROPERTY if the property was not found. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_GetInteger(VixPropertyListImpl *propList, // IN int propertyID, // IN int index, // IN int *resultValue) // OUT { VixError err = VIX_OK; VixPropertyValue *property = NULL; if ((NULL == resultValue) || (NULL == propList)) { err = VIX_E_INVALID_ARG; goto quit; } err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_INTEGER, index, FALSE, &property); if (VIX_OK != err) { goto quit; } *resultValue = property->value.intValue; quit: return err; } // VixPropertyList_GetInteger /* *----------------------------------------------------------------------------- * * VixPropertyList_SetInteger -- * * Saves a copy of a integer property value. The value is identified * by the integer property ID. * * Value names are unique within a single property list. * If a previous value with the same propertyID value already * existed in this property list, then it is replaced with the new * value. Otherwise, a new value is added. * * This fails if the value is present but has a different type. * * Results: * VixError. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_SetInteger(VixPropertyListImpl *propList, // IN int propertyID, // IN int value) // IN { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == propList) { err = VIX_E_INVALID_ARG; goto quit; } /* * Find or create an entry for this property. */ err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_INTEGER, 0, TRUE, &property); if (VIX_OK != err) { goto quit; } property->value.intValue = value; property->isDirty = TRUE; quit: return err; } // VixPropertyList_SetInteger /* *----------------------------------------------------------------------------- * * VixPropertyList_GetBool -- * * Return a copy of a boolean property value. The value is identified * by the integer property ID. * * This fails if the value is not present, or if it is a different * type, or if the caller did not pass a valid out parameter to * receive the value. * * Results: * VixError. VIX_OK if the property was found. * VIX_E_UNRECOGNIZED_PROPERTY if the property was not found. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_GetBool(VixPropertyListImpl *propList, // IN int propertyID, // IN int index, // IN Bool *resultValue) // OUT { VixError err = VIX_OK; VixPropertyValue *property = NULL; if ((NULL == resultValue) || (NULL == propList)) { err = VIX_E_INVALID_ARG; goto quit; } err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_BOOL, index, FALSE, &property); if (VIX_OK != err) { goto quit; } if (NULL == property) { goto quit; } *resultValue = property->value.boolValue; quit: return err; } // VixPropertyList_GetBool /* *----------------------------------------------------------------------------- * * VixPropertyList_SetBool -- * * Saves a copy of a Bool property value. The value is identified * by the integer property ID. * * Value names are unique within a single property list. * If a previous value with the same propertyID value already * existed in this property list, then it is replaced with the new * value. Otherwise, a new value is added. * * This fails if the value is present but has a different type. * * Results: * VixError. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_SetBool(VixPropertyListImpl *propList, // IN int propertyID, // IN Bool value) // IN { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == propList) { err = VIX_E_INVALID_ARG; goto quit; } /* * Find or create an entry for this property. */ err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_BOOL, 0, TRUE, &property); if (VIX_OK != err) { goto quit; } property->value.boolValue = value; property->isDirty = TRUE; quit: return err; } /* *----------------------------------------------------------------------------- * * VixPropertyList_GetInt64 -- * * Return a copy of a Int64 property value. The value is identified * by the integer property ID. * * This fails if the value is not present, or if it is a different * type, or if the caller did not pass a valid out parameter to * receive the value. * * Results: * VixError. VIX_OK if the property was found. * VIX_E_UNRECOGNIZED_PROPERTY if the property was not found. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_GetInt64(VixPropertyListImpl *propList, // IN int propertyID, // IN int index, // IN int64 *resultValue) // OUT { VixError err = VIX_OK; VixPropertyValue *property = NULL; if ((NULL == resultValue) || (NULL == propList)) { err = VIX_E_INVALID_ARG; goto quit; } err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_INT64, index, FALSE, &property); if (VIX_OK != err) { goto quit; } *resultValue = property->value.int64Value; quit: return err; } // VixPropertyList_GetInt64 /* *----------------------------------------------------------------------------- * * VixPropertyList_SetInt64 -- * * Saves a copy of a int64 property value. The value is identified * by the integer property ID. * * Value names are unique within a single property list. * If a previous value with the same propertyID value already * existed in this property list, then it is replaced with the new * value. Otherwise, a new value is added. * * This fails if the value is present but has a different type. * * Results: * VixError. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_SetInt64(VixPropertyListImpl *propList, // IN int propertyID, // IN int64 value) // IN { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == propList) { err = VIX_E_INVALID_ARG; goto quit; } /* * Find or create an entry for this property. */ err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_INT64, 0, TRUE, &property); if (VIX_OK != err) { goto quit; } property->value.int64Value = value; property->isDirty = TRUE; quit: return err; } // VixPropertyList_SetInt64 /* *----------------------------------------------------------------------------- * * VixPropertyList_GetBlob -- * * Return a copy of a Blob property value. The value is identified * by the integer property ID. * * This fails if the value is not present, or if it is a different * type, or if the caller did not pass a valid out parameter to * receive the value. * * Results: * VixError. VIX_OK if the property was found. * VIX_E_UNRECOGNIZED_PROPERTY if the property was not found. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_GetBlob(VixPropertyListImpl *propList, // IN int propertyID, // IN int index, // IN int *resultSize, // OUT unsigned char **resultValue) // OUT { VixError err = VIX_OK; VixPropertyValue *property = NULL; if ((NULL == propList) || (NULL == resultSize) || (NULL == resultValue)) { err = VIX_E_INVALID_ARG; goto quit; } *resultSize = 0; *resultValue = NULL; err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_BLOB, index, FALSE, &property); if (VIX_OK != err) { goto quit; } if ((property->value.blobValue.blobSize > 0) && (NULL != property->value.blobValue.blobContents)) { *resultSize = property->value.blobValue.blobSize; *resultValue = Util_SafeMalloc(property->value.blobValue.blobSize); memcpy(*resultValue, property->value.blobValue.blobContents, property->value.blobValue.blobSize); } quit: return err; } // VixPropertyList_GetBlob /* *----------------------------------------------------------------------------- * * VixPropertyListSetBlobImpl -- * * Saves a copy of a blob property value. Set sensitivity. * * Results: * As above. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void VixPropertyListSetBlobImpl(VixPropertyValue *property, // IN: int blobSize, // IN: const unsigned char *value, // IN: Bool isSensitive) // IN: { if (NULL != property->value.blobValue.blobContents) { if (property->isSensitive) { Util_Zero(property->value.blobValue.blobContents, property->value.blobValue.blobSize); } free(property->value.blobValue.blobContents); property->value.blobValue.blobContents = NULL; } property->value.blobValue.blobSize = blobSize; if ((NULL != value) && (blobSize > 0)) { property->value.blobValue.blobContents = Util_SafeMalloc(blobSize); memcpy(property->value.blobValue.blobContents, value, blobSize); } property->isDirty = TRUE; property->isSensitive = isSensitive; } // VixPropertyListSetBlobImpl /* *----------------------------------------------------------------------------- * * VixPropertyList_SetBlob -- * * Saves a copy of a blob property value. The value is identified * by the integer property ID. * * Value names are unique within a single property list. * If a previous value with the same propertyID value already * existed in this property list, then it is replaced with the new * value. Otherwise, a new value is added. * * This fails if the value is present but has a different type. * * Results: * VixError. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_SetBlob(VixPropertyListImpl *propList, // IN: int propertyID, // IN: int blobSize, // IN: const unsigned char *value) // IN: { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == propList) { err = VIX_E_INVALID_ARG; goto quit; } /* * Find or create an entry for this property. */ err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_BLOB, 0, TRUE, &property); if (VIX_OK == err) { VixPropertyListSetBlobImpl(property, blobSize, value, property->isSensitive); } quit: return err; } // VixPropertyList_SetBlob /* *----------------------------------------------------------------------------- * * VixPropertyList_SetBlobSensitive -- * * Saves a copy of a blob property value. The value is identified * by the integer property ID. Set sentivity. * * Value names are unique within a single property list. * If a previous value with the same propertyID value already * existed in this property list, then it is replaced with the new * value. Otherwise, a new value is added. * * This fails if the value is present but has a different type. * * Results: * VixError. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_SetBlobSensitive(VixPropertyListImpl *propList, // IN: int propertyID, // IN: int blobSize, // IN: const unsigned char *value) // IN: { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == propList) { err = VIX_E_INVALID_ARG; goto quit; } /* * Find or create an entry for this property. */ err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_BLOB, 0, TRUE, &property); if (VIX_OK == err) { VixPropertyListSetBlobImpl(property, blobSize, value, TRUE); } quit: return err; } // VixPropertyList_SetBlob /* *----------------------------------------------------------------------------- * * VixPropertyList_GetPtr -- * * Return a copy of a void* property value. The value is identified * by the integer property ID. * * This is a SHALLOW copy. It only copies the pointer, not what the * pointer references. * * This fails if the value is not present, or if it is a different * type, or if the caller did not pass a valid out parameter to * receive the value. * * Results: * VixError. VIX_OK if the property was found. * VIX_E_UNRECOGNIZED_PROPERTY if the property was not found. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_GetPtr(VixPropertyListImpl *propList, // IN int propertyID, // IN int index, // IN void **resultValue) // OUT { VixError err = VIX_OK; VixPropertyValue *property = NULL; if ((NULL == resultValue) || (NULL == propList)) { err = VIX_E_INVALID_ARG; goto quit; } err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_POINTER, index, FALSE, &property); if (VIX_OK != err) { goto quit; } *resultValue = property->value.ptrValue; quit: return err; } // VixPropertyList_GetPtr /* *----------------------------------------------------------------------------- * * VixPropertyList_SetPtr -- * * Saves a copy of a ptr property value. The value is identified * by the integer property ID. * * This is a SHALLOW copy. It only copies the pointer, not what the * pointer references. * * Value names are unique within a single property list. * If a previous value with the same propertyID value already * existed in this property list, then it is replaced with the new * value. Otherwise, a new value is added. * * This fails if the value is present but has a different type. * * Results: * VixError. * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError VixPropertyList_SetPtr(VixPropertyListImpl *propList, // IN int propertyID, // IN void *value) // IN { VixError err = VIX_OK; VixPropertyValue *property = NULL; if (NULL == propList) { err = VIX_E_INVALID_ARG; goto quit; } /* * Find or create an entry for this property. */ err = VixPropertyList_FindProperty(propList, propertyID, VIX_PROPERTYTYPE_POINTER, 0, TRUE, &property); if (VIX_OK != err) { goto quit; } property->value.ptrValue = value; property->isDirty = TRUE; quit: return err; } // VixPropertyList_SetPtr /* *----------------------------------------------------------------------------- * * VixPropertyList_PropertyExists -- * * * Results: * Bool * * Side effects: * *----------------------------------------------------------------------------- */ Bool VixPropertyList_PropertyExists(VixPropertyListImpl *propList, // IN int propertyID, // IN VixPropertyType type) // IN { VixError err = VIX_OK; VixPropertyValue *property = NULL; Bool foundIt = FALSE; err = VixPropertyList_FindProperty(propList, propertyID, type, 0, // index FALSE, // createIfMissing &property); if ((VIX_OK == err) && (NULL != property)) { foundIt = TRUE; } return foundIt; } // VixPropertyList_PropertyExists /* *----------------------------------------------------------------------------- * * VixPropertyList_NumItems -- * * Returns a count of the properties in the list. * * Results: * int - Number of properties in property list. * * Side effects: * None. * *----------------------------------------------------------------------------- */ int VixPropertyList_NumItems(VixPropertyListImpl *propList) // IN { VixPropertyValue *prop; int count = 0; if (propList == NULL) { return 0; } for (prop = propList->properties; prop != NULL; prop = prop->next) { ++count; } return count; } // VixPropertyList_NumItems /* *----------------------------------------------------------------------------- * * VixPropertyList_Empty -- * * Returns whether the property list has no properties. * * Results: * Bool - True iff property list has no properties. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool VixPropertyList_Empty(VixPropertyListImpl *propList) // IN { return (propList == NULL || propList->properties == NULL); } // VixPropertyList_Empty open-vm-tools-stable-12.5.0/open-vm-tools/lib/foundryMsg/vixTranslateErrOpenSource.c000066400000000000000000000237261470176644300305420ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2017,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * vixTranslateErrorOpenSource.c -- * * Routines which translate between various other error code systems * into foundry errors. * * This is the minimal functions needed to build the tools for open source. * Most of the error translation functions are in foundryTranslateError.c, * which is NOT being released as open source. We do not want to include * any unnecessary error functions, since those use lots of different * error code definitions, and that would drag in a lot of headers from * bora/lib/public. */ #include "vmware.h" #include "vixOpenSource.h" #include #include #ifdef _WIN32 #include "windowsu.h" #endif /* *----------------------------------------------------------------------------- * * Vix_TranslateGuestRegistryError -- * * Translate a guest windows registry error to a Foundry error. * * Results: * VixError * * Side effects: * None. * *----------------------------------------------------------------------------- */ VixError Vix_TranslateGuestRegistryError(int systemError) // IN { VixError err = VIX_E_FAIL; #ifdef _WIN32 char *msg; switch (systemError) { case ERROR_INVALID_PARAMETER: case ERROR_FILE_NOT_FOUND: err = VIX_E_REG_KEY_INVALID; break; case ERROR_ACCESS_DENIED: err = VIX_E_GUEST_USER_PERMISSIONS; break; case ERROR_CHILD_MUST_BE_VOLATILE: err = VIX_E_REG_KEY_PARENT_VOLATILE; break; default: return Vix_TranslateSystemError(systemError); } msg = Win32U_FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, systemError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), NULL); Log("Foundry operation failed with guest windows registry error: %s (%d), translated to %"FMT64"d\n", msg, systemError, err); free(msg); #endif return err; } // Vix_TranslateGuestRegistryError /* *----------------------------------------------------------------------------- * * Vix_TranslateSystemError -- * * Translate a System error to a Foundry error. * * Results: * VixError * * Side effects: * *----------------------------------------------------------------------------- */ VixError Vix_TranslateSystemError(int systemError) // IN { VixError err; #ifdef _WIN32 char *msg; switch (systemError) { case ERROR_ACCESS_DENIED: err = VIX_E_FILE_ACCESS_ERROR; break; case ERROR_INVALID_NAME: err = VIX_E_FILE_NAME_INVALID; break; case ERROR_FILENAME_EXCED_RANGE: err = VIX_E_FILE_NAME_TOO_LONG; break; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_BAD_PATHNAME: case ERROR_DIRECTORY: case ERROR_BUFFER_OVERFLOW: err = VIX_E_FILE_NOT_FOUND; break; case ERROR_DIR_NOT_EMPTY: err = VIX_E_DIRECTORY_NOT_EMPTY; break; case ERROR_TOO_MANY_OPEN_FILES: case ERROR_NO_MORE_FILES: case ERROR_WRITE_PROTECT: case ERROR_WRITE_FAULT: case ERROR_READ_FAULT: case ERROR_SHARING_VIOLATION: case ERROR_SEEK: case ERROR_CANNOT_MAKE: Log("%s: system error = %d\n", __FUNCTION__, systemError); err = VIX_E_FILE_ERROR; break; case ERROR_HANDLE_DISK_FULL: case ERROR_DISK_FULL: err = VIX_E_DISK_FULL; break; case ERROR_FILE_EXISTS: case ERROR_ALREADY_EXISTS: err = VIX_E_FILE_ALREADY_EXISTS; break; case ERROR_BUSY: case ERROR_PATH_BUSY: err = VIX_E_OBJECT_IS_BUSY; break; case ERROR_INVALID_PARAMETER: err = VIX_E_INVALID_ARG; break; case ERROR_NOT_SUPPORTED: err = VIX_E_NOT_SUPPORTED; break; case ERROR_NO_DATA: case ERROR_INVALID_DATA: err = VIX_E_NOT_FOUND; break; case ERROR_NOT_ENOUGH_MEMORY: err = VIX_E_OUT_OF_MEMORY; break; default: err = VIX_E_FAIL; } msg = Win32U_FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, systemError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), NULL); Log("Foundry operation failed with system error: %s (%d), translated to %"FMT64"d\n", msg, systemError, err); free(msg); #else // linux, other *nix err = Vix_TranslateErrno(systemError); #endif return err; } // Vix_TranslateSystemError /* *----------------------------------------------------------------------------- * * Vix_TranslateCOMError -- * * Translate a COM (Windows) error to a Foundry error. * * Results: * VixError. * * Side effects: * None. * *----------------------------------------------------------------------------- */ #ifdef _WIN32 VixError Vix_TranslateCOMError(HRESULT hrError) // IN { VixError err = VIX_E_FAIL; switch (hrError) { case E_ACCESSDENIED: err = VIX_E_FILE_ACCESS_ERROR; break; case STG_E_PATHNOTFOUND: case STG_E_FILENOTFOUND: err = VIX_E_FILE_NOT_FOUND; break; case STG_E_MEDIUMFULL: err = VIX_E_DISK_FULL; break; case STG_E_FILEALREADYEXISTS: err = VIX_E_FILE_ALREADY_EXISTS; break; case E_INVALIDARG: case E_POINTER: err = VIX_E_INVALID_ARG; break; case E_NOTIMPL: case E_NOINTERFACE: err = VIX_E_NOT_SUPPORTED; break; case E_OUTOFMEMORY: err = VIX_E_OUT_OF_MEMORY; break; case E_FAIL: default: err = VIX_E_FAIL; } return err; } // Vix_TranslateCOMError #endif /* *----------------------------------------------------------------------------- * * Vix_TranslateCryptoError -- * * Translate a Crypto error to a Foundry error. * * Results: * VixError * * Side effects: * *----------------------------------------------------------------------------- */ VixError Vix_TranslateCryptoError(CryptoError cryptoError) // IN { if (CRYPTO_ERROR_SUCCESS == cryptoError) { return VIX_OK; } else if (CRYPTO_ERROR_OPERATION_FAILED == cryptoError) { return VIX_E_GUEST_USER_PERMISSIONS; } else if (CRYPTO_ERROR_UNKNOWN_ALGORITHM == cryptoError) { return VIX_E_CRYPTO_UNKNOWN_ALGORITHM; } else if (CRYPTO_ERROR_BAD_BUFFER_SIZE == cryptoError) { return VIX_E_CRYPTO_BAD_BUFFER_SIZE; } else if (CRYPTO_ERROR_INVALID_OPERATION == cryptoError) { return VIX_E_CRYPTO_INVALID_OPERATION; } else if (CRYPTO_ERROR_NOMEM == cryptoError) { return VIX_E_OUT_OF_MEMORY; } else if (CRYPTO_ERROR_NEED_PASSWORD == cryptoError) { return VIX_E_CRYPTO_NEED_PASSWORD; } else if (CRYPTO_ERROR_BAD_PASSWORD == cryptoError) { return VIX_E_CRYPTO_BAD_PASSWORD; } else if (CRYPTO_ERROR_IO_ERROR == cryptoError) { Log("%s: crypto error = %d\n", __FUNCTION__, (int)cryptoError); return VIX_E_FILE_ERROR; } else if (CRYPTO_ERROR_UNKNOWN_ERROR == cryptoError) { return VIX_E_FAIL; } else if (CRYPTO_ERROR_NAME_NOT_FOUND == cryptoError) { return VIX_E_CRYPTO_NOT_IN_DICTIONARY; } else if (CRYPTO_ERROR_NO_CRYPTO == cryptoError) { return VIX_E_CRYPTO_NO_CRYPTO; } return VIX_E_FAIL; } /* *----------------------------------------------------------------------------- * * Vix_TranslateErrno -- * * Translate a Posix errno to a Foundry error. * * Results: * VixError * * Side effects: * None * *----------------------------------------------------------------------------- */ VixError Vix_TranslateErrno(int systemError) // IN { VixError err = VIX_E_FAIL; /* * Be careful while adding new error code translations. This function is * complied for both Windows and POSIX guests. Few errors i.e. ETIMEDOUT, * ENOBUFS are defined only for POSIX guests. When a new error code * translation is added, make sure you build a sandbox job and it is * successful. */ switch (systemError) { case EPERM: case EACCES: err = VIX_E_FILE_ACCESS_ERROR; break; case EAGAIN: case EBUSY: err = VIX_E_OBJECT_IS_BUSY; break; case EEXIST: err = VIX_E_FILE_ALREADY_EXISTS; break; case EFBIG: err = VIX_E_FILE_TOO_BIG; break; case ENOTEMPTY: err = VIX_E_DIRECTORY_NOT_EMPTY; break; case ENOTDIR: err = VIX_E_NOT_A_DIRECTORY; break; #ifndef _WIN32 case ETIMEDOUT: case ENOBUFS: #endif case EIO: case EMFILE: case ENFILE: case EMLINK: case EROFS: Log("%s: errno = %d\n", __FUNCTION__, systemError); err = VIX_E_FILE_ERROR; break; case ENODEV: case ENOENT: err = VIX_E_FILE_NOT_FOUND; break; case ENOSPC: err = VIX_E_DISK_FULL; break; case EISDIR: err = VIX_E_NOT_A_FILE; break; case ESRCH: err = VIX_E_NO_SUCH_PROCESS; break; case ENAMETOOLONG: err = VIX_E_FILE_NAME_TOO_LONG; break; #ifndef _WIN32 case EMSGSIZE: #endif case EINVAL: err = VIX_E_INVALID_ARG; break; #ifndef _WIN32 case ELOOP: #endif case ENOMEM: err = VIX_E_OUT_OF_MEMORY; break; default: err = VIX_E_FAIL; } Log("Foundry operation failed with system error: %s (%d), translated to %"FMT64"d\n", strerror(systemError), systemError, err); return err; } // Vix_TranslateErrno open-vm-tools-stable-12.5.0/open-vm-tools/lib/glibUtils/000077500000000000000000000000001470176644300230255ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/glibUtils/Makefile.am000066400000000000000000000021751470176644300250660ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2011-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libGlibUtils.la libGlibUtils_la_CPPFLAGS = libGlibUtils_la_CPPFLAGS += @GLIB2_CPPFLAGS@ libGlibUtils_la_SOURCES = libGlibUtils_la_SOURCES += fileLogger.c libGlibUtils_la_SOURCES += stdLogger.c libGlibUtils_la_SOURCES += sysLogger.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/glibUtils/fileLogger.c000066400000000000000000000334571470176644300252640ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2019, 2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /** * @file fileLogger.c * * Logger that uses file streams and provides optional log rotation. */ #include "glibUtils.h" #include #include #include #if defined(G_PLATFORM_WIN32) # include # include # include "win32Access.h" #else # include # include #endif typedef struct FileLogger { GlibLogger handler; GIOChannel *file; gchar *path; gint logSize; guint64 maxSize; guint maxFiles; gboolean append; gboolean error; GMutex lock; } FileLogger; #if !defined(_WIN32) /* ******************************************************************************* * FileLoggerIsValid -- */ /** * * Checks that the file descriptor backing this logger is still valid. * * This is a racy workaround for an issue with glib code; or, rather, two * issues. The first issue is that we can't intercept G_LOG_FLAG_RECURSION, * and glib just quits when that happens (see gnome bug 618956). The second * is that if a GIOChannel channel write fails, that calls * g_io_channel_error_from_errno, which helpfully logs stuff, causing recursion. * Don't get me started on why that's, well, at least questionable. * * This is racy because between the check and the actual GIOChannel operation, * the state of the FD may have changed. In reality, since the bug this is * fixing happens in very special situations where code outside this file is * doing weird things like closing random fds, it should be OK. * * We may still get other write errors from the GIOChannel than EBADF, but * those would be harder to work around. Hopefully this handles the most usual * cases. * * See bug 783999 for some details about what triggers the bug. * * @param[in] logger The logger instance. * * @return TRUE if the I/O channel is still valid. * ******************************************************************************* */ static gboolean FileLoggerIsValid(FileLogger *logger) { if (logger->file != NULL) { int fd = g_io_channel_unix_get_fd(logger->file); return fcntl(fd, F_GETFD) >= 0; } return FALSE; } #else #define FileLoggerIsValid(logger) TRUE #endif /* * This function is a temporary workaround for a broken glib version * 2.42.2 that is missing g_get_user_name_utf8 export. After glib * is fixed this needs to be removed and call to GlibGetUserName * replaced by g_get_user_name. See bug 1434059 for details. */ const char* GlibGetUserName() { #if !defined(_WIN32) return g_get_user_name(); #else wchar_t buffer[256] = { 0 }; DWORD len = ARRAYSIZE(buffer); static char* user_name_utf8 = NULL; if (!user_name_utf8) { if (GetUserNameW(buffer, &len)) { user_name_utf8 = g_utf16_to_utf8(buffer, -1, NULL, NULL, NULL); } } return user_name_utf8; #endif } /* ******************************************************************************* * FileLoggerGetPath -- */ /** * * Parses the given template file name and expands embedded variables, and * places the log index information at the right position. * * The following variables are expanded: * * - ${USER}: user's login name. * - ${PID}: current process's pid. * - ${IDX}: index of the log file (for rotation). * * @param[in] data Log handler data. * @param[in] index Index of the log file. * * @return The expanded log file path. * ****************************************************************************** */ static gchar * FileLoggerGetPath(FileLogger *data, gint index) { gboolean hasIndex = FALSE; gchar indexStr[11]; gchar *logpath; gchar *vars[] = { "${USER}", NULL, "${PID}", NULL, "${IDX}", indexStr, }; gchar *tmp; size_t i; logpath = g_strdup(data->path); vars[1] = (char *) GlibGetUserName(); vars[3] = g_strdup_printf("%u", (unsigned int) getpid()); g_snprintf(indexStr, sizeof indexStr, "%d", index); for (i = 0; i < G_N_ELEMENTS(vars); i += 2) { char *last = logpath; char *start; while ((start = strstr(last, vars[i])) != NULL) { gchar *tmp; char *end = start + strlen(vars[i]); size_t offset = (start - last) + strlen(vars[i+1]); *start = '\0'; tmp = g_strdup_printf("%s%s%s", logpath, vars[i+1], end); g_free(logpath); logpath = tmp; last = logpath + offset; /* XXX: ugly, but well... */ if (i == 4) { hasIndex = TRUE; } } } g_free(vars[3]); /* * Always make sure we add the index if it's not 0, since that's used for * backing up old log files. */ if (index != 0 && !hasIndex) { char *sep = strrchr(logpath, '.'); char *pathsep = strrchr(logpath, '/'); if (pathsep == NULL) { pathsep = strrchr(logpath, '\\'); } if (sep != NULL && sep > pathsep) { *sep = '\0'; sep++; tmp = g_strdup_printf("%s.%d.%s", logpath, index, sep); } else { tmp = g_strdup_printf("%s.%d", logpath, index); } g_free(logpath); logpath = tmp; } return logpath; } /* ******************************************************************************* * FileLoggerOpen -- */ /** * * Opens a log file for writing, backing up the existing log file if one is * present. Only one old log file is preserved. * * @note Make sure this function is called with the write lock held. * * @param[in] data Log handler data. * * @return Log file pointer (NULL on error). * ******************************************************************************* */ static GIOChannel * FileLoggerOpen(FileLogger *data) { GIOChannel *logfile = NULL; gchar *path; g_return_val_if_fail(data != NULL, NULL); path = FileLoggerGetPath(data, 0); if (g_file_test(path, G_FILE_TEST_EXISTS)) { /* GStatBuf was added in 2.26. */ #if GLIB_CHECK_VERSION(2, 26, 0) GStatBuf fstats; #else struct stat fstats; #endif /* * In order to determine whether we should rotate the logs, * we are calling the system call stat() to get the existing log file * size. * The time of check vs. time of use issue does not apply to this use * case, as even the file size is increasing, it will not affect the log * rotation decision. So Suppress the fs_check_call coverity warning. */ /* coverity[fs_check_call] */ if (g_stat(path, &fstats) > -1) { data->logSize = (gint) fstats.st_size; } if (!data->append || data->logSize >= data->maxSize) { /* * Find the last log file and iterate back, changing the indices as we go, * so that the oldest log file has the highest index (the new log file * will always be index "0"). When not rotating, "maxFiles" is 1, so we * always keep one backup. */ guint id; GPtrArray *logfiles = g_ptr_array_new(); /* * Find the id of the last log file. The pointer array will hold * the names of all existing log files + the name of the last log * file, which may or may not exist. */ for (id = 0; id < data->maxFiles; id++) { gchar *log = FileLoggerGetPath(data, id); g_ptr_array_add(logfiles, log); if (!g_file_test(log, G_FILE_TEST_IS_REGULAR)) { break; } } /* Rename the existing log files, increasing their index by 1. */ for (id = logfiles->len - 1; id > 0; id--) { gchar *dest = g_ptr_array_index(logfiles, id); gchar *src = g_ptr_array_index(logfiles, id - 1); if (!g_file_test(dest, G_FILE_TEST_IS_DIR) && (!g_file_test(dest, G_FILE_TEST_EXISTS) || g_unlink(dest) == 0)) { /* * We should ignore an unlikely rename() system call failure, * as we should keep our service running with non-critical errors. * We cannot log the error because we are already in the log * handler context to avoid crash or recursive logging loop. */ /* coverity[check_return] */ g_rename(src, dest); } else { g_unlink(src); } } /* Cleanup. */ for (id = 0; id < logfiles->len; id++) { g_free(g_ptr_array_index(logfiles, id)); } g_ptr_array_free(logfiles, TRUE); data->logSize = 0; data->append = FALSE; } } logfile = g_io_channel_new_file(path, data->append ? "a" : "w", NULL); if (logfile != NULL) { g_io_channel_set_encoding(logfile, NULL, NULL); #ifdef VMX86_TOOLS /* * Make the logfile readable only by user and root/administrator. * Can't do anything if it fails, so ignore return. */ #ifdef _WIN32 (void) Win32Access_SetFileOwnerRW(path); #else /* coverity[toctou] */ (void) chmod(path, 0600); #endif #endif // VMX86_TOOLS } g_free(path); return logfile; } /* ******************************************************************************* * FileLoggerLog -- */ /** * * Logs a message to the configured destination file. Also opens the file for * writing if it hasn't been done yet. * * @param[in] domain Log domain. * @param[in] level Log level. * @param[in] message Message to log. * @param[in] data File logger. * ******************************************************************************* */ static void FileLoggerLog(const gchar *domain, GLogLevelFlags level, const gchar *message, gpointer data) { FileLogger *logger = data; gsize written; g_mutex_lock(&logger->lock); if (logger->error) { goto exit; } if (logger->file == NULL) { if (logger->file == NULL) { logger->file = FileLoggerOpen(data); } if (logger->file == NULL) { logger->error = TRUE; goto exit; } } if (!FileLoggerIsValid(logger)) { logger->error = TRUE; goto exit; } /* Write the log file and do log rotation accounting. */ if (g_io_channel_write_chars(logger->file, message, -1, &written, NULL) == G_IO_STATUS_NORMAL) { if (logger->maxSize > 0) { logger->logSize += (gint) written; if (logger->logSize >= logger->maxSize) { g_io_channel_unref(logger->file); logger->append = FALSE; logger->file = FileLoggerOpen(logger); logger->handler.logHeader = TRUE; } else { g_io_channel_flush(logger->file, NULL); } } else { g_io_channel_flush(logger->file, NULL); } } exit: g_mutex_unlock(&logger->lock); } /* ****************************************************************************** * FileLoggerDestroy -- */ /** * * Cleans up the internal state of a file logger. * * @param[in] _data File logger data. * ****************************************************************************** */ static void FileLoggerDestroy(gpointer data) { FileLogger *logger = data; if (logger->file != NULL) { g_io_channel_unref(logger->file); } g_mutex_clear(&logger->lock); g_free(logger->path); g_free(logger); } /* ******************************************************************************* * GlibUtils_CreateFileLogger -- */ /** * * @brief Creates a new file logger based on the given configuration. * * @param[in] path Path to log file. * @param[in] append Whether to append to existing log file. * @param[in] maxSize Maximum log file size (in MB, 0 = no limit). * @param[in] maxFiles Maximum number of old files to be kept. * * @return A new logger, or NULL on error. * ******************************************************************************* */ GlibLogger * GlibUtils_CreateFileLogger(const char *path, gboolean append, guint maxSize, guint maxFiles) { FileLogger *data = NULL; g_return_val_if_fail(path != NULL, NULL); data = g_new0(FileLogger, 1); data->handler.addsTimestamp = FALSE; data->handler.shared = FALSE; data->handler.logfn = FileLoggerLog; data->handler.dtor = FileLoggerDestroy; data->handler.logHeader = TRUE; data->path = g_filename_from_utf8(path, -1, NULL, NULL, NULL); if (data->path == NULL) { g_free(data); return NULL; } data->append = append; data->maxSize = maxSize * 1024 * 1024; data->maxFiles = maxFiles + 1; /* To account for the active log file. */ g_mutex_init(&data->lock); return &data->handler; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/glibUtils/stdLogger.c000066400000000000000000000147531470176644300251350ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /** * @file stdLogger.c * * A very simplified version of a file logger that uses the standard output * streams (stdout / stderr). */ #include "glibUtils.h" #include #if defined(_WIN32) static GMutex gConsoleLock; static gint gRefCount = 0; #endif typedef struct StdLogger { GlibLogger handler; #if defined(_WIN32) gboolean attached; #endif } StdLogger; /* ******************************************************************************* * StdLoggerLog -- */ /** * * Logs a message to stdout or stderr depending on its severity. * * @param[in] domain Unused. * @param[in] level Log level. * @param[in] message Message to log. * @param[in] data Logger data. * ******************************************************************************* */ static void StdLoggerLog(const gchar *domain, GLogLevelFlags level, const gchar *message, gpointer data) { gchar *local; FILE *dest = (level < G_LOG_LEVEL_MESSAGE) ? stderr : stdout; #if defined(_WIN32) StdLogger *sdata = data; if (!sdata->attached) { g_mutex_lock(&gConsoleLock); if (gRefCount != 0 || GlibUtils_AttachConsole()) { gRefCount++; sdata->attached = TRUE; } g_mutex_unlock(&gConsoleLock); } if (!sdata->attached) { return; } #endif local = g_locale_from_utf8(message, -1, NULL, NULL, NULL); if (local != NULL) { fputs(local, dest); g_free(local); } else { fputs(message, dest); } } /* ******************************************************************************* * StdLoggerDestroy -- */ /** * * Cleans up the internal state of the logger. * * @param[in] data Logger data. * ******************************************************************************* */ static void StdLoggerDestroy(gpointer data) { #if defined(_WIN32) StdLogger *sdata = data; g_mutex_lock(&gConsoleLock); if (sdata->attached && --gRefCount == 0) { FreeConsole(); } g_mutex_unlock(&gConsoleLock); #endif g_free(data); } #if defined(_WIN32) /* ******************************************************************************* * GlibUtilsIsRedirected -- */ /** * * Checks whether given standard device (standard input, standard output, * or standard error) has been redirected to an on-disk file/pipe. * Win32-only. * * @param[in] nStdHandle The standard device number. * * @return TRUE if device redirected to a file/pipe. * ******************************************************************************* */ static gboolean GlibUtilsIsRedirected(DWORD nStdHandle) { HANDLE handle = GetStdHandle(nStdHandle); DWORD type = handle ? GetFileType(handle) : FILE_TYPE_UNKNOWN; return type == FILE_TYPE_DISK || type == FILE_TYPE_PIPE; } /* ******************************************************************************* * GlibUtils_AttachConsole -- */ /** * * Attaches a console to the current process. If the parent process already has * a console open, reuse it. Otherwise, create a new console for the current * process. Win32-only. * * It's safe to call this function multiple times (it won't do anything if * the process already has a console). * * @note Attaching to the parent process's console is only available on XP and * later. * * @return Whether the process is attached to a console. * ******************************************************************************* */ gboolean GlibUtils_AttachConsole(void) { typedef BOOL (WINAPI *AttachConsoleFn)(DWORD); gboolean ret = TRUE; AttachConsoleFn _AttachConsole; BOOL reopenStdout; BOOL reopenStderr; if (GetConsoleWindow() != NULL) { goto exit; } reopenStdout = !GlibUtilsIsRedirected(STD_OUTPUT_HANDLE); reopenStderr = !GlibUtilsIsRedirected(STD_ERROR_HANDLE); if (!reopenStdout && !reopenStderr) { goto exit; } _AttachConsole = (AttachConsoleFn) GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "AttachConsole"); if ((_AttachConsole != NULL && _AttachConsole(ATTACH_PARENT_PROCESS)) || AllocConsole()) { FILE *fptr; if (reopenStdout) { fptr = _wfreopen(L"CONOUT$", L"a", stdout); if (fptr == NULL) { g_warning("_wfreopen failed for stdout/CONOUT$: %d (%s)", errno, strerror(errno)); ret = FALSE; } } if (reopenStderr) { fptr = _wfreopen(L"CONOUT$", L"a", stderr); if (fptr == NULL) { g_warning("_wfreopen failed for stderr/CONOUT$: %d (%s)", errno, strerror(errno)); ret = FALSE; } else { setvbuf(fptr, NULL, _IONBF, 0); } } } else { ret = FALSE; } exit: if (!ret) { g_warning("Console redirection unavailable."); } return ret; } #endif /* ******************************************************************************* * GlibUtils_CreateStdLogger -- */ /** * * @brief Configures a new std logger. * * @return A new logger instance. * ******************************************************************************* */ GlibLogger * GlibUtils_CreateStdLogger(void) { StdLogger *data = g_new0(StdLogger, 1); data->handler.logfn = StdLoggerLog; data->handler.addsTimestamp = FALSE; data->handler.shared = FALSE; data->handler.dtor = StdLoggerDestroy; return &data->handler; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/glibUtils/sysLogger.c000066400000000000000000000136431470176644300251560ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /** * @file sysLogger.c * * Logger that writes to syslog(3). Since there's only one "syslog connection" * for the whole application, this code does reference counting to allow * different domains to be configured with a "syslog" handler, and still be * able to call closelog(3) when appropriate. */ #include "glibUtils.h" #include #include #include typedef struct SysLogger { GlibLogger handler; gchar *domain; gint refcount; } SysLogger; static SysLogger *gSysLogger; static GMutex gSysLoggerLock; /* ******************************************************************************* * SysLoggerLog -- */ /** * * @brief Sends the given log message to syslog. * * @param[in] domain Unused. * @param[in] level Log level. * @param[in] message Message to log. * @param[in] data Unused. * ****************************************************************************** */ static void SysLoggerLog(const gchar *domain, GLogLevelFlags level, const gchar *message, gpointer data) { gchar *local; int priority; /* glib and syslog disagree about critical / error. */ if (level & G_LOG_LEVEL_ERROR) { priority = LOG_CRIT; } else if (level & G_LOG_LEVEL_CRITICAL) { priority = LOG_ERR; } else if (level & G_LOG_LEVEL_WARNING) { priority = LOG_WARNING; } else if (level & G_LOG_LEVEL_MESSAGE) { priority = LOG_NOTICE; } else if (level & G_LOG_LEVEL_INFO) { priority = LOG_INFO; } else { priority = LOG_DEBUG; } local = g_locale_from_utf8(message, -1, NULL, NULL, NULL); if (local != NULL) { syslog(priority, "%s", local); g_free(local); } else { syslog(priority, "%s", message); } } /* ******************************************************************************* * SysLoggerUnref -- */ /** * * @brief Decreases the ref count and closes syslog if it reaches 0. * * @param[in] data Unused. * ******************************************************************************* */ static void SysLoggerUnref(gpointer data) { g_return_if_fail(data == gSysLogger); g_return_if_fail(gSysLogger->refcount > 0); g_mutex_lock(&gSysLoggerLock); gSysLogger->refcount -= 1; if (gSysLogger->refcount == 0) { closelog(); g_free(gSysLogger->domain); g_free(gSysLogger); gSysLogger = NULL; } g_mutex_unlock(&gSysLoggerLock); } /* ******************************************************************************* * GlibUtils_CreateSysLogger -- */ /** * * @brief Initializes syslog if it hasn't been done yet. * * Since syslog is shared, it's not recommended to change the default domain * during the lifetime of the application, since that may not reflect on the * syslogs (and, when it does, it might be confusing). * * @param[in] domain Application name, used as the syslog identity. * @param[in] facility Facility to use. One of: "daemon", "local[0-7]", "user" (default). * * @return Syslog logger data. * ******************************************************************************* */ GlibLogger * GlibUtils_CreateSysLogger(const char *domain, const char *facility) { g_mutex_lock(&gSysLoggerLock); if (gSysLogger == NULL) { int facid = LOG_USER; if (facility != NULL) { int idx; if (strcmp(facility, "daemon") == 0) { facid = LOG_DAEMON; } else if (sscanf(facility, "local%d", &idx) == 1) { switch (idx) { case 0: facid = LOG_LOCAL0; break; case 1: facid = LOG_LOCAL1; break; case 2: facid = LOG_LOCAL2; break; case 3: facid = LOG_LOCAL3; break; case 4: facid = LOG_LOCAL4; break; case 5: facid = LOG_LOCAL5; break; case 6: facid = LOG_LOCAL6; break; case 7: facid = LOG_LOCAL7; break; default: g_message("Invalid local facility for %s: %s\n", domain, facility); break; } } else if (strcmp(facility, "user") != 0) { g_message("Invalid syslog facility for %s: %s\n", domain, facility); } } gSysLogger = g_new0(SysLogger, 1); gSysLogger->handler.addsTimestamp = TRUE; gSysLogger->handler.shared = FALSE; gSysLogger->handler.logfn = SysLoggerLog; gSysLogger->handler.dtor = SysLoggerUnref; gSysLogger->domain = g_strdup(domain); gSysLogger->refcount = 1; openlog(gSysLogger->domain, LOG_CONS | LOG_PID, facid); } else { gSysLogger->refcount += 1; } g_mutex_unlock(&gSysLoggerLock); return &gSysLogger->handler; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/globalConfig/000077500000000000000000000000001470176644300234555ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/globalConfig/Makefile.am000066400000000000000000000020731470176644300255130ustar00rootroot00000000000000################################################################################ ### Copyright (c) 2021 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libGlobalConfig.la libGlobalConfig_la_SOURCES = libGlobalConfig_la_SOURCES += globalConfig.c libGlobalConfig_la_CPPFLAGS = libGlobalConfig_la_CPPFLAGS += @GLIB2_CPPFLAGS@ open-vm-tools-stable-12.5.0/open-vm-tools/lib/globalConfig/globalConfig.c000066400000000000000000000734561470176644300262260ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2020-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /** * @file globalConfig.c * * Implementation of the module that downloads the configuration from the * GuestStore. */ /* Need this header in the beginning for GLOBALCONFIG_SUPPORTED definition. */ #include "globalConfig.h" #if !defined(GLOBALCONFIG_SUPPORTED) # error This file should not be compiled #endif #include #include "conf.h" #include "file.h" #include "guestApp.h" #include #include #ifdef _WIN32 #include #else #include #endif #include "str.h" #include "vmware/tools/guestStore.h" #include "vmware/tools/utils.h" #include "vmware/tools/threadPool.h" #include "guestStoreClient.h" /** * Default value for CONFNAME_GLOBALCONF_ENABLED setting in tools.conf. * * TRUE will enable the module. GlobalConf module is disabled by default. */ #define GLOBALCONF_DEFAULT_ENABLED FALSE /** * Default value for CONFNAME_GLOBALCONF_POLL_INTERVAL setting in tools.conf. */ #define GLOBALCONF_DEFAULT_POLL_INTERVAL (60 * 60) /** * Minimum poll interval for fetching the global configuration from GuestStore. */ #ifdef VMX86_DEBUG #define GLOBALCONF_MIN_POLL_INTERVAL (2 * 60) #else #define GLOBALCONF_MIN_POLL_INTERVAL (30 * 60) #endif /** * Default value for CONFNAME_GLOBALCONF_RESOURCE setting in tools.conf. */ #if defined(_WIN32) #define GLOBALCONF_DEFAULT_RESOURCE \ "/vmware/configurations/vmtools/windows/tools.conf" #else #define GLOBALCONF_DEFAULT_RESOURCE \ "/vmware/configurations/vmtools/linux/tools.conf" #endif /** * Name of the local file populated with the global tools configuration. */ #define GLOBALCONF_LOCAL_FILENAME "tools-global.conf" /** * Name of the local temp file populated with the global tools configuration. */ #define GLOBALCONF_LOCAL_TEMP_FILENAME "temp-global.conf" /** * Macro to get the resource path from the config dictionary. */ #define GLOBALCONF_GET_RESOURCE_PATH(cfg) \ VMTools_ConfigGetString(cfg, CONFGROUPNAME_GLOBALCONF, \ CONFNAME_GLOBALCONF_RESOURCE, \ GLOBALCONF_DEFAULT_RESOURCE) typedef struct GlobalConfigInfo { gchar *localConfPath; gchar *localTempPath; gchar *guestStoreResource; guint pollInterval; } GlobalConfigInfo; typedef struct GlobalConfigThreadState { /* * 'mutex' protect concurrent accesses to terminate, cond, guestStoreEnabled * and useRandomInterval. */ GMutex mutex; GCond cond; gboolean terminate; gboolean guestStoreEnabled; gboolean useRandomInterval; GlobalConfigInfo *configInfo; } GlobalConfigThreadState; static GlobalConfigThreadState globalConfigThreadState; /* ************************************************************************** * GuestStoreStateChanged -- */ /** * * GuestStore access state has changed, now update the download thread * accordingly. * * @param[in] src Unused * @param[in] guestStoreEnabled GuestStore state enabled if TRUE * @param[in] unused Unused * ************************************************************************** */ static void GuestStoreStateChanged(gpointer src, gboolean guestStoreEnabled, gpointer unused) { GlobalConfigThreadState *threadState = &globalConfigThreadState; g_mutex_lock(&threadState->mutex); g_debug("%s: GuestStore old state: %d and new state: %d\n", __FUNCTION__, threadState->guestStoreEnabled, guestStoreEnabled); if (threadState->guestStoreEnabled != guestStoreEnabled) { threadState->guestStoreEnabled = guestStoreEnabled; g_debug("%s: Signalling the change in the GuestStore state.\n", __FUNCTION__); g_cond_signal(&threadState->cond); } g_mutex_unlock(&threadState->mutex); } /* ************************************************************************** * GlobalConfigGetPollInterval -- */ /** * * Parses the configuration and returns the poll-interval. * * @param[in] cfg VMTools configuration dictionary. * * @return unsigned integer representing the poll interval. * 0 if the globalconfig module is disabled. * GLOBALCONF_DEFAULT_POLL_INTERVAL if an invalid value is specified. * ************************************************************************** */ static guint GlobalConfigGetPollInterval(GKeyFile *cfg) { gint pollInterval = 0; gboolean enabled = GlobalConfig_GetEnabled(cfg); if (!enabled) { g_info("%s: global config module is disabled.", __FUNCTION__); return pollInterval; } pollInterval = VMTools_ConfigGetInteger(cfg, CONFGROUPNAME_GLOBALCONF, CONFNAME_GLOBALCONF_POLL_INTERVAL, GLOBALCONF_DEFAULT_POLL_INTERVAL); if (pollInterval < GLOBALCONF_MIN_POLL_INTERVAL) { g_warning("%s: Invalid value %d specified for '%s'. Using default %us", __FUNCTION__, pollInterval, CONFNAME_GLOBALCONF_POLL_INTERVAL, GLOBALCONF_DEFAULT_POLL_INTERVAL); pollInterval = GLOBALCONF_DEFAULT_POLL_INTERVAL; } return pollInterval; } /* ************************************************************************** * GenerateRandomInterval -- */ /** * * Generate a random value between MIN_RAND_WAIT_INTERVAL and * MAX_RAND_WAIT_INTERVAL. * * @return a random generated unsigned integer value. * ************************************************************************** */ static guint GenerateRandomInterval(void) { GRand *gRand = g_rand_new(); /* * The following min and max values are taken randomly. */ #define MIN_RAND_WAIT_INTERVAL 30 #define MAX_RAND_WAIT_INTERVAL 300 guint randomInterval = g_rand_int_range(gRand, MIN_RAND_WAIT_INTERVAL, MAX_RAND_WAIT_INTERVAL); g_rand_free(gRand); #undef MIN_RAND_WAIT_INTERVAL #undef MAX_RAND_WAIT_INTERVAL g_info("%s: Using random interval: %u.\n", __FUNCTION__, randomInterval); return randomInterval; } /* ************************************************************************** * VMToolsChannelReset -- */ /** * * Callback function that gets called when the VMTools channel gets reset. * * @param[in] src Unused * @param[in] ctx Unused * @param[in] unused Unused * ************************************************************************** */ static void VMToolsChannelReset(gpointer src, ToolsAppCtx *ctx, gpointer unused) { GlobalConfigThreadState *threadState = &globalConfigThreadState; g_debug("%s: VMTools channel got reset.\n", __FUNCTION__); g_mutex_lock(&threadState->mutex); if (threadState->configInfo->pollInterval > 0) { /* * The RPC channel may get reset due to various conditions like * snapshotting the VM, vmotion the VM, instant cloning of the VM. * In order to avoid potential load spikes in case of instant clones, * wait for a randomized interval. */ threadState->useRandomInterval = TRUE; } g_mutex_unlock(&threadState->mutex); } /* ************************************************************************** * GlobalConfigToolsConfReload -- */ /** * * Callback function that gets called when the VMTools configuration gets * reloaded. * * @param[in] src Unused * @param[in] ctx Application Context * @param[in] unused Unused * ************************************************************************** */ static void GlobalConfigToolsConfReload(gpointer src, ToolsAppCtx *ctx, gpointer unused) { guint pollInterval; GlobalConfigThreadState *threadState = &globalConfigThreadState; gchar *newResourcePath; g_debug("%s: VMTools configuration got reloaded.\n", __FUNCTION__); g_mutex_lock(&threadState->mutex); newResourcePath = GLOBALCONF_GET_RESOURCE_PATH(ctx->config); if (g_strcmp0(newResourcePath, threadState->configInfo->guestStoreResource)) { g_info("%s: '%s' changed. Old: %s, New: %s\n", __FUNCTION__, CONFNAME_GLOBALCONF_RESOURCE, threadState->configInfo->guestStoreResource, newResourcePath); g_free(threadState->configInfo->guestStoreResource); threadState->configInfo->guestStoreResource = newResourcePath; } else { g_free(newResourcePath); newResourcePath = NULL; } pollInterval = GlobalConfigGetPollInterval(ctx->config); if (pollInterval != threadState->configInfo->pollInterval) { g_info("%s: '%s' changed. Old: '%u', New: '%u' " "Signalling the change in the globalConfing configuration.\n", __FUNCTION__, CONFNAME_GLOBALCONF_POLL_INTERVAL, threadState->configInfo->pollInterval, pollInterval); threadState->configInfo->pollInterval = pollInterval; g_cond_signal(&threadState->cond); } else if (pollInterval == 0) { /* * Delete the stale config files (if any). */ GlobalConfig_DeleteConfig(); } g_mutex_unlock(&threadState->mutex); } /* ************************************************************************** * GlobalConfGetConfPath -- */ /** * * Returns the path to the global configuration file. * * @return Path of the global configuration file. The caller shouldn't * free the memory. Returns NULL if the path cannot be computed. * ************************************************************************** */ static const gchar * GlobalConfGetConfPath(void) { static gchar *globalConfPath = NULL; if (globalConfPath == NULL) { char *guestAppConfPath = GuestApp_GetConfPath(); if (guestAppConfPath == NULL) { g_warning("%s: Failed to get configuration directory.\n", __FUNCTION__); } else { globalConfPath = g_build_filename(guestAppConfPath, GLOBALCONF_LOCAL_FILENAME, NULL); } free(guestAppConfPath); } return globalConfPath; } /* ************************************************************************** * GlobalConfigThreadStateInit -- */ /** * * Reads the key/value pairs related to globalconf module from the user * specified configuration dictionary and intializes the globaconf module. * * @param[in] cfg Tools configuration dictionary. * * @return TRUE if the globalconf module is initialized. * FALSE if any error happened while initializing. * ************************************************************************** */ static gboolean GlobalConfigThreadStateInit(GKeyFile *cfg) { gchar *guestAppConfPath; GlobalConfigInfo *configInfo; GlobalConfigThreadState *threadState = &globalConfigThreadState; ASSERT(cfg != NULL); guestAppConfPath = GuestApp_GetConfPath(); if (guestAppConfPath == NULL) { g_warning("%s: Failed to get tools install path.\n", __FUNCTION__); return FALSE; } ASSERT(threadState->configInfo == NULL); configInfo = g_malloc0(sizeof(*configInfo)); configInfo->localConfPath = g_build_filename(guestAppConfPath, GLOBALCONF_LOCAL_FILENAME, NULL); configInfo->localTempPath = g_build_filename(guestAppConfPath, GLOBALCONF_LOCAL_TEMP_FILENAME, NULL); vm_free(guestAppConfPath); configInfo->pollInterval = GlobalConfigGetPollInterval(cfg); g_debug("%s: %s: %d", __FUNCTION__, CONFNAME_GLOBALCONF_POLL_INTERVAL, configInfo->pollInterval); configInfo->guestStoreResource = GLOBALCONF_GET_RESOURCE_PATH(cfg); g_debug("%s: Configuration Resource path in GuestStore: %s", __FUNCTION__, configInfo->guestStoreResource); threadState->configInfo = configInfo; return TRUE; } /* ************************************************************************** * GlobalConfigInfoFree -- */ /** * * Frees up memory allocated for GlobalConfigInfo structure. * * @param[in] data GlobalConfigInfo structure that needs to be freed. * ************************************************************************** */ static void GlobalConfigInfoFree(GlobalConfigInfo *configInfo) { if (configInfo != NULL) { g_free(configInfo->localConfPath); g_free(configInfo->localTempPath); g_free(configInfo->guestStoreResource); } g_free(configInfo); } /* ************************************************************************** * GlobalConfigThreadStateFree -- */ /** * * Frees up memory allocated for GlobalConfigThread structure. * * @param[in] unused Callback data. Not used. * ************************************************************************** */ static void GlobalConfigThreadStateFree(gpointer unused) { GlobalConfigThreadState *threadState = &globalConfigThreadState; GlobalConfigInfoFree(threadState->configInfo); threadState->configInfo = NULL; } /* ************************************************************************** * GlobalConfigThreadTerminate -- */ /** * * Signals the 'global config' thread to exit. * * @param[in] ctx Application context * @param[in] data Pointer to GlobalConfigThreadState sturcture. * ************************************************************************** */ static void GlobalConfigThreadTerminate(ToolsAppCtx *ctx, gpointer data) { GlobalConfigThreadState *threadState = &globalConfigThreadState; g_mutex_lock(&threadState->mutex); threadState->terminate = TRUE; threadState->guestStoreEnabled = FALSE; g_cond_signal(&threadState->cond); g_mutex_unlock(&threadState->mutex); } /* ************************************************************************** * LoadConfigFile -- */ /** * * Loads the specified config file. * * @param[in] confPath Path to the configuration file. * @param[in|out] config Configuration dictionary that is loaded with the * contents from the specified configuration file. When * loading, the old content is destroyed. Before * invoking this function the first time for a specific * confPath, the config must be initialized to NULL. * @param[in|out] mtime Last known modification time of the config file. * When the function succeeds, will contain the new * modification time read from the file. If NULL (or 0), * the configuration dictionary is always loaded. * * @return TRUE Whether a new configuration dictionary was loaded. * ************************************************************************** */ static gboolean LoadConfigFile(const gchar *confPath, GKeyFile **config, time_t *mtime) { gboolean configUpdated = FALSE; GStatBuf confStat; GError *err = NULL; GKeyFile *cfg; if (config == NULL || confPath == NULL ) { g_debug("%s: Invalid arguments specified.\n", __FUNCTION__); goto exit; } if (g_stat(confPath, &confStat) == -1) { /* * If the file doesn't exist, it's not an error. */ if (errno != ENOENT) { g_warning("%s: Failed to stat conf file: %s, Error: '%s'\n", __FUNCTION__, confPath, strerror(errno)); } else { /* * If we used to have a file, set the config to NULL. */ if (*config != NULL) { g_key_file_free(*config); *config = NULL; configUpdated = TRUE; } } goto exit; } /* Check if we really need to load the data. */ if (mtime != NULL && confStat.st_mtime <= *mtime) { goto exit; } cfg = g_key_file_new(); /* On error, 'err' will be set, null otherwise. */ /* coverity[check_return] */ g_key_file_load_from_file(cfg, confPath, G_KEY_FILE_NONE, &err); if (err != NULL) { g_warning("%s: Failed to load the configuration from '%s'. Error: '%s'", __FUNCTION__, confPath, err->message); g_clear_error(&err); g_key_file_free(cfg); cfg = NULL; goto exit; } if (*config != NULL) { g_key_file_free(*config); } *config = cfg; configUpdated = TRUE; if (mtime != NULL) { *mtime = confStat.st_mtime; } g_debug("%s: Loaded the configuration from %s.\n", __FUNCTION__, confPath); exit: return configUpdated; } /* ************************************************************************** * DownloadConfig -- */ /** * * Downloads the tools.conf from the GuestStore. * * @param[in] guestStoreResource Resource path in the GuestStore. * @param[in|opt] localTempPath File path to be used for temporarily download * of the resource from the GuestStore. If this is * NULL, then a random file path is used. * * @return GuestStoreClientError. ************************************************************************** */ static GuestStoreClientError DownloadConfig(const char *guestStoreResource, const char *localTempPath) { GuestStoreClientError status = GSLIBERR_GENERIC; const gchar *localConfPath = GlobalConfGetConfPath(); gchar *randomLocalTempPath = NULL; if (localConfPath == NULL) { g_warning("%s: Failed to get the configuration file path.\n", __FUNCTION__); return status; } if (localTempPath == NULL) { int fd = File_MakeSafeTemp(NULL, &randomLocalTempPath); if (fd != -1) { close(fd); } else { g_warning("%s: Failed to get the random temporary file.\n", __FUNCTION__); return status; } localTempPath = randomLocalTempPath; } g_debug("%s: Downloading the configuration to %s\n", __FUNCTION__, localTempPath); status = GuestStoreClient_GetContent(guestStoreResource, localTempPath, NULL, NULL); if (status == GSLIBERR_SUCCESS) { GKeyFile *newGlobalCfg = NULL; g_debug("%s: Successfully downloaded the configuration from GuestStore.", __FUNCTION__); LoadConfigFile(localTempPath, &newGlobalCfg, NULL); if (newGlobalCfg != NULL) { GKeyFile *existingGlobalCfg = NULL; LoadConfigFile(localConfPath, &existingGlobalCfg, NULL); if (!VMTools_CompareConfig(existingGlobalCfg, newGlobalCfg)) { /* * Write the config to the filesystem using VMTools_WriteConfig and * the content will be normalized. */ VMTools_WriteConfig(localConfPath, newGlobalCfg, NULL); } if (existingGlobalCfg != NULL) { g_key_file_free(existingGlobalCfg); } g_key_file_free(newGlobalCfg); } } else { g_debug("%s: Failed to download the configuration " "from GuestStore. Error: %d", __FUNCTION__, status); /* * If the global configuration is not available in the GuestStore or * VM is not allowed to access it, then delete the local copy of global * configuration downloaded previously. */ if (status == GSLIBERR_CONTENT_NOT_FOUND || status == GSLIBERR_CONTENT_FORBIDDEN) { File_UnlinkIfExists(localConfPath); } } File_UnlinkIfExists(localTempPath); g_free(randomLocalTempPath); return status; } /* ************************************************************************** * GlobalConfigThreadStart -- */ /** * * Entry function for the thread to download the global configuration from * the GuestStore. * * @param[in] ctx Application context * @param[in] unused Callback data. Not used. * ************************************************************************** */ static void GlobalConfigThreadStart(ToolsAppCtx *ctx, gpointer unused) { GlobalConfigThreadState *threadState = &globalConfigThreadState; gboolean waitBeforeDownload = FALSE; g_mutex_lock(&threadState->mutex); while (!threadState->terminate) { GlobalConfigInfo *configInfo = threadState->configInfo; if (threadState->guestStoreEnabled && configInfo->pollInterval > 0) { gint64 endTime; if (waitBeforeDownload) { waitBeforeDownload = FALSE; endTime = g_get_monotonic_time() + (configInfo->pollInterval * G_TIME_SPAN_SECOND); g_cond_wait_until(&threadState->cond, &threadState->mutex, endTime); continue; } else if (threadState->useRandomInterval) { threadState->useRandomInterval = FALSE; endTime = g_get_monotonic_time() + (GenerateRandomInterval() * G_TIME_SPAN_SECOND); g_cond_wait_until(&threadState->cond, &threadState->mutex, endTime); continue; } g_mutex_unlock(&threadState->mutex); DownloadConfig(configInfo->guestStoreResource, configInfo->localTempPath); g_mutex_lock(&threadState->mutex); waitBeforeDownload = TRUE; } else { if (configInfo->pollInterval == 0) { GlobalConfig_DeleteConfig(); } g_cond_wait(&threadState->cond, &threadState->mutex); waitBeforeDownload = FALSE; } } g_mutex_unlock(&threadState->mutex); } /* ************************************************************************** * GlobalConfig_Start -- */ /** * * Initializes the global config module. If the feature is not enabled in * tools.conf file, the module is not enabled. If this function is called * in the context of the Tools main service, a thread is started in the * background to periodically download the global configuration from the * GuestStore. * * @param[in] ctx Application context. * * @return TRUE if the download config module is successfully started * ************************************************************************** */ gboolean GlobalConfig_Start(ToolsAppCtx *ctx) { gboolean ret = FALSE; GKeyFile *cfg; ASSERT(ctx != NULL); cfg = ctx->config; ASSERT(cfg != NULL); if (!GlobalConfigThreadStateInit(cfg)) { g_warning("%s: Failed to initialize global config module.", __FUNCTION__); goto exit; } if (TOOLS_IS_MAIN_SERVICE(ctx)) { /* * Start the background thread only when this module is started by * 'vmsvc' service. */ ret = ToolsCorePool_StartThread(ctx, "toolsGlobalConfig", GlobalConfigThreadStart, GlobalConfigThreadTerminate, NULL, GlobalConfigThreadStateFree); if (!ret) { g_info("%s: Unable to start the GuestStore download config thread", __FUNCTION__); GlobalConfigThreadStateFree(NULL); goto exit; } if (g_signal_lookup(TOOLS_CORE_SIG_GUESTSTORE_STATE, G_OBJECT_TYPE(ctx->serviceObj)) != 0) { g_signal_connect(ctx->serviceObj, TOOLS_CORE_SIG_GUESTSTORE_STATE, G_CALLBACK(GuestStoreStateChanged), NULL); } if (g_signal_lookup(TOOLS_CORE_SIG_RESET, G_OBJECT_TYPE(ctx->serviceObj)) != 0) { g_signal_connect(ctx->serviceObj, TOOLS_CORE_SIG_RESET, G_CALLBACK(VMToolsChannelReset), NULL); } } else { ret = TRUE; } if (g_signal_lookup(TOOLS_CORE_SIG_CONF_RELOAD, G_OBJECT_TYPE(ctx->serviceObj)) != 0) { g_signal_connect(ctx->serviceObj, TOOLS_CORE_SIG_CONF_RELOAD, G_CALLBACK(GlobalConfigToolsConfReload), NULL); } exit: return ret; } /* ************************************************************************** * GlobalConfig_LoadConfig -- */ /** * * Loads the Global configuration downloaded from the GuestStore. The * modification time of the configuration file is checked and it's loaded only * if it has been updated since the caller specified modification time. * * @param[in|out] config Configuration dictionary that is loaded with the * contents downloaded from the GuestStore. When * loading, the old content is destroyed. The caller * must initialize this to NULL before the first * invocation of this function. * @param[in|out] mtime Last known modification time of the config file. * When the function succeeds, will contain the new * modification time read from the file. If NULL (or 0), * the configuration dictionary is always loaded. * * @return TRUE Whether a new configuration dictionary was loaded. * ************************************************************************** */ gboolean GlobalConfig_LoadConfig(GKeyFile **config, time_t *mtime) { static const gchar *confPath = NULL; if (confPath == NULL) { confPath = GlobalConfGetConfPath(); } if (confPath != NULL) { return LoadConfigFile(confPath, config, mtime); } else { return FALSE; } } /* ************************************************************************** * GlobalConfig_GetEnabled -- */ /** * * Query the given configuration dictionary and returns the status of * globaconf module. * * @param[in] config Configuration dictionary that needs to be queried. * * @return TRUE if the globalconf module is enabled. FALSE otherwise. * ************************************************************************** */ gboolean GlobalConfig_GetEnabled(GKeyFile *config) { return VMTools_ConfigGetBoolean(config, CONFGROUPNAME_GLOBALCONF, CONFNAME_GLOBALCONF_ENABLED, GLOBALCONF_DEFAULT_ENABLED); } /* ************************************************************************** * GlobalConfig_SetEnabled -- */ /** * * Changes the 'enabled' status of globalconf module in the specified * configuration dictionary. * * @param[in] enabled Desired state of the globalconf module. * @param[in|out] config Configuration dictionary that needs to be updated. * ************************************************************************** */ void GlobalConfig_SetEnabled(gboolean enabled, GKeyFile *config) { if (config != NULL) { g_key_file_set_boolean(config, CONFGROUPNAME_GLOBALCONF, CONFNAME_GLOBALCONF_ENABLED, enabled); } } /* ************************************************************************** * GlobalConfig_DeleteConfig -- */ /** * * Delete the global configuration downloaded from the GuestStore. * * @return TRUE if the global configuration is successfully deleted. * FALSE if any error happens. * ************************************************************************** */ gboolean GlobalConfig_DeleteConfig(void) { const gchar *confPath = GlobalConfGetConfPath(); return confPath != NULL && File_UnlinkIfExists(confPath) == 0; } /* ************************************************************************** * GlobalConfig_DownloadConfig -- */ /** * * Download the global configuration from the GuestStore. * * @param[in] config Configuration dictionary. * * @return GuestStoreClientError * ************************************************************************** */ GuestStoreClientError GlobalConfig_DownloadConfig(GKeyFile *config) { GuestStoreClientError status = GSLIBERR_GENERIC; char *guestStoreResource; if (config == NULL) { g_warning("%s: Invalid arguments specified.\n", __FUNCTION__); return status; } guestStoreResource = GLOBALCONF_GET_RESOURCE_PATH(config); status = DownloadConfig(guestStoreResource, NULL); g_free(guestStoreResource); return status; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestApp/000077500000000000000000000000001470176644300226575ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestApp/Makefile.am000066400000000000000000000017431470176644300247200ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libGuestApp.la libGuestApp_la_SOURCES = libGuestApp_la_SOURCES += guestApp.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestApp/guestApp.c000066400000000000000000000504431470176644300246210ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * guestApp.c -- * * Utility functions common to all guest applications */ #include #include #include #ifdef _MSC_VER #include #include #include "productState.h" #include "conf.h" // for tools install path regkey #include "winregistry.h" #include "windowsUtil.h" #endif #include "vmware.h" #include "vm_version.h" #include "vm_tools_version.h" #include "guestApp.h" #include "backdoor.h" #include "backdoor_def.h" #include "conf.h" #include "rpcout.h" #include "debug.h" #include "strutil.h" #include "str.h" #include "msg.h" #include "file.h" #include "posix.h" #include "vmware/guestrpc/tclodefs.h" /* * For Netware/Linux/BSD/Solaris, the install path * is the hardcoded value below. For Windows, it is * determined dynamically in GuestApp_GetInstallPath(), * so the empty string here is just for completeness. */ #if defined _WIN32 # define GUESTAPP_TOOLS_INSTALL_PATH "" #elif defined __APPLE__ # define GUESTAPP_TOOLS_INSTALL_PATH "/Library/Application Support/VMware Tools" #else # define GUESTAPP_TOOLS_INSTALL_PATH "/etc/vmware-tools" #endif #if defined _WIN32 static char *GuestAppGetOrCreateConfPath(void); static DWORD GuestAppCreateConfPathSecInfo(PSECURITY_ATTRIBUTES *confPathSecAttrs, PACL *confPathAcl); static VOID GuestAppDestroyConfPathSecInfo(PSECURITY_ATTRIBUTES confPathSecAttrs, PACL confPathAcl); static DWORD GuestAppCreateConfPathSD(PSECURITY_DESCRIPTOR *confPathSD, PACL *confPathAcl); static VOID GuestAppDestroyConfPathSD(PSECURITY_DESCRIPTOR confPathSd, PACL confPathAcl); static DWORD GuestAppCreateConfPathAcl(PACL *newAcl); static VOID GuestAppDestroyConfPathAcl(PACL confPathAcl); #endif /* *----------------------------------------------------------------------------- * * GuestApp_GetDefaultScript -- * * Returns the default power script for the given configuration option. * * Results: * Script name on success, NULL of the option is not recognized. * * Side effects: * None. * *----------------------------------------------------------------------------- */ const char * GuestApp_GetDefaultScript(const char *confName) // IN { const char *value = NULL; if (strcmp(confName, CONFNAME_SUSPENDSCRIPT) == 0) { value = CONFVAL_SUSPENDSCRIPT_DEFAULT; } else if (strcmp(confName, CONFNAME_RESUMESCRIPT) == 0) { value = CONFVAL_RESUMESCRIPT_DEFAULT; } else if (strcmp(confName, CONFNAME_POWEROFFSCRIPT) == 0) { value = CONFVAL_POWEROFFSCRIPT_DEFAULT; } else if (strcmp(confName, CONFNAME_POWERONSCRIPT) == 0) { value = CONFVAL_POWERONSCRIPT_DEFAULT; } return value; } #if defined _WIN32 /* *------------------------------------------------------------------------------ * * GuestApp_GetInstallPathW -- * * Returns the tools installation path as a UTF-16 encoded string, or NULL on * error. The caller must deallocate the returned string using free. * * Results: * See above. * * Side effects: * None. *------------------------------------------------------------------------------ */ LPWSTR GuestApp_GetInstallPathW(void) { HKEY key = NULL; LONG rc; DWORD cbData = 0; DWORD temp = 0; PWCHAR data = NULL; REGSAM samDesired = KEY_READ; rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, CONF_VMWARE_TOOLS_REGKEY_W, 0, samDesired, &key); if (ERROR_SUCCESS != rc) { Debug("%s: Couldn't open key \"%S\".\n", __FUNCTION__, CONF_VMWARE_TOOLS_REGKEY_W); Debug("%s: RegOpenKeyExW error 0x%x.\n", __FUNCTION__, GetLastError()); goto exit; } rc = RegQueryValueExW(key, CONF_VMWARE_TOOLS_INSTPATH_KEY_W, 0, NULL, NULL, &cbData); if (ERROR_SUCCESS != rc) { Debug("%s: Couldn't get length of value \"%S\".\n", __FUNCTION__, CONF_VMWARE_TOOLS_INSTPATH_KEY_W); Debug("%s: RegQueryValueExW error 0x%x.\n", __FUNCTION__, GetLastError()); goto exit; } /* * The data in the registry may not be null terminated. So allocate enough * space for one extra WCHAR and use that space to write our own NULL. */ data = (LPWSTR) malloc(cbData + sizeof(WCHAR)); if (NULL == data) { Debug("%s: Couldn't allocate %d bytes.\n", __FUNCTION__, cbData); goto exit; } temp = cbData; rc = RegQueryValueExW(key, CONF_VMWARE_TOOLS_INSTPATH_KEY_W, 0, NULL, (LPBYTE) data, &temp); if (ERROR_SUCCESS != rc) { Debug("%s: Couldn't get data for value \"%S\".\n", __FUNCTION__, CONF_VMWARE_TOOLS_INSTPATH_KEY_W); Debug("%s: RegQueryValueExW error 0x%x.\n", __FUNCTION__, GetLastError()); goto exit; } data[cbData / sizeof(WCHAR)] = L'\0'; exit: if (NULL != key) { RegCloseKey(key); } return data; } #endif /* *---------------------------------------------------------------------- * * GuestApp_GetInstallPath -- * * Get the tools installation path. The caller is responsible for * freeing the memory allocated for the path. * * Results: * The path in UTF-8 if successful. * NULL otherwise. * * Side effects: * Allocates memory. * *---------------------------------------------------------------------- */ char * GuestApp_GetInstallPath(void) { char *pathUtf8 = NULL; #if defined _WIN32 size_t pathLen = 0; if (WinReg_GetSZ(HKEY_LOCAL_MACHINE, CONF_VMWARE_TOOLS_REGKEY, CONF_VMWARE_TOOLS_INSTPATH_KEY, &pathUtf8) != ERROR_SUCCESS) { Warning("%s: Unable to retrieve install path: %s\n", __FUNCTION__, Msg_ErrString()); return NULL; } /* Strip off the trailing backslash, if present */ pathLen = strlen(pathUtf8); if (pathLen > 0) { if (pathUtf8[pathLen - 1] == '\\') { pathUtf8[pathLen - 1] = '\0'; } } #else pathUtf8 = Str_Asprintf(NULL, "%s", GUESTAPP_TOOLS_INSTALL_PATH); #endif return pathUtf8; } /* *---------------------------------------------------------------------- * * GuestApp_GetConfPath -- * * Get the path to the Tools configuration file. * * The return conf path is a dynamically allocated UTF-8 encoded * string that should be freed by the caller. * * However, the function will also return NULL if we fail to create * a "VMware/VMware Tools" directory. This can occur if we're not running * as Administrator, which VMwareUser doesn't. But I believe that * VMwareService will always come up before VMwareUser, so by the time * a non-root user process calls this function, the directory exists. * * Results: * The path in UTF-8, or NULL on failure. * * Side effects: * Allocates memory. * *---------------------------------------------------------------------- */ char * GuestApp_GetConfPath(void) { static char *confPath = NULL; if (confPath == NULL) { #if defined _WIN32 confPath = GuestAppGetOrCreateConfPath(); #else /* Just call into GuestApp_GetInstallPath. */ confPath = GuestApp_GetInstallPath(); #endif } /* * Return a copy of the cached confPath. */ return confPath ? Util_SafeStrdup(confPath) : NULL; } #if defined _WIN32 /* *---------------------------------------------------------------------- * * GuestAppGetOrCreateConfPath -- * * Get the path to the Tools configuration file. * * The return conf path is a dynamically allocated UTF-8 encoded * string that should be freed by the caller. * The directory will be created if it doesn't exist. * * However, the function will also return NULL if we fail to create * a "VMware/VMware Tools" directory. This can occur if we're not running * as Administrator, which VMwareUser doesn't. But I believe that * VMwareService will always come up before VMwareUser, so by the time * a non-root user process calls this function, the directory exists. * * Results: * The path in UTF-8, or NULL on failure. * * Side effects: * Allocates memory and creates the directory if it does not exist. * *---------------------------------------------------------------------- */ static char * GuestAppGetOrCreateConfPath(void) { PSECURITY_ATTRIBUTES confPathSecAttrs = NULL; PACL confPathAcl = NULL; char *path; char *tmp; DWORD status = ERROR_SUCCESS; path = W32Util_GetVmwareCommonAppDataFilePath(NULL); if (path == NULL) { goto exit; } tmp = Str_SafeAsprintf(NULL, "%s%c%s", path, DIRSEPC, ProductState_GetName()); free(path); path = tmp; if (File_Exists(path)) { goto exit; } status = GuestAppCreateConfPathSecInfo(&confPathSecAttrs, &confPathAcl); if (ERROR_SUCCESS != status) { Warning("%s: Error: Get security info failed %u\n", __FUNCTION__, status); goto exit; } if (!CreateDirectoryA(path, confPathSecAttrs)) { status = GetLastError(); if (ERROR_ALREADY_EXISTS == status) { Debug("%s: Error: CreateDirectory path exists %u\n", __FUNCTION__, status); status = ERROR_SUCCESS; } else { Warning("%s: Error: CreateDirectory failed %u\n", __FUNCTION__, status); goto exit; } } exit: GuestAppDestroyConfPathSecInfo(confPathSecAttrs, confPathAcl); if (ERROR_SUCCESS != status) { free(path); path = NULL; } return path; } /* *----------------------------------------------------------------------------- * * GuestAppCreateConfPathSecInfo -- * * Creates the user access security attributes. * * Results: * ERROR_SUCCESS on success or appropriate failure code. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ static DWORD GuestAppCreateConfPathSecInfo(PSECURITY_ATTRIBUTES *confPathSecAttrs, // OUT: security attrs PACL *confPathAcl) // OUT: acl { PSECURITY_ATTRIBUTES newSA = NULL; PSECURITY_DESCRIPTOR newSD = NULL; PACL newAcl = NULL; DWORD status = ERROR_SUCCESS; Debug("%s: entered\n", __FUNCTION__); ASSERT(NULL != confPathSecAttrs); ASSERT(NULL != confPathAcl); /* Initialize a security descriptor. */ newSA = malloc(sizeof *newSA); if (NULL == newSA) { status = ERROR_NOT_ENOUGH_MEMORY; Warning("%s: Error: malloc failed %u\n", __FUNCTION__, status); goto exit; } memset(newSA, 0, sizeof *newSA); status = GuestAppCreateConfPathSD(&newSD, &newAcl); if (ERROR_SUCCESS != status) { Warning("%s: Error: SD creation failed %u\n", __FUNCTION__, status); goto exit; } newSA->nLength = sizeof *newSA; newSA->bInheritHandle = FALSE; newSA->lpSecurityDescriptor = newSD; exit: if (ERROR_SUCCESS != status) { GuestAppDestroyConfPathSecInfo(newSA, newAcl); newSA = NULL; newAcl = NULL; } *confPathSecAttrs = newSA; *confPathAcl = newAcl; return status; } /* *----------------------------------------------------------------------------- * * GuestAppDestroyConfPathSecInfo -- * * Destroys the security attributes and ACL. * * Results: * None. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ static VOID GuestAppDestroyConfPathSecInfo(PSECURITY_ATTRIBUTES confPathSecAttrs, // IN/OUT: security attrs PACL confPathAcl) // IN/OUT: acl { if (NULL != confPathSecAttrs) { GuestAppDestroyConfPathSD(confPathSecAttrs->lpSecurityDescriptor, confPathAcl); free(confPathSecAttrs); } } /* *----------------------------------------------------------------------------- * * GuestAppCreateConfPathSD -- * * Creates a security descriptor for the configuration path. * * Results: * ERROR_SUCCESS on success or appropriate failure code. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ static DWORD GuestAppCreateConfPathSD(PSECURITY_DESCRIPTOR *confPathSD, // OUT: security PACL *confPathAcl) // OUT: acl { DWORD status = ERROR_SUCCESS; PACL newConfPathAcl = NULL; PSECURITY_DESCRIPTOR newConfPathSD = NULL; ASSERT(NULL != confPathSD); ASSERT(NULL != confPathAcl); status = GuestAppCreateConfPathAcl(&newConfPathAcl); if (ERROR_SUCCESS != status) { Warning("%s: Error: Get Acl failed %u\n", __FUNCTION__, status); goto exit; } /* Initialize a security descriptor. */ newConfPathSD = malloc(SECURITY_DESCRIPTOR_MIN_LENGTH); if (NULL == newConfPathSD) { status = ERROR_NOT_ENOUGH_MEMORY; Warning("%s: Error: malloc failed %u\n", __FUNCTION__, status); goto exit; } if (!InitializeSecurityDescriptor(newConfPathSD, SECURITY_DESCRIPTOR_REVISION)) { status = GetLastError(); Warning("%s: Error: InitializeSecurityDescriptor failed %u\n", __FUNCTION__, status); goto exit; } /* Add the ACL to the security descriptor. */ if (!SetSecurityDescriptorDacl(newConfPathSD, TRUE, newConfPathAcl, FALSE)) { status = GetLastError(); Warning("%s: Error: SetSecurityDescriptorDacl failed %u\n", __FUNCTION__, status); goto exit; } exit: if (ERROR_SUCCESS != status) { GuestAppDestroyConfPathSD(newConfPathSD, newConfPathAcl); newConfPathSD = NULL; newConfPathAcl = NULL; } *confPathSD = newConfPathSD; *confPathAcl = newConfPathAcl; return status; } /* *----------------------------------------------------------------------------- * * GuestAppDestroyConfPathSD -- * * Destroys the security descriptor and access control list. * * Results: * None. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ static VOID GuestAppDestroyConfPathSD(PSECURITY_DESCRIPTOR confPathSd, // IN/OUT: security PACL confPathAcl) // IN/OUT: acl { free(confPathSd); GuestAppDestroyConfPathAcl(confPathAcl); } /* *----------------------------------------------------------------------------- * * GuestAppCreateConfPathAcl -- * * Create a new user access ACL. * * Results: * ERROR_SUCCESS on success or appropriate failure code. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ static DWORD GuestAppCreateConfPathAcl(PACL *confPathAcl) // OUT: ACL { PACL newAcl = NULL; PSID systemSID = NULL; PSID adminsGrpSID = NULL; PSID everyoneSID = NULL; SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; DWORD newAclSize; DWORD status = ERROR_SUCCESS; ASSERT(NULL != confPathAcl); /* Create a well-known SID for the Everyone group. */ if (!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyoneSID)) { status = GetLastError(); Warning("%s: Error: AllocateAndInitializeSid Error %u\n", __FUNCTION__, status); goto exit; } /* Create a well-known SID for the Administrators group. */ if (!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &adminsGrpSID)) { status = GetLastError(); Warning("%s: Error: AllocateAndInitializeSid Error %u\n", __FUNCTION__, status); goto exit; } /* Create a well-known SID for the System user. */ if (!AllocateAndInitializeSid(&SIDAuthNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &systemSID)) { status = GetLastError(); Warning("%s: Error: AllocateAndInitializeSid Error %u\n", __FUNCTION__, status); goto exit; } /* * Get the size of the new ACL. See the following link for this calculation. * http://msdn.microsoft.com/en-us/library/windows/desktop/aa378853(v=vs.85).aspx? */ newAclSize = sizeof *newAcl; newAclSize += GetLengthSid(systemSID) + sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD); newAclSize += GetLengthSid(adminsGrpSID) + sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD); newAclSize += GetLengthSid(everyoneSID) + sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD); /* Align newAclSize to a DWORD. */ newAclSize = (newAclSize + (sizeof (DWORD) - 1)) & 0xfffffffc; /* Allocate the new ACL. */ newAcl = malloc(newAclSize); if (NULL == newAcl) { status = ERROR_NOT_ENOUGH_MEMORY; Warning("%s: Error: malloc Acl failed %u\n", __FUNCTION__, status); goto exit; } /* Initialize the new DACL. */ if (!InitializeAcl(newAcl, newAclSize, ACL_REVISION)) { status = GetLastError(); Warning("%s: Error: Init Acl failed %u\n", __FUNCTION__, status); goto exit; } /* Add the ACE to the DACL for the sid. Note: no inheritence. */ if (!AddAccessAllowedAceEx(newAcl, ACL_REVISION, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, GENERIC_READ | GENERIC_EXECUTE, everyoneSID)) { status = GetLastError(); Warning("%s: Error: Add Everyone Ace to Acl failed %u\n", __FUNCTION__, status); goto exit; } /* Add the ACE to the ACL for the sid. Note: no inheritence. */ if (!AddAccessAllowedAceEx(newAcl, ACL_REVISION, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, GENERIC_ALL, adminsGrpSID)) { status = GetLastError(); Warning("%s: Error: Add admins Grp Ace to Acl failed %u\n", __FUNCTION__, status); goto exit; } /* Add the ACE to the ACL for the sid. Note: no inheritence. */ if (!AddAccessAllowedAceEx(newAcl, ACL_REVISION, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, GENERIC_ALL, systemSID)) { status = GetLastError(); Warning("%s: Error: Add system Ace to Acl failed %u\n", __FUNCTION__, status); goto exit; } exit: /* Free the allocated SIDs. */ if (NULL != everyoneSID) { FreeSid(everyoneSID);; } if (NULL != adminsGrpSID) { FreeSid(adminsGrpSID); } if (NULL != systemSID) { FreeSid(systemSID); } if (ERROR_SUCCESS != status) { GuestAppDestroyConfPathAcl(newAcl); newAcl = NULL; } *confPathAcl = newAcl; return status; } /* *----------------------------------------------------------------------------- * * GuestAppDestroyConfPathAcl -- * * Destroys the ACL. * * Results: * None. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ static VOID GuestAppDestroyConfPathAcl(PACL confPathAcl) // IN/OUT: security { free(confPathAcl); } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestRpc/000077500000000000000000000000001470176644300226635ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestRpc/Makefile.am000066400000000000000000000034771470176644300247320ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2008-2018 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libGuestRpc.la libGuestRpc_la_SOURCES = libGuestRpc_la_SOURCES += nicinfo_xdr.c # XXX: Autoreconf complains about this and recommends using AM_CFLAGS instead. # Problem is, $(CFLAGS) is appended to the compiler command line after AM_CFLAGS # and after libGuestRpc_la_CFLAGS, so "-Wall -Werror" will override this flag. CFLAGS += -Wno-unused CLEANFILES = CLEANFILES += nicinfo.h CLEANFILES += nicinfo_xdr.c EXTRA_DIST = EXTRA_DIST += nicinfo.x # Rules to invoke rpcgen. rpcgen will generate funny paths in the generated # files if not invoked in the same directory as the source file, so we need # to copy the sources to the build dir before compiling them. nicinfo.h: nicinfo.x @RPCGEN_WRAPPER@ lib/guestRpc/nicinfo.x $@ nicinfo_xdr.c: nicinfo.x nicinfo.h @RPCGEN_WRAPPER@ lib/guestRpc/nicinfo.x $@ libGuestRpc_la_CPPFLAGS = libGuestRpc_la_CPPFLAGS += @XDR_CPPFLAGS@ libGuestRpc_la_LIBADD = libGuestRpc_la_LIBADD += @XDR_LIBS@ open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestRpc/nicinfo.x000066400000000000000000000171741470176644300245130ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * nicinfo.x -- * * Definition of the data structures used in the GuestRpc commands to * provide information about the guest NICs. */ /* * Enumerates the different versions of the messages. Starting at 2, since * version one is legacy code we can't change. */ enum NicInfoVersion { NIC_INFO_V1 = 1, /* XXX Not represented here. */ NIC_INFO_V2 = 2, NIC_INFO_V3 = 3 }; /* * These are arbitrary limits to avoid possible DoS attacks. * The IP limit is large enough to hold an IP address (either v4 or v6). */ const NICINFO_MAX_IP_LEN = 64; const NICINFO_MAX_IPS = 2048; const NICINFO_MAX_NICS = 16; /* MAC Addresses are "AA:BB:CC:DD:EE:FF" = 18 bytes. */ const NICINFO_MAC_LEN = 18; /* * Corresponds to public/guestInfo.h::GuestInfoIPAddressFamilyType. */ enum NicInfoAddrType { NICINFO_ADDR_IPV4 = 0, NICINFO_ADDR_IPV6 = 1 }; struct VmIpAddress { NicInfoAddrType addressFamily; Bool dhcpEnabled; char ipAddress[NICINFO_MAX_IP_LEN]; /* * For IPv4, may be either a hexadecimal mask ("0xffffff00") or CIDR-style * prefix length ("24"). For IPv6, will only be a prefix length. */ char subnetMask[NICINFO_MAX_IP_LEN]; }; struct GuestNic { char macAddress[NICINFO_MAC_LEN]; struct VmIpAddress ips; }; /* * This structure is not entirely necessary, but it makes the generated * code nicer to code to. */ struct GuestNicList { struct GuestNic nics; }; /* *----------------------------------------------------------------------------- * * NIC Info version 3. * * V3 adds routing, DNS, and WINS information to the NIC list. * *----------------------------------------------------------------------------- */ /* * IP v4 and v6 addressing. * * These types were redefined primarily to allow much more efficient wire * encoding. */ /* * See RFC 4001, InetAddress. */ const INET_ADDRESS_MAX_LEN = 255; typedef opaque InetAddress; /* * See RFC 4001, InetAddressType. */ enum InetAddressType { IAT_UNKNOWN = 0, IAT_IPV4 = 1, IAT_IPV6 = 2, IAT_IPV4Z = 3, IAT_IPV6Z = 4, IAT_DNS = 16 }; /* * See RFC 4001, InetAddressPrefixLength. */ typedef unsigned int InetAddressPrefixLength; /* * See RFC 4293, IpAddressOriginTC. */ enum IpAddressOrigin { IAO_OTHER = 1, IAO_MANUAL = 2, IAO_DHCP = 4, IAO_LINKLAYER = 5, IAO_RANDOM = 6 }; /* * See RFC 4293, IpAddressStatusTC. * * "The status of an address. Most of the states correspond to states * from the IPv6 Stateless Address Autoconfiguration protocol. * ... * "In the absence of other information, an IPv4 address is always * preferred(1)." */ enum IpAddressStatus { IAS_PREFERRED = 1, IAS_DEPRECATED = 2, IAS_INVALID = 3, IAS_INACCESSIBLE = 4, IAS_UNKNOWN = 5, IAS_TENTATIVE = 6, IAS_DUPLICATE = 7, IAS_OPTIMISTIC = 8 }; /* * Convenient type for lists of addresses. */ struct TypedIpAddress { InetAddressType ipAddressAddrType; InetAddress ipAddressAddr; }; /* * See RFC 4293, IpAddressEntry. * * "An address mapping for a particular interface." * * We deviate from the RFC in a few places: * - The prefix length is listed explicitly here rather than reference * a separate prefix table. * - Interface indices aren't included as this structure is dependent * upon/encapsulated by a GuestNicV3 structure. */ struct IpAddressEntry { TypedIpAddress ipAddressAddr; InetAddressPrefixLength ipAddressPrefixLength; IpAddressOrigin *ipAddressOrigin; IpAddressStatus *ipAddressStatus; }; /* * Runtime DNS resolver state. */ /* * Quoth RFC 2181 §11 (Name Syntax): * "The length of any one label is limited to between 1 and 63 octets. A * full domain name is limited to 255 octets (including the separators)." */ const DNSINFO_MAX_ADDRLEN = 255; typedef string DnsHostname; /* * Arbitrary limits. */ const DNSINFO_MAX_SUFFIXES = 10; const DNSINFO_MAX_SERVERS = 16; struct DnsConfigInfo { DnsHostname *hostName; DnsHostname *domainName; TypedIpAddress serverList; DnsHostname searchSuffixes; }; /* * Runtime WINS resolver state. Addresses are assumed to be IPv4 only. */ struct WinsConfigInfo { TypedIpAddress primary; TypedIpAddress secondary; }; /* * Runtime routing tables. */ /* * Arbitrary limit. */ const NICINFO_MAX_ROUTES = 100; /* * See RFC 4292 for details. */ enum InetCidrRouteType { ICRT_OTHER = 1, ICRT_REJECT = 2, ICRT_LOCAL = 3, ICRT_REMOTE = 4 }; struct InetCidrRouteEntry { TypedIpAddress inetCidrRouteDest; InetAddressPrefixLength inetCidrRoutePfxLen; /* * Next hop isn't mandatory. */ TypedIpAddress *inetCidrRouteNextHop; /* * inetCidrRouteProto is omitted as we're concerned only with static/ * netmgmt routes. */ /* This is an array index into GuestNicListV3::nics. */ uint32 inetCidrRouteIfIndex; /* XXX Do we really need this? */ InetCidrRouteType inetCidrRouteType; /* -1 == unused. */ uint32 inetCidrRouteMetric; }; /* * Fun with DHCP */ const DHCP_MAX_CONFIG_SIZE = 16384; struct DhcpConfigInfo { bool enabled; string dhcpSettings; }; /* * Top-level containers. */ /* * Describes a single NIC. */ struct GuestNicV3 { string macAddress; IpAddressEntry ips; DnsConfigInfo *dnsConfigInfo; WinsConfigInfo *winsConfigInfo; DhcpConfigInfo *dhcpConfigInfov4; DhcpConfigInfo *dhcpConfigInfov6; }; /* * Attempts to model general network state. */ struct NicInfoV3 { GuestNicV3 nics; InetCidrRouteEntry routes; DnsConfigInfo *dnsConfigInfo; WinsConfigInfo *winsConfigInfo; DhcpConfigInfo *dhcpConfigInfov4; DhcpConfigInfo *dhcpConfigInfov6; }; /* * This defines the protocol for a "nic info" message. The union allows * us to create new versions of the protocol later by creating new values * in the NicInfoVersion enumeration, without having to change much of * the code calling the (de)serialization functions. * * Since the union doesn't have a default case, de-serialization will fail * if an unknown version is provided on the wire. */ union GuestNicProto switch (NicInfoVersion ver) { case NIC_INFO_V2: struct GuestNicList *nicsV2; case NIC_INFO_V3: struct NicInfoV3 *nicInfoV3; }; open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestStoreClientHelper/000077500000000000000000000000001470176644300255325ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestStoreClientHelper/Makefile.am000066400000000000000000000021601470176644300275650ustar00rootroot00000000000000################################################################################ ### Copyright (c) 2020 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libGuestStoreClientHelper.la libGuestStoreClientHelper_la_SOURCES = libGuestStoreClientHelper_la_SOURCES += guestStoreClient.c libGuestStoreClientHelper_la_CPPFLAGS = libGuestStoreClientHelper_la_CPPFLAGS += @GLIB2_CPPFLAGS@open-vm-tools-stable-12.5.0/open-vm-tools/lib/guestStoreClientHelper/guestStoreClient.c000066400000000000000000000245471470176644300312150ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2020-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * guestStoreClient.c -- * * Wrapper functions to load/unload and get content from GuestStore. */ #define G_LOG_DOMAIN "guestStoreClient" #include #include #include #include #include #include #if defined(_WIN32) #include #else #include #include #endif #include "vm_assert.h" #include "vm_basic_defs.h" #include "guestStoreClient.h" #if defined(_WIN32) #define GUESTSTORE_CLIENTLIB_DLL WSTR("guestStoreClient.dll") #else #define GUESTSTORE_CLIENTLIB_DLL "libguestStoreClient.so.0" #endif /* * Track whether the library has been initialized or not. */ static gboolean gsClientInit = FALSE; /* * Module handle of GuestStore client library. */ #if defined(_WIN32) static HMODULE gsClientLibModule = NULL; #else static void *gsClientLibModule = NULL; #endif /* * Function pointer types for GuestStore client library exports. */ typedef GuestStoreLibError (*GuestStoreLibInit)(void); typedef GuestStoreLibError (*GuestStoreLibDeInit)(void); typedef GuestStoreLibError (*GuestStoreLibGetContent)(const char* contentPath, const char* outputPath, GuestStore_Logger logger, GuestStore_Panic panic, GuestStore_GetContentCallback getContentCb, void* clientData); /* * Function pointer definitions for GuestStore client library exports. */ static GuestStoreLibInit GuestStoreLib_Init; static GuestStoreLibDeInit GuestStoreLib_DeInit; static GuestStoreLibGetContent GuestStoreLib_GetContent; /* * Macro to get the export function address from GuestStore client library. */ #if defined(_WIN32) #define GET_GUESTSTORELIB_FUNC_ADDR(funcname) \ do { \ (FARPROC) XXCONC(GuestStoreLib_,funcname) = GetProcAddress(gsClientLibModule, \ "GuestStore_" #funcname); \ if (XXCONC(GuestStoreLib_,funcname) == NULL) { \ error = GetLastError(); \ g_critical("GetProcAddress failed for \'%s\': error=%u.\n", \ "GuestStore_" #funcname, error); \ return FALSE; \ } \ } while (0) #else #define GET_GUESTSTORELIB_FUNC_ADDR(funcname) \ do { \ dlerror(); \ *(void **)(&XXCONC(GuestStoreLib_,funcname)) = dlsym(gsClientLibModule, \ "GuestStore_" #funcname); \ if ((dlErrStr = dlerror()) != NULL) { \ g_critical("dlsym failed for \'%s\': %s\n", \ "GuestStore_" #funcname, dlErrStr); \ return FALSE; \ } \ } while (0) #endif /* *----------------------------------------------------------------------------- * * GuestStoreGetLibExportFunctions -- * * Get the export function addresses from GuestStore client library. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool GuestStoreGetLibExportFunctions(void) { #if defined(_WIN32) DWORD error; g_debug("Entering %s.\n", __FUNCTION__); gsClientLibModule = LoadLibraryW(GUESTSTORE_CLIENTLIB_DLL); if (gsClientLibModule == NULL) { error = GetLastError(); g_critical("%s: LoadLibrary failed: error=%u.\n", __FUNCTION__, error); return FALSE; } #else char const *dlErrStr; g_debug("Entering %s.\n", __FUNCTION__); gsClientLibModule = dlopen(GUESTSTORE_CLIENTLIB_DLL, RTLD_NOW); if (gsClientLibModule == NULL) { dlErrStr = dlerror(); g_critical("%s: dlopen failed: %s\n", __FUNCTION__, dlErrStr); return FALSE; } #endif GET_GUESTSTORELIB_FUNC_ADDR(Init); // For GuestStore_Init GET_GUESTSTORELIB_FUNC_ADDR(GetContent); // For GuestStore_GetContent GET_GUESTSTORELIB_FUNC_ADDR(DeInit); // For GuestStore_DeInit return TRUE; } /* *----------------------------------------------------------------------------- * * GuestStoreClientLogger -- * * Log messages from GuestStore client library. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void GuestStoreClientLogger(GuestStoreLibLogLevel level, // IN const char *message, // IN void *clientData) // IN { switch (level) { case GSLIBLOGLEVEL_ERROR: g_critical("%s: Error: %s\n", __FUNCTION__, message); break; case GSLIBLOGLEVEL_WARNING: g_warning("%s: Warning: %s\n", __FUNCTION__, message); break; case GSLIBLOGLEVEL_INFO: g_info("%s: Info: %s\n", __FUNCTION__, message); break; case GSLIBLOGLEVEL_DEBUG: g_debug("%s: Debug: %s\n", __FUNCTION__, message); break; default: ASSERT(0); } } /* *----------------------------------------------------------------------------- * * GuestStoreClientPanic -- * * Panic handler for GuestStore client library. * * Results: * None * * Side effects: * Process crashes? * *----------------------------------------------------------------------------- */ static void GuestStoreClientPanic(const char *message, // IN void *clientData) // IN { g_critical("%s: %s\n", __FUNCTION__, message); } /* *----------------------------------------------------------------------------- * * GuestStoreClient_Init -- * * Initialize the guest store client library access * * Results: * TRUE on success., FALSE otherwise * * Error code from GuestStore client library or * general process error exit code. * * Side effects: * None * *----------------------------------------------------------------------------- */ gboolean GuestStoreClient_Init(void) { GuestStoreLibError libErr; g_debug("Entering %s.\n", __FUNCTION__); if (!GuestStoreGetLibExportFunctions()) { goto exit; } libErr = GuestStoreLib_Init(); if (libErr != GSLIBERR_SUCCESS) { g_critical("%s: GuestStoreLib_Init failed: error=%d.\n", __FUNCTION__, libErr); goto exit; } gsClientInit = TRUE; exit: g_debug("%s: Exit -> %d.\n", __FUNCTION__, gsClientInit); return gsClientInit; } /* *----------------------------------------------------------------------------- * * GuestStoreClient_DeInit -- * * Deinitialize the guest store client library access * * Results: * TRUE on success, FALSE otherwise * * Error code from GuestStore client library or * general process error exit code. * * Side effects: * None * *----------------------------------------------------------------------------- */ gboolean GuestStoreClient_DeInit(void) { GuestStoreLibError libErr; g_debug("Entering %s.\n", __FUNCTION__); if (!gsClientInit) { return gsClientInit; } libErr = GuestStoreLib_DeInit(); if (libErr != GSLIBERR_SUCCESS) { g_critical("%s: GuestStore_DeInit failed: error=%d.\n", __FUNCTION__, libErr); } if (gsClientLibModule != NULL) { #if defined(_WIN32) if (!FreeLibrary(gsClientLibModule)) { g_critical("%s: FreeLibrary failed: error=%d.\n", __FUNCTION__, GetLastError()); } #else if (dlclose(gsClientLibModule) != 0) { g_critical("%s: dlclose failed with error: %s\n", __FUNCTION__, dlerror()); } #endif gsClientLibModule = NULL; } g_debug("Exiting %s.\n", __FUNCTION__); gsClientInit = FALSE; return TRUE; } /* *----------------------------------------------------------------------------- * * GuestStoreClient_GetContent -- * * Handle and parse gueststore command. * * Results: * Error code from GuestStore client library or * general process error exit code. * * Side effects: * None * *----------------------------------------------------------------------------- */ GuestStoreClientError GuestStoreClient_GetContent(const char *contentPath, // IN: content file path const char *outputPath, // IN: output file path GuestStoreClient_GetContentCb getContentCb, // IN: OPTIONAL callback void *clientCbData) // IN: OPTIONAL callback data { g_debug("Entering %s.\n", __FUNCTION__); if (!gsClientInit) { return GSLIBERR_NOT_INITIALIZED; } return GuestStoreLib_GetContent(contentPath, outputPath, GuestStoreClientLogger, GuestStoreClientPanic, getContentCb, clientCbData); } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hashMap/000077500000000000000000000000001470176644300224505ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/hashMap/Makefile.am000066400000000000000000000017351470176644300245120ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2013-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libHashMap.la libHashMap_la_SOURCES = libHashMap_la_SOURCES += hashMap.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/hashMap/hashMap.c000066400000000000000000000666061470176644300242130ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2018,2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #include "vm_basic_types.h" #include "vm_assert.h" #include #include #include "hashMap.h" #include "clamped.h" #include "util.h" #ifdef VMX86_SERVER #include "aioMgr.h" #include "iovector.h" #endif /* * hashMap.c -- * * This is a map data structure that can store a sparsely indexed data set. * It is not intended to be thread safe nor should it be used in a way that * this may cause problems. * * Entries are stored based on a simple hash of their key. Memory * allocations are kept to a minimum to ensure that this is appropriate for * use in a kernel mode driver. Linear probing is used to resolve hash * collisions. * * This implementation only supports static length keys. It might be * possible to store the keys outside the table and thus support keys of * variable length but this isn't currently planned. This would allow for * string keys for example. * * Callers should not store pointers to objects stored in the map as they may * become invalid as a result of a resize. If you need to share objects * stored as values in the map, then store pointers to the objects instead. * * All objects are copied into the map and must be freed as appropriate by * the caller. * * This particular HashMap has some important differences from the hash table * implementation in bora/lib/misc * - HashMap supports key removal * - HashMap only supports fixed size keys and values while hashTable * supports string and insensitive string keys and only supports pointer * data. This means its possible to store entire data structures in * HashMap. * - HashMap uses linear probing to resolve collisions while hashTable uses * chaining. HashMap will dynamically resize itself as necessary. * - Pointers to HashMap values will be invalidated if the internal structure * is resized. If this is a problem, you should store the pointer in the * HashMap rather than the object itself. * - HashMap will ensure that a maximum load factor is not exceeded. * * hashMap is now restrictd to userworld applications on ESX builds ONLY. * See PR 817760 which has an attached patchfile to remove this limitation * if in future that is felt to be desireable. */ #define HASHMAP_DEFAULT_ALPHA 2 struct HashMap { uint8 *entries; uint32 numEntries; uint32 count; uint32 alpha; size_t keySize; size_t dataSize; size_t entrySize; size_t keyOffset; size_t dataOffset; }; #ifdef VMX86_SERVER #pragma pack(push, 1) typedef struct HashMapOnDisk { uint32 numEntries; uint32 count; uint32 alpha; uint64 keySize; uint64 dataSize; uint64 entrySize; uint64 keyOffset; uint64 dataOffset; } HashMapOnDisk; #pragma pack(pop) #endif typedef enum { HashMapState_EMPTY = 0, HashMapState_FILLED, HashMapState_DELETED, } HashMapEntryState; typedef struct { uint32 state; uint32 hash; } HashMapEntryHeader; #define NO_FREE_INDEX ((uint32) -1) static Bool InitMap(struct HashMap *map, uint32 numEntries, uint32 alpha, size_t keySize, size_t dataSize); static void CalculateEntrySize(struct HashMap *map); static void GetEntry(struct HashMap *map, uint32 index, HashMapEntryHeader **header, void **key, void **data); static uint32 ComputeHash(struct HashMap *map, const void *key); static Bool LookupKey(struct HashMap* map, const void *key, Bool constTimeLookup, HashMapEntryHeader **header, void **data, uint32 *freeIndex); static Bool CompareKeys(struct HashMap *map, const void *key, const void *compare); static Bool ConstTimeCompareKeys(struct HashMap *map, const void *key, const void *compare); static Bool NeedsResize(struct HashMap *map); static void Resize(struct HashMap *map); INLINE void EnsureSanity(HashMap *map); /* * ---------------------------------------------------------------------------- * * CheckSanity -- * * Same code as EnsureSanity except return Bool instead of ASSERTing * * Results: * TRUE is sane. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ #ifdef VMX86_DEBUG static INLINE Bool CheckSanity(HashMap *map) { uint32 i, cnt = 0; ASSERT(map); for (i = 0; i < map->numEntries; i++) { HashMapEntryHeader *header = NULL; void *key, *data; GetEntry(map, i, &header, &key, &data); ASSERT(header); ASSERT(header->state == HashMapState_FILLED || header->state == HashMapState_EMPTY || header->state == HashMapState_DELETED); if (header->state == HashMapState_FILLED) { cnt++; if (header->hash != ComputeHash(map, key)) { return FALSE; } } } if (cnt != map->count) { return FALSE; } if (!map->numEntries) { return FALSE; } return TRUE; } #endif /* * ---------------------------------------------------------------------------- * * HashMap_AllocMap -- * * Allocate a map and the space for the entries. * * Results: * Returns a pointer to a HashMap or NULL on failure. * * Side Effects: * Allocates memory. * * ---------------------------------------------------------------------------- */ struct HashMap* HashMap_AllocMap(uint32 numEntries, // IN size_t keySize, // IN size_t dataSize) // IN { return HashMap_AllocMapAlpha(numEntries, HASHMAP_DEFAULT_ALPHA, keySize, dataSize); } /* * ---------------------------------------------------------------------------- * * HashMap_AllocMapAlpha -- * * Allocate a map and the space for the entries. The value of alpha is * treated as a denominator for the maximum allowable load factor. I.e. an * alpha value of 2 would correspond to a maximum load factor of 0.5. The * map will be enlarged when elements are added in order to maintain this * load factor. * * Results: * Returns a pointer to a HashMap or NULL on failure. * * Side Effects: * Allocates memory. * * ---------------------------------------------------------------------------- */ struct HashMap* HashMap_AllocMapAlpha(uint32 numEntries, // IN uint32 alpha, // IN size_t keySize, // IN size_t dataSize) // IN { struct HashMap *map; map = calloc(1, sizeof *map); ASSERT(alpha); if (map) { if (!InitMap(map, numEntries, alpha, keySize, dataSize)) { HashMap_DestroyMap(map); return NULL; } } return map; } /* * ---------------------------------------------------------------------------- * * HashMap_DestroyMap -- * * Destroy a HashMap, clear out all the entries and free the memory. * * Results: * None. * * Side Effects: * Frees memory. * * ---------------------------------------------------------------------------- */ void HashMap_DestroyMap(struct HashMap *map) // IN { if (map) { free(map->entries); } free(map); } /* * ---------------------------------------------------------------------------- * * InitMap -- * * Initializes a map's internal structure. The value of alpha is treated * as a denominator for the maximum allowable load factor. I.e. an alpha * value of 2 would correspond to a maximum load factor of 0.5. The map * will be enlarged when elements are added in order to maintain this load * factor. * * Results: * Returns TRUE on success or FALSE if the memory allocation failed. * * Side Effects: * Allocates memory. * * ---------------------------------------------------------------------------- */ static Bool InitMap(struct HashMap *map, // IN uint32 numEntries, // IN uint32 alpha, // IN size_t keySize, // IN size_t dataSize) // IN { ASSERT(map); ASSERT(alpha); ASSERT(numEntries); /* * Ensure that the entries map is at least large enough to hold all of the * entries that were requested taking into account the alpha factor. */ numEntries *= alpha; map->numEntries = numEntries; map->alpha = alpha; map->keySize = keySize; map->dataSize = dataSize; CalculateEntrySize(map); map->entries = calloc(numEntries, map->entrySize); if (map->entries) { EnsureSanity(map); } return map->entries != NULL; } /* * ---------------------------------------------------------------------------- * * HashMap_Put -- * * Put the value at data against the key. This will replace any existing * data that is in the table without warning. * * Results: * TRUE if the put operation is successful * FALSE otherwise * * Side Effects: * The value in data is copied to the table and can be referenced in the * future by the value in key. * * ---------------------------------------------------------------------------- */ Bool HashMap_Put(struct HashMap *map, // IN const void *key, // IN const void *data) // IN { uint32 freeIndex; HashMapEntryHeader *header; void *tableData; if (!LookupKey(map, key, FALSE, &header, &tableData, &freeIndex)) { uint32 hash = ComputeHash(map, key); void *tableKey; if (NeedsResize(map)) { Resize(map); if (LookupKey(map, key, FALSE, &header, &tableData, &freeIndex)) { /* * Somehow our key appeared after resizing the table. */ ASSERT(FALSE); } if (freeIndex == NO_FREE_INDEX) { /* * The resize must have failed. */ return FALSE; } } map->count++; GetEntry(map, freeIndex, &header, &tableKey, &tableData); ASSERT(header); header->state = HashMapState_FILLED; header->hash = hash; memcpy(tableKey, key, map->keySize); } ASSERT(data || map->dataSize == 0); memcpy(tableData, data, map->dataSize); EnsureSanity(map); return TRUE; } /* * ---------------------------------------------------------------------------- * * HashMap_Get -- * * Get the value corresponding to the given key. * * Results: * Returns a pointer to the data that was previously stored by HashMap_Put or * NULL if the key wasn't found. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ void * HashMap_Get(struct HashMap *map, // IN const void *key) // IN { void *data; uint32 freeIndex; HashMapEntryHeader *header; if (LookupKey(map, key, FALSE, &header, &data, &freeIndex)) { return data; } return NULL; } /* * ---------------------------------------------------------------------------- * * HashMap_ConstTimeGet -- * * Timing attack safe version of HashMap_Get. This will call LookupKey with * the constTime flag set to 1 which will do the memory comparison with * Util_ConstTimeMemDiff instead of memcmp. Note that there is a bit of a * time penalty associated with this so only use this if you are looking up * sensitive information. * * Results: * Returns a pointer to the data that was previously stored by HashMap_Put or * NULL if the key wasn't found. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ void * HashMap_ConstTimeGet(struct HashMap *map, // IN const void *key) // IN { void *data; uint32 freeIndex; HashMapEntryHeader *header; if (LookupKey(map, key, TRUE, &header, &data, &freeIndex)) { return data; } return NULL; } /* * ---------------------------------------------------------------------------- * * HashMap_Clear -- * * Remove all entries from the HashMap. * * Results: * None. * * Side Effects: * All entries in the map are removed. * * ---------------------------------------------------------------------------- */ void HashMap_Clear(struct HashMap *map) // IN { int i = 0; HashMapEntryHeader *header; void *key, *data; ASSERT(map); for (i = 0; i < map->numEntries; i++) { GetEntry(map, i, &header, &key, &data); ASSERT(header); header->state = HashMapState_EMPTY; } map->count = 0; EnsureSanity(map); } /* * ---------------------------------------------------------------------------- * * HashMap_Remove -- * * Remove an entry from the map. * * Results: * Returns TRUE if the entry was in the map, FALSE if the entry was not in * the map. * * Side Effects: * The entry is removed from the map. * * ---------------------------------------------------------------------------- */ Bool HashMap_Remove(struct HashMap *map, // IN const void *key) // IN { uint32 freeIndex; HashMapEntryHeader *header; void *tableData; if (!LookupKey(map, key, FALSE, &header, &tableData, &freeIndex)) { return FALSE; } /* * XXX: This could be made slightly smarter. We could check the next entry * to see if it's EMPTY and then mark this one as empty as well. */ map->count--; header->state = HashMapState_DELETED; EnsureSanity(map); return TRUE; } /* * ---------------------------------------------------------------------------- * * HashMap_Count -- * * Returns the current count of entries in the map. * * Results: * The current count of entries in the map. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ uint32 HashMap_Count(struct HashMap *map) // IN { return map->count; } /* * ---------------------------------------------------------------------------- * * CalculateEntrySize -- * * Calculate the size of the entry and the offsets to the key and data. * * Results: * None. * * Side Effects: * The map structure is adjusted to contain the correct sizes. * * ---------------------------------------------------------------------------- */ void CalculateEntrySize(struct HashMap *map) // IN { size_t alignKeySize, alignDataSize; size_t alignKeyOffset, alignDataOffset; ASSERT(map); alignKeySize = ROUNDUP(map->keySize, 4); alignDataSize = ROUNDUP(map->dataSize, 4); alignKeyOffset = sizeof (HashMapEntryHeader); alignDataOffset = ROUNDUP(alignKeyOffset + alignKeySize, 4); map->entrySize = sizeof (HashMapEntryHeader) + alignKeySize + alignDataSize; map->keyOffset = alignKeyOffset; map->dataOffset = alignDataOffset; } /* * ---------------------------------------------------------------------------- * * LookupKey -- * * Use linear probing to find a free space in the table or the data that * we're interested in. * * Call this function with constTimeLookup = TRUE to use a timing attack * safe version of memcmp while comparing keys. * * Returns: * - TRUE if the key was found in the table, FALSE otherwise. * - Returns the entry header on header, data pointer on data and the first * non-filled index that was encountered on freeIndex * * Side Effects: * - Header and Data are changed. They should only be considered valid if * the key was found. * - FreeIndex will be updated to point to the first non-filled index. * * ---------------------------------------------------------------------------- */ Bool LookupKey(struct HashMap* map, // IN const void *key, // IN Bool constTimeLookup, // IN HashMapEntryHeader **header, // OUT void **data, // OUT uint32 *freeIndex) // OUT { uint32 hash = ComputeHash(map, key); uint32 index = hash % map->numEntries; uint32 probe = 0; Bool done = FALSE, found = FALSE; void *tableKey; ASSERT(map); ASSERT(key); ASSERT(data); ASSERT(freeIndex); *freeIndex = NO_FREE_INDEX; while (!done && probe < map->numEntries + 1) { uint32 currentIndex = (index + probe) % map->numEntries; GetEntry(map, currentIndex, header, &tableKey, data); ASSERT(header); switch ((*header)->state) { case HashMapState_EMPTY: done = TRUE; /* FALL THROUGH */ case HashMapState_DELETED: /* * We're not done if we've found a deleted space. This may just mean * that the entry was deleted but that the target entry may appear * later. */ if (*freeIndex == NO_FREE_INDEX) { *freeIndex = currentIndex; } break; case HashMapState_FILLED: if ((*header)->hash == hash) { /* * There is some performance penalty to doing a constant time * comparison, so only use that version if it's been explicitly * asked for. */ if (constTimeLookup) { found = ConstTimeCompareKeys(map, key, tableKey); } else { found = CompareKeys(map, key, tableKey); } if (found) { done = TRUE; } } break; default: NOT_REACHED(); } probe++; } ASSERT(found || *freeIndex != NO_FREE_INDEX || map->count == map->numEntries); return found; } /* * ---------------------------------------------------------------------------- * * GetEntry -- * * Get a specific entry from the entries list. This does not perform any * hash compare, it's a simple index based lookup. * * Results: * The header is stored in header, key in key and the data in data. These * are all direct pointers into the table. * * Side Effects: * The header, key and data pointers are modified. * * ---------------------------------------------------------------------------- */ void GetEntry(struct HashMap *map, // IN uint32 index, // IN HashMapEntryHeader **header, // OUT void **key, // OUT void **data) // OUT { uint8 *entry; ASSERT(map); ASSERT(header); ASSERT(key); ASSERT(data); ASSERT(index < map->numEntries); entry = ((uint8 *)map->entries) + (map->entrySize * index); ASSERT(entry); *header = (HashMapEntryHeader *) (entry); *key = (void*) (entry + map->keyOffset); *data = (void*) (entry + map->dataOffset); } /* * ---------------------------------------------------------------------------- * * ComputeHash -- * * Compute the hash of the given key. * * Results: * An opaque hash value based on the given key. Given the same key in the * same map, this function will always return the same value. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ uint32 ComputeHash(struct HashMap *map, // IN const void *key) // IN { /* * djb2, with n == 33. See http://www.cse.yorku.ca/~oz/hash.html. * * This hash function is largely borrowed from the emmet library in bora/lib * This hash table implementation does a hash compare before comparing the * keys so it's inappropriate for the hash function to take the modulo before * returning. */ uint32 h = 5381; const uint8 *keyByte; size_t i = 0; for (keyByte = key, i = 0; i < map->keySize; keyByte++, i++) { h *= 33; h += *keyByte; } return h; } /* * ---------------------------------------------------------------------------- * * CompareKeys -- * * Compare two keys to one another. * * Results: * Returns TRUE if the two keys are binary equal over the length specified * in the map. FALSE if the two keys are different. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ Bool CompareKeys(struct HashMap *map, // IN const void *key, // IN const void *compare) // IN { return memcmp(key, compare, map->keySize) == 0; } /* * ---------------------------------------------------------------------------- * * ConstTimeCompareKeys -- * * Timing attack safe version of CompareKeys. Instead of calling memcmp, * which will return after the first character that doesn't match, this * calls a constant time memory comparison function. * * Results: * Returns TRUE if the two keys are binary equal over the length specified * in the map. FALSE if the two keys are different. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ Bool ConstTimeCompareKeys(struct HashMap *map, // IN const void *key, // IN const void *compare) // IN { return Util_ConstTimeMemDiff(key, compare, map->keySize) == 0; } /* * ---------------------------------------------------------------------------- * * NeedsResize -- * * Determine if adding another element to the map will require that the map * be resized. This takes into account the maximum load factor that is * allowed for this map. * * Results: * Returns TRUE if the map should be resized. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ Bool NeedsResize(struct HashMap *map) { uint32 required; Clamped_UMul32(&required, map->count, map->alpha); return required >= map->numEntries; } /* * ---------------------------------------------------------------------------- * * Resize -- * * Doubles the size of the entries array until it is at least large enough * to ensure the maximum load factor is not exceeded. * * Results: * None. * * Side Effects: * The entries list is doubled in size and the entries are copied into the * appropriate location. Callers should not assume that the locations that * were valid before this was called are still valid as all entries may * appear at different locations after this function completes. * * ---------------------------------------------------------------------------- */ void Resize(struct HashMap *map) // IN { struct HashMap oldHashMap = *map; int i; if (map->numEntries == MAX_UINT32) { if (map->count < MAX_UINT32) { /* * We're already at the maximum size of the array and there's still * room for the new entry, don't bother resizing. */ return; } else { /* * This situation is fatal, though we're unlikely to ever hit this with * realistic usage. */ Panic("Ran out of room in the hashtable\n"); } } /* * We might, at some point, want to look at making this grow geometrically * until we hit some threshold and then grow arithmetically after that. To * keep it simple for now, however, we'll just grow geometrically all the * time. */ map->entries = calloc(oldHashMap.numEntries * 2, oldHashMap.entrySize); if (!map->entries) { map->entries = oldHashMap.entries; return; } do { if (!Clamped_UMul32(&map->numEntries, map->numEntries, 2)) { /* Prevent overflow and */ break; } } while (NeedsResize(map)); map->count = 0; for (i = 0; i < oldHashMap.numEntries; i++) { HashMapEntryHeader *oldHeader; HashMapEntryHeader *newHeader; void *oldKey; void *oldData; void *newKey; void *newData; uint32 freeIndex; GetEntry(&oldHashMap, i, &oldHeader, &oldKey, &oldData); switch (oldHeader->state) { case HashMapState_EMPTY: case HashMapState_DELETED: continue; case HashMapState_FILLED: if (!LookupKey(map, oldKey, FALSE, &newHeader, &newData, &freeIndex)) { GetEntry(map, freeIndex, &newHeader, &newKey, &newData); newHeader->hash = oldHeader->hash; newHeader->state = HashMapState_FILLED; memcpy(newKey, oldKey, map->keySize); memcpy(newData, oldData, map->dataSize); map->count++; } else { /* * There is only one way that this could happen; the key is in the * old map twice. That's clearly an error. */ ASSERT(FALSE); continue; } } } ASSERT(oldHashMap.count == map->count); free(oldHashMap.entries); EnsureSanity(map); } /* * ---------------------------------------------------------------------------- * * HashMap_Iterate -- * * Iterate over the contents of the map, optionally clearing each entry as * it's passed. * * Results: * None. * * Side Effects: * itFn is called for each entry in the hashMap until. If clear is TRUE, * each entry will be removed from the map after it has been seen by the * iterator function. * * ---------------------------------------------------------------------------- */ void HashMap_Iterate(HashMap *map, // IN HashMapIteratorFn itFn, // IN Bool clear, // IN void *userData) // IN/OUT { int i = 0; HashMapEntryHeader *header; void *key, *data; ASSERT(map); ASSERT(itFn); for (i = 0; i < map->numEntries; i++) { GetEntry(map, i, &header, &key, &data); if (header->state == HashMapState_FILLED) { itFn(key, data, userData); if (clear) { map->count--; } } if (clear) { header->state = HashMapState_EMPTY; } } ASSERT(map->count == 0 || !clear); } /* * ---------------------------------------------------------------------------- * * EnsureSanity -- * * Ensure that the HashMap contents are still sane. That is, each entry has * a correctly computed hash, the count is correct and the header states are * valid for all entries. This should be called at the end of every * function which modifies the map. * * Results: * None. * * Side Effects: * Fails an assert if the contents are incorrect. * * ---------------------------------------------------------------------------- */ void EnsureSanity(HashMap *map) { ASSERT(CheckSanity(map) == TRUE); } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/000077500000000000000000000000001470176644300220165ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/Makefile.am000066400000000000000000000022511470176644300240520ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libHgfs.la libHgfs_la_SOURCES = libHgfs_la_SOURCES += cpName.c libHgfs_la_SOURCES += cpNameLite.c libHgfs_la_SOURCES += cpNameLinux.c libHgfs_la_SOURCES += cpNameUtil.c libHgfs_la_SOURCES += cpNameUtilLinux.c libHgfs_la_SOURCES += hgfsUtil.c libHgfs_la_SOURCES += hgfsEscape.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/cpName.c000066400000000000000000000330641470176644300233730ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2016,2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpName.c -- * * Shared portions of cross-platform name conversion routines used * by hgfs. [bac] * */ #ifdef sun #include #endif #include "cpName.h" #include "cpNameInt.h" #include "vm_assert.h" #include "hgfsEscape.h" /* *---------------------------------------------------------------------- * * CPName_GetComponent -- * * Get the next component of the CP name. * * Returns the length of the component starting with the begin * pointer, and a pointer to the next component in the buffer, if * any. The "next" pointer is set to "end" if there is no next * component. * * Results: * length (not including NUL termination) >= 0 of next * component on success. * error < 0 on failure (invalid component). * * Side effects: * None * *---------------------------------------------------------------------- */ int CPName_GetComponent(char const *begin, // IN: Beginning of buffer char const *end, // IN: End of buffer char const **next) // OUT: Start of next component { char const *walk; char const *myNext; size_t len; ASSERT(begin); ASSERT(end); ASSERT(next); ASSERT(begin <= end); for (walk = begin; ; walk++) { if (walk == end) { /* End of buffer. No NUL was found */ myNext = end; break; } if (*walk == '\0') { /* Found a NUL */ if (walk == begin) { Log("%s: error: first char can't be NUL\n", __FUNCTION__); return -1; } myNext = walk + 1; /* Skip consecutive path delimiters. */ while ((*myNext == '\0') && (myNext != end)) { myNext++; } if (myNext == end) { /* Last character in the buffer is not allowed to be NUL */ Log("%s: error: last char can't be NUL\n", __FUNCTION__); return -1; } break; } } len = walk - begin; *next = myNext; return (int) len; } /* *---------------------------------------------------------------------- * * CPNameEscapeAndConvertFrom -- * * Converts a cross-platform name representation into a string for * use in the local filesystem. * Escapes illegal characters as a part of convertion. * This is a cross-platform implementation and takes the path separator * argument as an argument. The path separator is prepended before each * additional path component, so this function never adds a trailing path * separator. * * Results: * 0 on success. * error < 0 on failure (the converted string did not fit in * the buffer provided or the input was invalid). * * Side effects: * None * *---------------------------------------------------------------------- */ int CPNameEscapeAndConvertFrom(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input size_t *outSize, // IN/OUT: Size of output buffer char **bufOut, // IN/OUT: Output buffer char pathSep) // IN: Path separator character { int result; int inputSize; inputSize = HgfsEscape_GetSize(*bufIn, *inSize); if (inputSize < 0) { result = -1; } else if (inputSize != 0) { char *savedBufOut = *bufOut; char const *savedOutConst = savedBufOut; size_t savedOutSize = *outSize; if (inputSize > *outSize) { Log("%s: error: not enough room for escaping\n", __FUNCTION__); return -1; } /* Leaving space for the leading path separator, thus output to savedBufOut + 1. */ result = HgfsEscape_Do(*bufIn, *inSize, savedOutSize - 1, savedBufOut + 1); if (result < 0) { Log("%s: error: not enough room to perform escape: %d\n", __FUNCTION__, result); return -1; } *inSize = (size_t) result; result = CPNameConvertFrom(&savedOutConst, inSize, outSize, bufOut, pathSep); *bufIn += *inSize; *inSize = 0; } else { result = CPNameConvertFrom(bufIn, inSize, outSize, bufOut, pathSep); } return result; } /* *---------------------------------------------------------------------- * * CPNameConvertFrom -- * * Converts a cross-platform name representation into a string for * use in the local filesystem. This is a cross-platform * implementation and takes the path separator argument as an * argument. The path separator is prepended before each additional * path component, so this function never adds a trailing path * separator. * * Results: * 0 on success. * error < 0 on failure (the converted string did not fit in * the buffer provided or the input was invalid). * * Side effects: * None * *---------------------------------------------------------------------- */ int CPNameConvertFrom(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input size_t *outSize, // IN/OUT: Size of output buffer char **bufOut, // IN/OUT: Output buffer char pathSep) // IN: Path separator character { char const *in; char const *inEnd; size_t myOutSize; char *out; Bool inPlaceConvertion = (*bufIn == *bufOut); ASSERT(bufIn); ASSERT(inSize); ASSERT(outSize); ASSERT(bufOut); in = *bufIn; inEnd = in + *inSize; if (inPlaceConvertion) { in++; // Skip place for the leading path separator. } myOutSize = *outSize; out = *bufOut; for (;;) { char const *next; int len; int newLen; len = CPName_GetComponent(in, inEnd, &next); if (len < 0) { Log("%s: error: get next component failed\n", __FUNCTION__); return len; } /* Bug 27926 - preventing escaping from shared folder. */ if ((len == 1 && *in == '.') || (len == 2 && in[0] == '.' && in[1] == '.')) { Log("%s: error: found dot/dotdot\n", __FUNCTION__); return -1; } if (len == 0) { /* No more component */ break; } newLen = ((int) myOutSize) - len - 1; if (newLen < 0) { Log("%s: error: not enough room\n", __FUNCTION__); return -1; } myOutSize = (size_t) newLen; *out++ = pathSep; if (!inPlaceConvertion) { memcpy(out, in, len); } out += len; in = next; } /* NUL terminate */ if (myOutSize < 1) { Log("%s: error: not enough room\n", __FUNCTION__); return -1; } *out = '\0'; /* Path name size should not require more than 4 bytes. */ ASSERT((in - *bufIn) <= 0xFFFFFFFF); /* Update pointers. */ *inSize -= (in - *bufIn); *outSize = myOutSize; *bufIn = in; *bufOut = out; return 0; } /* *---------------------------------------------------------------------------- * * CPName_Print -- * * Converts a CPName formatted string to a valid, NUL-terminated string by * replacing all embedded NUL characters with '|'. * * Results: * Pointer to a static buffer containing the converted string. * * Side effects: * None. * *---------------------------------------------------------------------------- */ char const * CPName_Print(char const *in, // IN: Name to print size_t size) // IN: Size of name { /* Static so it does not go on a kernel stack --hpreg */ static char out[128]; size_t i; ASSERT(in); ASSERT(sizeof out >= 4); if (size > sizeof out - 1) { size = sizeof out - 4; out[size] = '.'; out[size + 1] = '.'; out[size + 2] = '.'; out[size + 3] = '\0'; } else { out[size] = '\0'; } for (i = 0; i < size; i++) { out[i] = in[i] != '\0' ? in[i] : '|'; } return out; } /* *---------------------------------------------------------------------------- * * CPName_LinuxConvertTo -- * * Wrapper function that calls CPNameConvertTo() with the correct arguments * for Linux path conversions. * * Makes a cross-platform name representation from the Linux path input * string and writes it into the output buffer. * * Results: * On success, returns the number of bytes used in the cross-platform name, * NOT including the final terminating NUL character. On failure, returns * a negative error. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int CPName_LinuxConvertTo(char const *nameIn, // IN: Buf to convert size_t bufOutSize, // IN: Size of the output buffer char *bufOut) // OUT: Output buffer { return CPNameConvertTo(nameIn, bufOutSize, bufOut, '/'); } /* *---------------------------------------------------------------------------- * * CPName_WindowsConvertTo -- * * Wrapper function that calls CPNameConvertTo() with the correct arguments * for Windows path conversions. * * Makes a cross-platform name representation from the Linux path input * string and writes it into the output buffer. * * Results: * On success, returns the number of bytes used in the cross-platform name, * NOT including the final terminating NUL character. On failure, returns * a negative error. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int CPName_WindowsConvertTo(char const *nameIn, // IN: Buf to convert size_t bufOutSize, // IN: Size of the output buffer char *bufOut) // OUT: Output buffer { return CPNameConvertTo(nameIn, bufOutSize, bufOut, '\\'); } /* *---------------------------------------------------------------------- * * CPNameConvertTo -- * * Makes a cross-platform name representation from the input string * and writes it into the output buffer. * HGFS convention is to echange names between guest and host in uescaped form. * Both ends perform necessary name escaping according to its own rules * to avoid presenitng invalid file names to OS. Thus the name needs to be unescaped * as a part of conversion to host-independent format. * * Results: * On success, returns the number of bytes used in the * cross-platform name, NOT including the final terminating NUL * character. On failure, returns a negative error. * * Side effects: * None * *---------------------------------------------------------------------- */ int CPNameConvertTo(char const *nameIn, // IN: Buf to convert size_t bufOutSize, // IN: Size of the output buffer char *bufOut, // OUT: Output buffer char pathSep) // IN: path separator to use { char *origOut = bufOut; char const *endOut = bufOut + bufOutSize; size_t cpNameLength = 0; ASSERT(nameIn); ASSERT(bufOut); /* Skip any path separators at the beginning of the input string */ while (*nameIn == pathSep) { nameIn++; } /* * Copy the string to the output buf, converting all path separators into '\0'. * Collapse multiple consecutive path separators into a single one since * CPName_GetComponent can't handle consecutive path separators. */ while (*nameIn != '\0' && bufOut < endOut) { if (*nameIn == pathSep) { *bufOut = '\0'; do { nameIn++; } while (*nameIn == pathSep); } else { *bufOut = *nameIn; nameIn++; } bufOut++; } /* * NUL terminate. XXX This should go away. * * When we get rid of NUL termination here, this test should * also change to "if (*nameIn != '\0')". */ if (bufOut == endOut) { return -1; } *bufOut = '\0'; /* Path name size should not require more than 4 bytes. */ ASSERT((bufOut - origOut) <= 0xFFFFFFFF); /* If there were any trailing path separators, dont count them [krishnan] */ cpNameLength = bufOut - origOut; while ((cpNameLength >= 1) && (origOut[cpNameLength - 1] == 0)) { cpNameLength--; } cpNameLength = HgfsEscape_Undo(origOut, cpNameLength); /* Return number of bytes used */ return (int) cpNameLength; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/cpNameInt.h000066400000000000000000000052101470176644300240430ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpNameInt.h -- * * Cross-platform name format used by hgfs. * */ #ifndef __CP_NAME_INT_H__ #define __CP_NAME_INT_H__ #include "vm_basic_types.h" /* * Used by CPName_ConvertFrom */ int CPNameConvertFrom(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input size_t *outSize, // IN/OUT: Size of output buffer char **bufOut, // IN/OUT: Output buffer char pathSep); // IN: Path separator character int CPNameEscapeAndConvertFrom(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input size_t *outSize, // IN/OUT: Size of output buffer char **bufOut, // IN/OUT: Output buffer char pathSep); // IN: Path separator character /* * Common code for CPName_ConvertTo */ int CPNameConvertTo(char const *nameIn, // IN: Buf to convert size_t bufOutSize, // IN: Size of the output buffer char *bufOut, // OUT: Output buffer char pathSep); // IN: path separator to use #endif /* __CP_NAME_INT_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/cpNameLinux.c000066400000000000000000000127561470176644300244200ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpNameLinux.c -- * * Linux implementation of cross-platform name conversion * routines used by hgfs. [bac] * */ #if defined sun && !defined SOL9 #include #endif #include "cpName.h" #include "cpNameInt.h" #include "vm_assert.h" #include "hgfsEscape.h" /* *---------------------------------------------------------------------- * * CPName_ConvertFrom -- * * Converts a cross-platform name representation into a string for * use in the local filesystem. * * Results: * Length (not including NUL termination) >= 0 of resulting * string on success. * Negative error on failure (the converted string did not fit in * the buffer provided or the input was invalid). * * Side effects: * None * *---------------------------------------------------------------------- */ int CPName_ConvertFrom(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input size_t *outSize, // IN/OUT: Size of output buffer char **bufOut) // IN/OUT: Output buffer { ASSERT(bufIn); ASSERT(inSize); ASSERT(outSize); ASSERT(bufOut); return CPNameEscapeAndConvertFrom(bufIn, inSize, outSize, bufOut, '/'); } /* *---------------------------------------------------------------------- * * CPName_ConvertFromRoot -- * * Append the appropriate prefix to the output buffer for accessing * the root of the local filesystem. CPName_ConvertFrom prepends * leading path separators before each path component, but only * when the next component has nonzero length, so we still need to * special case this for Linux. * * The pointers and sizes are updated appropriately. * * Results: * Status of name conversion * * Side effects: * None * *---------------------------------------------------------------------- */ HgfsNameStatus CPName_ConvertFromRoot(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input size_t *outSize, // IN/OUT: Size of output buffer char **bufOut) // IN/OUT: Output buffer { char const *next; char *out; int len; ASSERT(bufIn); ASSERT(inSize); ASSERT(outSize); ASSERT(bufOut); out = *bufOut; /* * Get first component */ len = CPName_GetComponent(*bufIn, *bufIn + *inSize, &next); if (len < 0) { Log("%s: get first component failed\n", __FUNCTION__); return HGFS_NAME_STATUS_FAILURE; } /* Space for leading '/' plus NUL termination */ if (*outSize < len + 2) { return HGFS_NAME_STATUS_FAILURE; } /* Put a leading '/' in the output buffer either way */ *out++ = '/'; memcpy(out, *bufIn, len); out += len; /* NUL terminate */ *out = '\0'; *inSize -= next - *bufIn; *outSize -= out - *bufOut; *bufIn = next; *bufOut = out; return HGFS_NAME_STATUS_COMPLETE; } /* *---------------------------------------------------------------------------- * * CPName_ConvertTo -- * * Wrapper function that calls the Linux implementation of _ConvertTo(). * * Makes a cross-platform name representation from the Linux path input * string and writes it into the output buffer. * If the name being converter may be a result a of name escaping the * function performs unescaping. HGFS convention is to always exchange * unescaped names between guest and host and to perform necessary * name escaping on both ends. * * Results: * On success, returns the number of bytes used in the * cross-platform name, NOT including the final terminating NUL * character. On failure, returns a negative error. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int CPName_ConvertTo(char const *nameIn, // IN: Buf to convert size_t bufOutSize, // IN: Size of the output buffer char *bufOut) // OUT: Output buffer { int result; result = CPName_LinuxConvertTo(nameIn, bufOutSize, bufOut); return result; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/cpNameLite.c000066400000000000000000000062421470176644300242070ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpNameLite.c -- * * Shared portions of cross-platform name conversion routines used * by hgfs. Unlike the real CP name conversion routines, these ones * just convert path separators to nul characters and vice versa. * */ #include "cpNameLite.h" #include "vm_assert.h" /* *---------------------------------------------------------------------- * * CPNameLite_ConvertTo -- * * Makes a cross-platform lite name representation from the input * string. * * Results: * None * * Side effects: * None * *---------------------------------------------------------------------- */ void CPNameLite_ConvertTo(char *bufIn, // IN/OUT: Input to convert size_t inSize, // IN: Size of input buffer char pathSep) // IN: Path separator { size_t pos; ASSERT(bufIn); for (pos = 0; pos < inSize; pos++) { if (bufIn[pos] == pathSep) { bufIn[pos] = '\0'; } } } /* *---------------------------------------------------------------------- * * CPNameLite_ConvertFrom -- * * Converts a cross-platform lite name representation into a string for * use in the local filesystem. This is a cross-platform * implementation and takes the path separator as an * argument. * * Results: * None * * Side effects: * None * *---------------------------------------------------------------------- */ void CPNameLite_ConvertFrom(char *bufIn, // IN/OUT: Input to convert size_t inSize, // IN: Size of input buffer char pathSep) // IN: Path separator { size_t pos; ASSERT(bufIn); for (pos = 0; pos < inSize; pos++) { if (bufIn[pos] == '\0') { bufIn[pos] = pathSep; } } } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/cpNameUtil.c000066400000000000000000000255341470176644300242340ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2005-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpNameUtil.c * * Common implementations of CPName utility functions. */ /* Some of the headers below cannot be included in driver code */ #if !defined __KERNEL__ && !defined _KERNEL && !defined KERNEL #include "cpNameUtil.h" #include "hgfsServerPolicy.h" #include "hgfsVirtualDir.h" #include "util.h" #include "vm_assert.h" #include "str.h" #include "cpNameUtilInt.h" #define WIN_DIRSEPC '\\' #define WIN_DIRSEPS "\\" /* *---------------------------------------------------------------------------- * * CPNameUtil_Strrchr -- * * Performs strrchr(3) on a CPName path. * * Results: * Pointer to last occurrence of searchChar in cpNameIn if found, NULL if * not found. * * Side effects: * None. * *---------------------------------------------------------------------------- */ char * CPNameUtil_Strrchr(char const *cpNameIn, // IN: CPName path to search size_t cpNameInSize, // IN: Size of CPName path char searchChar) // IN: Character to search for { ssize_t index; ASSERT(cpNameIn); ASSERT(cpNameInSize > 0); for (index = cpNameInSize - 1; cpNameIn[index] != searchChar && index >= 0; index--); return (index < 0) ? NULL : (char *)(cpNameIn + index); } /* *---------------------------------------------------------------------------- * * CPNameUtil_LinuxConvertToRoot -- * * Performs CPName conversion and such that the result can be converted back * to an absolute path (in the "root" share) by a Linux hgfs server. * * Note that nameIn must contain an absolute path. * * Results: * Size of the output buffer on success, negative value on error * * Side effects: * None. * *---------------------------------------------------------------------------- */ int CPNameUtil_LinuxConvertToRoot(char const *nameIn, // IN: buf to convert size_t bufOutSize, // IN: size of the output buffer char *bufOut) // OUT: output buffer { const size_t shareNameSize = HGFS_STR_LEN(HGFS_SERVER_POLICY_ROOT_SHARE_NAME); int result; ASSERT(nameIn); ASSERT(bufOut); if (bufOutSize <= shareNameSize) { return -1; } /* Prepend the name of the "root" share directly in the output buffer */ memcpy(bufOut, HGFS_SERVER_POLICY_ROOT_SHARE_NAME, shareNameSize); bufOut[shareNameSize] = '\0'; result = CPName_LinuxConvertTo(nameIn, bufOutSize - shareNameSize - 1, bufOut + shareNameSize + 1); /* Return either the same error code or the correct size */ return (result < 0) ? result : (int)(result + shareNameSize + 1); } /* *---------------------------------------------------------------------------- * * CPNameUtil_WindowsConvertToRoot -- * * Performs CPName conversion and appends necessary strings ("root" and * "drive"|"unc") so that the result can be converted back to an absolute * path (in the "root" share) by a Windows hgfs server. * * Note that nameIn must contain an absolute path. * * Results: * Size of the output buffer on success, negative value on error * * Side effects: * None. * *---------------------------------------------------------------------------- */ int CPNameUtil_WindowsConvertToRoot(char const *nameIn, // IN: buf to convert size_t bufOutSize, // IN: size of the output buffer char *bufOut) // OUT: output buffer { const char partialName[] = HGFS_SERVER_POLICY_ROOT_SHARE_NAME; const size_t partialNameLen = HGFS_STR_LEN(HGFS_SERVER_POLICY_ROOT_SHARE_NAME); const char *partialNameSuffix = ""; size_t partialNameSuffixLen; char *fullName; size_t fullNameLen; size_t nameLen; int result; ASSERT(nameIn); ASSERT(bufOut); /* * Create the full name. Note that Str_Asprintf should not be * used here as it uses FormatMessages which interprets 'data', a UTF-8 * string, as a string in the current locale giving wrong results. */ /* * Is this file path a UNC path? */ if (nameIn[0] == WIN_DIRSEPC && nameIn[1] == WIN_DIRSEPC) { partialNameSuffix = WIN_DIRSEPS HGFS_UNC_DIR_NAME WIN_DIRSEPS; partialNameSuffixLen = HGFS_STR_LEN(WIN_DIRSEPS) + HGFS_STR_LEN(HGFS_UNC_DIR_NAME) + HGFS_STR_LEN(WIN_DIRSEPS); } else { partialNameSuffix = WIN_DIRSEPS HGFS_DRIVE_DIR_NAME WIN_DIRSEPS; partialNameSuffixLen = HGFS_STR_LEN(WIN_DIRSEPS) + HGFS_STR_LEN(HGFS_DRIVE_DIR_NAME) + HGFS_STR_LEN(WIN_DIRSEPS); } /* Skip any path separators at the beginning of the input string */ while (*nameIn == WIN_DIRSEPC) { nameIn++; } nameLen = strlen(nameIn); fullNameLen = partialNameLen + partialNameSuffixLen + nameLen; fullName = (char *)Util_SafeMalloc(fullNameLen + 1); memcpy(fullName, partialName, partialNameLen); memcpy(fullName + partialNameLen, partialNameSuffix, partialNameSuffixLen); if (nameIn[1] == ':') { /* * If the name is in format ":" strip out ':' from it * because the rest of the code assumes that driver letter in a * platform independent name is represented by a single character without colon. */ fullName[partialNameLen + partialNameSuffixLen] = nameIn[0]; memcpy(fullName + partialNameLen + partialNameSuffixLen + 1, nameIn + 2, nameLen - 2); fullNameLen--; } else { memcpy(fullName + partialNameLen + partialNameSuffixLen, nameIn, nameLen); } fullName[fullNameLen] = '\0'; /* CPName_ConvertTo strips out the ':' character */ result = CPName_WindowsConvertTo(fullName, bufOutSize, bufOut); free(fullName); return result; } /* *---------------------------------------------------------------------------- * * CPNameUtil_Utf8FormHostToUtf8FormC -- * * Convert CPname to form C (precomposed) which is used by the HGFS * protocol from host preferred format. On Mac hosts the current format * is unicode form D, so conversion is required, others the current * format is the same. * * Input/output name lengths include the nul-terminator so that the * conversion routine will include the final character when breaking * up the CPName into it's individual components. * * * Results: * TRUE if success result string is in form C format, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool CPNameUtil_Utf8FormHostToUtf8FormC(const char *cpNameToConvert, // IN: size_t cpNameToConvertLen, // IN: includes nul char **cpUtf8FormCName, // OUT: size_t *cpUtf8FormCNameLen) // OUT: includes nul { return CPNameUtilConvertUtf8FormCAndD(cpNameToConvert, cpNameToConvertLen, TRUE, cpUtf8FormCName, cpUtf8FormCNameLen); } /* *---------------------------------------------------------------------------- * * CPNameUtil_Utf8FormCToUtf8FormHost -- * * Convert from CP unicode form C (decomposed) name used by the HGFS * protocol to the host preferred format. On Mac OS is unicode form D * (precomposed), everyone else this stays as form C (precomposed). * * Input/output name lengths include the nul-terminator so that the * conversion routine will include the final character when breaking * up the CPName into it's individual components. * * Results: * TRUE if success result string is in CP format, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool CPNameUtil_Utf8FormCToUtf8FormHost(const char *cpUtf8FormCName, // IN: size_t cpUtf8FormCNameLen, // IN: includes nul char **cpConvertedName, // OUT: size_t *cpConvertedNameLen) // OUT: includes nul { return CPNameUtilConvertUtf8FormCAndD(cpUtf8FormCName, cpUtf8FormCNameLen, FALSE, cpConvertedName, cpConvertedNameLen); } /* *---------------------------------------------------------------------------- * * CPNameUitl_CharReplace -- * * A simple function to replace all oldChar's with newChar's in a binary * buffer. This is used for either replacing NULL with local DIRSPEC to * convert from relative cross-platform name to local relative name, or * replacing local DIRSEPC with NULL to convert from local relative name * to relative cross-platform file name * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ void CPNameUtil_CharReplace(char *buf, // IN/OUT size_t bufSize, // IN char oldChar, // IN char newChar) // IN { size_t i; ASSERT(buf); for (i = 0; i < bufSize; i++) { if (buf[i] == oldChar) { buf[i] = newChar; } } } #endif /* __KERNEL__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/cpNameUtilInt.h000066400000000000000000000037751470176644300247170ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpNameUtilInt.h -- * * Cross-platform name format used by hgfs. * */ #ifndef __CP_NAME_UTIL_INT_H__ #define __CP_NAME_UTIL_INT_H__ #include "vm_basic_types.h" /* * Used by CPNameUtil_Utf8FormHostToUtf8FormC and * CPNameUtil_Utf8FormCToUtf8FormHost. */ Bool CPNameUtilConvertUtf8FormCAndD(const char *cpNameToConvert, size_t cpNameToConvertLen, Bool convertToFormC, char **cpConvertedName, size_t *cpConvertedNameLen); #endif /* __CP_NAME_UTIL_INT_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/cpNameUtilLinux.c000066400000000000000000000140201470176644300252400ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2005-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpNameUtilLinux.c * * Linux implementation of CPName utility functions. These are not included * in the main CPName API since they may require other calls on the * resulting CPName to be from the same OS-type. */ /* Some of the headers in cpNameUtil.c cannot be included in driver code */ #if !defined __KERNEL__ && !defined _KERNEL && !defined KERNEL #include "cpNameUtil.h" #include "cpNameUtilInt.h" #if defined __APPLE__ #include "codeset.h" #endif /* defined __APPLE__ */ #include "util.h" /* *---------------------------------------------------------------------------- * * CPNameUtil_ConvertToRoot -- * * Pass through function that calls Linux version of _ConvertToRoot(). * * Performs CPName conversion and such that the result can be converted back * to an absolute path (in the "root" share) by a Linux hgfs server. * * Note that nameIn must contain an absolute path. * * Results: * Size of the output buffer on success, negative value on error. * * Side effects: * None. * *---------------------------------------------------------------------------- */ int CPNameUtil_ConvertToRoot(char const *nameIn, // IN: buf to convert size_t bufOutSize, // IN: size of the output buffer char *bufOut) // OUT: output buffer { return CPNameUtil_LinuxConvertToRoot(nameIn, bufOutSize, bufOut); } /* *---------------------------------------------------------------------------- * * CPNameUtilConvertUtf8FormCAndD -- * * Helper conversion routine to convert between a CP format name * in unicode form C (precomposed) format which is used by the HGFS * protocol requests and the unicode form D (decomposed) format, * which is used on Mac OS host (everyone else uses form C). * * Results: * TRUE if success result string is converted, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool CPNameUtilConvertUtf8FormCAndD(const char *cpNameToConvert, // IN: size_t cpNameToConvertLen, // IN: includes nul Bool convertToFormC, // IN: char **cpConvertedName, // OUT: size_t *cpConvertedNameLen) // OUT: includes nul { Bool status = TRUE; #if defined __APPLE__ const char *begin; const char *end; const char *next; char *newData = NULL; char *convertedName = NULL; size_t convertedNameLen; uint32 newDataLen = 0; int len; ASSERT(cpNameToConvert); ASSERT(cpConvertedName); ASSERT(cpConvertedNameLen); /* * Get first component. We bypass the higher level CPName_GetComponent * function so we'll have more control over the illegal characters. */ begin = cpNameToConvert; end = cpNameToConvert + cpNameToConvertLen - 1; /* Get the length of this component, and a pointer to the next. */ while ((len = CPName_GetComponent(begin, end, &next)) != 0) { uint32 origNewDataLen = newDataLen; if (len < 0) { status = FALSE; goto exit; } if (convertToFormC) { status = CodeSet_Utf8FormDToUtf8FormC(begin, len, &convertedName, &convertedNameLen); } else { status = CodeSet_Utf8FormCToUtf8FormD(begin, len, &convertedName, &convertedNameLen); } if (!status) { goto exit; } /* * Append this component to our list: allocate one more for NUL. */ newDataLen += convertedNameLen + 1; newData = (char *)Util_SafeRealloc(newData, newDataLen); memcpy(newData + origNewDataLen, convertedName, convertedNameLen); newData[newDataLen - 1] = '\0'; free(convertedName); convertedName = NULL; begin = next; } *cpConvertedName = newData; /* Including nul terminator */ *cpConvertedNameLen = newDataLen; exit: if (!status) { if (newData != NULL) { free(newData); } } #else /* defined __APPLE__ */ /* No conversion required return a copy of what is received. */ *cpConvertedName = Util_SafeCalloc(1, cpNameToConvertLen); memcpy(*cpConvertedName, cpNameToConvert, cpNameToConvertLen); *cpConvertedNameLen = cpNameToConvertLen; #endif /* defined __APPLE__ */ return status; } #endif /* __KERNEL__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/hgfsEscape.c000066400000000000000000000764021470176644300242430ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2008-2019,2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfsEscape.c -- * * Escape and unescape illegal filenames for different platforms. * */ #ifdef __KERNEL__ # include "driver-config.h" # include #elif defined __FreeBSD__ # if defined _KERNEL # include # define strchr(s,c) index(s,c) # else # include # endif # define memmove(s1,s2,n) bcopy(s2,s1,n) #elif defined __APPLE__ && defined KERNEL # include #elif !defined sun # include # include #else # include #endif #include "vmware.h" #include "hgfsEscape.h" #include "cpName.h" #ifdef _WIN32 #define UNREFERENCED_PARAMETER(P) (P) /* These characters are illegal in Windows file names. */ const char* HGFS_ILLEGAL_CHARS = "/\\*?:\"<>|"; const char* HGFS_SUBSTITUTE_CHARS = "!@#$^&(){"; /* Last character of a file name in Windows can be neither dot nor space. */ const char* HGFS_ILLEGAL_LAST_CHARS = ". "; /* http://msdn.microsoft.com/en-us/library/aa365247.aspx */ char *HgfsReservedNames[] = {"CON", "PRN", "AUX", "NUL"}; char *HgfsReservedNamesWithNumber[] = {"COM", "LPT"}; #define HGFS_RESERVED_NAME_CHARS_LENGTH 3 #define HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH (HGFS_RESERVED_NAME_CHARS_LENGTH + 1) /* Check for special escaping cases - reserved names and illegal last characters. */ #define IS_SPECIAL_CASE_ESCAPE(b,o,l) HgfsIsSpecialCaseEscape(b,o,l) /* Process Windows reserved names. */ #define PROCESS_RESERVED_NAME(b,s,p,o,c) \ if (!HgfsProcessReservedName(b,s,p,o,c)) \ { \ return FALSE; \ } /* Process Windows reserved names. */ #define PROCESS_LAST_CHARACTER(b,s,p,c) \ if (!HgfsProcessLastCharacter(b,s,p,c)) \ { \ return FALSE; \ } #else // _WIN32 #define UNREFERENCED_PARAMETER(P) /* There is no special escape sequences on other than Windows platforms. */ #define IS_SPECIAL_CASE_ESCAPE(b,o,l) FALSE /* There is no reserved names on other then Windows platforms. */ #define PROCESS_RESERVED_NAME(b,s,p,o,c) /* There is no special processing for the last character on non-Windows platforms. */ #define PROCESS_LAST_CHARACTER(b,s,p,c) #if defined __APPLE__ /* These characters are illegal in MAC OS file names. */ const char* HGFS_ILLEGAL_CHARS = "/:"; const char* HGFS_SUBSTITUTE_CHARS = "!&"; #else // __APPLE__ /* These characters are illegal in Linux file names. */ const char* HGFS_ILLEGAL_CHARS = "/"; const char* HGFS_SUBSTITUTE_CHARS = "!"; #endif // __APPLE__ #endif // _WIN32 #define HGFS_ESCAPE_CHAR '%' #define HGFS_ESCAPE_SUBSTITUE_CHAR ']' typedef enum { HGFS_ESCAPE_ILLEGAL_CHARACTER, HGFS_ESCAPE_RESERVED_NAME, HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER, HGFS_ESCAPE_ESCAPE_SEQUENCE, HGFS_ESCAPE_COMPLETE } HgfsEscapeReason; typedef Bool (*HgfsEnumCallback)(char const *bufIn, uint32 offset, HgfsEscapeReason reason, void* context); /* * The structure is used by HgfsAddEscapeCharacter to keep context information between * invocations * All offsets defined in this structure are in characters, not bytes */ typedef struct { uint32 processedOffset; // Offset of the first unprocessed input character uint32 outputBufferLength; // Number of characters in the output buffer uint32 outputOffset; // Number of characters that are already in the output char *outputBuffer; // Pointer to the output buffer } HgfsEscapeContext; static void HgfsEscapeUndoComponent(char *bufIn, uint32 *totalLength); static int HgfsEscapeGetComponentSize(char const *bufIn, uint32 sizeIn); static int HgfsEscapeDoComponent(char const *bufIn, uint32 sizeIn, uint32 sizeBufOut, char *bufOut); /* *----------------------------------------------------------------------------- * * HgfsAddEscapeCharacter -- * * Callback function that is called by HgfsEnumerate to insert an escape sequence * into the input name. * * Results: * TRUE if successful, FALSE if there is an error like the output buffer is * too small. * * Side effects: * Updates the output buffer pointer (stored in the context variable). * *----------------------------------------------------------------------------- */ static Bool HgfsAddEscapeCharacter(char const * bufIn, // IN: input name uint32 offset, // IN: offset that requires escaping HgfsEscapeReason reason, // IN: reason for esaping void *context) // IN/OUT: convertion context { HgfsEscapeContext *escapeContext = (HgfsEscapeContext *)context; uint32 charactersToCopy; uint32 outputSpace; char* illegal; Bool result = TRUE; ASSERT(offset >= escapeContext->processedOffset); // Scanning forward charactersToCopy = offset - escapeContext->processedOffset; if (escapeContext->outputOffset + charactersToCopy > escapeContext->outputBufferLength) { return FALSE; } memcpy(escapeContext->outputBuffer + escapeContext->outputOffset, bufIn + escapeContext->processedOffset, charactersToCopy * sizeof *bufIn); escapeContext->outputOffset += charactersToCopy; escapeContext->processedOffset += charactersToCopy; outputSpace = escapeContext->outputBufferLength - escapeContext->outputOffset; switch(reason) { case HGFS_ESCAPE_ILLEGAL_CHARACTER: if (outputSpace < 2) { return FALSE; } illegal = strchr(HGFS_ILLEGAL_CHARS, bufIn[escapeContext->processedOffset]); escapeContext->processedOffset++; // Skip illegal input character ASSERT(illegal != NULL); escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_SUBSTITUTE_CHARS[illegal - HGFS_ILLEGAL_CHARS]; escapeContext->outputOffset++; escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR; escapeContext->outputOffset++; break; case HGFS_ESCAPE_RESERVED_NAME: if (outputSpace < 1) { return FALSE; } escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR; escapeContext->outputOffset++; break; case HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER: if (outputSpace < 1) { return FALSE; } escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR; escapeContext->outputOffset++; break; case HGFS_ESCAPE_ESCAPE_SEQUENCE: if (outputSpace < 2) { return FALSE; } escapeContext->processedOffset++; // Skip input esape character escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_SUBSTITUE_CHAR; escapeContext->outputOffset++; escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR; escapeContext->outputOffset++; break; case HGFS_ESCAPE_COMPLETE: if (outputSpace < 1) { return FALSE; } escapeContext->outputBuffer[escapeContext->outputOffset] = '\0'; break; default: result = FALSE; ASSERT(FALSE); } return result; } /* *----------------------------------------------------------------------------- * * HgfsCountEscapeChars -- * * Callback function that is called by HgfsEnumerate to count additional characters * that need to be inserted in the input name. * * Results: * TRUE since it never fails. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsCountEscapeChars(char const *bufIn, // IN: input name uint32 offset, // IN: offset where escape is needed HgfsEscapeReason reason, // IN: reason for escaping void *context) // IN/OUT: context info { UNREFERENCED_PARAMETER(bufIn); UNREFERENCED_PARAMETER(offset); if (reason != HGFS_ESCAPE_COMPLETE) { uint32 *counter = (uint32*)context; (*counter)++; } return TRUE; } #ifdef _WIN32 /* *----------------------------------------------------------------------------- * * HgfsLetterToUpper -- * * Converts lowercase English letters to uppercase. * If the symbol is not a lowercase English letter returns the original character. * * Results: * Converted character. * * Side effects: * None * *----------------------------------------------------------------------------- */ static char HgfsLetterToUpper(char letter) { if (letter >= 'a' && letter <= 'z') { return letter - ('a' - 'A'); } return letter; } /* *----------------------------------------------------------------------------- * * HgfsIsEqualPrefix -- * * Verifies if the string prefix is equal to the given prefix. * It assumes that the prefix includes only uppercase English letters or numbers * and it does not have any international characters. * The string must be either NULL terminated or not shorter then the prefix. * * Results: * TRUE if the uppcased string starts with the given prefix. False otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsIsEqualPrefix(char const *prefix, // IN: prefix to check char const *string, // IN: input string uint32 prefixLength) // IN: length of the prefix in characters { int i; for (i = 0; i < prefixLength; i++) { ASSERT(prefix[i] > 0 && (prefix[i] < 'a' || prefix[i] > 'z' )); if (prefix[i] != HgfsLetterToUpper(string[i])) { return FALSE; } } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsIsReservedPrefix -- * * Verifies if the name's prefix is one of the reserved names. * * Results: * TRUE if the name's prefix is one of the reserved names. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsIsReservedPrefix(char const *bufIn) // IN: input name { uint32 i; for (i = 0; i < ARRAYSIZE(HgfsReservedNames); i++) { if (HgfsIsEqualPrefix(HgfsReservedNames[i], bufIn, HGFS_RESERVED_NAME_CHARS_LENGTH)) { return TRUE; } } return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsIsReservedPrefixWithNumber -- * * Verifies if the name's prefix is one of the reserved names with number: * COM1-9 or LPT1-9. * * Results: * TRUE if the name's prefix is one of the reserved names with number. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsIsReservedPrefixWithNumber(char const *bufIn) // IN: input name { uint32 i; for (i = 0; i < ARRAYSIZE(HgfsReservedNamesWithNumber); i++) { if (HgfsIsEqualPrefix(HgfsReservedNamesWithNumber[i], bufIn, HGFS_RESERVED_NAME_CHARS_LENGTH) && bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] >= '1' && bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] <= '9') { return TRUE; } } return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsIsSpecialCaseEscape -- * * Verifies if the escape character is a part of special case escape sequence * that exists only in Windows - escaped reserved name or escaped illegal last * character. * * Results: * TRUE if the name's prefix is one of the reserved names with number. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsIsSpecialCaseEscape(char const *bufIn, // IN: input name uint32 offset, // IN: offset of the escape character uint32 length) // IN: length of the name in characters { if (offset + 1 == length && strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[offset - 1]) != NULL) { return TRUE; } if (offset == HGFS_RESERVED_NAME_CHARS_LENGTH && (length == HGFS_RESERVED_NAME_CHARS_LENGTH + 1 || bufIn[offset+1] == '.')) { return HgfsIsReservedPrefix(bufIn); } if (offset == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH && (length == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH + 1 || bufIn[offset+1] == '.')) { return HgfsIsReservedPrefixWithNumber(bufIn); } return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsProcessReservedName -- * * Verifies if the name is one of reserved Windows file names. * If it is a reserved name invokes callback that performs required * processing. * * Results: * TRUE if no processing is required of if processing succeeded, * FALSE if processing failed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsProcessReservedName(char const *bufIn, // IN: Unescaped input buffer uint32 sizeIn, // IN: Length of the input HgfsEnumCallback processEscape, // IN: Callack that is invoked // if input is reserved name uint32 *offset, // OUT: New offset in the input void *context) // IN/OUT: Context for callback { /* Look reserved names: CON, PRN, AUX, NUL. */ if (sizeIn >= HGFS_RESERVED_NAME_CHARS_LENGTH && HgfsIsReservedPrefix(bufIn)) { if (HGFS_RESERVED_NAME_CHARS_LENGTH == sizeIn || bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] == '.') { if (!processEscape(bufIn, HGFS_RESERVED_NAME_CHARS_LENGTH, HGFS_ESCAPE_RESERVED_NAME, context)) { return FALSE; } *offset = HGFS_RESERVED_NAME_CHARS_LENGTH; } } /* Look reserved names with numbers: COM1-9 and LPT1-9. */ if (sizeIn >= HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH && HgfsIsReservedPrefixWithNumber(bufIn)) { if (HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH == sizeIn || bufIn[HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH] == '.') { if (!processEscape(bufIn, HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH, HGFS_ESCAPE_RESERVED_NAME, context)) { return FALSE; } *offset = HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH; } } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsProcessLastCharacter -- * * Verifies if the trailing character in the name is a valid last character. * In Windows it is illegal to have a file name that ends with dot ('.') or * space (' '). The only exception is "." and ".." directory names. * If the last character is invalid the function invokes a callback to process it. * * Results: * TRUE if no processing is required of if processing succeeded, * FALSE if processing failed. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsProcessLastCharacter(char const *bufIn, // IN: Unescaped input buffer uint32 sizeIn, // IN: Length of the input HgfsEnumCallback processEscape, // IN: Callack that is invoked // when escaping is needed void *context) // IN/OUT: Callback context { /* If the filename is '.' or '..' we shouldn't escape it. */ if ((sizeIn == 1 && bufIn[0] == '.') || (sizeIn == 2 && bufIn[0] == '.' && bufIn[1] == '.')) { return TRUE; } /* Invoke the callback if the last character is illegal. */ if (strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[sizeIn - 1]) != NULL) { if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER, context)) { return FALSE; } } return TRUE; } #endif // WIN32 /* *----------------------------------------------------------------------------- * * HgfsIsEscapeSequence -- * * Verifies if input buffer has an escape sequence at the position * defined by offset. * * Results: * TRUE if there is an escape sequence at the position defined by offset. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsIsEscapeSequence(char const *bufIn, // IN: input name uint32 offset, // IN: offset of the escape character uint32 length) // IN: length of the name in characters { if (bufIn[offset] == HGFS_ESCAPE_CHAR && offset > 0) { char *substitute; if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR && offset > 1) { /* * Possibly a valid sequence, check it must be preceded with a substitute * character or another escape-escape character. Otherwise, HGFS did * not generate this sequence and should leave it alone. */ if (bufIn[offset - 2] == HGFS_ESCAPE_SUBSTITUE_CHAR) { return TRUE; } substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 2]); if (substitute != NULL) { return TRUE; } } substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]); if (substitute != NULL) { return TRUE; } return IS_SPECIAL_CASE_ESCAPE(bufIn,offset,length); } return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsEscapeEnumerate -- * * The function scans the input buffer and calls processEscape callback for every * place in the input buffer which require escaping. * * Callback does the required processing. There are two different callbacks - * one counts extra symbols that are needed for escaping and another produces * escaped output name based on input name. * * 1. The first function calculates number of extra characters. It just increments * a counter which is passed to it in context variable every time it is called * for the reason different from "complete processing" assuming that * exactly one extra character is required to escape any invalid input. * * 2. The second function produces output name by copying everything from input * name into the output name up to the place which require escaping and * then inserts appropriate escape sequence into the output. It keeps track of its * progress and keeps pointer to the output buffer in the context variable. * HgfsEscapeEnumerate calls calback function one more time at the end of the * input buffer to let callback finish processing of the input (for example copy * the rest of the name after the last escape sequence from input buffer to * output buffer). * * Results: * TRUE if the input has been processed successfully by the callback, false otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsEscapeEnumerate(char const *bufIn, // IN: Buffer with unescaped input uint32 sizeIn, // IN: Number of input *characters* HgfsEnumCallback processEscape, // IN: Callack that is invoked every // time escaping is required void *context) // IN/OUT: Context for processEscape { /* First look for invalid characters in the input name. */ uint32 i, offset = 0; if (sizeIn == 0) { return TRUE; } ASSERT(processEscape); PROCESS_RESERVED_NAME(bufIn, sizeIn, processEscape, &offset, context); for (i = offset; i < sizeIn; i++) { if (strchr(HGFS_ILLEGAL_CHARS, bufIn[i]) != NULL) { if (!processEscape(bufIn, i, HGFS_ESCAPE_ILLEGAL_CHARACTER, context)) { return FALSE; } } else if (HgfsIsEscapeSequence(bufIn, i, sizeIn)) { if (!processEscape(bufIn, i, HGFS_ESCAPE_ESCAPE_SEQUENCE, context)) { return FALSE; } } } PROCESS_LAST_CHARACTER(bufIn, sizeIn, processEscape, context); if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_COMPLETE, context)) { return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsEscape_Do -- * * Escape any characters that are not legal in a windows filename. * Escape reserved file names that can't be used in Windows. * We also of course have to escape the escape character, which is "%", * when it is part of a character sequence that would require unescaping * * sizeBufOut must account for the NUL terminator. * * Results: * On success, the size (excluding the NUL terminator) of the * escaped, NUL terminated buffer. * On failure (bufOut not big enough to hold result), negative value. * * Side effects: * None * *----------------------------------------------------------------------------- */ int HgfsEscape_Do(char const *bufIn, // IN: Buffer with unescaped input uint32 sizeIn, // IN: Size of input buffer uint32 sizeBufOut, // IN: Size of output buffer char *bufOut) // OUT: Buffer for escaped output { const char *currentComponent = bufIn; uint32 sizeLeft = sizeBufOut; char *outPointer = bufOut; const char *end = bufIn + sizeIn; const char *next; ASSERT(sizeIn > 0); if (bufIn[sizeIn - 1] == '\0') { /* * In some cases a NUL terminated string is passed to HgfsEscape_Do * so it make sense to support such input even if CPName_GetComponent * does not. Detect this case and make the input compliant with * CPName_GetComponent by removing terminating NUL. */ end--; sizeIn--; } /* * Absolute symbolic link name starts with the '\0'. HgfsEscapeDo needs to work * with such names. Leading NULL symbols should be skipped here since * CPName_GetComponent does not support such names. */ while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) { currentComponent++; sizeLeft--; *outPointer++ = '\0'; } while (currentComponent - bufIn < sizeIn) { int escapedLength; int componentSize = CPName_GetComponent(currentComponent, end, &next); if (componentSize < 0) { return componentSize; } escapedLength = HgfsEscapeDoComponent(currentComponent, componentSize, sizeLeft, outPointer); if (escapedLength < 0) { return escapedLength; } currentComponent = next; sizeLeft -= escapedLength + 1; outPointer += escapedLength + 1; } return (int) (outPointer - bufOut) - 1; // Do not count the last NUL terminator } /* *----------------------------------------------------------------------------- * * HgfsEscape_GetSize -- * * Calculates required size in bytes for the buffer that is needed to hold escaped * cross platform path name. Returns 0 if no escaping is required. * * Results: * On success, the size (excluding the NUL terminator) of the * escaped, NUL terminated buffer. * Returns 0 if the name is a valid Windows file name. * Returns -1 if the name is not a valid file name. * * Side effects: * None * *----------------------------------------------------------------------------- */ int HgfsEscape_GetSize(char const *bufIn, // IN: Buffer with unescaped input uint32 sizeIn) // IN: Size of the input buffer { uint32 result = 0; const char *currentComponent = bufIn; const char *end = bufIn + sizeIn; const char *next; if (sizeIn == 0) { // No need to escape an empty name. return 0; } if (bufIn[sizeIn - 1] == '\0') { /* * In some cases, a NUL-terminated string is passed to HgfsEscape_GetSize, * so it makes sense to support such input even if CPName_GetComponent * does not. Detect this case and make the input compliant with * CPName_GetComponent by removing the terminating NUL. */ end--; sizeIn--; } /* Skip leading NULs to keep CPName_GetComponent happy. */ while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) { currentComponent++; } while (currentComponent - bufIn < sizeIn) { int componentSize = CPName_GetComponent(currentComponent, end, &next); if (componentSize < 0) { Log("%s: failed to calculate escaped name size - name is invalid\n", __FUNCTION__); return -1; } result += HgfsEscapeGetComponentSize(currentComponent, componentSize); currentComponent = next; } return (result == 0) ? 0 : result + sizeIn; } /* *----------------------------------------------------------------------------- * * HgfsEscape_Undo -- * * Unescape a buffer that was escaped using HgfsEscapeBuffer. * * The unescaping is done in place in the input buffer, and * can not fail. * * Results: * The size (excluding the NUL terminator) of the unescaped, NUL * terminated buffer. * * Side effects: * None * *----------------------------------------------------------------------------- */ uint32 HgfsEscape_Undo(char *bufIn, // IN: Characters to be unescaped uint32 sizeIn) // IN: Number of characters in bufIn { uint32 componentSize; uint32 unprocessedSize = sizeIn + 1; uint32 result = 0; char *currentComponent = bufIn; ASSERT(bufIn != NULL); while (currentComponent != NULL) { HgfsEscapeUndoComponent(currentComponent, &unprocessedSize); componentSize = strlen(currentComponent) + 1; // Unescaped size result += componentSize; if (unprocessedSize > 1) { currentComponent = currentComponent + componentSize; } else { currentComponent = NULL; } } return result - 1; } /* *----------------------------------------------------------------------------- * * HgfsEscapeUndoComponent -- * * Unescape a buffer that was escaped using HgfsEscapeBuffer. * * The unescaping is done in place in the input buffer, and * can not fail. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsEscapeUndoComponent(char *bufIn, // IN: Characters to be unescaped uint32 *unprocessedLength) // IN: Unprocessed characters // in the whole name { size_t sizeIn; char* curOutBuffer; char* escapePointer; ASSERT(bufIn != NULL); curOutBuffer = bufIn; sizeIn = strlen(curOutBuffer); escapePointer = strchr(curOutBuffer, HGFS_ESCAPE_CHAR); while (escapePointer != NULL) { size_t offset = escapePointer - bufIn; if (HgfsIsEscapeSequence(bufIn, offset, sizeIn)) { char* substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]); if (substitute != NULL) { bufIn[offset - 1] = HGFS_ILLEGAL_CHARS[substitute - HGFS_SUBSTITUTE_CHARS]; } else if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) { bufIn[offset - 1] = HGFS_ESCAPE_CHAR; } memmove(escapePointer, escapePointer + 1, (*unprocessedLength) - offset - 1); (*unprocessedLength)--; sizeIn--; if (sizeIn > 0) { escapePointer = strchr(escapePointer, HGFS_ESCAPE_CHAR); } else { escapePointer = NULL; } } else { escapePointer = strchr(escapePointer + 1, HGFS_ESCAPE_CHAR); } } ASSERT((*unprocessedLength) > sizeIn); (*unprocessedLength) -= sizeIn + 1; } /* *----------------------------------------------------------------------------- * * HgfsEscapeDoComponent -- * * Escape any characters that are not legal in a windows filename. * Escape reserved file names that can't be used in Windows. * We also of course have to escape the escape character, which is "%", * when it is part of a character sequence that would require unescaping * * sizeBufOut must account for the NUL terminator. * * Results: * On success, the size (excluding the NUL terminator) of the * escaped, NUL terminated buffer. * On failure (bufOut not big enough to hold result), negative value. * * Side effects: * None * *----------------------------------------------------------------------------- */ int HgfsEscapeDoComponent(char const *bufIn, // IN: Buffer with unescaped input uint32 sizeIn, // IN: Size of input buffer uint32 sizeBufOut, // IN: Size of output buffer char *bufOut) // OUT: Buffer for escaped output { HgfsEscapeContext conversionContext; conversionContext.processedOffset = 0; conversionContext.outputBufferLength = sizeBufOut / sizeof *bufOut; conversionContext.outputOffset = 0; conversionContext.outputBuffer = bufOut; if (!HgfsEscapeEnumerate(bufIn, sizeIn, HgfsAddEscapeCharacter, &conversionContext)) { return -1; } return conversionContext.outputOffset * sizeof *bufOut; } /* *----------------------------------------------------------------------------- * * HgfsEscapeGetComponentSize -- * * Calculates number of addtitional characters that are needed to escape * name for one NUL terminated component of the path. * * Results: * Number of additional escape characters needed to escape the name. * Returns 0 if no escaping is required. * * Side effects: * None * *----------------------------------------------------------------------------- */ int HgfsEscapeGetComponentSize(char const *bufIn, // IN: Buffer with unescaped input uint32 sizeIn) // IN: Size of the in input buffer { int result = 0; HgfsEscapeEnumerate(bufIn, sizeIn, HgfsCountEscapeChars, &result); return result; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfs/hgfsUtil.c000066400000000000000000000176461470176644300237650ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2016,2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfsUtil.c -- * * Utility routines used by both HGFS servers and clients, such as * conversion routines between Unix time and Windows NT time. * The former is in units of seconds since midnight 1/1/1970, while the * latter is in units of 100 nanoseconds since midnight 1/1/1601. */ /* * hgfsUtil.h must be included before vm_basic_asm.h, as hgfsUtil.h * includes kernel headers on Linux. That is, vmware.h must come after * hgfsUtil.h. */ #include "hgfsUtil.h" #include "vmware.h" #include "vm_basic_asm.h" #ifndef _WIN32 /* * NT time of the Unix epoch: * midnight January 1, 1970 UTC */ #define UNIX_EPOCH ((((uint64)369 * 365) + 89) * 24 * 3600 * 10000000) /* * NT time of the Unix 32 bit signed time_t wraparound: * 03:14:07 January 19, 2038 UTC */ #define UNIX_S32_MAX (UNIX_EPOCH + (uint64)0x80000000 * 10000000) /* *----------------------------------------------------------------------------- * * HgfsConvertToNtTime -- * * Convert from Unix time to Windows NT time. * * Results: * The time in Windows NT format. * * Side effects: * None * *----------------------------------------------------------------------------- */ uint64 HgfsConvertToNtTime(time_t unixTime, // IN: Time in Unix format (seconds) long nsec) // IN: nanoseconds { return (uint64)unixTime * 10000000 + nsec / 100 + UNIX_EPOCH; } /* *----------------------------------------------------------------------------- * * HgfsConvertFromNtTimeNsec -- * * Convert from Windows NT time to Unix time. If NT time is outside of * UNIX time range (1970-2038), returned time is nearest time valid in * UNIX. * * Results: * 0 on success * non-zero if NT time is outside of valid range for UNIX * * Side effects: * None * *----------------------------------------------------------------------------- */ int HgfsConvertFromNtTimeNsec(struct timespec *unixTime, // OUT: Time in UNIX format uint64 ntTime) // IN: Time in Windows NT format { ASSERT(unixTime); if (ntTime < UNIX_EPOCH) { unixTime->tv_sec = 0; unixTime->tv_nsec = 0; return -1; } #ifdef __i386__ if (sizeof unixTime->tv_sec == 4) { uint32 sec,nsec; /* Cap NT time values that are outside of Unix time's range */ if (ntTime >= UNIX_S32_MAX) { unixTime->tv_sec = 0x7FFFFFFF; unixTime->tv_nsec = 0; return 1; } Div643232(ntTime - UNIX_EPOCH, 10000000, &sec, &nsec); unixTime->tv_sec = sec; unixTime->tv_nsec = nsec * 100; return 0; } #endif unixTime->tv_sec = (ntTime - UNIX_EPOCH) / 10000000; unixTime->tv_nsec = ((ntTime - UNIX_EPOCH) % 10000000) * 100; return 0; } /* *----------------------------------------------------------------------------- * * HgfsConvertFromNtTime -- * * Convert from Windows NT time to Unix time. * * Results: * 0 on success * nonzero if time is not representable on UNIX * * Side effects: * None * *----------------------------------------------------------------------------- */ int HgfsConvertFromNtTime(time_t *unixTime, // OUT: Time in UNIX format uint64 ntTime) // IN: Time in Windows NT format { struct timespec tm; int ret; ret = HgfsConvertFromNtTimeNsec(&tm, ntTime); *unixTime = tm.tv_sec; return ret; } #endif /* !def(_WIN32) */ #undef UNIX_EPOCH #undef UNIX_S32_MAX /* *----------------------------------------------------------------------------- * * HgfsConvertFromInternalStatus -- * * This function converts between a platform-specific status code and a * cross-platform status code to be sent down the wire. * * Results: * Converted status code. * * Side effects: * None. * *----------------------------------------------------------------------------- */ #ifdef _WIN32 HgfsStatus HgfsConvertFromInternalStatus(HgfsInternalStatus status) // IN { switch(status) { case ERROR_SUCCESS: return HGFS_STATUS_SUCCESS; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: return HGFS_STATUS_NO_SUCH_FILE_OR_DIR; case ERROR_INVALID_HANDLE: return HGFS_STATUS_INVALID_HANDLE; case ERROR_ALREADY_EXISTS: case ERROR_FILE_EXISTS: return HGFS_STATUS_FILE_EXISTS; case ERROR_DIR_NOT_EMPTY: return HGFS_STATUS_DIR_NOT_EMPTY; case RPC_S_PROTOCOL_ERROR: return HGFS_STATUS_PROTOCOL_ERROR; case ERROR_ACCESS_DENIED: return HGFS_STATUS_ACCESS_DENIED; case ERROR_INVALID_NAME: return HGFS_STATUS_INVALID_NAME; case ERROR_SHARING_VIOLATION: return HGFS_STATUS_SHARING_VIOLATION; case ERROR_DISK_FULL: case ERROR_HANDLE_DISK_FULL: return HGFS_STATUS_NO_SPACE; case ERROR_NOT_SUPPORTED: return HGFS_STATUS_OPERATION_NOT_SUPPORTED; case ERROR_INVALID_PARAMETER: return HGFS_STATUS_INVALID_PARAMETER; case ERROR_NOT_SAME_DEVICE: return HGFS_STATUS_NOT_SAME_DEVICE; case ERROR_FILENAME_EXCED_RANGE: return HGFS_STATUS_NAME_TOO_LONG; case ERROR_CONNECTION_INVALID: // HGFS_ERROR_STALE_SESSION return HGFS_STATUS_STALE_SESSION; case ERROR_MAX_SESSIONS_REACHED: return HGFS_STATUS_TOO_MANY_SESSIONS; case ERROR_INTERNAL_ERROR: case HGFS_INTERNAL_STATUS_ERROR: default: return HGFS_STATUS_GENERIC_ERROR; } } #else /* Win32 */ HgfsStatus HgfsConvertFromInternalStatus(HgfsInternalStatus status) // IN { switch(status) { case 0: return HGFS_STATUS_SUCCESS; case ENOENT: return HGFS_STATUS_NO_SUCH_FILE_OR_DIR; case EBADF: return HGFS_STATUS_INVALID_HANDLE; case EPERM: return HGFS_STATUS_OPERATION_NOT_PERMITTED; case EISDIR: case EEXIST: return HGFS_STATUS_FILE_EXISTS; case ENOTDIR: return HGFS_STATUS_NOT_DIRECTORY; case ENOTEMPTY: return HGFS_STATUS_DIR_NOT_EMPTY; case EPROTO: return HGFS_STATUS_PROTOCOL_ERROR; case EACCES: return HGFS_STATUS_ACCESS_DENIED; case EINVAL: return HGFS_STATUS_INVALID_NAME; case ENOSPC: return HGFS_STATUS_NO_SPACE; case EOPNOTSUPP: return HGFS_STATUS_OPERATION_NOT_SUPPORTED; case ENAMETOOLONG: return HGFS_STATUS_NAME_TOO_LONG; case EPARAMETERNOTSUPPORTED: return HGFS_STATUS_INVALID_PARAMETER; case EXDEV: return HGFS_STATUS_NOT_SAME_DEVICE; case ENETRESET: // HGFS_ERROR_STALE_SESSION return HGFS_STATUS_STALE_SESSION; case ECONNREFUSED: return HGFS_STATUS_TOO_MANY_SESSIONS; case EINTERNAL: case HGFS_INTERNAL_STATUS_ERROR: default: return HGFS_STATUS_GENERIC_ERROR; } } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsBd/000077500000000000000000000000001470176644300222645ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsBd/Makefile.am000066400000000000000000000017311470176644300243220ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libHgfsBd.la libHgfsBd_la_SOURCES = libHgfsBd_la_SOURCES += hgfsBd.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsBd/hgfsBd.c000066400000000000000000000246201470176644300236310ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfsBd.c -- * * Backdoor calls used by hgfs pserver. [bac] */ #if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL) # include "kernelStubs.h" #else # include # include # include # include # include "str.h" // for Str_Strcpy # include "debug.h" #endif #include "vm_assert.h" #include "rpcout.h" #include "hgfs.h" // for common HGFS definitions #include "hgfsBd.h" /* *----------------------------------------------------------------------------- * * HgfsBdGetBufInt -- * * Allocates a buffer to send a hgfs request in. This can be either a * HGFS_PACKET_MAX or HGFS_LARGE_PACKET_MAX size buffer depending on the * external funciton called. * * Results: * Pointer to a buffer that has the correct backdoor command prefix for * sending hgfs requests over the backdoor. * NULL on failure (not enough memory). * * Side effects: * None. * *----------------------------------------------------------------------------- */ static char * HgfsBdGetBufInt(size_t bufSize) { /* * Allocate a buffer that is large enough for an HGFS packet and the * synchronous HGFS command, write the command, and return a pointer that * points into the buffer, after the command. */ size_t len = bufSize + HGFS_SYNC_REQREP_CLIENT_CMD_LEN; char *buf = (char*) calloc(sizeof(char), len); if (!buf) { Debug("HgfsBd_GetBuf: Failed to allocate a bd buffer\n"); return NULL; } Str_Strcpy(buf, HGFS_SYNC_REQREP_CLIENT_CMD, len); return buf + HGFS_SYNC_REQREP_CLIENT_CMD_LEN; } /* *----------------------------------------------------------------------------- * * HgfsBd_GetBuf -- * * Get a buffer of size HGFS_PACKET_MAX to send hgfs requests in. * * Results: * See HgfsBdGetBufInt. * * Side effects: * Allocates memory that must be freed with a call to HgfsBd_PutBuf. * *----------------------------------------------------------------------------- */ char * HgfsBd_GetBuf(void) { return HgfsBdGetBufInt(HGFS_PACKET_MAX); } /* *----------------------------------------------------------------------------- * * HgfsBd_GetLargeBuf -- * * Get a buffer of size HGFS_LARGE_PACKET_MAX to send hgfs requests in. * * Results: * See HgfsBdGetBufInt. * * Side effects: * Allocates memory that must be freed with a call to HgfsBd_PutBuf. * *----------------------------------------------------------------------------- */ char * HgfsBd_GetLargeBuf(void) { return HgfsBdGetBufInt(HgfsLargePacketMax(FALSE)); } /* *----------------------------------------------------------------------------- * * HgfsBd_PutBuf -- * * Release a buffer obtained with HgfsBd_GetBuf. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsBd_PutBuf(char *buf) // IN { ASSERT(buf); free(buf - HGFS_SYNC_REQREP_CLIENT_CMD_LEN); } /* *----------------------------------------------------------------------------- * * HgfsBd_GetChannel -- * * Allocate a new RpcOut channel, and try to open the connection. * * Results: * Pointer to the allocated, opened channel on success. * NULL on failure (not enough memory, or failed to open the connection). * * Side effects: * None * *----------------------------------------------------------------------------- */ RpcOut * HgfsBd_GetChannel(void) { RpcOut *out = RpcOut_Construct(); Bool status; if (!out) { Debug("HgfsBd_GetChannel: Failed to allocate an RpcOut\n"); return NULL; } status = RpcOut_start(out); if (status == FALSE) { RpcOut_Destruct(out); return NULL; } return out; } /* *----------------------------------------------------------------------------- * * HgfsBd_CloseChannel -- * * Close the channel and free the RpcOut object. * * Results: * TRUE if closing the channel succeeded, FALSE if it failed. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsBd_CloseChannel(RpcOut *out) // IN: Channel to close and free { Bool success; ASSERT(out); success = RpcOut_stop(out); if (success == TRUE) { RpcOut_Destruct(out); } return success; } /* *----------------------------------------------------------------------------- * * HgfsBd_Dispatch -- * * Get a reply to an hgfs request. We call RpcOut_Sent, which * returns a buffer with the reply in it, and we pass this back to * the caller. * * Results: * On success, returns zero. On failure, returns a negative error. * * Side effects: * None * *----------------------------------------------------------------------------- */ int HgfsBd_Dispatch(RpcOut *out, // IN: Channel to send on char *packetIn, // IN: Buf containing request packet size_t *packetSize, // IN/OUT: Size of packet in/out char const **packetOut) // OUT: Buf containing reply packet { Bool success; Bool rpcStatus; char const *reply; size_t replyLen; char *bdPacket = packetIn - HGFS_SYNC_REQREP_CLIENT_CMD_LEN; ASSERT(out); ASSERT(packetIn); ASSERT(packetSize); ASSERT(packetOut); memcpy(bdPacket, HGFS_SYNC_REQREP_CLIENT_CMD, HGFS_SYNC_REQREP_CLIENT_CMD_LEN); success = RpcOut_send(out, bdPacket, *packetSize + HGFS_CLIENT_CMD_LEN, &rpcStatus, &reply, &replyLen); if (!success || !rpcStatus) { Debug("HgfsBd_Dispatch: RpcOut_send returned failure\n"); return -1; } ASSERT(replyLen <= HgfsLargePacketMax(TRUE)); *packetOut = reply; *packetSize = replyLen; return 0; } /* *----------------------------------------------------------------------------- * * HgfsBd_Enabled -- * * Test to see if hgfs is enabled on the host. * * Results: * TRUE if hgfs is enabled. * FALSE if hgfs is disabled. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsBd_Enabled(RpcOut *out, // IN: RPCI Channel char *requestPacket) // IN: Buffer (obtained from HgfsBd_GetBuf) { char const *replyPacket; // Buffer returned by HgfsBd_Dispatch size_t replyLen; Bool success; Bool rpcStatus; /* * Send a bogus (empty) request to the VMX. If hgfs is disabled on * the host side then the request will fail (because the RPCI call * itself will fail). If hgfs is enabled, we will get a packet back * (it will be an error packet because our request was malformed, * but we just discard it anyway). */ success = RpcOut_send(out, requestPacket - HGFS_CLIENT_CMD_LEN, HGFS_CLIENT_CMD_LEN, &rpcStatus, &replyPacket, &replyLen); if (success && rpcStatus) { ASSERT(replyLen <= HgfsLargePacketMax(TRUE)); } return success && rpcStatus; } /* *----------------------------------------------------------------------------- * * HgfsBd_OpenBackdoor -- * * Check if the HGFS channel is open, and, if not, open it. This is a * one-stop convenience wrapper around HgfsBd_Enabled, HgfsBd_GetBuf, and * HgfsBd_GetChannel. * * Results: * TRUE if the backdoor is now open, regardless of its previous state. * FALSE if the backdoor could not be opened. * * Side effects: * May open a channel to the host. * *----------------------------------------------------------------------------- */ Bool HgfsBd_OpenBackdoor(RpcOut **out) // IN/OUT: RPCI Channel { char *packetBuffer = NULL; Bool success = FALSE; ASSERT(out); /* Short-circuit: backdoor is already open. */ if (*out != NULL) { return TRUE; } /* Open the channel. */ *out = HgfsBd_GetChannel(); if (*out == NULL) { return FALSE; } /* Allocate a buffer for use in pinging the HGFS server. */ packetBuffer = HgfsBd_GetBuf(); if (packetBuffer == NULL) { goto out; } /* Ping the HGFS server. */ if (!HgfsBd_Enabled(*out, packetBuffer)) { goto out; } success = TRUE; out: if (packetBuffer != NULL) { HgfsBd_PutBuf(packetBuffer); } if (!success && *out != NULL) { HgfsBd_CloseChannel(*out); *out = NULL; } return success; } /* *----------------------------------------------------------------------------- * * HgfsBd_CloseBackdoor -- * * Closes the backdoor channel, if it's open. * * Results: * TRUE if the channel is now closed, regardless of its previous state. * FALSE if we could not close the channel. * * Side effects: * May close the channel to the host. * *----------------------------------------------------------------------------- */ Bool HgfsBd_CloseBackdoor(RpcOut **out) // IN/OUT: RPCI Channel { Bool success = TRUE; ASSERT(out); if (*out != NULL) { if (!HgfsBd_CloseChannel(*out)) { success = FALSE; } *out = NULL; } return success; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsHelper/000077500000000000000000000000001470176644300231565ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsHelper/Makefile.am000066400000000000000000000017571470176644300252240ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2009-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libHgfsHelper.la libHgfsHelper_la_SOURCES = libHgfsHelper_la_SOURCES += hgfsHelperPosix.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsHelper/hgfsHelperPosix.c000066400000000000000000000053571470176644300264460ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsHelperPosix.c -- * * Provides a posix helper library for guest applications to access * the HGFS file system. * */ #if !defined __linux__ && !defined __FreeBSD__ && !defined sun && !defined __APPLE__ # error This file should not be compiled #endif #include "vmware.h" #include "debug.h" #include "hgfsHelper.h" #if defined __linux__ #define HGFSHLPR_DEFAULT_MOUNT_PATH "/mnt/hgfs" #elif defined sun #define HGFSHLPR_DEFAULT_MOUNT_PATH "/hgfs" #elif defined __APPLE__ #define HGFSHLPR_DEFAULT_MOUNT_PATH "/Volumes/VMware Shared Folders" #endif /* *----------------------------------------------------------------------------- * * HgfsHlpr_QuerySharesDefaultRootPath -- * * Queries the driver for its share's root paths. * Currently only one is expected to be supported * and returned, although later versions may not. * E.g. "/mnt/hgfs" is the root path to * the HGFS shares. * * Results: * TRUE always. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsHlpr_QuerySharesDefaultRootPath(char **hgfsRootPath) { #if defined __FreeBSD__ return FALSE; #else ASSERT(hgfsRootPath != NULL); *hgfsRootPath = Unicode_AllocWithUTF8(HGFSHLPR_DEFAULT_MOUNT_PATH); Debug("%s: HGFS shares root path name \"%s\"\n", __FUNCTION__, *hgfsRootPath); return TRUE; #endif } /* *----------------------------------------------------------------------------- * * HgfsHlpr_FreeSharesRootPath -- * * Frees the share's root paths previously returned * to the caller from the HgfsHlpr_QuerySharesRootPath. * * Results: * None. * * Side Effects: * None. * *----------------------------------------------------------------------------- */ void HgfsHlpr_FreeSharesRootPath(char *hgfsRootPath) { free(hgfsRootPath); } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/000077500000000000000000000000001470176644300232055ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/Makefile.am000066400000000000000000000027651470176644300252530ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016, 2020 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libHgfsServer.la libHgfsServer_la_SOURCES = libHgfsServer_la_SOURCES += hgfsCacheStub.c libHgfsServer_la_SOURCES += hgfsServer.c libHgfsServer_la_SOURCES += hgfsServerLinux.c libHgfsServer_la_SOURCES += hgfsServerPacketUtil.c libHgfsServer_la_SOURCES += hgfsDirNotifyStub.c libHgfsServer_la_SOURCES += hgfsServerParameters.c libHgfsServer_la_SOURCES += hgfsServerOplock.c libHgfsServer_la_SOURCES += hgfsServerOplockMonitor.c libHgfsServer_la_SOURCES += hgfsServerOplockLinux.c libHgfsServer_la_SOURCES += hgfsThreadpoolStub.c AM_CFLAGS = AM_CFLAGS += -DVMTOOLS_USE_GLIB AM_CFLAGS += @GLIB2_CPPFLAGS@ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsCache.h000066400000000000000000000032011470176644300252250ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsCache.h -- * * A customized LRU cache which is built by combining two data structures: * a doubly linked list and a hash table. */ #ifndef _HGFS_CACHE_H_ #define _HGFS_CACHE_H_ #include "dbllnklst.h" #include "userlock.h" typedef void(*HgfsCacheRemoveLRUCallback)(void *data); typedef struct HgfsCache { void *hashTable; DblLnkLst_Links links; MXUserExclLock *lock; HgfsCacheRemoveLRUCallback callback; } HgfsCache; HgfsCache *HgfsCache_Alloc(HgfsCacheRemoveLRUCallback callback); void HgfsCache_Destroy(HgfsCache *cache); void HgfsCache_Put(HgfsCache *cache, const char *key, void *data); Bool HgfsCache_Get(HgfsCache *cache, const char *key, void **data); Bool HgfsCache_Invalidate(HgfsCache *cache, const char *key); #endif // ifndef _HGFS_CACHE_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsCacheStub.c000066400000000000000000000062711470176644300260700ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsCacheStub.c -- * * This file contains the stub implementation for hgfs cache. */ #include "hgfsCache.h" #include "hgfsServerInt.h" /* *----------------------------------------------------------------------------- * * HgfsCache_Alloc -- * * Create a cache and the corresponding hash table/doubly linked list/lock. * * Results: * Always return NULL. * * Side effects: * None. * *----------------------------------------------------------------------------- */ HgfsCache * HgfsCache_Alloc(HgfsCacheRemoveLRUCallback callback) // IN { return NULL; } /* *----------------------------------------------------------------------------- * * HgfsCache_Destroy -- * * Destroy a cache and the corresponding hash table/doubly linked list/lock. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsCache_Destroy(HgfsCache *cache) // IN { } /* *----------------------------------------------------------------------------- * * HgfsCache_Put -- * * Put an entry into a cache. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsCache_Put(HgfsCache *cache, // IN const char *key, // IN void *data) // IN { } /* *----------------------------------------------------------------------------- * * HgfsCache_Get -- * * Get an entry in a cache. * * Results: * Always return FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsCache_Get(HgfsCache *cache, // IN const char *key, // IN void **data) // OUT { return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsCache_Invalidate -- * * Remove an entry from a cache. * * Results: * Always return FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsCache_Invalidate(HgfsCache *cache, // IN const char *key) // IN { return FALSE; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsDirNotify.h000066400000000000000000000067331470176644300261460ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _HGFS_DIRNOTIFY_H #define _HGFS_DIRNOTIFY_H /* * hgfsDirNotify.h -- * * Function definitions for directory change notification. */ #include "hgfsServer.h" // for HgfsSharedFolderHandle #include "hgfsProto.h" // for HgfsSubscriberHandle #include "hgfsUtil.h" // for HgfsInternalStatus struct HgfsSessionInfo; /* * Activate and deactivate reason. * Currently, there are two scenarios: * 1) HGFS server is check point synchronizing: the file system event * generation is deactivated at the start and activated at the end. * 2) The client has added the first subscriber or removed the last * subscriber. The file system event generation is activated on the * addition of the first subscriber and deactivated on removal of * the last one. * * Note, in case 1 above, if there are no subscribers even at the end * of the HGFS server check point syncing, the activation will not * activate the file system events. */ typedef enum { HGFS_NOTIFY_REASON_SERVER_SYNC, HGFS_NOTIFY_REASON_SUBSCRIBERS, } HgfsNotifyActivateReason; /* These are the callbacks that are implemented in hgfsServer.c */ typedef void (*HgfsNotifyEventReceiveCb)(HgfsSharedFolderHandle sharedFolder, HgfsSubscriberHandle subscriber, char *name, uint32 mask, struct HgfsSessionInfo *session); typedef struct HgfsServerNotifyCallbacks { HgfsNotifyEventReceiveCb eventReceive; } HgfsServerNotifyCallbacks; HgfsInternalStatus HgfsNotify_Init(const HgfsServerNotifyCallbacks *serverCbData); void HgfsNotify_Exit(void); void HgfsNotify_Deactivate(HgfsNotifyActivateReason mode, struct HgfsSessionInfo *session); void HgfsNotify_Activate(HgfsNotifyActivateReason mode, struct HgfsSessionInfo *session); HgfsSharedFolderHandle HgfsNotify_AddSharedFolder(const char *path, const char *shareName); HgfsSubscriberHandle HgfsNotify_AddSubscriber(HgfsSharedFolderHandle sharedFolder, const char *path, uint32 eventFilter, uint32 recursive, struct HgfsSessionInfo *session); Bool HgfsNotify_RemoveSharedFolder(HgfsSharedFolderHandle sharedFolder); Bool HgfsNotify_RemoveSubscriber(HgfsSubscriberHandle subscriber); void HgfsNotify_RemoveSessionSubscribers(struct HgfsSessionInfo *session); #endif // _HGFS_DIRNOTIFY_H open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsDirNotifyStub.c000066400000000000000000000137071470176644300267760ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsDirNotifyStub.c -- * * Stubs for directory notification support, used to build guest components. */ #include #include "vmware.h" #include "vm_basic_types.h" #include "hgfsProto.h" #include "hgfsServer.h" #include "hgfsUtil.h" #include "hgfsDirNotify.h" /* *----------------------------------------------------------------------------- * * HgfsNotify_Init -- * * Initialization for the notification component. * * Results: * Invalid value error. * * Side effects: * None. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsNotify_Init(const HgfsServerNotifyCallbacks *serverCbData) // IN: serverCbData unused { return HGFS_ERROR_NOT_SUPPORTED; } /* *----------------------------------------------------------------------------- * * HgfsNotify_Exit -- * * Exit for the notification component. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsNotify_Exit(void) { } /* *----------------------------------------------------------------------------- * * HgfsNotify_Activate -- * * Activates generating file system change notifications. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsNotify_Activate(HgfsNotifyActivateReason reason, // IN: reason struct HgfsSessionInfo *session) // IN: session { } /* *----------------------------------------------------------------------------- * * HgfsNotify_Deactivate -- * * Deactivates generating file system change notifications. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsNotify_Deactivate(HgfsNotifyActivateReason reason, // IN: reason struct HgfsSessionInfo *session) // IN: session { } /* *----------------------------------------------------------------------------- * * HgfsNotify_AddSharedFolder -- * * Allocates memory and initializes new shared folder structure. * * Results: * Opaque subscriber handle for the new subscriber or HGFS_INVALID_FOLDER_HANDLE * if adding shared folder fails. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsSharedFolderHandle HgfsNotify_AddSharedFolder(const char *path, // IN: path in the host const char *shareName) // IN: name of the shared folder { return HGFS_INVALID_FOLDER_HANDLE; } /* *----------------------------------------------------------------------------- * * HgfsNotify_AddSubscriber -- * * Allocates memory and initializes new subscriber structure. * Inserts allocated subscriber into corrspondent array. * * Results: * Opaque subscriber handle for the new subscriber or HGFS_INVALID_SUBSCRIBER_HANDLE * if adding subscriber fails. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsSubscriberHandle HgfsNotify_AddSubscriber(HgfsSharedFolderHandle sharedFolder, // IN: shared folder handle const char *path, // IN: relative path uint32 eventFilter, // IN: event filter uint32 recursive, // IN: look in subfolders struct HgfsSessionInfo *session) // IN: server context { return HGFS_INVALID_SUBSCRIBER_HANDLE; } /* *----------------------------------------------------------------------------- * * HgfsNotify_RemoveSharedFolder -- * * Deallcates memory used by shared folder and performs necessary cleanup. * Also deletes all subscribers that are defined for the shared folder. * * Results: * FALSE. * * Side effects: * Removes all subscribers that correspond to the shared folder and invalidates * thier handles. * *----------------------------------------------------------------------------- */ Bool HgfsNotify_RemoveSharedFolder(HgfsSharedFolderHandle sharedFolder) // IN { return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsNotify_RemoveSubscriber -- * * Deallcates memory used by NotificationSubscriber and performs necessary cleanup. * * Results: * FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsNotify_RemoveSubscriber(HgfsSubscriberHandle subscriber) // IN { return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsNotify_RemoveSessionSubscribers -- * * Removes all entries that are related to a particular session. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsNotify_RemoveSessionSubscribers(struct HgfsSessionInfo *session) // IN { } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServer.c000066400000000000000000011327331470176644300255010ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #if defined(__APPLE__) /* * DirectoryEntry type that is used in common code is * defined as dirent for Mac OS. * _DARWIN_USE_64_BIT_INODE definition is needed to make dirent * structure definitions in this file and in HgfsServerLinux.c * consistent. */ #define _DARWIN_USE_64_BIT_INODE #endif #include #include #include "vmware.h" #include "str.h" #include "cpName.h" #include "cpNameLite.h" #include "hashTable.h" #include "hgfsServerInt.h" #include "hgfsServerPolicy.h" #include "hgfsUtil.h" #include "hgfsVirtualDir.h" #include "codeset.h" #include "dbllnklst.h" #include "file.h" #include "util.h" #include "wiper.h" #include "hgfsServer.h" #include "hgfsServerParameters.h" #include "hgfsServerOplock.h" #include "hgfsServerOplockMonitor.h" #include "hgfsDirNotify.h" #include "hgfsThreadpool.h" #include "userlock.h" #include "poll.h" #include "mutexRankLib.h" #include "vm_basic_asm.h" #include "unicodeOperations.h" #ifndef VM_X86_ANY #include "random.h" #endif #if defined(_WIN32) #include #define HGFS_PARENT_DIR "..\\" #else #include #define stricmp strcasecmp #define HGFS_PARENT_DIR "../" #endif // _WIN32 #define HGFS_PARENT_DIR_LEN 3 /* * Define this to enable an ASSERT on HGFS_STATUS_PROTOCOL_ERROR. * This is useful if client is to be guaranteed to work with the server * without falling back to older protocol versions and to ensure that * clients don't send op value greater than HGFS_OP_MAX. * * NOTE: This flag is only meant to be used while testing. This should * _always_ be undefined when checking code in. */ #if 0 #define HGFS_ASSERT_CLIENT(op) \ do { \ LOG(4, "%s: op: %u.\n", __FUNCTION__, op); \ ASSERT(status != HGFS_STATUS_PROTOCOL_ERROR); \ } while(0) #else #define HGFS_ASSERT_CLIENT(op) #endif #define HGFS_ASSERT_INPUT(input) \ ASSERT(input && input->packet && input->request && \ ((!input->sessionEnabled && input->session) || \ (input->sessionEnabled && \ (input->op == HGFS_OP_CREATE_SESSION_V4 || input->session))) && \ (!input->payloadSize || input->payload)) /* * Define this to enable an ASSERT if server gets an op lower than * this value. This is useful if client is to be guaranteed to work with * the server without falling back to older protocol versions. * * NOTE: This flag is only meant to be used while testing. This should * _always_ be undefined when checking code in. */ #if 0 #define HGFS_ASSERT_MINIMUM_OP(op) \ do { \ LOG(4, "%s: op received - %u.\n", __FUNCTION__, op); \ ASSERT(op >= HGFS_OP_OPEN_V3); \ } while(0) #else #define HGFS_ASSERT_MINIMUM_OP(op) #endif /* * This ensures that the hgfs name conversion code never fails on long * filenames by using a buffer that is too small. If anything, we will * fail first elsewhere because the name is too big to fit in one hgfs * packet. [bac] */ #define HGFS_PATH_MAX HGFS_PACKET_MAX /* * Array of FileNodes for opening files. */ #define NUM_FILE_NODES 100 #define NUM_SEARCHES 100 /* Default maximun number of open nodes that have server locks. */ #define MAX_LOCKED_FILENODES 10 struct HgfsTransportSessionInfo { /* Default session id. */ uint64 defaultSessionId; /* Lock to manipulate the list of sessions */ MXUserExclLock *sessionArrayLock; /* List of sessions */ DblLnkLst_Links sessionArray; /* Max packet size that is supported by both client and server. */ uint32 maxPacketSize; /* Total number of sessions present this transport session*/ uint32 numSessions; /* Transport session context. */ void *transportData; /* Current state of the session. */ HgfsSessionInfoState state; /* Session is dynamic or internal. */ HgfsSessionInfoType type; /* Function callbacks into Hgfs Channels. */ HgfsServerChannelCallbacks *channelCbTable; Atomic_uint32 refCount; /* Reference count for session. */ HgfsServerChannelData channelCapabilities; }; /* The input request parameters object. */ typedef struct HgfsInputParam { const void *request; /* Hgfs header followed by operation request */ size_t requestSize; /* Size of Hgfs header and operation request */ HgfsSessionInfo *session; /* Hgfs session data */ HgfsTransportSessionInfo *transportSession; HgfsPacket *packet; /* Public (server/transport) Hgfs packet */ const void *payload; /* Hgfs operation request */ uint32 payloadOffset; /* Offset to start of Hgfs operation request */ size_t payloadSize; /* Hgfs operation request size */ HgfsOp op; /* Hgfs operation command code */ uint32 id; /* Request ID to be matched with the reply */ Bool sessionEnabled; /* Requests have session enabled headers */ } HgfsInputParam; /* * The HGFS server configurable settings. * (Note: the guest sets these to all defaults only modifiable from the VMX.) */ static HgfsServerConfig gHgfsCfgSettings = { (HGFS_CONFIG_NOTIFY_ENABLED | HGFS_CONFIG_VOL_INFO_MIN), HGFS_MAX_CACHED_FILENODES }; /* * Monotonically increasing handle counter used to dish out HgfsHandles. * This value is checkpointed. */ static Atomic_uint32 hgfsHandleCounter = {0}; static HgfsServerMgrCallbacks *gHgfsMgrData = NULL; /* * Session usage and locking. * * The channel will serialize callbacks to connect, disconnect, close * and invalidate objects for sessions. * The receives will also be serialized with the above when received through * the backdoor channel. * However, when requests are received from a socket, they will be from a * worker thread. It is the responsibility of the socket channel to keep * the session alive when processing the receive request which it does by * an additional reference for the session. This means even if a disconnect * occurs and the socket is closed, the channel will not call the session * close until the hgfs server returns from the receive processing. Thus * the hgfs server session data will remain valid. * When the hgfs server processes requests asynchronously, or returns from * receive request prior to sending the reply to be done at a later time, * a reference on the session is taken out while processing the message, * and not removed until the reply is processed. This reference will ensure * the session is not torndown until the final reference is removed, even * if the close session is called from the channel. */ /* Session related callbacks. */ static void HgfsServerSessionReceive(HgfsPacket *packet, void *clientData); static Bool HgfsServerSessionConnect(void *transportData, HgfsServerChannelCallbacks *channelCbTable, HgfsServerChannelData *channelCapabililies, void **clientData); static void HgfsServerSessionDisconnect(void *clientData); static void HgfsServerSessionClose(void *clientData); static void HgfsServerSessionInvalidateObjects(void *clientData, DblLnkLst_Links *shares); static uint32 HgfsServerSessionInvalidateInactiveSessions(void *clientData); static void HgfsServerSessionSendComplete(HgfsPacket *packet, void *clientData); static void HgfsServerSessionQuiesce(void * clientData, HgfsQuiesceOp quiesceOp); /* * Callback table passed to transport and any channels. */ static const HgfsServerCallbacks gHgfsServerCBTable = { { HgfsServerSessionConnect, HgfsServerSessionDisconnect, HgfsServerSessionClose, HgfsServerSessionReceive, HgfsServerSessionInvalidateObjects, HgfsServerSessionInvalidateInactiveSessions, HgfsServerSessionSendComplete, HgfsServerSessionQuiesce, }, }; static void HgfsServerNotifyReceiveEventCb(HgfsSharedFolderHandle sharedFolder, HgfsSubscriberHandle subscriber, char* fileName, uint32 mask, struct HgfsSessionInfo *session); /* * Callback table passed to the directory change notification component. */ static const HgfsServerNotifyCallbacks gHgfsServerNotifyCBTable = { HgfsServerNotifyReceiveEventCb, }; /* Lock that protects shared folders list. */ static MXUserExclLock *gHgfsSharedFoldersLock = NULL; /* List of shared folders nodes. */ static DblLnkLst_Links gHgfsSharedFoldersList; /* * Number of active sessions that support change directory notification. HGFS server * needs to maintain up-to-date shared folders list when there is * at least one such session. */ static Bool gHgfsDirNotifyActive = FALSE; /* * Indicates if the threadpool is active. If so then all the asynchronous IO will be * handled by worker thread in threadpool. If threadpool is not active, all the * asynchronous IO will be handled by poll. */ static Bool gHgfsThreadpoolActive = FALSE; typedef struct HgfsSharedFolderProperties { DblLnkLst_Links links; char *name; /* Name of the share. */ HgfsSharedFolderHandle notificationHandle; /* Directory notification handle. */ } HgfsSharedFolderProperties; /* Allocate/Add sessions helper functions. */ #ifndef VMX86_TOOLS static void HgfsServerAsyncInfoIncCount(HgfsAsyncRequestInfo *info); #endif static Bool HgfsServerAllocateSession(HgfsTransportSessionInfo *transportSession, HgfsCreateSessionInfo createSessionInfo, HgfsSessionInfo **sessionData); static HgfsInternalStatus HgfsServerTransportAddSessionToList(HgfsTransportSessionInfo *transportSession, HgfsSessionInfo *sessionInfo); static void HgfsServerTransportRemoveSessionFromList(HgfsTransportSessionInfo *transportSession, HgfsSessionInfo *sessionInfo); static HgfsSessionInfo * HgfsServerTransportGetSessionInfo(HgfsTransportSessionInfo *transportSession, uint64 sessionId); static HgfsTransportSessionInfo * HgfsServerTransportInit(void *transportData, HgfsServerChannelCallbacks *channelCbTable, HgfsServerChannelData *channelCapabilities); static void HgfsServerTransportExit(HgfsTransportSessionInfo *transportSession); /* Local functions. */ static void HgfsInvalidateSessionObjects(DblLnkLst_Links *shares, HgfsSessionInfo *session); static Bool HgfsAddToCacheInternal(HgfsHandle handle, HgfsSessionInfo *session); static Bool HgfsIsCachedInternal(HgfsHandle handle, HgfsSessionInfo *session); static Bool HgfsRemoveLruNode(HgfsSessionInfo *session); static Bool HgfsRemoveFromCacheInternal(HgfsHandle handle, HgfsSessionInfo *session); static void HgfsRemoveSearchInternal(HgfsSearch *search, HgfsSessionInfo *session); static HgfsSearch *HgfsSearchHandle2Search(HgfsHandle handle, HgfsSessionInfo *session); static HgfsHandle HgfsSearch2SearchHandle(HgfsSearch const *search); static HgfsSearch *HgfsAddNewSearch(char const *utf8Dir, DirectorySearchType type, char const *utf8ShareName, char const *rootDir, HgfsSessionInfo *session); static void HgfsDumpAllSearches(HgfsSessionInfo *session); static void HgfsDumpAllNodes(HgfsSessionInfo *session); static void HgfsFreeFileNode(HgfsHandle handle, HgfsSessionInfo *session); static void HgfsFreeFileNodeInternal(HgfsHandle handle, HgfsSessionInfo *session); static HgfsFileNode *HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, HgfsLocalId const *localId, fileDesc fileDesc, Bool append, size_t shareNameLen, char const *shareName, Bool sharedFolderOpen, HgfsSessionInfo *session); static void HgfsRemoveFileNode(HgfsFileNode *node, HgfsSessionInfo *session); static HgfsFileNode *HgfsGetNewNode(HgfsSessionInfo *session); static HgfsHandle HgfsFileNode2Handle(HgfsFileNode const *fileNode); static HgfsFileNode *HgfsHandle2FileNode(HgfsHandle handle, HgfsSessionInfo *session); static void HgfsServerExitSessionInternal(HgfsSessionInfo *session); static void HgfsServerCompleteRequest(HgfsInternalStatus status, size_t replyPayloadSize, HgfsInputParam *input); static Bool HgfsHandle2NotifyInfo(HgfsHandle handle, HgfsSessionInfo *session, char **fileName, size_t *fileNameSize, HgfsSharedFolderHandle *folderHandle); static void HgfsFreeSearchDirents(HgfsSearch *search); static HgfsInternalStatus HgfsServerTransportGetDefaultSession(HgfsTransportSessionInfo *transportSession, HgfsSessionInfo **session); static Bool HgfsPacketSend(HgfsPacket *packet, HgfsTransportSessionInfo *transportSession, HgfsSessionInfo *session, HgfsSendFlags flags); static void HgfsCacheRemoveLRUCb(void *data); /* * Opcode handlers */ static void HgfsServerOpen(HgfsInputParam *input); static void HgfsServerRead(HgfsInputParam *input); static void HgfsServerWrite(HgfsInputParam *input); static void HgfsServerSearchOpen(HgfsInputParam *input); static void HgfsServerSearchRead(HgfsInputParam *input); static void HgfsServerGetattr(HgfsInputParam *input); static void HgfsServerSetattr(HgfsInputParam *input); static void HgfsServerCreateDir(HgfsInputParam *input); static void HgfsServerDeleteFile(HgfsInputParam *input); static void HgfsServerDeleteDir(HgfsInputParam *input); static void HgfsServerRename(HgfsInputParam *input); static void HgfsServerQueryVolume(HgfsInputParam *input); static void HgfsServerSymlinkCreate(HgfsInputParam *input); static void HgfsServerServerLockChange(HgfsInputParam *input); static void HgfsServerWriteWin32Stream(HgfsInputParam *input); static void HgfsServerCreateSession(HgfsInputParam *input); static void HgfsServerDestroySession(HgfsInputParam *input); static void HgfsServerClose(HgfsInputParam *input); static void HgfsServerSearchClose(HgfsInputParam *input); static void HgfsServerSetDirNotifyWatch(HgfsInputParam *input); static void HgfsServerRemoveDirNotifyWatch(HgfsInputParam *input); /* *---------------------------------------------------------------------------- * * HgfsServerSessionGet -- * * Increment session reference count. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsServerSessionGet(HgfsSessionInfo *session) // IN: session context { ASSERT(session && Atomic_Read(&session->refCount) != 0); Atomic_Inc(&session->refCount); } /* *---------------------------------------------------------------------------- * * HgfsServerSessionPut -- * * Decrement session reference count. * * Free session info data if no reference. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsServerSessionPut(HgfsSessionInfo *session) // IN: session context { ASSERT(session); if (Atomic_ReadDec32(&session->refCount) == 1) { HgfsServerExitSessionInternal(session); } } /* *---------------------------------------------------------------------------- * * HgfsServerTransportSessionGet -- * * Increment transport session reference count. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ void HgfsServerTransportSessionGet(HgfsTransportSessionInfo *transportSession) // IN: session context { ASSERT(transportSession); Atomic_Inc(&transportSession->refCount); } /* *---------------------------------------------------------------------------- * * HgfsServerTransportSessionPut -- * * Decrement transport session reference count. * * Free session info data if no reference. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsServerTransportSessionPut(HgfsTransportSessionInfo *transportSession) // IN: transport session context { ASSERT(transportSession); if (Atomic_ReadDec32(&transportSession->refCount) == 1) { HgfsServerTransportExit(transportSession); } } /* *----------------------------------------------------------------------------- * * HgfsServerInitHandleCounter -- * * Initialize the file handle counter to the new value passed. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerInitHandleCounter(uint32 newHandleCounter) { Atomic_Write(&hgfsHandleCounter, newHandleCounter); } /* *----------------------------------------------------------------------------- * * HgfsServerGetHandleCounter -- * * Return file handle counter. This is used by the checkpointing code to * checkpoint this value so we avoid the risk of handle collision. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static uint32 HgfsServerGetHandleCounter(void) { return Atomic_Read(&hgfsHandleCounter); } /* *----------------------------------------------------------------------------- * * HgfsServerGetNextHandleCounter -- * * Return file handle counter. This is used by the checkpointing code to * checkpoint this value so we avoid the risk of handle collision. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static uint32 HgfsServerGetNextHandleCounter(void) { return Atomic_ReadInc32(&hgfsHandleCounter); } /* *----------------------------------------------------------------------------- * * HgfsHandle2FileNode -- * * Retrieve the file node a handle refers to. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * The file node if the handle is valid (i.e. it refers to an existing file * node that is currently in use). * NULL if the handle is invalid. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static HgfsFileNode * HgfsHandle2FileNode(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session) // IN: Session info { unsigned int i; HgfsFileNode *fileNode = NULL; ASSERT(session); ASSERT(session->nodeArray); /* XXX: This O(n) lookup can and should be optimized. */ for (i = 0; i < session->numNodes; i++) { if (session->nodeArray[i].state != FILENODE_STATE_UNUSED && session->nodeArray[i].handle == handle) { fileNode = &session->nodeArray[i]; break; } } return fileNode; } /* *----------------------------------------------------------------------------- * * HgfsFileNode2Handle -- * * Retrieve the handle that represents a file node outside of the server. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * The handle * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsHandle HgfsFileNode2Handle(HgfsFileNode const *fileNode) // IN { ASSERT(fileNode); return fileNode->handle; } /* *----------------------------------------------------------------------------- * * HgfsDumpAllNodes -- * * Debugging routine; print all nodes in the nodeArray. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsDumpAllNodes(HgfsSessionInfo *session) // IN: session info { unsigned int i; ASSERT(session); ASSERT(session->nodeArray); Log("Dumping all nodes\n"); for (i = 0; i < session->numNodes; i++) { Log("handle %u, name \"%s\", localdev %"FMT64"u, localInum %"FMT64"u %u\n", session->nodeArray[i].handle, session->nodeArray[i].utf8Name ? session->nodeArray[i].utf8Name : "NULL", session->nodeArray[i].localId.volumeId, session->nodeArray[i].localId.fileId, session->nodeArray[i].fileDesc); } Log("Done\n"); } /* *----------------------------------------------------------------------------- * * HgfsHandle2FileDesc -- * * Retrieve the file descriptor (host OS file handle) based on the hgfs * handle. * * Results: * TRUE if the handle is valid and the file desc was retrieved successfully. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsHandle2FileDesc(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info fileDesc *fd, // OUT: OS handle (file descriptor) void **fileCtx) // OUT: OS file context { Bool found = FALSE; HgfsFileNode *fileNode = NULL; MXUser_AcquireExclLock(session->nodeArrayLock); fileNode = HgfsHandle2FileNode(handle, session); if (fileNode == NULL) { goto exit; } *fd = fileNode->fileDesc; if (fileCtx) { *fileCtx = fileNode->fileCtx; } found = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return found; } /* *----------------------------------------------------------------------------- * * HgfsHandle2AppendFlag -- * * Retrieve the append flag for the file node that corresponds to * the specified hgfs handle. * * Results: * TRUE if the handle is valid and append flag was retrieved successfully. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsHandle2AppendFlag(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info Bool *appendFlag) // OUT: append flag { Bool found = FALSE; HgfsFileNode *fileNode = NULL; MXUser_AcquireExclLock(session->nodeArrayLock); fileNode = HgfsHandle2FileNode(handle, session); if (fileNode == NULL) { goto exit; } *appendFlag = fileNode->flags & HGFS_FILE_NODE_APPEND_FL; found = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return found; } /* *----------------------------------------------------------------------------- * * HgfsHandle2LocalId -- * * Retrieve the local id for the file node that corresponds to * the specified hgfs handle. * * Results: * TRUE if the hgfs handle is valid and local id was retrieved successfully. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsHandle2LocalId(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info HgfsLocalId *localId) // OUT: local id info { Bool found = FALSE; HgfsFileNode *fileNode = NULL; ASSERT(localId); MXUser_AcquireExclLock(session->nodeArrayLock); fileNode = HgfsHandle2FileNode(handle, session); if (fileNode == NULL) { goto exit; } localId->volumeId = fileNode->localId.volumeId; localId->fileId = fileNode->localId.fileId; found = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return found; } /* *----------------------------------------------------------------------------- * * HgfsFileDesc2Handle -- * * Given an OS handle/fd, return file's hgfs handle. * * Results: * TRUE if the node was found. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsFileDesc2Handle(fileDesc fd, // IN: OS handle (file descriptor) HgfsSessionInfo *session, // IN: Session info HgfsHandle *handle) // OUT: Hgfs file handle { unsigned int i; Bool found = FALSE; HgfsFileNode *existingFileNode = NULL; ASSERT(session); ASSERT(session->nodeArray); MXUser_AcquireExclLock(session->nodeArrayLock); for (i = 0; i < session->numNodes; i++) { existingFileNode = &session->nodeArray[i]; if ((existingFileNode->state == FILENODE_STATE_IN_USE_CACHED) && (existingFileNode->fileDesc == fd)) { *handle = HgfsFileNode2Handle(existingFileNode); found = TRUE; break; } } MXUser_ReleaseExclLock(session->nodeArrayLock); return found; } /* *----------------------------------------------------------------------------- * * HgfsHandle2ShareMode -- * * Given an OS handle/fd, return the share access mode. * * Results: * TRUE if the node was found. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsHandle2ShareMode(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info HgfsOpenMode *shareMode) // OUT:share access mode { Bool found = FALSE; HgfsFileNode *existingFileNode = NULL; HgfsNameStatus nameStatus; if (shareMode == NULL) { return found; } MXUser_AcquireExclLock(session->nodeArrayLock); existingFileNode = HgfsHandle2FileNode(handle, session); if (existingFileNode == NULL) { goto exit_unlock; } nameStatus = HgfsServerPolicy_GetShareMode(existingFileNode->shareName, existingFileNode->shareNameLen, shareMode); found = (nameStatus == HGFS_NAME_STATUS_COMPLETE); exit_unlock: MXUser_ReleaseExclLock(session->nodeArrayLock); return found; } /* *----------------------------------------------------------------------------- * * HgfsHandle2FileName -- * * Given an OS handle/fd, return file's hgfs name. * * Results: * TRUE if the node was found. * FALSE otherwise. * * Side effects: * Allocates memory and makes a copy of the file name. * *----------------------------------------------------------------------------- */ Bool HgfsHandle2FileName(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session,// IN: Session info char **fileName, // OUT: UTF8 file name size_t *fileNameSize) // OUT: UTF8 file name size { Bool unused1, unused2; return HgfsHandle2FileNameMode(handle, session, &unused1, &unused2, fileName, fileNameSize); } /* *----------------------------------------------------------------------------- * * HgfsHandle2FileNameMode -- * * Given an OS handle/fd, return file's hgfs name and permissions * associated with the corresponding shared folder. * * Results: * TRUE if the node was found. * FALSE otherwise. * * Side effects: * Allocates memory and makes a copy of the file name. * *----------------------------------------------------------------------------- */ Bool HgfsHandle2FileNameMode(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session,// IN: Session info Bool *readPermissions, // OUT: shared folder permissions Bool *writePermissions, // OUT: shared folder permissions char **fileName, // OUT: UTF8 file name size_t *fileNameSize) // OUT: UTF8 file name size { Bool found = FALSE; HgfsFileNode *existingFileNode = NULL; char *name = NULL; size_t nameSize = 0; if ((fileName == NULL) || (fileNameSize == NULL)) { return found; } MXUser_AcquireExclLock(session->nodeArrayLock); existingFileNode = HgfsHandle2FileNode(handle, session); if (existingFileNode == NULL) { goto exit_unlock; } name = malloc(existingFileNode->utf8NameLen + 1); if (name == NULL) { goto exit_unlock; } *readPermissions = existingFileNode->shareInfo.readPermissions; *writePermissions = existingFileNode->shareInfo.writePermissions; nameSize = existingFileNode->utf8NameLen; memcpy(name, existingFileNode->utf8Name, nameSize); name[nameSize] = '\0'; found = TRUE; exit_unlock: MXUser_ReleaseExclLock(session->nodeArrayLock); *fileName = name; *fileNameSize = nameSize; return found; } /* *----------------------------------------------------------------------------- * * HgfsHandle2FileNameMode -- * * Given an OS handle/fd, return information needed for directory * notification package: relative to the root share file name and * shared folder notification handle. * * Results: * TRUE if the node was found. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsHandle2NotifyInfo(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info char **fileName, // OUT: UTF8 file name size_t *fileNameSize, // OUT: UTF8 file name size HgfsSharedFolderHandle *folderHandle) // OUT: shared folder handle { Bool found = FALSE; HgfsFileNode *existingFileNode; char *name; size_t nameSize; ASSERT(fileName != NULL && fileNameSize != NULL); MXUser_AcquireExclLock(session->nodeArrayLock); existingFileNode = HgfsHandle2FileNode(handle, session); if (NULL != existingFileNode) { nameSize = existingFileNode->utf8NameLen - existingFileNode->shareInfo.rootDirLen; name = Util_SafeMalloc(nameSize + 1); *folderHandle = existingFileNode->shareInfo.handle; memcpy(name, existingFileNode->utf8Name, nameSize); name[nameSize] = '\0'; *fileName = name; *fileNameSize = nameSize; found = TRUE; } MXUser_ReleaseExclLock(session->nodeArrayLock); return found; } /* *----------------------------------------------------------------------------- * * HgfsGetNodeCopy -- * * Make a copy of the node. The node should not be kept around for long, as * the data might become stale. This is mostly a convenience function to get * node fields more efficiently. * * Results: * TRUE if the hgfs handle is valid and the copy was successful. * FALSE otherwise. * * Side effects: * Allocates memory for node.utf8Name if copyName was set to TRUE. * *----------------------------------------------------------------------------- */ Bool HgfsGetNodeCopy(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info Bool copyName, // IN: Should we copy the name? HgfsFileNode *copy) // IN/OUT: Copy of the node { HgfsFileNode *original = NULL; Bool found = FALSE; ASSERT(copy); MXUser_AcquireExclLock(session->nodeArrayLock); original = HgfsHandle2FileNode(handle, session); if (original == NULL) { goto exit; } if (copyName) { copy->utf8Name = malloc(original->utf8NameLen + 1); if (copy->utf8Name == NULL) { goto exit; } copy->utf8NameLen = original->utf8NameLen; memcpy(copy->utf8Name, original->utf8Name, copy->utf8NameLen); copy->utf8Name[copy->utf8NameLen] = '\0'; } else { copy->utf8Name = NULL; copy->utf8NameLen = 0; } copy->localId = original->localId; copy->fileDesc = original->fileDesc; copy->mode = original->mode; copy->shareAccess = original->shareAccess; copy->flags = original->flags; copy->state = original->state; copy->handle = original->handle; copy->fileCtx = original->fileCtx; found = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return found; } /* *---------------------------------------------------------------------------- * * HgfsHandleIsSequentialOpen -- * * Get the Hgfs open mode this handle was originally opened with. * * Results: * TRUE on success, FALSE on failure. sequentialOpen is filled in on * success. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool HgfsHandleIsSequentialOpen(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info Bool *sequentialOpen) // OUT: If open was sequential { HgfsFileNode *node; Bool success = FALSE; ASSERT(sequentialOpen); MXUser_AcquireExclLock(session->nodeArrayLock); node = HgfsHandle2FileNode(handle, session); if (node == NULL) { goto exit; } *sequentialOpen = node->flags & HGFS_FILE_NODE_SEQUENTIAL_FL; success = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return success; } /* *---------------------------------------------------------------------------- * * HgfsHandleIsSharedFolderOpen -- * * Find if this is a shared folder open. * * Results: * TRUE on success, FALSE on failure. sharedFolderOpen is filled in on * success. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool HgfsHandleIsSharedFolderOpen(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info Bool *sharedFolderOpen) // OUT: If shared folder { HgfsFileNode *node; Bool success = FALSE; ASSERT(sharedFolderOpen); MXUser_AcquireExclLock(session->nodeArrayLock); node = HgfsHandle2FileNode(handle, session); if (node == NULL) { goto exit; } *sharedFolderOpen = node->flags & HGFS_FILE_NODE_SHARED_FOLDER_OPEN_FL; success = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return success; } /* *----------------------------------------------------------------------------- * * HgfsUpdateNodeFileDesc -- * * Given a hgfs file handle, update the node with the new file desc (OS * handle) information. * * Results: * TRUE if the update is successful. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsUpdateNodeFileDesc(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info fileDesc fd, // IN: OS handle (file desc) void *fileCtx) // IN: OS file context { HgfsFileNode *node; Bool updated = FALSE; MXUser_AcquireExclLock(session->nodeArrayLock); node = HgfsHandle2FileNode(handle, session); if (node == NULL) { goto exit; } node->fileDesc = fd; node->fileCtx = fileCtx; updated = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return updated; } /* *----------------------------------------------------------------------------- * * HgfsUpdateNodeServerLock -- * * Given a file desc (OS handle), update the node with the new oplock * information. * * Results: * TRUE if the update is successful. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsUpdateNodeServerLock(fileDesc fd, // IN: OS handle HgfsSessionInfo *session, // IN: Session info HgfsLockType serverLock) // IN: new oplock { unsigned int i; HgfsFileNode *existingFileNode = NULL; Bool updated = FALSE; ASSERT(session); ASSERT(session->nodeArray); MXUser_AcquireExclLock(session->nodeArrayLock); for (i = 0; i < session->numNodes; i++) { existingFileNode = &session->nodeArray[i]; if (existingFileNode->state != FILENODE_STATE_UNUSED) { if (existingFileNode->fileDesc == fd) { existingFileNode->serverLock = serverLock; updated = TRUE; break; } } } MXUser_ReleaseExclLock(session->nodeArrayLock); return updated; } /* *----------------------------------------------------------------------------- * * HgfsUpdateNodeAppendFlag -- * * Given a hgfs file handle, update the node with the append flag info. * * Results: * TRUE if the update is successful. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsUpdateNodeAppendFlag(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info Bool appendFlag) // OUT: Append flag { HgfsFileNode *node; Bool updated = FALSE; MXUser_AcquireExclLock(session->nodeArrayLock); node = HgfsHandle2FileNode(handle, session); if (node == NULL) { goto exit; } if (appendFlag) { node->flags |= HGFS_FILE_NODE_APPEND_FL; } updated = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return updated; } /* *----------------------------------------------------------------------------- * * HgfsServerCheckOpenFlagsForShare -- * * Given an open mode check this is compatible with the mode for * the share upon which the open file resides. * * If the share is read only and mode is HGFS_OPEN_CREATE we remap * it to HGFS_OPEN which is allowed if the file exists. * * Results: * TRUE if the mode is compatible. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsServerCheckOpenFlagsForShare(HgfsFileOpenInfo *openInfo,// IN: Hgfs file handle HgfsOpenFlags *flags) // IN/OUT: open mode { Bool status = TRUE; HgfsNameStatus nameStatus; HgfsOpenMode shareMode; char const *inEnd; char const *next; int len; ASSERT(openInfo); ASSERT(flags); inEnd = openInfo->cpName + openInfo->cpNameSize; /* The share name is the first component of the cross-platform name. */ len = CPName_GetComponent(openInfo->cpName, inEnd, &next); if (len < 0) { LOG(4, "%s: get first component failed\n", __FUNCTION__); status = FALSE; goto exit; } nameStatus = HgfsServerPolicy_GetShareMode(openInfo->cpName, len, &shareMode); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { status = FALSE; goto exit; } if (shareMode == HGFS_OPEN_MODE_READ_ONLY) { /* Read only share we may have work to do. */ if (*flags != HGFS_OPEN && *flags != HGFS_OPEN_CREATE) { status = FALSE; goto exit; } if (*flags == HGFS_OPEN_CREATE) { /* * Map open or create, to just open, which will fail if * if the file does not exist, which it is okay, as creating * a new file is not allowed and should be failed. */ *flags = HGFS_OPEN; } } exit: return status; } /* *----------------------------------------------------------------------------- * * HgfsDumpAllSearches -- * * Debugging routine; print all searches in the searchArray. * * Caller should hold the session's searchArrayLock. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsDumpAllSearches(HgfsSessionInfo *session) // IN: session info { unsigned int i; ASSERT(session); ASSERT(session->searchArray); Log("Dumping all searches\n"); for (i = 0; i < session->numSearches; i++) { Log("handle %u, baseDir \"%s\"\n", session->searchArray[i].handle, session->searchArray[i].utf8Dir ? session->searchArray[i].utf8Dir : "(NULL)"); } Log("Done\n"); } /* *----------------------------------------------------------------------------- * * HgfsGetNewNode -- * * Remove a node from the free list and return it. Nodes on * the free list should already be initialized. * * If the free list is empty, reallocates more memory, * initializes it appropriately, adds the new entries to the * free list, and then returns one off the free list. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * An unused file node on success * NULL on failure * * Side effects: * Memory allocation (potentially). * *----------------------------------------------------------------------------- */ static HgfsFileNode * HgfsGetNewNode(HgfsSessionInfo *session) // IN: session info { HgfsFileNode *node; HgfsFileNode *newMem; unsigned int newNumNodes; unsigned int i; ASSERT(session); ASSERT(session->nodeArray); LOG(4, "%s: entered\n", __FUNCTION__); if (!DblLnkLst_IsLinked(&session->nodeFreeList)) { /* * This has to be unsigned and with maximum bit length. This is * required to take care of "negative" differences as well. */ uintptr_t ptrDiff; if (DOLOG(4)) { Log("Dumping nodes before realloc\n"); HgfsDumpAllNodes(session); } /* Try to get twice as much memory as we had */ newNumNodes = 2 * session->numNodes; newMem = (HgfsFileNode *)realloc(session->nodeArray, newNumNodes * sizeof *(session->nodeArray)); if (!newMem) { LOG(4, "%s: can't realloc more nodes\n", __FUNCTION__); return NULL; } ptrDiff = (char *)newMem - (char *)session->nodeArray; if (ptrDiff) { size_t const oldSize = session->numNodes * sizeof *(session->nodeArray); /* * The portion of memory that contains all our file nodes moved. * All pointers that pointed inside the previous portion of memory * must be updated to point to the new portion of memory. * * We'll need to lock this if we multithread. */ LOG(4, "Rebasing pointers, diff is %"FMTSZ"u, sizeof node is " "%"FMTSZ"u\n", ptrDiff, sizeof(HgfsFileNode)); LOG(4, "old: %p new: %p\n", session->nodeArray, newMem); ASSERT(newMem == (HgfsFileNode *)((char*)session->nodeArray + ptrDiff)); #define HgfsServerRebase(_ptr, _type) \ if ((size_t)((char *)_ptr - (char *)session->nodeArray) < oldSize) { \ _ptr = (_type *)((char *)_ptr + ptrDiff); \ } /* * Rebase the links of all file nodes */ for (i = 0; i < session->numNodes; i++) { HgfsServerRebase(newMem[i].links.prev, DblLnkLst_Links) HgfsServerRebase(newMem[i].links.next, DblLnkLst_Links) } /* * There is no need to rebase the anchor of the file node free list * because if we are here, it is empty. */ /* Rebase the anchor of the cached file nodes list. */ HgfsServerRebase(session->nodeCachedList.prev, DblLnkLst_Links) HgfsServerRebase(session->nodeCachedList.next, DblLnkLst_Links) #undef HgfsServerRebase } /* Initialize the new nodes */ LOG(4, "numNodes was %u, now is %u\n", session->numNodes, newNumNodes); for (i = session->numNodes; i < newNumNodes; i++) { DblLnkLst_Init(&newMem[i].links); newMem[i].state = FILENODE_STATE_UNUSED; newMem[i].utf8Name = NULL; newMem[i].utf8NameLen = 0; newMem[i].fileCtx = NULL; /* Append at the end of the list */ DblLnkLst_LinkLast(&session->nodeFreeList, &newMem[i].links); } session->nodeArray = newMem; session->numNodes = newNumNodes; if (DOLOG(4)) { Log("Dumping nodes after pointer changes\n"); HgfsDumpAllNodes(session); } } /* Remove the first item from the list */ node = DblLnkLst_Container(session->nodeFreeList.next, HgfsFileNode, links); DblLnkLst_Unlink1(&node->links); return node; } /* *----------------------------------------------------------------------------- * * HgfsRemoveFileNode -- * * Free its localname, clear its fields, return it to the free list. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * None * * Side effects: * node->utf8Name is freed. * node->state is set to FILENODE_STATE_UNUSED. * *----------------------------------------------------------------------------- */ static void HgfsRemoveFileNode(HgfsFileNode *node, // IN: file node HgfsSessionInfo *session) // IN: session info { ASSERT(node); LOG(4, "%s: handle %u, name %s, fileId %"FMT64"u\n", __FUNCTION__, HgfsFileNode2Handle(node), node->utf8Name, node->localId.fileId); if (node->shareName) { free(node->shareName); node->shareName = NULL; } if (node->utf8Name) { free(node->utf8Name); node->utf8Name = NULL; } node->state = FILENODE_STATE_UNUSED; ASSERT(node->fileCtx == NULL); node->fileCtx = NULL; if (node->shareInfo.rootDir) { free((void*)node->shareInfo.rootDir); node->shareInfo.rootDir = NULL; } /* Prepend at the beginning of the list */ DblLnkLst_LinkFirst(&session->nodeFreeList, &node->links); } /* *----------------------------------------------------------------------------- * * HgfsFreeFileNodeInternal -- * * Free its localname, clear its fields, return it to the free list. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * None * * Side effects: * node->utf8Name is freed. * node->state is set to FILENODE_STATE_UNUSED. * *----------------------------------------------------------------------------- */ static void HgfsFreeFileNodeInternal(HgfsHandle handle, // IN: Handle to free HgfsSessionInfo *session) // IN: Session info { HgfsFileNode *node = HgfsHandle2FileNode(handle, session); ASSERT(node); HgfsRemoveFileNode(node, session); } /* *----------------------------------------------------------------------------- * * HgfsFreeFileNode -- * * Free its localname, clear its fields, return it to the free list. * * Results: * None * * Side effects: * node->utf8Name is freed. * node->state is set to FILENODE_STATE_UNUSED. * *----------------------------------------------------------------------------- */ static void HgfsFreeFileNode(HgfsHandle handle, // IN: Handle to free HgfsSessionInfo *session) // IN: Session info { MXUser_AcquireExclLock(session->nodeArrayLock); HgfsFreeFileNodeInternal(handle, session); MXUser_ReleaseExclLock(session->nodeArrayLock); } /* *----------------------------------------------------------------------------- * * HgfsAddNewFileNode -- * * Gets a free node off the free list, sets its name, localId info, * file descriptor and permissions. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * A pointer to the newly added node on success * NULL on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsFileNode * HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct HgfsLocalId const *localId, // IN: Local unique file ID fileDesc fileDesc, // IN: File Handle Bool append, // IN: open with append flag size_t shareNameLen, // IN: share name byte length char const *shareName, // IN: share name Bool sharedFolderOpen, // IN: shared folder only open HgfsSessionInfo *session) // IN: session info { HgfsFileNode *newNode; char* rootDir; ASSERT(openInfo); ASSERT(localId); ASSERT(session); /* This was already verified in HgfsUnpackOpenRequest... */ ASSERT(openInfo->mask & HGFS_OPEN_VALID_FILE_NAME); /* Get an unused node */ newNode = HgfsGetNewNode(session); if (!newNode) { LOG(4, "%s: out of memory\n", __FUNCTION__); return NULL; } /* Set new node's fields */ if (!HgfsServerGetOpenMode(openInfo, &newNode->mode)) { HgfsRemoveFileNode(newNode, session); return NULL; } /* * Save a copy of the share name so we can look up its * access mode at various times over the node's lifecycle. */ newNode->shareName = malloc(shareNameLen + 1); if (newNode->shareName == NULL) { LOG(4, "%s: out of memory\n", __FUNCTION__); HgfsRemoveFileNode(newNode, session); return NULL; } memcpy(newNode->shareName, shareName, shareNameLen); newNode->shareName[shareNameLen] = '\0'; newNode->shareNameLen = shareNameLen; newNode->utf8NameLen = strlen(openInfo->utf8Name); newNode->utf8Name = malloc(newNode->utf8NameLen + 1); if (newNode->utf8Name == NULL) { LOG(4, "%s: out of memory\n", __FUNCTION__); HgfsRemoveFileNode(newNode, session); return NULL; } memcpy(newNode->utf8Name, openInfo->utf8Name, newNode->utf8NameLen); newNode->utf8Name[newNode->utf8NameLen] = '\0'; newNode->shareInfo.rootDirLen = strlen(openInfo->shareInfo.rootDir); rootDir = malloc(newNode->shareInfo.rootDirLen + 1); if (rootDir == NULL) { LOG(4, "HgfsAddNewFileNode: out of memory\n"); HgfsRemoveFileNode(newNode, session); return NULL; } memcpy(rootDir, openInfo->shareInfo.rootDir, newNode->shareInfo.rootDirLen); rootDir[newNode->shareInfo.rootDirLen] = '\0'; newNode->shareInfo.rootDir = rootDir; newNode->handle = HgfsServerGetNextHandleCounter(); newNode->localId = *localId; newNode->fileDesc = fileDesc; newNode->shareAccess = (openInfo->mask & HGFS_OPEN_VALID_SHARE_ACCESS) ? openInfo->shareAccess : HGFS_DEFAULT_SHARE_ACCESS; newNode->flags = 0; if (append) { newNode->flags |= HGFS_FILE_NODE_APPEND_FL; } if (sharedFolderOpen) { newNode->flags |= HGFS_FILE_NODE_SHARED_FOLDER_OPEN_FL; } if (HGFS_OPEN_MODE_FLAGS(openInfo->mode) & HGFS_OPEN_SEQUENTIAL) { newNode->flags |= HGFS_FILE_NODE_SEQUENTIAL_FL; } newNode->serverLock = openInfo->acquiredLock; newNode->state = FILENODE_STATE_IN_USE_NOT_CACHED; newNode->shareInfo.readPermissions = openInfo->shareInfo.readPermissions; newNode->shareInfo.writePermissions = openInfo->shareInfo.writePermissions; newNode->shareInfo.handle = openInfo->shareInfo.handle; LOG(4, "%s: got new node, handle %u\n", __FUNCTION__, HgfsFileNode2Handle(newNode)); return newNode; } /* *----------------------------------------------------------------------------- * * HgfsAddToCacheInternal -- * * Adds the node to cache. If the number of nodes in the cache exceed * the maximum number of entries then the first node is removed. The * first node should be the least recently used. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsAddToCacheInternal(HgfsHandle handle, // IN: HGFS file handle HgfsSessionInfo *session) // IN: Session info { HgfsFileNode *node; /* Check if the node is already cached. */ if (HgfsIsCachedInternal(handle, session)) { ASSERT((node = HgfsHandle2FileNode(handle, session)) && node->state == FILENODE_STATE_IN_USE_CACHED); return TRUE; } /* Remove the LRU node if the list is full. */ if (session->numCachedOpenNodes == gHgfsCfgSettings.maxCachedOpenNodes) { if (!HgfsRemoveLruNode(session)) { LOG(4, "%s: Unable to remove LRU node from cache.\n", __FUNCTION__); return FALSE; } } ASSERT(session->numCachedOpenNodes < gHgfsCfgSettings.maxCachedOpenNodes); node = HgfsHandle2FileNode(handle, session); ASSERT(node); /* Append at the end of the list. */ DblLnkLst_LinkLast(&session->nodeCachedList, &node->links); node->state = FILENODE_STATE_IN_USE_CACHED; session->numCachedOpenNodes++; /* * Keep track of how many open nodes we have with * server locks on them. The locked file should * always be present in the node cache. So we keep * the number of the files that have locks on them * limited, and smaller than the number of maximum * nodes in the cache. */ if (node->serverLock != HGFS_LOCK_NONE) { session->numCachedLockedNodes++; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsRemoveFromCacheInternal -- * * Remove the specified node from the cache and close the associated * file descriptor. If the node was not already in the cache then nothing * is done. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsRemoveFromCacheInternal(HgfsHandle handle, // IN: Hgfs handle to the node HgfsSessionInfo *session) // IN: Session info { HgfsFileNode *node; ASSERT(session); node = HgfsHandle2FileNode(handle, session); if (node == NULL) { LOG(4, "%s: invalid handle.\n", __FUNCTION__); return FALSE; } if (node->state == FILENODE_STATE_IN_USE_CACHED) { /* Unlink the node from the list of cached fileNodes. */ DblLnkLst_Unlink1(&node->links); node->state = FILENODE_STATE_IN_USE_NOT_CACHED; session->numCachedOpenNodes--; LOG(4, "%s: cache entries %u remove node %s id %"FMT64"u fd %u .\n", __FUNCTION__, session->numCachedOpenNodes, node->utf8Name, node->localId.fileId, node->fileDesc); /* * XXX: From this point and up in the call chain (i.e. this function and * all callers), Bool is returned instead of the HgfsInternalStatus. * HgfsPlatformCloseFile returns HgfsInternalStatus, which is far more granular, * but modifying this stack to use HgfsInternalStatus instead of Bool is * not worth it, as we'd have to #define per-platform error codes for * things like "ran out of memory", "bad file handle", etc. * * Instead, we'll just await the lobotomization of the node cache to * really fix this. */ if (HgfsPlatformCloseFile(node->fileDesc, node->fileCtx)) { LOG(4, "%s: Could not close fd %u\n", __FUNCTION__, node->fileDesc); return FALSE; } node->fileCtx = NULL; /* * If we have just removed the node then the number of used nodes better * be less than the max. If we didn't remove a node, it means the * node we tried to remove was not in the cache to begin with, and * we have a problem (see bug 36244). */ ASSERT(session->numCachedOpenNodes < gHgfsCfgSettings.maxCachedOpenNodes); } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsIsCachedInternal -- * * Check if the node exists in the cache. If the node is found in * the cache then move it to the end of the list. Most recently * used nodes move towards the end of the list. * * The session nodeArrayLock should be acquired prior to calling this * function. * * Results: * TRUE if the node is found in the cache. * FALSE if the node is not in the cache. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsIsCachedInternal(HgfsHandle handle, // IN: Structure representing file node HgfsSessionInfo *session) // IN: Session info { HgfsFileNode *node; ASSERT(session); node = HgfsHandle2FileNode(handle, session); if (node == NULL) { LOG(4, "%s: invalid handle.\n", __FUNCTION__); return FALSE; } if (node->state == FILENODE_STATE_IN_USE_CACHED) { /* * Move this node to the end of the list. */ DblLnkLst_Unlink1(&node->links); DblLnkLst_LinkLast(&session->nodeCachedList, &node->links); return TRUE; } return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsIsServerLockAllowed -- * * Check if there's room for another file node with the server lock. * If there's no room in the cache for the file with the server lock, * then the file will be opened without the lock even if the client * asked for the lock. * * * Results: * TRUE if the node is found in the cache. * FALSE if the node is not in the cache. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsIsServerLockAllowed(HgfsSessionInfo *session) // IN: session info { Bool allowed; MXUser_AcquireExclLock(session->nodeArrayLock); allowed = session->numCachedLockedNodes < MAX_LOCKED_FILENODES; MXUser_ReleaseExclLock(session->nodeArrayLock); return allowed; } /* *----------------------------------------------------------------------------- * * HgfsGetNewSearch -- * * Remove a search from the free list and return it. Searches on * the free list should already be initialized. * * If the free list is empty, reallocates more memory, * initializes it appropriately, adds the new entries to the * free list, and then returns one off the free list. * * Caller should hold the session's searchArrayLock. * * Results: * An unused search on success * NULL on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsSearch * HgfsGetNewSearch(HgfsSessionInfo *session) // IN: session info { HgfsSearch *search; HgfsSearch *newMem; unsigned int newNumSearches; unsigned int i; ASSERT(session); ASSERT(session->searchArray); LOG(4, "%s: entered\n", __FUNCTION__); if (!DblLnkLst_IsLinked(&session->searchFreeList)) { /* * This has to be unsigned and with maximum bit length. This is * required to take care of "negative" differences as well. */ uintptr_t ptrDiff; if (DOLOG(4)) { Log("Dumping searches before realloc\n"); HgfsDumpAllSearches(session); } /* Try to get twice as much memory as we had */ newNumSearches = 2 * session->numSearches; newMem = (HgfsSearch *)realloc(session->searchArray, newNumSearches * sizeof *(session->searchArray)); if (!newMem) { LOG(4, "%s: can't realloc more searches\n", __FUNCTION__); return NULL; } ptrDiff = (char *)newMem - (char *)session->searchArray; if (ptrDiff) { size_t const oldSize = session->numSearches * sizeof *(session->searchArray); /* * The portion of memory that contains all our searches moved. * All pointers that pointed inside the previous portion of memory * must be updated to point to the new portion of memory. */ LOG(4, "Rebasing pointers, diff is %"FMTSZ"u, sizeof search is " "%"FMTSZ"u\n", ptrDiff, sizeof(HgfsSearch)); LOG(4, "old: %p new: %p\n", session->searchArray, newMem); ASSERT(newMem == (HgfsSearch*)((char*)session->searchArray + ptrDiff)); #define HgfsServerRebase(_ptr, _type) \ if ((size_t)((char *)_ptr - (char *)session->searchArray) < oldSize) { \ _ptr = (_type *)((char *)_ptr + ptrDiff); \ } /* * Rebase the links of all searches */ for (i = 0; i < session->numSearches; i++) { HgfsServerRebase(newMem[i].links.prev, DblLnkLst_Links) HgfsServerRebase(newMem[i].links.next, DblLnkLst_Links) } /* * There is no need to rebase the links of the search free list * because if we are here, it is empty */ #undef HgfsServerRebase } /* Initialize the new searches */ LOG(4, "numSearches was %u, now is %u\n", session->numSearches, newNumSearches); for (i = session->numSearches; i < newNumSearches; i++) { DblLnkLst_Init(&newMem[i].links); newMem[i].utf8Dir = NULL; newMem[i].utf8DirLen = 0; newMem[i].utf8ShareName = NULL; newMem[i].utf8ShareNameLen = 0; newMem[i].shareInfo.rootDir = NULL; newMem[i].shareInfo.rootDirLen = 0; newMem[i].dents = NULL; newMem[i].numDents = 0; /* Append at the end of the list */ DblLnkLst_LinkLast(&session->searchFreeList, &newMem[i].links); } session->searchArray = newMem; session->numSearches = newNumSearches; if (DOLOG(4)) { Log("Dumping searches after pointer changes\n"); HgfsDumpAllSearches(session); } } /* Remove the first item from the list */ search = DblLnkLst_Container(session->searchFreeList.next, HgfsSearch, links); DblLnkLst_Unlink1(&search->links); return search; } /* *----------------------------------------------------------------------------- * * HgfsSearch2SearchHandle -- * * Retrieve the handle that represents a search outside of the server. * * Caller should hold the session's searchArrayLock. * * Results: * The handle * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsHandle HgfsSearch2SearchHandle(HgfsSearch const *search) // IN { ASSERT(search); return search->handle; } /* *----------------------------------------------------------------------------- * * HgfsSearchIsBaseNameSpace -- * * Check if the search is the base of our name space, i.e. the dirents are * the shares themselves. * * Results: * TRUE if the search is the base of the name space, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsSearchIsBaseNameSpace(HgfsSearch const *search) // IN { ASSERT(search); return search->type == DIRECTORY_SEARCH_TYPE_BASE; } /* *----------------------------------------------------------------------------- * * HgfsGetSearchCopy -- * * Make a copy of the search. It should not be kept around for long, as the * data might become stale. This is mostly a convenience function to get * search fields more efficiently. * * Note that unlike HgfsGetNodeCopy, we always copy the name, and we never * copy the dents. * * Results: * TRUE if the hgfs handle is valid and the copy was successful. * FALSE otherwise. * * Side effects: * Allocates memory for search.utf8Dir * *----------------------------------------------------------------------------- */ Bool HgfsGetSearchCopy(HgfsHandle handle, // IN: Hgfs search handle HgfsSessionInfo *session, // IN: Session info HgfsSearch *copy) // IN/OUT: Copy of the search { HgfsSearch *original = NULL; Bool found = FALSE; ASSERT(copy); MXUser_AcquireExclLock(session->searchArrayLock); original = HgfsSearchHandle2Search(handle, session); if (original == NULL) { goto exit; } copy->utf8Dir = malloc(original->utf8DirLen + 1); if (copy->utf8Dir == NULL) { goto exit; } copy->utf8DirLen = original->utf8DirLen; memcpy(copy->utf8Dir, original->utf8Dir, copy->utf8DirLen); copy->utf8Dir[copy->utf8DirLen] = '\0'; copy->utf8ShareName = malloc(original->utf8ShareNameLen + 1); if (copy->utf8ShareName == NULL) { goto exit; } copy->utf8ShareNameLen = original->utf8ShareNameLen; memcpy(copy->utf8ShareName, original->utf8ShareName, copy->utf8ShareNameLen); copy->utf8ShareName[copy->utf8ShareNameLen] = '\0'; /* No dents for the copy, they consume too much memory and aren't needed. */ copy->dents = NULL; copy->numDents = 0; copy->handle = original->handle; copy->type = original->type; found = TRUE; exit: MXUser_ReleaseExclLock(session->searchArrayLock); return found; } /* *----------------------------------------------------------------------------- * * HgfsAddNewSearch -- * * Gets a free search off the free list, sets its base directory, dents, * and type. * * Caller should hold the session's searchArrayLock. * * Results: * A pointer to the newly added search on success * NULL on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsSearch * HgfsAddNewSearch(char const *utf8Dir, // IN: UTF8 name of dir to search in DirectorySearchType type, // IN: What kind of search is this? char const *utf8ShareName, // IN: Share name containing the directory char const *rootDir, // IN: Root directory for the share HgfsSessionInfo *session) // IN: Session info { HgfsSearch *newSearch; ASSERT(utf8Dir); /* Get an unused search */ newSearch = HgfsGetNewSearch(session); if (!newSearch) { LOG(4, "%s: out of memory\n", __FUNCTION__); return NULL; } newSearch->dents = NULL; newSearch->numDents = 0; newSearch->flags = 0; newSearch->type = type; newSearch->handle = HgfsServerGetNextHandleCounter(); newSearch->utf8DirLen = strlen(utf8Dir); newSearch->utf8Dir = Util_SafeStrdup(utf8Dir); newSearch->utf8ShareNameLen = strlen(utf8ShareName); newSearch->utf8ShareName = Util_SafeStrdup(utf8ShareName); newSearch->shareInfo.rootDirLen = strlen(rootDir); newSearch->shareInfo.rootDir = Util_SafeStrdup(rootDir); LOG(4, "%s: got new search, handle %u\n", __FUNCTION__, HgfsSearch2SearchHandle(newSearch)); return newSearch; } /* *----------------------------------------------------------------------------- * * HgfsFreeSearchDirents -- * * Frees all dirents and dirents pointer array. * * Caller should hold the session's searchArrayLock. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsFreeSearchDirents(HgfsSearch *search) // IN/OUT: search { unsigned int i; if (NULL != search->dents) { for (i = 0; i < search->numDents; i++) { free(search->dents[i]); search->dents[i] = NULL; } free(search->dents); search->dents = NULL; } } /* *----------------------------------------------------------------------------- * * HgfsRemoveSearchInternal -- * * Destroy a search object and recycle it to the free list * * Caller should hold the session's searchArrayLock. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsRemoveSearchInternal(HgfsSearch *search, // IN: search HgfsSessionInfo *session) // IN: session info { ASSERT(search); ASSERT(session); LOG(4, "%s: handle %u, dir %s\n", __FUNCTION__, HgfsSearch2SearchHandle(search), search->utf8Dir); HgfsFreeSearchDirents(search); free(search->utf8Dir); free(search->utf8ShareName); free((char*)search->shareInfo.rootDir); search->utf8DirLen = 0; search->utf8Dir = NULL; search->utf8ShareNameLen = 0; search->utf8ShareName = NULL; search->shareInfo.rootDirLen = 0; search->shareInfo.rootDir = NULL; /* Prepend at the beginning of the list */ DblLnkLst_LinkFirst(&session->searchFreeList, &search->links); } /* *----------------------------------------------------------------------------- * * HgfsRemoveSearch -- * * Wrapper around HgfsRemoveSearchInternal that first takes the lock and * converts the handle to the search itself. * * Results: * TRUE if the search was freed successfully. * FALSE if the search could not be found. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsRemoveSearch(HgfsHandle handle, // IN: search HgfsSessionInfo *session) // IN: session info { HgfsSearch *search; Bool success = FALSE; MXUser_AcquireExclLock(session->searchArrayLock); search = HgfsSearchHandle2Search(handle, session); if (search != NULL) { HgfsRemoveSearchInternal(search, session); success = TRUE; } MXUser_ReleaseExclLock(session->searchArrayLock); return success; } /* *---------------------------------------------------------------------------- * * HgfsSearchHasReadAllEntries -- * * Return whether the client has read all the search entries or not. * * Results: * TRUE on success, FALSE on failure. readAllEntries is filled in on * success. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static Bool HgfsSearchHasReadAllEntries(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info Bool *readAllEntries) // OUT: If open was sequential { HgfsSearch *search; Bool success = FALSE; ASSERT(NULL != readAllEntries); MXUser_AcquireExclLock(session->searchArrayLock); search = HgfsSearchHandle2Search(handle, session); if (NULL == search) { goto exit; } *readAllEntries = search->flags & HGFS_SEARCH_FLAG_READ_ALL_ENTRIES; success = TRUE; exit: MXUser_ReleaseExclLock(session->searchArrayLock); return success; } /* *---------------------------------------------------------------------------- * * HgfsSearchSetReadAllEntries -- * * Set the flag to indicate the client has read all the search entries. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsSearchSetReadAllEntries(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session) // IN: Session info { HgfsSearch *search; MXUser_AcquireExclLock(session->searchArrayLock); search = HgfsSearchHandle2Search(handle, session); if (NULL == search) { goto exit; } search->flags |= HGFS_SEARCH_FLAG_READ_ALL_ENTRIES; exit: MXUser_ReleaseExclLock(session->searchArrayLock); } /* *----------------------------------------------------------------------------- * * HgfsServerGetDirEntry -- * * Returns a copy of the directory entry at the given index. If remove is set * to TRUE, the existing result is also pruned and the remaining results * are shifted up in the result array. * * Results: * NULL if there was an error or no search results were left. * Non-NULL if result was found. Caller must free it. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsServerGetDirEntry(HgfsHandle handle, // IN: Handle to search HgfsSessionInfo *session, // IN: Session info uint32 index, // IN: index to retrieve at Bool remove, // IN: If true, removes the result struct DirectoryEntry **dirEntry) // OUT: directory entry { HgfsSearch *search; struct DirectoryEntry *dent = NULL; HgfsInternalStatus status = HGFS_ERROR_SUCCESS; MXUser_AcquireExclLock(session->searchArrayLock); search = HgfsSearchHandle2Search(handle, session); if (search == NULL) { status = HGFS_ERROR_INVALID_HANDLE; goto out; } /* No more entries or none. */ if (search->dents == NULL) { goto out; } if (HGFS_SEARCH_LAST_ENTRY_INDEX == index) { /* Set the index to the final entry. */ index = search->numDents - 1; } status = HgfsPlatformGetDirEntry(search, session, index, remove, &dent); out: MXUser_ReleaseExclLock(session->searchArrayLock); *dirEntry = dent; return status; } /* *----------------------------------------------------------------------------- * * HgfsSearchHandle2Search -- * * Retrieve the search a handle refers to. * * Results: * The search if the handle is valid (i.e. it refers to an existing search * that is currently in use) * NULL if the handle is invalid * * Caller should hold the session's searchArrayLock. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsSearch * HgfsSearchHandle2Search(HgfsHandle handle, // IN: handle HgfsSessionInfo *session) // IN: session info { unsigned int i; HgfsSearch *search = NULL; ASSERT(session); ASSERT(session->searchArray); /* XXX: This O(n) lookup can and should be optimized. */ for (i = 0; i < session->numSearches; i++) { if (!DblLnkLst_IsLinked(&session->searchArray[i].links) && session->searchArray[i].handle == handle) { search = &session->searchArray[i]; break; } } return search; } /* *----------------------------------------------------------------------------- * * HgfsUpdateNodeNames -- * * Walk the node array and update all nodes that have the old file name to * store the new file name. * * Results: * None * * Side effects: * If there isn't enough memory to accommodate the new names, those file nodes * that couldn't be updated are deleted. * *----------------------------------------------------------------------------- */ void HgfsUpdateNodeNames(const char *oldLocalName, // IN: Name of file to look for const char *newLocalName, // IN: Name to replace with HgfsSessionInfo *session) // IN: Session info { HgfsFileNode *fileNode; unsigned int i; char *newBuffer; size_t newBufferLen; ASSERT(oldLocalName); ASSERT(newLocalName); ASSERT(session); ASSERT(session->nodeArray); newBufferLen = strlen(newLocalName); MXUser_AcquireExclLock(session->nodeArrayLock); for (i = 0; i < session->numNodes; i++) { fileNode = &session->nodeArray[i]; /* If the node is on the free list, skip it. */ if (fileNode->state == FILENODE_STATE_UNUSED) { continue; } if (strcmp(fileNode->utf8Name, oldLocalName) == 0) { newBuffer = malloc(newBufferLen + 1); if (!newBuffer) { LOG(4, "%s: Failed to update a node name.\n", __FUNCTION__); continue; } memcpy(newBuffer, newLocalName, newBufferLen); newBuffer[newBufferLen] = '\0'; /* Update this name to the new name. */ free(fileNode->utf8Name); fileNode->utf8Name = newBuffer; fileNode->utf8NameLen = newBufferLen; } } MXUser_ReleaseExclLock(session->nodeArrayLock); } /* *----------------------------------------------------------------------------- * * HgfsServerClose -- * * Handle a Close request. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerClose(HgfsInputParam *input) // IN: Input params { HgfsHandle file; HgfsInternalStatus status = HGFS_ERROR_SUCCESS; size_t replyPayloadSize = 0; HGFS_ASSERT_INPUT(input); if (HgfsUnpackCloseRequest(input->payload, input->payloadSize, input->op, &file)) { LOG(4, "%s: close fh %u\n", __FUNCTION__, file); if (!HgfsRemoveFromCache(file, input->session)) { LOG(4, "%s: Could not remove the node from cache.\n", __FUNCTION__); status = HGFS_ERROR_INVALID_HANDLE; } else { HgfsFreeFileNode(file, input->session); if (!HgfsPackCloseReply(input->packet, input->request, input->op, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } else { status = HGFS_ERROR_INTERNAL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerSearchClose -- * * Handle a "Search Close" request. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerSearchClose(HgfsInputParam *input) // IN: Input params { HgfsHandle search; HgfsInternalStatus status; size_t replyPayloadSize = 0; HGFS_ASSERT_INPUT(input); if (HgfsUnpackSearchCloseRequest(input->payload, input->payloadSize, input->op, &search)) { LOG(4, "%s: close search #%u\n", __FUNCTION__, search); if (HgfsRemoveSearch(search, input->session)) { if (HgfsPackSearchCloseReply(input->packet, input->request, input->op, &replyPayloadSize, input->session)) { status = HGFS_ERROR_SUCCESS; } else { status = HGFS_ERROR_INTERNAL; } } else { /* Invalid handle */ LOG(4, "%s: invalid handle %u\n", __FUNCTION__, search); status = HGFS_ERROR_INVALID_HANDLE; } } else { status = HGFS_ERROR_INTERNAL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } #define HGFS_SIZEOF_OP(type) (sizeof (type) + sizeof (HgfsRequest)) /* Opcode handlers, indexed by opcode */ static struct { void (*handler)(HgfsInputParam *input); /* Minimal size of the request packet */ unsigned int minReqSize; /* How do you process the request {sync, async} ? */ RequestHint reqType; } const handlers[] = { { HgfsServerOpen, sizeof (HgfsRequestOpen), REQ_SYNC }, { HgfsServerRead, sizeof (HgfsRequestRead), REQ_SYNC }, { HgfsServerWrite, sizeof (HgfsRequestWrite), REQ_SYNC }, { HgfsServerClose, sizeof (HgfsRequestClose), REQ_SYNC }, { HgfsServerSearchOpen, sizeof (HgfsRequestSearchOpen), REQ_SYNC }, { HgfsServerSearchRead, sizeof (HgfsRequestSearchRead), REQ_SYNC }, { HgfsServerSearchClose, sizeof (HgfsRequestSearchClose), REQ_SYNC }, { HgfsServerGetattr, sizeof (HgfsRequestGetattr), REQ_SYNC }, { HgfsServerSetattr, sizeof (HgfsRequestSetattr), REQ_SYNC }, { HgfsServerCreateDir, sizeof (HgfsRequestCreateDir), REQ_SYNC }, { HgfsServerDeleteFile, sizeof (HgfsRequestDelete), REQ_SYNC }, { HgfsServerDeleteDir, sizeof (HgfsRequestDelete), REQ_SYNC }, { HgfsServerRename, sizeof (HgfsRequestRename), REQ_SYNC }, { HgfsServerQueryVolume, sizeof (HgfsRequestQueryVolume), REQ_SYNC }, { HgfsServerOpen, sizeof (HgfsRequestOpenV2), REQ_SYNC }, { HgfsServerGetattr, sizeof (HgfsRequestGetattrV2), REQ_SYNC }, { HgfsServerSetattr, sizeof (HgfsRequestSetattrV2), REQ_SYNC }, { HgfsServerSearchRead, sizeof (HgfsRequestSearchReadV2), REQ_SYNC }, { HgfsServerSymlinkCreate, sizeof (HgfsRequestSymlinkCreate), REQ_SYNC }, { HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange), REQ_SYNC }, { HgfsServerCreateDir, sizeof (HgfsRequestCreateDirV2), REQ_SYNC }, { HgfsServerDeleteFile, sizeof (HgfsRequestDeleteV2), REQ_SYNC }, { HgfsServerDeleteDir, sizeof (HgfsRequestDeleteV2), REQ_SYNC }, { HgfsServerRename, sizeof (HgfsRequestRenameV2), REQ_SYNC }, { HgfsServerOpen, HGFS_SIZEOF_OP(HgfsRequestOpenV3), REQ_SYNC }, { HgfsServerRead, HGFS_SIZEOF_OP(HgfsRequestReadV3), REQ_SYNC }, { HgfsServerWrite, HGFS_SIZEOF_OP(HgfsRequestWriteV3), REQ_SYNC }, { HgfsServerClose, HGFS_SIZEOF_OP(HgfsRequestCloseV3), REQ_SYNC }, { HgfsServerSearchOpen, HGFS_SIZEOF_OP(HgfsRequestSearchOpenV3), REQ_SYNC }, { HgfsServerSearchRead, HGFS_SIZEOF_OP(HgfsRequestSearchReadV3), REQ_SYNC }, { HgfsServerSearchClose, HGFS_SIZEOF_OP(HgfsRequestSearchCloseV3), REQ_SYNC }, { HgfsServerGetattr, HGFS_SIZEOF_OP(HgfsRequestGetattrV3), REQ_SYNC }, { HgfsServerSetattr, HGFS_SIZEOF_OP(HgfsRequestSetattrV3), REQ_SYNC }, { HgfsServerCreateDir, HGFS_SIZEOF_OP(HgfsRequestCreateDirV3), REQ_SYNC }, { HgfsServerDeleteFile, HGFS_SIZEOF_OP(HgfsRequestDeleteV3), REQ_SYNC }, { HgfsServerDeleteDir, HGFS_SIZEOF_OP(HgfsRequestDeleteV3), REQ_SYNC }, { HgfsServerRename, HGFS_SIZEOF_OP(HgfsRequestRenameV3), REQ_SYNC }, { HgfsServerQueryVolume, HGFS_SIZEOF_OP(HgfsRequestQueryVolumeV3), REQ_SYNC }, { HgfsServerSymlinkCreate, HGFS_SIZEOF_OP(HgfsRequestSymlinkCreateV3), REQ_SYNC }, { HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange), REQ_SYNC }, { HgfsServerWriteWin32Stream, HGFS_SIZEOF_OP(HgfsRequestWriteWin32StreamV3), REQ_SYNC }, /* * Starting from HGFS_OP_CREATE_SESSION_V4 (all V4 commands and above) the * second field is the minimum size for actual HGFS operational request * and not the minimum size of operational request with a header. */ { HgfsServerCreateSession, sizeof (HgfsRequestCreateSessionV4), REQ_SYNC}, { HgfsServerDestroySession, sizeof (HgfsRequestDestroySessionV4), REQ_SYNC}, { HgfsServerRead, sizeof (HgfsRequestReadV3), REQ_ASYNC}, { HgfsServerWrite, sizeof (HgfsRequestWriteV3), REQ_ASYNC}, { HgfsServerSetDirNotifyWatch, sizeof (HgfsRequestSetWatchV4), REQ_SYNC}, { HgfsServerRemoveDirNotifyWatch, sizeof (HgfsRequestRemoveWatchV4), REQ_SYNC}, { NULL, 0, REQ_SYNC}, // No Op notify { HgfsServerSearchRead, sizeof (HgfsRequestSearchReadV4), REQ_SYNC}, }; /* *----------------------------------------------------------------------------- * * HgfsServerInputAllocInit -- * * Allocates and initializes the input params object with the operation parameters. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerInputAllocInit(HgfsPacket *packet, // IN: packet HgfsTransportSessionInfo *transportSession,// IN: session HgfsSessionInfo *session, // IN: session Id const void *request, // IN: HGFS packet size_t requestSize, // IN: request packet size Bool sessionEnabled, // IN: session enabled request uint32 requestId, // IN: unique request id HgfsOp requestOp, // IN: op size_t requestOpArgsSize, // IN: op args size const void *requestOpArgs, // IN: op args HgfsInputParam **params) // OUT: parameters { HgfsInputParam *localParams; localParams = Util_SafeCalloc(1, sizeof *localParams); localParams->packet = packet; localParams->request = request; localParams->requestSize = requestSize; localParams->transportSession = transportSession; localParams->session = session; localParams->id = requestId; localParams->sessionEnabled = sessionEnabled; localParams->op = requestOp; localParams->payload = requestOpArgs; localParams->payloadSize = requestOpArgsSize; if (NULL != localParams->payload) { localParams->payloadOffset = (char *)localParams->payload - (char *)localParams->request; } *params = localParams; } /* *----------------------------------------------------------------------------- * * HgfsServerInputExit -- * * Tearsdown and frees the input params object with the operation parameters. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerInputExit(HgfsInputParam *params) // IN: packet { if (NULL != params->session) { HgfsServerSessionPut(params->session); } HgfsServerTransportSessionPut(params->transportSession); free(params); } /* *----------------------------------------------------------------------------- * * HgfsServerGetRequest -- * * Takes the Hgfs packet and extracts the operation parameters. * This validates the incoming packet as part of the processing. * * Results: * HGFS_ERROR_SUCCESS if all the request parameters are successfully extracted. * HGFS_ERROR_INTERNAL if an error occurs without sufficient request data to be * able to send a reply to the client. * Any other appropriate error if the incoming packet has errors and there is * sufficient information to send a response. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerGetRequest(HgfsPacket *packet, // IN: packet HgfsTransportSessionInfo *transportSession,// IN: session HgfsInputParam **input) // OUT: parameters { HgfsSessionInfo *session = NULL; uint64 sessionId = HGFS_INVALID_SESSION_ID; Bool sessionEnabled = FALSE; uint32 requestId = 0; HgfsOp opcode; const void *request; size_t requestSize; const void *requestOpArgs; size_t requestOpArgsSize; HgfsInternalStatus parseStatus = HGFS_ERROR_SUCCESS; request = HSPU_GetMetaPacket(packet, &requestSize, transportSession->channelCbTable); if (NULL == request) { /* * How can I return error back to the client, clearly the client is either broken or * malicious? We cannot continue from here. */ parseStatus = HGFS_ERROR_INTERNAL; goto exit; } parseStatus = HgfsUnpackPacketParams(request, requestSize, &sessionEnabled, &sessionId, &requestId, &opcode, &requestOpArgsSize, &requestOpArgs); if (HGFS_ERROR_INTERNAL == parseStatus) { /* The packet was malformed and we cannot reply. */ goto exit; } /* * Every request must be processed within an HGFS session, except create session. * If we don't already have an HGFS session for processing this request, * then use or create the default session. */ if (sessionEnabled) { if (opcode != HGFS_OP_CREATE_SESSION_V4) { session = HgfsServerTransportGetSessionInfo(transportSession, sessionId); if (NULL == session || session->state != HGFS_SESSION_STATE_OPEN) { LOG(4, "%s: HGFS packet with invalid session id!\n", __FUNCTION__); parseStatus = HGFS_ERROR_STALE_SESSION; } } } else { parseStatus = HgfsServerTransportGetDefaultSession(transportSession, &session); } if (NULL != session) { session->isInactive = FALSE; } HgfsServerInputAllocInit(packet, transportSession, session, request, requestSize, sessionEnabled, requestId, opcode, requestOpArgsSize, requestOpArgs, input); exit: return parseStatus; } /* *----------------------------------------------------------------------------- * * HgfsServerGetHeaderSize -- * * Takes the Hgfs input and finds the size of the header component. * * Results: * Size of the HGFS protocol header used by this request or reply. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerGetHeaderSize(Bool sessionEnabled, // IN: session based request HgfsOp op, // IN: operation Bool request) // IN: TRUE for request, FALSE for reply { size_t headerSize; /* * If the HGFS request is session enabled we must have the new header. * Any V4 operation always must have the new header too. * Otherwise, starting from HGFS V3 the header is not included in the * request itself, so we must return the size of the separate header * structure, for requests this will be HgfsRequest and replies will be HgfsReply. * Prior to V3 (so V1 and V2) there was no separate header from the request * or reply structure for any given operation, so a zero size is returned for these. */ if (sessionEnabled) { headerSize = sizeof (HgfsHeader); } else if (op < HGFS_OP_CREATE_SESSION_V4 && op >= HGFS_OP_OPEN_V3) { headerSize = (request ? sizeof (HgfsRequest) : sizeof (HgfsReply)); } else { headerSize = 0; } return headerSize; } /* *----------------------------------------------------------------------------- * * HgfsServerGetRequestHeaderSize -- * * Takes the Hgfs request input and finds the size of the header component. * * Results: * Size of the HGFS protocol header used by this request and reply. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerGetRequestHeaderSize(Bool sessionEnabled, // IN: session based request HgfsOp op) // IN: operation { return HgfsServerGetHeaderSize(sessionEnabled, op, TRUE); } /* *----------------------------------------------------------------------------- * * HgfsServerGetReplyHeaderSize -- * * Takes the Hgfs reply input and finds the size of the header component. * * Results: * Size of the HGFS protocol header used by this reply. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerGetReplyHeaderSize(Bool sessionEnabled, // IN: session based request HgfsOp op) // IN: operation { return HgfsServerGetHeaderSize(sessionEnabled, op, FALSE); } /* *----------------------------------------------------------------------------- * * HgfsServerCompleteRequest -- * * Performs all necessary action which needed for completing HGFS request: * 1. Sends reply to the guest. * 2. Release allocated objects, mapped guest memory. * 3. Dereference objects that were referenced. * * Results: * None. * * Side effects: * Reference to Session is dropped. * *----------------------------------------------------------------------------- */ static void HgfsServerCompleteRequest(HgfsInternalStatus status, // IN: Status of the request size_t replyPayloadSize, // IN: sizeof the reply payload HgfsInputParam *input) // IN/OUT: request context { void *reply; size_t replySize; size_t replyTotalSize; size_t replyHeaderSize; uint64 replySessionId; if (HGFS_ERROR_SUCCESS == status) { HGFS_ASSERT_INPUT(input); } else { ASSERT(input); } replySessionId = (NULL != input->session) ? input->session->sessionId : HGFS_INVALID_SESSION_ID; replyHeaderSize = HgfsServerGetReplyHeaderSize(input->sessionEnabled, input->op); if (replyHeaderSize != 0) { replySize = replyHeaderSize + replyPayloadSize; } else { /* * For pre-V3 header is included in the payload size. * If we want to send just an error result then HgfsReply * only size is required. * * XXX - all callers should be verified that the reply payload * size for V1 and V2 should be correct (mininum HgfsReply size). */ replySize = MAX(replyPayloadSize, sizeof (HgfsReply)); } reply = HSPU_GetReplyPacket(input->packet, input->transportSession->channelCbTable, replySize, &replyTotalSize); ASSERT(reply && (replySize <= replyTotalSize)); if (!HgfsPackReplyHeader(status, replyPayloadSize, input->sessionEnabled, replySessionId, input->id, input->op, HGFS_PACKET_FLAG_REPLY, replyTotalSize, reply)) { Log("%s: Error packing header!\n", __FUNCTION__); goto exit; } if (!HgfsPacketSend(input->packet, input->transportSession, input->session, 0)) { /* Send failed. Drop the reply. */ Log("%s: Error sending reply\n", __FUNCTION__); } exit: HgfsServerInputExit(input); } /* *----------------------------------------------------------------------------- * * HgfsServerProcessRequest -- * * Dispatch an incoming packet (in packetIn) to a handler function. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerProcessRequest(void *context) { HgfsInputParam *input = (HgfsInputParam *)context; if (!input->request) { input->request = HSPU_GetMetaPacket(input->packet, &input->requestSize, input->transportSession->channelCbTable); } input->payload = (char *)input->request + input->payloadOffset; (*handlers[input->op].handler)(input); } /* *----------------------------------------------------------------------------- * * HgfsServerSessionReceive -- * * Dispatch an incoming packet (in packetIn) to a handler function. * * This function cannot fail; if something goes wrong, it returns * a packet containing only a reply header with error code. * * The handler function can send the reply packet either using * HgfsPacketSend helper functions. This function would return error * as a reply if the op handler do not return HGFS_ERROR_SUCCESS. * * NOTE: If any op handler needs to keep packetIn around for sending replies * at a later point (possibly in a different thread context), it should * make a copy of it. The validity of packetIn for the HGFS server is only * within the scope of this function. * * Definitions of Meta Packet, Data packet can be looked up in * hgfsChannelVmci.c * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerSessionReceive(HgfsPacket *packet, // IN: Hgfs Packet void *clientData) // IN: session info { HgfsTransportSessionInfo *transportSession = clientData; HgfsInternalStatus status; HgfsInputParam *input = NULL; ASSERT(transportSession); if (transportSession->state == HGFS_SESSION_STATE_CLOSED) { LOG(4, "%s: %d: Received packet after disconnected.\n", __FUNCTION__, __LINE__); return; } HgfsServerTransportSessionGet(transportSession); status = HgfsServerGetRequest(packet, transportSession, &input); if (HGFS_ERROR_INTERNAL == status) { LOG(4, "%s: %d: Error: packet invalid and cannot reply %d.\n ", __FUNCTION__, __LINE__, status); HgfsServerTransportSessionPut(transportSession); return; } HGFS_ASSERT_MINIMUM_OP(input->op); HGFS_ASSERT_CLIENT(input->op); if (HGFS_ERROR_SUCCESS == status) { HGFS_ASSERT_INPUT(input); if ((input->op < ARRAYSIZE(handlers)) && (handlers[input->op].handler != NULL) && (input->requestSize >= handlers[input->op].minReqSize)) { /* Initial validation passed, process the client request now. */ /* * Server will only handle the request asynchronously when both the * server and client support asynchronous IO, this is indicated by * bit HGFS_SESSION_ASYNC_IO_ENABLED in input->session->flags which * is negotiated when the session is created. */ if ((handlers[input->op].reqType == REQ_ASYNC) && (transportSession->channelCapabilities.flags & HGFS_CHANNEL_ASYNC) && (input->session->flags & HGFS_SESSION_ASYNC_IO_ENABLED)) { packet->state |= HGFS_STATE_ASYNC_REQUEST; } if (0 != (packet->state & HGFS_STATE_ASYNC_REQUEST)) { LOG(4, "%s: %d: @@Async\n", __FUNCTION__, __LINE__); #ifndef VMX86_TOOLS /* * Asynchronous processing is supported by the transport. * We can release mappings here and reacquire when needed. */ HSPU_PutMetaPacket(packet, transportSession->channelCbTable); input->request = NULL; HgfsServerAsyncInfoIncCount(&input->session->asyncRequestsInfo); if (gHgfsThreadpoolActive) { if (!HgfsThreadpool_QueueWorkItem(HgfsServerProcessRequest, input)) { LOG(4, "%s: %d: failed to queue item.\n", __FUNCTION__, __LINE__); HgfsServerProcessRequest(input); } } else { /* Remove pending requests during poweroff. */ Poll_Callback(POLL_CS_MAIN, POLL_FLAG_REMOVE_AT_POWEROFF, HgfsServerProcessRequest, input, POLL_REALTIME, 1000, NULL); } #else /* Tools code should never process request async. */ ASSERT(0); #endif } else { LOG(4, "%s: %d: ##Sync\n", __FUNCTION__, __LINE__); HgfsServerProcessRequest(input); } } else { /* * The input packet is smaller than the minimal size needed for the * operation. */ status = HGFS_ERROR_PROTOCOL; LOG(4, "%s: %d: Possible BUG! Malformed packet.\n", __FUNCTION__, __LINE__); } } /* Send error if we fail to process the op. */ if (HGFS_ERROR_SUCCESS != status) { LOG(4, "Error %d occurred parsing the packet\n", (uint32)status); HgfsServerCompleteRequest(status, 0, input); } /* * Contrary to Coverity analysis, storage pointed to by the variable * "input" is not leaked; it is freed either by HgfsServerProcessRequest * at the end of request processing or by HgfsServerCompleteRequest if * there is a protocol error. However, no Coverity annotation for * leaked_storage is added here because such an annotation cannot be * made specific to input; as a result, if any actual memory leaks were * to be introduced by a future change, the leaked_storage annotation * would cause such new leaks to be flagged as false positives. * * XXX - can something be done with Coverity function models so that * Coverity stops reporting this? */ } /* *----------------------------------------------------------------------------- * * HgfsServerTransportGetSessionInfo -- * * Scans the list of sessions and return the session with the specified * session id. * * Results: * A valid pointer to HgfsSessionInfo if there is a session with the * specified session id. NULL, otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsSessionInfo * HgfsServerTransportGetSessionInfo(HgfsTransportSessionInfo *transportSession, // IN: transport session info uint64 sessionId) // IN: session id { DblLnkLst_Links *curr; HgfsSessionInfo *session = NULL; ASSERT(transportSession); if (HGFS_INVALID_SESSION_ID == sessionId) { return NULL; } MXUser_AcquireExclLock(transportSession->sessionArrayLock); DblLnkLst_ForEach(curr, &transportSession->sessionArray) { session = DblLnkLst_Container(curr, HgfsSessionInfo, links); if (session->sessionId == sessionId) { HgfsServerSessionGet(session); break; } session = NULL; } MXUser_ReleaseExclLock(transportSession->sessionArrayLock); return session; } /* *----------------------------------------------------------------------------- * * HgfsServerTransportGetDefaultSession -- * * Returns default session if there is one, otherwise creates it. * XXX - this function should be moved to the HgfsServer file. * * Results: * HGFS_ERROR_SUCCESS and the session if found or created successfully * or an appropriate error if no memory or cannot add to the list of sessions. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerTransportGetDefaultSession(HgfsTransportSessionInfo *transportSession, // IN: transport HgfsSessionInfo **session) // OUT: session { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; HgfsSessionInfo *defaultSession; HgfsCreateSessionInfo info = { 0 }; defaultSession = HgfsServerTransportGetSessionInfo(transportSession, transportSession->defaultSessionId); if (NULL != defaultSession) { /* The default session already exists, we are done. */ goto exit; } /* * Create a new session if the default session doesn't exist. */ if (!HgfsServerAllocateSession(transportSession, info, &defaultSession)) { status = HGFS_ERROR_NOT_ENOUGH_MEMORY; goto exit; } status = HgfsServerTransportAddSessionToList(transportSession, defaultSession); if (HGFS_ERROR_SUCCESS != status) { LOG(4, "%s: Could not add session to the list.\n", __FUNCTION__); HgfsServerSessionPut(defaultSession); defaultSession = NULL; goto exit; } transportSession->defaultSessionId = defaultSession->sessionId; HgfsServerSessionGet(defaultSession); exit: *session = defaultSession; return status; } /* *----------------------------------------------------------------------------- * * HgfsServerTransportRemoveSessionFromList -- * * Unlinks the specified session info from the list. * * Note: The caller must acquire the sessionArrayLock in transportSession * before calling this function. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsServerTransportRemoveSessionFromList(HgfsTransportSessionInfo *transportSession, // IN: transport session info HgfsSessionInfo *session) // IN: session info { ASSERT(transportSession); ASSERT(session); DblLnkLst_Unlink1(&session->links); transportSession->numSessions--; HgfsServerSessionPut(session); } /* *----------------------------------------------------------------------------- * * HgfsServerTransportAddSessionToList -- * * Links the specified session info to the list. * * Results: * HGFS_ERROR_SUCCESS if the session is successfully added to the list, * HGFS_ERROR_TOO_MANY_SESSIONS if maximum number of sessions were already * added to the list. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerTransportAddSessionToList(HgfsTransportSessionInfo *transportSession, // IN: transport session info HgfsSessionInfo *session) // IN: session info { HgfsInternalStatus status = HGFS_ERROR_TOO_MANY_SESSIONS; ASSERT(transportSession); ASSERT(session); MXUser_AcquireExclLock(transportSession->sessionArrayLock); if (transportSession->numSessions == MAX_SESSION_COUNT) { goto quit; } DblLnkLst_LinkLast(&transportSession->sessionArray, &session->links); transportSession->numSessions++; HgfsServerSessionGet(session); status = HGFS_ERROR_SUCCESS; quit: MXUser_ReleaseExclLock(transportSession->sessionArrayLock); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerSharesDeleteStale -- * * This function iterates through all shared folders and removes all * deleted shared folders, removes them from notification package and * from the folders list. * * Note: this assumes that the list lock is already acquired. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerSharesDeleteStale(DblLnkLst_Links *newSharesList) // IN: new list of shares { DblLnkLst_Links *link, *nextElem; DblLnkLst_ForEachSafe(link, nextElem, &gHgfsSharedFoldersList) { HgfsSharedFolderProperties *currentShare = DblLnkLst_Container(link, HgfsSharedFolderProperties, links); Bool staleShare = TRUE; DblLnkLst_Links *linkNewShare, *nextNewShare; DblLnkLst_ForEachSafe(linkNewShare, nextNewShare, newSharesList) { HgfsSharedFolder *newShare = DblLnkLst_Container(linkNewShare, HgfsSharedFolder, links); ASSERT(newShare); if (strcmp(currentShare->name, newShare->name) == 0) { LOG(4, "%s: %s is still valid\n", __FUNCTION__, newShare->name); staleShare = FALSE; break; } } if (staleShare) { LOG(8, "%s: removing shared folder handle %#x\n", __FUNCTION__, currentShare->notificationHandle); if (!HgfsNotify_RemoveSharedFolder(currentShare->notificationHandle)) { LOG(4, "%s: Error: removing %d shared folder handle\n", __FUNCTION__, currentShare->notificationHandle); } DblLnkLst_Unlink1(link); free(currentShare->name); free(currentShare); } } } /* *----------------------------------------------------------------------------- * * HgfsServerShareAddInternal -- * * Add a new shared folder property entry if it is not in the list of shares. * * Note: this assumes that the list lock is already acquired. * * Results: * The share handle if entry was found HGFS_INVALID_FOLDER_HANDLE if not. * * Side effects: * May add a shared folders entry for change notifications. * *----------------------------------------------------------------------------- */ static HgfsSharedFolderHandle HgfsServerShareAddInternal(const char *shareName, // IN: shared folder name const char *sharePath) // IN: shared folder path { HgfsSharedFolderHandle handle = HGFS_INVALID_FOLDER_HANDLE; DblLnkLst_Links *link, *nextElem; DblLnkLst_ForEachSafe(link, nextElem, &gHgfsSharedFoldersList) { HgfsSharedFolderProperties *currentShare = DblLnkLst_Container(link, HgfsSharedFolderProperties, links); ASSERT(currentShare); if (strcmp(currentShare->name, shareName) == 0) { LOG(8, "%s: Share is not new\n", __FUNCTION__); handle = currentShare->notificationHandle; break; } } /* If the share is new then add it to the notification shares. */ if (handle == HGFS_INVALID_FOLDER_HANDLE) { handle = HgfsNotify_AddSharedFolder(sharePath, shareName); if (HGFS_INVALID_FOLDER_HANDLE != handle) { HgfsSharedFolderProperties *shareProps = (HgfsSharedFolderProperties *)Util_SafeMalloc(sizeof *shareProps); shareProps->notificationHandle = handle; shareProps->name = Util_SafeStrdup(shareName); DblLnkLst_Init(&shareProps->links); DblLnkLst_LinkLast(&gHgfsSharedFoldersList, &shareProps->links); } LOG(8, "%s: %s, %s, add hnd %#x\n",__FUNCTION__, (shareName ? shareName : "NULL"), (sharePath ? sharePath : "NULL"), handle); } return handle; } /* *----------------------------------------------------------------------------- * * HgfsServerShareAdd -- * * Add a new shared folder property entry if it is not in the list of shares. * * Note: this assumes that the list lock is already acquired. * * Results: * The shares handle if found or added. HGFS_INVALID_FOLDER_HANDLE otherwise. * * Side effects: * May add a shared folders entry for change notifications. * *----------------------------------------------------------------------------- */ static HgfsSharedFolderHandle HgfsServerShareAdd(const char *shareName, // IN: shared folder name const char *sharePath) // IN: shared folder path { HgfsSharedFolderHandle handle; LOG(8, "%s: entered\n", __FUNCTION__); if (!gHgfsDirNotifyActive) { LOG(8, "%s: notification disabled\n", __FUNCTION__); return HGFS_INVALID_FOLDER_HANDLE; } MXUser_AcquireExclLock(gHgfsSharedFoldersLock); handle = HgfsServerShareAddInternal(shareName, sharePath); MXUser_ReleaseExclLock(gHgfsSharedFoldersLock); LOG(8, "%s: exit(%#x)\n", __FUNCTION__, handle); return handle; } /* *----------------------------------------------------------------------------- * * HgfsServerSharesReset -- * * This is a callback function which is invoked by hgfsServerManagement * for every shared folder when something changed in shared folders * configuration. * The function any entries now not present as stale and removes them. * Any entries on the new list of shares not on the list of list of shares * will have new entries created and added to the list. * * Results: * None. * * Side effects: * May add an entry to known shared folders list. * *----------------------------------------------------------------------------- */ static void HgfsServerSharesReset(DblLnkLst_Links *newSharesList) // IN: List of new shares { DblLnkLst_Links *linkNewShare, *nextNewShare; LOG(8, "%s: entered\n", __FUNCTION__); if (!gHgfsDirNotifyActive) { LOG(8, "%s: notification disabled\n", __FUNCTION__); return; } MXUser_AcquireExclLock(gHgfsSharedFoldersLock); /* * Now we go through the shares properties list to * remove and delete those shares that are stale. */ HgfsServerSharesDeleteStale(newSharesList); /* * Iterate over the new shares and check for any not in the updated shares properties * list, as those will need a new share property created and added to the list. */ DblLnkLst_ForEachSafe(linkNewShare, nextNewShare, newSharesList) { HgfsSharedFolder *newShare = DblLnkLst_Container(linkNewShare, HgfsSharedFolder, links); ASSERT(newShare); HgfsServerShareAddInternal(newShare->name, newShare->path); } MXUser_ReleaseExclLock(gHgfsSharedFoldersLock); LOG(8, "%s: exit\n", __FUNCTION__); } /* *----------------------------------------------------------------------------- * * HgfsServerGetShareHandle -- * * The function returns shared folder notification handle for the specified * shared folder. * * Results: * HgfsSharedFolderHandle that corresponds to the shared folder. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static HgfsSharedFolderHandle HgfsServerGetShareHandle(const char *shareName) // IN: name of the shared folder { DblLnkLst_Links *link; HgfsSharedFolderHandle result = HGFS_INVALID_FOLDER_HANDLE; if (!gHgfsDirNotifyActive) { return HGFS_INVALID_FOLDER_HANDLE; } MXUser_AcquireExclLock(gHgfsSharedFoldersLock); DblLnkLst_ForEach(link, &gHgfsSharedFoldersList) { HgfsSharedFolderProperties *folder = DblLnkLst_Container(link, HgfsSharedFolderProperties, links); if (strcmp(folder->name, shareName) == 0) { result = folder->notificationHandle; break; } } MXUser_ReleaseExclLock(gHgfsSharedFoldersLock); return result; } /* *----------------------------------------------------------------------------- * * HgfsServerGetShareName -- * * Get the share name for a shared folder handle by looking at the * requested handle, finding the matching share (if any), and returning * the share's name. * * Results: * An Bool value indicating if the result is returned. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsServerGetShareName(HgfsSharedFolderHandle sharedFolder, // IN: Notify handle size_t *shareNameLen, // OUT: Name length char **shareName) // OUT: Share name { Bool result = FALSE; DblLnkLst_Links *link; if (!gHgfsDirNotifyActive) { return FALSE; } MXUser_AcquireExclLock(gHgfsSharedFoldersLock); DblLnkLst_ForEach(link, &gHgfsSharedFoldersList) { HgfsSharedFolderProperties *folder = DblLnkLst_Container(link, HgfsSharedFolderProperties, links); if (folder->notificationHandle == sharedFolder) { *shareName = Util_SafeStrdup(folder->name); result = TRUE; *shareNameLen = strlen(*shareName); break; } } MXUser_ReleaseExclLock(gHgfsSharedFoldersLock); return result; } /* *----------------------------------------------------------------------------- * * HgfsServer_InitState -- * * Initialize the global server state * * Results: * TRUE if succeeded, FALSE if failed. * * Side effects: * Memory allocation. * *----------------------------------------------------------------------------- */ Bool HgfsServer_InitState(const HgfsServerCallbacks **callbackTable, // IN/OUT: our callbacks HgfsServerConfig *serverCfgData, // IN: configurable settings HgfsServerMgrCallbacks *serverMgrData) // IN: mgr callback { Bool result = TRUE; ASSERT(callbackTable); /* Save any server manager data for logging state updates.*/ gHgfsMgrData = serverMgrData; if (NULL != serverCfgData) { gHgfsCfgSettings = *serverCfgData; } /* * Initialize the globals for handling the active shared folders. */ DblLnkLst_Init(&gHgfsSharedFoldersList); gHgfsSharedFoldersLock = MXUser_CreateExclLock("sharedFoldersLock", RANK_hgfsSharedFolders); if (!HgfsPlatformInit()) { LOG(4, "Could not initialize server platform specific \n"); result = FALSE; } if (result) { *callbackTable = &gHgfsServerCBTable; if (0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_NOTIFY_ENABLED)) { gHgfsDirNotifyActive = HgfsNotify_Init(&gHgfsServerNotifyCBTable) == HGFS_STATUS_SUCCESS; Log("%s: initialized notification %s.\n", __FUNCTION__, (gHgfsDirNotifyActive ? "active" : "inactive")); } if (0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_OPLOCK_MONITOR_ENABLED)) { if (!HgfsServerOplockInit()) { Log("%s: failed to init oplock module.\n", __FUNCTION__); HgfsServerOplockDestroy(); gHgfsCfgSettings.flags &= ~HGFS_CONFIG_OPLOCK_ENABLED; gHgfsCfgSettings.flags &= ~HGFS_CONFIG_OPLOCK_MONITOR_ENABLED; } } if (0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_THREADPOOL_ENABLED)) { gHgfsThreadpoolActive = HgfsThreadpool_Init() == HGFS_STATUS_SUCCESS; Log("%s: initialized threadpool %s.\n", __FUNCTION__, (gHgfsThreadpoolActive ? "active" : "inactive")); } if (0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_OPLOCK_MONITOR_ENABLED)) { if (!HgfsOplockMonitorInit()) { Log("%s: failed to init oplock monitor module.\n", __FUNCTION__); gHgfsCfgSettings.flags &= ~HGFS_CONFIG_OPLOCK_MONITOR_ENABLED; } } } else { HgfsServer_ExitState(); // Cleanup partially initialized state } return result; } /* *----------------------------------------------------------------------------- * * HgfsServer_ExitState -- * * Cleanup the global server state. * * This function should be called when all other HGFS threads stopped * running. Otherwise we'll be in trouble because this is where we delete * the node array lock. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsServer_ExitState(void) { if (0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_OPLOCK_MONITOR_ENABLED)) { HgfsOplockMonitorDestroy(); } if ( 0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_OPLOCK_ENABLED) || 0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_OPLOCK_MONITOR_ENABLED)) { HgfsServerOplockDestroy(); } if (gHgfsDirNotifyActive) { DblLnkLst_Links emptySharesList; DblLnkLst_Init(&emptySharesList); /* Make all existing shared folders stale and delete them. */ HgfsServerSharesReset(&emptySharesList); HgfsNotify_Exit(); gHgfsDirNotifyActive = FALSE; Log("%s: exit notification - inactive.\n", __FUNCTION__); } if (NULL != gHgfsSharedFoldersLock) { MXUser_DestroyExclLock(gHgfsSharedFoldersLock); gHgfsSharedFoldersLock = NULL; } if (gHgfsThreadpoolActive) { HgfsThreadpool_Exit(); gHgfsThreadpoolActive = FALSE; Log("%s: exit threadpool - inactive.\n", __FUNCTION__); } HgfsPlatformDestroy(); /* * Reset the server manager callbacks. */ gHgfsMgrData = NULL; } /* *----------------------------------------------------------------------------- * * HgfsServer_ShareAccessCheck -- * * Checks if the requested mode may be granted depending on read/write * permissions. * * Results: * An HgfsNameStatus value indicating the result is returned. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsServer_ShareAccessCheck(HgfsOpenMode accessMode, // IN: open mode to check Bool shareWriteable, // IN: share is writable Bool shareReadable) // IN: share is readable { /* * See if access is allowed in the requested mode. * * XXX We should be using bits instead of an enum for HgfsOpenMode. * Add it to the todo list. [bac] */ switch (HGFS_OPEN_MODE_ACCMODE(accessMode)) { case HGFS_OPEN_MODE_READ_ONLY: if (!shareReadable) { LOG(4, "%s: Read access denied\n", __FUNCTION__); return FALSE; } break; case HGFS_OPEN_MODE_WRITE_ONLY: if (!shareWriteable) { LOG(4, "%s: Write access denied\n", __FUNCTION__); return FALSE; } break; case HGFS_OPEN_MODE_READ_WRITE: if (!shareReadable || !shareWriteable) { LOG(4, "%s: Read/write access denied\n", __FUNCTION__); return FALSE; } break; default: LOG(0, "%s: Invalid mode %d\n", __FUNCTION__, accessMode); ASSERT(FALSE); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsGenerateSessionId -- * * Generates unique session id. * * Results: * Unique 64-bit value. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static uint64 HgfsGenerateSessionId(void) { #ifdef VM_X86_ANY return RDTSC(); #else uint64 sessionId; rqContext *rCtx = Random_QuickSeed((uint32)time(NULL)); sessionId = (uint64)Random_Quick(rCtx) << 32; sessionId |= Random_Quick(rCtx); free(rCtx); return sessionId; #endif } /* *----------------------------------------------------------------------------- * * HgfsServerSetSessionCapability -- * * Sets session capability for a specific operation code. * * Results: * TRUE is the capability for the operation has been changed. * FALSE if the operation is not represented in the capabilities array. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsServerSetSessionCapability(HgfsOp op, // IN: operation code HgfsOpCapFlags flags, // IN: flags that describe level of support HgfsSessionInfo *session) // IN/OUT: session to update { int i; Bool result = FALSE; for ( i = 0; i < ARRAYSIZE(session->hgfsSessionCapabilities); i++) { if (session->hgfsSessionCapabilities[i].op == op) { session->hgfsSessionCapabilities[i].flags = flags; result = TRUE; } } LOG(4, "%s: Setting capability flags %x for op code %d %s\n", __FUNCTION__, flags, op, result ? "succeeded" : "failed"); return result; } /* *----------------------------------------------------------------------------- * * HgfsServerResEnumInit -- * * Initialize an enumeration of all existing resources. * * Results: * The enumeration state object. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void * HgfsServerResEnumInit(void) { void *enumState = NULL; if (gHgfsMgrData != NULL && gHgfsMgrData->enumResources.init != NULL) { enumState = gHgfsMgrData->enumResources.init(); } return enumState; } /* *----------------------------------------------------------------------------- * * HgfsServerResEnumGet -- * * Enumerates the next resource associated with the enumeration state. * * Results: * TRUE on success and . * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsServerResEnumGet(void *enumState, // IN/OUT: enumeration state char const **enumResName, // OUT: enumerated resource name size_t *enumResNameLen, // OUT: enumerated resource name len Bool *enumResDone) // OUT: enumerated resources done { Bool success = FALSE; if (gHgfsMgrData != NULL && gHgfsMgrData->enumResources.get != NULL) { success = gHgfsMgrData->enumResources.get(enumState, enumResName, enumResNameLen, enumResDone); } return success; } /* *----------------------------------------------------------------------------- * * HgfsServerResEnumExit -- * * Exit the enumeration of all existing resources. * * Results: * TRUE on success, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsServerResEnumExit(void *enumState) // IN/OUT: enumeration state { Bool success = FALSE; if (gHgfsMgrData != NULL && gHgfsMgrData->enumResources.exit != NULL) { success = gHgfsMgrData->enumResources.exit(enumState); } return success; } /* *----------------------------------------------------------------------------- * * HgfsServerEnumerateSharedFolders -- * * Enumerates all existing shared folders and registers shared folders with * directory notification package. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsServerEnumerateSharedFolders(void) { void *state; Bool success = FALSE; LOG(8, "%s: entered\n", __FUNCTION__); state = HgfsServerResEnumInit(); if (NULL != state) { Bool done; do { char const *shareName; size_t len; success = HgfsServerResEnumGet(state, &shareName, &len, &done); if (success && !done) { HgfsSharedFolderHandle handle; char const *sharePath; size_t sharePathLen; HgfsNameStatus nameStatus; nameStatus = HgfsServerPolicy_GetSharePath(shareName, len, HGFS_OPEN_MODE_READ_ONLY, &sharePathLen, &sharePath); if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { LOG(8, "%s: registering share %s path %s\n", __FUNCTION__, shareName, sharePath); handle = HgfsServerShareAdd(shareName, sharePath); success = handle != HGFS_INVALID_FOLDER_HANDLE; LOG(8, "%s: registering share %s hnd %#x\n", __FUNCTION__, shareName, handle); } } } while (!done && success); HgfsServerResEnumExit(state); } LOG(8, "%s: exit %d\n", __FUNCTION__, success); return success; } /* *----------------------------------------------------------------------------- * * HgfsServerSessionConnect -- * * Initialize a new client session. * * Allocate HgfsTransportSessionInfo and initialize it. * * Results: * TRUE always. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsServerSessionConnect(void *transportData, // IN: transport session context HgfsServerChannelCallbacks *channelCbTable, // IN: Channel callbacks HgfsServerChannelData *channelCapabilities, // IN: channel capabilities void **transportSessionData) // OUT: server session context { ASSERT(transportSessionData); LOG(4, "%s: initting.\n", __FUNCTION__); *transportSessionData = HgfsServerTransportInit(transportData, channelCbTable, channelCapabilities); return TRUE; } /* *---------------------------------------------------------------------------- * * HgfsServerTransportInit -- * * Init a transport session. * * Allocated and initialize the transport session. * * Results: * The initialized transport session object. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static HgfsTransportSessionInfo * HgfsServerTransportInit(void *transportData, // IN: transport session context HgfsServerChannelCallbacks *channelCbTable, // IN: Channel callbacks HgfsServerChannelData *channelCapabilities) // IN: channel capabilities { HgfsTransportSessionInfo *transportSession; transportSession = Util_SafeCalloc(1, sizeof *transportSession); transportSession->transportData = transportData; transportSession->channelCbTable = channelCbTable; transportSession->type = HGFS_SESSION_TYPE_REGULAR; transportSession->state = HGFS_SESSION_STATE_OPEN; transportSession->channelCapabilities = *channelCapabilities; transportSession->numSessions = 0; transportSession->sessionArrayLock = MXUser_CreateExclLock("HgfsSessionArrayLock", RANK_hgfsSessionArrayLock); DblLnkLst_Init(&transportSession->sessionArray); transportSession->defaultSessionId = HGFS_INVALID_SESSION_ID; Atomic_Write(&transportSession->refCount, 0); /* Give our session a reference to hold while we are open. */ HgfsServerTransportSessionGet(transportSession); return transportSession; } /* *---------------------------------------------------------------------------- * * HgfsServerTransportExit -- * * Exit by destroying the transport session. * * Free session info data if no reference. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsServerTransportExit(HgfsTransportSessionInfo *transportSession) // IN: transport session context { DblLnkLst_Links *curr, *next; ASSERT(Atomic_Read(&transportSession->refCount) == 0); DblLnkLst_ForEachSafe(curr, next, &transportSession->sessionArray) { HgfsSessionInfo *session = DblLnkLst_Container(curr, HgfsSessionInfo, links); HgfsServerTransportRemoveSessionFromList(transportSession, session); HgfsServerSessionPut(session); } MXUser_DestroyExclLock(transportSession->sessionArrayLock); free(transportSession); } /* *----------------------------------------------------------------------------- * * HgfsServerAsyncInfoInit -- * * Initialize the async request info for a session. * * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerAsyncInfoInit(HgfsAsyncRequestInfo *info) // IN/OUT: info { Atomic_Write(&info->requestCount, 0); info->lock = MXUser_CreateExclLock("asyncLock", RANK_hgfsSharedFolders); info->requestCountIsZero = MXUser_CreateCondVarExclLock(info->lock); } /* *----------------------------------------------------------------------------- * * HgfsServerAsyncInfoExit -- * * Destroy the async request info for a session session. * * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerAsyncInfoExit(HgfsAsyncRequestInfo *info) // IN/OUT: info { ASSERT(Atomic_Read(&info->requestCount) == 0); if (NULL != info->lock) { MXUser_DestroyExclLock(info->lock); info->lock = NULL; } if (NULL != info->requestCountIsZero) { MXUser_DestroyCondVar(info->requestCountIsZero); info->requestCountIsZero = NULL; } } /* *----------------------------------------------------------------------------- * * HgfsServerAsyncWaitForAllRequestsDone -- * * Wait for all the async info requests to be done. * * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerAsyncWaitForAllRequestsDone(HgfsAsyncRequestInfo *info) // IN: info { MXUser_AcquireExclLock(info->lock); while (Atomic_Read(&info->requestCount)) { MXUser_WaitCondVarExclLock(info->lock, info->requestCountIsZero); } MXUser_ReleaseExclLock(info->lock); } /* *----------------------------------------------------------------------------- * * HgfsServerAsyncSignalAllRequestsDone -- * * Signal that all the async info requests are done. * * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerAsyncSignalAllRequestsDone(HgfsAsyncRequestInfo *info) // IN: info { MXUser_AcquireExclLock(info->lock); MXUser_BroadcastCondVar(info->requestCountIsZero); MXUser_ReleaseExclLock(info->lock); } /* *----------------------------------------------------------------------------- * * HgfsServerAsyncInfoDecCount -- * * Decrement the async info request count for a session. * * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerAsyncInfoDecCount(HgfsAsyncRequestInfo *info) // IN/OUT: info { if (Atomic_ReadDec32(&info->requestCount) == 1) { HgfsServerAsyncSignalAllRequestsDone(info); } } #ifndef VMX86_TOOLS /* *----------------------------------------------------------------------------- * * HgfsServerAsyncInfoIncCount -- * * Increment the async info request count for a session. * * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerAsyncInfoIncCount(HgfsAsyncRequestInfo *info) // IN/OUT: info { Atomic_Inc(&info->requestCount); } #endif // VMX86_TOOLS /* *----------------------------------------------------------------------------- * * HgfsServerAllocateSession -- * * Initialize a new Hgfs session. * * Allocate HgfsSessionInfo and initialize it. Create the nodeArray and * searchArray for the session. * * Results: * TRUE on success, FALSE otherwise. * * Side effects: * Allocates and initializes new session info. * *----------------------------------------------------------------------------- */ static Bool HgfsServerAllocateSession(HgfsTransportSessionInfo *transportSession, // IN: HgfsCreateSessionInfo createSessionInfo, // IN: HgfsSessionInfo **sessionData) // OUT: { int i; HgfsSessionInfo *session; HgfsOpCapFlags flags; LOG(8, "%s: entered\n", __FUNCTION__); ASSERT(transportSession); session = Util_SafeCalloc(1, sizeof *session); /* * Initialize all our locks first as these can fail. */ session->fileIOLock = MXUser_CreateExclLock("HgfsFileIOLock", RANK_hgfsFileIOLock); session->nodeArrayLock = MXUser_CreateExclLock("HgfsNodeArrayLock", RANK_hgfsNodeArrayLock); session->searchArrayLock = MXUser_CreateExclLock("HgfsSearchArrayLock", RANK_hgfsSearchArrayLock); session->sessionId = HgfsGenerateSessionId(); session->state = HGFS_SESSION_STATE_OPEN; DblLnkLst_Init(&session->links); session->isInactive = TRUE; session->transportSession = transportSession; session->numInvalidationAttempts = 0; if ( createSessionInfo.maxPacketSize < transportSession->channelCapabilities.maxPacketSize) { session->maxPacketSize = createSessionInfo.maxPacketSize; } else { session->maxPacketSize = transportSession->channelCapabilities.maxPacketSize; } session->flags |= HGFS_SESSION_MAXPACKETSIZE_VALID; /* * If the server is enabled for processing oplocks and the client * is requesting to use them, then report back to the client oplocks * are enabled by propagating the session flag. */ if ((0 != (createSessionInfo.flags & HGFS_SESSION_OPLOCK_ENABLED)) && (0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_OPLOCK_ENABLED))) { session->flags |= HGFS_SESSION_OPLOCK_ENABLED; } /* * Initialize the node handling components. */ DblLnkLst_Init(&session->nodeFreeList); DblLnkLst_Init(&session->nodeCachedList); /* Allocate array of FileNodes and add them to free list. */ session->numNodes = NUM_FILE_NODES; session->nodeArray = Util_SafeCalloc(session->numNodes, sizeof (HgfsFileNode)); session->numCachedOpenNodes = 0; session->numCachedLockedNodes = 0; for (i = 0; i < session->numNodes; i++) { DblLnkLst_Init(&session->nodeArray[i].links); /* Append at the end of the list. */ DblLnkLst_LinkLast(&session->nodeFreeList, &session->nodeArray[i].links); } /* * Initialize the search handling components. */ /* Initialize search freelist. */ DblLnkLst_Init(&session->searchFreeList); /* Give our session a reference to hold while we are open. */ Atomic_Write(&session->refCount, 1); /* Allocate array of searches and add them to free list. */ session->numSearches = NUM_SEARCHES; session->searchArray = Util_SafeCalloc(session->numSearches, sizeof (HgfsSearch)); for (i = 0; i < session->numSearches; i++) { DblLnkLst_Init(&session->searchArray[i].links); /* Append at the end of the list. */ DblLnkLst_LinkLast(&session->searchFreeList, &session->searchArray[i].links); } /* Initialize the async request info.*/ HgfsServerAsyncInfoInit(&session->asyncRequestsInfo); /* Get common to all sessions capabiities. */ HgfsServerGetDefaultCapabilities(session->hgfsSessionCapabilities, &session->numberOfCapabilities); if (transportSession->channelCapabilities.flags & HGFS_CHANNEL_SHARED_MEM) { flags = HGFS_OP_CAPFLAG_IS_SUPPORTED; if ( (0 != (createSessionInfo.flags & HGFS_SESSION_ASYNC_IO_ENABLED)) && gHgfsThreadpoolActive) { if (HgfsThreadpool_Activate()) { session->flags |= HGFS_SESSION_ASYNC_IO_ENABLED; flags |= HGFS_SESSION_ASYNC_IO_ENABLED; LOG(8, "%s: threadpool is enabled\n", __FUNCTION__); } else { HgfsThreadpool_Exit(); gHgfsThreadpoolActive = FALSE; Log("%s: failed to activate the threadpool\n", __FUNCTION__); } } HgfsServerSetSessionCapability(HGFS_OP_READ_FAST_V4, flags, session); HgfsServerSetSessionCapability(HGFS_OP_WRITE_FAST_V4, flags, session); if (gHgfsDirNotifyActive) { LOG(8, "%s: notify is enabled\n", __FUNCTION__); if (HgfsServerEnumerateSharedFolders()) { HgfsServerSetSessionCapability(HGFS_OP_SET_WATCH_V4, HGFS_OP_CAPFLAG_IS_SUPPORTED, session); HgfsServerSetSessionCapability(HGFS_OP_REMOVE_WATCH_V4, HGFS_OP_CAPFLAG_IS_SUPPORTED, session); session->flags |= HGFS_SESSION_CHANGENOTIFY_ENABLED; } else { HgfsServerSetSessionCapability(HGFS_OP_SET_WATCH_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED, session); HgfsServerSetSessionCapability(HGFS_OP_REMOVE_WATCH_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED, session); } LOG(8, "%s: session notify capability is %s\n", __FUNCTION__, (session->flags & HGFS_SESSION_CHANGENOTIFY_ENABLED ? "enabled" : "disabled")); } HgfsServerSetSessionCapability(HGFS_OP_SEARCH_READ_V4, HGFS_OP_CAPFLAG_IS_SUPPORTED, session); } if (0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_OPLOCK_MONITOR_ENABLED)) { /* Allocate symlink check status cache. */ session->symlinkCache = HgfsCache_Alloc(HgfsCacheRemoveLRUCb); /* Allocate file attributes cache. */ session->fileAttrCache = HgfsCache_Alloc(HgfsCacheRemoveLRUCb); } *sessionData = session; Log("%s: init session %p id %"FMT64"x\n", __FUNCTION__, session, session->sessionId); return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsDisconnectSessionInt -- * * Disconnect a client session. * * Mark the session as closed as we are in the process of teardown * of the session. No more new requests should be processed. We would * start draining any outstanding pending operations at this point. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsDisconnectSessionInt(HgfsSessionInfo *session) // IN: session context { LOG(8, "%s: entered\n", __FUNCTION__); ASSERT(session); ASSERT(session->nodeArray); ASSERT(session->searchArray); session->state = HGFS_SESSION_STATE_CLOSED; LOG(8, "%s: exit\n", __FUNCTION__); } /* *----------------------------------------------------------------------------- * * HgfsServerSessionDisconnect -- * * Disconnect a client session. * * Mark the session as closed as we are in the process of teardown * of the session. No more new requests should be processed. We would * start draining any outstanding pending operations at this point. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerSessionDisconnect(void *clientData) // IN: session context { HgfsTransportSessionInfo *transportSession = clientData; DblLnkLst_Links *curr, *next; LOG(8, "%s: entered\n", __FUNCTION__); ASSERT(transportSession); MXUser_AcquireExclLock(transportSession->sessionArrayLock); DblLnkLst_ForEachSafe(curr, next, &transportSession->sessionArray) { HgfsSessionInfo *session = DblLnkLst_Container(curr, HgfsSessionInfo, links); HgfsDisconnectSessionInt(session); } MXUser_ReleaseExclLock(transportSession->sessionArrayLock); transportSession->state = HGFS_SESSION_STATE_CLOSED; LOG(8, "%s: exit\n", __FUNCTION__); } /* *----------------------------------------------------------------------------- * * HgfsServerSessionClose -- * * Closes a client session. * * Remvoing the final reference will free the session's nodeArray * and seachArrary, and finally free the session object. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerSessionClose(void *clientData) // IN: session context { HgfsTransportSessionInfo *transportSession = clientData; LOG(8, "%s: entered\n", __FUNCTION__); ASSERT(transportSession); ASSERT(transportSession->state == HGFS_SESSION_STATE_CLOSED); /* Remove, typically, the last reference, will teardown everything. */ HgfsServerTransportSessionPut(transportSession); LOG(8, "%s: exit\n", __FUNCTION__); } /* *----------------------------------------------------------------------------- * * HgfsServerExitSessionInternal -- * * Destroys a session. * * Free the session's nodeArray and seachArrary. Free the session. * * The caller must have previously acquired the global sessions lock. * * Results: * TRUE on success, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerExitSessionInternal(HgfsSessionInfo *session) // IN: session context { int i; ASSERT(session); ASSERT(session->nodeArray); ASSERT(session->searchArray); ASSERT(session->state == HGFS_SESSION_STATE_CLOSED); /* Check and remove any notification handles we have for this session. */ if (session->flags & HGFS_SESSION_CHANGENOTIFY_ENABLED) { LOG(8, "%s: calling notify component to disconnect\n", __FUNCTION__); /* * This routine will synchronize itself with notification generator. * Therefore, it will remove subscribers and prevent the event generator * from generating any new events while it locks the subscribers lists. * New events will continue once more but with the updated subscriber list * that will not contain this session. */ HgfsNotify_RemoveSessionSubscribers(session); } MXUser_AcquireExclLock(session->nodeArrayLock); Log("%s: teardown session %p id 0x%"FMT64"x\n", __FUNCTION__, session, session->sessionId); /* Recycle all nodes that are still in use, then destroy the node pool. */ for (i = 0; i < session->numNodes; i++) { HgfsHandle handle; if (session->nodeArray[i].state == FILENODE_STATE_UNUSED) { continue; } handle = HgfsFileNode2Handle(&session->nodeArray[i]); HgfsRemoveFromCacheInternal(handle, session); HgfsFreeFileNodeInternal(handle, session); } free(session->nodeArray); session->nodeArray = NULL; MXUser_ReleaseExclLock(session->nodeArrayLock); /* * Recycle all searches that are still in use, then destroy the * search pool. */ MXUser_AcquireExclLock(session->searchArrayLock); for (i = 0; i < session->numSearches; i++) { if (DblLnkLst_IsLinked(&session->searchArray[i].links)) { continue; } HgfsRemoveSearchInternal(&session->searchArray[i], session); } free(session->searchArray); session->searchArray = NULL; MXUser_ReleaseExclLock(session->searchArrayLock); if (gHgfsThreadpoolActive) { HgfsThreadpool_Deactivate(); } /* Teardown the locks for the sessions and destroy itself. */ MXUser_DestroyExclLock(session->nodeArrayLock); MXUser_DestroyExclLock(session->searchArrayLock); MXUser_DestroyExclLock(session->fileIOLock); /* Teardown the async request info.*/ HgfsServerAsyncInfoExit(&session->asyncRequestsInfo); free(session); } /* *----------------------------------------------------------------------------- * * HgfsServer_GetHandleCounter -- * * Return file handle counter. This is used by the checkpointing code to * checkpoint this value so we avoid the risk of handle collision. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ uint32 HgfsServer_GetHandleCounter(void) { return HgfsServerGetHandleCounter(); } /* *----------------------------------------------------------------------------- * * HgfsServer_SetHandleCounter -- * * Set the file handle counter. This is used by the checkpointing code to * restore this value so we avoid the risk of handle collision. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsServer_SetHandleCounter(uint32 newHandleCounter) { HgfsServerInitHandleCounter(newHandleCounter); } /* *---------------------------------------------------------------------------- * * HgfsServerSessionSendComplete -- * * This is called by the Transport when it is done sending the packet. * Free the buffer. If we allocate buffers per session we have the session * that the buffer belongs too. * * Results: * None. * * Side effects: * Frees the packet buffer. * *--------------------------------------------------------------------------- */ void HgfsServerSessionSendComplete(HgfsPacket *packet, // IN/OUT: Hgfs packet void *clientData) // IN: session info { HgfsTransportSessionInfo *transportSession = clientData; if (0 != (packet->state & HGFS_STATE_CLIENT_REQUEST)) { HSPU_PutMetaPacket(packet, transportSession->channelCbTable); HSPU_PutReplyPacket(packet, transportSession->channelCbTable); HSPU_PutDataPacketBuf(packet, transportSession->channelCbTable); } else { if (packet->metaPacketIsAllocated) { free(packet->metaPacket); } free(packet); } } /* *---------------------------------------------------------------------------- * * HgfsServerSessionQuiesce -- * * The function is called when VM is about to take a snapshot and * when creation of the snapshot completed. When the freeze is TRUE the * function quiesces all asynchronous and background activity to prevent * interactions with snapshots and waits until there is no such activity. * When freeze is FALSE the function restarts background activity that * has been suspended previously. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsServerSessionQuiesce(void *clientData, // IN: transport and session HgfsQuiesceOp quiesceOp) // IN: operation { HgfsTransportSessionInfo *transportSession = clientData; DblLnkLst_Links *curr; LOG(4, "%s: Beginning\n", __FUNCTION__); MXUser_AcquireExclLock(transportSession->sessionArrayLock); DblLnkLst_ForEach(curr, &transportSession->sessionArray) { HgfsSessionInfo *session = DblLnkLst_Container(curr, HgfsSessionInfo, links); switch(quiesceOp) { case HGFS_QUIESCE_CHANNEL_FREEZE: /* * The channel is still alive now, it's the right time to * finish all asynchronous IO. */ if (gHgfsThreadpoolActive) { HgfsThreadpool_Deactivate(); } break; case HGFS_QUIESCE_FREEZE: /* Suspend background activity. */ LOG(8, "%s: Halt file system activity for session %p\n", __FUNCTION__, session); if (gHgfsDirNotifyActive) { HgfsNotify_Deactivate(HGFS_NOTIFY_REASON_SERVER_SYNC, session); } if (gHgfsThreadpoolActive) { HgfsThreadpool_Deactivate(); } HgfsServerAsyncWaitForAllRequestsDone(&session->asyncRequestsInfo); break; case HGFS_QUIESCE_THAW: /* Resume background activity. */ LOG(8, "%s: Resume file system activity for session %p\n", __FUNCTION__, session); if (gHgfsDirNotifyActive) { HgfsNotify_Activate(HGFS_NOTIFY_REASON_SERVER_SYNC, session); } if (gHgfsThreadpoolActive) { if (!HgfsThreadpool_Activate()) { HgfsThreadpool_Exit(); gHgfsThreadpoolActive = FALSE; Log("%s: failed to resume the threadpool\n", __FUNCTION__); } } break; default: NOT_REACHED(); } } MXUser_ReleaseExclLock(transportSession->sessionArrayLock); LOG(4, "%s: Ending\n", __FUNCTION__); } /* *---------------------------------------------------------------------------- * * HgfsPacketSend -- * * Send the packet. * * Results: * TRUE on success, FALSE on error. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static Bool HgfsPacketSend(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsTransportSessionInfo *transportSession, // IN: transport HgfsSessionInfo *session, // IN: session info HgfsSendFlags flags) // IN: send flags { Bool result = FALSE; Bool asyncClientRequest = (0 != (packet->state & HGFS_STATE_CLIENT_REQUEST) && 0 != (packet->state & HGFS_STATE_ASYNC_REQUEST)); ASSERT(packet); ASSERT(transportSession); if (transportSession->state == HGFS_SESSION_STATE_OPEN) { ASSERT(transportSession->type == HGFS_SESSION_TYPE_REGULAR); result = transportSession->channelCbTable->send(transportSession->transportData, packet, flags); } if (asyncClientRequest) { ASSERT(session); HgfsServerAsyncInfoDecCount(&session->asyncRequestsInfo); } return result; } /* *----------------------------------------------------------------------------- * * HgfsInvalidateSessionObjects -- * * Iterates over all nodes and searches, invalidating and removing those * that are no longer within a share. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsInvalidateSessionObjects(DblLnkLst_Links *shares, // IN: List of new shares HgfsSessionInfo *session) // IN: Session info { unsigned int i; ASSERT(shares); ASSERT(session); ASSERT(session->nodeArray); ASSERT(session->searchArray); LOG(4, "%s: Beginning\n", __FUNCTION__); MXUser_AcquireExclLock(session->nodeArrayLock); /* * Iterate over each node, skipping those that are unused. For each node, * if its filename is no longer within a share, remove it. */ for (i = 0; i < session->numNodes; i++) { HgfsHandle handle; DblLnkLst_Links *l; if (session->nodeArray[i].state == FILENODE_STATE_UNUSED) { continue; } handle = HgfsFileNode2Handle(&session->nodeArray[i]); LOG(4, "%s: Examining node with fd %d (%s)\n", __FUNCTION__, handle, session->nodeArray[i].utf8Name); /* For each share, is the node within the share? */ for (l = shares->next; l != shares; l = l->next) { HgfsSharedFolder *share; share = DblLnkLst_Container(l, HgfsSharedFolder, links); ASSERT(share); if (strcmp(session->nodeArray[i].shareInfo.rootDir, share->path) == 0) { LOG(4, "%s: Node is still valid\n", __FUNCTION__); break; } } /* If the node wasn't found in any share, remove it. */ if (l == shares) { LOG(4, "%s: Node is invalid, removing\n", __FUNCTION__); if (!HgfsRemoveFromCacheInternal(handle, session)) { LOG(4, "%s: Could not remove node with " "fh %d from the cache.\n", __FUNCTION__, handle); } else { HgfsFreeFileNodeInternal(handle, session); } } } MXUser_ReleaseExclLock(session->nodeArrayLock); MXUser_AcquireExclLock(session->searchArrayLock); /* * Iterate over each search, skipping those that are on the free list. For * each search, if its base name is no longer within a share, remove it. */ for (i = 0; i < session->numSearches; i++) { DblLnkLst_Links *l; if (DblLnkLst_IsLinked(&session->searchArray[i].links)) { continue; } if (HgfsSearchIsBaseNameSpace(&session->searchArray[i])) { /* Skip search of the base name space. Maybe stale but it is okay. */ continue; } LOG(4, "%s: Examining search (%s)\n", __FUNCTION__, session->searchArray[i].utf8Dir); /* For each share, is the search within the share? */ for (l = shares->next; l != shares; l = l->next) { HgfsSharedFolder *share; share = DblLnkLst_Container(l, HgfsSharedFolder, links); ASSERT(share); if (strcmp(session->searchArray[i].shareInfo.rootDir, share->path) == 0) { LOG(4, "%s: Search is still valid\n", __FUNCTION__); break; } } /* If the node wasn't found in any share, remove it. */ if (l == shares) { LOG(4, "%s: Search is invalid, removing\n", __FUNCTION__); HgfsRemoveSearchInternal(&session->searchArray[i], session); } } MXUser_ReleaseExclLock(session->searchArrayLock); HgfsCache* caches[] = {session->symlinkCache, session->fileAttrCache }; for (i = 0; i < sizeof(caches) / sizeof(caches[0]); i++) { const void **keys = NULL; size_t nkeys; int keyIdx; if (!caches[i]) { continue; } MXUser_AcquireExclLock(caches[i]->lock); HashTable_KeyArray(caches[i]->hashTable, &keys, &nkeys); MXUser_ReleaseExclLock(caches[i]->lock); for (keyIdx = 0; keyIdx < nkeys; keyIdx++) { DblLnkLst_Links *l; const char *name = (const char *)keys[keyIdx]; for (l = shares->next; l != shares; l = l->next) { HgfsSharedFolder *share; share = DblLnkLst_Container(l, HgfsSharedFolder, links); if (strncmp(name, share->path, strlen(name)) == 0) { break; } } if (l == shares) { LOG(4, "%s: Remove %s from cache\n", __FUNCTION__, name); HgfsCache_Invalidate(caches[i], name); } } free((void *)keys); } LOG(4, "%s: Ending\n", __FUNCTION__); } /* *----------------------------------------------------------------------------- * * HgfsServerSessionInvalidateObjects -- * * Iterates over all sessions and invalidate session objects for the shares * removed. * * Caller guarantees that the sessions won't go away under us, so no locks * needed. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsServerSessionInvalidateObjects(void *clientData, // IN: DblLnkLst_Links *shares) // IN: List of new shares { HgfsTransportSessionInfo *transportSession = clientData; DblLnkLst_Links *curr; LOG(4, "%s: Beginning\n", __FUNCTION__); ASSERT(transportSession); MXUser_AcquireExclLock(transportSession->sessionArrayLock); DblLnkLst_ForEach(curr, &transportSession->sessionArray) { HgfsSessionInfo *session = DblLnkLst_Container(curr, HgfsSessionInfo, links); HgfsServerSessionGet(session); HgfsInvalidateSessionObjects(shares, session); HgfsServerSessionPut(session); } MXUser_ReleaseExclLock(transportSession->sessionArrayLock); /* Now invalidate any stale shares and add any new ones. */ HgfsServerSharesReset(shares); LOG(4, "%s: Ending\n", __FUNCTION__); } /* *----------------------------------------------------------------------------- * * HgfsServerSessionInvalidateInactiveSessions -- * * Iterates over all sessions and invalidate all inactive session objects. * * Following clock algorithm is used to determine whether the session object * is inactive or not. * * When this function is called, the HGFS server manager will iterate * over all the sessions belonging to this manager. Each session is marked * as inactive. Whenever a message is processed for a session, that * session is marked as active. When this function is called the next time, * any sessions that are still inactive will be invalidated. * * Caller guarantees that the sessions won't go away under us, so no locks * needed. * * Results: * Number of active sessions remaining inside the HGFS server. * * Side effects: * None * *----------------------------------------------------------------------------- */ uint32 HgfsServerSessionInvalidateInactiveSessions(void *clientData) // IN: { HgfsTransportSessionInfo *transportSession = clientData; uint32 numActiveSessionsLeft = 0; DblLnkLst_Links shares, *curr, *next; ASSERT(transportSession); MXUser_AcquireExclLock(transportSession->sessionArrayLock); DblLnkLst_Init(&shares); DblLnkLst_ForEachSafe(curr, next, &transportSession->sessionArray) { HgfsSessionInfo *session = DblLnkLst_Container(curr, HgfsSessionInfo, links); HgfsServerSessionGet(session); session->numInvalidationAttempts++; numActiveSessionsLeft++; /* * Check if the session is inactive. If the session is inactive, then * invalidate the session objects. */ if (session->isInactive) { if (session->numInvalidationAttempts == MAX_SESSION_INVALIDATION_ATTEMPTS) { LOG(4, "%s: closing inactive session %"FMT64"x\n", __FUNCTION__, session->sessionId); session->state = HGFS_SESSION_STATE_CLOSED; HgfsServerTransportRemoveSessionFromList(transportSession, session); /* * We need to reduce the refcount by 1 since we want to * destroy the session. */ numActiveSessionsLeft--; HgfsServerSessionPut(session); } else { HgfsInvalidateSessionObjects(&shares, session); } } else { session->isInactive = TRUE; session->numInvalidationAttempts = 0; } HgfsServerSessionPut(session); } MXUser_ReleaseExclLock(transportSession->sessionArrayLock); return numActiveSessionsLeft; } /* *----------------------------------------------------------------------------- * * HgfsServerStatFs -- * * Calls on the wiper library to return the number of free bytes and * total bytes on the filesystem underlying the given pathname. * * Results: * TRUE if successful: freeBytes and totalBytes have been written to. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsServerStatFs(const char *pathName, // IN: Path we're interested in size_t pathLength, // IN: Length of path uint64 *freeBytes, // OUT: Free bytes on volume uint64 *totalBytes) // OUT: Total bytes on volume { WiperPartition p; unsigned char *wiperError; ASSERT(pathName); ASSERT(freeBytes); ASSERT(totalBytes); Wiper_Init(NULL); /* * Confidence checks. If length is good, assume well-formed drive path * (i.e. "C:\..." or "\\abc..."). Note that we throw out shares that * exactly equal p.mountPoint's size because we won't have room for a null * delimiter on copy. Allow 0 length drives so that hidden feature "" can * work. */ if (pathLength >= sizeof p.mountPoint) { LOG(4, "%s: could not get the volume name\n", __FUNCTION__); return FALSE; } /* Now call the wiper lib to get space information. */ Str_Strcpy(p.mountPoint, pathName, sizeof p.mountPoint); wiperError = WiperSinglePartition_GetSpace(&p, NULL, freeBytes, totalBytes); if (strlen(wiperError) > 0) { LOG(4, "%s: error using wiper lib: %s\n", __FUNCTION__, wiperError); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsOplockFileChangeCb -- * * The callback is invoked by the oplock when detecting file/directory is * changed. * This simply calls back to the cache's invalidate function. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsOplockFileChangeCb(HgfsSessionInfo *session, // IN: Session info void *data) // IN: Path { // There is no need to explicitly invoke HgfsOplockUnmonitorFileChange. if (NULL != session->symlinkCache) { HgfsCache_Invalidate(session->symlinkCache, data); } if (NULL != session->fileAttrCache) { HgfsCache_Invalidate(session->fileAttrCache, data); } free(data); } /* *----------------------------------------------------------------------------- * * HgfsCacheRemoveLRUCb -- * * The callback is invoked by the cache when removing the LRU entry. * This simply calls back to the oplock to unmonitor the file/directory * change event. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsCacheRemoveLRUCb(void *data) // IN { HgfsOplockUnmonitorFileChange(((HOM_HANDLE *)data)[0]); } /* *----------------------------------------------------------------------------- * * HgfsServerGetLocalNameInfo -- * * Construct local name based on the crossplatform CPName for the file and the * share information. * * The name returned is allocated and must be freed by the caller. * The name length is optionally returned. * * Results: * A status code indicating either success (correspondent share exists) or * a failure status. * * Side effects: * Memory allocation in the success case * *----------------------------------------------------------------------------- */ static HgfsNameStatus HgfsServerGetLocalNameInfo(const char *cpName, // IN: Cross-platform filename to check size_t cpNameSize, // IN: Size of name cpName uint32 caseFlags, // IN: Case-sensitivity flags HgfsSessionInfo *session,// IN: Session info HgfsShareInfo *shareInfo,// OUT: properties of the shared folder char **bufOut, // OUT: File name in local fs size_t *outLen) // OUT: Length of name out optional { HgfsNameStatus nameStatus; const char *inEnd; const char *next; char *myBufOut; char *convertedMyBufOut; char *out; size_t outSize; size_t myBufOutLen; size_t convertedMyBufOutLen; int len; uint32 pathNameLen; char tempBuf[HGFS_PATH_MAX]; size_t tempSize; char *tempPtr; uint32 startIndex = 0; HgfsShareOptions shareOptions; HgfsSymlinkCacheEntry *entry; ASSERT(cpName); ASSERT(bufOut); inEnd = cpName + cpNameSize; if (!Unicode_IsBufferValid(cpName, cpNameSize, STRING_ENCODING_UTF8)) { LOG(4, "%s: invalid UTF8 string @ %p\n", __FUNCTION__, cpName); return HGFS_NAME_STATUS_FAILURE; } /* * Get first component. */ len = CPName_GetComponent(cpName, inEnd, &next); if (len < 0) { LOG(4, "%s: get first component failed\n", __FUNCTION__); return HGFS_NAME_STATUS_FAILURE; } /* See if we are dealing with the base of the namespace */ if (!len) { return HGFS_NAME_STATUS_INCOMPLETE_BASE; } /* Check permission on the share and get the share path */ nameStatus = HgfsServerPolicy_ProcessCPName(cpName, len, &shareInfo->readPermissions, &shareInfo->writePermissions, &shareInfo->handle, // XXX: to be deleted. &shareInfo->rootDir); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, "%s: No such share (%s)\n", __FUNCTION__, cpName); return nameStatus; } shareInfo->rootDirLen = strlen(shareInfo->rootDir); /* * XXX: The handle is now NOT propagated back and held in the policy but only in the * table of share properties. * * Get shareInfo handle returns a valid handle only if we have change * notification active. * Note: cpName begins with the share name. */ shareInfo->handle = HgfsServerGetShareHandle(cpName); /* Get the config options. */ nameStatus = HgfsServerPolicy_GetShareOptions(cpName, len, &shareOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, "%s: no matching share: %s.\n", __FUNCTION__, cpName); return nameStatus; } /* Point to the next component, if any */ cpNameSize -= next - cpName; cpName = next; /* * Allocate space for the string. We trim the unused space later. */ outSize = HGFS_PATH_MAX; myBufOut = (char *) malloc(outSize * sizeof *myBufOut); if (!myBufOut) { LOG(4, "%s: out of memory allocating string\n", __FUNCTION__); return HGFS_NAME_STATUS_OUT_OF_MEMORY; } out = myBufOut; /* * See if we are dealing with a "root" share or regular share */ if (shareInfo->rootDirLen == 0) { size_t prefixLen; /* Are root shares allowed? If not, we exit with an error. */ if (0 == (gHgfsCfgSettings.flags & HGFS_CONFIG_SHARE_ALL_HOST_DRIVES_ENABLED)) { LOG(4, "%s: Root share being used\n", __FUNCTION__); nameStatus = HGFS_NAME_STATUS_ACCESS_DENIED; goto error; } /* * This is a "root" share. Interpret the input appropriately as * either a drive letter or UNC name and append it to the output * buffer (for Win32) or simply get the prefix for root (for * linux). */ tempSize = sizeof tempBuf; tempPtr = tempBuf; nameStatus = CPName_ConvertFromRoot(&cpName, &cpNameSize, &tempSize, &tempPtr); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, "%s: ConvertFromRoot not complete\n", __FUNCTION__); goto error; } prefixLen = tempPtr - tempBuf; /* Copy the UTF8 prefix to the output buffer. */ if (prefixLen >= HGFS_PATH_MAX) { Log("%s: error: prefix too long\n", __FUNCTION__); nameStatus = HGFS_NAME_STATUS_TOO_LONG; goto error; } memcpy(out, tempBuf, prefixLen); out += prefixLen; *out = 0; outSize -= prefixLen; } else { /* * This is a regular share. Append the path to the out buffer. */ if (outSize < shareInfo->rootDirLen + 1) { LOG(4, "%s: share path too big\n", __FUNCTION__); nameStatus = HGFS_NAME_STATUS_TOO_LONG; goto error; } memcpy(out, shareInfo->rootDir, shareInfo->rootDirLen + 1); out += shareInfo->rootDirLen; outSize -= shareInfo->rootDirLen; } /* Convert the rest of the input name (if any) to a local name */ tempSize = sizeof tempBuf; tempPtr = tempBuf; if (CPName_ConvertFrom(&cpName, &cpNameSize, &tempSize, &tempPtr) < 0) { LOG(4, "%s: CP name conversion failed\n", __FUNCTION__); nameStatus = HGFS_NAME_STATUS_FAILURE; goto error; } /* * For volume root directory shares the prefix will have a trailing * separator and since our remaining paths start with a separator, we * will skip over the second separator for this case. Bug 166755. */ if ((out != myBufOut) && (*(out - 1) == DIRSEPC) && (tempBuf[0] == DIRSEPC)) { startIndex++; } pathNameLen = tempPtr - &tempBuf[startIndex]; /* Copy UTF8 to the output buffer. */ if (pathNameLen >= outSize) { LOG(4, "%s: pathname too long\n", __FUNCTION__); nameStatus = HGFS_NAME_STATUS_TOO_LONG; goto error; } memcpy(out, &tempBuf[startIndex], pathNameLen); outSize -= pathNameLen; out += pathNameLen; *out = 0; myBufOutLen = out - myBufOut; #if defined(__APPLE__) { size_t nameLen; /* * For Mac hosts the unicode format is decomposed (form D) * so there is a need to convert the incoming name from HGFS clients * which is assumed to be in the normalized form C (precomposed). */ if (!CodeSet_Utf8FormCToUtf8FormD(myBufOut, myBufOutLen, &tempPtr, &nameLen)) { LOG(4, "%s: unicode conversion to form D failed.\n", __FUNCTION__); nameStatus = HGFS_NAME_STATUS_FAILURE; goto error; } free(myBufOut); LOG(4, "%s: name is \"%s\"\n", __FUNCTION__, tempPtr); /* Save returned pointers, update buffer length. */ myBufOut = tempPtr; out = tempPtr + nameLen; myBufOutLen = nameLen; } #endif /* defined(__APPLE__) */ /* * Look up the file name using the proper case if the config option is not set * to use the host default and lookup is supported for this platform. */ if (!HgfsServerPolicy_IsShareOptionSet(shareOptions, HGFS_SHARE_HOST_DEFAULT_CASE) && HgfsPlatformDoFilenameLookup()) { nameStatus = HgfsPlatformFilenameLookup(shareInfo->rootDir, shareInfo->rootDirLen, myBufOut, myBufOutLen, caseFlags, &convertedMyBufOut, &convertedMyBufOutLen); /* * On successful lookup, use the found matching file name for further operations. */ if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, "%s: HgfsPlatformFilenameLookup failed.\n", __FUNCTION__); goto error; } free(myBufOut); myBufOut = convertedMyBufOut; myBufOutLen = convertedMyBufOutLen; ASSERT(myBufOut); } /* Check for symlinks if the followSymlinks option is not set. */ if (!HgfsServerPolicy_IsShareOptionSet(shareOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) { if (NULL != session->symlinkCache && HgfsCache_Get(session->symlinkCache, myBufOut, (void **)&entry)) { nameStatus = entry->nameStatus; } else { /* * Verify that either the path is same as share path or the path until * the parent directory is within the share. * * XXX: Symlink check could become susceptible to * TOCTOU (time-of-check, time-of-use) attack when we move to * asynchrounous HGFS operations. * We should use the resolved file path for further file system * operations, instead of using the one passed from the client. */ nameStatus = HgfsPlatformPathHasSymlink(myBufOut, myBufOutLen, shareInfo->rootDir, shareInfo->rootDirLen); if (NULL != session->symlinkCache) { HOM_HANDLE handle = HgfsOplockMonitorFileChange(myBufOut, session, HgfsOplockFileChangeCb, Util_SafeStrdup(myBufOut)); if (handle != HGFS_OPLOCK_INVALID_MONITOR_HANDLE) { entry = Util_SafeCalloc(1, sizeof *entry); entry->handle = handle; entry->nameStatus = nameStatus; HgfsCache_Put(session->symlinkCache, myBufOut, entry); } } } if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, "%s: parent path failed to be resolved: %d\n", __FUNCTION__, nameStatus); goto error; } } { char *p; /* Trim unused memory */ /* Enough space for resulting string + NUL termination */ p = realloc(myBufOut, (myBufOutLen + 1) * sizeof *p); if (!p) { LOG(4, "%s: failed to trim memory\n", __FUNCTION__); } else { myBufOut = p; } if (outLen) { *outLen = myBufOutLen; } } LOG(4, "%s: name is \"%s\"\n", __FUNCTION__, myBufOut); *bufOut = myBufOut; /* * Contrary to Coverity analysis, storage pointed to by the variable * "entry" is not leaked; HgfsCache_Put stores a pointer to it in the * symlink cache. However, no Coverity annotation for leaked_storage * is added here because such an annotation cannot be made specific to * entry; as a result, if any actual memory leaks were to be introduced * by a future change, the leaked_storage annotation would cause such * new leaks to be flagged as false positives. * * XXX - can something be done with Coverity function models so that * Coverity stops reporting this? */ return HGFS_NAME_STATUS_COMPLETE; error: free(myBufOut); return nameStatus; } /* *----------------------------------------------------------------------------- * * HgfsServerIsSharedFolderOnly -- * * Test a name if it is a shared folder only or not * * This function assumes that CPName_GetComponent() will always succeed * with a size greater than 0, so it must ONLY be called after a call to * HgfsServerGetLocalNameInfo() that returns HGFS_NAME_STATUS_COMPLETE. * * Results: * True if it is a shared folder only, otherwise false * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsServerIsSharedFolderOnly(char const *cpName,// IN: Cross-platform filename to check size_t cpNameSize) // IN: Size of name cpName { char const *inEnd; char const *next; int len; ASSERT(cpName); inEnd = cpName + cpNameSize; len = CPName_GetComponent(cpName, inEnd, &next); ASSERT(len > 0); (void) len; /* Shuts up gcc's -Werror=unused-but-set-variable. */ return (next == inEnd); } #ifdef VMX86_LOG /* *----------------------------------------------------------------------------- * * HgfsServerDirDumpDents -- * * Dump a set of directory entries (debugging code) * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsServerDirDumpDents(HgfsHandle searchHandle, // IN: Handle to dump dents from HgfsSessionInfo *session) // IN: Session info { HgfsSearch *search; MXUser_AcquireExclLock(session->searchArrayLock); search = HgfsSearchHandle2Search(searchHandle, session); if (search != NULL) { HgfsPlatformDirDumpDents(search); } MXUser_ReleaseExclLock(session->searchArrayLock); } #endif /* *----------------------------------------------------------------------------- * * HgfsServerSearchRealDir -- * * Handle a search on a real directory. Takes a pointer to an enumerator * for the directory's contents and returns a handle to a search that is * correctly set up with the real directory's entries. * * The casual reader will notice that the "type" of this search is obviously * always DIRECTORY_SEARCH_TYPE_DIR, but the caller is nonetheless required * to pass it in, for completeness' sake with respect to * HgfsServerSearchVirtualDir. * * Results: * Zero on success, returns a handle to the created search. * Non-zero on failure. * * Side effects: * Memory allocation on success * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search size_t baseDirLen, // IN: Length of directory char const *shareName, // IN: Share name containing the directory char const *rootDir, // IN: Shared folder root directory HgfsSessionInfo *session, // IN: Session info HgfsHandle *handle) // OUT: Search handle { HgfsSearch *search = NULL; HgfsInternalStatus status = 0; HgfsNameStatus nameStatus; Bool followSymlinks; HgfsShareOptions configOptions; ASSERT(baseDir); ASSERT(handle); ASSERT(shareName); MXUser_AcquireExclLock(session->searchArrayLock); search = HgfsAddNewSearch(baseDir, DIRECTORY_SEARCH_TYPE_DIR, shareName, rootDir, session); if (!search) { LOG(4, "%s: failed to get new search\n", __FUNCTION__); status = HGFS_ERROR_INTERNAL; goto out; } /* Get the config options. */ nameStatus = HgfsServerPolicy_GetShareOptions(shareName, strlen(shareName), &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, "%s: no matching share: %s.\n", __FUNCTION__, shareName); status = HGFS_ERROR_INTERNAL; HgfsRemoveSearchInternal(search, session); goto out; } followSymlinks = HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS); status = HgfsPlatformScandir(baseDir, baseDirLen, followSymlinks, &search->dents, &search->numDents); if (HGFS_ERROR_SUCCESS != status) { LOG(4, "%s: couldn't scandir\n", __FUNCTION__); HgfsRemoveSearchInternal(search, session); goto out; } *handle = HgfsSearch2SearchHandle(search); out: MXUser_ReleaseExclLock(session->searchArrayLock); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerSearchVirtualDir -- * * Handle a search on a virtual directory (i.e. one that does not * really exist on the server). Takes a pointer to an enumerator * for the directory's contents and returns a handle to a search that is * correctly set up with the virtual directory's entries. * * Results: * Zero on success, returns a handle to the created search. * Non-zero on failure. * * Side effects: * Memory allocation on success * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsServerSearchVirtualDir(HgfsServerResEnumGetFunc getName, // IN: Name enumerator HgfsServerResEnumInitFunc initName, // IN: Init function HgfsServerResEnumExitFunc cleanupName, // IN: Cleanup function DirectorySearchType type, // IN: Kind of search HgfsSessionInfo *session, // IN: Session info HgfsHandle *handle) // OUT: Search handle { HgfsInternalStatus status = 0; HgfsSearch *search = NULL; ASSERT(getName); ASSERT(initName); ASSERT(cleanupName); ASSERT(handle); MXUser_AcquireExclLock(session->searchArrayLock); search = HgfsAddNewSearch("", type, "", "", session); if (!search) { LOG(4, "%s: failed to get new search\n", __FUNCTION__); status = HGFS_ERROR_INTERNAL; goto out; } status = HgfsPlatformScanvdir(getName, initName, cleanupName, type, &search->dents, &search->numDents); if (HGFS_ERROR_SUCCESS != status) { LOG(4, "%s: couldn't get dents\n", __FUNCTION__); HgfsRemoveSearchInternal(search, session); goto out; } *handle = HgfsSearch2SearchHandle(search); out: MXUser_ReleaseExclLock(session->searchArrayLock); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerRestartSearchVirtualDir -- * * Restart a search on a virtual directory (i.e. one that does not * really exist on the server). Takes a pointer to an enumerator * for the directory's contents and returns a handle to a search that is * correctly set up with the virtual directory's entries. * * Results: * Zero on success, returns a handle to the created search. * Non-zero on failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsServerRestartSearchVirtualDir(HgfsServerResEnumGetFunc getName, // IN: Name enumerator HgfsServerResEnumInitFunc initName, // IN: Init function HgfsServerResEnumExitFunc cleanupName, // IN: Cleanup function HgfsSessionInfo *session, // IN: Session info HgfsHandle searchHandle) // IN: search to restart { HgfsInternalStatus status = 0; HgfsSearch *vdirSearch; ASSERT(getName); ASSERT(initName); ASSERT(cleanupName); ASSERT(searchHandle); MXUser_AcquireExclLock(session->searchArrayLock); vdirSearch = HgfsSearchHandle2Search(searchHandle, session); if (NULL == vdirSearch) { status = HGFS_ERROR_INVALID_HANDLE; goto exit; } /* Release the virtual directory's old set of entries. */ HgfsFreeSearchDirents(vdirSearch); /* Restart by rescanning the virtual directory. */ status = HgfsPlatformScanvdir(getName, initName, cleanupName, vdirSearch->type, &vdirSearch->dents, &vdirSearch->numDents); if (HGFS_ERROR_SUCCESS != status) { LOG(4, "%s: couldn't get root dents %u\n", __FUNCTION__, status); goto exit; } /* Clear the flag to indicate that the client has read the entries. */ vdirSearch->flags &= ~HGFS_SEARCH_FLAG_READ_ALL_ENTRIES; exit: MXUser_ReleaseExclLock(session->searchArrayLock); LOG(4, "%s: refreshing dents return %d\n", __FUNCTION__, status); return status; } /* *----------------------------------------------------------------------------- * * HgfsRemoveFromCache -- * * Grab a node cache lock and call HgfsRemoveFromCacheInternal. * * If the node was not already in the cache then nothing is done. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsRemoveFromCache(HgfsHandle handle, // IN: Hgfs handle to the node HgfsSessionInfo *session) // IN: Session info { Bool removed = FALSE; MXUser_AcquireExclLock(session->nodeArrayLock); removed = HgfsRemoveFromCacheInternal(handle, session); MXUser_ReleaseExclLock(session->nodeArrayLock); return removed; } /* *----------------------------------------------------------------------------- * * HgfsIsCached -- * * Grab a lock and call HgfsIsCachedInternal. * * Results: * TRUE if the node is found in the cache. * FALSE if the node is not in the cache. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsIsCached(HgfsHandle handle, // IN: Structure representing file node HgfsSessionInfo *session) // IN: Session info { Bool cached = FALSE; MXUser_AcquireExclLock(session->nodeArrayLock); cached = HgfsIsCachedInternal(handle, session); MXUser_ReleaseExclLock(session->nodeArrayLock); return cached; } /* *----------------------------------------------------------------------------- * * HgfsRemoveLruNode-- * * Removes the least recently used node in the cache. The first node is * removed since most recently used nodes are moved to the end of the * list. * * XXX: Right now we do not remove nodes that have server locks on them * This is not correct and should be fixed before the release. * Instead we should cancel the server lock (by calling IoCancel) * notify client of the lock break, and close the file. * * Assumes that there is at least one node in the cache. * * The session's nodeArrayLock should be acquired prior to calling this * function. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsRemoveLruNode(HgfsSessionInfo *session) // IN: session info { HgfsFileNode *lruNode = NULL; HgfsHandle handle; Bool found = FALSE; uint32 numOpenNodes = session->numCachedOpenNodes; ASSERT(session); ASSERT(session->numCachedOpenNodes > 0); /* * Remove the first item from the list that does not have a server lock, * file context or is open in sequential mode. */ while (!found && (numOpenNodes-- > 0)) { lruNode = DblLnkLst_Container(session->nodeCachedList.next, HgfsFileNode, links); ASSERT(lruNode->state == FILENODE_STATE_IN_USE_CACHED); if (lruNode->serverLock != HGFS_LOCK_NONE || lruNode->fileCtx != NULL || (lruNode->flags & HGFS_FILE_NODE_SEQUENTIAL_FL) != 0) { /* * Move this node with the server lock to the beginning of the list. * Also, prevent files opened in HGFS_FILE_NODE_SEQUENTIAL_FL mode * from being closed. -- On some platforms, this mode does not * allow files to be closed/re-opened (eg: When restoring a file * into a Windows guest you cannot use BackupWrite, then close and * re-open the file and continue to use BackupWrite. */ DblLnkLst_Unlink1(&lruNode->links); DblLnkLst_LinkLast(&session->nodeCachedList, &lruNode->links); } else { found = TRUE; } } if (found) { handle = HgfsFileNode2Handle(lruNode); if (!HgfsRemoveFromCacheInternal(handle, session)) { LOG(4, "%s: Could not remove the node from cache.\n", __FUNCTION__); return FALSE; } } else { LOG(4, "%s: Could not find a node to remove from cache.\n", __FUNCTION__); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsAddToCache -- * * Grabs the cache lock and calls HgfsAddToCacheInternal. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsAddToCache(HgfsHandle handle, // IN: HGFS file handle HgfsSessionInfo *session) // IN: Session info { Bool added = FALSE; MXUser_AcquireExclLock(session->nodeArrayLock); added = HgfsAddToCacheInternal(handle, session); MXUser_ReleaseExclLock(session->nodeArrayLock); return added; } /* *----------------------------------------------------------------------------- * * HgfsCreateAndCacheFileNode -- * * Get a node from the free node list and cache it. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct HgfsLocalId const *localId, // IN: Local unique file ID fileDesc fileDesc, // IN: Handle to the fileopenInfo, Bool append, // IN: flag to append HgfsSessionInfo *session) // IN: session info { HgfsHandle handle; HgfsFileNode *node = NULL; char const *inEnd; char const *next; int len; Bool sharedFolderOpen = FALSE; ASSERT(openInfo); ASSERT(localId); ASSERT(session); inEnd = openInfo->cpName + openInfo->cpNameSize; /* * Get first component. */ len = CPName_GetComponent(openInfo->cpName, inEnd, &next); if (len < 0) { LOG(4, "%s: get first component failed\n", __FUNCTION__); HgfsPlatformCloseFile(fileDesc, NULL); return FALSE; } /* See if we are dealing with the base of the namespace */ if (!len) { HgfsPlatformCloseFile(fileDesc, NULL); return FALSE; } if (!next) { sharedFolderOpen = TRUE; } MXUser_AcquireExclLock(session->nodeArrayLock); node = HgfsAddNewFileNode(openInfo, localId, fileDesc, append, len, openInfo->cpName, sharedFolderOpen, session); if (node == NULL) { LOG(4, "%s: Failed to add new node.\n", __FUNCTION__); MXUser_ReleaseExclLock(session->nodeArrayLock); HgfsPlatformCloseFile(fileDesc, NULL); return FALSE; } handle = HgfsFileNode2Handle(node); if (!HgfsAddToCacheInternal(handle, session)) { HgfsFreeFileNodeInternal(handle, session); HgfsPlatformCloseFile(fileDesc, NULL); LOG(4, "%s: Failed to add node to the cache.\n", __FUNCTION__); MXUser_ReleaseExclLock(session->nodeArrayLock); return FALSE; } MXUser_ReleaseExclLock(session->nodeArrayLock); /* Only after everything is successful, save the handle in the open info. */ openInfo->file = handle; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsAllocInitReply -- * * Retrieves the hgfs protocol reply data buffer that follows the reply header. * * Results: * Cannot fail, returns the protocol reply data buffer for the corresponding * processed protocol request. * * Side effects: * None * *----------------------------------------------------------------------------- */ void * HgfsAllocInitReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header size_t replyDataSize, // IN: replyDataSize size HgfsSessionInfo *session) // IN: Session Info { const HgfsRequest *request = packetHeader; size_t replyPacketSize; size_t headerSize = 0; /* Replies prior to V3 do not have a header. */ void *replyHeader; void *replyData; /* * XXX - this should be modified to use the common HgfsServerGetReplyHeaderSize * so that all requests and replies are handled consistently. */ if (HGFS_OP_NEW_HEADER == request->op) { headerSize = sizeof(HgfsHeader); } else if (request->op < HGFS_OP_CREATE_SESSION_V4 && request->op > HGFS_OP_RENAME_V2) { headerSize = sizeof(HgfsReply); } replyHeader = HSPU_GetReplyPacket(packet, session->transportSession->channelCbTable, headerSize + replyDataSize, &replyPacketSize); ASSERT(replyHeader && (replyPacketSize >= headerSize + replyDataSize)); memset(replyHeader, 0, headerSize + replyDataSize); if (replyDataSize > 0) { replyData = (char *)replyHeader + headerSize; } else { replyData = NULL; ASSERT(FALSE); } return replyData; } /* *----------------------------------------------------------------------------- * * HgfsServerValidateRead -- * * Validate a Read request's arguments. * * Note, the readOffset is ignored here but is checked in the platform specific * read handler. * * Results: * HGFS_ERROR_SUCCESS on success. * HGFS error code on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerValidateRead(HgfsInputParam *input, // IN: Input params HgfsHandle readHandle, // IN: read Handle uint32 readSize, // IN: size to read uint64 readOffset, // IN: offset to read unused fileDesc *readfd, // OUT: read file descriptor size_t *readReplySize, // OUT: read reply size size_t *readDataSize) // OUT: read data size { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; size_t replyReadHeaderSize; size_t replyReadResultSize = 0; size_t replyReadResultDataSize = 0; size_t replyReadDataSize = 0; fileDesc readFileDesc = 0; Bool useMappedBuffer; useMappedBuffer = (input->transportSession->channelCbTable->getWriteVa != NULL); replyReadHeaderSize = HgfsServerGetReplyHeaderSize(input->sessionEnabled, input->op); switch (input->op) { case HGFS_OP_READ_FAST_V4: /* Data is packed into a separate buffer from the read results. */ replyReadResultSize = sizeof (HgfsReplyReadV3); replyReadResultDataSize = 0; replyReadDataSize = readSize; break; case HGFS_OP_READ_V3: /* Data is packed as a part of the read results. */ replyReadResultSize = sizeof (HgfsReplyReadV3); replyReadResultDataSize = readSize; replyReadDataSize = 0; break; case HGFS_OP_READ: /* Data is packed as a part of the read results. */ replyReadResultSize = sizeof (HgfsReplyRead); replyReadResultDataSize = readSize; replyReadDataSize = 0; break; default: status = HGFS_ERROR_PROTOCOL; LOG(4, "%s: Unsupported protocol version passed %d -> PROTOCOL_ERROR.\n", __FUNCTION__, input->op); NOT_IMPLEMENTED(); goto exit; } if (!HSPU_ValidateDataPacketSize(input->packet, replyReadDataSize) || !HSPU_ValidateReplyPacketSize(input->packet, replyReadHeaderSize, replyReadResultSize, replyReadResultDataSize, useMappedBuffer)) { status = HGFS_ERROR_INVALID_PARAMETER; LOG(4, "%s: Error: arg validation read size -> %d.\n", __FUNCTION__, status); goto exit; } /* Validate the file handle by retrieving it possibly from the cache. */ status = HgfsPlatformGetFd(readHandle, input->session, FALSE, &readFileDesc); if (status != HGFS_ERROR_SUCCESS) { LOG(4, "%s: Error: arg validation handle -> %d.\n", __FUNCTION__, status); goto exit; } exit: *readDataSize = replyReadDataSize; *readReplySize = replyReadResultSize + replyReadResultDataSize; *readfd = readFileDesc; LOG(4, "%s: arg validation check return (%"FMTSZ"u) %d.\n", __FUNCTION__, replyReadDataSize, status); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerRead -- * * Handle a Read request. * * Results: * HGFS_ERROR_SUCCESS on success. * HGFS error code on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerRead(HgfsInputParam *input) // IN: Input params { HgfsInternalStatus status; HgfsHandle file; fileDesc readFd; uint64 offset; uint32 requiredSize; size_t replyPayloadSize = 0; size_t replyReadSize = 0; size_t replyReadDataSize = 0; void *replyRead; HGFS_ASSERT_INPUT(input); if (!HgfsUnpackReadRequest(input->payload, input->payloadSize, input->op, &file, &offset, &requiredSize)) { LOG(4, "%s: Failed to unpack a valid packet -> PROTOCOL_ERROR.\n", __FUNCTION__); status = HGFS_ERROR_PROTOCOL; goto exit; } /* * Validate the read arguments with the data and reply buffers to ensure * there isn't a malformed request or we read more data than the buffer can * hold. */ status = HgfsServerValidateRead(input, file, requiredSize, offset, &readFd, &replyReadSize, &replyReadDataSize); if (status != HGFS_ERROR_SUCCESS) { LOG(4, "%s: Error: validate args %u.\n", __FUNCTION__, status); goto exit; } replyRead = HgfsAllocInitReply(input->packet, input->request, replyReadSize, input->session); switch (input->op) { case HGFS_OP_READ_FAST_V4: case HGFS_OP_READ_V3: { HgfsReplyReadV3 *reply = replyRead; void *payload; Bool readUseDataBuffer = replyReadDataSize != 0; /* * The read data size holds the size of the data to read which will be read * into the separate data packet buffer. Zero indicates data is read into the * same buffer as the reply arguments. */ if (readUseDataBuffer) { payload = HSPU_GetDataPacketBuf(input->packet, BUF_WRITEABLE, input->transportSession->channelCbTable); } else { payload = &reply->payload[0]; } if (payload) { uint32 actualSize = 0; status = HgfsPlatformReadFile(readFd, input->session, offset, requiredSize, payload, &actualSize); if (HGFS_ERROR_SUCCESS == status) { reply->reserved = 0; reply->actualSize = actualSize; replyPayloadSize = sizeof *reply; if (readUseDataBuffer) { HSPU_SetDataPacketSize(input->packet, reply->actualSize); } else { replyPayloadSize += reply->actualSize; } } } else { status = HGFS_ERROR_PROTOCOL; LOG(4, "%s: V3/V4 Failed to get payload -> PROTOCOL_ERROR.\n", __FUNCTION__); } break; } case HGFS_OP_READ: { uint32 actualSize = 0; HgfsReplyRead *reply = replyRead; status = HgfsPlatformReadFile(readFd, input->session, offset, requiredSize, reply->payload, &actualSize); if (HGFS_ERROR_SUCCESS == status) { reply->actualSize = actualSize; replyPayloadSize = sizeof *reply + reply->actualSize; } else { LOG(4, "%s: V1 Failed to read-> %d.\n", __FUNCTION__, status); } break; } default: NOT_REACHED(); break; } exit: HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerValidateWrite -- * * Validate a write request's arguments. * * The HGFS Packet stored in the following possible formats as follows: * * Protocol V4 versions: * In the HgfsPacket metaPacket buffer * [HgfsHeader][HgfsRequestWriteV3] * In the HgfsPacket dataPacket buffer * [Variable length data to write] * * Protocol V3 versions: * In the HgfsPacket metaPacket buffer * [HgfsHeader][HgfsRequestWriteV3][Variable length data to write] * [HgfsRequest][HgfsRequestWriteV3][Variable length data to write] * * Protocol V2 versions: * Does not exist * * Protocol V1 versions: * In the HgfsPacket metaPacket buffer * [HgfsRequestWrite][Variable length data to write] * (Note, the HgfsRequestWrite contains an HgfsRequest within it.) * * Note, the writeOffset is ignored here but is checked in the platform specific * write handler. * * Results: * HGFS_ERROR_SUCCESS on success. * HGFS error code on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerValidateWrite(HgfsInputParam *input, // IN: Input params HgfsHandle writeHandle, // IN: write Handle uint64 writeOffset, // IN: write offset of file uint32 writeSize, // IN: size to write HgfsWriteFlags flags, // IN: write flags fileDesc *writefd, // OUT: write file descriptor Bool *writeSequential, // OUT: write is sequential Bool *writeAppend) // OUT: write is append { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; size_t requestWriteHeaderSize; size_t requestWritePacketSize = 0; size_t requestWritePacketDataSize = 0; size_t requestWriteDataSize = 0; fileDesc writeFileDesc = 0; Bool sequentialHandle = FALSE; Bool appendHandle = FALSE; requestWriteHeaderSize = HgfsServerGetRequestHeaderSize(input->sessionEnabled, input->op); switch (input->op) { case HGFS_OP_WRITE_FAST_V4: /* * For this the operation data is in the shared memory, * which depends on the mapping functions from the transport. */ ASSERT(input->transportSession->channelCbTable->getReadVa != NULL); /* * The write data is packed in a separate buffer to the write request. * Note, for size we **include** the 1 byte placeholder payload that was not * counted in earlier versions of the write request. Sigh. See below. */ requestWritePacketSize = sizeof (HgfsRequestWriteV3); requestWritePacketDataSize = 0; requestWriteDataSize = writeSize; break; case HGFS_OP_WRITE_V3: /* * Data is packed as a part of the write request. * Note, for size we remove the 1 byte placeholder payload * so it isn't counted twice. */ requestWritePacketSize = sizeof (HgfsRequestWriteV3) - 1; requestWritePacketDataSize = writeSize; requestWriteDataSize = 0; break; case HGFS_OP_WRITE: /* * Data is packed as a part of the write request. * Note, for size we remove the 1 byte placeholder payload * so it isn't counted twice. */ requestWritePacketSize = sizeof (HgfsRequestWrite) - 1; requestWritePacketDataSize = writeSize; requestWriteDataSize = 0; break; default: status = HGFS_ERROR_PROTOCOL; LOG(4, "%s: Unsupported protocol version passed %d -> PROTOCOL_ERROR.\n", __FUNCTION__, input->op); NOT_IMPLEMENTED(); goto exit; } /* * Validate the packet size with the header, write request and write data. */ if (!HSPU_ValidateDataPacketSize(input->packet, requestWriteDataSize) || !HSPU_ValidateRequestPacketSize(input->packet, requestWriteHeaderSize, requestWritePacketSize, requestWritePacketDataSize)) { status = HGFS_ERROR_INVALID_PARAMETER; LOG(4, "%s: Error: write data size pkt %"FMTSZ"u data %"FMTSZ"u\n", __FUNCTION__, requestWritePacketDataSize, requestWriteDataSize); goto exit; } /* * Now map the file handle, and extract the details of the write e.g. writing * sequentially or appending * * Validate the file handle by retrieving it possibly from the cache. */ status = HgfsPlatformGetFd(writeHandle, input->session, ((flags & HGFS_WRITE_APPEND) ? TRUE : FALSE), &writeFileDesc); if (status != HGFS_ERROR_SUCCESS) { LOG(4, "%s: Error: arg validation handle -> %d.\n", __FUNCTION__, status); goto exit; } if (!HgfsHandleIsSequentialOpen(writeHandle, input->session, &sequentialHandle)) { status = HGFS_ERROR_INVALID_HANDLE; LOG(4, "%s: Could not get sequential open status\n", __FUNCTION__); goto exit; } #if defined(__APPLE__) if (!HgfsHandle2AppendFlag(writeHandle, input->session, &appendHandle)) { status = HGFS_ERROR_INVALID_HANDLE; LOG(4, "%s: Could not get append mode\n", __FUNCTION__); goto exit; } #endif exit: *writefd = writeFileDesc; *writeSequential = sequentialHandle; *writeAppend = appendHandle; LOG(4, "%s: arg validation check return (file %u data size %u) %u.\n", __FUNCTION__, writeHandle, writeSize, status); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerWrite -- * * Handle a Write request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerWrite(HgfsInputParam *input) // IN: Input params { uint64 writeOffset; uint32 writeSize; uint32 writtenSize = 0; HgfsInternalStatus status = HGFS_ERROR_SUCCESS; HgfsWriteFlags writeFlags; const void *writeData; size_t writeReplySize = 0; HgfsHandle writeFile; fileDesc writeFd; Bool writeSequential; Bool writeAppend; HGFS_ASSERT_INPUT(input); if (!HgfsUnpackWriteRequest(input->payload, input->payloadSize, input->op, &writeFile, &writeOffset, &writeSize, &writeFlags, &writeData)) { LOG(4, "%s: Error: Op %d unpack write request arguments\n", __FUNCTION__, input->op); status = HGFS_ERROR_PROTOCOL; goto exit; } /* * Validate the write arguments with the data and request buffers to ensure * there isn't a malformed request or we try to write more data than is in the buffer. */ status = HgfsServerValidateWrite(input, writeFile, writeOffset, writeSize, writeFlags, &writeFd, &writeSequential, &writeAppend); if (status != HGFS_ERROR_SUCCESS) { LOG(4, "%s: Error: validate args %u.\n", __FUNCTION__, status); goto exit; } if (writeSize > 0) { if (NULL == writeData) { /* No inline data to write, get it from the transport shared memory. */ HSPU_SetDataPacketSize(input->packet, writeSize); writeData = HSPU_GetDataPacketBuf(input->packet, BUF_READABLE, input->transportSession->channelCbTable); if (NULL == writeData) { LOG(4, "%s: Error: Op %d mapping write data buffer\n", __FUNCTION__, input->op); status = HGFS_ERROR_PROTOCOL; goto exit; } } status = HgfsPlatformWriteFile(writeFd, input->session, writeOffset, writeSize, writeFlags, writeSequential, writeAppend, writeData, &writtenSize); if (HGFS_ERROR_SUCCESS != status) { goto exit; } } if (!HgfsPackWriteReply(input->packet, input->request, input->op, writtenSize, &writeReplySize, input->session)) { status = HGFS_ERROR_INTERNAL; } exit: HgfsServerCompleteRequest(status, writeReplySize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerQueryVolInt -- * * Internal function to query the volume's free space and capacity. * The volume queried can be: * - real taken from the file path of a real file or folder * - virtual taken from one of the HGFS virtual folders which can span * multiple volumes. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerQueryVolInt(HgfsSessionInfo *session, // IN: session info const char *fileName, // IN: cpName for the volume size_t fileNameLength, // IN: cpName length uint32 caseFlags, // IN: case sensitive/insensitive name uint64 *freeBytes, // OUT: free space in bytes uint64 *totalBytes) // OUT: capacity in bytes { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; uint64 outFreeBytes = 0; uint64 outTotalBytes = 0; char *utf8Name = NULL; size_t utf8NameLen; HgfsNameStatus nameStatus; HgfsShareInfo shareInfo; VolumeInfoType infoType; /* * XXX - make the filename const! * It is now safe to read the file name field. */ nameStatus = HgfsServerGetLocalNameInfo(fileName, fileNameLength, caseFlags, session, &shareInfo, &utf8Name, &utf8NameLen); /* Check if we have a real path and if so handle it here. */ if (nameStatus == HGFS_NAME_STATUS_COMPLETE) { Bool success; ASSERT(utf8Name); LOG(4, "%s: querying path %s\n", __FUNCTION__, utf8Name); success = HgfsServerStatFs(utf8Name, utf8NameLen, &outFreeBytes, &outTotalBytes); free(utf8Name); if (!success) { LOG(4, "%s: error getting volume information\n", __FUNCTION__); status = HGFS_ERROR_IO; } goto exit; } /* * If we're outside the Tools, find out if we're to compute the minimum * values across all shares, or the maximum values. */ infoType = VOLUME_INFO_TYPE_MIN; /* We have a virtual folder path and if so pass it over to the platform code. */ if (0 == (gHgfsCfgSettings.flags & HGFS_CONFIG_VOL_INFO_MIN)) { /* Using the maximum volume size and space values. */ infoType = VOLUME_INFO_TYPE_MAX; } status = HgfsPlatformVDirStatsFs(session, nameStatus, infoType, &outFreeBytes, &outTotalBytes); exit: *freeBytes = outFreeBytes; *totalBytes = outTotalBytes; LOG(4, "%s: return %"FMT64"u bytes Free %"FMT64"u bytes\n", __FUNCTION__, outTotalBytes, outFreeBytes); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerQueryVolume -- * * Handle a Query Volume request. * * Right now we only handle the volume space request. Call Wiper library * to get the volume information. * It is possible that shared folders can belong to different volumes on * the server. If this is the case, default to return the space information * of the volume that has the least amount of the available space, but it's * configurable with a config option (tools.hgfs.volumeInfoType). 2 possible * options, min and max. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerQueryVolume(HgfsInputParam *input) // IN: Input params { HgfsInternalStatus status; size_t replyPayloadSize = 0; HgfsHandle file; const char *fileName; size_t fileNameLength; uint32 caseFlags; Bool useHandle; uint64 freeBytes; uint64 totalBytes; HGFS_ASSERT_INPUT(input); if (HgfsUnpackQueryVolumeRequest(input->payload, input->payloadSize, input->op, &useHandle, &fileName, &fileNameLength, &caseFlags, &file)) { /* * We don't yet support file handle for this operation. * Clients should retry using the file name. */ if (useHandle) { LOG(4, "%s: Doesn't support file handle.\n", __FUNCTION__); status = HGFS_ERROR_INVALID_PARAMETER; } else { status = HgfsServerQueryVolInt(input->session, fileName, fileNameLength, caseFlags, &freeBytes, &totalBytes); if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackQueryVolumeReply(input->packet, input->request, input->op, freeBytes, totalBytes, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsSymlinkCreate -- * * Platform independent function that verifies whether symbolic link creation * is allowed for the specific shared folder and then calls platform specific * HgfsPlatformSymlinkCreate to do the actual job. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsSymlinkCreate(HgfsSessionInfo *session, // IN: session info, const char *srcFileName, // IN: symbolic link file name uint32 srcFileNameLength, // IN: symbolic link name length uint32 srcCaseFlags, // IN: symlink case flags const char *trgFileName, // IN: symbolic link target name uint32 trgFileNameLength, // IN: target name length uint32 trgCaseFlags) // IN: target case flags { HgfsShareInfo shareInfo; HgfsInternalStatus status = 0; HgfsNameStatus nameStatus; HgfsShareOptions configOptions; char *localSymlinkName = NULL; size_t localSymlinkNameLen; char localTargetName[HGFS_PACKET_MAX]; /* * It is now safe to read the symlink file name and the * "targetName" field */ nameStatus = HgfsServerGetLocalNameInfo(srcFileName, srcFileNameLength, srcCaseFlags, session, &shareInfo, &localSymlinkName, &localSymlinkNameLen); if (nameStatus == HGFS_NAME_STATUS_COMPLETE) { if (shareInfo.writePermissions ) { /* Get the config options. */ nameStatus = HgfsServerPolicy_GetShareOptions(srcFileName, srcFileNameLength, &configOptions); if (nameStatus == HGFS_NAME_STATUS_COMPLETE) { /* Prohibit symlink ceation if symlink following is enabled. */ if (HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) { status = HGFS_ERROR_ACCESS_DENIED; } } else { LOG(4, "%s: no matching share: %s.\n", __FUNCTION__, srcFileName); status = HgfsPlatformConvertFromNameStatus(nameStatus); } } else { status = HgfsPlatformFileExists(localSymlinkName); if (status != 0) { if (status == HGFS_ERROR_FILE_NOT_FOUND) { status = HGFS_ERROR_ACCESS_DENIED; } } else { status = HGFS_ERROR_FILE_EXIST; } LOG(4, "%s: failed access check, error %d\n", __FUNCTION__, status); } } else { LOG(4, "%s: symlink name access check failed\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } if (HGFS_ERROR_SUCCESS == status) { /* Convert from CPName-lite to normal and NUL-terminate. */ memcpy(localTargetName, trgFileName, trgFileNameLength); CPNameLite_ConvertFrom(localTargetName, trgFileNameLength, DIRSEPC); localTargetName[trgFileNameLength] = '\0'; status = HgfsPlatformSymlinkCreate(localSymlinkName, localTargetName); } free(localSymlinkName); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerSymlinkCreate -- * * Handle a SymlinkCreate request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerSymlinkCreate(HgfsInputParam *input) // IN: Input params { HgfsInternalStatus status; HgfsHandle srcFile; const char *srcFileName; size_t srcFileNameLength; uint32 srcCaseFlags; Bool srcUseHandle; HgfsHandle trgFile; const char *trgFileName; size_t trgFileNameLength; uint32 trgCaseFlags; Bool trgUseHandle; size_t replyPayloadSize = 0; HGFS_ASSERT_INPUT(input); if (HgfsUnpackSymlinkCreateRequest(input->payload, input->payloadSize, input->op, &srcUseHandle, &srcFileName, &srcFileNameLength, &srcCaseFlags, &srcFile, &trgUseHandle, &trgFileName, &trgFileNameLength, &trgCaseFlags, &trgFile)) { /* * We don't yet support file handle for this operation. * Clients should retry using the file name. */ if (srcUseHandle || trgUseHandle) { LOG(4, "%s: Doesn't support file handle.\n", __FUNCTION__); status = HGFS_ERROR_INVALID_PARAMETER; } else { status = HgfsSymlinkCreate(input->session, srcFileName, srcFileNameLength, srcCaseFlags, trgFileName, trgFileNameLength, trgCaseFlags); if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackSymlinkCreateReply(input->packet, input->request, input->op, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerSearchOpen -- * * Handle a search open request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerSearchOpen(HgfsInputParam *input) // IN: Input params { HgfsInternalStatus status; size_t replyPayloadSize = 0; const char *dirName; size_t dirNameLength; uint32 caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; HgfsHandle search; HgfsNameStatus nameStatus; HgfsShareInfo shareInfo; char *baseDir = NULL; size_t baseDirLen; HGFS_ASSERT_INPUT(input); if (HgfsUnpackSearchOpenRequest(input->payload, input->payloadSize, input->op, &dirName, &dirNameLength, &caseFlags)) { nameStatus = HgfsServerGetLocalNameInfo(dirName, dirNameLength, caseFlags, input->session, &shareInfo, &baseDir, &baseDirLen); status = HgfsPlatformSearchDir(nameStatus, dirName, dirNameLength, caseFlags, &shareInfo, baseDir, baseDirLen, input->session, &search); if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackSearchOpenReply(input->packet, input->request, input->op, search, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); free(baseDir); } /* *----------------------------------------------------------------------------- * * HgfsValidateRenameFile -- * * Validates if the file can can participate in rename process either as * as a source or as a target. * * Results: * HGFS_ERROR_SUCCESS if rename operation is allowed. * Appropriate error code otherwise. * * Side effects: * Allcates locaFileName which must be freed by the caller. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsValidateRenameFile(Bool useHandle, // IN: HgfsHandle fileHandle, // IN: const char *cpName, // IN: size_t cpNameLength, // IN: uint32 caseFlags, // IN: HgfsSessionInfo *session, // IN: Session info fileDesc* descr, // OUT: HgfsShareInfo *shareInfo, // OUT: char **localFileName, // OUT: size_t *localNameLength) // OUT: { HgfsInternalStatus status; Bool sharedFolderOpen = FALSE; HgfsLockType serverLock = HGFS_LOCK_NONE; HgfsNameStatus nameStatus; if (useHandle) { status = HgfsPlatformGetFd(fileHandle, session, FALSE, descr); if (HGFS_ERROR_SUCCESS != status) { LOG(4, "%s: could not map cached handle %d, error %u\n", __FUNCTION__, fileHandle, status); } else if (!HgfsHandle2FileNameMode(fileHandle, session, &shareInfo->readPermissions, &shareInfo->writePermissions, localFileName, localNameLength)) { /* * HgfsPlatformRename requires valid source file name even when file handle * is specified. * Also the name will be required to update the nodes on a successful * rename operation. */ LOG(4, "%s: could not get file name for fd %d\n", __FUNCTION__, *descr); status = HGFS_ERROR_INVALID_HANDLE; } else if (HgfsHandleIsSharedFolderOpen(fileHandle, session, &sharedFolderOpen) && sharedFolderOpen) { LOG(4, "%s: Cannot rename shared folder\n", __FUNCTION__); status = HGFS_ERROR_ACCESS_DENIED; } } else { nameStatus = HgfsServerGetLocalNameInfo(cpName, cpNameLength, caseFlags, session, shareInfo, localFileName, localNameLength); if (HGFS_NAME_STATUS_COMPLETE != nameStatus) { LOG(4, "%s: access check failed\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } else if (HgfsServerIsSharedFolderOnly(cpName, cpNameLength)) { /* Guest OS is not allowed to rename shared folder. */ LOG(4, "%s: Cannot rename shared folder\n", __FUNCTION__); status = HGFS_ERROR_ACCESS_DENIED; } else { status = HGFS_ERROR_SUCCESS; } } ASSERT(*localFileName != NULL || HGFS_ERROR_SUCCESS != status); if (HGFS_ERROR_SUCCESS == status) { if (HgfsFileHasServerLock(*localFileName, session, &serverLock, descr)) { /* * XXX: Before renaming the file, check to see if we are holding * an oplock on both the old and new files. If one of them is oplocked, and * we commence with the rename, we'll trigger an oplock break that'll * deadlock us. The client should be smart enough to break necessary oplocks * on the source and target files before calling rename, so we'll return * an error. */ LOG (4, "%s: File has an outstanding oplock. Client " "should remove this oplock and try again.\n", __FUNCTION__); status = HGFS_ERROR_PATH_BUSY; } } return status; } /* *----------------------------------------------------------------------------- * * HgfsServerRename -- * * Handle a Rename request. * * Simply converts the new and old names to local filenames, calls * platform specific function to rename/move the file, and returns an * appropriate response to the driver. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerRename(HgfsInputParam *input) // IN: Input params { char *utf8OldName = NULL; size_t utf8OldNameLen; char *utf8NewName = NULL; size_t utf8NewNameLen; const char *cpOldName; size_t cpOldNameLen; const char *cpNewName; size_t cpNewNameLen; HgfsInternalStatus status; #ifdef _WIN32 fileDesc srcFileDesc = INVALID_HANDLE_VALUE; fileDesc targetFileDesc = INVALID_HANDLE_VALUE; #else fileDesc srcFileDesc = -1; fileDesc targetFileDesc = -1; #endif HgfsHandle srcFile; HgfsHandle targetFile; HgfsRenameHint hints; uint32 oldCaseFlags; uint32 newCaseFlags; HgfsShareInfo shareInfo; size_t replyPayloadSize = 0; HGFS_ASSERT_INPUT(input); if (HgfsUnpackRenameRequest(input->payload, input->payloadSize, input->op, &cpOldName, &cpOldNameLen, &cpNewName, &cpNewNameLen, &hints, &srcFile, &targetFile, &oldCaseFlags, &newCaseFlags)) { status = HgfsValidateRenameFile((hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) != 0, srcFile, cpOldName, cpOldNameLen, oldCaseFlags, input->session, &srcFileDesc, &shareInfo, &utf8OldName, &utf8OldNameLen); if (HGFS_ERROR_SUCCESS == status) { /* * Renaming a file requires both read and write permssions for the * original file. * However the error code must be different depending on the existence * of the file with the same name. */ if (!shareInfo.writePermissions || !shareInfo.readPermissions) { status = HgfsPlatformFileExists(utf8OldName); if (HGFS_ERROR_SUCCESS == status) { status = HGFS_ERROR_ACCESS_DENIED; } LOG(4, "HgfsServerRename: failed access check, error %d\n", status); } else { status = HgfsValidateRenameFile((hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) != 0, targetFile, cpNewName, cpNewNameLen, newCaseFlags, input->session, &targetFileDesc, &shareInfo, &utf8NewName, &utf8NewNameLen); if (HGFS_ERROR_SUCCESS == status) { /* * Renaming a file requires both read and write permssions for * the target directory. * However the error code must be different depending on the existence * of the target directory - if the destination directory exists then * ERROR_ACCESS_DENIED should be returned regardless if the destination * file exists. */ if (!shareInfo.writePermissions || !shareInfo.readPermissions) { status = HgfsPlatformFileExists(utf8NewName); if (HGFS_ERROR_SUCCESS == status || HGFS_ERROR_FILE_NOT_FOUND == status) { status = HGFS_ERROR_ACCESS_DENIED; } LOG(4, "HgfsServerRename: failed access check, error %d\n", status); } } } } } else { status = HGFS_ERROR_PROTOCOL; } /* If all pre-conditions are met go ahead with actual rename. */ if (HGFS_ERROR_SUCCESS == status) { status = HgfsPlatformRename(utf8OldName, srcFileDesc, utf8NewName, targetFileDesc, hints); if (HGFS_ERROR_SUCCESS == status) { /* Update all file nodes that refer to this file to contain the new name. */ HgfsUpdateNodeNames(utf8OldName, utf8NewName, input->session); if (!HgfsPackRenameReply(input->packet, input->request, input->op, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } free(utf8OldName); free(utf8NewName); HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerCreateDir -- * * Handle a CreateDir request. * * Simply converts to the local filename, calls platform specific * code to create a directory, and returns an appropriate response to the driver. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerCreateDir(HgfsInputParam *input) // IN: Input params { HgfsInternalStatus status; HgfsNameStatus nameStatus; HgfsCreateDirInfo info; char *utf8Name = NULL; size_t utf8NameLen; size_t replyPayloadSize = 0; HgfsShareInfo shareInfo; HGFS_ASSERT_INPUT(input); if (!HgfsUnpackCreateDirRequest(input->payload, input->payloadSize, input->op, &info)) { status = HGFS_ERROR_PROTOCOL; goto exit; } nameStatus = HgfsServerGetLocalNameInfo(info.cpName, info.cpNameSize, info.caseFlags, input->session, &shareInfo, &utf8Name, &utf8NameLen); if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { ASSERT(utf8Name); /* * Check if the guest is attempting to create a directory as a new * share in our virtual root folder. If so, then it exists as we have found * the share. This should error as a file exists whereas access denied is for * new folders that do not collide. * The virtual root folder is read-only for guests and new shares can only be * created from the host. */ if (HgfsServerIsSharedFolderOnly(info.cpName, info.cpNameSize)) { /* Disallow creating a subfolder matching the share in the virtual folder. */ LOG(4, "%s: Collision: cannot create a folder which is a share\n", __FUNCTION__); status = HGFS_ERROR_FILE_EXIST; goto exit; } /* * For read-only shares we must never attempt to create a directory. * However the error code must be different depending on the existence * of the file with the same name. */ if (shareInfo.writePermissions) { status = HgfsPlatformCreateDir(&info, utf8Name); if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackCreateDirReply(input->packet, input->request, info.requestType, &replyPayloadSize, input->session)) { status = HGFS_ERROR_PROTOCOL; } } } else { status = HgfsPlatformFileExists(utf8Name); if (HGFS_ERROR_SUCCESS == status) { status = HGFS_ERROR_FILE_EXIST; } else if (HGFS_ERROR_FILE_NOT_FOUND == status) { status = HGFS_ERROR_ACCESS_DENIED; } } } else { /* * Check if the name does not exist - the share was not found. * Then it could one of two things: the share was removed/disabled; * or we could be in the root share itself and have a new name. * To return the correct error, if we are in the root share, * we must check the open mode too - creation of new files/folders * should fail access denied, for anything else "not found" is acceptable. */ if (nameStatus == HGFS_NAME_STATUS_DOES_NOT_EXIST) { if (HgfsServerIsSharedFolderOnly(info.cpName, info.cpNameSize)) { nameStatus = HGFS_NAME_STATUS_ACCESS_DENIED; LOG(4, "%s: disallow new folder creation in virtual share root.\n", __FUNCTION__); } else { LOG(4, "%s: Shared folder not found\n", __FUNCTION__); } } else { LOG(4, "%s: Shared folder access error %u\n", __FUNCTION__, nameStatus); } status = HgfsPlatformConvertFromNameStatus(nameStatus); } exit: HgfsServerCompleteRequest(status, replyPayloadSize, input); free(utf8Name); } /* *----------------------------------------------------------------------------- * * HgfsServerDeleteFile -- * * Handle a Delete File request. * * Simply converts to the local filename, calls DeleteFile on the * file or calls the Windows native API Delete, and returns an * appropriate response to the driver. * * Enforcing read-only shares restrictions * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerDeleteFile(HgfsInputParam *input) // IN: Input params { const char *cpName; size_t cpNameSize; HgfsLockType serverLock = HGFS_LOCK_NONE; fileDesc fileDesc; HgfsHandle file; HgfsDeleteHint hints = 0; HgfsInternalStatus status; HgfsNameStatus nameStatus; uint32 caseFlags; size_t replyPayloadSize = 0; HgfsShareInfo shareInfo; HGFS_ASSERT_INPUT(input); if (HgfsUnpackDeleteRequest(input->payload, input->payloadSize, input->op, &cpName, &cpNameSize, &hints, &file, &caseFlags)) { if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) { status = HgfsPlatformDeleteFileByHandle(file, input->session); } else { char *utf8Name = NULL; size_t utf8NameLen; nameStatus = HgfsServerGetLocalNameInfo(cpName, cpNameSize, caseFlags, input->session, &shareInfo, &utf8Name, &utf8NameLen); if (nameStatus == HGFS_NAME_STATUS_COMPLETE) { /* * Deleting a file needs both read and write permssions. * However the error code must be different depending on the existence * of the file with the same name. */ if (!shareInfo.writePermissions || !shareInfo.readPermissions) { status = HgfsPlatformFileExists(utf8Name); if (HGFS_ERROR_SUCCESS == status) { status = HGFS_ERROR_ACCESS_DENIED; } LOG(4, "HgfsServerDeleteFile: failed access check, error %d\n", status); } else if (HgfsFileHasServerLock(utf8Name, input->session, &serverLock, &fileDesc)) { /* * XXX: If the file has an oplock, the client should have broken it on * its own by now. Sorry! */ LOG (4, "%s: File has an outstanding oplock. Client should " "remove this oplock and try again.\n", __FUNCTION__); status = HGFS_ERROR_PATH_BUSY; } else { LOG(4, "%s: deleting \"%s\"\n", __FUNCTION__, utf8Name); status = HgfsPlatformDeleteFileByName(utf8Name); } free(utf8Name); } else { LOG(4, "%s: Shared folder does not exist.\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } } if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackDeleteReply(input->packet, input->request, input->op, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerDeleteDir -- * * Handle a Delete Dir request. * * Simply converts to the local filename, calls RemoveDirectory on the * directory or Windows native API delete if we have a valid handle, * and returns an appropriate response to the driver. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerDeleteDir(HgfsInputParam *input) // IN: Input params { const char *cpName; size_t cpNameSize; HgfsInternalStatus status; HgfsNameStatus nameStatus; HgfsHandle file; HgfsDeleteHint hints = 0; fileDesc fileDesc; Bool sharedFolderOpen = FALSE; uint32 caseFlags; size_t replyPayloadSize = 0; HgfsShareInfo shareInfo; HGFS_ASSERT_INPUT(input); if (HgfsUnpackDeleteRequest(input->payload, input->payloadSize, input->op, &cpName, &cpNameSize, &hints, &file, &caseFlags)) { if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) { status = HgfsPlatformGetFd(file, input->session, FALSE, &fileDesc); if (HGFS_ERROR_SUCCESS == status) { if (HgfsHandleIsSharedFolderOpen(file, input->session, &sharedFolderOpen) && sharedFolderOpen) { LOG(4, "%s: Cannot delete shared folder\n", __FUNCTION__); status = HGFS_ERROR_ACCESS_DENIED; } else { status = HgfsPlatformDeleteDirByHandle(file, input->session); if (HGFS_ERROR_SUCCESS != status) { LOG(4, "%s: error deleting directory %d: %d\n", __FUNCTION__, file, status); } } } else { LOG(4, "%s: could not map cached handle %u, error %u\n", __FUNCTION__, file, status); } } else { char *utf8Name = NULL; size_t utf8NameLen; nameStatus = HgfsServerGetLocalNameInfo(cpName, cpNameSize, caseFlags, input->session, &shareInfo, &utf8Name, &utf8NameLen); if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { ASSERT(utf8Name); /* Guest OS is not allowed to delete shared folder. */ if (HgfsServerIsSharedFolderOnly(cpName, cpNameSize)){ LOG(4, "%s: Cannot delete shared folder\n", __FUNCTION__); status = HGFS_ERROR_ACCESS_DENIED; } else if (!shareInfo.writePermissions || !shareInfo.readPermissions) { /* * Deleting a directory requires both read and write permissions. * However the error code must be different depending on the existence * of the file with the same name. */ status = HgfsPlatformFileExists(utf8Name); if (HGFS_ERROR_SUCCESS == status) { status = HGFS_ERROR_ACCESS_DENIED; } LOG(4, "HgfsServerDeleteDir: failed access check, error %d\n", status); } else { LOG(4, "%s: removing \"%s\"\n", __FUNCTION__, utf8Name); status = HgfsPlatformDeleteDirByName(utf8Name); } free(utf8Name); } else { LOG(4, "%s: access check failed\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } } if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackDeleteReply(input->packet, input->request, input->op, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerServerLockChange -- * * Called by the client when it wants to either acquire an oplock on a file * that was previously opened, or when it wants to release/downgrade an * oplock on a file that was previously oplocked. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerServerLockChange(HgfsInputParam *input) // IN: Input params { HGFS_ASSERT_INPUT(input); HgfsServerCompleteRequest(HGFS_ERROR_NOT_SUPPORTED, 0, input); } /* *----------------------------------------------------------------------------- * * HgfsServerWriteWin32Stream -- * * Handle a write request in the WIN32_STREAM_ID format. * * Results: * ERROR_SUCCESS or an appropriate Win32 error code. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerWriteWin32Stream(HgfsInputParam *input) // IN: Input params { uint32 actualSize; HgfsInternalStatus status; HgfsHandle file; const char *dataToWrite; Bool doSecurity; size_t replyPayloadSize = 0; size_t requiredSize; HGFS_ASSERT_INPUT(input); if (HgfsUnpackWriteWin32StreamRequest(input->payload, input->payloadSize, input->op, &file, &dataToWrite, &requiredSize, &doSecurity)) { status = HgfsPlatformWriteWin32Stream(file, (char *)dataToWrite, (uint32)requiredSize, doSecurity, &actualSize, input->session); if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackWriteWin32StreamReply(input->packet, input->request, input->op, actualSize, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerSetDirWatchByHandle -- * * Sets directory notification watch request using directory handle. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerSetDirWatchByHandle(HgfsInputParam *input, // IN: Input params HgfsHandle dir, // IN: directory handle uint32 events, // IN: event types to report Bool watchTree, // IN: recursive watch HgfsSubscriberHandle *watchId) // OUT: watch id { HgfsInternalStatus status; char *fileName = NULL; size_t fileNameSize; HgfsSharedFolderHandle sharedFolder = HGFS_INVALID_FOLDER_HANDLE; LOG(8, "%s: entered\n", __FUNCTION__); ASSERT(watchId != NULL); if (HgfsHandle2NotifyInfo(dir, input->session, &fileName, &fileNameSize, &sharedFolder)) { LOG(4, "%s: adding a subscriber on shared folder handle %#x\n", __FUNCTION__, sharedFolder); *watchId = HgfsNotify_AddSubscriber(sharedFolder, fileName, events, watchTree, input->session); status = (HGFS_INVALID_SUBSCRIBER_HANDLE == *watchId) ? HGFS_ERROR_INTERNAL : HGFS_ERROR_SUCCESS; LOG(4, "%s: result of add subscriber id %"FMT64"x status %u\n", __FUNCTION__, *watchId, status); } else { status = HGFS_ERROR_INTERNAL; } free(fileName); LOG(8, "%s: exit %u\n", __FUNCTION__, status); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerSetDirWatchByName -- * * Sets directory notification watch request using directory name. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerSetDirWatchByName(HgfsInputParam *input, // IN: Input params const char *cpName, // IN: directory name uint32 cpNameSize, // IN: directory name length uint32 caseFlags, // IN: case flags uint32 events, // IN: event types to report Bool watchTree, // IN: recursive watch HgfsSubscriberHandle *watchId) // OUT: watch id { HgfsInternalStatus status; HgfsNameStatus nameStatus; char *utf8Name = NULL; size_t utf8NameLen; HgfsShareInfo shareInfo; HgfsSharedFolderHandle sharedFolder = HGFS_INVALID_FOLDER_HANDLE; ASSERT(cpName != NULL); ASSERT(watchId != NULL); LOG(8, "%s: entered\n",__FUNCTION__); nameStatus = HgfsServerGetLocalNameInfo(cpName, cpNameSize, caseFlags, input->session, &shareInfo, &utf8Name, &utf8NameLen); if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { char const *inEnd = cpName + cpNameSize; char const *next; int len; ASSERT(utf8Name); /* * Get first component. */ len = CPName_GetComponent(cpName, inEnd, (char const **) &next); if (len < 0) { LOG(4, "%s: get first component failed\n", __FUNCTION__); nameStatus = HGFS_NAME_STATUS_FAILURE; } else if (0 == len) { /* See if we are dealing with the base of the namespace */ nameStatus = HGFS_NAME_STATUS_INCOMPLETE_BASE; } else { sharedFolder = shareInfo.handle; } if (HGFS_NAME_STATUS_COMPLETE == nameStatus && HGFS_INVALID_FOLDER_HANDLE != sharedFolder) { if (cpNameSize > len + 1) { size_t nameSize = cpNameSize - len - 1; char tempBuf[HGFS_PATH_MAX]; char *tempPtr = tempBuf; size_t tempSize = sizeof tempBuf; nameStatus = CPName_ConvertFrom((char const **) &next, &nameSize, &tempSize, &tempPtr); if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { LOG(8, "%s: session %p id %"FMT64"x on share hnd %#x\n", __FUNCTION__, input->session, input->session->sessionId, sharedFolder); *watchId = HgfsNotify_AddSubscriber(sharedFolder, tempBuf, events, watchTree, input->session); status = (HGFS_INVALID_SUBSCRIBER_HANDLE == *watchId) ? HGFS_ERROR_INTERNAL : HGFS_ERROR_SUCCESS; LOG(8, "%s: watchId %"FMT64"x result %u\n", __FUNCTION__, *watchId, status); } else { LOG(4, "%s: Conversion to platform specific name failed\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } } else { LOG(8, "%s: adding subscriber on share hnd %#x\n", __FUNCTION__, sharedFolder); *watchId = HgfsNotify_AddSubscriber(sharedFolder, "", events, watchTree, input->session); status = (HGFS_INVALID_SUBSCRIBER_HANDLE == *watchId) ? HGFS_ERROR_INTERNAL : HGFS_ERROR_SUCCESS; LOG(8, "%s: adding subscriber on share hnd %#x watchId %"FMT64"x result %u\n", __FUNCTION__, sharedFolder, *watchId, status); } } else if (HGFS_NAME_STATUS_INCOMPLETE_BASE == nameStatus) { LOG(4, "%s: Notification for root share is not supported yet\n", __FUNCTION__); status = HGFS_ERROR_INVALID_PARAMETER; } else { LOG(4, "%s: file not found.\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } } else { LOG(4, "%s: file not found.\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } free(utf8Name); LOG(8, "%s: exit %u\n",__FUNCTION__, status); return status; } /* *----------------------------------------------------------------------------- * * HgfsServerSetDirNotifyWatch -- * * Handle a set directory notification watch request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerSetDirNotifyWatch(HgfsInputParam *input) // IN: Input params { const char *cpName; size_t cpNameSize; HgfsInternalStatus status; HgfsHandle dir; uint32 caseFlags; size_t replyPayloadSize = 0; uint32 flags; uint32 events; HgfsSubscriberHandle watchId = HGFS_INVALID_SUBSCRIBER_HANDLE; Bool useHandle; HGFS_ASSERT_INPUT(input); LOG(8, "%s: entered\n", __FUNCTION__); /* * If the active session does not support directory change notification - bail out * with an error immediately. * Clients are expected to check the session capabilities and flags but a malicious * or broken client could still issue this to us. */ if (0 == (input->session->flags & HGFS_SESSION_CHANGENOTIFY_ENABLED)) { HgfsServerCompleteRequest(HGFS_ERROR_PROTOCOL, 0, input); return; } if (HgfsUnpackSetWatchRequest(input->payload, input->payloadSize, input->op, &useHandle, &cpName, &cpNameSize, &flags, &events, &dir, &caseFlags)) { Bool watchTree = 0 != (flags & HGFS_NOTIFY_FLAG_WATCH_TREE); if (useHandle) { status = HgfsServerSetDirWatchByHandle(input, dir, events, watchTree, &watchId); } else { status = HgfsServerSetDirWatchByName(input, cpName, cpNameSize, caseFlags, events, watchTree, &watchId); } if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackSetWatchReply(input->packet, input->request, input->op, watchId, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); LOG(8, "%s: exit %u\n", __FUNCTION__, status); } /* *----------------------------------------------------------------------------- * * HgfsServerRemoveDirNotifyWatch -- * * Handle a remove directory notification watch request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerRemoveDirNotifyWatch(HgfsInputParam *input) // IN: Input params { HgfsSubscriberHandle watchId; HgfsInternalStatus status; size_t replyPayloadSize = 0; LOG(8, "%s: entered\n", __FUNCTION__); HGFS_ASSERT_INPUT(input); /* * If the active session does not support directory change notification - bail out * with an error immediately. * Clients are expected to check the session capabilities and flags but a malicious * or broken client could still issue this to us. */ if (0 == (input->session->flags & HGFS_SESSION_CHANGENOTIFY_ENABLED)) { HgfsServerCompleteRequest(HGFS_ERROR_PROTOCOL, 0, input); return; } if (HgfsUnpackRemoveWatchRequest(input->payload, input->payloadSize, input->op, &watchId)) { LOG(8, "%s: remove subscriber on subscr id %"FMT64"x\n", __FUNCTION__, watchId); if (HgfsNotify_RemoveSubscriber(watchId)) { status = HGFS_ERROR_SUCCESS; } else { status = HGFS_ERROR_INTERNAL; } LOG(8, "%s: remove subscriber on subscr id %"FMT64"x result %u\n", __FUNCTION__, watchId, status); } else { status = HGFS_ERROR_PROTOCOL; } if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackRemoveWatchReply(input->packet, input->request, input->op, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } HgfsServerCompleteRequest(status, replyPayloadSize, input); LOG(8, "%s: exit result %u\n", __FUNCTION__, status); } /* *----------------------------------------------------------------------------- * * HgfsServerGetattr -- * * Handle a Getattr request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerGetattr(HgfsInputParam *input) // IN: Input params { char *localName = NULL; HgfsAttrHint hints = 0; HgfsFileAttrInfo attr; HgfsInternalStatus status = 0; HgfsNameStatus nameStatus; const char *cpName; size_t cpNameSize; char *targetName = NULL; uint32 targetNameLen = 0; HgfsHandle file; /* file handle from driver */ uint32 caseFlags = 0; HgfsShareOptions configOptions; size_t localNameLen; HgfsShareInfo shareInfo; size_t replyPayloadSize = 0; HgfsSessionInfo *session; HgfsFileAttrCacheEntry *entry; HGFS_ASSERT_INPUT(input); session = input->session; if (HgfsUnpackGetattrRequest(input->payload, input->payloadSize, input->op, &attr, &hints, &cpName, &cpNameSize, &file, &caseFlags)) { /* Client wants us to reuse an existing handle. */ if (hints & HGFS_ATTR_HINT_USE_FILE_DESC) { fileDesc fd; HgfsFileNode node; Bool found; memset(&node, 0, sizeof node); found = HgfsGetNodeCopy(file, session, TRUE, &node); if (found && NULL != session->fileAttrCache && HgfsCache_Get(session->fileAttrCache, node.utf8Name, (void **)&entry)) { attr = entry->attr; status = HGFS_ERROR_SUCCESS; } else { targetNameLen = 0; status = HgfsPlatformGetFd(file, session, FALSE, &fd); if (HGFS_ERROR_SUCCESS == status) { status = HgfsPlatformGetattrFromFd(fd, session, &attr); if (found && HGFS_ERROR_SUCCESS == status && NULL != session->fileAttrCache) { HOM_HANDLE handle = HgfsOplockMonitorFileChange(node.utf8Name, session, HgfsOplockFileChangeCb, Util_SafeStrdup(node.utf8Name)); if (handle != HGFS_OPLOCK_INVALID_MONITOR_HANDLE) { entry = Util_SafeCalloc(1, sizeof *entry); entry->handle = handle; entry->attr = attr; HgfsCache_Put(session->fileAttrCache, node.utf8Name, entry); } } } else { LOG(4, "%s: Could not get file descriptor\n", __FUNCTION__); } } if (found) { free(node.utf8Name); } } else { /* * Depending on whether this file/dir is real or virtual, either * forge its attributes or look them up in the actual filesystem. */ nameStatus = HgfsServerGetLocalNameInfo(cpName, cpNameSize, caseFlags, session, &shareInfo, &localName, &localNameLen); switch (nameStatus) { case HGFS_NAME_STATUS_INCOMPLETE_BASE: /* * This is the base of our namespace; make up fake status for * this directory. */ LOG(4, "%s: getting attrs for base dir\n", __FUNCTION__); HgfsPlatformGetDefaultDirAttrs(&attr); break; case HGFS_NAME_STATUS_COMPLETE: /* This is a regular lookup; proceed as usual */ ASSERT(localName); if (NULL != session->fileAttrCache && HgfsCache_Get(session->fileAttrCache, localName, (void **)&entry)) { attr = entry->attr; status = HGFS_ERROR_SUCCESS; } else { /* Get the config options. */ nameStatus = HgfsServerPolicy_GetShareOptions(cpName, cpNameSize, &configOptions); if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { status = HgfsPlatformGetattrFromName(localName, configOptions, (char *)cpName, &attr, &targetName); if (HGFS_ERROR_SUCCESS == status && NULL != session->fileAttrCache) { HOM_HANDLE handle = HgfsOplockMonitorFileChange(localName, session, HgfsOplockFileChangeCb, Util_SafeStrdup(localName)); if (handle != HGFS_OPLOCK_INVALID_MONITOR_HANDLE) { entry = Util_SafeCalloc(1, sizeof *entry); entry->handle = handle; entry->attr = attr; HgfsCache_Put(session->fileAttrCache, localName, entry); } } } else { LOG(4, "%s: no matching share: %s.\n", __FUNCTION__, cpName); status = HGFS_ERROR_FILE_NOT_FOUND; } if (HGFS_ERROR_SUCCESS == status && !HgfsServer_ShareAccessCheck(HGFS_OPEN_MODE_READ_ONLY, shareInfo.writePermissions, shareInfo.readPermissions)) { status = HGFS_ERROR_ACCESS_DENIED; } else if (status != HGFS_ERROR_SUCCESS) { /* * If it is a dangling share server should not return * HGFS_ERROR_FILE_NOT_FOUND * to the client because it causes confusion: a name that is returned * by directory enumeration should not produce "name not found" * error. * Replace it with a more appropriate error code: no such device. */ if (status == HGFS_ERROR_FILE_NOT_FOUND && HgfsServerIsSharedFolderOnly(cpName, cpNameSize)) { status = HGFS_ERROR_IO; } } } break; default: status = HgfsPlatformHandleIncompleteName(nameStatus, &attr); } targetNameLen = targetName ? strlen(targetName) : 0; } if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackGetattrReply(input->packet, input->request, &attr, targetName, targetNameLen, &replyPayloadSize, session)) { status = HGFS_ERROR_INTERNAL; } } } else { status = HGFS_ERROR_PROTOCOL; } free(targetName); free(localName); HgfsServerCompleteRequest(status, replyPayloadSize, input); /* * Contrary to Coverity analysis, storage pointed to by the variable * "entry" is not leaked; HgfsCache_Put stores a pointer to it in the * symlink cache. However, no Coverity annotation for leaked_storage * is added here because such an annotation cannot be made specific to * entry; as a result, if any actual memory leaks were to be introduced * by a future change, the leaked_storage annotation would cause such * new leaks to be flagged as false positives. * * XXX - can something be done with Coverity function models so that * Coverity stops reporting this? */ } /* *----------------------------------------------------------------------------- * * HgfsServerSetattr -- * * Handle a Setattr request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerSetattr(HgfsInputParam *input) // IN: Input params { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; HgfsNameStatus nameStatus; HgfsFileAttrInfo attr; const char *cpName; size_t cpNameSize = 0; HgfsAttrHint hints = 0; HgfsOpenMode shareMode; uint32 caseFlags = 0; HgfsShareInfo shareInfo; HgfsHandle file; size_t replyPayloadSize = 0; HGFS_ASSERT_INPUT(input); if (HgfsUnpackSetattrRequest(input->payload, input->payloadSize, input->op, &attr, &hints, &cpName, &cpNameSize, &file, &caseFlags)) { Bool useHostTime = 0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_USE_HOST_TIME); /* Client wants us to reuse an existing handle. */ if (hints & HGFS_ATTR_HINT_USE_FILE_DESC) { if (HgfsHandle2ShareMode(file, input->session, &shareMode)) { if (HGFS_OPEN_MODE_READ_ONLY != shareMode) { status = HgfsPlatformSetattrFromFd(file, input->session, &attr, hints, useHostTime); } else { status = HGFS_ERROR_ACCESS_DENIED; } } else { LOG(4, "%s: could not get share mode fd %d\n", __FUNCTION__, file); status = HGFS_ERROR_INVALID_HANDLE; } } else { /* Client wants us to open a new handle for this operation. */ char *utf8Name = NULL; size_t utf8NameLen; nameStatus = HgfsServerGetLocalNameInfo(cpName, cpNameSize, caseFlags, input->session, &shareInfo, &utf8Name, &utf8NameLen); if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { fileDesc hFile; HgfsLockType serverLock = HGFS_LOCK_NONE; HgfsShareOptions configOptions; /* * XXX: If the client has an oplock on this file, it must reuse the * handle for the oplocked node (or break the oplock) prior to making * a setattr request. Fail this request. */ if (!HgfsServer_ShareAccessCheck(HGFS_OPEN_MODE_WRITE_ONLY, shareInfo.writePermissions, shareInfo.readPermissions)) { status = HGFS_ERROR_ACCESS_DENIED; } else if (HGFS_NAME_STATUS_COMPLETE != HgfsServerPolicy_GetShareOptions(cpName, cpNameSize, &configOptions)) { LOG(4, "%s: no matching share: %s.\n", __FUNCTION__, cpName); status = HGFS_ERROR_FILE_NOT_FOUND; } else if (HgfsFileHasServerLock(utf8Name, input->session, &serverLock, &hFile)) { LOG(4, "%s: An open, oplocked handle exists for " "this file. The client should retry with that handle\n", __FUNCTION__); status = HGFS_ERROR_PATH_BUSY; } else { status = HgfsPlatformSetattrFromName(utf8Name, &attr, configOptions, hints, useHostTime); } free(utf8Name); } else { LOG(4, "%s: file not found.\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } } if (HGFS_ERROR_SUCCESS == status) { if (!HgfsPackSetattrReply(input->packet, input->request, attr.requestType, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerValidateOpenParameters -- * * Performs confidence check of the input parameters. * * Results: * HGFS_ERROR_SUCCESS if the parameters are valid. * Appropriate error code otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsServerValidateOpenParameters(HgfsFileOpenInfo *openInfo, // IN/OUT: openfile info HgfsSessionInfo *session, // IN: Session info Bool *denyCreatingFile, // OUT: No new files int *followSymlinks) // OUT: Host resolves link { size_t utf8NameLen; HgfsInternalStatus status; *followSymlinks = 0; *denyCreatingFile = FALSE; if ((openInfo->mask & HGFS_OPEN_VALID_MODE)) { HgfsNameStatus nameStatus; /* It is now safe to read the file name. */ nameStatus = HgfsServerGetLocalNameInfo(openInfo->cpName, openInfo->cpNameSize, openInfo->caseFlags, session, &openInfo->shareInfo, &openInfo->utf8Name, &utf8NameLen); if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { if (openInfo->mask & HGFS_OPEN_VALID_FLAGS) { HgfsOpenFlags savedOpenFlags = openInfo->flags; if (HgfsServerCheckOpenFlagsForShare(openInfo, &openInfo->flags)) { HgfsShareOptions configOptions; /* Get the config options. */ nameStatus = HgfsServerPolicy_GetShareOptions(openInfo->cpName, openInfo->cpNameSize, &configOptions); if (nameStatus == HGFS_NAME_STATUS_COMPLETE) { *followSymlinks = HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS); *denyCreatingFile = savedOpenFlags != openInfo->flags; status = HGFS_ERROR_SUCCESS; } else { LOG(4, "%s: no matching share: %s.\n", __FUNCTION__, openInfo->cpName); *denyCreatingFile = TRUE; status = HGFS_ERROR_FILE_NOT_FOUND; } } else { /* Incompatible open mode with share mode. */ status = HGFS_STATUS_ACCESS_DENIED; } } else { status = HGFS_ERROR_PROTOCOL; } } else { /* * Check if the name does not exist - the share was not found. * Then it could one of two things: the share was removed/disabled; * or we could be in the root share itself and have a new name. * To return the correct error, if we are in the root share, * we must check the open mode too - creation of new files/folders * should fail access denied, for anything else "not found" is acceptable. */ if (nameStatus == HGFS_NAME_STATUS_DOES_NOT_EXIST) { if ((openInfo->mask & HGFS_OPEN_VALID_FLAGS && (openInfo->flags == HGFS_OPEN_CREATE || openInfo->flags == HGFS_OPEN_CREATE_SAFE || openInfo->flags == HGFS_OPEN_CREATE_EMPTY)) && HgfsServerIsSharedFolderOnly(openInfo->cpName, openInfo->cpNameSize)) { nameStatus = HGFS_NAME_STATUS_ACCESS_DENIED; LOG(4, "%s: New file creation in share root not allowed\n", __FUNCTION__); } else { LOG(4, "%s: Shared folder not found\n", __FUNCTION__); } } else { LOG(4, "%s: Shared folder access error %u\n", __FUNCTION__, nameStatus); } status = HgfsPlatformConvertFromNameStatus(nameStatus); } } else { LOG(4, "%s: filename or mode not provided\n", __FUNCTION__); status = HGFS_ERROR_PROTOCOL; } return status; } /* *----------------------------------------------------------------------------- * * HgfsServerOpen -- * * Handle an Open request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerOpen(HgfsInputParam *input) // IN: Input params { HgfsInternalStatus status; fileDesc newHandle; HgfsLocalId localId; HgfsFileOpenInfo openInfo; fileDesc fileDesc; HgfsLockType serverLock = HGFS_LOCK_NONE; size_t replyPayloadSize = 0; HGFS_ASSERT_INPUT(input); if (HgfsUnpackOpenRequest(input->payload, input->payloadSize, input->op, &openInfo)) { int followSymlinks; Bool denyCreatingFile; status = HgfsServerValidateOpenParameters(&openInfo, input->session, &denyCreatingFile, &followSymlinks); if (HGFS_ERROR_SUCCESS == status) { ASSERT(openInfo.utf8Name); LOG(4, "%s: opening \"%s\", mode %u, flags %u, perms %u%u%u%u attr %u\n", __FUNCTION__, openInfo.utf8Name, openInfo.mode, openInfo.mask & HGFS_OPEN_VALID_FLAGS ? openInfo.flags : 0, (openInfo.mask & HGFS_OPEN_VALID_SPECIAL_PERMS) ? openInfo.specialPerms : 0, (openInfo.mask & HGFS_OPEN_VALID_OWNER_PERMS) ? openInfo.ownerPerms : 0, (openInfo.mask & HGFS_OPEN_VALID_GROUP_PERMS) ? openInfo.groupPerms : 0, (openInfo.mask & HGFS_OPEN_VALID_OTHER_PERMS) ? openInfo.otherPerms : 0, openInfo.mask & HGFS_OPEN_VALID_FILE_ATTR ? (uint32)openInfo.attr : 0); /* * XXX: Before opening the file, see if we already have this file opened on * the server with an oplock on it. If we do, we must fail the new open * request, otherwise we will trigger an oplock break that the guest cannot * handle at this time (since the HGFS server is running in the context of * the vcpu thread), and we'll deadlock. * * Until we overcome this limitation via Crosstalk, we will be extra smart * in the client drivers so as to prevent open requests on handles that * already have an oplock. And the server will protect itself like so. * * XXX: With some extra effort, we could allow a second open for read here, * since that won't break a shared oplock, but the clients should already * realize that the second open can be avoided via sharing handles, too. */ if (!HgfsFileHasServerLock(openInfo.utf8Name, input->session, &serverLock, &fileDesc)) { /* See if the name is valid, and if so add it and return the handle. */ status = HgfsPlatformValidateOpen(&openInfo, followSymlinks, input->session, &localId, &newHandle); if (status == HGFS_ERROR_SUCCESS) { ASSERT(newHandle >= 0); /* * Open succeeded, so make new node and return its handle. If we fail, * it's almost certainly an internal server error. */ if (HgfsCreateAndCacheFileNode(&openInfo, &localId, newHandle, FALSE, input->session)) { if (!HgfsPackOpenReply(input->packet, input->request, &openInfo, &replyPayloadSize, input->session)) { status = HGFS_ERROR_INTERNAL; } } } else if (denyCreatingFile && HGFS_ERROR_FILE_NOT_FOUND == status) { status = HGFS_ERROR_ACCESS_DENIED; } } else { status = HGFS_ERROR_PATH_BUSY; } free(openInfo.utf8Name); } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerSearchReadAttrToMask -- * * Sets a search read information mask from the retrieved attribute * information. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerSearchReadAttrToMask(HgfsFileAttrInfo *attr, // IN/OUT: attributes for entry HgfsSearchReadMask *mask) // IN/OUT: what info is required/returned { if (0 != (attr->mask & HGFS_ATTR_VALID_TYPE)) { *mask |= (HGFS_SEARCH_READ_FILE_NODE_TYPE); } if (0 != (attr->mask & HGFS_ATTR_VALID_SIZE)) { *mask |= (HGFS_SEARCH_READ_FILE_SIZE); } if (0 != (attr->mask & HGFS_ATTR_VALID_ALLOCATION_SIZE)) { *mask |= (HGFS_SEARCH_READ_ALLOCATION_SIZE); } if (0 != (attr->mask & (HGFS_ATTR_VALID_CREATE_TIME | HGFS_ATTR_VALID_ACCESS_TIME | HGFS_ATTR_VALID_WRITE_TIME | HGFS_ATTR_VALID_CHANGE_TIME))) { *mask |= (HGFS_SEARCH_READ_TIME_STAMP); } if (0 != (attr->mask & (HGFS_ATTR_VALID_FLAGS | HGFS_ATTR_VALID_OWNER_PERMS | HGFS_ATTR_VALID_GROUP_PERMS | HGFS_ATTR_VALID_OTHER_PERMS))) { Bool isReadOnly = TRUE; *mask |= (HGFS_SEARCH_READ_FILE_ATTRIBUTES); /* * For V4 we don't return the permissions as they are really not * used. Only used to see if the entry is read only. So set the * attribute flag if the entry is read only. */ if (attr->mask & HGFS_ATTR_VALID_OWNER_PERMS && attr->ownerPerms & HGFS_PERM_WRITE) { isReadOnly = FALSE; } if (attr->mask & HGFS_ATTR_VALID_GROUP_PERMS && attr->groupPerms & HGFS_PERM_WRITE) { isReadOnly = FALSE; } if (attr->mask & HGFS_ATTR_VALID_OTHER_PERMS && attr->otherPerms & HGFS_PERM_WRITE) { isReadOnly = FALSE; } if (isReadOnly) { attr->flags |= HGFS_ATTR_READONLY; attr->mask |= HGFS_ATTR_VALID_FLAGS; } } if (0 != (attr->mask & (HGFS_ATTR_VALID_FILEID | HGFS_ATTR_VALID_NON_STATIC_FILEID))) { *mask |= (HGFS_SEARCH_READ_FILE_ID); } } /* *----------------------------------------------------------------------------- * * HgfsGetDirEntry -- * * Gets a directory entry at specified index. * * Results: * A platform specific error or success. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsGetDirEntry(HgfsHandle hgfsSearchHandle, // IN: ID for search data HgfsSearch *search, // IN: search data HgfsShareOptions configOptions, // IN: share configuration settings HgfsSessionInfo *session, // IN: session we are called in HgfsSearchReadInfo *info, // IN/OUT: request details HgfsSearchReadEntry *entry, // OUT: directory entry Bool *moreEntries) // OUT: any more entries { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; struct DirectoryEntry *dent; HgfsSearchReadMask infoRetrieved; HgfsSearchReadMask infoRequested; HgfsFileAttrInfo *entryAttr; char **entryName; uint32 *entryNameLength; Bool getAttrs; uint32 requestedIndex; infoRequested = info->requestedMask; entryAttr = &entry->attr; entryName = &entry->name; entryNameLength = &entry->nameLength; requestedIndex = info->currentIndex; getAttrs = (0 != (infoRequested & (HGFS_SEARCH_READ_FILE_SIZE | HGFS_SEARCH_READ_ALLOCATION_SIZE | HGFS_SEARCH_READ_TIME_STAMP | HGFS_SEARCH_READ_FILE_ATTRIBUTES | HGFS_SEARCH_READ_FILE_ID | HGFS_SEARCH_READ_FILE_NODE_TYPE))); /* Clear out what we will return. */ infoRetrieved = 0; memset(entryAttr, 0, sizeof *entryAttr); *moreEntries = FALSE; *entryName = NULL; *entryNameLength = 0; status = HgfsServerGetDirEntry(hgfsSearchHandle, session, requestedIndex, FALSE, &dent); if (HGFS_ERROR_SUCCESS != status) { goto exit; } if (NULL == dent) { /* End of directory entries marker. */ info->replyFlags |= HGFS_SEARCH_READ_REPLY_FINAL_ENTRY; HgfsSearchSetReadAllEntries(hgfsSearchHandle, session); goto exit; } status = HgfsPlatformSetDirEntry(search, configOptions, session, dent, getAttrs, entryAttr, entryName, entryNameLength); if (HGFS_ERROR_SUCCESS != status) { goto exit; } if (getAttrs) { /* * Update the search read mask for the attributes information. */ HgfsServerSearchReadAttrToMask(entryAttr, &infoRetrieved); } infoRetrieved |= HGFS_SEARCH_READ_NAME; /* Update the entry fields for valid data and index for the dent. */ entry->mask = infoRetrieved; entry->fileIndex = requestedIndex; *moreEntries = TRUE; exit: free(dent); return status; } /* *----------------------------------------------------------------------------- * * HgfsDoSearchRead -- * * Gets all the directory entries that remain or as many that will * fit into the reply buffer from the specified index. Fill in the * reply with the records and complete the reply details. * * Results: * A platform specific error or success. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsDoSearchRead(HgfsHandle hgfsSearchHandle, // IN: ID for search data HgfsSearch *search, // IN: search data HgfsShareOptions configOptions, // IN: share configuration settings HgfsSessionInfo *session, // IN: session we are called in HgfsSearchReadInfo *info, // IN/OUT: request details size_t *replyHeaderSize, // OUT: reply info written size size_t *replyDirentSize) // OUT: reply dirent written size { HgfsSearchReadEntry entry; size_t bytesWritten = 0; size_t bytesRemaining = 0; char *currentSearchReadRecord = NULL; char *lastSearchReadRecord = NULL; Bool moreEntries = TRUE; HgfsInternalStatus status = HGFS_ERROR_SUCCESS; info->currentIndex = info->startIndex; *replyHeaderSize = 0; *replyDirentSize = 0; while (moreEntries) { size_t offsetInBuffer = ROUNDUP(*replyDirentSize, sizeof (uint64)); if (info->payloadSize <= offsetInBuffer) { break; } memset(&entry, 0, sizeof entry); currentSearchReadRecord = (char*)info->replyPayload + offsetInBuffer; bytesRemaining = info->payloadSize - offsetInBuffer; bytesWritten = 0; status = HgfsGetDirEntry(hgfsSearchHandle, search, configOptions, session, info, &entry, &moreEntries); if (HGFS_ERROR_SUCCESS != status) { /* Failed to retrieve an entry record, bail. */ break; } if (!HgfsPackSearchReadReplyRecord(info->requestType, &entry, bytesRemaining, lastSearchReadRecord, currentSearchReadRecord, &bytesWritten)) { /* * The current entry is too large to be contained in the reply. * If this is the first entry returned then we have an error. * Otherwise, we return success for what is already in the reply. */ if (0 == info->numberRecordsWritten) { status = HGFS_ERROR_INTERNAL; } moreEntries = FALSE; } if (NULL != entry.name) { free(entry.name); } if (HGFS_ERROR_SUCCESS != status) { /* Failed to pack any entry records, bail. */ break; } /* * Only count records actually written to the reply. * (The final, empty record is not written for all protocol versions.) */ if (0 < bytesWritten) { if (0 != (info->flags & HGFS_SEARCH_READ_SINGLE_ENTRY)) { moreEntries = FALSE; } *replyDirentSize = ROUNDUP(*replyDirentSize, sizeof (uint64)) + bytesWritten; lastSearchReadRecord = currentSearchReadRecord; info->currentIndex++; info->numberRecordsWritten++; } } /* Now pack the search read reply common reply part. */ if (HgfsPackSearchReadReplyHeader(info, &bytesWritten)) { /* The search read reply common reply part size was already done so should be 0. */ *replyHeaderSize = bytesWritten; } else { status = HGFS_ERROR_PROTOCOL; } return status; } /* *----------------------------------------------------------------------------- * * HgfsServerSearchRead -- * * Handle a "Search Read" request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerSearchRead(HgfsInputParam *input) // IN: Input params { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; HgfsNameStatus nameStatus; HgfsHandle hgfsSearchHandle; HgfsSearch search; HgfsShareOptions configOptions = 0; size_t replyInfoSize = 0; size_t replyDirentSize = 0; size_t replyPayloadSize = 0; size_t inlineDataSize = 0; size_t baseReplySize; HgfsSearchReadInfo info; HGFS_ASSERT_INPUT(input); memset(&info, 0, sizeof info); /* * For search read V4 we use the whole packet buffer available to pack * as many replies as can fit into that size. For all previous versions * only one record is going to be returned, so we allow the old packet * max for the reply. */ if (HgfsUnpackSearchReadRequest(input->payload, input->payloadSize, input->op, &info, &baseReplySize, &inlineDataSize, &hgfsSearchHandle)) { LOG(4, "%s: read search #%u, offset %u\n", __FUNCTION__, hgfsSearchHandle, info.startIndex); info.reply = HgfsAllocInitReply(input->packet, input->request, baseReplySize + inlineDataSize, input->session); if (inlineDataSize == 0) { info.replyPayload = HSPU_GetDataPacketBuf(input->packet, BUF_WRITEABLE, input->transportSession->channelCbTable); } else { info.replyPayload = (char *)info.reply + baseReplySize; } if (info.replyPayload == NULL) { LOG(4, "%s: Op %d reply buffer failure\n", __FUNCTION__, input->op); status = HGFS_ERROR_PROTOCOL; } else { if (HgfsGetSearchCopy(hgfsSearchHandle, input->session, &search)) { /* Get the config options. */ if (search.utf8ShareNameLen != 0) { nameStatus = HgfsServerPolicy_GetShareOptions(search.utf8ShareName, search.utf8ShareNameLen, &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, "%s: no matching share: %s.\n", __FUNCTION__, search.utf8ShareName); status = HGFS_ERROR_FILE_NOT_FOUND; } } else if (0 == info.startIndex) { Bool readAllEntries = FALSE; /* * Reading the first entry, we check if this is a second scan * of the directory. If so, in some cases we restart the scan * by refreshing the entries first. */ if (!HgfsSearchHasReadAllEntries(hgfsSearchHandle, input->session, &readAllEntries)) { status = HGFS_ERROR_INTERNAL; } if (readAllEntries) { /* * XXX - a hack that is now required until Fusion 5.0 end * of lifes see bug 710697. * The coder modified the server instead of the OS X client * for the shares directory refresh needed by OS X clients in * order to work around handles remaining open by Finder. * This was fixed CLN 1988575 in the OS X client for 5.0.2. * However, Fusion 4.0 and Fusion 5.0 tools will rely on this hack. * At least now it works correctly without breaking everything * else. */ status = HgfsPlatformRestartSearchDir(hgfsSearchHandle, input->session, search.type); } } if (HGFS_ERROR_SUCCESS == status) { status = HgfsDoSearchRead(hgfsSearchHandle, &search, configOptions, input->session, &info, &replyInfoSize, &replyDirentSize); } if (HGFS_ERROR_SUCCESS == status) { replyPayloadSize = replyInfoSize + ((inlineDataSize == 0) ? 0 : replyDirentSize); if (0 == inlineDataSize) { HSPU_SetDataPacketSize(input->packet, replyDirentSize); } } free(search.utf8Dir); free(search.utf8ShareName); } else { LOG(4, "%s: handle %u is invalid\n", __FUNCTION__, hgfsSearchHandle); status = HGFS_ERROR_INVALID_HANDLE; } } } else { status = HGFS_ERROR_PROTOCOL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerCreateSession -- * * Handle a "Create session" request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerCreateSession(HgfsInputParam *input) // IN: Input params { size_t replyPayloadSize = 0; HgfsCreateSessionInfo info; HgfsInternalStatus status; HGFS_ASSERT_INPUT(input); if (HgfsUnpackCreateSessionRequest(input->payload, input->payloadSize, input->op, &info)) { HgfsSessionInfo *session; LOG(4, "%s: create session\n", __FUNCTION__); if (!HgfsServerAllocateSession(input->transportSession, info, &session)) { status = HGFS_ERROR_NOT_ENOUGH_MEMORY; goto quit; } else { status = HgfsServerTransportAddSessionToList(input->transportSession, session); if (HGFS_ERROR_SUCCESS != status) { LOG(4, "%s: Could not add session to the list.\n", __FUNCTION__); HgfsServerSessionPut(session); goto quit; } } if (HgfsPackCreateSessionReply(input->packet, input->request, &replyPayloadSize, session)) { status = HGFS_ERROR_SUCCESS; } else { status = HGFS_ERROR_INTERNAL; } } else { status = HGFS_ERROR_PROTOCOL; } quit: HgfsServerCompleteRequest(status, replyPayloadSize, input); } /* *----------------------------------------------------------------------------- * * HgfsServerDestroySession -- * * Handle a "Destroy session" request. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerDestroySession(HgfsInputParam *input) // IN: Input params { HgfsTransportSessionInfo *transportSession; HgfsSessionInfo *session; size_t replyPayloadSize = 0; HgfsInternalStatus status; HGFS_ASSERT_INPUT(input); transportSession = input->transportSession; session = input->session; session->state = HGFS_SESSION_STATE_CLOSED; if (session->sessionId == transportSession->defaultSessionId) { transportSession->defaultSessionId = HGFS_INVALID_SESSION_ID; } if (0 != (gHgfsCfgSettings.flags & HGFS_CONFIG_OPLOCK_MONITOR_ENABLED)) { HgfsCache_Destroy(session->symlinkCache); session->symlinkCache = NULL; HgfsCache_Destroy(session->fileAttrCache); session->fileAttrCache = NULL; } /* * Remove the session from the list. By doing that, the refcount of * the session will be decremented. Later, we will be invoking * HgfsServerCompleteRequest which will decrement the session's * refcount and cleanup the session */ MXUser_AcquireExclLock(transportSession->sessionArrayLock); HgfsServerTransportRemoveSessionFromList(transportSession, session); MXUser_ReleaseExclLock(transportSession->sessionArrayLock); if (HgfsPackDestroySessionReply(input->packet, input->request, &replyPayloadSize, session)) { status = HGFS_ERROR_SUCCESS; } else { status = HGFS_ERROR_INTERNAL; } HgfsServerCompleteRequest(status, replyPayloadSize, input); HgfsServerSessionPut(session); } /* *----------------------------------------------------------------------------- * * HgfsServerGetTargetRelativePath -- * * Generates relative file path which need to be used a symbolic link * target which would generate target name defined in "target" if the path * to symbolic link file defined in the "source". * Both source and target parameters represent absolute paths. * * Results: * Allocated path that caller must free. * NULL if there is a low memory condition. * * Side effects: * None * *----------------------------------------------------------------------------- */ char* HgfsServerGetTargetRelativePath(const char* source, // IN: source file name const char* target) // IN: target file name { const char *relativeSource = source; const char *relativeTarget = target; const char* sourceSep; const char* targetSep; int level = 0; size_t targetSize; char *result; char *currentPosition; /* * First remove the part of the path which is common between source and * target */ while (*relativeSource != '\0' && *relativeTarget != '\0') { sourceSep = strchr(relativeSource, DIRSEPC); targetSep = strchr(relativeTarget, DIRSEPC); if (sourceSep == NULL || targetSep == NULL) { break; } if ((sourceSep - relativeSource) != (targetSep - relativeTarget)) { break; } if (strncmp(relativeSource, relativeTarget, (targetSep - relativeTarget)) != 0) { break; } relativeSource = sourceSep + 1; relativeTarget = targetSep + 1; }; /* * Find out how many directories deep the source file is from the common * part of the path. */ while(*relativeSource != '\0') { sourceSep = strchr(relativeSource, DIRSEPC); if (sourceSep != NULL) { /* Several consecutive separators mean only one level. */ while (*sourceSep == DIRSEPC) { sourceSep++; } if (*sourceSep != '\0') { level++; relativeSource = sourceSep; } else { break; } } else { break; } } /* * Consruct relative path by adding level number of "../" * to the relative target path. */ targetSize = level * HGFS_PARENT_DIR_LEN + strlen(relativeTarget) + sizeof '\0'; result = malloc(targetSize); currentPosition = result; if (result != NULL) { while (level != 0) { memcpy(currentPosition, HGFS_PARENT_DIR, HGFS_PARENT_DIR_LEN); level--; currentPosition += HGFS_PARENT_DIR_LEN; } memcpy(currentPosition, relativeTarget, strlen(relativeTarget) + sizeof '\0'); } return result; } /* *----------------------------------------------------------------------------- * * HgfsServerNotifyReceiveEventCb -- * * The callback is invoked by the file system change notification component * in response to a change event when the client has set at least one watch * on a directory. * * The function builds directory notification packet and queues it to be sent * to the client. It processes one notification at a time. Any consolidation of * packets is expected to occur at the transport layer. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerNotifyReceiveEventCb(HgfsSharedFolderHandle sharedFolder, // IN: shared folder HgfsSubscriberHandle subscriber, // IN: subsciber char* fileName, // IN: name of the file uint32 mask, // IN: event type struct HgfsSessionInfo *session) // IN: session info { HgfsPacket *packet = NULL; HgfsHeader *packetHeader = NULL; char *shareName = NULL; size_t shareNameLen; size_t sizeNeeded; uint32 notifyFlags; LOG(4, "%s: Entered shr hnd %u hnd %"FMT64"x file %s mask %u\n", __FUNCTION__, sharedFolder, subscriber, fileName, mask); if (session->state == HGFS_SESSION_STATE_CLOSED) { LOG(4, "%s: session has been closed drop the notification %"FMT64"x\n", __FUNCTION__, session->sessionId); goto exit; } if (!HgfsServerGetShareName(sharedFolder, &shareNameLen, &shareName)) { LOG(4, "%s: failed to find shared folder for a handle %x\n", __FUNCTION__, sharedFolder); goto exit; } sizeNeeded = HgfsPackCalculateNotificationSize(shareName, fileName); /* * Use a single buffer zero'd out, as the packet and metapacket have the same * lifespan which is ended at the send complete callback (HgfsServerSessionSendComplete). */ packet = Util_SafeCalloc(1, sizeof *packet + sizeNeeded); packetHeader = (HgfsHeader *)((char *)packet + sizeof *packet); /* * The buffer is zero'd out, so no need to set the following explicitly: * packet->metaPacketIsAllocated = FALSE; * packet->state &= ~HGFS_STATE_CLIENT_REQUEST; */ packet->metaPacketSize = sizeNeeded; packet->metaPacketDataSize = packet->metaPacketSize; packet->metaPacket = packetHeader; notifyFlags = 0; if (mask & HGFS_NOTIFY_EVENTS_DROPPED) { notifyFlags |= HGFS_NOTIFY_FLAG_OVERFLOW; } if (!HgfsPackChangeNotificationRequest(packetHeader, subscriber, shareName, fileName, mask, notifyFlags, session, &sizeNeeded)) { LOG(4, "%s: failed to pack notification request\n", __FUNCTION__); goto exit; } if (!HgfsPacketSend(packet, session->transportSession, session, 0)) { LOG(4, "%s: failed to send notification to the host\n", __FUNCTION__); goto exit; } /* The transport will call the server send complete callback to release the packets. */ packet = NULL; LOG(4, "%s: Sent notify for: %u index: %"FMT64"u file name %s mask %x\n", __FUNCTION__, sharedFolder, subscriber, fileName, mask); exit: if (shareName) { free(shareName); } if (packet) { free(packet); } } /* * more testing */ #if 0 void TestNodeFreeList(void) { HgfsHandle array[10 * NUM_FILE_NODES]; HgfsFileNode *node; unsigned int i; printf("%s: begin >>>>>>>>>>>>>>>>>>>>>>>>>>>\n", __FUNCTION__); for (i = 0; i < sizeof array / sizeof array[0]; i++) { char tempName[20]; HgfsLocalId localId; Str_Sprintf(tempName, sizeof tempName, "name%u", i); printf("\nadding node with name: %s\n", tempName); localId.volumeId = 0; localId.fileId = i + 1000; node = HgfsAddNewFileNode(Util_SafeStrdup(tempName), &localId); array[i] = HgfsFileNode2Handle(node); } HgfsDumpAllNodes(); printf("done getting nodes, now freeing\n"); for (i = 0; i < sizeof array / sizeof array[0]; i++) { printf("removing node #%u\n", i); HgfsRemoveFileNode(&nodeArray[array[i]]); } HgfsDumpAllNodes(); printf("%s: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n", __FUNCTION__); } void TestSearchFreeList(void) { HgfsHandle array[10 * NUM_SEARCHES]; HgfsSearch *search; unsigned int i; printf("%s: begin >>>>>>>>>>>>>>>>>>>>>>>>>>>\n", __FUNCTION__); for (i = 0; i < sizeof array / sizeof array[0]; i++) { char tempName[20]; Str_Sprintf(tempName, sizeof tempName, "baseDir%u", i); printf("\nadding search with baseDir: \"%s\"\n", tempName); search = HgfsAddNewSearch(Util_SafeStrdup(tempName)); array[i] = HgfsSearch2SearchHandle(search); } HgfsDumpAllSearches(); printf("done getting searches, now freeing\n"); for (i = 0; i < sizeof array / sizeof array[0]; i++) { printf("removing search #%u\n", i); HgfsRemoveSearch(&searchArray[array[i]]); } HgfsDumpAllSearches(); printf("%s: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n", __FUNCTION__); } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerInt.h000066400000000000000000001203161470176644300261520ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef __HGFS_SERVER_INT_H__ # define __HGFS_SERVER_INT_H__ #include "vm_basic_types.h" struct DirectoryEntry; #ifndef _WIN32 typedef int fileDesc; #else # include typedef HANDLE fileDesc; #endif #include "dbllnklst.h" #include "cpName.h" // for HgfsNameStatus #include "hgfsCache.h" #include "hgfsProto.h" #include "hgfsServer.h" // for the server public types #include "hgfsServerPolicy.h" #include "hgfsUtil.h" // for HgfsInternalStatus #include "userlock.h" #include "vm_atomic.h" #ifndef VMX86_TOOLS #define LOGLEVEL_MODULE hgfsServer #include "loglevel_user.h" #else // VMX86_TOOLS #undef DOLOG #undef LOG /* * Map all LOG statements to a Debug or g_debug tools log. * Set the level to a default log level of 10 so that we will * capture everything if tools logging is set to debug. * * Note, for future work would be to go through the log * statements and set the levels correctly so that we can * map to info, error and warnings. */ #define LGLEVEL (10) #define LGPFX_FMT "%s:%s:" #define LGPFX "hgfsServer" #if defined VMTOOLS_USE_GLIB #define Debug g_debug #define Warning g_warning #define G_LOG_DOMAIN LGPFX #include "vmware/tools/utils.h" #include "vmware/tools/log.h" #else // VMTOOLS_USE_GLIB #include "debug.h" #endif // VMTOOLS_USE_GLIB #define DOLOG(_min) ((_min) <= LGLEVEL) /* gcc needs special syntax to handle zero-length variadic arguments */ #if defined(_MSC_VER) #define LOG(_level, fmt, ...) \ do { \ if (DOLOG(_level)) { \ Debug(LGPFX_FMT fmt, LGPFX , __FUNCTION__, __VA_ARGS__); \ } \ } while (0) #else #define LOG(_level, fmt, ...) \ do { \ if (DOLOG(_level)) { \ Debug(LGPFX_FMT fmt, LGPFX, __FUNCTION__, ##__VA_ARGS__); \ } \ } while (0) #endif #endif // VNMX86_TOOLS #define HGFS_DEBUG_ASYNC (0) typedef uintptr_t HOM_HANDLE; typedef struct HgfsTransportSessionInfo HgfsTransportSessionInfo; /* Identifier for a local file */ typedef struct HgfsLocalId { uint64 volumeId; uint64 fileId; } HgfsLocalId; typedef enum { REQ_ASYNC, /* Hint that request should be processed Async. */ REQ_SYNC, /* " Sync. */ } RequestHint; /* Three possible filenode states */ typedef enum { FILENODE_STATE_UNUSED, /* Linked on the free list */ FILENODE_STATE_IN_USE_CACHED, /* Linked on the cached nodes list */ FILENODE_STATE_IN_USE_NOT_CACHED, /* Not linked on any list */ } FileNodeState; /* Three possible search types */ typedef enum { DIRECTORY_SEARCH_TYPE_DIR, /* Objects are files and subdirectories */ DIRECTORY_SEARCH_TYPE_BASE, /* Objects are shares */ DIRECTORY_SEARCH_TYPE_OTHER, /* Objects are the contents of "root/drive" or contents of "root" */ } DirectorySearchType; #define HGFS_SEARCH_LAST_ENTRY_INDEX ((uint32)~((uint32)0)) /* Two possible volume info type */ typedef enum { VOLUME_INFO_TYPE_MIN, VOLUME_INFO_TYPE_MAX, } VolumeInfoType; /* * The "default" share access is used in cross-platform code, so it's helpful * to have a single macro for accessing it. */ #ifdef _WIN32 # define HGFS_DEFAULT_SHARE_ACCESS (FILE_SHARE_READ | FILE_SHARE_WRITE | \ FILE_SHARE_DELETE) #else # define HGFS_DEFAULT_SHARE_ACCESS 0 #endif // _WIN32 typedef struct HgfsShareInfo { /* Filename of the root directory for the shared folder */ const char *rootDir; /* Length of the root directory filename (does not include nul terminator) */ size_t rootDirLen; /* Read permissions for the shared folder, needed for handle => name conversions. */ Bool readPermissions; /* Write permissions for the shared folder, needed for handle => name conversions. */ Bool writePermissions; /* * Shared folder handle used by change directory notification code to identify * shared folder. */ HgfsSharedFolderHandle handle; } HgfsShareInfo; /* * This struct represents a file on the local filesystem that has been * opened by a remote client. We store the name of the local file and * enough state to keep track of whether the file has changed locally * between remote accesses. None of the fields contain cross-platform * types; everything has been converted for the local filesystem. * * A file node object can only be in 1 of these 3 states: * 1) FILENODE_STATE_UNUSED: linked on the free list * 2) FILENODE_STATE_IN_USE_CACHED: Linked on the cached nodes list * 3) FILENODE_STATE_IN_USE_NOT_CACHED: Linked on neither of the above two lists. */ typedef struct HgfsFileNode { /* Links to place the object on various lists */ DblLnkLst_Links links; /* HGFS handle uniquely identifying this node. */ HgfsHandle handle; /* Local filename (in UTF8) */ char *utf8Name; /* Length of filename (does not include nul terminator) */ size_t utf8NameLen; /* share name */ char *shareName; /* Length of share name (does not include nul terminator) */ size_t shareNameLen; /* ID of file in local filesystem */ HgfsLocalId localId; /* File descriptor */ fileDesc fileDesc; /* On POSIX, access mode. On Windows, desired access */ uint32 mode; /* Share access to open with (Windows only) */ uint32 shareAccess; /* The server lock that the node currently has. */ HgfsLockType serverLock; /* File node state on lists */ FileNodeState state; /* File flags - see below. */ uint32 flags; /* * Context as required by some file operations. Eg: BackupWrite on * Windows: BackupWrite requires the caller to hold on to a pointer * to a Windows internal data structure between subsequent calls to * BackupWrite while restoring a file. */ void *fileCtx; /* Parameters associated with the share. */ HgfsShareInfo shareInfo; } HgfsFileNode; /* HgfsFileNode flags. */ /* TRUE if opened in append mode */ #define HGFS_FILE_NODE_APPEND_FL (1 << 0) /* Whether this file was opened in sequential mode. */ #define HGFS_FILE_NODE_SEQUENTIAL_FL (1 << 1) /* Whether this a shared folder open. */ #define HGFS_FILE_NODE_SHARED_FOLDER_OPEN_FL (1 << 2) /* * This struct represents a file search that a client initiated. * * A search object can only be in 1 of these 2 states: * 1) Unused: linked on the free list * 2) In use: unlinked */ typedef struct HgfsSearch { /* Links to place the object on various lists */ DblLnkLst_Links links; /* Flags to track state and information: see below. */ uint32 flags; /* HGFS handle uniquely identifying this search. */ HgfsHandle handle; /* Local directory name (in UTF8) */ char *utf8Dir; /* Length of directory name (does not include nul terminator) */ size_t utf8DirLen; /* Share name. */ char *utf8ShareName; /* Share name length. */ size_t utf8ShareNameLen; /* Directory entries for this search */ struct DirectoryEntry **dents; /* Number of dents */ uint32 numDents; /* * What type of search is this (what objects does it track)? This is * important to know so we can do the right kind of stat operation later * when we want to retrieve the attributes for each dent. */ DirectorySearchType type; /* Parameters associated with the share. */ HgfsShareInfo shareInfo; } HgfsSearch; /* HgfsSearch flags. */ /* TRUE if opened in append mode */ #define HGFS_SEARCH_FLAG_READ_ALL_ENTRIES (1 << 0) /* HgfsSessionInfo flags. */ typedef enum { HGFS_SESSION_TYPE_REGULAR, /* Dynamic session, created by the HgfsTransport. */ HGFS_SESSION_TYPE_INTERNAL, /* This is a static session. */ } HgfsSessionInfoType; /* HgfsSessionState, used for session status. */ typedef enum { HGFS_SESSION_STATE_OPEN, HGFS_SESSION_STATE_CLOSED, } HgfsSessionInfoState; typedef struct HgfsAsyncRequestInfo { /* Asynchronous request handling. */ Atomic_uint32 requestCount; MXUserExclLock *lock; MXUserCondVar *requestCountIsZero; } HgfsAsyncRequestInfo; typedef struct HgfsSessionInfo { DblLnkLst_Links links; Bool isInactive; /* The sessions state and capabilities. */ HgfsSessionFlags flags; /* Unique session id. */ uint64 sessionId; /* Max packet size that is supported by both client and server. */ uint32 maxPacketSize; /* Transport session context. */ HgfsTransportSessionInfo *transportSession; /* Current state of the session. */ HgfsSessionInfoState state; /* Lock to ensure some fileIO requests are atomic for a handle. */ MXUserExclLock *fileIOLock; int numInvalidationAttempts; Atomic_uint32 refCount; /* Reference count for session. */ /* ** START NODE ARRAY ************************************************** * * Lock for the following 6 fields: the node array, * counters and lists for this session. */ MXUserExclLock *nodeArrayLock; /* Open file nodes of this session. */ HgfsFileNode *nodeArray; /* Number of nodes in the nodeArray. */ uint32 numNodes; /* Free list of file nodes. LIFO to be cache-friendly. */ DblLnkLst_Links nodeFreeList; /* List of cached open nodes. */ DblLnkLst_Links nodeCachedList; /* Current number of open nodes. */ unsigned int numCachedOpenNodes; /* Number of open nodes having server locks. */ unsigned int numCachedLockedNodes; /** END NODE ARRAY ****************************************************/ /* ** START SEARCH ARRAY ************************************************ * * Lock for the following three fields: for the search array * and it's counter and list, for this session. */ MXUserExclLock *searchArrayLock; /* Directory entry cache for this session. */ HgfsSearch *searchArray; /* Number of entries in searchArray. */ uint32 numSearches; /* Free list of searches. LIFO. */ DblLnkLst_Links searchFreeList; /** END SEARCH ARRAY ****************************************************/ /* Array of session specific capabiities. */ HgfsOpCapability hgfsSessionCapabilities[HGFS_OP_MAX]; uint32 numberOfCapabilities; /* Asynchronous request handling. */ HgfsAsyncRequestInfo asyncRequestsInfo; /* Cache for symlink check status. */ HgfsCache *symlinkCache; /* Cache for file attributes. */ HgfsCache *fileAttrCache; } HgfsSessionInfo; /* * This represents the maximum number of HGFS sessions that can be * created in a HGFS transport session. We picked a random value * for this variable. There is no specific reason behind picking * this value. */ #define MAX_SESSION_COUNT 1024 /* * This represents the maximum number attempts made by the HGFS * invalidator before completely destroying the HGFS session. We * picked a random value and there is no specific reason behind * the value 4 for thie variable. */ #define MAX_SESSION_INVALIDATION_ATTEMPTS 4 /* * These structs represent information about file open requests, file * attributes, and directory creation requests. * * The main reason for these structs is data abstraction -- we pass * a struct around instead of the individual parameters. This way * as more parameters are implemented, we don't have to add more * parameters to the functions, instead just extend the structs. */ typedef struct HgfsFileOpenInfo { HgfsOp requestType; HgfsHandle file; /* Opaque file ID used by the server */ HgfsOpenValid mask; /* Bitmask that specified which fields are valid. */ HgfsOpenMode mode; /* Which type of access requested. See desiredAccess */ HgfsOpenFlags flags; /* Which flags to open the file with */ HgfsPermissions specialPerms; /* Desired 'special' permissions for file creation */ HgfsPermissions ownerPerms; /* Desired 'owner' permissions for file creation */ HgfsPermissions groupPerms; /* Desired 'group' permissions for file creation */ HgfsPermissions otherPerms; /* Desired 'other' permissions for file creation */ HgfsAttrFlags attr; /* Attributes, if any, for file creation */ uint64 allocationSize; /* How much space to pre-allocate during creation */ uint32 desiredAccess; /* Extended support for windows access modes */ uint32 shareAccess; /* Windows only, share access modes */ HgfsLockType desiredLock; /* The type of lock desired by the client */ HgfsLockType acquiredLock; /* The type of lock acquired by the server */ uint32 cpNameSize; const char *cpName; char *utf8Name; uint32 caseFlags; /* Case-sensitivity flags. */ HgfsShareInfo shareInfo; /* Parameters associated with the share. */ } HgfsFileOpenInfo; typedef struct HgfsFileAttrInfo { HgfsOp requestType; HgfsAttrValid mask; HgfsFileType type; /* File type */ uint64 size; /* File size (in bytes) */ uint64 creationTime; /* Creation time. Ignored by POSIX */ uint64 accessTime; /* Time of last access */ uint64 writeTime; /* Time of last write */ uint64 attrChangeTime; /* Time file attributes were last * changed. Ignored by Windows */ HgfsPermissions specialPerms; /* Special permissions bits. Ignored by Windows */ HgfsPermissions ownerPerms; /* Owner permissions bits */ HgfsPermissions groupPerms; /* Group permissions bits. Ignored by Windows */ HgfsPermissions otherPerms; /* Other permissions bits. Ignored by Windows */ HgfsAttrFlags flags; /* Various flags and Windows 'attributes' */ uint64 allocationSize; /* Actual size of file on disk */ uint32 userId; /* User identifier, ignored by Windows */ uint32 groupId; /* group identifier, ignored by Windows */ uint64 hostFileId; /* File Id of the file on host: inode_t on Linux */ uint32 volumeId; /* Volume Id of the volune on which the file resides */ uint32 effectivePerms; /* Permissions in effect for the current user */ uint32 eaSize; /* Extended attribute data size */ uint32 reparseTag; /* Windows reparse point tag, valid by attr flag */ HgfsShortFileName shortName; /* Windows DOS 8 dot 3 name for long names */ } HgfsFileAttrInfo; typedef struct HgfsSearchReadEntry { HgfsSearchReadMask mask; /* Info returned mask */ HgfsFileAttrInfo attr; /* Attributes of entry */ uint32 fileIndex; /* Entry directory index */ char *name; /* Name */ uint32 nameLength; /* Name byte length */ } HgfsSearchReadEntry; typedef struct HgfsSearchReadInfo { HgfsOp requestType; /* HGFS request version */ HgfsSearchReadMask requestedMask; /* Entry info requested mask */ HgfsSearchReadFlags flags; /* Request specific flags */ HgfsSearchReadFlags replyFlags; /* Reply specific flags */ char *searchPattern; /* Search pattern to match entries with */ uint32 searchPatternLength; /* Byte length of search pattern */ uint32 startIndex; /* Starting index for entries */ uint32 currentIndex; /* Current index for entries */ uint32 numberRecordsWritten; /* Number of entries written */ void *reply; /* Fixed part of search read reply */ void *replyPayload; /* Variable part (dirent records) of reply */ size_t payloadSize; /* Remaining bytes in reply payload. */ } HgfsSearchReadInfo; typedef struct HgfsCreateDirInfo { HgfsOp requestType; HgfsCreateDirValid mask; HgfsPermissions specialPerms; /* Special permissions bits. Ignored by Windows */ HgfsPermissions ownerPerms; /* Owner permissions bits */ HgfsPermissions groupPerms; /* Group permissions bits. Ignored by Windows */ HgfsPermissions otherPerms; /* Other permissions bits. Ignored by Windows */ uint32 cpNameSize; const char *cpName; uint32 caseFlags; /* Case-sensitivity flags. */ HgfsAttrFlags fileAttr; /* Various flags and Windows 'attributes' */ } HgfsCreateDirInfo; typedef struct HgfsCreateSessionInfo { uint32 maxPacketSize; HgfsSessionFlags flags; /* Session capability flags. */ } HgfsCreateSessionInfo; typedef struct HgfsSymlinkCacheEntry { HOM_HANDLE handle; /* File handle. */ HgfsNameStatus nameStatus; /* Symlink check status. */ } HgfsSymlinkCacheEntry; typedef struct HgfsFileAttrCacheEntry { HOM_HANDLE handle; /* File handle. */ HgfsFileAttrInfo attr; /* Attributes of entry. */ } HgfsFileAttrCacheEntry; Bool HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct HgfsLocalId const *localId, // IN: Local unique file ID fileDesc fileDesc, // IN: OS file handle Bool append, // IN: Open with append flag HgfsSessionInfo *session); // IN: Session info Bool HgfsSearchHandle2FileName(HgfsHandle handle, // IN: Hgfs search handle char **fileName, // OUT: cp file name uint32 *fileNameSize); // OUT: cp file name size void HgfsUpdateNodeNames(const char *oldLocalName, // IN: Name of file to look for const char *newLocalName, // IN: Name to replace with HgfsSessionInfo *session); // IN: Session info Bool HgfsRemoveSearch(HgfsHandle searchHandle, HgfsSessionInfo *session); #ifdef VMX86_LOG #define HGFS_SERVER_DIR_DUMP_DENTS(_searchHandle, _session) do { \ if (DOLOG(4)) { \ HgfsServerDirDumpDents(_searchHandle, _session); \ } \ } while (0) void HgfsServerDirDumpDents(HgfsHandle searchHandle, // IN: Handle to dump dents from HgfsSessionInfo *session); // IN: Session info #else #define HGFS_SERVER_DIR_DUMP_DENTS(_searchHandle, _session) do {} while (0) #endif struct DirectoryEntry * HgfsGetSearchResult(HgfsHandle handle, // IN: Handle to search HgfsSessionInfo *session, // IN: Session info uint32 offset, // IN: Offset to retrieve at Bool remove); // IN: If true, removes the result Bool HgfsServerStatFs(const char *pathName, // IN: Path we're interested in size_t pathLength, // IN: Length of path uint64 *freeBytes, // OUT: Free bytes on volume uint64 *totalBytes); // OUT: Total bytes on volume HgfsNameStatus HgfsServerGetAccess(char *in, // IN: CP filename to check size_t inSize, // IN: Size of name in HgfsOpenMode mode, // IN: Requested access mode uint32 caseFlags, // IN: Case-sensitivity flags char **bufOut, // OUT: File name in local fs size_t *outLen); // OUT: Length of name out Bool HgfsServerIsSharedFolderOnly(char const *in, // IN: CP filename to check size_t inSize); // IN: Size of name in void * HgfsServerResEnumInit(void); Bool HgfsServerResEnumGet(void *enumState, char const **enumResName, size_t *enumResNameLen, Bool *enumResDone); Bool HgfsServerResEnumExit(void *enumState); HgfsInternalStatus HgfsServerGetDirEntry(HgfsHandle handle, // IN: Handle to search HgfsSessionInfo *session, // IN: Session info uint32 index, // IN: index to retrieve at Bool remove, // IN: If true, removes the result struct DirectoryEntry **dirEntry);// OUT: directory entry HgfsInternalStatus HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search size_t baseDirLen, // IN: Length of directory char const *shareName, // IN: Share name char const *rootDir, // IN: Root directory for the share HgfsSessionInfo *session, // IN: Session info HgfsHandle *handle); // OUT: Search handle HgfsInternalStatus HgfsServerSearchVirtualDir(HgfsServerResEnumGetFunc getName, // IN: Name enumerator HgfsServerResEnumInitFunc initName, // IN: Init function HgfsServerResEnumExitFunc cleanupName, // IN: Cleanup function DirectorySearchType type, // IN: Kind of search HgfsSessionInfo *session, // IN: Session info HgfsHandle *handle); // OUT: Search handle HgfsInternalStatus HgfsServerRestartSearchVirtualDir(HgfsServerResEnumGetFunc getName, // IN: Name enumerator HgfsServerResEnumInitFunc initName, // IN: Init function HgfsServerResEnumExitFunc cleanupName, // IN: Cleanup function HgfsSessionInfo *session, // IN: Session info HgfsHandle searchHandle); // IN: search to restart void * HgfsAllocInitReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: incoming packet header size_t replyDataSize, // IN: payload size HgfsSessionInfo *session); // IN: Session Info /* Node cache functions. */ Bool HgfsRemoveFromCache(HgfsHandle handle, // IN: Hgfs handle of the node HgfsSessionInfo *session); // IN: Session info Bool HgfsAddToCache(HgfsHandle handle, // IN: Hgfs handle of the node HgfsSessionInfo *session); // IN: Session info Bool HgfsIsCached(HgfsHandle handle, // IN: Hgfs handle of the node HgfsSessionInfo *session); // IN: Session info Bool HgfsIsServerLockAllowed(HgfsSessionInfo *session); // IN: session info Bool HgfsHandle2FileDesc(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info fileDesc *fd, // OUT: OS handle (file descriptor) void **fileCtx); // OUT: OS file context Bool HgfsFileDesc2Handle(fileDesc fd, // IN: OS handle (file descriptor) HgfsSessionInfo *session, // IN: session info HgfsHandle *handle); // OUT: Hgfs file handle Bool HgfsHandle2ShareMode(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info HgfsOpenMode *shareMode); // OUT: UTF8 file name size Bool HgfsHandle2FileName(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info char **fileName, // OUT: CP file name size_t *fileNameSize); // OUT: CP file name size Bool HgfsHandle2FileNameMode(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session,// IN: Session info Bool *readPermissions, // OUT: shared folder permissions Bool *writePermissions, // OUT: shared folder permissions char **fileName, // OUT: UTF8 file name size_t *fileNameSize); // OUT: UTF8 file name size Bool HgfsHandle2AppendFlag(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info Bool *appendFlag); // OUT: Append flag Bool HgfsHandle2LocalId(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info HgfsLocalId *localId); // OUT: Local id info Bool HgfsUpdateNodeFileDesc(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info fileDesc fd, // IN: OS handle (file desc void *fileCtx); // IN: OS file context Bool HgfsUpdateNodeServerLock(fileDesc fd, // IN: OS handle HgfsSessionInfo *session, // IN: session info HgfsLockType serverLock); // IN: new oplock Bool HgfsUpdateNodeAppendFlag(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info Bool appendFlag); // OUT: Append flag Bool HgfsGetNodeCopy(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info Bool copyName, // IN: Should we copy the name? HgfsFileNode *copy); // IN/OUT: Copy of the node Bool HgfsHandleIsSequentialOpen(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info Bool *sequentialOpen); // OUT: If open was sequential Bool HgfsHandleIsSharedFolderOpen(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info Bool *sharedFolderOpen); // OUT: If shared folder Bool HgfsGetSearchCopy(HgfsHandle handle, // IN: Hgfs search handle HgfsSessionInfo *session, // IN: Session info HgfsSearch *copy); // IN/OUT: Copy of the search Bool HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN: Open info to examine uint32 *modeOut); // OUT: Local mode char* HgfsServerGetTargetRelativePath(const char* source, // IN: source file name const char* target); // IN: target file name Bool HgfsServerCheckOpenFlagsForShare(HgfsFileOpenInfo *openInfo, // IN: Hgfs file handle HgfsOpenFlags *flags); // IN/OUT: open mode /* Platform specific exports. */ Bool HgfsPlatformInit(void); void HgfsPlatformDestroy(void); HgfsInternalStatus HgfsPlatformCloseFile(fileDesc fileDesc, // IN: OS handle of the file void *fileCtx); // IN: file context Bool HgfsPlatformDoFilenameLookup(void); HgfsNameStatus HgfsPlatformFilenameLookup(const char *sharePath, // IN: share path in question size_t sharePathLength, // IN char *fileName, // IN: filename to be looked up size_t fileNameLength, // IN uint32 caseFlags, // IN: case-sensitivity flags char **convertedFileName, // OUT: case-converted filename size_t *convertedFileNameLength); // OUT HgfsInternalStatus HgfsPlatformConvertFromNameStatus(HgfsNameStatus status); // IN: name status HgfsNameStatus HgfsPlatformPathHasSymlink(const char *fileName, // IN: fileName to be checked size_t fileNameLength, // IN const char *sharePath, // IN: share path in question size_t sharePathLen); // IN HgfsInternalStatus HgfsPlatformSymlinkCreate(char *localSymlinkName, // IN: symbolic link file name char *localTargetName); // IN: symlink target name HgfsInternalStatus HgfsPlatformGetattrFromName(char *fileName, // IN: file name HgfsShareOptions configOptions, // IN: configuration options char *shareName, // IN: share name HgfsFileAttrInfo *attr, // OUT: file attributes char **targetName); // OUT: Symlink target HgfsInternalStatus HgfsPlatformGetDirEntry(HgfsSearch *search, // IN: search HgfsSessionInfo *session, // IN: Session info uint32 offset, // IN: Offset to retrieve at Bool remove, // IN: If true, removes the result struct DirectoryEntry **dirEntry); // OUT: dirent HgfsInternalStatus HgfsPlatformSetDirEntry(HgfsSearch *search, // IN: search HgfsShareOptions configOptions, // IN: share configuration settings HgfsSessionInfo *session, // IN: session info struct DirectoryEntry *dirEntry, // IN: the indexed dirent Bool getAttr, // IN: get the entry attributes HgfsFileAttrInfo *entryAttr, // OUT: entry attributes, optional char **entryName, // OUT: entry name uint32 *entryNameLength); // OUT: entry name length HgfsInternalStatus HgfsPlatformScandir(char const *baseDir, // IN: Directory to search in size_t baseDirLen, // IN: Length of directory Bool followSymlinks, // IN: followSymlinks config option struct DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys int *numDents); // OUT: Number of DirectoryEntrys HgfsInternalStatus HgfsPlatformScanvdir(HgfsServerResEnumGetFunc enumNamesGet, // IN: Function to get name HgfsServerResEnumInitFunc enumNamesInit, // IN: Setup function HgfsServerResEnumExitFunc enumNamesExit, // IN: Cleanup function DirectorySearchType type, // IN: Kind of search struct DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys uint32 *numDents); // OUT: total number of directory entrys HgfsInternalStatus HgfsPlatformSearchDir(HgfsNameStatus nameStatus, // IN: name status const char *dirName, // IN: relative directory name size_t dirNameLength, // IN: length of dirName uint32 caseFlags, // IN: case flags HgfsShareInfo *shareInfo, // IN: sharfed folder information char *baseDir, // IN: name of the shared directory uint32 baseDirLen, // IN: length of the baseDir HgfsSessionInfo *session, // IN: session info HgfsHandle *handle); // OUT: search handle HgfsInternalStatus HgfsPlatformRestartSearchDir(HgfsHandle handle, // IN: search handle HgfsSessionInfo *session, // IN: session info DirectorySearchType searchType); // IN: Kind of search #ifdef VMX86_LOG void HgfsPlatformDirDumpDents(HgfsSearch *search); // IN: search #endif HgfsInternalStatus HgfsPlatformReadFile(fileDesc readFile, // IN: file descriptor HgfsSessionInfo *session, // IN: session info uint64 offset, // IN: file offset to read from uint32 requiredSize, // IN: length of data to read void* payload, // OUT: buffer for the read data uint32 *actualSize); // OUT: actual length read HgfsInternalStatus HgfsPlatformWriteFile(fileDesc writeFile, // IN: file descriptor HgfsSessionInfo *session, // IN: session info uint64 writeOffset, // IN: file offset to write to uint32 writeDataSize, // IN: length of data to write HgfsWriteFlags writeFlags, // IN: write flags Bool writeSequential, // IN: write is sequential Bool writeAppend, // IN: write is appended const void *writeData, // IN: data to be written uint32 *writtenSize); // OUT: byte length written HgfsInternalStatus HgfsPlatformWriteWin32Stream(HgfsHandle file, // IN: packet header char *dataToWrite, // IN: data to write size_t requiredSize, // IN: data size Bool doSecurity, // IN: write ACL uint32 *actualSize, // OUT: written data size HgfsSessionInfo *session); // IN: session info HgfsInternalStatus HgfsPlatformVDirStatsFs(HgfsSessionInfo *session, // IN: session info HgfsNameStatus nameStatus, // IN: VolumeInfoType infoType, // IN: uint64 *outFreeBytes, // OUT: uint64 *outTotalBytes); // OUT: HgfsInternalStatus HgfsPlatformGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle HgfsSessionInfo *session, // IN: Session info Bool append, // IN: Open with append flag fileDesc *fd); // OUT: Opened file descriptor HgfsInternalStatus HgfsPlatformFileExists(char *utf8LocalName); // IN: Full file path utf8 encoding /* * NOTE. * This function requires valid localSrcName and localTargetName even when * srcFile and targetFile are specified. * Depending on some various conditions it may fall back on using file names * instead of file handles. */ HgfsInternalStatus HgfsPlatformRename(char *localSrcName, // IN: local path to source file fileDesc srcFile, // IN: source file handle char *localTargetName, // IN: local path to target file fileDesc targetFile, // IN: target file handle HgfsRenameHint hints); // IN: rename hints HgfsInternalStatus HgfsPlatformCreateDir(HgfsCreateDirInfo *info, // IN: direcotry properties char *utf8Name); // IN: full path for the new directory HgfsInternalStatus HgfsPlatformDeleteFileByHandle(HgfsHandle file, // IN: file being deleted HgfsSessionInfo *session); // IN: session info HgfsInternalStatus HgfsPlatformDeleteFileByName(char const *utf8Name); // IN: full file path in utf8 encoding HgfsInternalStatus HgfsPlatformDeleteDirByHandle(HgfsHandle dir, // IN: directory being deleted HgfsSessionInfo *session); // IN: session info HgfsInternalStatus HgfsPlatformDeleteDirByName(char const *utf8Name); // IN: full file path in utf8 encoding HgfsInternalStatus HgfsPlatformHandleIncompleteName(HgfsNameStatus nameStatus, // IN: name status HgfsFileAttrInfo *attr); // OUT: attributes void HgfsPlatformGetDefaultDirAttrs(HgfsFileAttrInfo *attr); // OUT: attributes HgfsInternalStatus HgfsPlatformGetattrFromFd(fileDesc fileDesc, // IN: file descriptor to query HgfsSessionInfo *session, // IN: session info HgfsFileAttrInfo *attr); // OUT: file attributes HgfsInternalStatus HgfsPlatformSetattrFromFd(HgfsHandle file, // IN: file descriptor HgfsSessionInfo *session, // IN: session info HgfsFileAttrInfo *attr, // IN: attrs to set HgfsAttrHint hints, // IN: attr hints Bool useHostTime); // IN: use current host time HgfsInternalStatus HgfsPlatformSetattrFromName(char *utf8Name, // IN: local file path HgfsFileAttrInfo *attr, // IN: attrs to set HgfsShareOptions configOptions, // IN: share options HgfsAttrHint hints, // IN: attr hints Bool useHostTime); // IN: use current host time HgfsInternalStatus HgfsPlatformValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct Bool followLinks, // IN: follow symlinks on the host HgfsSessionInfo *session, // IN: Session info HgfsLocalId *localId, // OUT: Local unique file ID fileDesc *newHandle); // OUT: Handle to the file void * HSPU_GetMetaPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet size_t *metaPacketSize, // OUT: Size of metaPacket HgfsServerChannelCallbacks *chanCb); // IN: Channel callbacks Bool HSPU_ValidateDataPacketSize(HgfsPacket *packet, // IN: Hgfs Packet size_t dataSize); // IN: data size void * HSPU_GetDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet MappingType mappingType, // IN: Readable/ Writeable ? HgfsServerChannelCallbacks *chanCb); // IN: Channel callbacks void HSPU_SetDataPacketSize(HgfsPacket *packet, // IN/OUT: Hgfs Packet size_t dataSize); // IN: data size void HSPU_PutDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsServerChannelCallbacks *chanCb); // IN: Channel callbacks void HSPU_PutMetaPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsServerChannelCallbacks *chanCb); // IN: Channel callbacks Bool HSPU_ValidateRequestPacketSize(HgfsPacket *packet, // IN: Hgfs Packet size_t requestHeaderSize, // IN: request header size size_t requestOpSize, // IN: request packet size size_t requestOpDataSize); // IN: request packet data size Bool HSPU_ValidateReplyPacketSize(HgfsPacket *packet, // IN: Hgfs Packet size_t replyHeaderSize, // IN: reply header size size_t replyResultSize, // IN: reply result size size_t replyResultDataSize, // IN: reply result data size Bool useMappedMetaPacket); // IN: using meta buffer void * HSPU_GetReplyPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsServerChannelCallbacks *chanCb, // IN: Channel callbacks size_t replyDataSize, // IN: Size of reply data size_t *replyPacketSize); // OUT: Size of reply Packet void HSPU_PutReplyPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsServerChannelCallbacks *chanCb); // IN: Channel callbacks #endif /* __HGFS_SERVER_INT_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c000066400000000000000000005067351470176644300265270ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerLinux.c -- * * This file contains the linux implementation of the server half * of the Host/Guest File System (hgfs), a.k.a. "Shared Folder". * * The hgfs server carries out filesystem requests that it receives * over the backdoor from a driver in the other world. */ #define _GNU_SOURCE // for O_NOFOLLOW #if defined(__APPLE__) #define _DARWIN_USE_64_BIT_INODE #endif #include #include #include #include #include #include #include // for utimes(2) #include #include #include #include #include // for getrlimit #if defined(__FreeBSD__) # include #else # include # include #endif #include "vmware.h" #include "hgfsServerPolicy.h" // for security policy #include "hgfsServerInt.h" #include "hgfsServerOplock.h" #include "hgfsEscape.h" #include "err.h" #include "str.h" #include "cpNameLite.h" #include "hgfsUtil.h" // for cross-platform time conversion #include "posix.h" #include "file.h" #include "util.h" #include "su.h" #include "codeset.h" #include "unicodeOperations.h" #include "userlock.h" #if defined(__linux__) && !defined(SYS_getdents64) /* For DT_UNKNOWN */ # include #endif #ifndef VMX86_TOOLS # include "config.h" #endif #if defined(__APPLE__) #include // for the alias manager #include // for CFString and CFURL #include // for getattrlist #include // for VERG / VDIR #endif #ifdef __linux__ typedef struct DirectoryEntry { uint64 d_ino; uint64 d_off; uint16 d_reclen; uint8 d_type; char d_name[256]; } DirectoryEntry; #else #include typedef struct DirectoryEntry { uint64 d_ino; uint16 d_reclen; uint16 d_namlen; uint8 d_type; char d_name[1024]; } DirectoryEntry; #endif /* * ALLPERMS (mode 07777) and ACCESSPERMS (mode 0777) are not defined in the * Solaris version of . */ #ifdef sun # define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) # define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) #endif /* * On Linux, we must wrap getdents64, as glibc does not wrap it for us. We use getdents64 * (rather than getdents) because with the latter, we'll get 64-bit offsets and inode * numbers. Note that getdents64 isn't supported everywhere, in particular, kernels older * than 2.4.1 do not implement it. On those older guests, we try using getdents(), and * translating the results to our DirectoryEntry structure... * * On FreeBSD and Mac platforms, getdents is implemented as getdirentries, and takes an * additional parameter which returns the position of the block read, which we don't care * about. */ #if defined(__linux__) static INLINE int getdents_linux(unsigned int fd, DirectoryEntry *dirp, unsigned int count) { # if defined(SYS_getdents64) return syscall(SYS_getdents64, fd, dirp, count); # else /* * Fall back to regular getdents on older Linux systems that don't have * getdents64. Because glibc does translation between the kernel's "struct dirent" and * the libc "struct dirent", this structure matches the one in linux/dirent.h, rather * than us using the libc 'struct dirent' directly */ struct linux_dirent { long d_ino; long d_off; /* __kernel_off_t expands to long on RHL 6.2 */ unsigned short d_reclen; char d_name[NAME_MAX]; } *dirp_temp; int retval; dirp_temp = alloca((sizeof *dirp_temp) * count); retval = syscall(SYS_getdents, fd, dirp_temp, count); if (retval > 0) { int i; /* * Translate from the Linux 'struct dirent' to the hgfs DirectoryEntry, since * they're not always the same layout. */ for (i = 0; i < count; i++) { dirp[i].d_ino = dirp_temp[i].d_ino; dirp[i].d_off = dirp_temp[i].d_off; dirp[i].d_reclen = dirp_temp[i].d_reclen; dirp[i].d_type = DT_UNKNOWN; memset(dirp[i].d_name, 0, sizeof dirp->d_name); memcpy(dirp[i].d_name, dirp_temp[i].d_name, ((sizeof dirp->d_name) < (sizeof dirp_temp->d_name)) ? (sizeof dirp->d_name) : (sizeof dirp_temp->d_name)); } } return retval; # endif } # define getdents getdents_linux #elif defined(__FreeBSD__) #if defined(__INO64) typedef off_t BASEPTYPE; #else typedef long BASEPTYPE; #endif #define getdents_freebsd(fd, dirp, count) \ ({ \ BASEPTYPE basep; \ getdirentries(fd, dirp, count, &basep); \ }) # define getdents getdents_freebsd #elif defined(__APPLE__) static INLINE int getdents_apple(DIR *fd, // IN DirectoryEntry *dirp, // OUT unsigned int count) // IN: ignored { int res = 0; struct dirent *dirEntry; dirEntry = readdir(fd); if (NULL != dirEntry) { /* * Assert that the hgfs DirectoryEntry version and system dirent * name fields are of the same size. Since that is where it was taken from. */ ASSERT_ON_COMPILE(sizeof dirp->d_name == sizeof dirEntry->d_name); dirp->d_ino = dirEntry->d_ino; dirp->d_type = dirEntry->d_type; dirp->d_namlen = dirEntry->d_namlen; memcpy(dirp->d_name, dirEntry->d_name, dirEntry->d_namlen + 1); dirp->d_reclen = offsetof(DirectoryEntry, d_name) + dirp->d_namlen + 1; res = dirp->d_reclen; } return res; } # define getdents getdents_apple #endif /* * O_DIRECTORY is only relevant on Linux. For other platforms, we'll hope that * the kernel is smart enough to deny getdents(2) (or getdirentries(2)) on * files which aren't directories. * * Likewise, O_NOFOLLOW doesn't exist on Solaris 9. Oh well. */ #ifndef O_DIRECTORY #define O_DIRECTORY 0 #endif #ifndef O_NOFOLLOW #define O_NOFOLLOW 0 #endif #if defined(sun) || defined(__linux__) /* * Implements futimes(), which was introduced in glibc 2.3.3. * For now the only caller to futimes() is HgfsServerSetattr which doesn't get * invoked at all in the HGFS server which runs in the Tools. */ #define PROC_SELF_FD "/proc/self/fd/" #define STRLEN_OF_MAXINT_AS_STRING 10 int futimes(int fd, const struct timeval times[2]) { #ifndef sun /* * Hack to allow the timevals in futimes() to be const even when utimes() * expects non-const timevals. This is the case on glibc up to 2.3 or * thereabouts. */ struct timeval mytimes[2]; /* Maximum size of "/proc/self/fd/" as a string. Accounts for nul. */ char nameBuffer[sizeof PROC_SELF_FD + STRLEN_OF_MAXINT_AS_STRING]; mytimes[0] = times[0]; mytimes[1] = times[1]; if (snprintf(nameBuffer, sizeof nameBuffer, PROC_SELF_FD "%d", fd) < 0) { return -1; } return Posix_Utimes(nameBuffer, mytimes); #else /* !sun */ return futimesat(fd, NULL, times); #endif /* !sun */ } #undef PROC_SELF_FD #undef STRLEN_OF_MAXINT_AS_STRING #endif #if defined(__APPLE__) struct FInfoAttrBuf { uint32 length; fsobj_type_t objType; char finderInfo[32]; }; #endif /* * Taken from WinNT.h. * For verifying the Windows client which can ask for delete access as well as the * standard read, write, execute permissions. * XXX - should probably be moved into a header file and may need to be expanded if * Posix looks at the access mode more thoroughly or we expand the set of cross-platform * access mode flags. */ #define DELETE (0x00010000L) /* * Server open flags, indexed by HgfsOpenFlags. Stolen from * lib/fileIOPosix.c * * Using O_NOFOLLOW will allow us to forgo a (racy) symlink check just * before opening the file. * * Using O_NONBLOCK will prevent us from blocking the HGFS server if * we open a FIFO. */ static const int HgfsServerOpenFlags[] = { O_NONBLOCK | O_NOFOLLOW, O_NONBLOCK | O_NOFOLLOW | O_TRUNC, O_NONBLOCK | O_NOFOLLOW | O_CREAT, O_NONBLOCK | O_NOFOLLOW | O_CREAT | O_EXCL, O_NONBLOCK | O_NOFOLLOW | O_CREAT | O_TRUNC, }; /* * Server open mode, indexed by HgfsOpenMode. */ static const int HgfsServerOpenMode[] = { O_RDONLY, O_WRONLY, O_RDWR, }; /* Local functions. */ static HgfsInternalStatus HgfsGetattrResolveAlias(char const *fileName, char **targetName); static void HgfsStatToFileAttr(struct stat *stats, uint64 *creationTime, HgfsFileAttrInfo *attr); static int HgfsStat(const char* fileName, Bool followLink, struct stat *stats, uint64 *creationTime); static int HgfsFStat(int fd, struct stat *stats, uint64 *creationTime); static void HgfsGetSequentialOnlyFlagFromName(const char *fileName, Bool followSymlinks, HgfsFileAttrInfo *attr); static void HgfsGetSequentialOnlyFlagFromFd(int fd, HgfsFileAttrInfo *attr); static int HgfsConvertComponentCase(char *currentComponent, const char *dirPath, const char **convertedComponent, size_t *convertedComponentSize); static int HgfsConstructConvertedPath(char **path, size_t *pathSize, char *convertedPath, size_t convertedPathSize); static int HgfsCaseInsensitiveLookup(const char *sharePath, size_t sharePathLength, char *fileName, size_t fileNameLength, char **convertedFileName, size_t *convertedFileNameLength); static Bool HgfsSetattrMode(struct stat *statBuf, HgfsFileAttrInfo *attr, mode_t *newPermissions); static Bool HgfsSetattrOwnership(HgfsFileAttrInfo *attr, uid_t *newUid, gid_t *newGid); static HgfsInternalStatus HgfsSetattrTimes(struct stat *statBuf, HgfsFileAttrInfo *attr, HgfsAttrHint hints, Bool useHostTime, struct timeval *accessTime, struct timeval *modTime, Bool *timesChanged); static HgfsInternalStatus HgfsGetHiddenXAttr(char const *fileName, Bool *attribute); static HgfsInternalStatus HgfsSetHiddenXAttr(char const *fileName, Bool value, mode_t permissions); static HgfsInternalStatus HgfsEffectivePermissions(char *fileName, Bool readOnlyShare, uint32 *permissions); static uint64 HgfsGetCreationTime(const struct stat *stats); #if !defined(sun) static HgfsInternalStatus HgfsWriteCheckIORange(off_t offset, uint32 bytesToWrite); #endif /* *----------------------------------------------------------------------------- * * HgfsPlatformConvertFromNameStatus -- * * This function converts between a status code used in processing a cross * platform filename, and a platform-specific status code. * * Because the two status codes never go down the wire, there is no danger * of backwards compatibility here, and we should ASSERT if we encounter * an status code that we're not familiar with. * * Results: * Converted status code. * * Side effects: * None. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformConvertFromNameStatus(HgfsNameStatus status) // IN { switch(status) { case HGFS_NAME_STATUS_COMPLETE: return 0; case HGFS_NAME_STATUS_FAILURE: case HGFS_NAME_STATUS_INCOMPLETE_BASE: case HGFS_NAME_STATUS_INCOMPLETE_ROOT: case HGFS_NAME_STATUS_INCOMPLETE_DRIVE: case HGFS_NAME_STATUS_INCOMPLETE_UNC: case HGFS_NAME_STATUS_INCOMPLETE_UNC_MACH: return EINVAL; case HGFS_NAME_STATUS_DOES_NOT_EXIST: return ENOENT; case HGFS_NAME_STATUS_ACCESS_DENIED: return EACCES; case HGFS_NAME_STATUS_SYMBOLIC_LINK: return ELOOP; case HGFS_NAME_STATUS_OUT_OF_MEMORY: return ENOMEM; case HGFS_NAME_STATUS_TOO_LONG: return ENAMETOOLONG; case HGFS_NAME_STATUS_NOT_A_DIRECTORY: return ENOTDIR; default: NOT_IMPLEMENTED(); } } /* *----------------------------------------------------------------------------- * * HgfsPlatformGetDefaultDirAttrs -- * * Get default directory attributes. Permissions are Read and * Execute permission only. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsPlatformGetDefaultDirAttrs(HgfsFileAttrInfo *attr) // OUT { struct timeval tv; uint64 hgfsTime; ASSERT(attr); attr->type = HGFS_FILE_TYPE_DIRECTORY; attr->size = 4192; /* * Linux and friends are OK with receiving timestamps of 0, but just * for consistency with the Windows server, we'll pass back the * host's time in a virtual directory's timestamps. */ if (gettimeofday(&tv, NULL) != 0) { hgfsTime = 0; } else { hgfsTime = HgfsConvertToNtTime(tv.tv_sec, tv.tv_usec * 1000); } attr->creationTime = hgfsTime; attr->accessTime = hgfsTime; attr->writeTime = hgfsTime; attr->attrChangeTime = hgfsTime; attr->specialPerms = 0; attr->ownerPerms = HGFS_PERM_READ | HGFS_PERM_EXEC; attr->groupPerms = HGFS_PERM_READ | HGFS_PERM_EXEC; attr->otherPerms = HGFS_PERM_READ | HGFS_PERM_EXEC; attr->mask = HGFS_ATTR_VALID_TYPE | HGFS_ATTR_VALID_SIZE | HGFS_ATTR_VALID_CREATE_TIME | HGFS_ATTR_VALID_ACCESS_TIME | HGFS_ATTR_VALID_WRITE_TIME | HGFS_ATTR_VALID_CHANGE_TIME | HGFS_ATTR_VALID_SPECIAL_PERMS | HGFS_ATTR_VALID_OWNER_PERMS | HGFS_ATTR_VALID_GROUP_PERMS | HGFS_ATTR_VALID_OTHER_PERMS; } /* *----------------------------------------------------------------------------- * * HgfsServerGetOpenFlags -- * * Retrieve system open flags from HgfsOpenFlags. * * Does the correct bounds checking on the HgfsOpenFlags before * indexing into the array of flags to use. See bug 54429. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsServerGetOpenFlags(HgfsOpenFlags flagsIn, // IN int *flagsOut) // OUT { unsigned int arraySize; ASSERT(flagsOut); arraySize = ARRAYSIZE(HgfsServerOpenFlags); if ((unsigned int)flagsIn >= arraySize) { Log("%s: Invalid HgfsOpenFlags %d\n", __FUNCTION__, flagsIn); return FALSE; } *flagsOut = HgfsServerOpenFlags[flagsIn]; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPlatformInit -- * * Set up any state needed to start Linux HGFS server. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsPlatformInit(void) { return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPlatformDestroy -- * * Tear down any state used for Linux HGFS server. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsPlatformDestroy(void) { } /* *----------------------------------------------------------------------------- * * HgfsServerGetOpenMode -- * * Retrieve system open mode from HgfsOpenMode. * * Does the correct bounds checking on the HgfsOpenMode before * indexing into the array of modes to use. See bug 54429. * * This is just the POSIX implementation; the Windows implementation is * more complicated, hence the need for the HgfsFileOpenInfo as an * argument. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN: Open info to examine uint32 *modeOut) // OUT: Local mode { ASSERT(modeOut); /* * If we didn't get the mode in the open request, we'll return a mode of 0. * This has the effect of failing the call to open(2) later, which is * exactly what we want. */ if ((openInfo->mask & HGFS_OPEN_VALID_MODE) == 0) { *modeOut = 0; return TRUE; } if (!HGFS_OPEN_MODE_IS_VALID_MODE(openInfo->mode)) { Log("%s: Invalid HgfsOpenMode %d\n", __FUNCTION__, openInfo->mode); return FALSE; } *modeOut = HgfsServerOpenMode[HGFS_OPEN_MODE_ACCMODE(openInfo->mode)]; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPlatformCloseFile -- * * Closes the file descriptor and release the file context. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformCloseFile(fileDesc fileDesc, // IN: File descriptor void *fileCtx) // IN: File context { if (close(fileDesc) != 0) { int error = errno; LOG(4, "%s: Could not close fd %d: %s\n", __FUNCTION__, fileDesc, Err_Errno2String(error)); return error; } return 0; } /* *----------------------------------------------------------------------------- * * HgfsCheckFileNode -- * * Check if a file node is still valid (i.e. if the file name stored in the * file node still refers to the same file) * * Results: * Zero if the file node is valid * Non-zero if the file node is stale * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsCheckFileNode(char const *localName, // IN HgfsLocalId const *localId) // IN { struct stat nodeStat; ASSERT(localName); ASSERT(localId); /* * A file is uniquely identified by a (device; inode) pair. Check that the * file name still refers to the same pair */ #if defined(__APPLE__) /* * Can't use Posix_Stat because of inconsistent definition * of _DARWIN_USE_64_BIT_INODE in this file and in other libraries. */ if (stat(localName, &nodeStat) < 0) { #else if (Posix_Stat(localName, &nodeStat) < 0) { #endif int error = errno; LOG(4, "%s: couldn't stat local file \"%s\": %s\n", __FUNCTION__, localName, Err_Errno2String(error)); return error; } if (nodeStat.st_dev != localId->volumeId || nodeStat.st_ino != localId->fileId) { LOG(4, "%s: local Id mismatch\n", __FUNCTION__); return ENOENT; } return 0; } /* *----------------------------------------------------------------------------- * * HgfsPlatformGetFd -- * * Returns the file descriptor associated with the node. If the node is * cached then it just returns the cached file descriptor (checking for * correct write flags). Otherwise, it opens a new file, caches the node * and returns the file desriptor. * * Results: * Zero on success. fd contains the opened file descriptor. * Non-zero on error. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle HgfsSessionInfo *session, // IN: Session info Bool append, // IN: Open with append flag fileDesc *fd) // OUT: Opened file descriptor { int newFd = -1, openFlags = 0; HgfsFileNode node; HgfsInternalStatus status = 0; ASSERT(fd); ASSERT(session); /* * Use node copy convenience function to get the node information. * Note that we shouldn't keep this node around for too long because * the information can become stale. However, it's ok to get all the * fields in one step, instead of getting them all separate. * * XXX: It would be better if we didn't do this node copy on the fast * path. Unfortuntely, even the fast path may need to look at the node's * append flag. */ node.utf8Name = NULL; if (!HgfsGetNodeCopy(hgfsHandle, session, TRUE, &node)) { /* XXX: Technically, this can also fail if we're out of memory. */ LOG(4, "%s: Invalid hgfs handle.\n", __FUNCTION__); status = EBADF; goto exit; } /* If the node is found in the cache */ if (HgfsIsCached(hgfsHandle, session)) { /* * If the append flag is set check to see if the file was opened * in append mode. If not, close the file and reopen it in append * mode. */ if (append && !(node.flags & HGFS_FILE_NODE_APPEND_FL)) { status = HgfsPlatformCloseFile(node.fileDesc, node.fileCtx); if (status != 0) { LOG(4, "%s: Couldn't close file \"%s\" for reopening\n", __FUNCTION__, node.utf8Name); goto exit; } /* * Update the node in the cache with the new value of the append * flag. */ if (!HgfsUpdateNodeAppendFlag(hgfsHandle, session, TRUE)) { LOG(4, "%s: Could not update the node in the cache\n", __FUNCTION__); status = EBADF; goto exit; } } else { newFd = node.fileDesc; goto exit; } } /* * If we got here then the file was either not in the cache or needs * reopening. This means we need to open a file. But first, verify * that the file we intend to open isn't stale. */ status = HgfsCheckFileNode(node.utf8Name, &node.localId); if (status != 0) { goto exit; } /* * We're not interested in creating a new file. So let's just get the * flags for a simple open request. This really should always work. */ HgfsServerGetOpenFlags(0, &openFlags); /* * We don't need to specify open permissions here because we're only * reopening an existing file, not creating a new one. * * XXX: We should use O_LARGEFILE, see lib/file/fileIOPosix.c --hpreg */ newFd = Posix_Open(node.utf8Name, node.mode | openFlags | (append ? O_APPEND : 0)); if (newFd < 0) { int error = errno; LOG(4, "%s: Couldn't open file \"%s\": %s\n", __FUNCTION__, node.utf8Name, Err_Errno2String(errno)); status = error; goto exit; } /* * Update the original node with the new value of the file desc. * This call might fail if the node is not used anymore. */ if (!HgfsUpdateNodeFileDesc(hgfsHandle, session, newFd, NULL)) { LOG(4, "%s: Could not update the node -- node is not used.\n", __FUNCTION__); status = EBADF; goto exit; } /* Add the node to the cache. */ if (!HgfsAddToCache(hgfsHandle, session)) { LOG(4, "%s: Could not add node to the cache\n", __FUNCTION__); status = EBADF; goto exit; } exit: if (status == 0) { *fd = newFd; } free(node.utf8Name); return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformValidateOpen -- * * Verify that the file with the given local name exists in the * local filesystem by trying to open the file with the requested * mode and permissions. If the open succeeds we stat the file * and fill in the volumeId and fileId with the file's local * filesystem device and inode number, respectively. * * Results: * Zero on success * Non-zero on failure. * * Side effects: * File with name "localName" may be created or truncated. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct Bool followSymlinks, // IN: followSymlinks config option HgfsSessionInfo *session, // IN: session info HgfsLocalId *localId, // OUT: Local unique file ID fileDesc *fileDesc) // OUT: Handle to the file { struct stat fileStat; int fd; int openMode = 0, openFlags = 0; mode_t openPerms; HgfsLockType serverLock; HgfsInternalStatus status = 0; Bool needToSetAttribute = FALSE; ASSERT(openInfo); ASSERT(localId); ASSERT(fileDesc); ASSERT(session); /* * Get correct system flags and mode from the HgfsOpenFlags and * HgfsOpenMode. This is related to bug 54429. */ if (!HgfsServerGetOpenFlags(openInfo->mask & HGFS_OPEN_VALID_FLAGS ? openInfo->flags : 0, &openFlags) || !HgfsServerGetOpenMode(openInfo, &openMode)) { status = EPROTO; goto exit; } /* * Create mode_t for use in open(). If owner permissions are missing, use * read/write for the owner permissions. If group or other permissions * are missing, use the owner permissions. * * This sort of makes sense. If the Windows driver wants to make a file * read-only, it probably intended for the file to be 555. Since creating * a file requires a valid mode, it's highly unlikely that we'll ever * be creating a file without owner permissions. */ openPerms = 0; openPerms |= openInfo->mask & HGFS_OPEN_VALID_SPECIAL_PERMS ? openInfo->specialPerms << 9 : 0; openPerms |= openInfo->mask & HGFS_OPEN_VALID_OWNER_PERMS ? openInfo->ownerPerms << 6 : S_IWUSR | S_IRUSR; openPerms |= openInfo->mask & HGFS_OPEN_VALID_GROUP_PERMS ? openInfo->groupPerms << 3 : (openPerms & S_IRWXU) >> 3; openPerms |= openInfo->mask & HGFS_OPEN_VALID_OTHER_PERMS ? openInfo->otherPerms : (openPerms & S_IRWXU) >> 6; /* * By default we don't follow symlinks, O_NOFOLLOW is always set. * Unset it if followSymlinks config option is specified. */ if (followSymlinks) { openFlags &= ~O_NOFOLLOW; } /* * Need to validate that open does not change the file for read * only shared folders. */ status = 0; if (!openInfo->shareInfo.writePermissions) { Bool deleteAccess = FALSE; /* * If a valid desiredAccess field specified by the Windows client, we use that * as the desiredAccess field has more data such as delete than is contained * in the mode. */ if ((0 != (openInfo->mask & HGFS_OPEN_VALID_DESIRED_ACCESS)) && (0 != (openInfo->desiredAccess & DELETE))) { deleteAccess = TRUE; } if ((openFlags & (O_APPEND | O_CREAT | O_TRUNC)) || (openMode & (O_WRONLY | O_RDWR)) || deleteAccess) { status = Posix_Access(openInfo->utf8Name, F_OK); if (status < 0) { status = errno; if (status == ENOENT && (openFlags & O_CREAT) != 0) { status = EACCES; } } else { /* * Handle the case when the file already exists: * If there is an attempt to createa new file, fail with "EEXIST" * error, otherwise set error to "EACCES". */ if ((openFlags & O_CREAT) && (openFlags & O_EXCL)) { status = EEXIST; } else { status = EACCES; } } } if (status != 0) { LOG(4, "%s: Error: Unwritable share mode %u flags %u file \"%s\": %d %s\n", __FUNCTION__, openMode, openFlags, openInfo->utf8Name, status, Err_Errno2String(status)); goto exit; } } if (!openInfo->shareInfo.readPermissions) { /* * "Drop Box" / "FTP incoming" type of shared folders. * Only allow creating a new file. * Any access to an existing file requires read so fail EACCES. */ int accessStatus = Posix_Access(openInfo->utf8Name, F_OK); if (accessStatus < 0) { accessStatus = errno; /* Not creating a new file, then fail. */ if (!(accessStatus == ENOENT && (openFlags & O_CREAT))) { status = EACCES; } } else { /*An existing file, then fail */ status = EACCES; } if (status == EACCES) { LOG(4, "%s: Error: Unreadable share flags %u file \"%s\": %d %s\n", __FUNCTION__, openFlags, openInfo->utf8Name, status, Err_Errno2String(status)); goto exit; } } /* * Determine if hidden attribute needs to be updated. * It needs to be updated if a new file is created or an existing file is truncated. * Since Posix_Open does not tell us if a new file has been created when O_CREAT is * specified we need to find out if the file exists before an open that may create * it. */ if (openInfo->mask & HGFS_OPEN_VALID_FILE_ATTR) { if ((openFlags & O_TRUNC) || ((openFlags & O_CREAT) && (openFlags & O_EXCL))) { needToSetAttribute = TRUE; } else if (openFlags & O_CREAT) { int err = Posix_Access(openInfo->utf8Name, F_OK); needToSetAttribute = (err != 0) && (errno == ENOENT); } } /* * Try to open the file with the requested mode, flags and permissions. */ fd = Posix_Open(openInfo->utf8Name, openMode | openFlags, openPerms); if (fd < 0) { status = errno; if (status == EAGAIN) { /* * We have tried opening with O_NONBLOCK but looks like an incompatible * lease may be held on the file. Tell the client that this access mode * is not allowed currently. */ status = EACCES; } LOG(4, "%s: Error: open file \"%s\": %d %s\n", __FUNCTION__, openInfo->utf8Name, status, Err_Errno2String(status)); goto exit; } /* Stat file to get its volume and file info */ if (fstat(fd, &fileStat) < 0) { status = errno; LOG(4, "%s: Error: stat file\"%s\": %d %s\n", __FUNCTION__, openInfo->utf8Name, status, Err_Errno2String(status)); close(fd); goto exit; } /* Set the rest of the Windows specific attributes if necessary. */ if (needToSetAttribute) { HgfsSetHiddenXAttr(openInfo->utf8Name, (openInfo->attr & HGFS_ATTR_HIDDEN) != 0, fileStat.st_mode); } /* Try to acquire an oplock. */ if (openInfo->mask & HGFS_OPEN_VALID_SERVER_LOCK) { serverLock = openInfo->desiredLock; if (!HgfsAcquireServerLock(fd, session, &serverLock)) { openInfo->acquiredLock = HGFS_LOCK_NONE; } else { openInfo->acquiredLock = serverLock; } } else { openInfo->acquiredLock = HGFS_LOCK_NONE; } *fileDesc = fd; /* Set volume and file ids from stat results */ localId->volumeId = fileStat.st_dev; localId->fileId = fileStat.st_ino; exit: return status; } /* *----------------------------------------------------------------------------- * * HgfsGetattrResolveAlias -- * * Mac OS defines a special file type known as an alias which behaves like a * symlink when viewed through the Finder, but is actually a regular file * otherwise. * * If the given filename is (or contains) an alias, this function will * resolve it completely and set targetName to something non-NULL. * * Results: * Zero on success. targetName is allocated if the file was an alias, and * NULL otherwise. * Non-zero on failure. targetName is unmodified. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsGetattrResolveAlias(char const *fileName, // IN: Input filename char **targetName) // OUT: Target filename { #ifndef __APPLE__ *targetName = NULL; return 0; #else // __APPLE__ HgfsInternalStatus status = HGFS_INTERNAL_STATUS_ERROR; Boolean success; CFURLRef resolvedURL = NULL; CFStringRef resolvedString = NULL; CFIndex maxPath; *targetName = NULL; if (CFURLCreateBookmarkDataFromFile != NULL) { /* We are running on Mac OS 10.6 or later. */ CFURLRef fileURL; CFBooleanRef isAlias = NULL; CFDataRef bookmarkData = NULL; CFURLBookmarkResolutionOptions resolutionOptions; Boolean isStale; fileURL = CFURLCreateFromFileSystemRepresentation(NULL, fileName, strlen(fileName), FALSE); if (!fileURL) { Log("%s: could not create CFURL for file.\n", __FUNCTION__); goto newExit; } success = CFURLCopyResourcePropertyForKey(fileURL, kCFURLIsAliasFileKey, &isAlias, NULL); if (!success) { Log("%s: could not copy IsAlias property key for file.\n", __FUNCTION__); goto newExit; } if (!CFBooleanGetValue(isAlias)) { status = 0; LOG(4, "%s: file was not an alias\n", __FUNCTION__); goto newExit; } LOG(4, "%s: file was an alias\n", __FUNCTION__); bookmarkData = CFURLCreateBookmarkDataFromFile(NULL, fileURL, NULL); if (!bookmarkData) { Log("%s: could not retrieve bookmark data for file.\n", __FUNCTION__); goto newExit; } /* * Don't show any UI during alias resolution and don't mount volumes * containing the alias target. This avoids blocking the current process * and/or Finder while trying to mount unreachable hosts (bug 1396411). */ resolutionOptions = kCFBookmarkResolutionWithoutUIMask | kCFBookmarkResolutionWithoutMountingMask; resolvedURL = CFURLCreateByResolvingBookmarkData(NULL, bookmarkData, resolutionOptions, NULL, NULL, &isStale, NULL); if (!resolvedURL) { Log("%s: could not resolve bookmark data for file.\n", __FUNCTION__); goto newExit; } newExit: if (fileURL) { CFRelease(fileURL); } if (isAlias) { CFRelease(isAlias); } if (bookmarkData) { CFRelease(bookmarkData); } } else { /* We are running on Mac OS 10.5 or earlier. */ #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* * Mac OS 10.5 used a type of alias which appears on disk as a 0-byte * file but stores its linking data in a resource fork. The APIs for * interacting with this type of alias are deprecated when targetting * 10.8+. */ FSRef fileRef; Boolean isAlias; Boolean targetIsFolder; OSStatus osStatus; ASSERT_ON_COMPILE(sizeof osStatus == sizeof (int32)); osStatus = FSPathMakeRef(fileName, &fileRef, NULL); if (osStatus != noErr) { Log("%s: could not create file reference: error %d\n", __FUNCTION__, (int32)osStatus); goto oldExit; } osStatus = FSIsAliasFile(&fileRef, &isAlias, &targetIsFolder); if (osStatus != noErr) { Log("%s: could not detect if file is an old style alias: error %d\n", __FUNCTION__, (int32)osStatus); goto oldExit; } if (!isAlias) { status = 0; LOG(4, "%s: file was not an alias\n", __FUNCTION__); goto oldExit; } LOG(4, "%s: file was an alias\n", __FUNCTION__); /* * Create and resolve an FSRef of the desired path. We pass FALSE to * resolveAliasChains because aliases to aliases should behave as * symlinks to symlinks. * * If alias points to an unmounted volume, the volume needs to be * explicitly mounted. Mount flag kResolveAliasFileNoUI prevents the user * from being prompted about mounting. * * Caution: Mac OS 10.10.2 will attempt to mount volumes silently, * unlike the earlier behavior of only resolving within existing mounts. * The new CFURLCreateByResolvingBookmarkData API must be used to avoid * mounting the alias target. * * XXX: This function returns fnfErr (file not found) if it encounters a * broken alias. Perhaps we should make that look like a dangling symlink * instead of returning an error? */ osStatus = FSResolveAliasFileWithMountFlags(&fileRef, FALSE, &targetIsFolder, &isAlias, kResolveAliasFileNoUI); if (osStatus != noErr) { Log("%s: could not resolve reference: error %d\n", __FUNCTION__, (int32)osStatus); goto oldExit; } resolvedURL = CFURLCreateFromFSRef(NULL, &fileRef); if (!resolvedURL) { Log("%s: could not create resolved URL reference from " "resolved filesystem reference\n", __FUNCTION__); goto oldExit; } oldExit: (void)0; // Need a statement for the label. #else // __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 // We are running on 10.5 but the build was targetting 10.6+. Eject! NOT_IMPLEMENTED(); #endif // __MAC_OS_X_VERSION_MIN_REQUIRED } if (resolvedURL) { /* * This is somewhat convoluted. We want to call * CFURLGetFileSystemRepresentation() to get a UTF-8 string representing * the target of the alias. But to call * CFStringGetMaximumSizeOfFileSystemRepresentation(), we need a CFString, * so we make one from the CFURL. Once we've got the max number of bytes * for a filename on the filesystem, we allocate some memory and convert * the CFURL to a basic UTF-8 string using a call to * CFURLGetFileSystemRepresentation(). */ resolvedString = CFURLGetString(resolvedURL); if (!resolvedString) { Log("%s: could not create resolved string reference from " "resolved URL reference\n", __FUNCTION__); goto exit; } maxPath = CFStringGetMaximumSizeOfFileSystemRepresentation(resolvedString); *targetName = malloc(maxPath); if (*targetName == NULL) { Log("%s: could not allocate %"FMTSZ"d bytes of memory for " "target name storage\n", __FUNCTION__, maxPath); goto exit; } success = CFURLGetFileSystemRepresentation(resolvedURL, FALSE, *targetName, maxPath); if (!success) { Log("%s: could not convert and copy resolved URL reference " "into allocated buffer\n", __FUNCTION__); goto exit; } status = 0; } exit: if (resolvedURL) { CFRelease(resolvedURL); } if (status != 0) { free(*targetName); *targetName = NULL; } return status; #endif // __APPLE__ } /* *----------------------------------------------------------------------------- * * HgfsGetHiddenAttr -- * * For Mac hosts and Linux hosts, if a guest is Windows we force the "dot", * files to be treated as hidden too in the Windows client by always setting * the hidden attribute flag. * Currently, this flag cannot be removed by Windows clients. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsGetHiddenAttr(char const *fileName, // IN: Input filename HgfsFileAttrInfo *attr) // OUT: Struct to copy into { char *baseName; ASSERT(fileName); ASSERT(attr); baseName = strrchr(fileName, DIRSEPC); if ((baseName != NULL) && (baseName[1] == '.') && (strcmp(&baseName[1], ".") != 0) && (strcmp(&baseName[1], "..") != 0)) { attr->mask |= HGFS_ATTR_VALID_FLAGS; attr->flags |= HGFS_ATTR_HIDDEN; /* * The request sets the forced flag so the client knows it is simulated * and is not a real attribute, which can only happen on a Windows server. * This allows the client to enforce some checks correctly if the flag * is real or not. * This replicates SMB behavior see bug 292189. */ attr->flags |= HGFS_ATTR_HIDDEN_FORCED; } else { Bool isHidden = FALSE; /* * Do not propagate any error returned from HgfsGetHiddenXAttr. * Consider that the file is not hidden if can't get hidden attribute for * whatever reason; most likely it fails because hidden attribute is not supported * by the OS or file system. */ HgfsGetHiddenXAttr(fileName, &isHidden); if (isHidden) { attr->mask |= HGFS_ATTR_VALID_FLAGS; attr->flags |= HGFS_ATTR_HIDDEN; } } } /* *----------------------------------------------------------------------------- * * HgfsConvertComponentCase -- * * Do a case insensitive search of a directory for the specified entry. If * a matching entry is found, return it in the convertedComponent argument. * * Results: * On Success: * Returns 0 and the converted component name in the argument convertedComponent. * The length for the convertedComponent is returned in convertedComponentSize. * * On Failure: * Non-zero errno return, with convertedComponent and convertedComponentSize * set to NULL and 0 respectively. * * Side effects: * On success, allocated memory is returned in convertedComponent and needs * to be freed. * *----------------------------------------------------------------------------- */ static int HgfsConvertComponentCase(char *currentComponent, // IN const char *dirPath, // IN const char **convertedComponent, // OUT size_t *convertedComponentSize) // OUT { struct dirent *dirent; DIR *dir = NULL; char *dentryName; size_t dentryNameLen; char *myConvertedComponent = NULL; size_t myConvertedComponentSize; int ret; ASSERT(currentComponent); ASSERT(dirPath); ASSERT(convertedComponent); ASSERT(convertedComponentSize); /* Open the specified directory. */ dir = Posix_OpenDir(dirPath); if (!dir) { ret = errno; goto exit; } /* * Unicode_CompareIgnoreCase crashes with invalid unicode strings, * validate it before passing it to Unicode_* functions. */ if (!Unicode_IsBufferValid(currentComponent, -1, STRING_ENCODING_UTF8)) { /* Invalid unicode string, return failure. */ ret = EINVAL; goto exit; } /* * Read all of the directory entries. For each one, convert the name * to lower case and then compare it to the lower case component. */ while ((dirent = readdir(dir))) { char *dentryNameU; int cmpResult; dentryName = dirent->d_name; dentryNameLen = strlen(dentryName); /* * Unicode_CompareIgnoreCase crashes with invalid unicode strings, * validate and convert it appropriately before passing it to Unicode_* * functions. */ if (!Unicode_IsBufferValid(dentryName, dentryNameLen, STRING_ENCODING_DEFAULT)) { /* Invalid unicode string, skip the entry. */ continue; } dentryNameU = Unicode_Alloc(dentryName, STRING_ENCODING_DEFAULT); cmpResult = Unicode_CompareIgnoreCase(currentComponent, dentryNameU); free(dentryNameU); if (cmpResult == 0) { /* * The current directory entry is a case insensitive match to * the specified component. Malloc and copy the current directory entry. */ myConvertedComponentSize = dentryNameLen + 1; myConvertedComponent = malloc(myConvertedComponentSize); if (myConvertedComponent == NULL) { ret = errno; LOG(4, "%s: failed to malloc myConvertedComponent.\n", __FUNCTION__); goto exit; } Str_Strcpy(myConvertedComponent, dentryName, myConvertedComponentSize); /* Success. Cleanup and exit. */ ret = 0; *convertedComponentSize = myConvertedComponentSize; *convertedComponent = myConvertedComponent; goto exit; } } /* We didn't find a match. Failure. */ ret = ENOENT; exit: if (dir) { closedir(dir); } if (ret) { *convertedComponent = NULL; *convertedComponentSize = 0; } return ret; } /* *----------------------------------------------------------------------------- * * HgfsConstructConvertedPath -- * * Expand the passed string and append the converted path. * * Results: * Returns 0 if successful, errno on failure. Note that this * function cannot return ENOENT. * * Side effects: * Reallocs the path. * *----------------------------------------------------------------------------- */ static int HgfsConstructConvertedPath(char **path, // IN/OUT size_t *pathSize, // IN/OUT char *convertedPath, // IN size_t convertedPathSize) // IN { char *p; size_t convertedPathLen = convertedPathSize - 1; ASSERT(path); ASSERT(*path); ASSERT(convertedPath); ASSERT(pathSize); p = realloc(*path, *pathSize + convertedPathLen + sizeof (DIRSEPC)); if (!p) { int error = errno; LOG(4, "%s: failed to realloc.\n", __FUNCTION__); return error; } *path = p; *pathSize += convertedPathLen + sizeof (DIRSEPC); /* Copy out the converted component to curDir, and free it. */ Str_Strncat(p, *pathSize, DIRSEPS, sizeof (DIRSEPS)); Str_Strncat(p, *pathSize, convertedPath, convertedPathLen); return 0; } /* *----------------------------------------------------------------------------- * * HgfsCaseInsensitiveLookup -- * * Do a case insensitive lookup for fileName. Each component past sharePath is * looked-up case-insensitively. Expensive! * * NOTE: * shareName is always expected to be a prefix of fileName. * * Results: * Returns 0 if successful and resolved path for fileName is returned in * convertedFileName and its length (without nul) in convertedFileNameLength. * Otherwise returns non-zero errno with convertedFileName and * convertedFileNameLength set to NULL and 0 respectively. * * Side effects: * On success, allocated memory is returned in convertedFileName and needs * to be freed. * *----------------------------------------------------------------------------- */ static int HgfsCaseInsensitiveLookup(const char *sharePath, // IN size_t sharePathLength, // IN char *fileName, // IN size_t fileNameLength, // IN char **convertedFileName, // OUT size_t *convertedFileNameLength) // OUT { char *currentComponent; char *nextComponent; char *curDir; size_t curDirSize; char *convertedComponent = NULL; size_t convertedComponentSize = 0; int error = 0; ASSERT(sharePath); ASSERT(fileName); ASSERT(convertedFileName); ASSERT(fileNameLength >= sharePathLength); curDirSize = sharePathLength + 1; curDir = malloc(curDirSize); if (!curDir) { error = errno; LOG(4, "%s: failed to allocate for curDir\n", __FUNCTION__); goto exit; } Str_Strcpy(curDir, sharePath, curDirSize); currentComponent = fileName + sharePathLength; /* Check there is something beyond the share name. */ if (*currentComponent == '\0') { /* * The fileName is the same as sharePath. Nothing else to do. * Return the duplicated sharePath string and return. */ goto exit; } /* Skip a component separator if not in the share path. */ if (*currentComponent == DIRSEPC) { currentComponent += 1; } while (TRUE) { /* Get the next component. */ nextComponent = strchr(currentComponent, DIRSEPC); if (nextComponent != NULL) { *nextComponent = '\0'; } /* * Try to match the current component against the one in curDir. * HgfsConvertComponentCase may return ENOENT. In that case return * the path case-converted uptil now (curDir) and append to it the * rest of the unconverted path. */ error = HgfsConvertComponentCase(currentComponent, curDir, (const char **)&convertedComponent, &convertedComponentSize); /* Restore the path separator if we removed it earlier. */ if (nextComponent != NULL) { *nextComponent = DIRSEPC; } if (error) { if (error == ENOENT) { /* * We could not find the current component so no need to convert it. * So it most likely a new path is to be created or an ENOENT genuine error. * Copy out the components starting from currentComponent. We do this * after replacing DIRSEPC, so all the components following * currentComponent gets copied. */ error = HgfsConstructConvertedPath(&curDir, &curDirSize, currentComponent, strlen(currentComponent) + 1); } break; } /* Expand curDir and copy out the converted component. */ error = HgfsConstructConvertedPath(&curDir, &curDirSize, convertedComponent, convertedComponentSize); if (error) { break; } /* Free the converted component. */ free(convertedComponent); convertedComponent = NULL; /* If there is no component after the current one then we are done. */ if (nextComponent == NULL) { /* Set success. */ error = 0; break; } /* * Set the current component pointer to point at the start of the next * component. */ currentComponent = nextComponent + 1; } exit: /* * If the conversion was successful, return the result. * The length does NOT include the nul terminator. */ if (error == 0) { *convertedFileName = curDir; *convertedFileNameLength = curDirSize - 1; } else { *convertedFileName = NULL; *convertedFileNameLength = 0; free(curDir); } free(convertedComponent); return error; } /* *----------------------------------------------------------------------------- * * HgfsPlatformFilenameLookup -- * * Perform a fileName lookup of the fileName if requested. * * The type of lookup depends on the flags passed. Currently, * case insensitive is checked and if set we lookup the file name. * Otherwise this function assumes the file system is the default * of case sensitive and returns a copy of the passed name. * * Results: * Returns HGFS_NAME_STATUS_COMPLETE if successful and converted * path for fileName is returned in convertedFileName and it length in * convertedFileNameLength. * * Otherwise returns non-zero integer without affecting fileName with * convertedFileName and convertedFileNameLength set to NULL and 0 * respectively. * * Side effects: * On success, allocated memory is returned in convertedFileName and needs * to be freed. * *----------------------------------------------------------------------------- */ HgfsNameStatus HgfsPlatformFilenameLookup(const char *sharePath, // IN size_t sharePathLength, // IN char *fileName, // IN size_t fileNameLength, // IN uint32 caseFlags, // IN char **convertedFileName, // OUT size_t *convertedFileNameLength) // OUT { int error = 0; HgfsNameStatus nameStatus = HGFS_NAME_STATUS_COMPLETE; ASSERT(sharePath); ASSERT(fileName); ASSERT(convertedFileName); ASSERT(convertedFileNameLength); *convertedFileName = NULL; *convertedFileNameLength = 0; /* * Case-insensitive lookup is expensive, do it only if the flag is set * and file is inaccessible using the case passed to us. We use access(2) * call to check if the passed case of the file name is correct. */ if (caseFlags == HGFS_FILE_NAME_CASE_INSENSITIVE && Posix_Access(fileName, F_OK) == -1) { LOG(4, "%s: Case insensitive lookup, fileName: %s, flags: %u.\n", __FUNCTION__, fileName, caseFlags); error = HgfsCaseInsensitiveLookup(sharePath, sharePathLength, fileName, fileNameLength, convertedFileName, convertedFileNameLength); /* * Map the success or an error code. */ switch (error) { /* * 0 means that HgfsCaseInsensitiveLookup completed * successfully built the converted name thus we return * HGFS_NAME_STATUS_COMPLETE in this case. */ case 0: nameStatus = HGFS_NAME_STATUS_COMPLETE; break; case ENOTDIR: nameStatus = HGFS_NAME_STATUS_NOT_A_DIRECTORY; break; default: nameStatus = HGFS_NAME_STATUS_FAILURE; break; } return nameStatus; } *convertedFileName = strdup(fileName); if (!*convertedFileName) { nameStatus = HGFS_NAME_STATUS_OUT_OF_MEMORY; LOG(4, "%s: strdup on fileName failed.\n", __FUNCTION__); } else { *convertedFileNameLength = fileNameLength; } return nameStatus; } /* *----------------------------------------------------------------------------- * * HgfsPlatformDoFilenameLookup -- * * Determines if the file name lookup depending on case flags is required. * * Results: * TRUE on Linux / Apple. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsPlatformDoFilenameLookup(void) { return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsEffectivePermissions -- * * Get permissions that are in efffect for the current user. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsEffectivePermissions(char *fileName, // IN: Input filename Bool readOnlyShare, // IN: Share name uint32 *permissions) // OUT: Effective permissions { *permissions = 0; if (Posix_Access(fileName, R_OK) == 0) { *permissions |= HGFS_PERM_READ; } if (Posix_Access(fileName, X_OK) == 0) { *permissions |= HGFS_PERM_EXEC; } if (!readOnlyShare && (Posix_Access(fileName, W_OK) == 0)) { *permissions |= HGFS_PERM_WRITE; } return 0; } /* *----------------------------------------------------------------------------- * * HgfsGetCreationTime -- * * Calculates actual or emulated file creation time from stat structure. * Definition of stat structure are different on diferent platforms. * This function hides away all these differences and produces 64 bit value * which should be reported to the client. * * Results: * Value that should be used as a file creation time stamp. * The resulting timestamp is in platform independent HGFS format. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static uint64 HgfsGetCreationTime(const struct stat *stats) { uint64 creationTime; /* * Linux doesn't know about creation time; we just use the time * of last data modification for the creation time. * FreeBSD 5+ supports file creation time. * * Using mtime when creation time is unavailable to be consistent with SAMBA. */ #ifdef __FreeBSD__ /* * FreeBSD: All supported versions have timestamps with nanosecond resolution * and have file creation time. */ creationTime = HgfsConvertTimeSpecToNtTime(&stats->st_birthtimespec); #elif defined(__linux__) /* * Linux: Glibc 2.3+ has st_Xtim. Glibc 2.1/2.2 has st_Xtime/__unusedX on * same place (see below). We do not support Glibc 2.0 or older. */ # if (__GLIBC__ == 2) && (__GLIBC_MINOR__ < 3) && !defined(__UCLIBC__) /* * stat structure is same between glibc 2.3 and older glibcs, just * these __unused fields are always zero. If we'll use __unused* * instead of zeroes, we get automatically nanosecond timestamps * when running on host which provides them. */ creationTime = HgfsConvertToNtTime(stats->st_mtime, stats->__unused2); # else creationTime = HgfsConvertTimeSpecToNtTime(&stats->st_mtim); # endif #elif defined(__APPLE__) creationTime = HgfsConvertTimeSpecToNtTime(&stats->st_birthtimespec); #else /* * Solaris: No nanosecond timestamps, no file create timestamp. */ creationTime = HgfsConvertToNtTime(stats->st_mtime, 0); #endif return creationTime; } /* *----------------------------------------------------------------------------- * * HgfsStat -- * * Wrapper function that invokes stat on Mac OS and on Linux. * * Returns filled stat structure and a file creation time. File creation time is * the birthday time for Mac OS and last write time for Linux (which does not support * file creation time). * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static int HgfsStat(const char* fileName, // IN: file name Bool followLink, // IN: If true then follow symlink struct stat *stats, // OUT: file attributes uint64 *creationTime) // OUT: file creation time { int error; #if defined(__APPLE__) if (followLink) { error = stat(fileName, stats); } else { error = lstat(fileName, stats); } #else if (followLink) { error = Posix_Stat(fileName, stats); } else { error = Posix_Lstat(fileName, stats); } #endif *creationTime = HgfsGetCreationTime(stats); return error; } /* *----------------------------------------------------------------------------- * * HgfsFStat -- * * Wrapper function that invokes fstat. * * Returns filled stat structure and a file creation time. File creation time is * the birthday time for Mac OS and last write time for Linux (which does not support * file creation time). * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static int HgfsFStat(int fd, // IN: file descriptor struct stat *stats, // OUT: file attributes uint64 *creationTime) // OUT: file creation time { int error = 0; if (fstat(fd, stats) < 0) { error = errno; } *creationTime = HgfsGetCreationTime(stats); return error; } /* *---------------------------------------------------------------------------- * * HgfsGetSequentialOnlyFlagFromName -- * * Certain files like 'kallsyms' residing in /proc/ filesystem can be * copied only if they are opened in sequential mode. Check for such files * and set the 'sequential only' flag. This is done by trying to read the file * content using 'pread'. If 'pread' fails with ESPIPE then they are * tagged as 'sequential only' files. * * Results: * None. * * Side effects: * None * *---------------------------------------------------------------------------- */ static void HgfsGetSequentialOnlyFlagFromName(const char *fileName, // IN Bool followSymlinks, // IN: If true then follow symlink HgfsFileAttrInfo *attr) // IN/OUT { #if defined(__linux__) || defined(__APPLE__) int fd; int openFlags; if ((NULL == fileName) || (NULL == attr)) { return; } /* * We're not interested in creating a new file. So let's just get the * flags for a simple open request. This really should always work. */ HgfsServerGetOpenFlags(0, &openFlags); /* * By default we don't follow symlinks, O_NOFOLLOW is always set. * Unset it if followSymlinks config option is specified. */ if (followSymlinks) { openFlags &= ~O_NOFOLLOW; } /* * Checking for a FIFO we open in nonblocking mode. In this case, opening for * read only will succeed even if no-one has opened on the write side yet, * opening for write only will fail with ENXIO (no such device or address) * unless the other end has already been opened. * Note, Under Linux, opening a FIFO for read and write will succeed both * in blocking and nonblocking mode. POSIX leaves this behavior undefined. */ fd = Posix_Open(fileName, openFlags | O_RDONLY); if (fd < 0) { LOG(4, "%s: Couldn't open the file \"%s\"\n", __FUNCTION__, fileName); return; } HgfsGetSequentialOnlyFlagFromFd(fd, attr); close(fd); return; #endif } /* *---------------------------------------------------------------------------- * * HgfsGetSequentialOnlyFlagFromFd -- * * Certain files like 'kallsyms' residing in /proc/ filesystem can be * copied only if they are opened in sequential mode. Check for such files * and set the 'sequential only' flag. This is done by trying to read the file * content using 'pread'. If 'pread' fails with ESPIPE then they are * tagged as 'sequential only' files. * * Results: * None. * * Side effects: * None * *---------------------------------------------------------------------------- */ static void HgfsGetSequentialOnlyFlagFromFd(int fd, // IN HgfsFileAttrInfo *attr) // IN/OUT { #if defined(__linux__) || defined(__APPLE__) int error; char buffer[2]; struct stat stats; if (NULL == attr) { return; } if (fstat(fd, &stats) < 0) { return; } if (S_ISDIR(stats.st_mode) || S_ISLNK(stats.st_mode)) { return; } /* * At this point in the code, we are not reading any amount of data from the * file. We just want to check the behavior of pread. Since we are not * reading any data, we can call pread with size specified as 0. */ error = pread(fd, buffer, 0, 0); LOG(4, "%s: pread returned %d, errno %d\n", __FUNCTION__, error, errno); if ((-1 == error) && (ESPIPE == errno)) { LOG(4, "%s: Marking the file as 'Sequential only' file\n", __FUNCTION__); attr->flags |= HGFS_ATTR_SEQUENTIAL_ONLY; } return; #endif } /* *----------------------------------------------------------------------------- * * HgfsPlatformGetattrFromName -- * * Performs a stat operation on the given filename, and, if it is a symlink, * allocates the target filename on behalf of the caller and performs a * readlink to get it. If not a symlink, the targetName argument is * untouched. Does necessary translation between Unix file stats and the * HgfsFileAttrInfo formats. * NOTE: The function is different from HgfsGetAttrFromId: this function returns * effectve permissions while HgfsGetAttrFromId does not. * The reason for this asymmetry is that effective permissions are needed * to get a new handle. If the file is already opened then * getting effective permissions does not have any value. However getting * effective permissions would hurt perfomance and should be avoided. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformGetattrFromName(char *fileName, // IN/OUT: Input filename HgfsShareOptions configOptions, // IN: Share config options char *shareName, // IN: Share name HgfsFileAttrInfo *attr, // OUT: Struct to copy into char **targetName) // OUT: Symlink target { HgfsInternalStatus status = 0; struct stat stats; int error; char *myTargetName = NULL; uint64 creationTime; Bool followSymlinks; ASSERT(fileName); ASSERT(attr); LOG(4, "%s: getting attrs for \"%s\"\n", __FUNCTION__, fileName); followSymlinks = HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS), error = HgfsStat(fileName, followSymlinks, &stats, &creationTime); if (error) { status = errno; LOG(4, "%s: error stating file: %s\n", __FUNCTION__, Err_Errno2String(status)); goto exit; } /* * Deal with the file type returned from lstat(2). We currently support * regular files, directories, and symlinks. On Mac OS, we'll additionally * treat finder aliases as symlinks. */ if (S_ISDIR(stats.st_mode)) { attr->type = HGFS_FILE_TYPE_DIRECTORY; LOG(4, "%s: is a directory\n", __FUNCTION__); } else if (S_ISLNK(stats.st_mode)) { attr->type = HGFS_FILE_TYPE_SYMLINK; LOG(4, "%s: is a symlink\n", __FUNCTION__); /* * In the case of a symlink, we should populate targetName if the * caller asked. Use st_size and readlink() to do so. */ if (targetName != NULL) { myTargetName = Posix_ReadLink(fileName); if (myTargetName == NULL) { error = errno; LOG(4, "%s: readlink returned wrong size\n", __FUNCTION__); /* * Because of an unavoidable race between the lstat(2) and the * readlink(2), the symlink target may have lengthened and we may * not have read the entire link. If that happens, just return * "out of memory". */ status = error ? error : ENOMEM; goto exit; } } } else { /* * Now is a good time to check if the file was an alias. If so, we'll * treat it as a symlink. * * XXX: If HgfsGetattrResolveAlias fails, we'll treat the file as a * regular file. This isn't completely correct (the function may have * failed because we're out of memory), but it's better than having to * call LScopyItemInfoForRef for each file, which may negatively affect * performance. See: * * http://lists.apple.com/archives/carbon-development/2001/Nov/msg00007.html */ LOG(4, "%s: NOT a directory or symlink\n", __FUNCTION__); if (HgfsGetattrResolveAlias(fileName, &myTargetName)) { LOG(4, "%s: could not resolve file aliases\n", __FUNCTION__); } attr->type = HGFS_FILE_TYPE_REGULAR; if (myTargetName != NULL) { /* * At this point the alias target has been successfully resolved. If * the alias target is inside the same shared folder then convert it * to relative path. Converting to a relative path produces a symlink * that points to the target file in the guest OS. If the target lies * outside the shared folder then treat it the same way as if alias * has not been resolved - we drop the error and treat as a regular file! */ HgfsNameStatus nameStatus; size_t sharePathLen; const char* sharePath; nameStatus = HgfsServerPolicy_GetSharePath(shareName, strlen(shareName), HGFS_OPEN_MODE_READ_ONLY, &sharePathLen, &sharePath); if (nameStatus == HGFS_NAME_STATUS_COMPLETE && sharePathLen < strlen(myTargetName) && Str_Strncmp(sharePath, myTargetName, sharePathLen) == 0) { char *relativeName; relativeName = HgfsServerGetTargetRelativePath(fileName, myTargetName); free(myTargetName); myTargetName = relativeName; if (myTargetName != NULL) { /* * Let's mangle the permissions and size of the file so that * it more closely resembles a symlink. The size should be * the length of the target name (not including the * nul-terminator), and the permissions should be 777. */ stats.st_size = strlen(myTargetName); stats.st_mode |= ACCESSPERMS; attr->type = HGFS_FILE_TYPE_SYMLINK; } else { LOG(4, "%s: out of memory\n", __FUNCTION__); } } else { LOG(4, "%s: alias target is outside shared folder\n", __FUNCTION__); } } } if (myTargetName != NULL && targetName != NULL) { #if defined(__APPLE__) /* * HGFS clients will expect filenames in unicode normal form C * (precomposed) so Mac hosts must convert from normal form D * (decomposed). */ if (!CodeSet_Utf8FormDToUtf8FormC(myTargetName, strlen(myTargetName), targetName, NULL)) { LOG(4, "%s: Unable to normalize form C \"%s\"\n", __FUNCTION__, myTargetName); status = HgfsPlatformConvertFromNameStatus(HGFS_NAME_STATUS_FAILURE); goto exit; } #else *targetName = myTargetName; myTargetName = NULL; #endif LOG(4, "%s: symlink target \"%s\"\n", __FUNCTION__, *targetName); } HgfsStatToFileAttr(&stats, &creationTime, attr); /* * In the case we have a Windows client, force the hidden flag. * This will be ignored by Linux, Solaris clients. */ HgfsGetHiddenAttr(fileName, attr); HgfsGetSequentialOnlyFlagFromName(fileName, followSymlinks, attr); /* Get effective permissions if we can */ if (!(S_ISLNK(stats.st_mode))) { HgfsOpenMode shareMode; uint32 permissions; HgfsNameStatus nameStatus; nameStatus = HgfsServerPolicy_GetShareMode(shareName, strlen(shareName), &shareMode); if (nameStatus == HGFS_NAME_STATUS_COMPLETE && HgfsEffectivePermissions(fileName, shareMode == HGFS_OPEN_MODE_READ_ONLY, &permissions) == 0) { attr->mask |= HGFS_ATTR_VALID_EFFECTIVE_PERMS; attr->effectivePerms = permissions; } } exit: free(myTargetName); return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformGetattrFromFd -- * * Performs a stat operation on the given file desc. * Does necessary translation between Unix file stats and the * HgfsFileAttrInfo formats. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformGetattrFromFd(fileDesc fileDesc, // IN: file descriptor HgfsSessionInfo *session, // IN: session info HgfsFileAttrInfo *attr) // OUT: FileAttrInfo to copy into { HgfsInternalStatus status = 0; struct stat stats; int error; HgfsOpenMode shareMode; HgfsHandle handle = HGFS_INVALID_HANDLE; char *fileName = NULL; size_t fileNameLen; uint64 creationTime; ASSERT(attr); ASSERT(session); LOG(4, "%s: getting attrs for %u\n", __FUNCTION__, fileDesc); error = HgfsFStat(fileDesc, &stats, &creationTime); if (error) { LOG(4, "%s: error stating file: %s\n", __FUNCTION__, Err_Errno2String(error)); status = error; goto exit; } /* * For now, everything that isn't a directory or symlink is a regular * file. */ if (S_ISDIR(stats.st_mode)) { attr->type = HGFS_FILE_TYPE_DIRECTORY; LOG(4, "%s: is a directory\n", __FUNCTION__); } else if (S_ISLNK(stats.st_mode)) { attr->type = HGFS_FILE_TYPE_SYMLINK; LOG(4, "%s: is a symlink\n", __FUNCTION__); } else { attr->type = HGFS_FILE_TYPE_REGULAR; LOG(4, "%s: NOT a directory or symlink\n", __FUNCTION__); } HgfsStatToFileAttr(&stats, &creationTime, attr); /* * XXX - Correct share mode checking should be fully implemented. * * For now, we must ensure that the client only sees read only * attributes when the share is read only. This allows the client * to make decisions to fail write/delete operations. * It is required by clients who use file handles that * are cached, for setting attributes, renaming and deletion. */ if (!HgfsFileDesc2Handle(fileDesc, session, &handle)) { LOG(4, "%s: could not get HGFS handle for fd %u\n", __FUNCTION__, fileDesc); status = EBADF; goto exit; } if (!HgfsHandle2ShareMode(handle, session, &shareMode)) { LOG(4, "%s: could not get share mode fd %u\n", __FUNCTION__, fileDesc); status = EBADF; goto exit; } if (!HgfsHandle2FileName(handle, session, &fileName, &fileNameLen)) { LOG(4, "%s: could not map cached target file handle %u\n", __FUNCTION__, handle); status = EBADF; goto exit; } /* * In the case we have a Windows client, force the hidden flag. * This will be ignored by Linux, Solaris clients. */ HgfsGetHiddenAttr(fileName, attr); HgfsGetSequentialOnlyFlagFromFd(fileDesc, attr); if (shareMode == HGFS_OPEN_MODE_READ_ONLY) { /* * Share does not allow write, so tell the client * everything is read only. */ if (attr->mask & HGFS_ATTR_VALID_OWNER_PERMS) { attr->ownerPerms &= ~HGFS_PERM_WRITE; } if (attr->mask & HGFS_ATTR_VALID_GROUP_PERMS) { attr->groupPerms &= ~HGFS_PERM_WRITE; } if (attr->mask & HGFS_ATTR_VALID_OTHER_PERMS) { attr->otherPerms &= ~HGFS_PERM_WRITE; } } exit: free(fileName); return status; } /* *----------------------------------------------------------------------------- * * HgfsStatToFileAttr -- * * Does necessary translation between Unix file stats and the * HgfsFileAttrInfo formats. * It expects creationTime to be in platform-independent HGFS format and * stats in a platform-specific stat format. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsStatToFileAttr(struct stat *stats, // IN: stat information uint64 *creationTime, // IN: file creation time HgfsFileAttrInfo *attr) // OUT: FileAttrInfo to copy into { attr->size = stats->st_size; attr->allocationSize = stats->st_blocks * 512; attr->creationTime = *creationTime; #ifdef __FreeBSD__ /* * FreeBSD: All supported versions have timestamps with nanosecond resolution * and have file creation time. */ attr->accessTime = HgfsConvertTimeSpecToNtTime(&stats->st_atimespec); attr->writeTime = HgfsConvertTimeSpecToNtTime(&stats->st_mtimespec); attr->attrChangeTime = HgfsConvertTimeSpecToNtTime(&stats->st_ctimespec); #elif defined(__linux__) /* * Linux: Glibc 2.3+ has st_Xtim. Glibc 2.1/2.2 has st_Xtime/__unusedX on * same place (see below). We do not support Glibc 2.0 or older. */ # if (__GLIBC__ == 2) && (__GLIBC_MINOR__ < 3) && !defined(__UCLIBC__) /* * stat structure is same between glibc 2.3 and older glibcs, just * these __unused fields are always zero. If we'll use __unused* * instead of zeroes, we get automatically nanosecond timestamps * when running on host which provides them. */ attr->accessTime = HgfsConvertToNtTime(stats->st_atime, stats->__unused1); attr->writeTime = HgfsConvertToNtTime(stats->st_mtime, stats->__unused2); attr->attrChangeTime = HgfsConvertToNtTime(stats->st_ctime, stats->__unused3); # else attr->accessTime = HgfsConvertTimeSpecToNtTime(&stats->st_atim); attr->writeTime = HgfsConvertTimeSpecToNtTime(&stats->st_mtim); attr->attrChangeTime = HgfsConvertTimeSpecToNtTime(&stats->st_ctim); # endif #else /* * Solaris, Mac OS: No nanosecond timestamps. */ attr->accessTime = HgfsConvertToNtTime(stats->st_atime, 0); attr->writeTime = HgfsConvertToNtTime(stats->st_mtime, 0); attr->attrChangeTime = HgfsConvertToNtTime(stats->st_ctime, 0); #endif attr->specialPerms = (stats->st_mode & (S_ISUID | S_ISGID | S_ISVTX)) >> 9; attr->ownerPerms = (stats->st_mode & S_IRWXU) >> 6; attr->groupPerms = (stats->st_mode & S_IRWXG) >> 3; attr->otherPerms = stats->st_mode & S_IRWXO; LOG(4, "%s: done, permissions %o%o%o%o, size %"FMT64"u\n", __FUNCTION__, attr->specialPerms, attr->ownerPerms, attr->groupPerms, attr->otherPerms, attr->size); #ifdef __FreeBSD__ # if !defined(VM_X86_64) && !defined(VM_ARM_64) # define FMTTIMET "" # else # define FMTTIMET "l" # endif #else # define FMTTIMET "l" #endif LOG(4, "access: %"FMTTIMET"d/%"FMT64"u \nwrite: %"FMTTIMET"d/%"FMT64"u \n" "attr: %"FMTTIMET"d/%"FMT64"u\n", stats->st_atime, attr->accessTime, stats->st_mtime, attr->writeTime, stats->st_ctime, attr->attrChangeTime); #undef FMTTIMET attr->userId = stats->st_uid; attr->groupId = stats->st_gid; attr->hostFileId = stats->st_ino; attr->volumeId = stats->st_dev; attr->mask = HGFS_ATTR_VALID_TYPE | HGFS_ATTR_VALID_SIZE | HGFS_ATTR_VALID_ALLOCATION_SIZE | HGFS_ATTR_VALID_CREATE_TIME | HGFS_ATTR_VALID_ACCESS_TIME | HGFS_ATTR_VALID_WRITE_TIME | HGFS_ATTR_VALID_CHANGE_TIME | HGFS_ATTR_VALID_SPECIAL_PERMS | HGFS_ATTR_VALID_OWNER_PERMS | HGFS_ATTR_VALID_GROUP_PERMS | HGFS_ATTR_VALID_OTHER_PERMS | HGFS_ATTR_VALID_USERID | HGFS_ATTR_VALID_GROUPID | HGFS_ATTR_VALID_FILEID | HGFS_ATTR_VALID_VOLID; } /* *----------------------------------------------------------------------------- * * HgfsSetattrMode -- * * Set the permissions based on stat and attributes. * * Results: * TRUE if permissions have changed. * FALSE otherwise. * * Note that newPermissions is always set. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsSetattrMode(struct stat *statBuf, // IN: stat info HgfsFileAttrInfo *attr, // IN: attrs to set mode_t *newPermissions) // OUT: new perms { Bool permsChanged = FALSE; ASSERT(statBuf); ASSERT(attr); ASSERT(newPermissions); *newPermissions = 0; if (attr->mask & HGFS_ATTR_VALID_SPECIAL_PERMS) { *newPermissions |= attr->specialPerms << 9; permsChanged = TRUE; } else { *newPermissions |= statBuf->st_mode & (S_ISUID | S_ISGID | S_ISVTX); } if (attr->mask & HGFS_ATTR_VALID_OWNER_PERMS) { *newPermissions |= attr->ownerPerms << 6; permsChanged = TRUE; } else { *newPermissions |= statBuf->st_mode & S_IRWXU; } if (attr->mask & HGFS_ATTR_VALID_GROUP_PERMS) { *newPermissions |= attr->groupPerms << 3; permsChanged = TRUE; } else { *newPermissions |= statBuf->st_mode & S_IRWXG; } if (attr->mask & HGFS_ATTR_VALID_OTHER_PERMS) { *newPermissions |= attr->otherPerms; permsChanged = TRUE; } else { *newPermissions |= statBuf->st_mode & S_IRWXO; } return permsChanged; } /* *----------------------------------------------------------------------------- * * HgfsSetattrOwnership -- * * Set the user and group ID based the attributes. * * Results: * TRUE if ownership has changed. * FALSE otherwise. * * Note that newUid/newGid are always set. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsSetattrOwnership(HgfsFileAttrInfo *attr, // IN: attrs to set uid_t *newUid, // OUT: new user ID gid_t *newGid) // OUT: new group ID { Bool idChanged = FALSE; ASSERT(attr); ASSERT(newUid); ASSERT(newGid); *newUid = *newGid = -1; if (attr->mask & HGFS_ATTR_VALID_USERID) { *newUid = attr->userId; idChanged = TRUE; } if (attr->mask & HGFS_ATTR_VALID_GROUPID) { *newGid = attr->groupId; idChanged = TRUE; } return idChanged; } /* *----------------------------------------------------------------------------- * * HgfsSetattrTimes -- * * Set the time stamps based on stat and attributes. * * Results: * Zero on success. accessTime/modTime contain new times. * Non-zero on failure. * * Note that timesChanged is always set. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsSetattrTimes(struct stat *statBuf, // IN: stat info HgfsFileAttrInfo *attr, // IN: attrs to set HgfsAttrHint hints, // IN: attr hints Bool useHostTime, // IN: use the current host time struct timeval *accessTime, // OUT: access time struct timeval *modTime, // OUT: modification time Bool *timesChanged) // OUT: times changed { HgfsInternalStatus status = 0; int error; ASSERT(statBuf); ASSERT(attr); ASSERT(accessTime); ASSERT(modTime); ASSERT(timesChanged); *timesChanged = FALSE; if (attr->mask & (HGFS_ATTR_VALID_ACCESS_TIME | HGFS_ATTR_VALID_WRITE_TIME)) { /* * utime(2) only lets you update both atime and mtime at once, so * if either one needs updating, first we get the current times * and call utime with some combination of the current and new * times. This is a bit racy because someone else could update * one of them in between, but this seems to be how "touch" does * things, so we'll go with it. [bac] */ if ((attr->mask & (HGFS_ATTR_VALID_ACCESS_TIME | HGFS_ATTR_VALID_WRITE_TIME)) != (HGFS_ATTR_VALID_ACCESS_TIME | HGFS_ATTR_VALID_WRITE_TIME)) { /* * XXX Set also usec from nsec stat fields. */ accessTime->tv_sec = statBuf->st_atime; accessTime->tv_usec = 0; modTime->tv_sec = statBuf->st_mtime; modTime->tv_usec = 0; } /* * If times need updating, we either use the guest-provided time or the * host time. HGFS_ATTR_HINT_SET_x_TIME_ will be set if we should use * the guest time, and useHostTime will be TRUE if the config * option to always use host time is set. */ if (attr->mask & HGFS_ATTR_VALID_ACCESS_TIME) { if (!useHostTime && (hints & HGFS_ATTR_HINT_SET_ACCESS_TIME)) { /* Use the guest-provided time */ struct timespec ts; HgfsConvertFromNtTimeNsec(&ts, attr->accessTime); accessTime->tv_sec = ts.tv_sec; accessTime->tv_usec = ts.tv_nsec / 1000; } else { /* Use the host's time */ struct timeval tv; if (gettimeofday(&tv, NULL) != 0) { error = errno; LOG(4, "%s: gettimeofday error: %s\n", __FUNCTION__, Err_Errno2String(error)); status = error; goto exit; } accessTime->tv_sec = tv.tv_sec; accessTime->tv_usec = tv.tv_usec; } } if (attr->mask & HGFS_ATTR_VALID_WRITE_TIME) { if (!useHostTime && (hints & HGFS_ATTR_HINT_SET_WRITE_TIME)) { struct timespec ts; HgfsConvertFromNtTimeNsec(&ts, attr->writeTime); modTime->tv_sec = ts.tv_sec; modTime->tv_usec = ts.tv_nsec / 1000; } else { struct timeval tv; if (gettimeofday(&tv, NULL) != 0) { error = errno; LOG(4, "%s: gettimeofday error: %s\n", __FUNCTION__, Err_Errno2String(error)); status = error; goto exit; } modTime->tv_sec = tv.tv_sec; modTime->tv_usec = tv.tv_usec; } } *timesChanged = TRUE; } exit: return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformSetattrFromFd -- * * Handle a Setattr request by file descriptor. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformSetattrFromFd(HgfsHandle file, // IN: file descriptor HgfsSessionInfo *session, // IN: session info HgfsFileAttrInfo *attr, // OUT: attrs to set HgfsAttrHint hints, // IN: attr hints Bool useHostTime) // IN: use current host time { HgfsInternalStatus status = 0, timesStatus; int error; struct stat statBuf; struct timeval times[2]; mode_t newPermissions; uid_t newUid = -1; gid_t newGid = -1; Bool permsChanged = FALSE; Bool timesChanged = FALSE; Bool idChanged = FALSE; int fd; HgfsLockType serverLock; ASSERT(session); ASSERT(file != HGFS_INVALID_HANDLE); status = HgfsPlatformGetFd(file, session, FALSE, &fd); if (status != 0) { LOG(4, "%s: Could not get file descriptor\n", __FUNCTION__); goto exit; } /* We need the old stats so that we can preserve times. */ if (fstat(fd, &statBuf) == -1) { error = errno; LOG(4, "%s: error stating file %u: %s\n", __FUNCTION__, fd, Err_Errno2String(error)); status = error; goto exit; } /* * Try to make each requested attribute change. In the event that * one operation fails, we still attempt to perform any other * operations that the driver requested. We return success only * if all operations succeeded. */ idChanged = HgfsSetattrOwnership(attr, &newUid, &newGid); if (idChanged) { LOG(4, "%s: set uid %"FMTUID" and gid %"FMTUID"\n", __FUNCTION__, newUid, newGid); if (fchown(fd, newUid, newGid) < 0) { error = errno; LOG(4, "%s: error chowning file %u: %s\n", __FUNCTION__, fd, Err_Errno2String(error)); status = error; } } /* * Set permissions based on what we got in the packet. If we didn't get * a particular bit, use the existing permissions. In that case we don't * toggle permsChanged since it should not influence our decision of * whether to actually call chmod or not. * * NOTE: Setting ownership clears SUID and SGID bits, therefore set the * file permissions after setting ownership. */ permsChanged = HgfsSetattrMode(&statBuf, attr, &newPermissions); if (permsChanged) { LOG(4, "%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions); if (fchmod(fd, newPermissions) < 0) { error = errno; LOG(4, "%s: error chmoding file %u: %s\n", __FUNCTION__, fd, Err_Errno2String(error)); status = error; } } if (attr->mask & HGFS_ATTR_VALID_SIZE) { /* * XXX: Truncating the file will trigger an oplock break. The client * should have predicted this and removed the oplock prior to sending * the truncate request. At this point, the server must safeguard itself * against deadlock. */ if (!HgfsHandle2ServerLock(file, session, &serverLock)) { LOG(4, "%s: File handle is no longer valid.\n", __FUNCTION__); status = EBADF; } else if (serverLock != HGFS_LOCK_NONE) { LOG(4, "%s: Client attempted to truncate an oplocked file\n", __FUNCTION__); status = EBUSY; } else if (ftruncate(fd, attr->size) < 0) { error = errno; LOG(4, "%s: error truncating file %u: %s\n", __FUNCTION__, fd, Err_Errno2String(error)); status = error; } else { LOG(4, "%s: set size %"FMT64"u\n", __FUNCTION__, attr->size); } } /* Setting hidden attribute for symlink itself is not supported. */ if ((attr->mask & HGFS_ATTR_VALID_FLAGS) && !S_ISLNK(statBuf.st_mode)) { char *localName; size_t localNameSize; if (HgfsHandle2FileName(file, session, &localName, &localNameSize)) { status = HgfsSetHiddenXAttr(localName, (attr->flags & HGFS_ATTR_HIDDEN) != 0, newPermissions); free(localName); } } timesStatus = HgfsSetattrTimes(&statBuf, attr, hints, useHostTime, ×[0], ×[1], ×Changed); if (timesStatus == 0 && timesChanged) { uid_t uid = (uid_t)-1; Bool switchToSuperUser = FALSE; LOG(4, "%s: setting new times\n", __FUNCTION__); /* * If the VMX is neither the file owner nor running as root, return an error. * Otherwise if we are not the file owner switch to superuser briefly * to set the files times using futimes. */ if (geteuid() != statBuf.st_uid) { /* We are not the file owner. Check if we are running as root. */ if (!Id_IsSuperUser()) { LOG(4, "%s: only owner of file %u or root can call futimes\n", __FUNCTION__, fd); /* XXX: Linux kernel says both EPERM and EACCES are valid here. */ status = EPERM; goto exit; } uid = Id_BeginSuperUser(); switchToSuperUser = TRUE; } /* * XXX Newer glibc provide also lutimes() and futimes() * when we politely ask with -D_GNU_SOURCE -D_BSD_SOURCE */ if (futimes(fd, times) < 0) { if (!switchToSuperUser) { /* * Check bug 718252. If futimes() fails, switch to * superuser briefly and try futimes() one more time. */ uid = Id_BeginSuperUser(); switchToSuperUser = TRUE; if (futimes(fd, times) < 0) { error = errno; LOG(4, "%s: Executing futimes as owner on file: %u " "failed with error: %s\n", __FUNCTION__, fd, Err_Errno2String(error)); status = error; } } else { error = errno; LOG(4, "%s: Executing futimes as superuser on file: %u " "failed with error: %s\n", __FUNCTION__, fd, Err_Errno2String(error)); status = error; } } if (switchToSuperUser) { Id_EndSuperUser(uid); } } else if (timesStatus != 0) { status = timesStatus; } exit: return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformSetattrFromName -- * * Handle a Setattr request by name. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformSetattrFromName(char *localName, // IN: Name HgfsFileAttrInfo *attr, // IN: attrs to set HgfsShareOptions configOptions, // IN: share options HgfsAttrHint hints, // IN: attr hints Bool useHostTime) // IN: use current host time { HgfsInternalStatus status = 0, timesStatus; struct stat statBuf; struct timeval times[2]; mode_t newPermissions; uid_t newUid = -1; gid_t newGid = -1; Bool permsChanged = FALSE; Bool timesChanged = FALSE; Bool idChanged = FALSE; int error; ASSERT(localName); if (!HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) { /* * If followSymlink option is not set, verify that the pathname isn't a * symlink. Some of the following syscalls (chmod, for example) will * follow a link. So we need to verify the final component too. The * parent has already been verified in HgfsServerGetAccess. * * XXX: This is racy. But clients interested in preventing a race should * have sent us a Setattr packet with a valid HGFS handle. */ if (File_IsSymLink(localName)) { LOG(4, "%s: pathname contains a symlink\n", __FUNCTION__); status = EINVAL; goto exit; } } LOG(4, "%s: setting attrs for \"%s\"\n", __FUNCTION__, localName); /* We need the old stats so that we can preserve times. */ if (Posix_Lstat(localName, &statBuf) == -1) { error = errno; LOG(4, "%s: error stating file \"%s\": %s\n", __FUNCTION__, localName, Err_Errno2String(error)); status = error; goto exit; } /* * Try to make each requested attribute change. In the event that * one operation fails, we still attempt to perform any other * operations that the driver requested. We return success only * if all operations succeeded. */ idChanged = HgfsSetattrOwnership(attr, &newUid, &newGid); /* * Chown changes the uid and gid together. If one of them should * not be changed, we pass in -1. */ if (idChanged) { if (Posix_Lchown(localName, newUid, newGid) < 0) { error = errno; LOG(4, "%s: error chowning file \"%s\": %s\n", __FUNCTION__, localName, Err_Errno2String(error)); status = error; } } /* * Set permissions based on what we got in the packet. If we didn't get * a particular bit, use the existing permissions. In that case we don't * toggle permsChanged since it should not influence our decision of * whether to actually call chmod or not. * * NOTE: Setting ownership clears SUID and SGID bits, therefore set the * file permissions after setting ownership. */ permsChanged = HgfsSetattrMode(&statBuf, attr, &newPermissions); if (permsChanged) { LOG(4, "%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions); if (Posix_Chmod(localName, newPermissions) < 0) { error = errno; LOG(4, "%s: error chmoding file \"%s\": %s\n", __FUNCTION__, localName, Err_Errno2String(error)); status = error; } } if (attr->mask & HGFS_ATTR_VALID_SIZE) { if (Posix_Truncate(localName, attr->size) < 0) { error = errno; LOG(4, "%s: error truncating file \"%s\": %s\n", __FUNCTION__, localName, Err_Errno2String(error)); status = error; } else { LOG(4, "%s: set size %"FMT64"u\n", __FUNCTION__, attr->size); } } if (attr->mask & HGFS_ATTR_VALID_FLAGS) { status = HgfsSetHiddenXAttr(localName, (attr->flags & HGFS_ATTR_HIDDEN) != 0, newPermissions); } timesStatus = HgfsSetattrTimes(&statBuf, attr, hints, useHostTime, ×[0], ×[1], ×Changed); if (timesStatus == 0 && timesChanged) { /* * XXX Newer glibc provide also lutimes() and futimes() * when we politely ask with -D_GNU_SOURCE -D_BSD_SOURCE */ if (Posix_Utimes(localName, times) < 0) { error = errno; LOG(4, "%s: utimes error on file \"%s\": %s\n", __FUNCTION__, localName, Err_Errno2String(error)); status = error; } } else if (timesStatus != 0) { status = timesStatus; } exit: return status; } HgfsInternalStatus HgfsPlatformWriteWin32Stream(HgfsHandle file, // IN: packet header char *dataToWrite, // IN: request type size_t requiredSize, Bool doSecurity, uint32 *actualSize, HgfsSessionInfo *session) { return EPROTO; } /* *----------------------------------------------------------------------------- * * HgfsPlatformVDirStatsFs -- * * Handle a statfs (query volume information) request for a virtual folder. * * Results: * HGFS_ERROR_SUCCESS or an appropriate error code. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformVDirStatsFs(HgfsSessionInfo *session, // IN: session info HgfsNameStatus nameStatus, // IN: VolumeInfoType infoType, // IN: uint64 *outFreeBytes, // OUT: uint64 *outTotalBytes) // OUT: { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; HgfsInternalStatus firstErr = HGFS_ERROR_SUCCESS; Bool firstShare = TRUE; size_t failed = 0; size_t shares = 0; DirectoryEntry *dent; HgfsHandle handle; ASSERT(nameStatus != HGFS_NAME_STATUS_COMPLETE); switch (nameStatus) { case HGFS_NAME_STATUS_INCOMPLETE_BASE: /* * This is the base of our namespace. Clients can request a * QueryVolumeInfo on it, on individual shares, or on just about * any pathname. */ LOG(4, "%s: opened search on base\n", __FUNCTION__); status = HgfsServerSearchVirtualDir(HgfsServerResEnumGet, HgfsServerResEnumInit, HgfsServerResEnumExit, DIRECTORY_SEARCH_TYPE_BASE, session, &handle); if (status != HGFS_ERROR_SUCCESS) { break; } /* * Now go through all shares and get share paths on the server. * Then retrieve space info for each share's volume. */ while ((status = HgfsServerGetDirEntry(handle, session, HGFS_SEARCH_LAST_ENTRY_INDEX, TRUE, &dent)) == HGFS_ERROR_SUCCESS) { char const *sharePath; size_t sharePathLen; uint64 currentFreeBytes = 0; uint64 currentTotalBytes = 0; size_t length; if (NULL == dent) { break; } length = strlen(dent->d_name); /* * Now that the server is passing '.' and ".." around as dents, we * need to make sure to handle them properly. In particular, they * should be ignored within QueryVolume, as they're not real shares. */ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) { LOG(4, "%s: Skipping fake share %s\n", __FUNCTION__, dent->d_name); free(dent); continue; } /* * The above check ignores '.' and '..' so we do not include them in * the share count here. */ shares++; /* * Check permission on the share and get the share path. It is not * fatal if these do not succeed. Instead we ignore the failures * (apart from logging them) until we have processed all shares. Only * then do we check if there were any failures; if all shares failed * to process then we bail out with an error code. */ nameStatus = HgfsServerPolicy_GetSharePath(dent->d_name, length, HGFS_OPEN_MODE_READ_ONLY, &sharePathLen, &sharePath); free(dent); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, "%s: No such share or access denied\n", __FUNCTION__); if (0 == firstErr) { firstErr = HgfsPlatformConvertFromNameStatus(nameStatus); } failed++; continue; } /* * Pick the drive with amount of space available and return that * according to different volume info type. */ if (!HgfsServerStatFs(sharePath, sharePathLen, ¤tFreeBytes, ¤tTotalBytes)) { LOG(4, "%s: error getting volume information\n", __FUNCTION__); if (0 == firstErr) { firstErr = HGFS_ERROR_IO; } failed++; continue; } /* * Pick the drive with amount of space available and return that * according to different volume info type. */ switch (infoType) { case VOLUME_INFO_TYPE_MIN: if ((*outFreeBytes > currentFreeBytes) || firstShare) { firstShare = FALSE; *outFreeBytes = currentFreeBytes; *outTotalBytes = currentTotalBytes; } break; case VOLUME_INFO_TYPE_MAX: if ((*outFreeBytes < currentFreeBytes)) { *outFreeBytes = currentFreeBytes; *outTotalBytes = currentTotalBytes; } break; default: NOT_IMPLEMENTED(); } } if (!HgfsRemoveSearch(handle, session)) { LOG(4, "%s: could not close search on base\n", __FUNCTION__); } if (shares == failed) { if (firstErr != 0) { /* * We failed to query any of the shares. We return the error] * from the first share failure. */ status = firstErr; } /* No shares but no error, return zero for sizes and success. */ } break; default: LOG(4, "%s: file access check failed\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } return status; } #ifdef VMX86_LOG /* *----------------------------------------------------------------------------- * * HgfsPlatformDirDumpDents -- * * Dump a set of directory entries (debugging code). * Note: this must be called with the session search lock acquired. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsPlatformDirDumpDents(HgfsSearch *search) // IN: search { unsigned int i; ASSERT(search != NULL); Log("%s: %u dents in \"%s\"\n", __FUNCTION__, search->numDents, search->utf8Dir); for (i = 0; i < search->numDents; i++) { Log("\"%s\"\n", search->dents[i]->d_name); } } #endif /* *----------------------------------------------------------------------------- * * HgfsConvertToUtf8FormC -- * * Converts file name coming from OS to Utf8 form C. * The function NOOP on Linux where the name is already in correct * encoding. * On Mac OS the default encoding is Utf8 form D thus a convertion to * Utf8 for C is required. * * Results: * TRUE on success. Buffer has name in Utf8 form C encoding. * FALSE on error. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsConvertToUtf8FormC(char *buffer, // IN/OUT: name to normalize size_t bufferSize) // IN: size of the name buffer { #if defined(__APPLE__) size_t entryNameLen; char *entryName = NULL; Bool result; /* * HGFS clients receive names in unicode normal form C, * (precomposed) so Mac hosts must convert from normal form D * (decomposed). */ if (CodeSet_Utf8FormDToUtf8FormC(buffer, bufferSize, &entryName, &entryNameLen)) { result = entryNameLen < bufferSize; if (result) { memcpy(buffer, entryName, entryNameLen + 1); } free(entryName); } else { LOG(4, "%s: Unable to normalize form C \"%s\"\n", __FUNCTION__, buffer); result = FALSE; } return result; #else size_t size; /* * Buffer may contain invalid data after the null terminating character. * We need to check the validity of the buffer only till the null * terminating character (if any). Calculate the real size of the * string before calling Unicode_IsBufferValid(). */ for (size = 0; size < bufferSize ; size++) { if ('\0' == buffer[size]) { break; } } return Unicode_IsBufferValid(buffer, size, STRING_ENCODING_UTF8); #endif /* defined(__APPLE__) */ } /* *----------------------------------------------------------------------------- * * HgfsPlatformGetDirEntry -- * * Returns the directory entry (or a copy) at the given index. If remove is set * to TRUE, the existing result is also pruned and the remaining results * are shifted up in the result array. * * Results: * HGFS_ERROR_SUCCESS or an appropriate error code. * * Side effects: * None. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformGetDirEntry(HgfsSearch *search, // IN: search HgfsSessionInfo *session, // IN: Session info uint32 index, // IN: Offset to retrieve at Bool remove, // IN: If true, removes the result struct DirectoryEntry **dirEntry) // OUT: dirent { DirectoryEntry *dent = NULL; HgfsInternalStatus status = HGFS_ERROR_SUCCESS; if (index >= search->numDents) { goto out; } /* If we're not removing the result, we need to make a copy of it. */ if (remove) { /* * We're going to shift the dents array, overwriting the dent pointer at * offset, so first we need to save said pointer so that we can return it * later to the caller. */ dent = search->dents[index]; if (index < search->numDents - 1) { /* Shift up the remaining results */ memmove(&search->dents[index], &search->dents[index + 1], (search->numDents - (index + 1)) * sizeof search->dents[0]); } /* Decrement the number of results */ search->numDents--; } else { DirectoryEntry *originalDent; size_t nameLen; originalDent = search->dents[index]; ASSERT(originalDent); nameLen = strlen(originalDent->d_name); /* * Make sure the name will not overrun the d_name buffer, the end of * which is also the end of the DirectoryEntry. */ ASSERT(offsetof(DirectoryEntry, d_name) + nameLen < originalDent->d_reclen); dent = malloc(originalDent->d_reclen); if (dent == NULL) { status = HGFS_ERROR_NOT_ENOUGH_MEMORY; goto out; } /* * Yes, there are more members than this in a dirent. But if you look * at the top of hgfsServerInt.h, you'll see that on Windows we only * define d_reclen and d_name, as those are the only fields we need. */ dent->d_reclen = originalDent->d_reclen; memcpy(dent->d_name, originalDent->d_name, nameLen); dent->d_name[nameLen] = 0; } out: if (status == HGFS_ERROR_SUCCESS) { *dirEntry = dent; } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformSetDirEntry -- * * Sets the directory entry into the search read information. * * Results: * HGFS_ERROR_SUCCESS or an appropriate error code. * * Side effects: * None. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformSetDirEntry(HgfsSearch *search, // IN: partially valid search HgfsShareOptions configOptions, // IN: share configuration settings HgfsSessionInfo *session, // IN: session info struct DirectoryEntry *dirEntry, // IN: the indexed dirent Bool getAttr, // IN: get the entry attributes HgfsFileAttrInfo *entryAttr, // OUT: entry attributes, optional char **entryName, // OUT: entry name uint32 *entryNameLength) // OUT: entry name length { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; unsigned int length; char *fullName; char *sharePath; size_t sharePathLen; size_t fullNameLen; HgfsLockType serverLock = HGFS_LOCK_NONE; fileDesc fileDesc; Bool unescapeName = TRUE; length = strlen(dirEntry->d_name); /* Each type of search gets a dent's attributes in a different way. */ switch (search->type) { case DIRECTORY_SEARCH_TYPE_DIR: /* * Construct the UTF8 version of the full path to the file, and call * HgfsGetattrFromName to get the attributes of the file. */ fullNameLen = search->utf8DirLen + 1 + length; fullName = (char *)malloc(fullNameLen + 1); if (fullName) { memcpy(fullName, search->utf8Dir, search->utf8DirLen); fullName[search->utf8DirLen] = DIRSEPC; memcpy(&fullName[search->utf8DirLen + 1], dirEntry->d_name, length + 1); LOG(4, "%s: about to stat \"%s\"\n", __FUNCTION__, fullName); /* Do we need to query the attributes information? */ if (getAttr) { /* * XXX: It is unreasonable to make the caller either 1) pass existing * handles for directory objects as part of the SearchRead, or 2) * prior to calling SearchRead on a directory, break all oplocks on * that directory's objects. * * To compensate for that, if we detect that this directory object * has an oplock, we'll quietly reuse the handle. Note that this * requires clients who take out an exclusive oplock to open a * handle with read as well as write access, otherwise we'll fail * further down in HgfsStat. * * XXX: We could open a new handle safely if its a shared oplock. * But isn't this handle sharing always desirable? */ if (HgfsFileHasServerLock(fullName, session, &serverLock, &fileDesc)) { LOG(4, "%s: Reusing existing oplocked handle " "to avoid oplock break deadlock\n", __FUNCTION__); status = HgfsPlatformGetattrFromFd(fileDesc, session, entryAttr); } else { status = HgfsPlatformGetattrFromName(fullName, configOptions, search->utf8ShareName, entryAttr, NULL); } if (HGFS_ERROR_SUCCESS != status) { HgfsOp savedOp = entryAttr->requestType; LOG(4, "%s: stat FAILED %s (%d)\n", __FUNCTION__, fullName, status); memset(entryAttr, 0, sizeof *entryAttr); entryAttr->requestType = savedOp; entryAttr->type = HGFS_FILE_TYPE_REGULAR; entryAttr->mask = HGFS_ATTR_VALID_TYPE; status = HGFS_ERROR_SUCCESS; } } free(fullName); } else { LOG(4, "%s: could not allocate space for \"%s\\%s\"\n", __FUNCTION__, search->utf8Dir, dirEntry->d_name); status = HGFS_ERROR_NOT_ENOUGH_MEMORY; } break; case DIRECTORY_SEARCH_TYPE_BASE: /* * We only want to unescape names that we could have escaped. * This cannot apply to our shares since they are created by the user. * The client will take care of escaping anything it requires. */ unescapeName = FALSE; if (getAttr) { /* * For a search enumerating all shares, give the default attributes * for '.' and ".." (which aren't really shares anyway). Each real * share gets resolved into its full path, and gets its attributes * via HgfsGetattrFromName. */ if (strcmp(dirEntry->d_name, ".") == 0 || strcmp(dirEntry->d_name, "..") == 0) { LOG(4, "%s: assigning %s default attributes\n", __FUNCTION__, dirEntry->d_name); HgfsPlatformGetDefaultDirAttrs(entryAttr); } else { HgfsNameStatus nameStatus; /* Check permission on the share and get the share path */ nameStatus = HgfsServerPolicy_GetSharePath(dirEntry->d_name, length, HGFS_OPEN_MODE_READ_ONLY, &sharePathLen, (char const **)&sharePath); if (nameStatus == HGFS_NAME_STATUS_COMPLETE) { /* * Server needs to produce list of shares that is consistent with * the list defined in UI. If a share can't be accessed because of * problems on the host, the server still enumerates it and * returns to the client. * XXX: We will open a new handle for this, but it should be safe * from oplock-induced deadlock because these are all directories, * and thus cannot have oplocks placed on them. */ status = HgfsPlatformGetattrFromName(sharePath, configOptions, dirEntry->d_name, entryAttr, NULL); if (HGFS_ERROR_SUCCESS != status) { /* * The dent no longer exists. Log the event. */ LOG(4, "%s: stat FAILED\n", __FUNCTION__); status = HGFS_ERROR_SUCCESS; } } else { LOG(4, "%s: No such share or access denied\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } } } break; case DIRECTORY_SEARCH_TYPE_OTHER: default: NOT_IMPLEMENTED(); break; } /* * We need to unescape the name before sending it back to the client */ if (HGFS_ERROR_SUCCESS == status) { *entryName = Util_SafeStrdup(dirEntry->d_name); if (unescapeName) { *entryNameLength = HgfsEscape_Undo(*entryName, length + 1); } else { *entryNameLength = length; } LOG(4, "%s: dent name is \"%s\" len = %u\n", __FUNCTION__, *entryName, *entryNameLength); } else { *entryName = NULL; *entryNameLength = 0; LOG(4, "%s: error %d getting dent\n", __FUNCTION__, status); } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformScandir -- * * The cross-platform HGFS server code will call into this function * in order to populate a list of dents. In the Linux case, we want to avoid * using scandir(3) because it makes no provisions for not following * symlinks. Instead, we'll open(2) the directory with O_DIRECTORY and * O_NOFOLLOW, call getdents(2) directly, then close(2) the directory. * * On Mac OS getdirentries became deprecated starting from 10.6 and * there is no similar API available. Thus on Mac OS readdir is used that * returns one directory entry at a time. * * Results: * Zero on success. numDents contains the number of directory entries found. * Non-zero on error. * * Side effects: * Memory allocation. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformScandir(char const *baseDir, // IN: Directory to search in size_t baseDirLen, // IN: Ignored Bool followSymlinks, // IN: followSymlinks config option struct DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys int *numDents) // OUT: Number of DirectoryEntrys { #if defined(__APPLE__) DIR *fd = NULL; #else int fd = -1; int openFlags = O_NONBLOCK | O_RDONLY | O_DIRECTORY | O_NOFOLLOW; #endif int result; DirectoryEntry **myDents = NULL; int myNumDents = 0; HgfsInternalStatus status = 0; /* * XXX: glibc uses 8192 (BUFSIZ) when it can't get st_blksize from a stat. * Should we follow its lead and use stat to get st_blksize? */ char buffer[8192]; #if defined(__APPLE__) /* * Since opendir does not support O_NOFOLLOW flag need to explicitly verify * that we are not dealing with symlink if follow symlinks is * not allowed. */ if (!followSymlinks) { struct stat st; if (lstat(baseDir, &st) == -1) { status = errno; LOG(4, "%s: error in lstat: %d (%s)\n", __FUNCTION__, status, Err_Errno2String(status)); goto exit; } if (S_ISLNK(st.st_mode)) { status = EACCES; LOG(4, "%s: do not follow symlink\n", __FUNCTION__); goto exit; } } fd = Posix_OpenDir(baseDir); if (NULL == fd) { status = errno; LOG(4, "%s: error in opendir: %d (%s)\n", __FUNCTION__, status, Err_Errno2String(status)); goto exit; } #else /* Follow symlinks if config option is set. */ if (followSymlinks) { openFlags &= ~O_NOFOLLOW; } /* We want a directory. No FIFOs. Symlinks only if config option is set. */ result = Posix_Open(baseDir, openFlags); if (result < 0) { status = errno; LOG(4, "%s: error in open: %d (%s)\n", __FUNCTION__, status, Err_Errno2String(status)); goto exit; } fd = result; #endif /* * Rather than read a single dent at a time, batch up multiple dents * in each call by using a buffer substantially larger than one dent. */ while ((result = getdents(fd, (void *)buffer, sizeof buffer)) > 0) { size_t offset = 0; while (offset < result) { DirectoryEntry *newDent, **newDents; newDent = (DirectoryEntry *)(buffer + offset); /* This dent had better fit in the actual space we've got left. */ ASSERT(newDent->d_reclen <= result - offset); /* Add another dent pointer to the dents array. */ newDents = realloc(myDents, sizeof *myDents * (myNumDents + 1)); if (newDents == NULL) { status = ENOMEM; goto exit; } myDents = newDents; /* * Allocate the new dent and set it up. We do a straight memcpy of * the entire record to avoid dealing with platform-specific fields. */ myDents[myNumDents] = malloc(newDent->d_reclen); if (myDents[myNumDents] == NULL) { status = ENOMEM; goto exit; } if (HgfsConvertToUtf8FormC(newDent->d_name, newDent->d_reclen - offsetof(DirectoryEntry, d_name))) { memcpy(myDents[myNumDents], newDent, newDent->d_reclen); /* * Dent is done. Bump the offset to the batched buffer to process the * next dent within it. */ myNumDents++; } else { /* * XXX: * HGFS discards all file names that can't be converted to utf8. * It is not desirable since it causes many problems like * failure to delete directories which contain such files. * Need to change this to a more reasonable behavior, similar * to name escaping which is used to deal with illegal file names. */ free(myDents[myNumDents]); } offset += newDent->d_reclen; } } if (result == -1) { status = errno; LOG(4, "%s: error in getdents: %d (%s)\n", __FUNCTION__, status, Err_Errno2String(status)); goto exit; } exit: #if defined(__APPLE__) if (NULL != fd && closedir(fd) < 0) { #else if (fd != -1 && close(fd) < 0) { #endif status = errno; LOG(4, "%s: error in close: %d (%s)\n", __FUNCTION__, status, Err_Errno2String(status)); } /* * On error, free all allocated dents. On success, set the dents pointer * given to us by the client. */ if (status != 0) { size_t i; for (i = 0; i < myNumDents; i++) { free(myDents[i]); } free(myDents); } else { *dents = myDents; *numDents = myNumDents; } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformScanvdir -- * * Perform a scandir on our virtual directory. * * Get directory entry names from the given callback function, and * build an array of DirectoryEntrys of all the names. Somewhat similar to * scandir(3) on linux, but more general. * * Results: * On success, the number of directory entries found. * On failure, negative error. * * Side effects: * Memory allocation. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformScanvdir(HgfsServerResEnumGetFunc enumNamesGet, // IN: Function to get name HgfsServerResEnumInitFunc enumNamesInit, // IN: Setup function HgfsServerResEnumExitFunc enumNamesExit, // IN: Cleanup function DirectorySearchType type, // IN: Kind of search - unused struct DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys uint32 *numDents) // OUT: total number of directory entrys { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; uint32 totalDents = 0; // Number of allocated dents uint32 myNumDents = 0; // Current actual number of dents DirectoryEntry **myDents = NULL; // So realloc is happy w/ zero myNumDents void *enumNamesHandle; ASSERT(NULL != enumNamesInit); ASSERT(NULL != enumNamesGet); ASSERT(NULL != enumNamesExit); enumNamesHandle = enumNamesInit(); if (NULL == enumNamesHandle) { status = HGFS_ERROR_NOT_ENOUGH_MEMORY; LOG(4, "%s: Error: init state ret %u\n", __FUNCTION__, status); goto exit; } for (;;) { DirectoryEntry *currentEntry; char const *currentEntryName; size_t currentEntryNameLen; size_t currentEntryLen; size_t maxNameLen; Bool done = FALSE; /* Add '.' and ".." as the first dents. */ if (myNumDents == 0) { currentEntryName = "."; currentEntryNameLen = 1; } else if (myNumDents == 1) { currentEntryName = ".."; currentEntryNameLen = 2; } else { if (!enumNamesGet(enumNamesHandle, ¤tEntryName, ¤tEntryNameLen, &done)) { status = HGFS_ERROR_INVALID_PARAMETER; LOG(4, "%s: Error: get next entry name ret %u\n", __FUNCTION__, status); goto exit; } } if (done) { LOG(4, "%s: No more names\n", __FUNCTION__); break; } #if defined(sun) /* * Solaris lacks a single definition of NAME_MAX and using pathconf(), to * determine NAME_MAX for the current directory, is too cumbersome for * our purposes, so we use PATH_MAX as a reasonable upper bound on the * length of the name. */ maxNameLen = PATH_MAX; #else maxNameLen = sizeof currentEntry->d_name; #endif if (currentEntryNameLen >= maxNameLen) { Log("%s: Error: Name \"%s\" is too long.\n", __FUNCTION__, currentEntryName); continue; } /* See if we need to allocate more memory */ if (myNumDents == totalDents) { void *p; if (totalDents != 0) { totalDents *= 2; } else { totalDents = 100; } p = realloc(myDents, totalDents * sizeof *myDents); if (NULL == p) { status = HGFS_ERROR_NOT_ENOUGH_MEMORY; LOG(4, "%s: Error: realloc growing array memory ret %u\n", __FUNCTION__, status); goto exit; } myDents = p; } /* This file/directory can be added to the list. */ LOG(4, "%s: Nextfilename = \"%s\"\n", __FUNCTION__, currentEntryName); /* * Start with the size of the DirectoryEntry struct, subtract the static * length of the d_name buffer (256 in Linux, 1 in Solaris, etc) and add * back just enough space for the UTF-8 name and nul terminator. */ currentEntryLen = offsetof(DirectoryEntry, d_name) + currentEntryNameLen + 1; currentEntry = malloc(currentEntryLen); if (NULL == currentEntry) { status = HGFS_ERROR_NOT_ENOUGH_MEMORY; LOG(4, "%s: Error: allocate dentry memory ret %u\n", __FUNCTION__, status); goto exit; } currentEntry->d_reclen = (unsigned short)currentEntryLen; memcpy(currentEntry->d_name, currentEntryName, currentEntryNameLen); currentEntry->d_name[currentEntryNameLen] = 0; myDents[myNumDents] = currentEntry; myNumDents++; } /* Trim extra memory off of dents */ { void *p; p = realloc(myDents, myNumDents * sizeof *myDents); if (NULL != p) { myDents = p; } else { LOG(4, "%s: Error: realloc trimming array memory\n", __FUNCTION__); } } *dents = myDents; *numDents = myNumDents; exit: if (NULL != enumNamesHandle) { /* Call the exit callback to teardown any state. */ if (!enumNamesExit(enumNamesHandle)) { LOG(4, "%s: Error cleanup failed\n", __FUNCTION__); } } if (HGFS_ERROR_SUCCESS != status) { unsigned int i; /* Free whatever has been allocated so far */ for (i = 0; i < myNumDents; i++) { free(myDents[i]); } free(myDents); } return status; } /* *---------------------------------------------------------------------- * * Request Handler Functions * ------------------------- * * The functions that follow are all of the same type: they take a * request packet which came from the driver, process it, and fill out * a reply packet which is then sent back to the driver. They are * called by DispatchPacket, which dispatches an incoming packet to * the correct handler function based on the packet's opcode. * * These functions all take the following as input: * * - A pointer to a buffer containing the incoming request packet, * - A pointer to a buffer big enough to hold the outgoing reply packet, * - A pointer to the size of the incoming packet, packetSize. * * After processing the request, the handler functions write the reply * packet into the output buffer and set the packetSize to be the size * of the OUTGOING reply packet. The ServerLoop function uses the size * to send the reply back to the driver. * * Note that it is potentially okay for the caller to use the same * buffer for both input and output; handler functions should make * sure they are safe w.r.t. this possibility by storing any state * from the input buffer before they clobber it by potentially writing * output into the same buffer. * * Handler functions should return zero if they successfully processed * the request, or a negative error if an unrecoverable error * occurred. Normal errors (e.g. a poorly formed request packet) * should be handled by sending an error packet back to the driver, * NOT by returning an error code to the caller, because errors * returned by handler functions cause the server to terminate. * * [bac] * *---------------------------------------------------------------------- */ /* *----------------------------------------------------------------------------- * * HgfsPlatformReadFile -- * * Reads data from a file. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformReadFile(fileDesc file, // IN: file descriptor HgfsSessionInfo *session, // IN: session info uint64 offset, // IN: file offset to read from uint32 requiredSize, // IN: length of data to read void* payload, // OUT: buffer for the read data uint32 *actualSize) // OUT: actual length read { int error; HgfsInternalStatus status = 0; HgfsHandle handle; Bool sequentialOpen; ASSERT(session); LOG(4, "%s: read fh %u, offset %"FMT64"u, count %u\n", __FUNCTION__, file, offset, requiredSize); if (!HgfsFileDesc2Handle(file, session, &handle)) { LOG(4, "%s: Could not get file handle\n", __FUNCTION__); return EBADF; } if (!HgfsHandleIsSequentialOpen(handle, session, &sequentialOpen)) { LOG(4, "%s: Could not get sequenial open status\n", __FUNCTION__); return EBADF; } #if defined(__linux__) || defined(__APPLE__) /* Read from the file. */ if (sequentialOpen) { error = read(file, payload, requiredSize); } else { error = pread(file, payload, requiredSize, offset); } #else /* * Seek to the offset and read from the file. Grab the IO lock to make * this and the subsequent read atomic. */ MXUser_AcquireExclLock(session->fileIOLock); if (sequentialOpen) { error = 0; // No error from seek } else { # ifdef __linux__ { uint64 res; # if !defined(VM_X86_64) error = _llseek(file, offset >> 32, offset & 0xFFFFFFFF, &res, 0); # else error = llseek(file, offset >> 32, offset & 0xFFFFFFFF, &res, 0); # endif } # else error = lseek(file, offset, 0); # endif } if (error >= 0) { error = read(file, payload, requiredSize); } else { LOG(4, "%s: could not seek to %"FMT64"u: %s\n", __FUNCTION__, offset, Err_Errno2String(status)); } MXUser_ReleaseExclLock(session->fileIOLock); #endif if (error < 0) { status = errno; LOG(4, "%s: error reading from file: %s\n", __FUNCTION__, Err_Errno2String(status)); } else { LOG(4, "%s: read %d bytes\n", __FUNCTION__, error); *actualSize = error; } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformWriteFile -- * * Performs actual writing data to a file. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformWriteFile(fileDesc writeFd, // IN: file descriptor HgfsSessionInfo *session, // IN: session info uint64 writeOffset, // IN: file offset to write to uint32 writeDataSize, // IN: length of data to write HgfsWriteFlags writeFlags, // IN: write flags Bool writeSequential, // IN: write is sequential Bool writeAppend, // IN: write is appended const void *writeData, // IN: data to be written uint32 *writtenSize) // OUT: actual length written { HgfsInternalStatus status = 0; int error = 0; LOG(4, "%s: write fh %u offset %"FMT64"u, count %u\n", __FUNCTION__, writeFd, writeOffset, writeDataSize); #if !defined(sun) if (!writeSequential) { status = HgfsWriteCheckIORange(writeOffset, writeDataSize); if (status != 0) { return status; } } #endif #if defined(__linux__) /* Write to the file. */ if (writeSequential) { error = write(writeFd, writeData, writeDataSize); } else { error = pwrite(writeFd, writeData, writeDataSize, writeOffset); } #elif defined(__APPLE__) { /* Write to the file. */ if (writeSequential || writeAppend) { error = write(writeFd, writeData, writeDataSize); } else { error = pwrite(writeFd, writeData, writeDataSize, writeOffset); } } #else /* * Seek to the offset and write from the file. Grab the IO lock to make * this and the subsequent write atomic. */ MXUser_AcquireExclLock(session->fileIOLock); if (!writeSequential) { # ifdef __linux__ { uint64 res; # if !defined(VM_X86_64) error = _llseek(writeFd, writeOffset >> 32, writeOffset & 0xFFFFFFFF, &res, 0); # else error = llseek(writeFd, writeOffset >> 32, writeOffset & 0xFFFFFFFF, &res, 0); # endif } # else error = lseek(writeFd, writeOffset, 0); # endif } if (error < 0) { LOG(4, "%s: could not seek to %"FMT64"u: %s\n", __FUNCTION__, writeOffset, Err_Errno2String(errno)); } else { error = write(writeFd, writeData, writeDataSize); } { int savedErr = errno; MXUser_ReleaseExclLock(session->fileIOLock); errno = savedErr; } #endif if (error < 0) { status = errno; LOG(4, "%s: error writing to file: %s\n", __FUNCTION__, Err_Errno2String(status)); } else { *writtenSize = error; LOG(4, "%s: wrote %d bytes\n", __FUNCTION__, *writtenSize); } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformSearchDir -- * * Handle platform specific logic needed to perform search open request. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformSearchDir(HgfsNameStatus nameStatus, // IN: name status const char *dirName, // IN: relative directory name size_t dirNameLength, // IN: length of dirName uint32 caseFlags, // IN: case flags HgfsShareInfo *shareInfo, // IN: sharfed folder information char *baseDir, // IN: name of the shared directory uint32 baseDirLen, // IN: length of the baseDir HgfsSessionInfo *session, // IN: session info HgfsHandle *handle) // OUT: search handle { HgfsInternalStatus status = 0; switch (nameStatus) { case HGFS_NAME_STATUS_COMPLETE: { const char *inEnd; const char *next; int len; ASSERT(baseDir); LOG(4, "%s: searching in \"%s\", %s.\n", __FUNCTION__, baseDir, dirName); inEnd = dirName + dirNameLength; /* Get the first component. */ len = CPName_GetComponent(dirName, inEnd, &next); if (len >= 0) { if (*inEnd != '\0') { LOG(4, "%s: dir name not nul-terminated!\n", __FUNCTION__); /* * NT4 clients can send the name without a nul-terminator. * The space for the nul is included and tested for in the size * calculations above. Size of structure (includes a single * character of the name) and the full dirname length. */ *(char *)inEnd = '\0'; } LOG(4, "%s: dirName: %s.\n", __FUNCTION__, dirName); status = HgfsServerSearchRealDir(baseDir, baseDirLen, dirName, shareInfo->rootDir, session, handle); } else { LOG(4, "%s: get first component failed\n", __FUNCTION__); status = ENOENT; } /* * If the directory exists but shared folder is write only * then return access denied, otherwise preserve the original * error code. */ if (!shareInfo->readPermissions && HGFS_NAME_STATUS_COMPLETE == status) { status = HGFS_NAME_STATUS_ACCESS_DENIED; } if (status != 0) { LOG(4, "%s: couldn't scandir\n", __FUNCTION__); } break; } case HGFS_NAME_STATUS_INCOMPLETE_BASE: /* * This is the base of our namespace, so enumerate all * shares. [bac] */ LOG(4, "%s: opened search on base\n", __FUNCTION__); status = HgfsServerSearchVirtualDir(HgfsServerResEnumGet, HgfsServerResEnumInit, HgfsServerResEnumExit, DIRECTORY_SEARCH_TYPE_BASE, session, handle); if (status != 0) { LOG(4, "%s: couldn't enumerate shares\n", __FUNCTION__); } break; default: LOG(4, "%s: access check failed\n", __FUNCTION__); status = HgfsPlatformConvertFromNameStatus(nameStatus); } if (status == 0) { HGFS_SERVER_DIR_DUMP_DENTS(*handle, session); } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformRestartSearchDir -- * * Handle platform specific restarting of a directory search. * * Results: * HGFS_ERROR_SUCCESS or an appropriate error code. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformRestartSearchDir(HgfsHandle handle, // IN: search handle HgfsSessionInfo *session, // IN: session info DirectorySearchType searchType) // IN: Kind of search { HgfsInternalStatus status; switch (searchType) { case DIRECTORY_SEARCH_TYPE_BASE: /* Entries are shares */ status = HgfsServerRestartSearchVirtualDir(HgfsServerResEnumGet, HgfsServerResEnumInit, HgfsServerResEnumExit, session, handle); break; case DIRECTORY_SEARCH_TYPE_OTHER: /* Entries of this type are unknown and not supported for this platform. */ case DIRECTORY_SEARCH_TYPE_DIR: /* Entries are files and subdirectories: currently not implemented! */ default: status = EINVAL; break; } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformHandleIncompleteName -- * * Returns platform error that matches HgfsNameStatus. * * Results: * Non-zero error code. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformHandleIncompleteName(HgfsNameStatus nameStatus, // IN: name status HgfsFileAttrInfo *attr) // OUT: unused { return HgfsPlatformConvertFromNameStatus(nameStatus); } /* *----------------------------------------------------------------------------- * * HgfsPlatformDeleteFileByName -- * * POSIX specific implementation of a delete file request which accepts * utf8 file path as a parameter. * * Simply calls Posix_Unlink. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformDeleteFileByName(char const *utf8Name) // IN: full file path in uf8 encoding { HgfsInternalStatus status; LOG(4, "%s: unlinking \"%s\"\n", __FUNCTION__, utf8Name); status = Posix_Unlink(utf8Name); if (status) { status = errno; LOG(4, "%s: error: %s\n", __FUNCTION__, Err_Errno2String(status)); } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformDeleteFileByHandle -- * * POSIX specific implementation of a delete file request which accepts * HgfsHandle as a parameter. * * File handle must have appropriate access mode to allow file deletion. * Shared folder restrictions are enforced here as well. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformDeleteFileByHandle(HgfsHandle file, // IN: File being deleted HgfsSessionInfo *session) // IN: session info { HgfsInternalStatus status; Bool readPermissions; Bool writePermissions; char *localName; size_t localNameSize; if (HgfsHandle2FileNameMode(file, session, &readPermissions, &writePermissions, &localName, &localNameSize)) { if (writePermissions && readPermissions) { status = HgfsPlatformDeleteFileByName(localName); } else { status = EPERM; } free(localName); } else { LOG(4, "%s: could not map cached file handle %u\n", __FUNCTION__, file); status = EBADF; } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformDeleteDirByName -- * * POSIX specific implementation of a delete directory request which accepts * utf8 file path as a parameter. * * Simply calls Posix_Rmdir. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformDeleteDirByName(char const *utf8Name) // IN: full file path in uf8 encoding { HgfsInternalStatus status; LOG(4, "%s: removing \"%s\"\n", __FUNCTION__, utf8Name); status = Posix_Rmdir(utf8Name); if (status) { status = errno; LOG(4, "%s: error: %s\n", __FUNCTION__, Err_Errno2String(status)); } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformDeleteDirByHandle -- * * POSIX specific implementation of a Delete directory request which accepts * HgfsHandle as a parameter. * * File handle must have appropriate access mode to allow file deletion. * Shared folder restrictions are enforced here as well. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformDeleteDirByHandle(HgfsHandle file, // IN: File being deleted HgfsSessionInfo *session) // IN: session info { HgfsInternalStatus status; Bool readPermissions; Bool writePermissions; char *localName; size_t localNameSize; if (HgfsHandle2FileNameMode(file, session, &readPermissions, &writePermissions, &localName, &localNameSize)) { if (writePermissions && readPermissions) { status = HgfsPlatformDeleteDirByName(localName); } else { status = EPERM; } free(localName); } else { LOG(4, "%s: could not map cached file handle %u\n", __FUNCTION__, file); status = EBADF; } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformFileExists -- * * Platform specific function that that verifies if a file or directory exists. * * Results: * 0 if user has permissions to traverse the parent directory and * the file exists, POSIX error code otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformFileExists(char *localTargetName) // IN: Full file path utf8 encoding { int err; err = Posix_Access(localTargetName, F_OK); if (-1 == err) { err = errno; } return err; } /* *----------------------------------------------------------------------------- * * HgfsPlatformRename -- * * POSIX version of the function that renames a file or directory. * * Results: * 0 on success, POSIX error code otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformRename(char *localSrcName, // IN: local path to source file fileDesc srcFile, // IN: source file handle char *localTargetName, // IN: local path to target file fileDesc targetFile, // IN: target file handle HgfsRenameHint hints) // IN: rename hints { HgfsInternalStatus status = 0; if (hints & HGFS_RENAME_HINT_NO_REPLACE_EXISTING) { if (0 == HgfsPlatformFileExists(localTargetName)) { status = EEXIST; goto exit; } } LOG(4, "%s: renaming \"%s\" to \"%s\"\n", __FUNCTION__, localSrcName, localTargetName); status = Posix_Rename(localSrcName, localTargetName); if (status) { status = errno; LOG(4, "%s: error: %s\n", __FUNCTION__, Err_Errno2String(status)); } exit: return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformCreateDir -- * * POSIX specific code that implements create directory request. * * It invokes POSIX to create the directory and then assigns * file attributes to the new directory if attributes are specified * by the guest. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformCreateDir(HgfsCreateDirInfo *info, // IN: direcotry properties char *utf8Name) // IN: full path for the new directory { mode_t permissions; HgfsInternalStatus status; /* * Create mode_t for use in mkdir(). If owner permissions are missing, use * read/write/execute for the owner permissions. If group or other * permissions are missing, use the owner permissions. * * This sort of makes sense. If the Windows driver wants to make a dir * read-only, it probably intended for the dir to be 666. Since creating * a directory requires a valid mode, it's highly unlikely that we'll ever * be creating a directory without owner permissions. */ permissions = 0; permissions |= info->mask & HGFS_CREATE_DIR_VALID_SPECIAL_PERMS ? info->specialPerms << 9 : 0; permissions |= info->mask & HGFS_CREATE_DIR_VALID_OWNER_PERMS ? info->ownerPerms << 6 : S_IRWXU; permissions |= info->mask & HGFS_CREATE_DIR_VALID_GROUP_PERMS ? info->groupPerms << 3 : (permissions & S_IRWXU) >> 3; permissions |= info->mask & HGFS_CREATE_DIR_VALID_OTHER_PERMS ? info->otherPerms : (permissions & S_IRWXU) >> 6; LOG(4, "%s: making dir \"%s\", mode %"FMTMODE"\n", __FUNCTION__, utf8Name, permissions); status = Posix_Mkdir(utf8Name, permissions); if ((info->mask & HGFS_CREATE_DIR_VALID_FILE_ATTR) && (info->fileAttr & HGFS_ATTR_HIDDEN) && 0 == status) { /* * Set hidden attribute when requested. * Do not fail directory creation if setting hidden attribute fails. */ HgfsSetHiddenXAttr(utf8Name, TRUE, permissions); } if (status) { status = errno; LOG(4, "%s: error: %s\n", __FUNCTION__, Err_Errno2String(status)); } return status; } /* *----------------------------------------------------------------------------- * * HgfsPlatformSymlinkCreate -- * * Platform specific function that actually creates the symbolic link. * * Results: * Zero on success. * Non-zero on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsPlatformSymlinkCreate(char *localSymlinkName, // IN: symbolic link file name char *localTargetName) // IN: symlink target name { HgfsInternalStatus status = 0; int error; LOG(4, "%s: %s -> %s\n", __FUNCTION__, localSymlinkName, localTargetName); /* XXX: Should make use of targetNameP->flags? */ error = Posix_Symlink(localTargetName, localSymlinkName); if (error) { status = errno; LOG(4, "%s: error: %s\n", __FUNCTION__, Err_Errno2String(errno)); } return status; } /* *---------------------------------------------------------------------- * * HgfsPlatformPathHasSymlink -- * * This function determines if any of the intermediate components of the * fileName makes references outside the actual shared path. We do not * check for the last component as none of the server operations follow * symlinks. Also some ops that call us expect to operate on a symlink * final component. * * We use following algorithm. It takes 2 parameters, sharePath and * fileName, and returns non-zero errno if fileName makes an invalid * reference. The idea is to resolve both the sharePath and parent * directory of the fileName. The sharePath is already resolved * beforehand in HgfsServerPolicyRead. During resolution, we eliminate * all the ".", "..", and symlinks handled by the realpath(3) libc call. * * We use parent because last component could be a symlink or a component * that doesn't exist. After resolving, we determine if sharePath is a * prefix of fileName. * * Note that realpath(3) behaves differently on GNU and BSD systems. * Following table lists the difference: * * GNU realpath BSD realpath * ----------------------- ----------------------- * * "/tmp/existingFile" "/tmp/existingFile" (0) "/tmp/existingFile" (0) * "/tmp/missingFile" NULL (ENOENT) "/tmp/missingFile" (0) * "/missingDir/foo" NULL (ENOENT) NULL (ENOENT) * In /tmp, "" NULL (ENOENT) "/tmp" (0) * In /tmp, "." "/tmp" (0) "/tmp" (0) * * Results: * HGFS_NAME_STATUS_COMPLETE if the given path has a symlink, an appropriate name status error otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ HgfsNameStatus HgfsPlatformPathHasSymlink(const char *fileName, // IN size_t fileNameLength, // IN const char *sharePath, // IN size_t sharePathLength) // IN { char *resolvedFileDirPath = NULL; char *fileDirName = NULL; HgfsInternalStatus status; HgfsNameStatus nameStatus = HGFS_NAME_STATUS_COMPLETE; ASSERT(fileName); ASSERT(sharePath); ASSERT(sharePathLength <= fileNameLength); LOG(4, "%s: fileName: %s, sharePath: %s#\n", __FUNCTION__, fileName, sharePath); /* * Return success if: * - empty fileName or * - sharePath is empty (this is for special root share that allows * access to entire host) or * - fileName and sharePath are same. */ if (fileNameLength == 0 || sharePathLength == 0 || Str_Strcmp(sharePath, fileName) == 0) { goto exit; } /* Separate out parent directory of the fileName. */ File_GetPathName(fileName, &fileDirName, NULL); /* * File_GetPathName may return an empty string to signify the root of * the filesystem. To simplify subsequent processing, let's convert such * empty strings to "/" when found. See File_GetPathName header comment * for details. */ if (strlen(fileDirName) == 0) { char *p; p = realloc(fileDirName, sizeof (DIRSEPS)); if (p == NULL) { nameStatus = HGFS_NAME_STATUS_OUT_OF_MEMORY; LOG(4, "%s: failed to realloc fileDirName.\n", __FUNCTION__); goto exit; } else { fileDirName = p; Str_Strcpy(fileDirName, DIRSEPS, sizeof (DIRSEPS)); } } /* * Resolve parent directory of fileName. * Use realpath(2) to resolve the parent. */ resolvedFileDirPath = Posix_RealPath(fileDirName); if (resolvedFileDirPath == NULL) { /* Let's return some meaningful errors if possible. */ status = errno; switch (status) { case ENOENT: nameStatus = HGFS_NAME_STATUS_DOES_NOT_EXIST; break; case ENOTDIR: nameStatus = HGFS_NAME_STATUS_NOT_A_DIRECTORY; break; default: nameStatus = HGFS_NAME_STATUS_FAILURE; break; } LOG(4, "%s: realpath failed: fileDirName: %s: %s\n", __FUNCTION__, fileDirName, Err_Errno2String(errno)); goto exit; } /* Resolved parent should match with the shareName. */ if (Str_Strncmp(sharePath, resolvedFileDirPath, sharePathLength) != 0) { nameStatus = HGFS_NAME_STATUS_ACCESS_DENIED; LOG(4, "%s: resolved parent do not match, parent: %s, resolved: %s#\n", __FUNCTION__, fileDirName, resolvedFileDirPath); goto exit; } exit: free(resolvedFileDirPath); free(fileDirName); return nameStatus; } /* *----------------------------------------------------------------------------- * * HgfsServerWriteWin32Stream -- * * Handle a write request in the WIN32_STREAM_ID format. * * Results: * EOPNOTSUPP, because this is unimplemented. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet HgfsOp op, // IN: request type const void *payload, // IN: HGFS operational packet (without header) size_t payloadSize, // IN: size of HGFS operational packet HgfsSessionInfo *session) // IN: session info { return EOPNOTSUPP; } #if defined(__APPLE__) /* *----------------------------------------------------------------------------- * * HgfsGetHiddenXattr -- * * For Mac hosts returns true if file has invisible bit set in the FileFinder * extended attributes. * * Results: * 0 if succeeded getting attribute, error code otherwise otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsGetHiddenXAttr(char const *fileName, // IN: File name Bool *attribute) // OUT: Hidden atribute { struct attrlist attrList; struct FInfoAttrBuf attrBuf; HgfsInternalStatus err; ASSERT(fileName); ASSERT(attribute); memset(&attrList, 0, sizeof attrList); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_OBJTYPE | ATTR_CMN_FNDRINFO; err = getattrlist(fileName, &attrList, &attrBuf, sizeof attrBuf, 0); if (err == 0) { switch (attrBuf.objType) { case VREG: { FileInfo *info = (FileInfo*) attrBuf.finderInfo; uint16 finderFlags = CFSwapInt16BigToHost(info->finderFlags); *attribute = (finderFlags & kIsInvisible) != 0; break; } case VDIR: { FolderInfo *info = (FolderInfo*) attrBuf.finderInfo; uint16 finderFlags = CFSwapInt16BigToHost(info->finderFlags); *attribute = (finderFlags & kIsInvisible) != 0; break; } default: LOG(4, "%s: Unrecognized object type %d\n", __FUNCTION__, attrBuf.objType); err = EINVAL; } } else { LOG(4, "%s: Error %d when getting attributes\n", __FUNCTION__, err); } return err; } /* *----------------------------------------------------------------------------- * * ChangeInvisibleFlag -- * * Changes value of the invisible bit in a flags variable to a value defined * by setHidden parameter. * * Results: * TRUE flag has been changed, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool ChangeInvisibleFlag(uint16 *flags, // IN/OUT: variable that contains flags Bool setHidden) // IN: new value for the invisible flag { Bool changed = FALSE; /* * Finder keeps, reports and expects to set flags in big endian format. * Needs to convert to host endian before using constants * and then convert back to big endian before saving */ uint16 finderFlags = CFSwapInt16BigToHost(*flags); Bool isHidden = (finderFlags & kIsInvisible) != 0; if (setHidden) { if (!isHidden) { finderFlags |= kIsInvisible; changed = TRUE; } } else if (isHidden) { finderFlags &= ~kIsInvisible; changed = TRUE; } if (changed) { *flags = CFSwapInt16HostToBig(finderFlags); } return changed; } /* *----------------------------------------------------------------------------- * * HgfsSetHiddenXAttr -- * * Sets new value for the invisible attribute of a file. * * Results: * 0 if succeeded, error code otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsSetHiddenXAttr(char const *fileName, // IN: path to the file Bool setHidden, // IN: new value to the invisible attribute mode_t permissions) // IN: permissions of the file { HgfsInternalStatus err; Bool changed = FALSE; struct attrlist attrList; struct FInfoAttrBuf attrBuf; ASSERT(fileName); memset(&attrList, 0, sizeof attrList); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_OBJTYPE | ATTR_CMN_FNDRINFO; err = getattrlist(fileName, &attrList, &attrBuf, sizeof attrBuf, 0); if (err == 0) { switch (attrBuf.objType) { case VREG: { FileInfo *info = (FileInfo*) attrBuf.finderInfo; changed = ChangeInvisibleFlag(&info->finderFlags, setHidden); break; } case VDIR: { FolderInfo *info = (FolderInfo*) attrBuf.finderInfo; changed = ChangeInvisibleFlag(&info->finderFlags, setHidden); break; } default: LOG(4, "%s: Unrecognized object type %d\n", __FUNCTION__, attrBuf.objType); err = EINVAL; } } else { err = errno; } if (changed) { attrList.commonattr = ATTR_CMN_FNDRINFO; err = setattrlist(fileName, &attrList, attrBuf.finderInfo, sizeof attrBuf.finderInfo, 0); if (0 != err) { err = errno; } if (EACCES == err) { mode_t mode = permissions | S_IWOTH | S_IWGRP | S_IWUSR; if (chmod(fileName, mode) == 0) { err = setattrlist(fileName, &attrList, attrBuf.finderInfo, sizeof attrBuf.finderInfo, 0); if (0 != err) { err = errno; } chmod(fileName, permissions); } else { err = errno; } } } return err; } #else // __APPLE__ /* *----------------------------------------------------------------------------- * * HgfsGetHiddenXAttr -- * * Always returns 0 since there is no support for invisible files in Linux * HGFS server. * * Results: * 0 always. This is required to allow apps that use the hidden feature to * continue to work. attribute value is set to FALSE always. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsGetHiddenXAttr(char const *fileName, // IN: File name Bool *attribute) // OUT: Value of the hidden attribute { *attribute = FALSE; return 0; } /* *----------------------------------------------------------------------------- * * HgfsSetHiddenXAttr -- * * Sets new value for the invisible attribute of a file. * Currently Linux server does not support invisible or hiddden files. * So this is a nop. * * Results: * 0 always. This is required to allow apps that use the hidden feature to * continue to work. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsSetHiddenXAttr(char const *fileName, // IN: File name Bool value, // IN: Value of the attribute to set mode_t permissions) // IN: permissions of the file { return 0; } #endif // __APPLE__ #if !defined(sun) /* *----------------------------------------------------------------------------- * * HgfsWriteCheckIORange -- * * Verifies that the write arguments do not exceed the maxiuum file size. * * Results: * 0 on success, otherwise an appropriate error. * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsWriteCheckIORange(off_t offset, // IN: uint32 bytesToWrite) // IN: { HgfsInternalStatus status = 0; struct rlimit fileSize; if (getrlimit(RLIMIT_FSIZE, &fileSize) < 0) { status = errno; LOG(4, "%s: Could not get file size limit\n", __FUNCTION__); goto exit; } LOG(6, "%s: File Size limits: 0x%"FMT64"x 0x%"FMT64"x\n", __FUNCTION__, fileSize.rlim_cur, fileSize.rlim_max); /* * Check the offset is within the file size range. */ if (fileSize.rlim_cur < offset) { status = EFBIG; LOG(4, "%s: Write offset exceeds max file size limit - 0x%"FMT64"x\n", __FUNCTION__, offset); goto exit; } /* * Check the data to write does not exceed the max file size. */ if (fileSize.rlim_cur - offset < bytesToWrite) { status = EFBIG; LOG(4, "%s: Write data 0x%x bytes @ 0x%"FMT64"x size exceeds max file size\n", __FUNCTION__, bytesToWrite, offset); goto exit; } exit: LOG(6, "%s: Write data 0x%x bytes @ 0x%"FMT64"x returns %d\n", __FUNCTION__, bytesToWrite, offset, status); return status; } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerOplock.c000066400000000000000000000250561470176644300266470ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2012-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerOplock.c -- * * HGFS server opportunistic lock support that is common to all platforms. */ #if defined(__APPLE__) #define _DARWIN_USE_64_BIT_INODE #endif #include #include #include "vmware.h" #include "str.h" #include "cpName.h" #include "cpNameLite.h" #include "hgfsServerInt.h" #include "hgfsServerOplockInt.h" /* * Local data */ /* Indicates if the oplock module is initialized. */ static Bool gOplockInit = FALSE; /* * Global data */ /* * Local functions */ /* *----------------------------------------------------------------------------- * * HgfsServerOplockInit -- * * Set up any oplock related state used for HGFS server. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsServerOplockInit(void) { if (gOplockInit) { return TRUE; } gOplockInit = HgfsPlatformOplockInit(); return gOplockInit; } /* *----------------------------------------------------------------------------- * * HgfsServerOplockDestroy -- * * Tear down any oplock related state used for HGFS server. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsServerOplockDestroy(void) { if (!gOplockInit) { return; } /* Tear down oplock state, so we no longer catch signals. */ HgfsPlatformOplockDestroy(); gOplockInit = FALSE; } /* *----------------------------------------------------------------------------- * * HgfsServerOplockIsInited -- * * Check if the oplock related state is set up. * * Results: * TRUE if the oplock related state is set up. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsServerOplockIsInited(void) { return gOplockInit; } /* *----------------------------------------------------------------------------- * * HgfsHandle2ServerLock -- * * Retrieve the serverlock information for the file node that corresponds to * the specified hgfs handle. If the server is not compiled with oplock * support, we always return TRUE and HGFS_LOCK_NONE. * * Results: * TRUE if the hgfs handle is valid and the lock was retrieved successfully. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsHandle2ServerLock(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info HgfsLockType *lock) // OUT: Server lock { #ifdef HGFS_OPLOCKS Bool found = FALSE; HgfsFileNode *fileNode; ASSERT(lock); MXUser_AcquireExclLock(session->nodeArrayLock); fileNode = HgfsHandle2FileNode(handle, session); if (fileNode == NULL) { goto exit; } *lock = fileNode->serverLock; found = TRUE; exit: MXUser_ReleaseExclLock(session->nodeArrayLock); return found; #else *lock = HGFS_LOCK_NONE; return TRUE; #endif } /* *----------------------------------------------------------------------------- * * HgfsFileHasServerLock -- * * Check if the file with the given name is already opened with a server * lock on it. If the server is compiled without oplock support, we always * return FALSE. * * Results: * TRUE if the node was found and has an oplock. * FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsFileHasServerLock(const char *utf8Name, // IN: Name in UTF8 HgfsSessionInfo *session, // IN: Session info HgfsLockType *serverLock, // OUT: Existing oplock fileDesc *fileDesc) // OUT: Existing fd { #ifdef HGFS_OPLOCKS unsigned int i; Bool found = FALSE; ASSERT(utf8Name); ASSERT(session); ASSERT(session->nodeArray); MXUser_AcquireExclLock(session->nodeArrayLock); for (i = 0; i < session->numNodes; i++) { HgfsFileNode *existingFileNode = &session->nodeArray[i]; if ((existingFileNode->state == FILENODE_STATE_IN_USE_CACHED) && (existingFileNode->serverLock != HGFS_LOCK_NONE) && (!stricmp(existingFileNode->utf8Name, utf8Name))) { LOG(4, "Found file with a lock: %s\n", utf8Name); *serverLock = existingFileNode->serverLock; *fileDesc = existingFileNode->fileDesc; found = TRUE; break; } } MXUser_ReleaseExclLock(session->nodeArrayLock); return found; #else return FALSE; #endif } #ifdef HGFS_OPLOCKS /* *----------------------------------------------------------------------------- * * HgfsServerOplockBreakReply -- * * The client was sent an oplock break request, and responded with this * reply. It contains the oplock status that the client is now in. Since * the break could have actually been a degrade, it is well within the * client's rights to transition to a non-broken state. We need to make * sure that such a transition was legal, acknowledge the brea * appropriately, and update our own state. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsServerOplockBreakReply(const unsigned char *packetIn, // IN: Reply packet unsigned int packetSize, // IN: Size of packet void *clientData) // IN: From request { HgfsReplyServerLockChange *reply; ServerLockData *lockData = clientData; ASSERT(packetIn); ASSERT(clientData); if (packetSize < sizeof *reply) { return; } reply = (HgfsReplyServerLockChange *)packetIn; /* * XXX: It should be safe to ignore the status and id from the actual * HgfsReply. The only information we need to properly acknowledge the break * is the original fd and the new lease, which, in the case of a degrade, * is double checked in HgfsAckOplockBreak, so we'd be safe from a garbage * value. */ HgfsAckOplockBreak(lockData, reply->serverLock); } /* *----------------------------------------------------------------------------- * * HgfsServerOplockBreak -- * * When the host FS needs to break the oplock so that another client * can open the file, it signals the event in the overlapped structure * that we used to request an oplock. * This sets off the following chains of events: * 1. Send the oplock break request to the guest. * 2. Once the guest acknowledges the oplock break, the completion * routine GuestRpcServerRequestCallback will fire, causing * HgfsServerOplockBreakReply to also fire, which will break the oplock * on the host FS. * * Results: * None. * * Side effects: * If successful, allocates memory for the rpc request. * *----------------------------------------------------------------------------- */ void HgfsServerOplockBreak(ServerLockData *lockData) { HgfsHandle hgfsHandle; char *requestBuffer = NULL; HgfsRequestServerLockChange *request; HgfsLockType lock; LOG(4, "%s: entered\n", __FUNCTION__); /* * XXX: Just because the file in not in the cache on the server, * does not mean it was closed on the client. It is possible that * we closed the file on the server because we ran out of space * in cache. That's why for now as long as a file has a lock, * we don't remove it from the node cache. This should be fixed. * * In any case, none of these cache-related failures should cause us to ack * the oplock break locally. That is because if the file wasn't in the * cache, or it had no lock, chances are someone else (maybe the VCPU * thread) broke the oplock and/or closed the file. */ if (!HgfsFileDesc2Handle(lockData->fileDesc, &hgfsHandle)) { LOG(4, "%s: file is not in the cache\n", __FUNCTION__); goto free_and_exit; } if (!HgfsHandle2ServerLock(hgfsHandle, &lock)) { LOG(4, "%s: could not retrieve node's lock info.\n", __FUNCTION__); goto free_and_exit; } if (lock == HGFS_LOCK_NONE) { LOG(4, "%s: the file does not have a server lock.\n", __FUNCTION__); goto free_and_exit; } /* * We need to setup the entire request here. The command prefix will be * added later, so save some space for it. * * XXX: This should probably go into a common allocation function that * other out-of-band requests can use. */ requestBuffer = malloc(sizeof *request + HGFS_CLIENT_CMD_LEN); if (requestBuffer == NULL) { LOG(4, "%s: could not allocate memory.\n", __FUNCTION__); goto ack_and_exit; } /* Save space for the command prefix. */ request = (HgfsRequestServerLockChange *) (requestBuffer + HGFS_CLIENT_CMD_LEN); request->header.op = HGFS_OP_SERVER_LOCK_CHANGE; request->header.id = 0; /* XXX */ request->file = hgfsHandle; request->newServerLock = lockData->serverLock; /* * Just send the request size for our actual request; our callee will * write in the command prefix and modify the request size appropriately. * * If for some reason we fail, we'll acknowledge the oplock break * immediately. */ if (HgfsServerManager_SendRequest(requestBuffer, sizeof *request, HgfsServerOplockBreakReply, lockData)) { return; } free(requestBuffer); ack_and_exit: HgfsAckOplockBreak(lockData, HGFS_LOCK_NONE); return; free_and_exit: free(lockData); } #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerOplock.h000066400000000000000000000035561470176644300266550ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2013-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerOplock.h -- * * Header file for public common data types used in the HGFS * opportunistic lock routines. */ #ifndef _HGFS_SERVER_OPLOCK_H_ #define _HGFS_SERVER_OPLOCK_H_ #include "hgfsProto.h" // for protocol types #include "hgfsServerInt.h" // for common server types e.g. HgfsSessionInfo /* * Data structures */ /* * Global variables */ /* * Global functions */ Bool HgfsServerOplockInit(void); void HgfsServerOplockDestroy(void); Bool HgfsHandle2ServerLock(HgfsHandle handle, HgfsSessionInfo *session, HgfsLockType *lock); Bool HgfsFileHasServerLock(const char *utf8Name, HgfsSessionInfo *session, HgfsLockType *serverLock, fileDesc *fileDesc); Bool HgfsAcquireServerLock(fileDesc fileDesc, HgfsSessionInfo *session, HgfsLockType *serverLock); #endif // ifndef _HGFS_SERVER_OPLOCK_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerOplockInt.h000066400000000000000000000053351470176644300273250ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2013-2016,2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerOplock.h -- * * Header file for private common data types used in the HGFS * opportunistic lock routines. */ #ifndef _HGFS_SERVER_OPLOCKINT_H_ #define _HGFS_SERVER_OPLOCKINT_H_ #ifdef _WIN32 #include // for REQUEST_OPLOCK_OUTPUT_BUFFER #endif #include "hgfsProto.h" // for protocol types #include "hgfsServerInt.h" // for common server types e.g. HgfsSessionInfo /* * Does this platform have oplock support? We define it here to avoid long * ifdefs all over the code. For now, Linux and Windows hosts only. * * XXX: Just kidding, no oplock support yet. */ #if 0 #define HGFS_OPLOCKS #endif /* * XXX describe the data structure */ typedef void(*HgfsOplockCallback)(HgfsSessionInfo *session, void *data); /* Server lock related structure */ typedef struct { fileDesc fileDesc; HgfsSessionInfo *session; HgfsLockType serverLock; HgfsOplockCallback callback; void *data; #ifdef _WIN32 REQUEST_OPLOCK_OUTPUT_BUFFER oplockInfo; OVERLAPPED overlapped; #endif } ServerLockData; /* * Global variables */ /* * The maximum count of oplocks that the server supports. * This value can be adjusted as necessary, but must be a power of 2. */ #define HGFS_OPLOCK_MAX_COUNT 1024 /* * Global functions */ Bool HgfsServerOplockIsInited(void); Bool HgfsPlatformOplockInit(void); void HgfsPlatformOplockDestroy(void); Bool HgfsAcquireAIOServerLock(fileDesc fileDesc, HgfsSessionInfo *session, HgfsLockType *serverLock, HgfsOplockCallback callback, void *data); void HgfsRemoveAIOServerLock(fileDesc fileDesc); #ifdef HGFS_OPLOCKS void HgfsServerOplockBreak(ServerLockData *data); void HgfsAckOplockBreak(ServerLockData *lockData, HgfsLockType replyLock); #endif #endif // ifndef _HGFS_SERVER_OPLOCKINT_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerOplockLinux.c000066400000000000000000000273171470176644300276710ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2012-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerOplockLinux.c -- * * HGFS server opportunistic lock support for the Linux platform. */ #include #include #include #include #include "vmware.h" #include "err.h" #include "hgfsServerInt.h" #include "hgfsServerOplockInt.h" #ifdef HGFS_OPLOCKS # include # include "sig.h" #endif /* * Local data */ /* * Global data */ /* * Local functions */ #ifdef HGFS_OPLOCKS static void HgfsServerSigOplockBreak(int sigNum, siginfo_t *info, ucontext_t *u, void *clientData); #endif /* *----------------------------------------------------------------------------- * * HgfsPlatformOplockInit -- * * Set up any state needed to start Linux HGFS server oplock support. * * Results: * TRUE always. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsPlatformOplockInit(void) { #ifdef HGFS_OPLOCKS /* Register a signal handler to catch oplock break signals. */ Sig_Callback(SIGIO, SIG_SAFE, HgfsServerSigOplockBreak, NULL); #endif return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPlatformOplockDestroy -- * * Tear down any state used for Linux HGFS server. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsPlatformOplockDestroy(void) { #ifdef HGFS_OPLOCKS /* Tear down oplock state, so we no longer catch signals. */ Sig_Callback(SIGIO, SIG_NOHANDLER, NULL, NULL); #endif } /* *----------------------------------------------------------------------------- * * HgfsRemoveAIOServerLock -- * * Remove an oplock for an open file. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsRemoveAIOServerLock(fileDesc fileDesc) // IN: { } /* *----------------------------------------------------------------------------- * * HgfsAcquireAIOServerLock -- * * Acquire an oplock for an open file and register the break oplock event. * * Results: * TRUE on success. serverLock contains the type of the lock acquired. * FALSE on failure. serverLock is HGFS_LOCK_NONE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsAcquireAIOServerLock(fileDesc fileDesc, // IN: HgfsSessionInfo *session, // IN: Session info HgfsLockType *serverLock, // IN/OUT: Oplock asked for/granted HgfsOplockCallback callback, // IN: call back void *data) // IN: parameter for call back { return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsAcquireServerLock -- * * Acquire a lease for the open file. Typically we try and get the exact * lease desired, but if the client asked for HGFS_LOCK_OPPORTUNISTIC, we'll * take the "best" lease we can get. * * Results: * TRUE on success. serverLock contains the type of the lock acquired. * FALSE on failure. serverLock is HGFS_LOCK_NONE. * * XXX: This function has the potential to return per-platform error codes, * but since it is opportunistic by nature, it isn't necessary to do so. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsAcquireServerLock(fileDesc fileDesc, // IN: OS handle HgfsSessionInfo *session, // IN: session info HgfsLockType *serverLock) // IN/OUT: Oplock asked for/granted { #ifdef HGFS_OPLOCKS HgfsLockType desiredLock; int leaseType, error; ASSERT(serverLock); ASSERT(session); desiredLock = *serverLock; if (desiredLock == HGFS_LOCK_NONE) { return TRUE; } if (!HgfsIsServerLockAllowed(session)) { return FALSE; } /* * First tell the kernel which signal to send us. SIGIO is already the * default, but if we skip this step, we won't get the siginfo_t when * a lease break occurs. * * XXX: Do I need to do fcntl(fileDesc, F_SETOWN, getpid())? */ if (fcntl(fileDesc, F_SETSIG, SIGIO)) { error = errno; Log("%s: Could not set SIGIO as the desired lease break signal for " "fd %d: %s\n", __FUNCTION__, fileDesc, Err_Errno2String(error)); return FALSE; } /* * If the client just wanted the best lock possible, start off with a write * lease and move down to a read lease if that was unavailable. */ if ((desiredLock == HGFS_LOCK_OPPORTUNISTIC) || (desiredLock == HGFS_LOCK_EXCLUSIVE)) { leaseType = F_WRLCK; } else if (desiredLock == HGFS_LOCK_SHARED) { leaseType = F_RDLCK; } else { LOG(4, "%s: Unknown server lock\n", __FUNCTION__); return FALSE; } if (fcntl(fileDesc, F_SETLEASE, leaseType)) { /* * If our client was opportunistic and we failed to get his lease because * someone else is already writing or reading to the file, try again with * a read lease. */ if (desiredLock == HGFS_LOCK_OPPORTUNISTIC && (errno == EAGAIN || errno == EACCES)) { leaseType = F_RDLCK; if (fcntl(fileDesc, F_SETLEASE, leaseType)) { error = errno; LOG(4, "%s: Could not get any opportunistic lease for fd %d: %s\n", __FUNCTION__, fileDesc, Err_Errno2String(error)); return FALSE; } } else { error = errno; LOG(4, "%s: Could not get %s lease for fd %d: %s\n", __FUNCTION__, leaseType == F_WRLCK ? "write" : "read", fileDesc, Err_Errno2String(errno)); return FALSE; } } /* Got a lease of some kind. */ LOG(4, "%s: Got %s lease for fd %d\n", __FUNCTION__, leaseType == F_WRLCK ? "write" : "read", fileDesc); *serverLock = leaseType == F_WRLCK ? HGFS_LOCK_EXCLUSIVE : HGFS_LOCK_SHARED; return TRUE; #else return FALSE; #endif } #ifdef HGFS_OPLOCKS /* *----------------------------------------------------------------------------- * * HgfsAckOplockBreak -- * * Platform-dependent implementation of oplock break acknowledgement. * This function gets called when the oplock break rpc command is completed. * The rpc oplock break command (HgfsServerOplockBreak) is in hgfsServer.c * * On Linux, we use fcntl() to downgrade the lease. Then we update the node * cache, free the clientData, and call it a day. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsAckOplockBreak(ServerLockData *lockData, // IN: server lock info HgfsLockType replyLock) // IN: client has this lock { int fileDesc, newLock; HgfsLockType actualLock; ASSERT(lockData); fileDesc = lockData->fileDesc; LOG(4, "%s: Acknowledging break on fd %d\n", __FUNCTION__, fileDesc); /* * The Linux server supports lock downgrading. We only downgrade to a shared * lock if our previous call to fcntl() said we could, and if the client * wants to downgrade to a shared lock. Otherwise, we break altogether. */ if (lockData->serverLock == HGFS_LOCK_SHARED && replyLock == HGFS_LOCK_SHARED) { newLock = F_RDLCK; actualLock = replyLock; } else { newLock = F_UNLCK; actualLock = HGFS_LOCK_NONE; } /* Downgrade or acknowledge the break altogether. */ if (fcntl(fileDesc, F_SETLEASE, newLock) == -1) { int error = errno; Log("%s: Could not break lease on fd %d: %s\n", __FUNCTION__, fileDesc, Err_Errno2String(error)); } /* Cleanup. */ HgfsUpdateNodeServerLock(fileDesc, actualLock); free(lockData); } /* *----------------------------------------------------------------------------- * * HgfsServerSigOplockBreak -- * * Handle a pending oplock break. Called from the VMX poll loop context. * All we really do is set up the state for an oplock break and call * HgfsServerOplockBreak which will do the rest of the work. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsServerSigOplockBreak(int sigNum, // IN: Signal number siginfo_t *info, // IN: Additional info about signal ucontext_t *u, // IN: Interrupted context (regs etc) void *clientData) // IN: Ignored { ServerLockData *lockData; int newLease, fd; HgfsLockType newServerLock; ASSERT(sigNum == SIGIO); ASSERT(info); ASSERT(clientData == NULL); fd = info->si_fd; LOG(4, "%s: Received SIGIO for fd %d\n", __FUNCTION__, fd); /* * We've got all we need from the signal handler, let it continue handling * signals of this type. */ Sig_Continue(sigNum); /* * According to locks.c in kernel source, doing F_GETLEASE when a lease * break is pending will return the new lease we should use. It'll be * F_RDLCK if we can downgrade, or F_UNLCK if we should break altogether. */ newLease = fcntl(fd, F_GETLEASE); if (newLease == F_RDLCK) { newServerLock = HGFS_LOCK_SHARED; } else if (newLease == F_UNLCK) { newServerLock = HGFS_LOCK_NONE; } else if (newLease == -1) { int error = errno; Log("%s: Could not get old lease for fd %d: %s\n", __FUNCTION__, fd, Err_Errno2String(error)); goto error; } else { Log("%s: Unexpected reply to get lease for fd %d: %d\n", __FUNCTION__, fd, newLease); goto error; } /* * Setup a ServerLockData struct so that we can make use of * HgfsServerOplockBreak which does the heavy lifting of discovering which * HGFS handle we're interested in breaking, sending the break, receiving * the acknowledgement, and firing the platform-specific acknowledgement * function (where we'll downgrade the lease). */ lockData = malloc(sizeof *lockData); if (lockData) { lockData->fileDesc = fd; lockData->serverLock = newServerLock; lockData->event = 0; // not needed /* * Relinquish control of this data. It'll get freed later, when the RPC * command completes. */ HgfsServerOplockBreak(lockData); return; } else { Log("%s: Could not allocate memory for lease break on behalf of fd %d\n", __FUNCTION__, fd); } error: /* Clean up as best we can. */ fcntl(fd, F_SETLEASE, F_UNLCK); HgfsUpdateNodeServerLock(fd, HGFS_LOCK_NONE); } #endif /* HGFS_OPLOCKS */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerOplockMonitor.c000066400000000000000000000331701470176644300302130ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2020-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerOplockMonitor.c -- * * Implements functions for HGFS server opportunistic lock monitoring * subfeature. */ #include "vmware.h" #include "hashTable.h" #include "hgfsServerOplockMonitor.h" #include "mutexRankLib.h" #include "util.h" /* * Local data */ #define AS_KEY(_x) ((const void *)(uintptr_t)(_x)) /* * Define the max count for hash table gOplockMonitorMap. */ #define OPLOCK_MONITOR_MAP_MAX_COUNT HGFS_OPLOCK_MAX_COUNT /* * Define the max count for hash table gOplockMonitorHandleMap. * Different monitor requests may target the same file, for each file there is * one item in hash table gOplockMonitorMap, and for each monitor request there * is one item in hash table gOplockMonitorHandleMap. * We support 4 monitor requests for each file. */ #define OPLOCK_MONITOR_HANDLE_MAP_MAX_COUNT (4 * OPLOCK_MONITOR_MAP_MAX_COUNT) /* * This structure is the type of oplockMonitorData.callbackList. */ typedef struct { DblLnkLst_Links links; uint64 handle; HgfsOplockCallback callback; void *data; } oplockMonitorCallbackList; /* * This structure is the value field of hash table gOplockMonitorMap. */ typedef struct { fileDesc fileDesc; char *utf8Name; MXUserExclLock *lock; DblLnkLst_Links callbackList; } oplockMonitorData; /* * Caller can use oplock module to monitor the file change event by providing * the file path instead of file descriptor. * This hash table maps the file path to structure oplockMonitorData * which stores the information for the file, for example the file descriptor. * This hash table is mainly used to check if a file has already been opened, * which means when many callers monitor the same file, we only need to open * that file once. */ static HashTable *gOplockMonitorMap = NULL; /* * This hash table is used to map the monitor handle to structure * oplockMonitorData. * This hash table is used when un-monitor the file change. */ static HashTable *gOplockMonitorHandleMap = NULL; /* Lock for gOplockMonitorMap and gOplockMonitorHandleMap. */ static MXUserExclLock *oplockMonitorLock; /* Indicates if the oplock monitor module is initialized. */ static Bool gOplockMonitorInit = FALSE; void HgfsOplockUnmonitorFileChangeInternal(HOM_HANDLE handle); /* *----------------------------------------------------------------------------- * * HgfsOplockMonitorInit -- * * Set up any related state for monitoring. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsOplockMonitorInit(void) { if (gOplockMonitorInit) { return TRUE; } // Oplock module must be initialized first. if (!HgfsServerOplockIsInited()) { Log("%s: Oplock module is not inited\n", __FUNCTION__); return FALSE; } gOplockMonitorMap = HashTable_Alloc(OPLOCK_MONITOR_MAP_MAX_COUNT, HASH_ISTRING_KEY | HASH_FLAG_COPYKEY, NULL); ASSERT(gOplockMonitorMap); gOplockMonitorHandleMap = HashTable_Alloc(OPLOCK_MONITOR_HANDLE_MAP_MAX_COUNT, HASH_INT_KEY, NULL); ASSERT(gOplockMonitorHandleMap); oplockMonitorLock = MXUser_CreateExclLock("HgfsoplockMonitorLock", RANK_hgfsSharedFolders); gOplockMonitorInit = TRUE; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsOplockMonitorDestroy -- * * Tear down any related state for monitoring. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsOplockMonitorDestroy(void) { if (!gOplockMonitorInit) { return; } HashTable_Free(gOplockMonitorMap); HashTable_Free(gOplockMonitorHandleMap); MXUser_DestroyExclLock(oplockMonitorLock); gOplockMonitorInit = FALSE; } /* *----------------------------------------------------------------------------- * * HgfsOplockMonitorFileChangeCallback -- * * A callback function that called when the target file/directory is * changed. * Calls the caller provided callback. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsOplockMonitorFileChangeCallback(HgfsSessionInfo *session, // IN: void *data) // IN: { oplockMonitorData *monitorData = data; ASSERT(monitorData); MXUser_AcquireExclLock(oplockMonitorLock); if (HashTable_Lookup(gOplockMonitorMap, monitorData->utf8Name, NULL)) { DblLnkLst_Links *link, *nextLink; DblLnkLst_ForEachSafe(link, nextLink, &monitorData->callbackList) { oplockMonitorCallbackList *callbackItem = DblLnkLst_Container(link, oplockMonitorCallbackList, links); callbackItem->callback(session, callbackItem->data); /* * callbackItem->data has been freed in the user callback. */ callbackItem->data = NULL; HgfsOplockUnmonitorFileChangeInternal(callbackItem->handle); /* * callbackItem has been freed in above function. */ callbackItem = NULL; } } MXUser_ReleaseExclLock(oplockMonitorLock); } /* *----------------------------------------------------------------------------- * * HgfsOplockMonitorFileChange -- * * Monitor the file/directory change event by using oplock. * The caller provided callback will be called if the file/directory is * changed. * This is one-shot action, after the event is fired, the oplock will be * removed. * The data that caller provides will be freed by: * 1. caller callback if the callback is called; * 2. caller callback if this function failed; * 3. this module if caller cancels the file change monitor. * * Results: * HGFS_OPLOCK_INVALID_MONITOR_HANDLE on fail, handle on success. * * Side effects: * None. * *----------------------------------------------------------------------------- */ HOM_HANDLE HgfsOplockMonitorFileChange(char *utf8Name, // IN: Name in UTF8 HgfsSessionInfo *session, // IN: HgfsOplockCallback callback,// IN: void *data) // IN: { oplockMonitorData *monitorData = NULL; oplockMonitorCallbackList *callbackItem; HOM_HANDLE handle = HGFS_OPLOCK_INVALID_MONITOR_HANDLE; HgfsFileOpenInfo openInfo; HgfsLocalId localId; fileDesc newHandle; HgfsInternalStatus status; HgfsLockType serverLock = HGFS_LOCK_SHARED; MXUser_AcquireExclLock(oplockMonitorLock); if (!gOplockMonitorInit) { LOG(4, "%s: Oplock monitor is not inited\n", __FUNCTION__); goto error; } if ( HashTable_GetNumElements(gOplockMonitorMap) >= OPLOCK_MONITOR_MAP_MAX_COUNT) { LOG(4, "%s: Exceeds OPLOCK_MONITOR_MAP_MAX_COUNT\n", __FUNCTION__); goto error; } if ( HashTable_GetNumElements(gOplockMonitorHandleMap) >= OPLOCK_MONITOR_HANDLE_MAP_MAX_COUNT) { LOG(4, "%s: Exceeds OPLOCK_MONITOR_HANDLE_MAP_MAX_COUNT\n", __FUNCTION__); goto error; } /* * If there are multiple monitor request for the same file, we should open * the file only once, and add all the callback functions into one double * link list. */ if (HashTable_Lookup(gOplockMonitorMap, utf8Name, (void **)&monitorData)) { callbackItem = Util_SafeMalloc(sizeof *callbackItem); handle = (HOM_HANDLE)callbackItem; DblLnkLst_Init(&callbackItem->links); callbackItem->handle = handle; callbackItem->callback = callback; callbackItem->data = data; DblLnkLst_LinkLast(&monitorData->callbackList, &callbackItem->links); HashTable_Insert(gOplockMonitorHandleMap, AS_KEY(handle), (void *)monitorData); MXUser_ReleaseExclLock(oplockMonitorLock); return handle; } memset(&openInfo, 0, sizeof(openInfo)); openInfo.mask = HGFS_OPEN_VALID_MODE | HGFS_OPEN_VALID_SHARE_ACCESS; openInfo.mode = HGFS_OPEN_MODE_READ_ONLY; #ifdef _WIN32 openInfo.shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; #endif openInfo.flags = HGFS_OPEN; openInfo.utf8Name = utf8Name; openInfo.shareInfo.readPermissions = TRUE; status = HgfsPlatformValidateOpen(&openInfo, TRUE, session, &localId, &newHandle); if (status != HGFS_ERROR_SUCCESS) { LOG(4, "%s: Failed to open file: %s\n", __FUNCTION__, utf8Name); goto error; } monitorData = Util_SafeMalloc(sizeof *monitorData); monitorData->fileDesc = newHandle; monitorData->utf8Name = Util_SafeStrdup(utf8Name); DblLnkLst_Init(&monitorData->callbackList); if (!HgfsAcquireAIOServerLock(newHandle, session, &serverLock, HgfsOplockMonitorFileChangeCallback, monitorData)) { HgfsPlatformCloseFile(newHandle, NULL); LOG(4, "%s: Failed to acquire server lock for file: %s\n", __FUNCTION__, utf8Name); goto error; } callbackItem = Util_SafeMalloc(sizeof *callbackItem); handle = (HOM_HANDLE)callbackItem; DblLnkLst_Init(&callbackItem->links); callbackItem->handle = handle; callbackItem->callback = callback; callbackItem->data = data; DblLnkLst_LinkLast(&monitorData->callbackList, &callbackItem->links); HashTable_Insert(gOplockMonitorMap, utf8Name, (void *)monitorData); HashTable_Insert(gOplockMonitorHandleMap, AS_KEY(handle), (void *)monitorData); MXUser_ReleaseExclLock(oplockMonitorLock); return handle; error: if (monitorData) { free(monitorData->utf8Name); free(monitorData); } free(data); MXUser_ReleaseExclLock(oplockMonitorLock); return HGFS_OPLOCK_INVALID_MONITOR_HANDLE; } /* *----------------------------------------------------------------------------- * * HgfsOplockUnmonitorFileChangeInternal -- * * Cancel the monitor action by closing the file descriptor. * The lock for oplockMonitorLock should be acquired before calling this * funcion. * All the objects that related to handle will be released when returns * from this function. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsOplockUnmonitorFileChangeInternal(HOM_HANDLE handle) // IN: { oplockMonitorData *monitorData = NULL; DblLnkLst_Links *link, *nextLink; oplockMonitorCallbackList *callbackItem; if (HashTable_Lookup(gOplockMonitorHandleMap, AS_KEY(handle), (void **)&monitorData)) { HashTable_Delete(gOplockMonitorHandleMap, AS_KEY(handle)); DblLnkLst_ForEachSafe(link, nextLink, &monitorData->callbackList) { callbackItem = DblLnkLst_Container(link, oplockMonitorCallbackList, links); if (callbackItem->handle == handle) { DblLnkLst_Unlink1(&callbackItem->links); free(callbackItem->data); free(callbackItem); break; } } /* * Close the file if no one is monitoring it anymore. */ if (DblLnkLst_IsLinked(&monitorData->callbackList) == FALSE) { HashTable_Delete(gOplockMonitorMap, monitorData->utf8Name); HgfsRemoveAIOServerLock(monitorData->fileDesc); free(monitorData->utf8Name); free(monitorData); } } } /* *----------------------------------------------------------------------------- * * HgfsOplockUnmonitorFileChange -- * * Cancel the monitor action. * All the objects that related to handle will be released when returns * from this function. * the caller provided callback will not be called. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsOplockUnmonitorFileChange(HOM_HANDLE handle) // IN: { /* * This function is a callback function and may be called at any time, even * when the oplock monitor module is destroyed. * So, check if the oplock monitor module is initialized. */ if (!gOplockMonitorInit) { Log("%s: OplockMonitor module is not inited\n", __FUNCTION__); return; } MXUser_AcquireExclLock(oplockMonitorLock); HgfsOplockUnmonitorFileChangeInternal(handle); MXUser_ReleaseExclLock(oplockMonitorLock); } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerOplockMonitor.h000066400000000000000000000031601470176644300302140ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerOplockMonitor.h -- * * Header file for public common data types used in the HGFS * opportunistic lock monitoring subfeature. */ #ifndef _HGFS_SERVER_OPLOCK_MONITOR_H_ #define _HGFS_SERVER_OPLOCK_MONITOR_H_ #include "hgfsServerOplockInt.h" /* * Data structures */ /* * Global variables */ #define HGFS_OPLOCK_INVALID_MONITOR_HANDLE 0 /* * Global functions */ Bool HgfsOplockMonitorInit(void); void HgfsOplockMonitorDestroy(void); HOM_HANDLE HgfsOplockMonitorFileChange(char *utf8Name, HgfsSessionInfo *session, HgfsOplockCallback callback, void *data); void HgfsOplockUnmonitorFileChange(HOM_HANDLE handle); #endif // ifndef _HGFS_SERVER_OPLOCK_MONITOR_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerPacketUtil.c000066400000000000000000000630031470176644300274570ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerPacketUtil.c -- * * Utility functions for manipulating packet used by hgfs server code */ #include #include #include #include "vmware.h" #include "hgfsServer.h" #include "hgfsServerInt.h" #include "util.h" static void *HSPUGetBuf(HgfsServerChannelCallbacks *chanCb, MappingType mappingType, HgfsVmxIov *iov, uint32 iovCount, uint32 startIndex, size_t dataSize, size_t bufSize, void **buf, Bool *isAllocated, uint32 *iovMappedCount); static void HSPUPutBuf(HgfsServerChannelCallbacks *chanCb, MappingType mappingType, HgfsVmxIov *iov, uint32 iovCount, uint32 startIndex, size_t bufSize, void **buf, Bool *isAllocated, uint32 *iovMappedCount); static void HSPUCopyBufToIovec(HgfsVmxIov *iov, uint32 iovMapped, uint32 startIndex, void *buf, size_t bufSize); static void HSPUCopyIovecToBuf(HgfsVmxIov *iov, uint32 iovMapped, uint32 startIndex, void *buf, size_t bufSize); static Bool HSPUMapBuf(HgfsChannelMapVirtAddrFunc mapVa, HgfsChannelUnmapVirtAddrFunc putVa, size_t mapSize, uint32 startIndex, uint32 iovCount, HgfsVmxIov *iov, uint32 *mappedCount); static void HSPUUnmapBuf(HgfsChannelUnmapVirtAddrFunc unmapVa, uint32 startIndex, HgfsVmxIov *iov, uint32 *mappedCount); /* *----------------------------------------------------------------------------- * * HSPU_ValidateRequestPacketSize -- * * Validate an HGFS packet size with the HGFS header in use, the HGFS opcode request * (its arguments) and optionally any opcode request data that is contained in the * size for the packet. * * Results: * TRUE if the packet size is large enough for the required request data. * FALSE if not. * * Side effects: * None. *----------------------------------------------------------------------------- */ Bool HSPU_ValidateRequestPacketSize(HgfsPacket *packet, // IN: Hgfs Packet size_t requestHeaderSize, // IN: request header size size_t requestOpSize, // IN: request op size size_t requestOpDataSize) // IN: request op data size { size_t bytesRemaining = packet->metaPacketDataSize; Bool requestSizeIsOkay = FALSE; /* * Validate the request buffer size ensuring that the the contained components * (request header, the operation arguments and lastly any data) fall within it. */ if (bytesRemaining >= requestHeaderSize) { bytesRemaining -= requestHeaderSize; } else { goto exit; } if (bytesRemaining >= requestOpSize) { bytesRemaining -= requestOpSize; } else { goto exit; } if (bytesRemaining >= requestOpDataSize) { requestSizeIsOkay = TRUE; } exit: return requestSizeIsOkay; } /* *----------------------------------------------------------------------------- * * HSPU_ValidateReplyPacketSize -- * * Validate a reply buffer size in an hgfs packet with the reply data * size for the request. * * Results: * TRUE if the reply buffer size is large enough for the request reply * results. FALSE if not. * * Side effects: * None. *----------------------------------------------------------------------------- */ Bool HSPU_ValidateReplyPacketSize(HgfsPacket *packet, // IN: Hgfs Packet size_t replyHeaderSize, // IN: reply header size size_t replyResultSize, // IN: reply result size size_t replyResultDataSize, // IN: reply result data size Bool useMappedMetaPacket) // IN: using meta buffer { size_t bytesRemaining; Bool replySizeIsOkay = FALSE; if (packet->replyPacket != NULL) { /* Pre-allocated reply buffer (as used by the backdoor). */ bytesRemaining = packet->replyPacketSize; } else if (useMappedMetaPacket) { /* No reply buffer (as used by the VMCI) reuse the metapacket buffer. */ bytesRemaining = packet->metaPacketSize; } else { /* No reply buffer but we will allocate the size required. */ replySizeIsOkay = TRUE; goto exit; } if (bytesRemaining >= replyHeaderSize) { bytesRemaining -= replyHeaderSize; } else { goto exit; } if (bytesRemaining >= replyResultSize) { bytesRemaining -= replyResultSize; } else { goto exit; } if (bytesRemaining >= replyResultDataSize) { replySizeIsOkay = TRUE; } exit: return replySizeIsOkay; } /* *----------------------------------------------------------------------------- * * HSPU_GetReplyPacket -- * * Get a reply packet given an hgfs packet. * Guest mappings may be established. * * Results: * Pointer to reply packet. * * Side effects: * Buffer may be allocated. *----------------------------------------------------------------------------- */ void * HSPU_GetReplyPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsServerChannelCallbacks *chanCb, // IN: Channel callbacks size_t replyDataSize, // IN: Size of reply data size_t *replyPacketSize) // OUT: Size of reply Packet { if (packet->replyPacket != NULL) { /* * When we are transferring packets over backdoor, reply packet * is a static buffer. Backdoor should always return from here. */ packet->replyPacketDataSize = replyDataSize; LOG(4, "Existing reply packet %s %"FMTSZ"u %"FMTSZ"u\n", __FUNCTION__, replyDataSize, packet->replyPacketSize); ASSERT(replyDataSize <= packet->replyPacketSize); } else if (chanCb != NULL && chanCb->getWriteVa != NULL) { /* Can we write directly into guest memory? */ if (packet->metaPacket != NULL) { /* * Use the mapped metapacket buffer for the reply. * This currently makes assumptions about the mapping - * - It is mapped read -write * - It is always large enough for any reply * This will change as it is grossly inefficient as the maximum size * is always mapped and copied no matter how much data it really contains. */ LOG(10, "%s Using meta packet for reply packet\n", __FUNCTION__); ASSERT(BUF_READWRITEABLE == packet->metaMappingType); ASSERT(replyDataSize <= packet->metaPacketSize); packet->replyPacket = packet->metaPacket; packet->replyPacketDataSize = replyDataSize; packet->replyPacketSize = packet->metaPacketSize; packet->replyPacketIsAllocated = FALSE; /* * The reply is using the meta buffer so update the valid data size. * * Note, currently We know the reply size is going to be less than the * incoming request valid data size. This will updated when that part is * fixed. See the above comment about the assumptions and asserts. */ packet->metaPacketDataSize = packet->replyPacketDataSize; } else { NOT_IMPLEMENTED(); } } else { /* For sockets channel we always need to allocate buffer */ LOG(10, "%s Allocating reply packet\n", __FUNCTION__); packet->replyPacket = Util_SafeMalloc(replyDataSize); packet->replyPacketIsAllocated = TRUE; packet->replyPacketDataSize = replyDataSize; packet->replyPacketSize = replyDataSize; } *replyPacketSize = packet->replyPacketSize; return packet->replyPacket; } /* *----------------------------------------------------------------------------- * * HSPU_PutReplyPacket -- * * Free buffer if reply packet was allocated. * * Results: * None. * * Side effects: * None. *----------------------------------------------------------------------------- */ void HSPU_PutReplyPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsServerChannelCallbacks *chanCb) // IN: Channel callbacks { /* * If there wasn't an allocated buffer for the reply, there is nothing to * do as the reply is in the metapacket buffer which will be handled by the * put on the metapacket. */ if (packet->replyPacketIsAllocated) { LOG(10, "%s Freeing reply packet", __FUNCTION__); free(packet->replyPacket); packet->replyPacketIsAllocated = FALSE; packet->replyPacket = NULL; packet->replyPacketSize = 0; } } /* *----------------------------------------------------------------------------- * * HSPU_GetMetaPacket -- * * Get a meta packet given an hgfs packet. * Guest mappings will be established. * * Results: * Pointer to meta packet. * * Side effects: * Buffer may be allocated. *----------------------------------------------------------------------------- */ void * HSPU_GetMetaPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet size_t *metaPacketSize, // OUT: Size of metaPacket HgfsServerChannelCallbacks *chanCb) // IN: Channel callbacks { *metaPacketSize = packet->metaPacketDataSize; if (packet->metaPacket != NULL) { return packet->metaPacket; } if (packet->metaPacketSize == 0) { return NULL; } packet->metaMappingType = BUF_READWRITEABLE; return HSPUGetBuf(chanCb, packet->metaMappingType, packet->iov, packet->iovCount, 0, packet->metaPacketDataSize, packet->metaPacketSize, &packet->metaPacket, &packet->metaPacketIsAllocated, &packet->metaPacketMappedIov); } /* *----------------------------------------------------------------------------- * * HSPU_ValidateDataPacketSize -- * * Validate a data packet buffer size in an hgfs packet with the required data * size for the request. * * Results: * TRUE if the data buffer size is valid for the request. * FALSE if not. * * Side effects: * None. *----------------------------------------------------------------------------- */ Bool HSPU_ValidateDataPacketSize(HgfsPacket *packet, // IN: Hgfs Packet size_t dataSize) // IN: data size { return (dataSize <= packet->dataPacketSize); } /* *----------------------------------------------------------------------------- * * HSPU_GetDataPacketBuf -- * * Get a data packet given an hgfs packet. * Guest mappings will be established. * * Results: * Pointer to data packet. * * Side effects: * Buffer may be allocated. *----------------------------------------------------------------------------- */ void * HSPU_GetDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet MappingType mappingType, // IN: Writeable/Readable HgfsServerChannelCallbacks *chanCb) // IN: Channel callbacks { if (packet->dataPacket != NULL) { return packet->dataPacket; } if (packet->dataPacketSize == 0) { return NULL; } packet->dataMappingType = mappingType; return HSPUGetBuf(chanCb, packet->dataMappingType, packet->iov, packet->iovCount, packet->dataPacketIovIndex, packet->dataPacketDataSize, packet->dataPacketSize, &packet->dataPacket, &packet->dataPacketIsAllocated, &packet->dataPacketMappedIov); } /* *----------------------------------------------------------------------------- * * HSPUGetBuf -- * * Get a {meta, data} packet given an hgfs packet. * Guest mappings will be established. * * Results: * Pointer to buffer. * * Side effects: * Buffer may be allocated. *----------------------------------------------------------------------------- */ static void * HSPUGetBuf(HgfsServerChannelCallbacks *chanCb, // IN: Channel callbacks MappingType mappingType, // IN: Access type Readable/Writeable HgfsVmxIov *iov, // IN: iov array uint32 iovCount, // IN: iov array size uint32 startIndex, // IN: Start index of iov size_t dataSize, // IN: Size of data in tghe buffer size_t bufSize, // IN: Size of buffer void **buf, // OUT: Contigous buffer Bool *isAllocated, // OUT: Buffer allocated uint32 *iovMappedCount) // OUT: iov mapped count { uint32 iovMapped = 0; HgfsChannelMapVirtAddrFunc mapVa; Bool releaseMappings = FALSE; ASSERT(buf != NULL); *buf = NULL; *isAllocated = FALSE; if (chanCb == NULL) { goto exit; } if (mappingType == BUF_WRITEABLE || mappingType == BUF_READWRITEABLE) { mapVa = chanCb->getWriteVa; } else { ASSERT(mappingType == BUF_READABLE); mapVa = chanCb->getReadVa; } /* Looks like we are in the middle of poweroff. */ if (mapVa == NULL) { goto exit; } /* Establish guest memory mappings */ if (!HSPUMapBuf(mapVa, chanCb->putVa, bufSize, startIndex, iovCount, iov, &iovMapped)) { /* Guest probably passed us bad physical address */ goto exit; } if (iovMapped == 1) { /* A single page buffer is contiguous so hold on to guest mappings. */ *buf = iov[startIndex].va; goto exit; } /* More than one page was mapped. */ ASSERT(iov[startIndex].len < bufSize); LOG(10, "%s: Hgfs Allocating buffer \n", __FUNCTION__); *buf = Util_SafeMalloc(bufSize); *isAllocated = TRUE; if ((mappingType == BUF_READABLE || mappingType == BUF_READWRITEABLE) && (0 != dataSize)) { HSPUCopyIovecToBuf(iov, iovMapped, startIndex, *buf, dataSize); } releaseMappings = TRUE; exit: if (releaseMappings) { HSPUUnmapBuf(chanCb->putVa, startIndex, iov, &iovMapped); } *iovMappedCount = iovMapped; return *buf; } /* *----------------------------------------------------------------------------- * * HSPU_PutMetaPacket -- * * Free meta packet buffer if allocated. * Guest mappings will be released. * * Results: * void. * * Side effects: * *----------------------------------------------------------------------------- */ void HSPU_PutMetaPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsServerChannelCallbacks *chanCb) // IN: Channel callbacks { if (packet->metaPacket == NULL) { return; } LOG(4, "%s Hgfs Putting Meta packet\n", __FUNCTION__); HSPUPutBuf(chanCb, packet->metaMappingType, packet->iov, packet->iovCount, 0, packet->metaPacketDataSize, &packet->metaPacket, &packet->metaPacketIsAllocated, &packet->metaPacketMappedIov); } /* *----------------------------------------------------------------------------- * * HSPU_SetDataPacketSize -- * * Set the size of the valid data in the data packet buffer. * * Results: * void. * * Side effects: * None. *----------------------------------------------------------------------------- */ void HSPU_SetDataPacketSize(HgfsPacket *packet, // IN/OUT: Hgfs Packet size_t dataSize) // IN: data size { ASSERT(NULL != packet); ASSERT(dataSize <= packet->dataPacketSize); packet->dataPacketDataSize = dataSize; } /* *----------------------------------------------------------------------------- * * HSPU_PutDataPacketBuf -- * * Free data packet buffer if allocated. * Guest mappings will be released. * * Results: * void. * * Side effects: * None. *----------------------------------------------------------------------------- */ void HSPU_PutDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsServerChannelCallbacks *chanCb) // IN: Channel callbacks { if (packet->dataPacket == NULL) { return; } LOG(4, "%s Hgfs Putting Data packet\n", __FUNCTION__); HSPUPutBuf(chanCb, packet->dataMappingType, packet->iov, packet->iovCount, packet->dataPacketIovIndex, packet->dataPacketDataSize, &packet->dataPacket, &packet->dataPacketIsAllocated, &packet->dataPacketMappedIov); } /* *----------------------------------------------------------------------------- * * HSPUPutBuf -- * * Free buffer if allocated and release guest mappings. * * Results: * None. * * Side effects: * None. *----------------------------------------------------------------------------- */ void HSPUPutBuf(HgfsServerChannelCallbacks *chanCb, // IN: Channel callbacks MappingType mappingType, // IN: Access type Readable/Writeable HgfsVmxIov *iov, // IN: iov array uint32 iovCount, // IN: iov array size uint32 startIndex, // IN: Start index of iov size_t bufSize, // IN: Size of buffer void **buf, // OUT: Contigous buffer Bool *isAllocated, // OUT: Buffer allocated uint32 *iovMappedCount) // OUT: iov mapped count { ASSERT(buf != NULL); if (chanCb == NULL || chanCb->putVa == NULL) { goto exit; } if (*isAllocated && (mappingType == BUF_WRITEABLE || mappingType == BUF_READWRITEABLE)) { /* * 1. Map the iov's if required for the size into host addresses. * 2. Write the buffer data into the iov host addresses. * 3. Unmap the iov's host virtual addresses. */ if (0 == *iovMappedCount) { if (!HSPUMapBuf(chanCb->getWriteVa, chanCb->putVa, bufSize, startIndex, iovCount, iov, iovMappedCount)) { goto exit; } } HSPUCopyBufToIovec(iov, *iovMappedCount, startIndex, *buf, bufSize); } if (0 < *iovMappedCount) { HSPUUnmapBuf(chanCb->putVa, startIndex, iov, iovMappedCount); } exit: if (*isAllocated) { LOG(10, "%s: Hgfs Freeing buffer \n", __FUNCTION__); free(*buf); *isAllocated = FALSE; } *buf = NULL; } /* *----------------------------------------------------------------------------- * * HSPUCopyBufToIovec -- * * Write out buffer to data Iovec. * * Results: * void * * Side effects: * @iov is populated with contents of @buf *----------------------------------------------------------------------------- */ static void HSPUCopyBufToIovec(HgfsVmxIov *iov, // IN: iovs (array of mappings) uint32 iovCount, // IN: iov count of mappings uint32 startIndex, // IN: start index into iov void *buf, // IN: Contigous Buffer size_t bufSize) // IN: Size of buffer { size_t iovIndex; size_t endIndex; size_t remainingSize; size_t copiedAmount = 0; ASSERT(buf != NULL); for (iovIndex = startIndex, endIndex = startIndex + iovCount, remainingSize = bufSize; iovIndex < endIndex && remainingSize > 0; iovIndex++) { size_t copyAmount = remainingSize < iov[iovIndex].len ? remainingSize: iov[iovIndex].len; ASSERT(iov[iovIndex].va != NULL); memcpy(iov[iovIndex].va, (char *)buf + copiedAmount, copyAmount); remainingSize -= copyAmount; copiedAmount += copyAmount; } ASSERT(remainingSize == 0); } /* *----------------------------------------------------------------------------- * * HSPUCopyIovecToBuf -- * * Read Iovec into the buffer. * * Results: * void * * Side effects: * @iov is populated with contents of @buf *----------------------------------------------------------------------------- */ static void HSPUCopyIovecToBuf(HgfsVmxIov *iov, // IN: iovs (array of mappings) uint32 iovCount, // IN: iov count of mappings uint32 startIndex, // IN: start index into iov void *buf, // IN: contigous Buffer size_t bufSize) // IN: size of buffer { size_t iovIndex; size_t endIndex; size_t remainingSize; size_t copiedAmount = 0; for (iovIndex = startIndex, endIndex = startIndex + iovCount, remainingSize = bufSize; iovIndex < endIndex && remainingSize > 0; iovIndex++) { size_t copyAmount = remainingSize < iov[iovIndex].len ? remainingSize : iov[iovIndex].len; memcpy((char *)buf + copiedAmount, iov[iovIndex].va, copyAmount); copiedAmount += copyAmount; remainingSize -= copyAmount; } ASSERT(copiedAmount == bufSize && remainingSize == 0); } /* *----------------------------------------------------------------------------- * * HSPUMapBuf -- * * Map the buffer for the required size. * * Results: * TRUE if we mapped the requested size and the number of mappings performed. * Otherwise FALSE if something failed, and 0 mappings performed. * * Side effects: * None. *----------------------------------------------------------------------------- */ static Bool HSPUMapBuf(HgfsChannelMapVirtAddrFunc mapVa, // IN: map virtual address function HgfsChannelUnmapVirtAddrFunc putVa, // IN: unmap virtual address function size_t mapSize, // IN: size to map uint32 startIndex, // IN: Start index of iovs to map uint32 iovCount, // IN: iov count HgfsVmxIov *iov, // IN/OUT: iovs (array) to map uint32 *mappedCount) // OUT: mapped iov count { uint32 iovIndex; uint32 mappedIovCount; size_t remainingSize; Bool mapped = TRUE; for (iovIndex = startIndex, mappedIovCount = 0, remainingSize = mapSize; iovIndex < iovCount && remainingSize > 0; iovIndex++, mappedIovCount++) { /* Check: Iov in VMCI should never cross page boundary */ ASSERT(iov[iovIndex].len <= (PAGE_SIZE - PAGE_OFFSET(iov[iovIndex].pa))); iov[iovIndex].va = mapVa(&iov[iovIndex]); if (NULL == iov[iovIndex].va) { /* Failed to map the physical address. */ break; } remainingSize = remainingSize < iov[iovIndex].len ? 0: remainingSize - iov[iovIndex].len; } if (0 != remainingSize) { /* Something failed in the mappings Undo any mappings we created. */ HSPUUnmapBuf(putVa, startIndex, iov, &mappedIovCount); mapped = FALSE; } *mappedCount = mappedIovCount; return mapped; } /* *----------------------------------------------------------------------------- * * HSPUUnmapBuf -- * * Unmap the buffer and release guest mappings. * * Results: * None. * * Side effects: * None. *----------------------------------------------------------------------------- */ static void HSPUUnmapBuf(HgfsChannelUnmapVirtAddrFunc unmapVa, // IN/OUT: Hgfs Packet uint32 startIndex, // IN: Start index of iovs to map HgfsVmxIov *iov, // IN/OUT: iovs (array) to map uint32 *mappedCount) // IN/OUT: iov count to unmap { uint32 iovIndex; uint32 endIndex; for (iovIndex = startIndex, endIndex = startIndex + *mappedCount; iovIndex < endIndex; iovIndex++) { unmapVa(&iov[iovIndex].context); iov[iovIndex].va = NULL; } *mappedCount = 0; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerParameters.c000066400000000000000000005743761470176644300275410ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2010-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #include #include #include "vmware.h" #include "str.h" #include "cpName.h" #include "cpNameLite.h" #include "hgfsServerInt.h" #include "hgfsServerPolicy.h" #include "codeset.h" #include "config.h" #include "file.h" #include "util.h" #include "wiper.h" #include "vm_basic_asm.h" #include "hgfsServerParameters.h" #ifdef _WIN32 #define HGFS_OP_CAPFLAG_WIN32_IS_SUPPORTED HGFS_OP_CAPFLAG_IS_SUPPORTED #define HGFS_OP_CAPFLAG_POSIX_IS_SUPPORTED HGFS_OP_CAPFLAG_NOT_SUPPORTED #else #define HGFS_OP_CAPFLAG_WIN32_IS_SUPPORTED HGFS_OP_CAPFLAG_NOT_SUPPORTED #define HGFS_OP_CAPFLAG_POSIX_IS_SUPPORTED HGFS_OP_CAPFLAG_IS_SUPPORTED #endif #define HGFS_ASSERT_PACK_PARAMS \ do { \ ASSERT(packet); \ ASSERT(packetHeader); \ ASSERT(session); \ ASSERT(payloadSize); \ } while(0) /* * This is the default/minimal set of capabilities which is supported by every transport. * Every transport and session may have additional capabilities in addition to these. */ static HgfsOpCapability hgfsDefaultCapabilityTable[] = { {HGFS_OP_OPEN, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_READ, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_WRITE, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_CLOSE, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SEARCH_OPEN, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SEARCH_READ, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SEARCH_CLOSE, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_GETATTR, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SETATTR, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_CREATE_DIR, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_DELETE_FILE, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_DELETE_DIR, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_RENAME, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_QUERY_VOLUME_INFO, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_OPEN_V2, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_GETATTR_V2, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SETATTR_V2, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SEARCH_READ_V2, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_CREATE_SYMLINK, HGFS_OP_CAPFLAG_POSIX_IS_SUPPORTED}, {HGFS_OP_SERVER_LOCK_CHANGE, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_CREATE_DIR_V2, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_DELETE_FILE_V2, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_DELETE_DIR_V2, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_RENAME_V2, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_OPEN_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_READ_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_WRITE_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_CLOSE_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SEARCH_OPEN_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SEARCH_READ_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SEARCH_CLOSE_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_GETATTR_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_SETATTR_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_CREATE_DIR_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_DELETE_FILE_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_DELETE_DIR_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_RENAME_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_QUERY_VOLUME_INFO_V3, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_CREATE_SYMLINK_V3, HGFS_OP_CAPFLAG_POSIX_IS_SUPPORTED}, {HGFS_OP_SERVER_LOCK_CHANGE_V3, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_WRITE_WIN32_STREAM_V3, HGFS_OP_CAPFLAG_WIN32_IS_SUPPORTED}, {HGFS_OP_CREATE_SESSION_V4, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_DESTROY_SESSION_V4, HGFS_OP_CAPFLAG_IS_SUPPORTED}, {HGFS_OP_READ_FAST_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_WRITE_FAST_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_SET_WATCH_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_REMOVE_WATCH_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_NOTIFY_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_SEARCH_READ_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_OPEN_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_ENUMERATE_STREAMS_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_GETATTR_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_SETATTR_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_DELETE_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_LINKMOVE_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_FSCTL_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_ACCESS_CHECK_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_FSYNC_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_QUERY_VOLUME_INFO_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_OPLOCK_ACQUIRE_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_OPLOCK_BREAK_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_LOCK_BYTE_RANGE_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_UNLOCK_BYTE_RANGE_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_QUERY_EAS_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, {HGFS_OP_SET_EAS_V4, HGFS_OP_CAPFLAG_NOT_SUPPORTED}, }; /* *----------------------------------------------------------------------------- * * HgfsValidateReplySize -- * * Verify if the size of a reply does not exceed maximum supported size. * * Results: * TRUE if the packet size is acceptable, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsValidateReplySize(char const *packetIn, HgfsOp op, size_t packetSize) { Bool result; HgfsRequest *request = (HgfsRequest *)packetIn; if (HGFS_OP_NEW_HEADER != request->op) { if (HGFS_OP_READ_V3 == op) { result = packetSize <= HgfsLargePacketMax(FALSE); } else { result = packetSize <= HGFS_PACKET_MAX; } } else { result = TRUE; } if (!result) { LOG(4, "%s: Reply exceeded maximum support size!\n", __FUNCTION__); } return result; } /* *----------------------------------------------------------------------------- * * HgfsGetPayloadSize -- * * Returns size of the payload based on incoming packet and total * packet size. * * Results: * Size of the payload in bytes. * * Side effects: * None * *----------------------------------------------------------------------------- */ size_t HgfsGetPayloadSize(char const *packetIn, // IN: request packet size_t packetSize) // IN: request packet size { HgfsRequest *request = (HgfsRequest *)packetIn; size_t result; ASSERT(packetSize >= sizeof *request); if (request->op < HGFS_OP_CREATE_SESSION_V4) { result = packetSize - sizeof *request; } else { HgfsHeader *header = (HgfsHeader *)packetIn; ASSERT(packetSize >= header->packetSize); ASSERT(header->packetSize >= header->headerSize); result = header->packetSize - header->headerSize; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackHeaderV1V2 -- * * Unpack the client request that contains a basic valid HgfsHeader for protocol * versions 1 and 2. * Extract the useful details for the caller. * * Results: * HGFS_ERROR_SUCCESS always. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsUnpackHeaderV1V2(const HgfsRequest *request, // IN: request header size_t requestSize, // IN: request data size uint32 *requestId, // OUT: unique request id HgfsOp *opcode, // OUT: request opcode size_t *payloadSize, // OUT: size of the payload const void **payload) // OUT: pointer to the payload { /* V1 or V2 requests do not have a separate header. */ *requestId = request->id; *opcode = request->op; *payloadSize = requestSize; *payload = request; return HGFS_ERROR_SUCCESS; } /* *----------------------------------------------------------------------------- * * HgfsUnpackHeaderV3 -- * * Unpack the client request that contains a basic valid HgfsHeader for protocol * version 3. * Extract the useful details for the caller. * * Results: * HGFS_ERROR_SUCCESS always. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsUnpackHeaderV3(const HgfsRequest *request, // IN: request header size_t requestSize, // IN: request data size uint32 *requestId, // OUT: unique request id HgfsOp *opcode, // OUT: request opcode size_t *payloadSize, // OUT: size of the payload const void **payload) // OUT: pointer to the payload { /* Old header with V3 request. */ *requestId = request->id; *opcode = request->op; if (requestSize > sizeof *request) { *payload = HGFS_REQ_GET_PAYLOAD_V3(request); *payloadSize = requestSize - ((char *)*payload - (char *)request); } else { *payload = NULL; *payloadSize = 0; } return HGFS_ERROR_SUCCESS; } /* *----------------------------------------------------------------------------- * * HgfsUnpackHeaderV4 -- * * Unpack the client request that contains a basic valid HgfsHeader for protocol * version 4 and newer. * Extract the useful details for the caller. * * Results: * HGFS_ERROR_SUCCESS if successful or * HGFS_ERROR_PROTOCOL for a malformed request, and we cannot trust the data. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static HgfsInternalStatus HgfsUnpackHeaderV4(const HgfsHeader *requestHeader, // IN: request header size_t requestSize, // IN: request data size uint64 *sessionId, // OUT: session Id uint32 *requestId, // OUT: unique request id uint32 *hdrFlags, // OUT: header flags uint32 *information, // OUT: generic information HgfsOp *opcode, // OUT: request opcode size_t *payloadSize, // OUT: size of the payload const void **payload) // OUT: pointer to the payload { HgfsInternalStatus status = HGFS_ERROR_SUCCESS; if (requestSize < sizeof *requestHeader) { LOG(4, "%s: Malformed HGFS packet received - header is too small!\n", __FUNCTION__); status = HGFS_ERROR_PROTOCOL; goto exit; } if (requestSize < requestHeader->packetSize || requestHeader->packetSize < requestHeader->headerSize) { LOG(4, "%s: Malformed HGFS packet received - inconsistent header " "and packet sizes!\n", __FUNCTION__); status = HGFS_ERROR_PROTOCOL; goto exit; } if (HGFS_HEADER_VERSION_1 > requestHeader->version) { LOG(4, "%s: Malformed HGFS packet received - invalid header version!\n", __FUNCTION__); status = HGFS_ERROR_PROTOCOL; goto exit; } ASSERT(HGFS_OP_NEW_HEADER == requestHeader->dummy); /* The basics of the header are validated, get the remaining parameters. */ *sessionId = requestHeader->sessionId; *requestId = requestHeader->requestId; *opcode = requestHeader->op; /* * For version 1 of the header the file copy client did not ensure * the following fields (and reserved fields) were set and thus can * contain garbage. * For this reason, we just zero out these fields for this header version. */ if (HGFS_HEADER_VERSION_1 == requestHeader->version) { *hdrFlags = 0; *information = 0; } else { *hdrFlags = requestHeader->flags; *information = requestHeader->information; } *payloadSize = requestHeader->packetSize - requestHeader->headerSize; if (0 < *payloadSize) { *payload = (char *)requestHeader + requestHeader->headerSize; } else { *payload = NULL; Log("%s: HGFS packet with header and no payload!\n", __FUNCTION__); } exit: return status; } /* *----------------------------------------------------------------------------- * * HgfsUnpackPacketParams -- * * Takes the Hgfs packet and extracts the operation parameters. * This validates the incoming packet as part of the processing. * * Results: * HGFS_ERROR_SUCCESS if all the request parameters are successfully extracted. * HGFS_ERROR_INTERNAL if an error occurs without sufficient request data to be * able to send a reply to the client. * Any other appropriate error if the incoming packet has errors and there is * sufficient information to send a response. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsUnpackPacketParams(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size Bool *sessionEnabled, // OUT: session enabled request uint64 *sessionId, // OUT: session Id uint32 *requestId, // OUT: unique request id HgfsOp *opcode, // OUT: request opcode size_t *payloadSize, // OUT: size of the opcode request const void **payload) // OUT: pointer to the opcode request { const HgfsRequest *request; HgfsInternalStatus unpackStatus = HGFS_ERROR_SUCCESS; ASSERT(NULL != packet); request = packet; LOG(4, "%s: Received a request with opcode %d.\n", __FUNCTION__, request->op); /* * Error out if less than HgfsRequest size. * We cannot continue any further with this packet. */ if (packetSize < sizeof *request) { LOG(4, "%s: Received a request with opcode %"FMTSZ"u.\n", __FUNCTION__, packetSize); unpackStatus = HGFS_ERROR_INTERNAL; goto exit; } *sessionEnabled = FALSE; if (request->op < HGFS_OP_OPEN_V3) { unpackStatus = HgfsUnpackHeaderV1V2(request, packetSize, requestId, opcode, payloadSize, payload); } else if (request->op < HGFS_OP_CREATE_SESSION_V4) { unpackStatus = HgfsUnpackHeaderV3(request, packetSize, requestId, opcode, payloadSize, payload); } else if (HGFS_OP_NEW_HEADER == request->op) { /* The legacy op means a new header but we can have V3 and newer opcodes. */ const HgfsHeader *requestHdr = packet; uint32 hdrFlags = 0; uint32 information; *sessionEnabled = TRUE; unpackStatus = HgfsUnpackHeaderV4(requestHdr, packetSize, sessionId, requestId, &hdrFlags, &information, opcode, payloadSize, payload); /* * Test if the client sent invalid flags (and information in future cases). * Note, a basic sanitation was done in the unpack header itself, only V2 * or newer allowed to pass meaningful values through. */ if (0 != hdrFlags && 0 == (hdrFlags & (HGFS_PACKET_FLAG_REQUEST | HGFS_PACKET_FLAG_REPLY))) { unpackStatus = HGFS_ERROR_PROTOCOL; } } else { LOG(4, "%s: HGFS packet - unknown opcode == newer client or malformed!\n", __FUNCTION__); unpackStatus = HGFS_ERROR_INTERNAL; } exit: LOG(4, "%s: unpacked request(op %d, id %u) -> %u.\n", __FUNCTION__, request->op, *requestId, unpackStatus); return unpackStatus; } /* *----------------------------------------------------------------------------- * * HgfsUnpackOpenPayloadV1 -- * * Unpack and validate payload for hgfs open request V1 to the HgfsFileOpenInfo * structure that is used to pass around open request information. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackOpenPayloadV1(const HgfsRequestOpen *requestV1, // IN: request payload size_t payloadSize, // IN: request payload size HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct { size_t extra; /* Enforced by the dispatch function. */ if (payloadSize < sizeof *requestV1) { LOG(4, "%s: Malformed HGFS packet received - payload too small\n", __FUNCTION__); return FALSE; } extra = payloadSize - sizeof *requestV1; /* * The request file name length is user-provided, so this test must be * carefully written to prevent wraparounds. */ if (requestV1->fileName.length > extra) { /* The input packet is smaller than the request. */ LOG(4, "%s: Malformed HGFS packet received - payload too small to hold file name\n", __FUNCTION__); return FALSE; } /* For OpenV1 requests, we know exactly what fields we expect. */ openInfo->mask = HGFS_OPEN_VALID_MODE | HGFS_OPEN_VALID_FLAGS | HGFS_OPEN_VALID_OWNER_PERMS | HGFS_OPEN_VALID_FILE_NAME; openInfo->mode = requestV1->mode; openInfo->cpName = requestV1->fileName.name; openInfo->cpNameSize = requestV1->fileName.length; openInfo->flags = requestV1->flags; openInfo->ownerPerms = requestV1->permissions; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackOpenPayloadV2 -- * * Unpack and validate payload for hgfs open request V2 to the HgfsFileOpenInfo * structure that is used to pass around open request information. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackOpenPayloadV2(const HgfsRequestOpenV2 *requestV2, // IN: request payload size_t payloadSize, // IN: request payload size HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct { size_t extra; /* Enforced by the dispatch function. */ if (payloadSize < sizeof *requestV2) { LOG(4, "%s: Malformed HGFS packet received - payload too small\n", __FUNCTION__); return FALSE; } extra = payloadSize - sizeof *requestV2; if (!(requestV2->mask & HGFS_OPEN_VALID_FILE_NAME)) { /* We do not support open requests without a valid file name. */ LOG(4, "%s: Malformed HGFS packet received - invalid mask\n", __FUNCTION__); return FALSE; } /* * The request file name length is user-provided, so this test must be * carefully written to prevent wraparounds. */ if (requestV2->fileName.length > extra) { /* The input packet is smaller than the request. */ LOG(4, "%s: Malformed HGFS packet received - payload too small to hold file name\n", __FUNCTION__); return FALSE; } /* * Copy all the fields into our carrier struct. Some will probably be * garbage, but it's simpler to copy everything now and check the * valid bits before reading later. */ openInfo->mask = requestV2->mask; openInfo->mode = requestV2->mode; openInfo->cpName = requestV2->fileName.name; openInfo->cpNameSize = requestV2->fileName.length; openInfo->flags = requestV2->flags; openInfo->specialPerms = requestV2->specialPerms; openInfo->ownerPerms = requestV2->ownerPerms; openInfo->groupPerms = requestV2->groupPerms; openInfo->otherPerms = requestV2->otherPerms; openInfo->attr = requestV2->attr; openInfo->allocationSize = requestV2->allocationSize; openInfo->desiredAccess = requestV2->desiredAccess; openInfo->shareAccess = requestV2->shareAccess; openInfo->desiredLock = requestV2->desiredLock; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackOpenPayloadV3 -- * * Unpack and validate payload for hgfs open request V3 to the HgfsFileOpenInfo * structure that is used to pass around open request information. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackOpenPayloadV3(const HgfsRequestOpenV3 *requestV3, // IN: request payload size_t payloadSize, // IN: request payload size HgfsFileOpenInfo *openInfo) // IN/OUT: open info struct { size_t extra; /* Enforced by the dispatch function. */ if (payloadSize < sizeof *requestV3) { LOG(4, "%s: Malformed HGFS packet received - payload too small\n", __FUNCTION__); return FALSE; } extra = payloadSize - sizeof *requestV3; if (!(requestV3->mask & HGFS_OPEN_VALID_FILE_NAME)) { /* We do not support open requests without a valid file name. */ LOG(4, "%s: Malformed HGFS packet received - incorrect mask\n", __FUNCTION__); return FALSE; } /* * The request file name length is user-provided, so this test must be * carefully written to prevent wraparounds. */ if (requestV3->fileName.length > extra) { /* The input packet is smaller than the request. */ LOG(4, "%s: Malformed HGFS packet received - payload too small to hold file name\n", __FUNCTION__); return FALSE; } /* * Copy all the fields into our carrier struct. Some will probably be * garbage, but it's simpler to copy everything now and check the * valid bits before reading later. */ openInfo->mask = requestV3->mask; openInfo->mode = requestV3->mode; openInfo->cpName = requestV3->fileName.name; openInfo->cpNameSize = requestV3->fileName.length; openInfo->caseFlags = requestV3->fileName.caseType; openInfo->flags = requestV3->flags; openInfo->specialPerms = requestV3->specialPerms; openInfo->ownerPerms = requestV3->ownerPerms; openInfo->groupPerms = requestV3->groupPerms; openInfo->otherPerms = requestV3->otherPerms; openInfo->attr = requestV3->attr; openInfo->allocationSize = requestV3->allocationSize; openInfo->desiredAccess = requestV3->desiredAccess; openInfo->shareAccess = requestV3->shareAccess; openInfo->desiredLock = requestV3->desiredLock; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackOpenRequest -- * * Unpack hgfs open request to the HgfsFileOpenInfo structure that is used * to pass around open request information. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackOpenRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: packet size HgfsOp op, // IN: requested operation HgfsFileOpenInfo *openInfo) // IN/OUT: open info structure { Bool result; ASSERT(packet); ASSERT(openInfo); openInfo->requestType = op; openInfo->caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; switch (op) { case HGFS_OP_OPEN_V3: { const HgfsRequestOpenV3 *requestV3 = packet; LOG(4, "%s: HGFS_OP_OPEN_V3\n", __FUNCTION__); result = HgfsUnpackOpenPayloadV3(requestV3, packetSize, openInfo); break; } case HGFS_OP_OPEN_V2: { const HgfsRequestOpenV2 *requestV2 = packet; LOG(4, "%s: HGFS_OP_OPEN_V2\n", __FUNCTION__); result = HgfsUnpackOpenPayloadV2(requestV2, packetSize, openInfo); break; } case HGFS_OP_OPEN: { const HgfsRequestOpen *requestV1 = packet; LOG(4, "%s: HGFS_OP_OPEN\n", __FUNCTION__); result = HgfsUnpackOpenPayloadV1(requestV1, packetSize, openInfo); break; } default: NOT_REACHED(); result = FALSE; } if (!result) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); } return result; } /* *----------------------------------------------------------------------------- * * HgfsPackReplyHeaderV4 -- * * Pack hgfs header that corresponds to an HGFS protocol packet. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsPackReplyHeaderV4(HgfsStatus status, // IN: reply status uint32 payloadSize, // IN: size of the reply payload HgfsOp opcode, // IN: request type uint64 sessionId, // IN: session id uint32 requestId, // IN: request id uint32 hdrFlags, // IN: header flags size_t hdrPacketSize, // IN: header packet size HgfsHeader *hdrPacket) // OUT: outgoing packet header { Bool result = FALSE; if (hdrPacketSize >= sizeof *hdrPacket) { memset(hdrPacket, 0, sizeof *hdrPacket); hdrPacket->version = HGFS_HEADER_VERSION; hdrPacket->dummy = HGFS_OP_NEW_HEADER; hdrPacket->packetSize = payloadSize + sizeof *hdrPacket; hdrPacket->headerSize = sizeof *hdrPacket; hdrPacket->requestId = requestId; hdrPacket->op = opcode; hdrPacket->status = status; hdrPacket->flags = hdrFlags; hdrPacket->information = status; hdrPacket->sessionId = sessionId; result = TRUE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsPackLegacyReplyHeader -- * * Pack pre-V4 reply header. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsPackLegacyReplyHeader(HgfsStatus status, // IN: reply status HgfsHandle id, // IN: original packet id size_t hdrPacketSize, // IN: header packet size HgfsReply *hdrPacket) // OUT: outgoing packet header { Bool result = FALSE; if (hdrPacketSize >= sizeof *hdrPacket) { memset(hdrPacket, 0, sizeof *hdrPacket); hdrPacket->status = status; hdrPacket->id = id; result = TRUE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsPackReplyHeader -- * * Pack hgfs header that corresponds to an HGFS protocol packet. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackReplyHeader(HgfsInternalStatus status, // IN: reply status uint32 payloadSize, // IN: size of the reply payload Bool sessionEnabledHeader, // IN: session enabled header uint64 sessionId, // IN: session id uint32 requestId, // IN: request id HgfsOp opcode, // IN: request operation uint32 hdrFlags, // IN: header flags size_t hdrPacketSize, // IN: header packet size void *hdrPacket) // OUT: outgoing packet header { HgfsStatus replyStatus; Bool result; if (NULL == hdrPacket) { result = FALSE; goto exit; } replyStatus = HgfsConvertFromInternalStatus(status); if (sessionEnabledHeader) { result = HgfsPackReplyHeaderV4(replyStatus, payloadSize, opcode, sessionId, requestId, HGFS_PACKET_FLAG_REPLY, hdrPacketSize, hdrPacket); } else { result = HgfsPackLegacyReplyHeader(replyStatus, requestId, hdrPacketSize, hdrPacket); } exit: return result; } /* *----------------------------------------------------------------------------- * * HgfsPackOpenReplyV3 -- * * Pack hgfs open V3 reply payload to the HgfsReplyOpenV3 structure. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackOpenReplyV3(HgfsFileOpenInfo *openInfo, // IN: open info struct HgfsReplyOpenV3 *reply) // OUT: size of packet { reply->file = openInfo->file; reply->reserved = 0; reply->flags = 0; if (openInfo->mask & HGFS_OPEN_VALID_SERVER_LOCK) { reply->acquiredLock = openInfo->acquiredLock; } else { reply->acquiredLock = HGFS_LOCK_NONE; } } /* *----------------------------------------------------------------------------- * * HgfsPackOpenV2Reply -- * * Pack hgfs open V2 reply payload to the HgfsReplyOpenV3 structure. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackOpenV2Reply(HgfsFileOpenInfo *openInfo, // IN: open info struct HgfsReplyOpenV2 *reply) // OUT: reply payload { reply->file = openInfo->file; if (openInfo->mask & HGFS_OPEN_VALID_SERVER_LOCK) { reply->acquiredLock = openInfo->acquiredLock; } else { reply->acquiredLock = HGFS_LOCK_NONE; } } /* *----------------------------------------------------------------------------- * * HgfsPackOpenV1Reply -- * * Pack hgfs open V1 reply payload to the HgfsReplyOpenV3 structure. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackOpenV1Reply(HgfsFileOpenInfo *openInfo, // IN: open info struct HgfsReplyOpen *reply) // OUT: reply payload { reply->file = openInfo->file; } /* *----------------------------------------------------------------------------- * * HgfsPackOpenReply -- * * Pack hgfs open reply to the HgfsReplyOpen{V2} structure. * * Results: * Always TRUE, FALSE if bad opcode. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsFileOpenInfo *openInfo, // IN: open info struct size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; ASSERT(openInfo); HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; switch (openInfo->requestType) { case HGFS_OP_OPEN_V3: { HgfsReplyOpenV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); HgfsPackOpenReplyV3(openInfo, reply); *payloadSize = sizeof *reply; break; } case HGFS_OP_OPEN_V2: { HgfsReplyOpenV2 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); HgfsPackOpenV2Reply(openInfo, reply); *payloadSize = sizeof *reply; break; } case HGFS_OP_OPEN: { HgfsReplyOpen *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); HgfsPackOpenV1Reply(openInfo, reply); *payloadSize = sizeof *reply; break; } default: NOT_REACHED(); result = FALSE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackClosePayload -- * * Unpack hgfs close payload to get the handle which need to be closed. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackClosePayload(const HgfsRequestClose *request, // IN: payload size_t payloadSize, // IN: payload size HgfsHandle* file) // OUT: HGFS handle to close { LOG(4, "%s: HGFS_OP_CLOSE\n", __FUNCTION__); if (payloadSize >= sizeof *request) { *file = request->file; return TRUE; } return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackClosePayloadV3 -- * * Unpack hgfs close payload V3 to get the handle which need to be closed. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackClosePayloadV3(const HgfsRequestCloseV3 *requestV3, // IN: payload size_t payloadSize, // IN: payload size HgfsHandle* file) // OUT: HGFS handle to close { LOG(4, "%s: HGFS_OP_CLOSE_V3\n", __FUNCTION__); if (payloadSize >= sizeof *requestV3) { *file = requestV3->file; return TRUE; } LOG(4, "%s: Too small HGFS packet\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackCloseRequest -- * * Unpack hgfs close request to get the handle to close. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackCloseRequest(const void *packet, // IN: request packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type HgfsHandle *file) // OUT: Handle to close { ASSERT(packet); switch (op) { case HGFS_OP_CLOSE_V3: { const HgfsRequestCloseV3 *requestV3 = packet; if (!HgfsUnpackClosePayloadV3(requestV3, packetSize, file)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_CLOSE: { const HgfsRequestClose *requestV1 = packet; if (!HgfsUnpackClosePayload(requestV1, packetSize, file)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } default: NOT_REACHED(); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackCloseReply -- * * Pack hgfs close reply to the HgfsReplyClose(V3) structure. * * Results: * Always TRUE, FALSE if bad opcode. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of packet excluding header HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; switch (op) { case HGFS_OP_CLOSE_V3: { HgfsReplyCloseV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); /* Reply consists of a reserved field only. */ reply->reserved = 0; *payloadSize = sizeof *reply; break; } case HGFS_OP_CLOSE: { HgfsReplyClose *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } default: NOT_REACHED(); result = FALSE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSearchClosePayload -- * * Unpack hgfs search close payload to get the search handle which need to be closed. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSearchClosePayload(const HgfsRequestSearchClose *request, // IN: payload size_t payloadSize, // IN: payload size HgfsHandle* search) // OUT: search to close { LOG(4, "%s: HGFS_OP_SEARCH_CLOSE\n", __FUNCTION__); if (payloadSize >= sizeof *request) { *search = request->search; return TRUE; } LOG(4, "%s: Too small HGFS packet\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSearchClosePayloadV3 -- * * Unpack hgfs search close payload V3 to get the search handle which need to * be closed. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSearchClosePayloadV3(const HgfsRequestSearchCloseV3 *requestV3, // IN: payload size_t payloadSize, // IN: payload size HgfsHandle* search) // OUT: search { LOG(4, "%s: HGFS_OP_SEARCH_CLOSE_V3\n", __FUNCTION__); if (payloadSize >= sizeof *requestV3) { *search = requestV3->search; return TRUE; } LOG(4, "%s: Too small HGFS packet\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSearchCloseRequest -- * * Unpack hgfs search close request to get the search handle. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackSearchCloseRequest(const void *packet, // IN: request packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type HgfsHandle *search) // OUT: search to close { ASSERT(packet); switch (op) { case HGFS_OP_SEARCH_CLOSE_V3: { const HgfsRequestSearchCloseV3 *requestV3 = packet; if (!HgfsUnpackSearchClosePayloadV3(requestV3, packetSize, search)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_SEARCH_CLOSE: { const HgfsRequestSearchClose *requestV1 = packet; if (!HgfsUnpackSearchClosePayload(requestV1, packetSize, search)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } default: NOT_REACHED(); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackSearchCloseReply -- * * Pack hgfs SearchClose reply into a HgfsReplySearchClose(V3) structure. * * Results: * Always TRUE, except when it is called with a * wrong op or insufficient output buffer (which is a programming error). * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackSearchCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; switch (op) { case HGFS_OP_SEARCH_CLOSE_V3: { HgfsReplyCloseV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); /* Reply consists of only a reserved field. */ reply->reserved = 0; *payloadSize = sizeof *reply; break; } case HGFS_OP_SEARCH_CLOSE: { HgfsReplyClose *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } default: NOT_REACHED(); result = FALSE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackFileName -- * * Unpack HgfsFileName into a pointer to a CPName and size of the name. * Verifies that input buffer has enough space to hold the name. * * Results: * TRUE on success, FALSE on failure (buffer too small). * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackFileName(const HgfsFileName *name, // IN: file name size_t maxNameSize, // IN: space allocated for the name const char **cpName, // OUT: CP name size_t *cpNameSize) // OUT: CP name size { /* * The request file name length is user-provided, so this test must be * carefully written to prevent wraparounds. */ if (name->length > maxNameSize) { /* The input packet is smaller than the request. */ return FALSE; } *cpName = name->name; *cpNameSize = name->length; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackFileNameV3 -- * * Unpack HgfsFileNameV3 into a pointer to a CPName and size of the name * or into file handle. * Verifies that input buffer has enough space to hold the name. * * Results: * TRUE on success, FALSE on failure (buffer too small). * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackFileNameV3(const HgfsFileNameV3 *name, // IN: file name size_t maxNameSize, // IN: space allocated for the name Bool *useHandle, // OUT: file name or handle returned? const char **cpName, // OUT: CP name size_t *cpNameSize, // OUT: CP name size HgfsHandle *file, // OUT: HGFS file handle uint32 *caseFlags) // OUT: case-sensitivity flags { *useHandle = FALSE; *file = HGFS_INVALID_HANDLE; *cpName = NULL; *cpNameSize = 0; /* * If we've been asked to reuse a handle, we don't need to look at, let * alone test the filename or its length. */ if (name->flags & HGFS_FILE_NAME_USE_FILE_DESC) { *file = name->fid; *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; *useHandle = TRUE; } else { /* * The request file name length is user-provided, so this test must be * carefully written to prevent wraparounds. */ if (name->length > maxNameSize) { /* The input packet is smaller than the request */ LOG(4, "%s: Error unpacking file name - buffer too small\n", __FUNCTION__); return FALSE; } *cpName = name->name; *cpNameSize = name->length; *caseFlags = name->caseType; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackDeletePayloadV3 -- * * Unpack hgfs delete request V3 payload and initialize a corresponding * HgfsHandle or file name to tell us which to delete. Hints * holds flags to specify a handle or name for the file or * directory to delete. * * Since the structure of the get delete request packet is the same * for Delete File or Directory of the protocol, code is identical for * both operations. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackDeletePayloadV3(const HgfsRequestDeleteV3 *requestV3, // IN: request payload size_t payloadSize, // IN: payload size const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsDeleteHint *hints, // OUT: delete hints HgfsHandle *file, // OUT: file handle uint32 *caseFlags) // OUT: case-sensitivity flags { Bool result = TRUE; Bool useHandle; if (payloadSize < sizeof *requestV3) { result = FALSE; goto exit; } *hints = requestV3->hints; if (!HgfsUnpackFileNameV3(&requestV3->fileName, payloadSize - sizeof *requestV3, &useHandle, cpName, cpNameSize, file, caseFlags)) { result = FALSE; goto exit; } if (useHandle) { *hints |= HGFS_DELETE_HINT_USE_FILE_DESC; } exit: LOG(8, "%s: unpacking HGFS_OP_DELETE_DIR/FILE_V3 -> %d\n", __FUNCTION__, result); return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackDeletePayloadV2 -- * * Unpack hgfs delete request V2 payload and initialize a corresponding * HgfsHandle or file name to tell us which to delete. Hints * holds flags to specify a handle or name for the file or * directory to delete. * * Since the structure of the get delete request packet is the same * for Delete File or Directory of the protocol, code is identical for * both operations. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackDeletePayloadV2(const HgfsRequestDeleteV2 *requestV2, // IN: request payload size_t payloadSize, // IN: payload size const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsDeleteHint *hints, // OUT: delete hints HgfsHandle *file) // OUT: file handle { Bool result = TRUE; /* Enforced by the dispatch function. */ ASSERT(payloadSize >= sizeof *requestV2); *file = HGFS_INVALID_HANDLE; *hints = requestV2->hints; /* * If we've been asked to reuse a handle, we don't need to look at, let * alone test the filename or its length. */ if (requestV2->hints & HGFS_DELETE_HINT_USE_FILE_DESC) { *file = requestV2->file; *cpName = NULL; *cpNameSize = 0; } else { result = HgfsUnpackFileName(&requestV2->fileName, payloadSize - sizeof *requestV2, cpName, cpNameSize); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackDeletePayloadV1 -- * * Unpack hgfs delete request V1 payload and initialize a corresponding * file name to tell us which to delete. * * Since the structure of the get delete request packet is the same * for Delete File or Directory of the protocol, code is identical for * both operations. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackDeletePayloadV1(const HgfsRequestDelete *requestV1, // IN: request payload size_t payloadSize, // IN: payload size const char **cpName, // OUT: cpName size_t *cpNameSize) // OUT: cpName size { return HgfsUnpackFileName(&requestV1->fileName, payloadSize - sizeof *requestV1, cpName, cpNameSize); } /* *----------------------------------------------------------------------------- * * HgfsUnpackDeleteRequest -- * * Unpack hgfs delete request and initialize a corresponding * HgfsHandle or file name to tell us which to delete. Hints * holds flags to specify a handle or name for the file or * directory to delete. * * Since the structure of the get delete request packet is the same * for Delete File or Directory of the protocol, code is identical for * both operations. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackDeleteRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: requested operation const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsDeleteHint *hints, // OUT: delete hints HgfsHandle *file, // OUT: file handle uint32 *caseFlags) // OUT: case-sensitivity flags { ASSERT(packet); ASSERT(cpName); ASSERT(cpNameSize); ASSERT(file); ASSERT(hints); ASSERT(caseFlags); *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; *hints = 0; *file = HGFS_INVALID_HANDLE; switch (op) { case HGFS_OP_DELETE_FILE_V3: case HGFS_OP_DELETE_DIR_V3: { const HgfsRequestDeleteV3 *requestV3 = packet; if (!HgfsUnpackDeletePayloadV3(requestV3, packetSize, cpName, cpNameSize, hints, file, caseFlags)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_DELETE_FILE_V2: case HGFS_OP_DELETE_DIR_V2: { const HgfsRequestDeleteV2 *requestV2 = packet; if (!HgfsUnpackDeletePayloadV2(requestV2, packetSize, cpName, cpNameSize, hints, file)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_DELETE_FILE: case HGFS_OP_DELETE_DIR: { const HgfsRequestDelete *requestV1 = packet; if (!HgfsUnpackDeletePayloadV1(requestV1, packetSize, cpName, cpNameSize)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } default: NOT_REACHED(); LOG(4, "%s: Invalid opcode\n", __FUNCTION__); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackDeleteReply -- * * Pack hgfs delete reply. * Since the structure of the delete reply packet hasn't changed in * version 2 of the protocol, HgfsReplyDeleteV2 is identical to * HgfsReplyDelete. So use HgfsReplyDelete type to access packetIn to * keep the code simple. * * Results: * TRUE if valid op version reply filled, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackDeleteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: requested operation size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; /* No reply payload, just header. */ switch (op) { case HGFS_OP_DELETE_FILE_V3: case HGFS_OP_DELETE_DIR_V3: { HgfsReplyDeleteV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } case HGFS_OP_DELETE_FILE_V2: case HGFS_OP_DELETE_FILE: case HGFS_OP_DELETE_DIR_V2: case HGFS_OP_DELETE_DIR: { HgfsReplyDelete *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } default: LOG(4, "%s: invalid op code %d\n", __FUNCTION__, op); result = FALSE; NOT_REACHED(); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackRenamePayloadV3 -- * * Unpack hgfs rename request V3 payload and initialize a corresponding * HgfsHandles or file names to tell us old and new names/handles. Hints * holds flags to specify a handle or name for the file or * directory to rename. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackRenamePayloadV3(const HgfsRequestRenameV3 *requestV3, // IN: request payload size_t payloadSize, // IN: payload size const char **cpOldName, // OUT: rename src size_t *cpOldNameLen, // OUT: rename src size const char **cpNewName, // OUT: rename dst size_t *cpNewNameLen, // OUT: rename dst size HgfsRenameHint *hints, // OUT: rename hints HgfsHandle *srcFile, // OUT: src file handle HgfsHandle *targetFile, // OUT: target file handle uint32 *oldCaseFlags, // OUT: source case flags uint32 *newCaseFlags) // OUT: dest. case flags { size_t extra; const HgfsFileNameV3 *newName; Bool useHandle; LOG(4, "%s: HGFS_OP_RENAME_V3\n", __FUNCTION__); if (payloadSize < sizeof *requestV3) { return FALSE; } extra = payloadSize - sizeof *requestV3; *hints = requestV3->hints; /* * Get the old and new filenames from the request. * * Getting the new filename is somewhat inconvenient, because we * don't know where request->newName actually starts, thanks to the * fact that request->oldName is of variable length. We get around * this by using an HgfsFileName*, assigning it to the correct address * just after request->oldName ends, and using that to access the * new name. */ /* * If we've been asked to reuse a handle, we don't need to look at, let * alone test the filename or its length. This applies to the source * and the target. */ if (!HgfsUnpackFileNameV3(&requestV3->oldName, extra, &useHandle, cpOldName, cpOldNameLen, srcFile, oldCaseFlags)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } if (useHandle) { *hints |= HGFS_RENAME_HINT_USE_SRCFILE_DESC; newName = &requestV3->newName; } else { newName = (const HgfsFileNameV3 *)(requestV3->oldName.name + 1 + *cpOldNameLen); extra -= *cpOldNameLen; } if (!HgfsUnpackFileNameV3(newName, extra, &useHandle, cpNewName, cpNewNameLen, targetFile, newCaseFlags)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } if (useHandle) { *hints |= HGFS_RENAME_HINT_USE_TARGETFILE_DESC; } LOG(8, "%s: unpacking HGFS_OP_RENAME_V3 -> success\n", __FUNCTION__); return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackRenamePayloadV2 -- * * Unpack hgfs rename request V2 payload and initialize a corresponding * HgfsHandle or file name to tell us which to delete. Hints * holds flags to specify a handle or name for the file or * directory to rename. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackRenamePayloadV2(const HgfsRequestRenameV2 *requestV2, // IN: request payload size_t payloadSize, // IN: payload size const char **cpOldName, // OUT: rename src size_t *cpOldNameLen, // OUT: rename src size const char **cpNewName, // OUT: rename dst size_t *cpNewNameLen, // OUT: rename dst size HgfsRenameHint *hints, // OUT: rename hints HgfsHandle *srcFile, // OUT: src file handle HgfsHandle *targetFile) // OUT: target file handle { const HgfsFileName *newName; size_t extra; /* Enforced by the dispatch function. */ if (payloadSize < sizeof *requestV2) { LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } extra = payloadSize - sizeof *requestV2; *hints = requestV2->hints; /* * If we've been asked to reuse a handle, we don't need to look at, let * alone test the filename or its length. This applies to the source * and the target. */ if (*hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) { *srcFile = requestV2->srcFile; *cpOldName = NULL; *cpOldNameLen = 0; } else { if (!HgfsUnpackFileName(&requestV2->oldName, extra, cpOldName, cpOldNameLen)) { LOG(4, "%s: Error decoding HGFS packet - not enough room for file name\n", __FUNCTION__); return FALSE; } extra -= *cpOldNameLen; } if (*hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) { *targetFile = requestV2->targetFile; *cpNewName = NULL; *cpNewNameLen = 0; } else { newName = (const HgfsFileName *)((char *)(&requestV2->oldName + 1) + *cpOldNameLen); /* * The HgfsRequestRenameV2 structure overlay on the data has the old and * new data interlaced rather. The newName pointer in the data is * calculated as an offset from the oldName field. This confuses Coverity, * there is no overrun here. */ /* coverity[overrun-local] */ if (!HgfsUnpackFileName(newName, extra, cpNewName, cpNewNameLen)) { LOG(4, "%s: Error decoding HGFS packet - not enough room for file name\n", __FUNCTION__); return FALSE; } } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackRenamePayloadV1 -- * * Unpack hgfs rename request V1 payload and initialize a corresponding * old and new file names. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackRenamePayloadV1(const HgfsRequestRename *requestV1, // IN: request payload size_t payloadSize, // IN: payload size const char **cpOldName, // OUT: rename src size_t *cpOldNameLen, // OUT: rename src size const char **cpNewName, // OUT: rename dst size_t *cpNewNameLen) // OUT: rename dst size { const HgfsFileName *newName; uint32 extra; if (payloadSize < sizeof *requestV1) { return FALSE; } extra = payloadSize - sizeof *requestV1; if (!HgfsUnpackFileName(&requestV1->oldName, extra, cpOldName, cpOldNameLen)) { LOG(4, "%s: Error decoding HGFS packet - not enough room for file name\n", __FUNCTION__); return FALSE; } extra -= requestV1->oldName.length; newName = (const HgfsFileName *)((char *)(&requestV1->oldName + 1) + requestV1->oldName.length); return HgfsUnpackFileName(newName, extra, cpNewName, cpNewNameLen); } /* *----------------------------------------------------------------------------- * * HgfsUnpackRenameRequest -- * * Unpack hgfs rename request and initialize a corresponding * HgfsHandle or file name to tell us which to rename. Hints * holds flags to specify a handle or name for the file or * directory to rename. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackRenameRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: requested operation const char **cpOldName, // OUT: rename src size_t *cpOldNameLen, // OUT: rename src size const char **cpNewName, // OUT: rename dst size_t *cpNewNameLen, // OUT: rename dst size HgfsRenameHint *hints, // OUT: rename hints HgfsHandle *srcFile, // OUT: src file handle HgfsHandle *targetFile, // OUT: target file handle uint32 *oldCaseFlags, // OUT: source case-sensitivity flags uint32 *newCaseFlags) // OUT: dest. case-sensitivity flags { ASSERT(packet); ASSERT(cpOldName); ASSERT(cpOldNameLen); ASSERT(cpNewName); ASSERT(cpNewNameLen); ASSERT(srcFile); ASSERT(targetFile); ASSERT(hints); ASSERT(oldCaseFlags); ASSERT(newCaseFlags); /* Default values for legacy requests. */ *oldCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE; *newCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE; *hints = 0; switch (op) { case HGFS_OP_RENAME_V3: { const HgfsRequestRenameV3 *requestV3 = packet; if (!HgfsUnpackRenamePayloadV3(requestV3, packetSize, cpOldName, cpOldNameLen, cpNewName, cpNewNameLen, hints, srcFile, targetFile, oldCaseFlags, newCaseFlags)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_RENAME_V2: { const HgfsRequestRenameV2 *requestV2 = packet; if (!HgfsUnpackRenamePayloadV2(requestV2, packetSize, cpOldName, cpOldNameLen, cpNewName, cpNewNameLen, hints, srcFile, targetFile)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_RENAME: { const HgfsRequestRename *requestV1 = packet; if (!HgfsUnpackRenamePayloadV1(requestV1, packetSize, cpOldName, cpOldNameLen, cpNewName, cpNewNameLen)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } default: LOG(4, "%s: Invalid opcode %d\n", __FUNCTION__, op); NOT_REACHED(); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackRenameReply -- * * Pack hgfs rename reply. * Since the structure of the rename reply packet hasn't changed in * version 2 of the protocol, HgfsReplyRenameV2 is identical to * HgfsReplyRename. So use HgfsReplyRename type to access packetIn to * keep the code simple. * * Results: * TRUE if valid op and reply set, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackRenameReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: requested operation size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; switch (op) { case HGFS_OP_RENAME_V3: { HgfsReplyRenameV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); /* Reply consists of only a reserved field. */ reply->reserved = 0; *payloadSize = sizeof *reply; break; } case HGFS_OP_RENAME_V2: case HGFS_OP_RENAME: { HgfsReplyRename *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } default: LOG(4, "%s: invalid op code %d\n", __FUNCTION__, op); result = FALSE; NOT_REACHED(); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackGetattrPayloadV3 -- * * Unpack hgfs get attr request V3 payload and initialize a corresponding * HgfsHandle or file name to tell us which file to get attributes. Hints * holds flags to specify a handle or name for the file or * directory to get attributes. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackGetattrPayloadV3(const HgfsRequestGetattrV3 *requestV3,// IN: request payload size_t payloadSize, // IN: payload size const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsAttrHint *hints, // OUT: getattr hints HgfsHandle *file, // OUT: file handle uint32 *caseFlags) // OUT: case-sensitivity flags { Bool result = TRUE; Bool useHandle; if (payloadSize < sizeof *requestV3) { result = FALSE; goto exit; } *hints = requestV3->hints; if (!HgfsUnpackFileNameV3(&requestV3->fileName, payloadSize - sizeof *requestV3, &useHandle, cpName, cpNameSize, file, caseFlags)) { result = FALSE; goto exit; } if (useHandle) { *hints |= HGFS_ATTR_HINT_USE_FILE_DESC; } exit: LOG(8, "%s: unpacking HGFS_OP_GETATTR_V3 -> %d\n", __FUNCTION__, result); return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackGetattrPayloadV2 -- * * Unpack hgfs Getattr request V2 payload and initialize a corresponding * HgfsHandle or file name to tell us which to get attributes. Hints * holds flags to specify a handle or name for the file or * directory to get attributes. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackGetattrPayloadV2(const HgfsRequestGetattrV2 *requestV2,// IN: request payload size_t payloadSize, // IN: payload size const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsAttrHint *hints, // OUT: delete hints HgfsHandle *file) // OUT: file handle { Bool result = TRUE; if (payloadSize < sizeof *requestV2) { return FALSE; } *file = HGFS_INVALID_HANDLE; *hints = requestV2->hints; /* * If we've been asked to reuse a handle, we don't need to look at, let * alone test the filename or its length. */ if (requestV2->hints & HGFS_ATTR_HINT_USE_FILE_DESC) { *file = requestV2->file; *cpName = NULL; *cpNameSize = 0; } else { result = HgfsUnpackFileName(&requestV2->fileName, payloadSize - sizeof *requestV2, cpName, cpNameSize); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackGetattrPayloadV1 -- * * Unpack hgfs getattr request V1 payload and initialize a corresponding * file name to tell us which to get attributes. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackGetattrPayloadV1(const HgfsRequestGetattr *requestV1, // IN: request payload size_t payloadSize, // IN: payload size const char **cpName, // OUT: cpName size_t *cpNameSize) // OUT: cpName size { return HgfsUnpackFileName(&requestV1->fileName, payloadSize - sizeof *requestV1, cpName, cpNameSize); } /* *----------------------------------------------------------------------------- * * HgfsPackAttrV2 -- * * Packs attr version 2 reply structure. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackAttrV2(HgfsFileAttrInfo *attr, // IN: attr stucture HgfsAttrV2 *attr2) // OUT: attr in payload { attr2->mask = attr->mask; attr2->type = attr->type; attr2->size = attr->size; attr2->creationTime = attr->creationTime; attr2->accessTime = attr->accessTime; attr2->writeTime = attr->writeTime; attr2->attrChangeTime = attr->attrChangeTime; attr2->specialPerms = attr->specialPerms; attr2->ownerPerms = attr->ownerPerms; attr2->groupPerms = attr->groupPerms; attr2->otherPerms = attr->otherPerms; attr2->flags = attr->flags; attr2->allocationSize = attr->allocationSize; attr2->userId = attr->userId; attr2->groupId = attr->groupId; attr2->hostFileId = attr->hostFileId; attr2->volumeId = attr->volumeId; attr2->effectivePerms = attr->effectivePerms; } /* *----------------------------------------------------------------------------- * * HgfsUnpackAttrV2 -- * * Unpacks attr version 2 reply structure. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsUnpackAttrV2(const HgfsAttrV2 *attr2, // IN: attr in payload HgfsFileAttrInfo *attr) // OUT: attr stucture { attr->mask = attr2->mask; attr->type = attr2->type; attr->size = attr2->size; attr->creationTime = attr2->creationTime; attr->accessTime = attr2->accessTime; attr->writeTime = attr2->writeTime; attr->attrChangeTime = attr2->attrChangeTime; attr->specialPerms = attr2->specialPerms; attr->ownerPerms = attr2->ownerPerms; attr->groupPerms = attr2->groupPerms; attr->otherPerms = attr2->otherPerms; attr->flags = attr2->flags; attr->allocationSize = attr2->allocationSize; attr->userId = attr2->userId; attr->groupId = attr2->groupId; attr->hostFileId = attr2->hostFileId; attr->volumeId = attr2->volumeId; attr->effectivePerms = attr2->effectivePerms; } /* *----------------------------------------------------------------------------- * * HgfsInitFileAttr -- * * Initializes HgfsFileAttrInfo structure. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsInitFileAttr(HgfsOp op, // IN: request type HgfsFileAttrInfo *attr) // OUT: attr stucture { /* Initialize all fields with 0. */ memset(attr, 0, sizeof *attr); /* Explicitly initialize fields which need it. */ attr->requestType = op; attr->mask = HGFS_ATTR_VALID_NONE; } /* *----------------------------------------------------------------------------- * * HgfsPackGetattrReplyPayloadV3 -- * * Packs Getattr V3 reply payload. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackGetattrReplyPayloadV3(HgfsFileAttrInfo *attr, // IN: attr stucture const char *utf8TargetName, // IN: optional target name uint32 utf8TargetNameLen, // IN: file name length HgfsReplyGetattrV3 *reply) // OUT: payload { LOG(4, "%s: attr type: %u\n", __FUNCTION__, attr->type); HgfsPackAttrV2(attr, &reply->attr); reply->reserved = 0; if (utf8TargetName) { memcpy(reply->symlinkTarget.name, utf8TargetName, utf8TargetNameLen); CPNameLite_ConvertTo(reply->symlinkTarget.name, utf8TargetNameLen, DIRSEPC); } else { ASSERT(utf8TargetNameLen == 0); } reply->symlinkTarget.length = utf8TargetNameLen; reply->symlinkTarget.name[utf8TargetNameLen] = '\0'; reply->symlinkTarget.flags = 0; reply->symlinkTarget.fid = 0; reply->symlinkTarget.caseType = HGFS_FILE_NAME_DEFAULT_CASE; } /* *----------------------------------------------------------------------------- * * HgfsPackGetattrReplyPayloadV2 -- * * Packs rename reply payload V2 requests. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackGetattrReplyPayloadV2(HgfsFileAttrInfo *attr, // IN: attr stucture const char *utf8TargetName, // IN: optional target name uint32 utf8TargetNameLen, // IN: file name length HgfsReplyGetattrV2 *reply) // OUT: payload { HgfsPackAttrV2(attr, &reply->attr); if (utf8TargetName) { memcpy(reply->symlinkTarget.name, utf8TargetName, utf8TargetNameLen); CPNameLite_ConvertTo(reply->symlinkTarget.name, utf8TargetNameLen, DIRSEPC); } else { ASSERT(utf8TargetNameLen == 0); } reply->symlinkTarget.length = utf8TargetNameLen; reply->symlinkTarget.name[utf8TargetNameLen] = '\0'; } /* *----------------------------------------------------------------------------- * * HgfsPackGetattrReplyPayloadV1 -- * * Packs rename reply payload for V1 requests. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackGetattrReplyPayloadV1(HgfsFileAttrInfo *attr, // IN: attr stucture HgfsReplyGetattr *reply) // OUT: reply info { /* In GetattrV1, symlinks are treated as regular files. */ if (attr->type == HGFS_FILE_TYPE_SYMLINK) { reply->attr.type = HGFS_FILE_TYPE_REGULAR; } else { reply->attr.type = attr->type; } reply->attr.size = attr->size; reply->attr.creationTime = attr->creationTime; reply->attr.accessTime = attr->accessTime; reply->attr.writeTime = attr->writeTime; reply->attr.attrChangeTime = attr->attrChangeTime; reply->attr.permissions = attr->ownerPerms; } /* *----------------------------------------------------------------------------- * * HgfsUnpackGetattrRequest -- * * Unpack hgfs getattr request and initialize a corresponding * HgfsFileAttrInfo structure that is used to pass around getattr request * information. * * Since the structure of the get attributes request packet hasn't changed * in version 2 of the protocol, HgfsRequestGetattrV2 is identical to * HgfsRequestGetattr. So use HgfsRequestGetattr type to access packetIn to * keep the code simple. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackGetattrRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN request type HgfsFileAttrInfo *attrInfo, // IN/OUT: getattr info HgfsAttrHint *hints, // OUT: getattr hints const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsHandle *file, // OUT: file handle uint32 *caseType) // OUT: case-sensitivity flags { ASSERT(packet); ASSERT(attrInfo); ASSERT(cpName); ASSERT(cpNameSize); ASSERT(file); ASSERT(caseType); HgfsInitFileAttr(op, attrInfo); /* Default values for legacy requests. */ *caseType = HGFS_FILE_NAME_DEFAULT_CASE; *hints = 0; *file = HGFS_INVALID_HANDLE; switch (op) { case HGFS_OP_GETATTR_V3: { const HgfsRequestGetattrV3 *requestV3 = packet; if (!HgfsUnpackGetattrPayloadV3(requestV3, packetSize, cpName, cpNameSize, hints, file, caseType)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } LOG(4, "%s: HGFS_OP_GETATTR_V3: %u\n", __FUNCTION__, *caseType); break; } case HGFS_OP_GETATTR_V2: { const HgfsRequestGetattrV2 *requestV2 = packet; if (!HgfsUnpackGetattrPayloadV2(requestV2, packetSize, cpName, cpNameSize, hints, file)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_GETATTR: { const HgfsRequestGetattr *requestV1 = packet; if (!HgfsUnpackGetattrPayloadV1(requestV1, packetSize, cpName, cpNameSize)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } default: return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackGetattrReply -- * * Pack hgfs getattr reply to the HgfsReplyGetattr structure. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackGetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsFileAttrInfo *attr, // IN: attr stucture const char *utf8TargetName, // IN: optional target name uint32 utf8TargetNameLen, // IN: file name length size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; switch (attr->requestType) { case HGFS_OP_GETATTR_V3: { HgfsReplyGetattrV3 *reply; *payloadSize = sizeof *reply + utf8TargetNameLen; reply = HgfsAllocInitReply(packet, packetHeader, *payloadSize, session); HgfsPackGetattrReplyPayloadV3(attr, utf8TargetName, utf8TargetNameLen, reply); break; } case HGFS_OP_GETATTR_V2: { HgfsReplyGetattrV2 *reply; *payloadSize = sizeof *reply + utf8TargetNameLen; reply = HgfsAllocInitReply(packet, packetHeader, *payloadSize, session); HgfsPackGetattrReplyPayloadV2(attr, utf8TargetName, utf8TargetNameLen, reply); break; } case HGFS_OP_GETATTR: { HgfsReplyGetattr *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); HgfsPackGetattrReplyPayloadV1(attr, reply); *payloadSize = sizeof *reply; break; } default: LOG(4, "%s: Invalid GetAttr op.\n", __FUNCTION__); NOT_REACHED(); result = FALSE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyHeaderV4 -- * * Packs SearchRead V4 reply header part for all entry records returned. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSearchReadReplyHeaderV4(HgfsSearchReadInfo *info, // IN: reply info HgfsReplySearchReadV4 *reply, // OUT: payload size_t *headerSize) // OUT: size written { reply->numberEntriesReturned = info->numberRecordsWritten; reply->offsetToContinue = info->currentIndex; reply->flags = info->replyFlags; reply->reserved = 0; *headerSize = offsetof(HgfsReplySearchReadV4, entries); } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyRecordV4 -- * * Packs SearchRead V4 reply record. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSearchReadReplyRecordV4(HgfsSearchReadEntry *entry, // IN: entry info HgfsDirEntryV4 *replylastEntry, // IN/OUT: payload HgfsDirEntryV4 *replyCurrentEntry) // OUT: reply buffer for dirent { HgfsFileAttrInfo *attr = &entry->attr; memset(replyCurrentEntry, 0, sizeof *replyCurrentEntry); if (NULL != replylastEntry) { replylastEntry->nextEntryOffset = ((char*)replyCurrentEntry - (char*)replylastEntry); } /* Set the valid data mask for the entry. */ replyCurrentEntry->mask = entry->mask; if (0 != (entry->mask & HGFS_SEARCH_READ_NAME)) { replyCurrentEntry->nextEntryOffset = 0; replyCurrentEntry->fileIndex = entry->fileIndex; if (0 != (replyCurrentEntry->mask & HGFS_SEARCH_READ_FILE_NODE_TYPE)) { replyCurrentEntry->fileType = attr->type; } if (0 != (entry->mask & HGFS_SEARCH_READ_FILE_SIZE)) { replyCurrentEntry->fileSize = attr->size; } if (0 != (entry->mask & HGFS_SEARCH_READ_ALLOCATION_SIZE)) { replyCurrentEntry->allocationSize = attr->allocationSize; } if (0 != (entry->mask & HGFS_SEARCH_READ_TIME_STAMP)) { replyCurrentEntry->creationTime = attr->creationTime; replyCurrentEntry->accessTime = attr->accessTime; replyCurrentEntry->writeTime = attr->writeTime; replyCurrentEntry->attrChangeTime = attr->attrChangeTime; } if (0 != (entry->mask & HGFS_SEARCH_READ_FILE_ATTRIBUTES)) { replyCurrentEntry->attrFlags = attr->flags; } if (0 != (entry->mask & HGFS_SEARCH_READ_FILE_ID)) { replyCurrentEntry->hostFileId = attr->hostFileId; } if (0 != (entry->mask & HGFS_SEARCH_READ_EA_SIZE)) { replyCurrentEntry->eaSize = attr->eaSize; } if (0 != (entry->mask & HGFS_SEARCH_READ_REPARSE_TAG)) { replyCurrentEntry->reparseTag = attr->reparseTag; } if (0 != (entry->mask & HGFS_SEARCH_READ_SHORT_NAME)) { ASSERT(attr->shortName.length > 0); memcpy(replyCurrentEntry->shortName.name, attr->shortName.name, attr->shortName.length); replyCurrentEntry->shortName.length = attr->shortName.length; } memcpy(replyCurrentEntry->fileName.name, entry->name, entry->nameLength); replyCurrentEntry->fileName.name[entry->nameLength] = 0; replyCurrentEntry->fileName.length = entry->nameLength; replyCurrentEntry->reserved = 0; } } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyHeaderV3 -- * * Packs SearchRead V3 reply record. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSearchReadReplyHeaderV3(HgfsSearchReadInfo *info, // IN: reply info HgfsReplySearchReadV3 *reply, // OUT: payload size_t *headerSize) // OUT: size written { ASSERT(info->numberRecordsWritten <= 1 && 0 != (info->flags & HGFS_SEARCH_READ_SINGLE_ENTRY)); reply->count = info->numberRecordsWritten; reply->reserved = 0; /* * Previous shipping tools expect to account for a whole reply, * which is not strictly correct, but we are stuck with it. */ *headerSize = sizeof *reply; } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyRecordV3 -- * * Packs SearchRead V3 reply record. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSearchReadReplyRecordV3(HgfsFileAttrInfo *attr, // IN: attr stucture const char *utf8Name, // IN: file name uint32 utf8NameLen, // IN: file name length HgfsDirEntry *replyDirent) // OUT: reply buffer for dirent { replyDirent->fileName.length = (uint32)utf8NameLen; replyDirent->fileName.flags = 0; replyDirent->fileName.fid = 0; replyDirent->fileName.caseType = HGFS_FILE_NAME_DEFAULT_CASE; replyDirent->nextEntry = 0; if (utf8NameLen != 0) { memcpy(replyDirent->fileName.name, utf8Name, utf8NameLen); replyDirent->fileName.name[utf8NameLen] = 0; HgfsPackAttrV2(attr, &replyDirent->attr); } } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyHeaderV2 -- * * Packs SearchRead V2 reply header (common) part for all records. * V2 replies only contain a single record, so there is nothing to do here. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSearchReadReplyHeaderV2(HgfsSearchReadInfo *info, // IN: unused HgfsReplySearchReadV2 *reply, // OUT: unused size_t *headerSize) // OUT: size written { /* The header has already been accounted for. */ *headerSize = sizeof *reply; } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyRecordV2 -- * * Packs SearchRead V2 reply record. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSearchReadReplyRecordV2(HgfsFileAttrInfo *attr, // IN: attr stucture const char *utf8Name, // IN: file name uint32 utf8NameLen, // IN: file name length HgfsReplySearchReadV2 *reply) // OUT: reply buffer { reply->fileName.length = (uint32)utf8NameLen; if (utf8NameLen != 0) { memcpy(reply->fileName.name, utf8Name, utf8NameLen); reply->fileName.name[utf8NameLen] = 0; HgfsPackAttrV2(attr, &reply->attr); } } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyHeaderV1 -- * * Packs SearchRead V1 reply header (common) part for all records. * V1 replies only contain a single record, so there is nothing to do here. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSearchReadReplyHeaderV1(HgfsSearchReadInfo *info, // IN: unused HgfsReplySearchRead *reply, // OUT: unused size_t *headerSize) // OUT: size written { /* The header has already been accounted for. */ *headerSize = sizeof *reply; } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyRecordV1 -- * * Packs SearchRead V1 reply record. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSearchReadReplyRecordV1(HgfsFileAttrInfo *attr, // IN: attr stucture const char *utf8Name, // IN: file name uint32 utf8NameLen, // IN: file name length HgfsReplySearchRead *reply) // OUT: reply buffer { reply->fileName.length = (uint32)utf8NameLen; if (utf8NameLen != 0) { memcpy(reply->fileName.name, utf8Name, utf8NameLen); reply->fileName.name[utf8NameLen] = 0; /* In SearchReadV1, symlinks are treated as regular files. */ if (attr->type == HGFS_FILE_TYPE_SYMLINK) { reply->attr.type = HGFS_FILE_TYPE_REGULAR; } else { reply->attr.type = attr->type; } reply->attr.size = attr->size; reply->attr.creationTime = attr->creationTime; reply->attr.accessTime = attr->accessTime; reply->attr.writeTime = attr->writeTime; reply->attr.attrChangeTime = attr->attrChangeTime; reply->attr.permissions = attr->ownerPerms; } } /* *----------------------------------------------------------------------------- * * HgfsUnpackSearchReadRequest -- * * Unpack hgfs search read request and initialize a corresponding * HgfsFileAttrInfo structure that is used to pass around attribute * information. * * Since the structure of the search read request packet hasn't changed in * version 2 of the protocol, HgfsRequestSearchReadV2 is identical to * HgfsRequestSearchRead. So use HgfsRequestSearchRead type to access * packetIn to keep the code simple. * * Results: * Always TRUE. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackSearchReadRequest(const void *packet, // IN: request packet size_t packetSize, // IN: packet size HgfsOp op, // IN: reqest type HgfsSearchReadInfo *info, // OUT: search info size_t *baseReplySize, // OUT: op base reply size size_t *inlineReplyDataSize, // OUT: size of inline reply data HgfsHandle *hgfsSearchHandle) // OUT: hgfs search handle { Bool result = TRUE; uint32 *startIndex; HgfsSearchReadMask *mask; HgfsSearchReadFlags *flags; size_t *replyPayloadSize; ASSERT(packet); ASSERT(info); ASSERT(baseReplySize); ASSERT(inlineReplyDataSize); ASSERT(hgfsSearchHandle); info->requestType = op; info->searchPattern = NULL; startIndex = &info->startIndex; replyPayloadSize = &info->payloadSize; mask = &info->requestedMask; flags = &info->flags; *mask = 0; *flags = 0; switch (op) { case HGFS_OP_SEARCH_READ_V4: { const HgfsRequestSearchReadV4 *request = packet; /* Enforced by the dispatch function. */ ASSERT(packetSize >= sizeof *request); if (0 != (request->flags & HGFS_SEARCH_READ_FID_OPEN_V4)) { /* * XXX - When this is implemented, the handle will get us a node, * (of directory type) and then with the node, we can look up a * search handle, if the data is cached in the search array. */ NOT_IMPLEMENTED(); } *hgfsSearchHandle = request->fid; *startIndex = request->restartIndex; *mask = request->mask; *flags = request->flags; *baseReplySize = offsetof(HgfsReplySearchReadV4, entries); *replyPayloadSize = request->replyDirEntryMaxSize; *inlineReplyDataSize = 0; ASSERT(*replyPayloadSize > 0); LOG(4, "%s: HGFS_OP_SEARCH_READ_V4\n", __FUNCTION__); break; } case HGFS_OP_SEARCH_READ_V3: { const HgfsRequestSearchReadV3 *request = packet; /* Enforced by the dispatch function. */ ASSERT(packetSize >= sizeof *request); *hgfsSearchHandle = request->search; *startIndex = request->offset; *flags = HGFS_SEARCH_READ_SINGLE_ENTRY; *mask = (HGFS_SEARCH_READ_FILE_NODE_TYPE | HGFS_SEARCH_READ_NAME | HGFS_SEARCH_READ_FILE_SIZE | HGFS_SEARCH_READ_TIME_STAMP | HGFS_SEARCH_READ_FILE_ATTRIBUTES | HGFS_SEARCH_READ_FILE_ID); *baseReplySize = offsetof(HgfsReplySearchReadV3, payload); *replyPayloadSize = HGFS_PACKET_MAX - *baseReplySize; *inlineReplyDataSize = *replyPayloadSize; LOG(4, "%s: HGFS_OP_SEARCH_READ_V3\n", __FUNCTION__); break; } case HGFS_OP_SEARCH_READ_V2: /* * Currently, the HgfsRequestSearchReadV2 is the same as * HgfsRequestSearchRead, so drop through. */ case HGFS_OP_SEARCH_READ: { const HgfsRequestSearchRead *request = packet; /* Enforced by the dispatch function. */ ASSERT(packetSize >= sizeof *request); *hgfsSearchHandle = request->search; *startIndex = request->offset; *flags = HGFS_SEARCH_READ_SINGLE_ENTRY; *mask = (HGFS_SEARCH_READ_FILE_NODE_TYPE | HGFS_SEARCH_READ_NAME | HGFS_SEARCH_READ_FILE_SIZE | HGFS_SEARCH_READ_TIME_STAMP | HGFS_SEARCH_READ_FILE_ATTRIBUTES); *baseReplySize = 0; *replyPayloadSize = HGFS_PACKET_MAX; *inlineReplyDataSize = *replyPayloadSize; break; } default: /* Should never occur. */ NOT_REACHED(); result = FALSE; Log("%s: ERROR Invalid OP %u\n", __FUNCTION__, op); break; } ASSERT(result); return result; } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyRecord -- * * Pack hgfs search read reply record to the current entry record. * If the last record is not NULL then update its offset to the current * entry field. * * Results: * TRUE on success and number of bytes written in replyRecordSize. * FALSE on failure, nothing written. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackSearchReadReplyRecord(HgfsOp requestType, // IN: search read request HgfsSearchReadEntry *entry, // IN: entry info size_t bytesRemaining, // IN: space in bytes for record void *lastSearchReadRecord, // IN/OUT: last packed entry void *currentSearchReadRecord,// OUT: currrent entry to pack size_t *replyRecordSize) // OUT: size of packet { Bool result = TRUE; size_t recordSize = 0; switch (requestType) { case HGFS_OP_SEARCH_READ_V4: { HgfsDirEntryV4 *replyCurrentEntry = currentSearchReadRecord; HgfsDirEntryV4 *replyLastEntry = lastSearchReadRecord; /* Skip the final empty record, it is not needed for V4.*/ if (0 == entry->nameLength) { break; } recordSize = offsetof(HgfsDirEntryV4, fileName.name) + entry->nameLength + 1; if (recordSize > bytesRemaining) { result = FALSE; break; } HgfsPackSearchReadReplyRecordV4(entry, replyLastEntry, replyCurrentEntry); break; } case HGFS_OP_SEARCH_READ_V3: { HgfsDirEntry *replyCurrentEntry = currentSearchReadRecord; /* * Previous shipping tools expect to account for a whole reply, * which is not strictly correct, it should be using * offsetof(HgfsDirEntry, fileName.name) + entry->nameLength + 1 * but we are stuck with it. */ recordSize = sizeof *replyCurrentEntry + entry->nameLength; if (recordSize > bytesRemaining) { result = FALSE; break; } HgfsPackSearchReadReplyRecordV3(&entry->attr, entry->name, entry->nameLength, replyCurrentEntry); break; } case HGFS_OP_SEARCH_READ_V2: { HgfsReplySearchReadV2 *replyV2 = currentSearchReadRecord; /* We have already accounted for the fixed part of the record. */ recordSize = entry->nameLength; if (recordSize > bytesRemaining) { result = FALSE; break; } HgfsPackSearchReadReplyRecordV2(&entry->attr, entry->name, entry->nameLength, replyV2); break; } case HGFS_OP_SEARCH_READ: { HgfsReplySearchRead *replyV1 = currentSearchReadRecord; /* We have already accounted for the fixed part of the record. */ recordSize = entry->nameLength; if (recordSize > bytesRemaining) { result = FALSE; break; } HgfsPackSearchReadReplyRecordV1(&entry->attr, entry->name, entry->nameLength, replyV1); break; } default: { Log("%s: Invalid SearchRead Op.", __FUNCTION__); NOT_REACHED(); result = FALSE; } } if (result) { *replyRecordSize = recordSize; } return result; } /* *----------------------------------------------------------------------------- * * HgfsPackSearchReadReplyHeader -- * * Pack hgfs search read reply header (common) part to all the * entries returned in the search read reply. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackSearchReadReplyHeader(HgfsSearchReadInfo *info, // IN: request info size_t *payloadSize) // OUT: size of packet { Bool result = TRUE; *payloadSize = 0; switch (info->requestType) { case HGFS_OP_SEARCH_READ_V4: { HgfsReplySearchReadV4 *reply = info->reply; HgfsPackSearchReadReplyHeaderV4(info, reply, payloadSize); break; } case HGFS_OP_SEARCH_READ_V3: { HgfsReplySearchReadV3 *reply = info->reply; HgfsPackSearchReadReplyHeaderV3(info, reply, payloadSize); break; } case HGFS_OP_SEARCH_READ_V2: { HgfsReplySearchReadV2 *reply = info->reply; HgfsPackSearchReadReplyHeaderV2(info, reply, payloadSize); break; } case HGFS_OP_SEARCH_READ: { HgfsReplySearchRead *reply = info->reply; HgfsPackSearchReadReplyHeaderV1(info, reply, payloadSize); break; } default: { LOG(4, "%s: Invalid SearchRead Op.", __FUNCTION__); NOT_REACHED(); result = FALSE; } } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSetattrPayloadV3 -- * * Unpack hgfs set attr request V3 payload and initialize a corresponding * HgfsHandle or file name to tell us which file to set attributes. Hints * holds flags to specify a handle or name for the file or * directory to set attributes. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSetattrPayloadV3(const HgfsRequestSetattrV3 *requestV3,// IN: request payload size_t payloadSize, // IN: payload size HgfsFileAttrInfo *attr, // OUT: setattr info const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsAttrHint *hints, // OUT: getattr hints HgfsHandle *file, // OUT: file handle uint32 *caseFlags) // OUT: case-sensitivity flags { Bool result = TRUE; Bool useHandle; if (payloadSize < sizeof *requestV3) { result = FALSE; goto exit; } *hints = requestV3->hints; HgfsUnpackAttrV2(&requestV3->attr, attr); if (!HgfsUnpackFileNameV3(&requestV3->fileName, payloadSize - sizeof *requestV3, &useHandle, cpName, cpNameSize, file, caseFlags)) { result = FALSE; goto exit; } if (useHandle) { *hints |= HGFS_ATTR_HINT_USE_FILE_DESC; } exit: LOG(8, "%s: unpacking HGFS_OP_SETATTR_V3 -> %d\n", __FUNCTION__, result); return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSetattrPayloadV2 -- * * Unpack hgfs Setattr request V2 payload and initialize a corresponding * HgfsHandle or file name to tell us which to set attributes. Hints * holds flags to specify a handle or name for the file or * directory to set attributes. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSetattrPayloadV2(const HgfsRequestSetattrV2 *requestV2,// IN: request payload size_t payloadSize, // IN: payload size HgfsFileAttrInfo *attr, // OUT: setattr info const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsAttrHint *hints, // OUT: delete hints HgfsHandle *file) // OUT: file handle { Bool result = TRUE; /* Enforced by the dispatch function. */ if (payloadSize < sizeof *requestV2) { return FALSE; } LOG(4, "%s: unpacking HGFS_OP_SETATTR_V2\n", __FUNCTION__); *file = HGFS_INVALID_HANDLE; *hints = requestV2->hints; HgfsUnpackAttrV2(&requestV2->attr, attr); if (requestV2->hints & HGFS_ATTR_HINT_USE_FILE_DESC) { *file = requestV2->file; *cpName = NULL; *cpNameSize = 0; } else { result = HgfsUnpackFileName(&requestV2->fileName, payloadSize - sizeof *requestV2, cpName, cpNameSize); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSetattrPayloadV1 -- * * Unpack hgfs setattr request V1 payload and initialize a corresponding * file name to tell us which to set attributes. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSetattrPayloadV1(const HgfsRequestSetattr *requestV1, // IN: request payload size_t payloadSize, // IN: payload size HgfsFileAttrInfo *attr, // OUT: setattr info const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsAttrHint *hints) // OUT: setattr hints { LOG(4, "%s: unpacking HGFS_OP_SETATTR\n", __FUNCTION__); attr->mask = 0; attr->mask |= requestV1->update & HGFS_ATTR_SIZE ? HGFS_ATTR_VALID_SIZE : 0; attr->mask |= requestV1->update & HGFS_ATTR_CREATE_TIME ? HGFS_ATTR_VALID_CREATE_TIME : 0; attr->mask |= requestV1->update & HGFS_ATTR_ACCESS_TIME ? HGFS_ATTR_VALID_ACCESS_TIME : 0; attr->mask |= requestV1->update & HGFS_ATTR_WRITE_TIME ? HGFS_ATTR_VALID_WRITE_TIME : 0; attr->mask |= requestV1->update & HGFS_ATTR_CHANGE_TIME ? HGFS_ATTR_VALID_CHANGE_TIME : 0; attr->mask |= requestV1->update & HGFS_ATTR_PERMISSIONS ? HGFS_ATTR_VALID_OWNER_PERMS : 0; *hints |= requestV1->update & HGFS_ATTR_ACCESS_TIME_SET ? HGFS_ATTR_HINT_SET_ACCESS_TIME : 0; *hints |= requestV1->update & HGFS_ATTR_WRITE_TIME_SET ? HGFS_ATTR_HINT_SET_WRITE_TIME : 0; attr->type = requestV1->attr.type; attr->size = requestV1->attr.size; attr->creationTime = requestV1->attr.creationTime; attr->accessTime = requestV1->attr.accessTime; attr->writeTime = requestV1->attr.writeTime; attr->attrChangeTime = requestV1->attr.attrChangeTime; attr->ownerPerms = requestV1->attr.permissions; return HgfsUnpackFileName(&requestV1->fileName, payloadSize - sizeof *requestV1, cpName, cpNameSize); } /* *----------------------------------------------------------------------------- * * HgfsUnpackSetattrRequest -- * * Unpack hgfs setattr request and initialize a corresponding * HgfsFileAttrInfo structure that is used to pass around setattr request * information. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackSetattrRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type HgfsFileAttrInfo *attr, // OUT: setattr info HgfsAttrHint *hints, // OUT: setattr hints const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsHandle *file, // OUT: server file ID uint32 *caseType) // OUT: case-sensitivity flags { ASSERT(packet); ASSERT(attr); ASSERT(cpName); ASSERT(cpNameSize); ASSERT(file); ASSERT(caseType); attr->requestType = op; /* Default values for legacy requests. */ *caseType = HGFS_FILE_NAME_DEFAULT_CASE; *hints = 0; *file = HGFS_INVALID_HANDLE; switch (op) { case HGFS_OP_SETATTR_V3: { const HgfsRequestSetattrV3 *requestV3 = packet; if (!HgfsUnpackSetattrPayloadV3(requestV3, packetSize, attr, cpName, cpNameSize, hints, file, caseType)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_SETATTR_V2: { const HgfsRequestSetattrV2 *requestV2 = packet; if (!HgfsUnpackSetattrPayloadV2(requestV2, packetSize, attr, cpName, cpNameSize, hints, file)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_SETATTR: { const HgfsRequestSetattr *requestV1 = packet; if (!HgfsUnpackSetattrPayloadV1(requestV1, packetSize, attr, cpName, cpNameSize, hints)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } default: LOG(4, "%s: Incorrect opcode %d\n", __FUNCTION__, op); NOT_REACHED(); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackSetattrReply -- * * Pack hgfs setattr reply. * Since the structure of the set attributes reply packet hasn't changed in * version 2 of the protocol, HgfsReplySetattrV2 is identical to * HgfsReplySetattr. So use HgfsReplySetattr type to access packetIn to * keep the code simple. * * Results: * TRUE if valid op and reply set, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackSetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; *payloadSize = 0; switch (op) { case HGFS_OP_SETATTR_V3: { HgfsReplySetattrV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); /* Reply consists of only a reserved field. */ reply->reserved = 0; *payloadSize = sizeof *reply; break; } case HGFS_OP_SETATTR_V2: case HGFS_OP_SETATTR: { HgfsReplySetattr *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } default: result = FALSE; LOG(4, "%s: invalid op code %d\n", __FUNCTION__, op); NOT_REACHED(); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackCreateDirPayloadV3 -- * * Unpack hgfs create directory request V3 payload and initialize a corresponding * file name to tell us which directory to create. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackCreateDirPayloadV3(const HgfsRequestCreateDirV3 *requestV3, // IN: request payload size_t payloadSize, // IN: payload size HgfsCreateDirInfo *info) // IN/OUT: info struct { /* * The request file name length is user-provided, so this test must be * carefully written to prevent wraparounds. */ LOG(4, "%s: HGFS_OP_CREATE_DIR_V3\n", __FUNCTION__); ASSERT(payloadSize >= sizeof *requestV3); if (requestV3->fileName.length > payloadSize - sizeof *requestV3) { /* The input packet is smaller than the request. */ return FALSE; } if (!(requestV3->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) { /* We do not support requests without a valid file name. */ LOG(4, "%s: Incorrect mask %x\n", __FUNCTION__, (uint32)requestV3->mask); return FALSE; } /* * Copy all the fields into our carrier struct. Some will probably be * garbage, but it's simpler to copy everything now and check the * valid bits before reading later. */ info->mask = requestV3->mask; info->cpName = requestV3->fileName.name; info->cpNameSize = requestV3->fileName.length; info->caseFlags = requestV3->fileName.caseType; info->specialPerms = requestV3->specialPerms; info->fileAttr = requestV3->fileAttr; info->ownerPerms = requestV3->ownerPerms; info->groupPerms = requestV3->groupPerms; info->otherPerms = requestV3->otherPerms; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackCreateDirPayloadV2 -- * * Unpack hgfs create directory request V2 payload and initialize a corresponding * file name to tell us which directory to create. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackCreateDirPayloadV2(const HgfsRequestCreateDirV2 *requestV2, // IN: request payload size_t payloadSize, // IN: payload size HgfsCreateDirInfo *info) // IN/OUT: info struct { /* * The request file name length is user-provided, so this test must be * carefully written to prevent wraparounds. */ LOG(4, "%s: HGFS_OP_CREATE_DIR_V2\n", __FUNCTION__); ASSERT(payloadSize >= sizeof *requestV2); if (requestV2->fileName.length > payloadSize - sizeof *requestV2) { /* The input packet is smaller than the request. */ return FALSE; } if (!(requestV2->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) { /* We do not support requests without a valid file name. */ LOG(4, "%s: Incorrect mask %x\n", __FUNCTION__, (uint32)requestV2->mask); return FALSE; } /* * Copy all the fields into our carrier struct. Some will probably be * garbage, but it's simpler to copy everything now and check the * valid bits before reading later. */ info->mask = requestV2->mask; info->cpName = requestV2->fileName.name; info->cpNameSize = requestV2->fileName.length; info->specialPerms = requestV2->specialPerms; info->ownerPerms = requestV2->ownerPerms; info->groupPerms = requestV2->groupPerms; info->otherPerms = requestV2->otherPerms; info->fileAttr = 0; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackCreateDirPayloadV1 -- * * Unpack hgfs create directory request V1 payload and initialize a corresponding * file name to tell us which directory to create. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackCreateDirPayloadV1(const HgfsRequestCreateDir *requestV1, // IN: request payload size_t payloadSize, // IN: payload size HgfsCreateDirInfo *info) // IN/OUT: info struct { /* * The request file name length is user-provided, so this test must be * carefully written to prevent wraparounds. */ LOG(4, "%s: HGFS_OP_CREATE_DIR_V1\n", __FUNCTION__); ASSERT(payloadSize >= sizeof *requestV1); if (requestV1->fileName.length > payloadSize - sizeof *requestV1) { /* The input packet is smaller than the request. */ LOG(4, "%s: HGFS packet too small for the file name\n", __FUNCTION__); return FALSE; } /* For CreateDirV1 requests, we know exactly what fields we expect. */ info->mask = HGFS_CREATE_DIR_VALID_OWNER_PERMS | HGFS_CREATE_DIR_VALID_FILE_NAME; info->cpName = requestV1->fileName.name; info->cpNameSize = requestV1->fileName.length; info->ownerPerms = requestV1->permissions; info->fileAttr = 0; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackCreateDirRequest -- * * Unpack hgfs CreateDir request and initialize a corresponding * HgfsCreateDirInfo structure that is used to pass around CreateDir request * information. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackCreateDirRequest(const void *packet, // IN: incoming packet size_t packetSize, // IN: size of packet HgfsOp op, // IN: request type HgfsCreateDirInfo *info) // IN/OUT: info struct { ASSERT(packet); ASSERT(info); info->requestType = op; /* Default value for legacy requests. */ info->caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; switch (op) { case HGFS_OP_CREATE_DIR_V3: { const HgfsRequestCreateDirV3 *requestV3 = packet; if (!HgfsUnpackCreateDirPayloadV3(requestV3, packetSize, info)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_CREATE_DIR_V2: { const HgfsRequestCreateDirV2 *requestV2 = packet; if (!HgfsUnpackCreateDirPayloadV2(requestV2, packetSize, info)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_CREATE_DIR: { const HgfsRequestCreateDir *requestV1 = packet; if (!HgfsUnpackCreateDirPayloadV1(requestV1, packetSize, info)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } default: LOG(4, "%s: Incorrect opcode %d\n", __FUNCTION__, op); NOT_REACHED(); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackCreateDirReply -- * * Pack hgfs CreateDir reply. * * Results: * TRUE if valid op and reply set, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackCreateDirReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; *payloadSize = 0; switch (op) { case HGFS_OP_CREATE_DIR_V3: { HgfsReplyCreateDirV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); /* Reply consists of only a reserved field. */ reply->reserved = 0; *payloadSize = sizeof *reply; break; } case HGFS_OP_CREATE_DIR_V2: { HgfsReplyCreateDirV2 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } case HGFS_OP_CREATE_DIR: { HgfsReplyCreateDir *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } default: result = FALSE; LOG(4, "%s: invalid op code %d\n", __FUNCTION__, op); NOT_REACHED(); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackWriteWin32StreamPayloadV3 -- * * Unpack hgfs write stream request V3 payload and initialize a corresponding * file name to tell us which directory to create. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackWriteWin32StreamPayloadV3(const HgfsRequestWriteWin32StreamV3 *requestV3, // IN: size_t payloadSize, // IN: HgfsHandle *file, // OUT: const char **data, // OUT: size_t *dataSize, // OUT: Bool *doSecurity) // OUT: { LOG(4, "%s: HGFS_OP_WRITE_WIN32_STREAM_V3\n", __FUNCTION__); if (payloadSize < sizeof *requestV3) { LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } if (payloadSize >= requestV3->requiredSize + sizeof *requestV3) { *file = requestV3->file; *data = requestV3->payload; *dataSize = requestV3->requiredSize; *doSecurity = (requestV3->flags & HGFS_WIN32_STREAM_IGNORE_SECURITY) == 0; return TRUE; } LOG(4, "%s: HGFS packet too small - user data do not fit\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackWriteWin32StreamRequest -- * * Unpack hgfs SendFileUsingReader request. Returns file to write to, data * and whether to restore the security stream. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackWriteWin32StreamRequest(const void *packet, // IN: incoming packet size_t packetSize, // IN: size of packet HgfsOp op, // IN: request type HgfsHandle *file, // OUT: file to write to const char **data, // OUT: data to write size_t *dataSize, // OUT: size of data Bool *doSecurity) // OUT: restore sec.str. { ASSERT(packet); ASSERT(file); ASSERT(data); ASSERT(dataSize); ASSERT(doSecurity); if (op != HGFS_OP_WRITE_WIN32_STREAM_V3) { /* The only supported version for the moment is V3. */ LOG(4, "%s: Incorrect opcode %d\n", __FUNCTION__, op); NOT_REACHED(); return FALSE; } return HgfsUnpackWriteWin32StreamPayloadV3(packet, packetSize, file, data, dataSize, doSecurity); } /* *----------------------------------------------------------------------------- * * HgfsPackWriteWin32StreamReply -- * * Pack hgfs SendFileUsingReader reply. * Returns the actual amount of data written in the reply. * * Results: * TRUE if valid op and reply set, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackWriteWin32StreamReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type uint32 actualSize, // IN: amount written size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { HgfsReplyWriteWin32StreamV3 *reply; Bool result = TRUE; *payloadSize = 0; if (HGFS_OP_WRITE_WIN32_STREAM_V3 == op) { reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); reply->reserved = 0; reply->actualSize = actualSize; *payloadSize = sizeof *reply; } else { LOG(4, "%s: Incorrect opcode %d\n", __FUNCTION__, op); NOT_REACHED(); result = FALSE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackReadPayload -- * * Unpack hgfs read payload to get the file handle and file offset to read from and * the length of data to read. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackReadPayload(const HgfsRequestRead *request, // IN: payload size_t payloadSize, // IN: payload size HgfsHandle* file, // OUT: HGFS handle to close uint64 *offset, // OUT: offset to read from uint32 *length) // OUT: length of data to read { LOG(4, "%s: HGFS_OP_READ\n", __FUNCTION__); if (payloadSize >= sizeof *request) { *file = request->file; *offset = request->offset; *length = request->requiredSize; return TRUE; } LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackReadPayloadV3 -- * * Unpack hgfs read payload V3 to get parameters needed to perform read. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackReadPayloadV3(const HgfsRequestReadV3 *requestV3, // IN: payload size_t payloadSize, // IN: payload size HgfsHandle* file, // OUT: HGFS handle to close uint64 *offset, // OUT: offset to read from uint32 *length) // OUT: length of data to read { LOG(4, "%s: HGFS_OP_READ_V3\n", __FUNCTION__); if (payloadSize >= sizeof *requestV3) { *file = requestV3->file; *offset = requestV3->offset; *length = requestV3->requiredSize; return TRUE; } LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackReadRequest -- * * Unpack hgfs read request. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackReadRequest(const void *packet, // IN: HGFS request size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type HgfsHandle *file, // OUT: Handle to close uint64 *offset, // OUT: offset to read from uint32 *length) // OUT: length of data to read { Bool result; ASSERT(packet); switch (op) { case HGFS_OP_READ_FAST_V4: case HGFS_OP_READ_V3: { const HgfsRequestReadV3 *requestV3 = packet; result = HgfsUnpackReadPayloadV3(requestV3, packetSize, file, offset, length); break; } case HGFS_OP_READ: { const HgfsRequestRead *requestV1 = packet; result = HgfsUnpackReadPayload(requestV1, packetSize, file, offset, length); break; } default: NOT_REACHED(); result = FALSE; } if (!result) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackWritePayload -- * * Unpack hgfs write payload to get the file handle, file offset, of data to write, * write flags and pointer to the data to write. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackWritePayload(const HgfsRequestWrite *request, // IN: request payload size_t payloadSize, // IN: request payload size HgfsHandle* file, // OUT: HGFS handle to write to uint64 *offset, // OUT: offset to read from uint32 *length, // OUT: length of data to write HgfsWriteFlags *flags, // OUT: write flags const void **data) // OUT: data to be written { LOG(4, "%s: HGFS_OP_WRITE\n", __FUNCTION__); if (payloadSize >= sizeof *request) { if (sizeof *request + request->requiredSize - 1 <= payloadSize) { *file = request->file; *flags = request->flags; *offset = request->offset; *data = request->payload; *length = request->requiredSize; return TRUE; } } LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackWritePayloadV3 -- * * Unpack hgfs write payload V3. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackWritePayloadV3(const HgfsRequestWriteV3 *requestV3, // IN: payload size_t payloadSize, // IN: request payload size HgfsHandle* file, // OUT: HGFS handle write to uint64 *offset, // OUT: offset to read from uint32 *length, // OUT: length of data to write HgfsWriteFlags *flags, // OUT: write flags const void **data) // OUT: data to be written { LOG(4, "%s: HGFS_OP_WRITE_V3\n", __FUNCTION__); if (payloadSize >= sizeof *requestV3) { if (sizeof *requestV3 + requestV3->requiredSize - 1 <= payloadSize) { *file = requestV3->file; *flags = requestV3->flags; *offset = requestV3->offset; *data = requestV3->payload; *length = requestV3->requiredSize; return TRUE; } } LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackWriteFastPayloadV4 -- * * Unpack hgfs write fast payload V4. * The only difference from V3 payload is that data to write are * provided in the payload but located in a separate buffer. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackWriteFastPayloadV4(const HgfsRequestWriteV3 *requestV3, // IN: payload size_t payloadSize, // IN: request payload size HgfsHandle* file, // OUT: HGFS handle write to uint64 *offset, // OUT: offset to write to uint32 *length, // OUT: size of data to write HgfsWriteFlags *flags) // OUT: write flags { LOG(4, "%s: HGFS_OP_WRITE_V3\n", __FUNCTION__); if (payloadSize >= sizeof *requestV3) { *file = requestV3->file; *flags = requestV3->flags; *offset = requestV3->offset; *length = requestV3->requiredSize; return TRUE; } LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackWriteRequest -- * * Unpack hgfs write request to get parameters and data to write. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackWriteRequest(const void *writeRequest,// IN: write request params size_t writeRequestSize, // IN: write request params size HgfsOp writeOp, // IN: request version HgfsHandle *file, // OUT: Handle to write to uint64 *offset, // OUT: offset to write to uint32 *length, // OUT: length of data to write HgfsWriteFlags *flags, // OUT: write flags const void **data) // OUT: data to be written { Bool result; switch (writeOp) { case HGFS_OP_WRITE_FAST_V4: { const HgfsRequestWriteV3 *requestV3 = writeRequest; *data = NULL; /* Write data is retrieved from shared memory. */ result = HgfsUnpackWriteFastPayloadV4(requestV3, writeRequestSize, file, offset, length, flags); break; } case HGFS_OP_WRITE_V3: { const HgfsRequestWriteV3 *requestV3 = writeRequest; result = HgfsUnpackWritePayloadV3(requestV3, writeRequestSize, file, offset, length, flags, data); break; } case HGFS_OP_WRITE: { const HgfsRequestWrite *requestV1 = writeRequest; result = HgfsUnpackWritePayload(requestV1, writeRequestSize, file, offset, length, flags, data); break; } default: LOG(4, "%s: Incorrect opcode %d\n", __FUNCTION__, writeOp); NOT_REACHED(); result = FALSE; } if (!result) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); } return result; } /* *----------------------------------------------------------------------------- * * HgfsPackWriteReply -- * * Pack hgfs write reply to the HgfsReplyWrite structure. * * Results: * Always TRUE, FALSE if bad opcode. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackWriteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type uint32 actualSize, // IN: number of bytes that were written size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; *payloadSize = 0; switch (op) { case HGFS_OP_WRITE_FAST_V4: case HGFS_OP_WRITE_V3: { HgfsReplyWriteV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); reply->reserved = 0; reply->actualSize = actualSize; *payloadSize = sizeof *reply; break; } case HGFS_OP_WRITE: { HgfsReplyWrite *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); reply->actualSize = actualSize; *payloadSize = sizeof *reply; break; } default: NOT_REACHED(); result = FALSE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackQueryVolumePayload -- * * Unpack hgfs query volume payload to get the file name which must be used to query * volume information. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackQueryVolumePayload(const HgfsRequestQueryVolume *request, // IN: request payload size_t payloadSize, // IN: request payload size const char **fileName, // OUT: volume name size_t *nameLength) // OUT: volume name length { LOG(4, "%s: HGFS_OP_QUERY_VOLUME_INFO\n", __FUNCTION__); if (payloadSize >= sizeof *request) { return HgfsUnpackFileName(&request->fileName, payloadSize - sizeof *request + 1, fileName, nameLength); } LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackQueryVolumePayloadV3 -- * * Unpack hgfs query volume payload V3. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackQueryVolumePayloadV3(const HgfsRequestQueryVolumeV3 *requestV3, // IN: payload size_t payloadSize, // IN: payload size Bool *useHandle, // OUT: use handle HgfsHandle* file, // OUT: HGFS handle const char **fileName, // OUT: volume name size_t *nameLength, // OUT: name length uint32 * caseFlags) // OUT: case flags { LOG(4, "%s: HGFS_OP_QUERY_VOLUME_INFO_V3\n", __FUNCTION__); if (payloadSize >= sizeof *requestV3) { return HgfsUnpackFileNameV3(&requestV3->fileName, payloadSize - sizeof *requestV3 + 1, useHandle, fileName, nameLength, file, caseFlags); } LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackQueryVolumeRequest -- * * Unpack hgfs query volume information request to get parameters related to * query volume operation. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackQueryVolumeRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type Bool *useHandle, // OUT: use handle const char **fileName, // OUT: file name size_t *fileNameLength, // OUT: file name length uint32 *caseFlags, // OUT: case sensitivity HgfsHandle *file) // OUT: Handle to the volume { ASSERT(packet); switch (op) { case HGFS_OP_QUERY_VOLUME_INFO_V3: { const HgfsRequestQueryVolumeV3 *requestV3 = packet; if (!HgfsUnpackQueryVolumePayloadV3(requestV3, packetSize, useHandle, file, fileName, fileNameLength, caseFlags)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_QUERY_VOLUME_INFO: { const HgfsRequestQueryVolume *requestV1 = packet; if (!HgfsUnpackQueryVolumePayload(requestV1, packetSize, fileName, fileNameLength)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } *file = HGFS_INVALID_HANDLE; *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; *useHandle = FALSE; break; } default: LOG(4, "%s: Incorrect opcode %d\n", __FUNCTION__, op); NOT_REACHED(); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackQueryVolumeReply -- * * Pack hgfs query volume reply. * * Results: * TRUE if valid op and reply set, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackQueryVolumeReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type uint64 freeBytes, // IN: volume free space uint64 totalBytes, // IN: volume capacity size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; *payloadSize = 0; switch (op) { case HGFS_OP_QUERY_VOLUME_INFO_V3: { HgfsReplyQueryVolumeV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); reply->reserved = 0; reply->freeBytes = freeBytes; reply->totalBytes = totalBytes; *payloadSize = sizeof *reply; break; } case HGFS_OP_QUERY_VOLUME_INFO: { HgfsReplyQueryVolume *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); reply->freeBytes = freeBytes; reply->totalBytes = totalBytes; *payloadSize = sizeof *reply; break; } default: result = FALSE; LOG(4, "%s: invalid op code %d\n", __FUNCTION__, op); NOT_REACHED(); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSymlinkCreatePayload -- * * Unpack hgfs symbolic link payload to get symbolic link file name * and symbolic link target. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSymlinkCreatePayload(const HgfsRequestSymlinkCreate *request, // IN: request payload size_t payloadSize, // IN: payload size const char **srcFileName, // OUT: link file name size_t *srcNameLength, // OUT: file name length const char **tgFileName, // OUT: target file name size_t *tgNameLength) // OUT: target name length { uint32 prefixSize; LOG(4, "%s: HGFS_OP_CREATE_SYMLINK_V3\n", __FUNCTION__); prefixSize = offsetof(HgfsRequestSymlinkCreate, symlinkName.name); if (payloadSize >= prefixSize) { if (HgfsUnpackFileName(&request->symlinkName, payloadSize - prefixSize, srcFileName, srcNameLength)) { const HgfsFileName *targetName = (const HgfsFileName *)(*srcFileName + 1 + *srcNameLength); prefixSize = ((char *)targetName - (char *)request) + offsetof(HgfsFileName, name); return HgfsUnpackFileName(targetName, payloadSize - prefixSize, tgFileName, tgNameLength); } } return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSymlinkCreatePayloadV3 -- * * Unpack hgfs create symbolic link payload V3. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSymlinkCreatePayloadV3(const HgfsRequestSymlinkCreateV3 *requestV3, // IN: size_t payloadSize, // IN: Bool *srcUseHandle, // OUT: HgfsHandle* srcFile, // OUT: const char **srcFileName, // OUT: size_t *srcNameLength, // OUT: uint32 *srcCaseFlags, // OUT: Bool *tgUseHandle, // OUT: HgfsHandle* tgFile, // OUT: const char **tgFileName, // OUT: size_t *tgNameLength, // OUT: uint32 * tgCaseFlags) // OUT: { uint32 prefixSize; LOG(4, "%s: HGFS_OP_CREATE_SYMLINK_V3\n", __FUNCTION__); prefixSize = offsetof(HgfsRequestSymlinkCreateV3, symlinkName.name); if (payloadSize >= prefixSize) { if (HgfsUnpackFileNameV3(&requestV3->symlinkName, payloadSize - prefixSize, srcUseHandle, srcFileName, srcNameLength, srcFile, srcCaseFlags)) { const HgfsFileNameV3 *targetName; if (*srcUseHandle) { targetName = &requestV3->targetName; } else { targetName = (const HgfsFileNameV3 *)(*srcFileName + 1 + *srcNameLength); } prefixSize = ((char *)targetName - (char *)requestV3) + offsetof(HgfsFileNameV3, name); return HgfsUnpackFileNameV3(targetName, payloadSize - prefixSize, tgUseHandle, tgFileName, tgNameLength, tgFile, tgCaseFlags); } } return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSymlinkCreateRequest -- * * Unpack hgfs symbolic link creation request to get parameters related to * creating the symbolic link. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackSymlinkCreateRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type Bool *srcUseHandle, // OUT: use source handle const char **srcFileName, // OUT: source file name size_t *srcFileNameLength, // OUT: source file name length uint32 *srcCaseFlags, // OUT: source case sensitivity HgfsHandle *srcFile, // OUT: source file handle Bool *tgUseHandle, // OUT: use target handle const char **tgFileName, // OUT: target file name size_t *tgFileNameLength, // OUT: target file name length uint32 *tgCaseFlags, // OUT: target case sensitivity HgfsHandle *tgFile) // OUT: target file handle { ASSERT(packet); switch (op) { case HGFS_OP_CREATE_SYMLINK_V3: { const HgfsRequestSymlinkCreateV3 *requestV3 = packet; if (!HgfsUnpackSymlinkCreatePayloadV3(requestV3, packetSize, srcUseHandle, srcFile, srcFileName, srcFileNameLength, srcCaseFlags, tgUseHandle, tgFile, tgFileName, tgFileNameLength, tgCaseFlags)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_CREATE_SYMLINK: { const HgfsRequestSymlinkCreate *requestV1 = packet; if (!HgfsUnpackSymlinkCreatePayload(requestV1, packetSize, srcFileName, srcFileNameLength, tgFileName, tgFileNameLength)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } *srcFile = HGFS_INVALID_HANDLE; *srcCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE; *srcUseHandle = FALSE; *tgFile = HGFS_INVALID_HANDLE; *tgCaseFlags = HGFS_FILE_NAME_DEFAULT_CASE; *tgUseHandle = FALSE; break; } default: LOG(4, "%s: Incorrect opcode %d\n", __FUNCTION__, op); NOT_REACHED(); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackSymlinkCreateReply -- * * Pack hgfs symbolic link creation reply. * * Results: * TRUE if valid op and reply set, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackSymlinkCreateReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; switch (op) { case HGFS_OP_CREATE_SYMLINK_V3: { HgfsReplySymlinkCreateV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); /* Reply only consists of a reserved field. */ reply->reserved = 0; *payloadSize = sizeof *reply; break; } case HGFS_OP_CREATE_SYMLINK: { HgfsReplySymlinkCreate *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); *payloadSize = sizeof *reply; break; } default: result = FALSE; LOG(4, "%s: invalid op code %d\n", __FUNCTION__, op); NOT_REACHED(); } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSearchOpenPayload -- * * Unpack hgfs search open payload to get name of directory to open. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSearchOpenPayload(const HgfsRequestSearchOpen *request, // IN: payload size_t payloadSize, // IN: payload size const char **dirName, // OUT: directory name size_t *dirNameLength) // OUT: name length { LOG(4, "%s: HGFS_OP_SEARCH_OPEN\n", __FUNCTION__); if (payloadSize >= sizeof *request) { if (sizeof *request + request->dirName.length - 1 <= payloadSize) { *dirName = request->dirName.name; *dirNameLength = request->dirName.length; return TRUE; } } LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSearchOpenPayloadV3 -- * * Unpack hgfs search open payload V3 to get name of directory to open and * case flags. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSearchOpenPayloadV3(const HgfsRequestSearchOpenV3 *requestV3, // IN: payload size_t payloadSize, // IN: payload size const char **dirName, // OUT: directory name size_t *dirNameLength, // OUT: name length uint32 *caseFlags) // OUT: case flags { Bool result = FALSE; LOG(4, "%s: HGFS_OP_SEARCH_OPEN_V3\n", __FUNCTION__); if (payloadSize >= sizeof *requestV3) { uint32 prefixSize = offsetof(HgfsRequestSearchOpenV3, dirName.name); Bool useDirHandle; HgfsHandle dirHandle; result = HgfsUnpackFileNameV3(&requestV3->dirName, payloadSize - prefixSize, &useDirHandle, dirName, dirNameLength, &dirHandle, caseFlags); if (useDirHandle) { LOG(4, "%s: client is trying to a handle %u\n", __FUNCTION__, dirHandle); result = FALSE; } } LOG(4, "%s: returns %d\n", __FUNCTION__, result); return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSearchOpenRequest -- * * Unpack hgfs search open request to get directory name and case flags. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackSearchOpenRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type const char **dirName, // OUT: directory name size_t *dirNameLength, // OUT: name length uint32 *caseFlags) // OUT: case flags { ASSERT(packet); switch (op) { case HGFS_OP_SEARCH_OPEN_V3: { const HgfsRequestSearchOpenV3 *requestV3 = packet; if (!HgfsUnpackSearchOpenPayloadV3(requestV3, packetSize, dirName, dirNameLength, caseFlags)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } break; } case HGFS_OP_SEARCH_OPEN: { const HgfsRequestSearchOpen *requestV1 = packet; if (!HgfsUnpackSearchOpenPayload(requestV1, packetSize, dirName, dirNameLength)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } *caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; break; } default: LOG(4, "%s: Incorrect opcode %d\n", __FUNCTION__, op); NOT_REACHED(); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackSearchOpenReply -- * * Pack hgfs search open reply. * * Results: * TRUE unless it is invoked for a wrong op (which indicates a bug in the code). * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackSearchOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type HgfsHandle search, // IN: search handle size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; switch (op) { case HGFS_OP_SEARCH_OPEN_V3: { HgfsReplySearchOpenV3 *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); reply->reserved = 0; reply->search = search; *payloadSize = sizeof *reply; break; } case HGFS_OP_SEARCH_OPEN: { HgfsReplySearchOpen *reply; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); reply->search = search; *payloadSize = sizeof *reply; break; } default: NOT_REACHED(); result = FALSE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackCreateSessionPayloadV4 -- * * Unpack hgfs create session request V4 payload. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackCreateSessionPayloadV4(const HgfsRequestCreateSessionV4 *requestV4, // IN: payload size_t payloadSize, // IN: HgfsCreateSessionInfo *info) // IN/OUT: info { LOG(4, "%s: HGFS_OP_CREATE_SESSION_V4\n", __FUNCTION__); if (payloadSize < offsetof(HgfsRequestCreateSessionV4, reserved)) { /* The input packet is smaller than the request. */ return FALSE; } if (requestV4->numCapabilities) { if (payloadSize < offsetof(HgfsRequestCreateSessionV4, capabilities) + requestV4->numCapabilities * sizeof(HgfsOpCapability)) { LOG(4, "%s: HGFS packet too small\n", __FUNCTION__); return FALSE; } } info->maxPacketSize = requestV4->maxPacketSize; info->flags = requestV4->flags; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackCreateSessionRequest -- * * Unpack hgfs CreateSession request and initialize a corresponding * HgfsCreateDirInfo structure that is used to pass around CreateDir request * information. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackCreateSessionRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: size of packet HgfsOp op, // IN: request type HgfsCreateSessionInfo *info) // IN/OUT: info struct { const HgfsRequestCreateSessionV4 *requestV4; ASSERT(packet); ASSERT(info); ASSERT(op == HGFS_OP_CREATE_SESSION_V4); requestV4 = packet; if (!HgfsUnpackCreateSessionPayloadV4(requestV4, packetSize, info)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackCreateSessionReply -- * * Pack hgfs CreateSession reply. * * Results: * Always TRUE. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackCreateSessionReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { HgfsReplyCreateSessionV4 *reply; uint32 numCapabilities = session->numberOfCapabilities; uint32 capabilitiesLen = numCapabilities * sizeof *session->hgfsSessionCapabilities; HGFS_ASSERT_PACK_PARAMS; *payloadSize = offsetof(HgfsReplyCreateSessionV4, capabilities) + capabilitiesLen; reply = HgfsAllocInitReply(packet, packetHeader, *payloadSize, session); reply->sessionId = session->sessionId; reply->numCapabilities = numCapabilities; reply->maxPacketSize = session->maxPacketSize; reply->identityOffset = 0; reply->flags = session->flags; reply->reserved = 0; memcpy(reply->capabilities, session->hgfsSessionCapabilities, capabilitiesLen); return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackDestroySessionReply -- * * Pack hgfs CreateSession reply. * * Results: * Always TRUE. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackDestroySessionReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { HgfsReplyDestroySessionV4 *reply; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); /* Reply only consists of a reserved field. */ *payloadSize = sizeof *reply; reply->reserved = 0; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsServerGetDefaultCapabilities -- * * Returns list capabilities that are supported by all sessions. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ void HgfsServerGetDefaultCapabilities(HgfsOpCapability *capabilities, // OUT: capabilities uint32 *numberOfCapabilities) // OUT: number of items { *numberOfCapabilities = ARRAYSIZE(hgfsDefaultCapabilityTable); ASSERT(*numberOfCapabilities <= HGFS_OP_MAX); memcpy(capabilities, hgfsDefaultCapabilityTable, sizeof hgfsDefaultCapabilityTable); } /* *----------------------------------------------------------------------------- * * HgfsPackSetWatchReplyV4 -- * * Pack hgfs set watch V4 reply payload to the HgfsReplySetWatchV4 structure. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsPackSetWatchReplyV4(HgfsSubscriberHandle watchId, // IN: host id of thee new watch HgfsReplySetWatchV4 *reply) // OUT: reply buffer to fill { reply->watchId = watchId; reply->reserved = 0; } /* *----------------------------------------------------------------------------- * * HgfsPackSetWatchReply -- * * Pack hgfs set watch reply to the HgfsReplySetWatchV4 structure. * * Results: * TRUE if successfully allocated reply request, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackSetWatchReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: operation code HgfsSubscriberHandle watchId, // IN: id of the new watch size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HgfsReplySetWatchV4 *reply; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; if (HGFS_OP_SET_WATCH_V4 == op) { reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); HgfsPackSetWatchReplyV4(watchId, reply); *payloadSize = sizeof *reply; } else { NOT_REACHED(); result = FALSE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackSetWatchPayloadV4 -- * * Unpack HGFS set directory notication watch payload version 4 and initializes * a corresponding HgfsHandle or file name to tell us which directory to watch. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackSetWatchPayloadV4(const HgfsRequestSetWatchV4 *requestV4, // IN: request payload size_t payloadSize, // IN: payload size Bool *useHandle, // OUT: handle or cpName uint32 *flags, // OUT: watch flags uint32 *events, // OUT: event filter const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsHandle *dir, // OUT: directory handle uint32 *caseFlags) // OUT: case-sensitivity { if (payloadSize < sizeof *requestV4) { return FALSE; } *flags = requestV4->flags; *events = requestV4->events; return HgfsUnpackFileNameV3(&requestV4->fileName, payloadSize - sizeof *requestV4, useHandle, cpName, cpNameSize, dir, caseFlags); } /* *----------------------------------------------------------------------------- * * HgfsUnpackSetWatchRequest -- * * Unpack hgfs set directory notication watch request and initialize a corresponding * HgfsHandle or directory name to tell us which directory to monitor. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackSetWatchRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: requested operation Bool *useHandle, // OUT: handle or cpName const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size uint32 *flags, // OUT: flags for the new watch uint32 *events, // OUT: event filter HgfsHandle *dir, // OUT: direrctory handle uint32 *caseFlags) // OUT: case-sensitivity flags { const HgfsRequestSetWatchV4 *requestV4 = packet; Bool result; ASSERT(packet); ASSERT(cpName); ASSERT(cpNameSize); ASSERT(dir); ASSERT(flags); ASSERT(events); ASSERT(caseFlags); ASSERT(useHandle); if (HGFS_OP_SET_WATCH_V4 != op) { NOT_REACHED(); result = FALSE; } else { LOG(4, "%s: HGFS_OP_SET_WATCH_V4\n", __FUNCTION__); result = HgfsUnpackSetWatchPayloadV4(requestV4, packetSize, useHandle, flags, events, cpName, cpNameSize, dir, caseFlags); } if (!result) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); } return result; } /* *----------------------------------------------------------------------------- * * HgfsPackRemoveWatchReply -- * * Pack hgfs remove watch reply to the HgfsReplyRemoveWatchV4 structure. * * Results: * TRUE if successfully allocated reply request, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackRemoveWatchReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: operation code size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session) // IN: Session info { Bool result = TRUE; HgfsReplyRemoveWatchV4 *reply; HGFS_ASSERT_PACK_PARAMS; *payloadSize = 0; if (HGFS_OP_REMOVE_WATCH_V4 != op) { NOT_REACHED(); result = FALSE; } else { reply = HgfsAllocInitReply(packet, packetHeader, sizeof *reply, session); reply->reserved = 0; *payloadSize = sizeof *reply; } return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackRemoveWatchPayload -- * * Unpack HGFS remove directory notication watch payload version 4. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackRemoveWatchPayloadV4(const HgfsRequestRemoveWatchV4 *requestV4, // IN: request payload size_t payloadSize, // IN: payload size HgfsSubscriberHandle *watchId) // OUT: watch id { if (payloadSize < sizeof *requestV4) { return FALSE; } *watchId = requestV4->watchId; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackRemoveWatchRequest -- * * Unpack hgfs remove directory notication watch request. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackRemoveWatchRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: requested operation HgfsSubscriberHandle *watchId) // OUT: watch Id to remove { const HgfsRequestRemoveWatchV4 *requestV4 = packet; ASSERT(packet); ASSERT(watchId); ASSERT(HGFS_OP_REMOVE_WATCH_V4 == op); if (HGFS_OP_REMOVE_WATCH_V4 != op) { return FALSE; } else if (!HgfsUnpackRemoveWatchPayloadV4(requestV4, packetSize, watchId)) { LOG(4, "%s: Error decoding HGFS packet\n", __FUNCTION__); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackCalculateNotificationSize -- * * Calculates size needed for change notification packet. * * Results: * TRUE if successfully allocated reply request, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ size_t HgfsPackCalculateNotificationSize(char const *shareName, // IN: shared folder name char *fileName) // IN: relative file path { size_t result = sizeof (HgfsRequestNotifyV4); if (NULL != fileName) { size_t shareNameLen = strlen(shareName); result += strlen(fileName) + 1 + shareNameLen; } result += sizeof (HgfsHeader); return result; } /* *----------------------------------------------------------------------------- * * HgfsPackGetOplockBreakSize -- * * Gets the size needed for the oplock break request. * * Results: * Size of the oplock break request. * * Side effects: * None. * *----------------------------------------------------------------------------- */ size_t HgfsPackGetOplockBreakSize(void) { return sizeof (HgfsRequestOplockBreakV4) + sizeof (HgfsHeader); } /* *----------------------------------------------------------------------------- * * HgfsPackOplockBreakRequestV4( -- * * Pack hgfs oplock break V4 request to be sent to the guest. * * Results: * Length of the packed structure or 0 if the structure does not fit in the * the buffer. * * Side effects: * None * *----------------------------------------------------------------------------- */ static size_t HgfsPackOplockBreakRequestV4(HgfsHandle fileId, // IN: file ID HgfsLockType serverLock, // IN: lock type size_t bufferSize, // IN: available space HgfsRequestOplockBreakV4 *reply) // OUT: notification buffer { size_t size = 0; if (bufferSize < sizeof *reply) { goto exit; } reply->reserved = 0; reply->fid = fileId; reply->serverLock = serverLock; size = sizeof *reply; exit: return size; } /* *----------------------------------------------------------------------------- * * HgfsPackOplockBreakRequest -- * * Pack the HGFS protocol Oplock break request. * * Results: * TRUE if successfully packed the request, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackOplockBreakRequest(void *packet, // IN/OUT: Hgfs Packet HgfsHandle fileId, // IN: file ID HgfsLockType serverLock, // IN: lock type uint64 sessionId, // IN: session ID size_t *bufferSize) // IN/OUT: size of packet { size_t opBreakRequestSize; HgfsRequestOplockBreakV4 *opBreakRequest; HgfsHeader *header = packet; Bool result = TRUE; ASSERT(packet); ASSERT(bufferSize); if (*bufferSize < sizeof *header) { result = FALSE; goto exit; } /* * Initialize notification header. * Set status and requestId to 0 since these fields are not relevant for * oplock break requests. * Initialize payload size to 0 - it is not known yet and will be filled later. */ opBreakRequest = (HgfsRequestOplockBreakV4 *)((char *)header + sizeof *header); opBreakRequestSize = HgfsPackOplockBreakRequestV4(fileId, serverLock, *bufferSize - sizeof *header, opBreakRequest); if (0 == opBreakRequestSize) { result = FALSE; goto exit; } result = HgfsPackReplyHeaderV4(HGFS_ERROR_SUCCESS, opBreakRequestSize, HGFS_OP_OPLOCK_BREAK_V4, sessionId, 0, HGFS_PACKET_FLAG_REQUEST, *bufferSize, header); exit: return result; } /* *----------------------------------------------------------------------------- * * HgfsUnpackOplockBreakAckPayloadV4 -- * * Unpack HGFS oplock break acknowledge payload version 4. * * Results: * TRUE on success. * FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsUnpackOplockBreakAckPayloadV4(const HgfsReplyOplockBreakV4 *opBrkAck, // IN: request payload size_t payloadSize, // IN: payload size HgfsHandle *fileId, // OUT: file Id to remove HgfsLockType *serverLock) // OUT: lock type { if (payloadSize < sizeof *opBrkAck) { return FALSE; } *fileId = opBrkAck->fid; *serverLock = opBrkAck->serverLock; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsUnpackOplockBreakAckReply -- * * Unpack hgfs oplock break acknowledge reply. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsUnpackOplockBreakAckReply(const void *packet, // IN: HGFS packet size_t packetSize, // IN: reply packet size HgfsOp op, // IN: operation version HgfsHandle *fileId, // OUT: file Id to remove HgfsLockType *serverLock) // OUT: lock type { const HgfsReplyOplockBreakV4 *replyV4 = packet; Bool result = FALSE; ASSERT(fileId); ASSERT(serverLock); ASSERT(HGFS_OP_OPLOCK_BREAK_V4 == op); if (HGFS_OP_OPLOCK_BREAK_V4 == op) { result = HgfsUnpackOplockBreakAckPayloadV4(replyV4, packetSize, fileId, serverLock); } if (!result) { LOG(4, "%s: Error unpacking HGFS_OP_OPLOCK_BREAK_V4 packet\n", __FUNCTION__); } return result; } /* *----------------------------------------------------------------------------- * * HgfsBuildCPName -- * * Build crossplatform name out of share name and relative to the shared folder * file path. * * Results: * Length of the output crossplatform name. * * Side effects: * None * *----------------------------------------------------------------------------- */ static int HgfsBuildCPName(char const *shareName, // IN: utf8 share name char *fileName, // IN: utf8 file path char **cpName) // OUT: full name in cp format { size_t shareNameLen = strlen(shareName) + 1; size_t fileNameLen = strlen(fileName) + 1; char *fullName = Util_SafeMalloc(shareNameLen + fileNameLen); int cpNameResult; *cpName = Util_SafeMalloc(shareNameLen + fileNameLen); Str_Strcpy(fullName, shareName, shareNameLen); fullName[shareNameLen - 1] = DIRSEPC; Str_Strcpy(fullName + shareNameLen, fileName, fileNameLen); // Unescaped name can't be longer then escaped thus it must fit. cpNameResult = CPName_ConvertTo(fullName, shareNameLen + fileNameLen, *cpName); free(fullName); if (cpNameResult < 0) { free(*cpName); *cpName = NULL; } return cpNameResult; } /* *----------------------------------------------------------------------------- * * HgfsPackHgfsName -- * * Pack cpName into HgfsFileName structure. * * Results: * TRUE if there is enough space in the buffer, * FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsPackHgfsName(char *cpName, // IN: cpName to pack size_t cpNameLen, // IN: length of the cpName size_t availableSpace, // IN: space available for HgfsFileName size_t *nameSize, // OUT: space consumed by HgfsFileName HgfsFileName *fileName) // OUT: structure to pack cpName into { if (availableSpace < offsetof(HgfsFileName, name) + cpNameLen) { return FALSE; } fileName->length = cpNameLen; memcpy(fileName->name, cpName, cpNameLen); *nameSize = offsetof(HgfsFileName, name) + cpNameLen; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsPackChangeNotifyEventV4 -- * * Pack single change directory notification event information. * * Results: * Length of the packed structure or 0 if the structure does not fit in the * the buffer. * * Side effects: * None * *----------------------------------------------------------------------------- */ static size_t HgfsPackChangeNotifyEventV4(uint32 mask, // IN: event mask char const *shareName, // IN: share name char *fileName, // IN: file name size_t bufferSize, // IN: available space HgfsNotifyEventV4 *reply) // OUT: notificaiton buffer { size_t totalLength = 0; if (sizeof *reply > bufferSize) { /* Not enough space for the event, drop the event. */ goto exit; } reply->nextOffset = 0; reply->mask = mask; if (NULL != fileName) { char *cpFullName; size_t remainingSize; size_t hgfsNameSize; int cpFullNameSize; cpFullNameSize = HgfsBuildCPName(shareName, fileName, &cpFullName); if (cpFullNameSize < 0) { /* Could not build the crossplatform name, drop the event. */ goto exit; } remainingSize = bufferSize - offsetof(HgfsNotifyEventV4, fileName); if (!HgfsPackHgfsName(cpFullName, cpFullNameSize, remainingSize, &hgfsNameSize, &reply->fileName)) { /* Name would not fit, drop the event. */ free(cpFullName); goto exit; } remainingSize -= hgfsNameSize; totalLength = bufferSize - remainingSize; free(cpFullName); } else { reply->fileName.length = 0; totalLength = sizeof *reply; } exit: return totalLength; } /* *----------------------------------------------------------------------------- * * HgfsPackChangeNotifyRequestV4 -- * * Pack hgfs directory change notification request to be sent to the guest. * * Results: * Length of the packed structure or 0 if the structure does not fit in the * the buffer. * * Side effects: * None * *----------------------------------------------------------------------------- */ static size_t HgfsPackChangeNotifyRequestV4(HgfsSubscriberHandle watchId, // IN: watch uint32 flags, // IN: notify flags uint32 mask, // IN: event mask char const *shareName, // IN: share name char *fileName, // IN: relative file path size_t bufferSize, // IN: available space HgfsRequestNotifyV4 *reply) // OUT: notification buffer { size_t size = 0; size_t notificationOffset; if (bufferSize < sizeof *reply) { LOG(4, "%s: Error HGFS_OP_NOTIFY_V4 buf size %"FMTSZ"u reply size %"FMTSZ"u\n", __FUNCTION__, bufferSize, sizeof *reply); goto exit; } reply->watchId = watchId; reply->flags = flags; if ((flags & HGFS_NOTIFY_FLAG_OVERFLOW) == HGFS_NOTIFY_FLAG_OVERFLOW) { size = sizeof *reply; reply->count = 0; reply->flags = HGFS_NOTIFY_FLAG_OVERFLOW; } else { /* * For the moment server sends only one notification at a time and it relies * on transport to coalesce requests. * Later on we may consider supporting multiple notifications. */ reply->count = 1; notificationOffset = offsetof(HgfsRequestNotifyV4, events); size = HgfsPackChangeNotifyEventV4(mask, shareName, fileName, bufferSize - notificationOffset, reply->events); if (size != 0) { size += notificationOffset; } else { /* * Set event flag to tell guest that some events were dropped * when filling out notification details failed. */ size = sizeof *reply; reply->count = 0; reply->flags = HGFS_NOTIFY_FLAG_OVERFLOW; } } exit: return size; } /* *----------------------------------------------------------------------------- * * HgfsPackChangeNotificationRequest -- * * Pack hgfs directory change notification request to the * HgfsRequestNotifyV4 structure. * * Results: * TRUE if successfully allocated reply request, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsPackChangeNotificationRequest(void *packet, // IN/OUT: Hgfs Packet HgfsSubscriberHandle subscriber, // IN: watch char const *shareName, // IN: share name char *fileName, // IN: relative name uint32 mask, // IN: event mask uint32 notifyFlags, // IN: notify flags HgfsSessionInfo *session, // IN: session size_t *bufferSize) // INOUT: size of packet { size_t notifyRequestSize; HgfsRequestNotifyV4 *notifyRequest; HgfsHeader *header = packet; Bool result = FALSE; ASSERT(packet); ASSERT(shareName); ASSERT(NULL != fileName || (notifyFlags & HGFS_NOTIFY_FLAG_OVERFLOW) == HGFS_NOTIFY_FLAG_OVERFLOW); ASSERT(session); ASSERT(bufferSize); LOG(4, "%s: HGFS_OP_NOTIFY_V4\n", __FUNCTION__); if (*bufferSize < sizeof *header) { LOG(4, "%s: Error HGFS_OP_NOTIFY_V4 buf size %"FMTSZ"u min %"FMTSZ"u\n", __FUNCTION__, *bufferSize, sizeof *header); goto exit; } /* * Initialize notification header. * Set status and requestId to 0 since these fields are not relevant for * notifications. * Initialize payload size to 0 - it is not known yet and will be filled later. */ notifyRequest = (HgfsRequestNotifyV4 *)((char *)header + sizeof *header); notifyRequestSize = HgfsPackChangeNotifyRequestV4(subscriber, notifyFlags, mask, shareName, fileName, *bufferSize - sizeof *header, notifyRequest); if (0 != notifyRequestSize) { result = HgfsPackReplyHeaderV4(HGFS_ERROR_SUCCESS, notifyRequestSize, HGFS_OP_NOTIFY_V4, session->sessionId, 0, HGFS_PACKET_FLAG_REQUEST, *bufferSize, header); } exit: return result; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsServerParameters.h000066400000000000000000000512351470176644300275260ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2013-2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerParameters.h -- * * This defines the HGFS protocol message packet functions * for creating requests and extracting data from replies. */ #ifndef _HGFS_SERVER_PARAMETERS_H_ #define _HGFS_SERVER_PARAMETERS_H_ #include "hgfsServer.h" // for HgfsPacket type #include "hgfsProto.h" // for the HGFS protocol request, reply and types #include "hgfsUtil.h" // for HgfsInternalStatus #include "hgfsServerInt.h" // for HgfsSessionInfo /* * Global functions */ HgfsInternalStatus HgfsUnpackPacketParams(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size Bool *sessionEnabled, // OUT: session enabled request uint64 *sessionId, // OUT: session Id uint32 *requestId, // OUT: unique request id HgfsOp *opcode, // OUT: request opcode size_t *payloadSize, // OUT: size of the opcode request const void **payload); // OUT: pointer to the opcode request Bool HgfsPackReplyHeader(HgfsInternalStatus status, // IN: reply status uint32 payloadSize, // IN: size of the reply payload Bool sessionEnabledHeader, // IN: session enabled header uint64 sessionId, // IN: session id uint32 requestId, // IN: request id HgfsOp op, // IN: request type uint32 hdrFlags, // IN: header flags size_t hdrPacketSize, // IN: header packet size void *hdrPacket); // OUT: outgoing packet header Bool HgfsUnpackOpenRequest(const void *packet, // IN: incoming packet size_t packetSize, // IN: size of packet HgfsOp op, // IN: request type HgfsFileOpenInfo *openInfo); // IN/OUT: open info struct Bool HgfsPackOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsFileOpenInfo *openInfo, // IN: open info struct size_t *payloadSize, // OUT: outgoing packet size HgfsSessionInfo *session); // IN: Session Info Bool HgfsUnpackGetattrRequest(const void *packetHeader, // IN: packet header size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type HgfsFileAttrInfo *attrInfo, // IN/OUT: unpacked attr struct HgfsAttrHint *hints, // OUT: getattr hints const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsHandle *file, // OUT: file handle uint32 *caseFlags); // OUT: case-sensitivity flags Bool HgfsUnpackDeleteRequest(const void *packet, // IN: request packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: requested operation const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsDeleteHint *hints, // OUT: delete hints HgfsHandle *file, // OUT: file handle uint32 *caseFlags); // OUT: case-sensitivity flags Bool HgfsPackDeleteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: requested operation size_t *payloadSize, // OUT: size of HGFS packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsUnpackRenameRequest(const void *packet, // IN: request packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: requested operation const char **cpOldName, // OUT: rename src size_t *cpOldNameLen, // OUT: rename src size const char **cpNewName, // OUT: rename dst size_t *cpNewNameLen, // OUT: rename dst size HgfsRenameHint *hints, // OUT: rename hints HgfsHandle *srcFile, // OUT: src file handle HgfsHandle *targetFile, // OUT: target file handle uint32 *oldCaseFlags, // OUT: old case-sensitivity flags uint32 *newCaseFlags); // OUT: new case-sensitivity flags Bool HgfsPackRenameReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: requested operation size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsPackGetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs packet const void *packetHeader, // IN: packet header HgfsFileAttrInfo *attr, // IN: attr stucture const char *utf8TargetName, // IN: optional target name uint32 utf8TargetNameLen, // IN: file name length size_t *payloadSize, // OUT: size of HGFS packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsPackSymlinkCreateReply(HgfsPacket *packet, // IN/OUT: Hgfs packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of HGFS packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsUnpackSearchReadRequest(const void *packet, // IN: request packet size_t packetSize, // IN: packet size HgfsOp op, // IN: requested operation HgfsSearchReadInfo *info, // OUT: search info size_t *baseReplySize, // OUT: op base reply size size_t *inlineReplyDataSize, // OUT: size of inline reply data HgfsHandle *hgfsSearchHandle);// OUT: hgfs search handle Bool HgfsPackSearchReadReplyRecord(HgfsOp requestType, // IN: search read request HgfsSearchReadEntry *entry, // IN: entry info size_t maxRecordSize, // IN: max size in bytes for record void *lastSearchReadRecord, // IN/OUT: last packed entry void *currentSearchReadRecord,// OUT: currrent entry to pack size_t *replyRecordSize); // OUT: size of packet Bool HgfsPackSearchReadReplyHeader(HgfsSearchReadInfo *info, // IN: request info size_t *payloadSize); // OUT: size of packet Bool HgfsUnpackSetattrRequest(const void *packet, // IN: request packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: requested operation HgfsFileAttrInfo *attr, // IN/OUT: getattr info HgfsAttrHint *hints, // OUT: setattr hints const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size HgfsHandle *file, // OUT: server file ID uint32 *caseFlags); // OUT: case-sensitivity flags Bool HgfsPackSetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsUnpackCreateDirRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: size of packet HgfsOp op, // IN: requested operation HgfsCreateDirInfo *info); // IN/OUT: info struct Bool HgfsPackCreateDirReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsPackQueryVolumeReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type uint64 freeBytes, // IN: volume free space uint64 totalBytes, // IN: volume capacity size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsUnpackQueryVolumeRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type Bool *useHandle, // OUT: use handle const char **fileName, // OUT: file name size_t *fileNameLength, // OUT: file name length uint32 *caseFlags, // OUT: case sensitivity HgfsHandle *file); // OUT: Handle to the volume Bool HgfsUnpackSymlinkCreateRequest(const void *packet, // IN: request packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type Bool *srcUseHandle, // OUT: use source handle const char **srcFileName, // OUT: source file name size_t *srcFileNameLength, // OUT: source file name length uint32 *srcCaseFlags, // OUT: source case sensitivity HgfsHandle *srcFile, // OUT: source file handle Bool *tgUseHandle, // OUT: use target handle const char **tgFileName, // OUT: target file name size_t *tgFileNameLength, // OUT: target file name length uint32 *tgCaseFlags, // OUT: target case sensitivity HgfsHandle *tgFile); // OUT: target file handle Bool HgfsUnpackWriteWin32StreamRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: size of packet HgfsOp op, // IN: request type HgfsHandle *file, // OUT: file to write to const char **payload, // OUT: data to write size_t *requiredSize, // OUT: size of data Bool *doSecurity); // OUT: restore sec.str. Bool HgfsUnpackCreateSessionRequest(const void *packetHeader, // IN: request packet size_t packetSize, // IN: size of packet HgfsOp op, // IN: request type HgfsCreateSessionInfo *info); // IN/OUT: info struct Bool HgfsPackWriteWin32StreamReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet headert HgfsOp op, // IN: request type uint32 actualSize, // IN: amount written size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN:Session Info Bool HgfsUnpackCloseRequest(const void *packet, // IN: request packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type HgfsHandle *file); // OUT: Handle to close Bool HgfsUnpackSearchOpenRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type const char **dirName, // OUT: directory name size_t *dirNameLength, // OUT: name length uint32 *caseFlags); // OUT: case flags Bool HgfsPackCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsUnpackSearchCloseRequest(const void *packet, // IN: request packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type HgfsHandle *file); // OUT: Handle to close Bool HgfsPackSearchOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type HgfsHandle search, // IN: search handle size_t *packetSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsPackSearchCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type size_t *packetSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsPackWriteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: request type uint32 actualSize, // IN: number of bytes that were written size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session info Bool HgfsUnpackReadRequest(const void *packet, // IN: HGFS request size_t packetSize, // IN: request packet size HgfsOp op, // IN: request type HgfsHandle *file, // OUT: Handle to close uint64 *offset, // OUT: offset to read from uint32 *length); // OUT: length of data to read Bool HgfsUnpackWriteRequest(const void *writeRequest,// IN: HGFS write request params size_t writeRequestSize, // IN: write request params size HgfsOp writeOp, // IN: request version HgfsHandle *file, // OUT: Handle to write to uint64 *offset, // OUT: offset to write to uint32 *length, // OUT: length of data to write HgfsWriteFlags *flags, // OUT: write flags const void **data); // OUT: data to be written Bool HgfsPackCreateSessionReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info Bool HgfsPackDestroySessionReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session Info void HgfsServerGetDefaultCapabilities(HgfsOpCapability *capabilities, // OUT: uint32 *numberOfCapabilities); // OUT: Bool HgfsUnpackSetWatchRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: request packet size HgfsOp op, // IN: requested operation Bool *useHandle, // OUT: handle or cpName const char **cpName, // OUT: cpName size_t *cpNameSize, // OUT: cpName size uint32 *flags, // OUT: flags for the new watch uint32 *events, // OUT: event filter HgfsHandle *dir, // OUT: direrctory handle uint32 *caseFlags); // OUT: case-sensitivity flags Bool HgfsPackSetWatchReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: operation code HgfsSubscriberHandle watchId, // IN: new watch id size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session info Bool HgfsUnpackRemoveWatchRequest(const void *packet, // IN: HGFS packet size_t packetSize, // IN: packet size HgfsOp op, // IN: operation code HgfsSubscriberHandle *watchId); // OUT: watch Id Bool HgfsPackRemoveWatchReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet const void *packetHeader, // IN: packet header HgfsOp op, // IN: operation code size_t *payloadSize, // OUT: size of packet HgfsSessionInfo *session); // IN: Session info size_t HgfsPackCalculateNotificationSize(char const *shareName, // IN: shared folder name char *fileName); // IN: file name Bool HgfsPackChangeNotificationRequest(void *packet, // IN/OUT: Hgfs Packet HgfsSubscriberHandle subscriber, // IN: watch char const *shareName, // IN: share name char *fileName, // IN: file name uint32 mask, // IN: event mask uint32 notifyFlags, // IN: notify flags HgfsSessionInfo *session, // IN: session size_t *bufferSize); // IN/OUT: packet size #endif // ifndef _HGFS_SERVER_PARAMETERS_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsThreadpool.h000066400000000000000000000032121470176644300263250ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _HGFS_THREADPOOL_H #define _HGFS_THREADPOOL_H /* * hgfsThreadpool.h -- * * Function definitions for threadpool. */ #include "hgfsUtil.h" // for HgfsInternalStatus #include "hgfsServerInt.h" // for HgfsSessionInfo /* * The maximum count of thread in threadpool. * For Windows 10 guest, the file explorer issues 8 asynchronous request * at one time. * Please keep this value same with the PHYSMEM_HGFS_WORKER_THREADS */ #define HGFS_THREADPOOL_MAX_COUNT 10 typedef void(*HgfsThreadpoolWorkItem)(void *data); HgfsInternalStatus HgfsThreadpool_Init(void); Bool HgfsThreadpool_Activate(void); void HgfsThreadpool_Deactivate(void); void HgfsThreadpool_Exit(void); Bool HgfsThreadpool_QueueWorkItem(HgfsThreadpoolWorkItem workItem, void *data); #endif // _HGFS_THREADPOOL_H open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServer/hgfsThreadpoolStub.c000066400000000000000000000061151470176644300271630ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsThreadPoolStub.c -- * * Stubs for threadpool support, used to build guest components. */ #include "vmware.h" #include "vm_basic_types.h" #include "util.h" #include "hgfsProto.h" #include "hgfsServer.h" #include "hgfsThreadpool.h" /* *----------------------------------------------------------------------------- * * HgfsThreadpool_Init -- * * Initialization of the threadpool component. * * Results: * 0 if success, error code otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ HgfsInternalStatus HgfsThreadpool_Init(void) { return HGFS_ERROR_NOT_SUPPORTED; } /* *----------------------------------------------------------------------------- * * HgfsThreadpool_Activate -- * * Activate the threadpool. * * Results: * Always return FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsThreadpool_Activate(void) { return FALSE; } /* *----------------------------------------------------------------------------- * * HgfsThreadpool_Deactivate -- * * Deactivate the threadpool. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsThreadpool_Deactivate(void) { } /* *----------------------------------------------------------------------------- * * HgfsThreadpool_Exit -- * * Exit for the threadpool component. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void HgfsThreadpool_Exit(void) { } /* *----------------------------------------------------------------------------- * * HgfsThreadpool_QueueWorkItem -- * * Execute a work item. * * Results: * TRUE if the work item is queued successfully, * FALSE if the work item is not queued. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool HgfsThreadpool_QueueWorkItem(HgfsThreadpoolWorkItem workItem, // IN void *data) // IN { return FALSE; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerManagerGuest/000077500000000000000000000000001470176644300255105ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerManagerGuest/Makefile.am000066400000000000000000000022211470176644300275410ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libHgfsServerManagerGuest.la libHgfsServerManagerGuest_la_SOURCES = libHgfsServerManagerGuest_la_SOURCES += hgfsServerManagerGuest.c libHgfsServerManagerGuest_la_SOURCES += hgfsChannelGuest.c libHgfsServerManagerGuest_la_SOURCES += hgfsChannelGuestBd.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerManagerGuest/hgfsChannelGuest.c000066400000000000000000000515161470176644300311140ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2017,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsChannelGuest.c -- * * Channel abstraction for the HGFS server. * */ #include #include "vm_basic_defs.h" #include "vm_assert.h" #include "vm_atomic.h" #include "util.h" #include "hgfsChannelGuestInt.h" #include "hgfsServer.h" #include "hgfsServerManager.h" /* * HGFS server connection channel and state object usage. * * Currently, all plugins can share this same HGFS server channel and state. * This allows us to use a common channel so it is only initialized * once, by the first loaded plugin which requires an HGFS channel, and torn * down when the final plugin that uses the HGFS server is unloaded. * * Currently, the plugins are loaded (and unloaded) in any particular order, * and those operations are serialized. (For example the HGFS server plugin * maybe the first plugin loaded that uses this channel, but is not the final * plugin to be unloaded that uses the channel. This also may change in the * future, so no dependencies can be made on order of loading and unloading * of plugins.) * Furthermore, multiple plugins use the HGFS channel and server and some plugins * have multiple connections. Some plugins also create and teardown connections * during general mutlithreaded operation of the tools processes. * * In order to support the above, we must track how many users of the shared * connection there are. This allows us to tear down the shared connection * when the final plugin that is using it is unloaded, and when no * channels are in use the HGFS server state can be torn down. */ /* * The HGFS server state. * * This object is initiliazed once only and is shared across all * connections, shared or private. * Each new channel connection will reference the server and so the HGFS * server is initialized when the first new channel is being created. Each * new channel just increments the reference of server state object. * When the final channel is torn down the final HGFS server reference is * also removed and the HGFS server exit is called and this object is torn down. */ typedef struct HgfsChannelServerData { const HgfsServerCallbacks *serverCBTable; /* HGFS server entry points. */ Atomic_uint32 refCount; /* Server data reference count. */ } HgfsChannelServerData; /* * Transport channels context. * * Multiple callers share this same channel currently as only one * transport channel is required. Therefore, the channel is referenced * for each client that it is returned to (a usage count). */ typedef struct HgfsChannelData { const char *name; /* Channel name. */ const HgfsGuestChannelCBTable *ops; /* Channel operations. */ uint32 state; /* Channel state (see flags below). */ struct HgfsGuestConn *connection; /* Opaque server connection */ HgfsChannelServerData *serverInfo; /* HGFS server entry points. */ Atomic_uint32 refCount; /* Channel reference count. */ } HgfsChannelData; #define HGFS_CHANNEL_STATE_INIT (1 << 0) #define HGFS_CHANNEL_STATE_CBINIT (1 << 1) /* Static channel registration - assumes only one for now. */ static HgfsChannelData gHgfsChannels[] = { { "guest", &gGuestBackdoorOps, 0, NULL, NULL, {0} }, }; static HgfsServerConfig gHgfsGuestCfgSettings = { (HGFS_CONFIG_SHARE_ALL_HOST_DRIVES_ENABLED | HGFS_CONFIG_VOL_INFO_MIN), HGFS_MAX_CACHED_FILENODES }; /* HGFS server info state. Referenced by each separate channel that uses it. */ static HgfsChannelServerData gHgfsChannelServerInfo = { NULL, {0} }; static void HgfsChannelTeardownChannel(HgfsChannelData *channel); static void HgfsChannelTeardownServer(HgfsChannelServerData *serverInfo); static void HgfsChannelExitChannel(HgfsChannelData *channel); /* *---------------------------------------------------------------------------- * * HGFS SERVER DATA FUNCTIONS * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * HgfsChannelGetServer -- * * Increment the server data reference count. * * Results: * The value of the reference count before the increment. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static uint32 HgfsChannelGetServer(HgfsChannelServerData *serverInfo) // IN/OUT: ref count { ASSERT(NULL != serverInfo); return Atomic_ReadInc32(&serverInfo->refCount); } /* *---------------------------------------------------------------------------- * * HgfsChannelPutServer -- * * Decrement server data reference count. * * Teardown the server data object if removed the final reference. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsChannelPutServer(HgfsChannelServerData *serverInfo) // IN/OUT: ref count { ASSERT(NULL != serverInfo); if (Atomic_ReadDec32(&serverInfo->refCount) == 1) { HgfsChannelTeardownServer(serverInfo); } } /* *---------------------------------------------------------------------------- * * HgfsChannelInitServer -- * * Initialize HGFS server and save the state. * * Results: * TRUE if success, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static Bool HgfsChannelInitServer(HgfsServerMgrCallbacks *mgrCb, // IN: server manager callbacks HgfsChannelServerData *serverInfo) // IN/OUT: ref count { Bool result; ASSERT(NULL == serverInfo->serverCBTable); Debug("%s: Initialize Hgfs server.\n", __FUNCTION__); /* If we have a new connection initialize the server session with default settings. */ result = HgfsServer_InitState(&serverInfo->serverCBTable, &gHgfsGuestCfgSettings, mgrCb); if (!result) { Debug("%s: Could not init Hgfs server.\n", __FUNCTION__); } return result; } /* *---------------------------------------------------------------------------- * * HgfsChannelExitServer -- * * Reset the HGFS server and destroy the state. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsChannelExitServer(HgfsChannelServerData *serverInfo) // IN/OUT: ref count { if (NULL != serverInfo->serverCBTable) { Debug("%s: Teardown Hgfs server.\n", __FUNCTION__); HgfsServer_ExitState(); serverInfo->serverCBTable = NULL; } } /* *---------------------------------------------------------------------------- * * HgfsChannelTeardownServer -- * * Teardown the HGFS server state for all connections. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsChannelTeardownServer(HgfsChannelServerData *serverInfo) // IN/OUT: connection manager object { HgfsChannelExitServer(serverInfo); } /* *---------------------------------------------------------------------------- * * CHANNEL DATA FUNCTIONS * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * HgfsChannelGetChannel -- * * Increment channel data reference count. * * Results: * The value of the reference count before the increment. * * Side effects: * None. * *---------------------------------------------------------------------------- */ uint32 HgfsChannelGetChannel(HgfsChannelData *channel) // IN/OUT: ref count { ASSERT(NULL != channel); return Atomic_ReadInc32(&channel->refCount); } /* *---------------------------------------------------------------------------- * * HgfsChannelPutChannel -- * * Decrement channel reference count. * * Teardown channel object if removed the final reference. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsChannelPutChannel(HgfsChannelData *channel) // IN/OUT: ref count { ASSERT(NULL != channel); if (Atomic_ReadDec32(&channel->refCount) == 1) { HgfsChannelTeardownChannel(channel); } } /* *----------------------------------------------------------------------------- * * HgfsChannelInitChannel -- * * Initializes a channel by initializing the HGFS server state. * * Results: * TRUE if the channel initialized, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsChannelInitChannel(HgfsChannelData *channel, // IN/OUT: channel object HgfsServerMgrCallbacks *mgrCb, // IN: server manager callbacks HgfsChannelServerData *serverInfo) // IN/OUT: server info { Bool result = TRUE; uint32 serverInfoCount; channel->state = 0; /* * Reference the HGFS server as it will be used by the new channel. * The HGFS server should only be initialized once, i.e. on the first * caller instance, otherwise only reference the server info for * the new channel. */ serverInfoCount = HgfsChannelGetServer(serverInfo); /* Referenced the server, save it for dereferencing. */ channel->serverInfo = serverInfo; if (0 == serverInfoCount) { /* The HGFS server has not been initialized, do it now. */ result = HgfsChannelInitServer(mgrCb, channel->serverInfo); if (!result) { Debug("%s: Could not init Hgfs server.\n", __FUNCTION__); goto exit; } } channel->state |= HGFS_CHANNEL_STATE_INIT; exit: if (!result) { HgfsChannelExitChannel(channel); } Debug("%s: Init channel return %d.\n", __FUNCTION__, result); return result; } /* *----------------------------------------------------------------------------- * * HgfsChannelExitChannel -- * * Teardown the channel and teardown the HGFS server. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsChannelExitChannel(HgfsChannelData *channel) // IN/OUT: channel object { if (NULL != channel->serverInfo) { /* Remove the reference for the HGFS server info. */ HgfsChannelPutServer(channel->serverInfo); channel->serverInfo = NULL; } channel->state = 0; Debug("%s: Exit channel returns.\n", __FUNCTION__); } /* *----------------------------------------------------------------------------- * * HgfsChannelActivateChannel -- * * Activate a channel by calling the channels init callback. * * Results: * TRUE if a channel is active. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsChannelActivateChannel(HgfsChannelData *channel, // IN/OUT: channel object void *rpc, // IN: Rpc channel void *rpcCallback) // IN: Rpc callback { Bool success = FALSE; struct HgfsGuestConn *connData = NULL; if (channel->ops->init(&channel->serverInfo->serverCBTable->session, rpc, rpcCallback, &connData)) { channel->state |= HGFS_CHANNEL_STATE_CBINIT; channel->connection = connData; success = TRUE; } return success; } /* *----------------------------------------------------------------------------- * * HgfsChannelDeactivateChannel -- * * Deactivate a channel by calling the channels exit callback. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsChannelDeactivateChannel(HgfsChannelData *channel) // IN/OUT: channel object { channel->ops->exit(channel->connection); channel->state &= ~HGFS_CHANNEL_STATE_CBINIT; channel->connection = NULL; } /* *----------------------------------------------------------------------------- * * HgfsChannelIsChannelActive -- * * Is the channel active (initialized) for processing requests. * * Results: * TRUE if a channel is active. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsChannelIsChannelActive(HgfsChannelData *channel) // IN/OUT: channel object { return (0 != (channel->state & HGFS_CHANNEL_STATE_INIT) && 0 != (channel->state & HGFS_CHANNEL_STATE_CBINIT)); } /* *----------------------------------------------------------------------------- * * HgfsChannelReceive -- * * Received a request on a channel pass on to the channel callback. * * Results: * TRUE if a channel ws deactivated. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsChannelReceive(HgfsChannelData *channel, // IN/OUT: channel object char const *packetIn, // IN: incoming packet size_t packetInSize, // IN: incoming packet size char *packetOut, // OUT: outgoing packet size_t *packetOutSize) // IN/OUT: outgoing packet size { return channel->ops->receive(channel->connection, packetIn, packetInSize, packetOut, packetOutSize); } /* *---------------------------------------------------------------------------- * * HgfsChannelTeardownChannel -- * * Teardown the channel for HGFS. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsChannelTeardownChannel(HgfsChannelData *channel) // IN/OUT: connection manager object { if (HgfsChannelIsChannelActive(channel)) { HgfsChannelDeactivateChannel(channel); } HgfsChannelExitChannel(channel); } /* *---------------------------------------------------------------------------- * * CHANNEL PUBLIC FUNCTIONS * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * HgfsChannelGuest_Init -- * * Sets up the channel for HGFS. * * Initialize all the defined channels. * At least one channel should succeed it's initialization * completely, else we fail. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool HgfsChannelGuest_Init(HgfsServerMgrData *mgrData, // IN/OUT: server manager data HgfsServerMgrCallbacks *mgrCb) // IN: server manager callbacks { Bool success = FALSE; HgfsChannelData *channel = &gHgfsChannels[0]; // Shared channel (internal RPC) uint32 channelRefCount; ASSERT(NULL != mgrData); ASSERT(NULL == mgrData->connection); /* Currently, the RPC override is not implemented. */ ASSERT(NULL == mgrData->rpc); ASSERT(NULL == mgrData->rpcCallback); ASSERT(NULL != mgrData->appName); Debug("%s: app %s rpc = %p rpc cb = %p.\n", __FUNCTION__, mgrData->appName, mgrData->rpc, mgrData->rpcCallback); if (NULL != mgrData->rpc || NULL != mgrData->rpcCallback) { /* * XXX - Would malloc a new channel here and activate * with the required RPC. */ Debug("%s: Guest channel RPC override not supported.\n", __FUNCTION__); goto exit; } /* * Reference the channel. Initialize only for the first * caller instance, otherwise only reference the channel for * return to the caller. */ channelRefCount = HgfsChannelGetChannel(channel); /* We have referenced the channel, save it for later dereference. */ mgrData->connection = channel; if (0 == channelRefCount) { /* Initialize channels objects. */ if (!HgfsChannelInitChannel(channel, mgrCb, &gHgfsChannelServerInfo)) { Debug("%s: Could not init channel.\n", __FUNCTION__); goto exit; } /* Call the channels initializers. */ if (!HgfsChannelActivateChannel(channel, mgrData->rpc, mgrData->rpcCallback)) { Debug("%s: Could not activate channel.\n", __FUNCTION__); goto exit; } } success = TRUE; exit: if (!success) { HgfsChannelGuest_Exit(mgrData); } return success; } /* *---------------------------------------------------------------------------- * * HgfsChannelGuest_Exit -- * * Dereference the channel which for the final reference will * close the channel for HGFS. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ void HgfsChannelGuest_Exit(HgfsServerMgrData *mgrData) // IN/OUT: connection manager object { HgfsChannelData *channel; ASSERT(NULL != mgrData); ASSERT(NULL != mgrData->appName); channel = mgrData->connection; Debug("%s: app %s rpc = %p rpc cb = %p chn = %p.\n", __FUNCTION__, mgrData->appName, mgrData->rpc, mgrData->rpcCallback, channel); if (NULL != channel) { HgfsChannelPutChannel(channel); mgrData->connection = NULL; } } /* *---------------------------------------------------------------------------- * * HgfsChannelGuest_Receive -- * * Process packet not associated with an HGFS only registered callback. * * * Results: * TRUE if successfully processed FALSE otherwise. * * Side effects: * None * *---------------------------------------------------------------------------- */ Bool HgfsChannelGuest_Receive(HgfsServerMgrData *mgrData, // IN/OUT : conn manager char const *packetIn, // IN: incoming packet size_t packetInSize, // IN: incoming packet size char *packetOut, // OUT: outgoing packet size_t *packetOutSize) // IN/OUT: outgoing packet size { HgfsChannelData *channel; Bool result = FALSE; ASSERT(NULL != mgrData); ASSERT(NULL != mgrData->connection); ASSERT(NULL != mgrData->appName); channel = mgrData->connection; Debug("%s: %s Channel receive request.\n", __FUNCTION__, mgrData->appName); if (HgfsChannelIsChannelActive(channel)) { result = HgfsChannelReceive(channel, packetIn, packetInSize, packetOut, packetOutSize); } Debug("%s: Channel receive returns %#x.\n", __FUNCTION__, result); return result; } /* *---------------------------------------------------------------------------- * * HgfsChannelGuest_InvalidateInactiveSessions - * * Sends a request to invalidate all the inactive HGFS server sessions. * * Results: * Number of active sessions remaining inside the HGFS server. * * Side effects: * None * *---------------------------------------------------------------------------- */ uint32 HgfsChannelGuest_InvalidateInactiveSessions(HgfsServerMgrData *mgrData) // IN: conn manager { HgfsChannelData *channel; uint32 result = 0; ASSERT(NULL != mgrData); ASSERT(NULL != mgrData->connection); ASSERT(NULL != mgrData->appName); channel = mgrData->connection; Debug("%s: %s Channel. Invalidating inactive sessions.\n", __FUNCTION__, mgrData->appName); if (HgfsChannelIsChannelActive(channel)) { result = channel->ops->invalidateInactiveSessions(channel->connection); } return result; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerManagerGuest/hgfsChannelGuestBd.c000066400000000000000000000504641470176644300313630ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2017,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsChannel.c -- * * Channel abstraction for the HGFS server. * */ #include #include "vm_basic_defs.h" #include "vm_assert.h" #include "vm_atomic.h" #include "util.h" #include "hgfsChannelGuestInt.h" #include "hgfsServer.h" #include "hgfsServerManager.h" typedef enum { HGFS_GST_CONN_UNINITIALIZED, HGFS_GST_CONN_NOTCONNECTED, HGFS_GST_CONN_CONNECTED, } HgfsGuestConnState; /* Since there is only one connection we use globals. */ typedef struct HgfsGuestConn { Atomic_uint32 refCount; /* Reference count. */ HgfsGuestConnState state; const HgfsServerSessionCallbacks *serverCbTable; /* Server session callbacks. */ HgfsServerChannelCallbacks channelCbTable; void *serverSession; size_t packetOutLen; unsigned char *clientPacketOut; /* Client supplied buffer. */ unsigned char packetOut[HGFS_LARGE_PACKET_MAX]; /* For RPC msg callbacks. */ } HgfsGuestConn; /* Callback functions. */ static Bool HgfsChannelGuestBdInit(const HgfsServerSessionCallbacks *serverCBTable, void *rpc, void *rpcCallback, HgfsGuestConn **connection); static void HgfsChannelGuestBdExit(HgfsGuestConn *data); static Bool HgfsChannelGuestBdSend(void *data, HgfsPacket *packet, HgfsSendFlags flags); static Bool HgfsChannelGuestBdReceive(HgfsGuestConn *data, char const *packetIn, size_t packetInSize, char *packetOut, size_t *packetOutSize); static uint32 HgfsChannelGuestBdInvalidateInactiveSessions(HgfsGuestConn *data); const HgfsGuestChannelCBTable gGuestBackdoorOps = { HgfsChannelGuestBdInit, HgfsChannelGuestBdExit, HgfsChannelGuestBdReceive, HgfsChannelGuestBdInvalidateInactiveSessions, }; /* Private functions. */ static Bool HgfsChannelGuestConnConnect(HgfsGuestConn *connData); static void HgfsChannelGuestConnDestroy(HgfsGuestConn *connData); static Bool HgfsChannelGuestReceiveInternal(HgfsGuestConn *connData, char const *packetIn, size_t packetInSize, char *packetOut, size_t *packetOutSize); /* *---------------------------------------------------------------------------- * * CONNECTION DATA FUNCTIONS * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * HgfsChannelGuestConnGet -- * * Increment connection reference count. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsChannelGuestConnGet(HgfsGuestConn *connData) // IN: connection { ASSERT(connData); Atomic_Inc(&connData->refCount); } /* *---------------------------------------------------------------------------- * * HgfsChannelGuestConnPut -- * * Decrement connection reference count. * * Free connection data if this is the last reference. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsChannelGuestConnPut(HgfsGuestConn *connData) // IN: connection { ASSERT(connData); if (Atomic_ReadDec32(&connData->refCount) == 1) { HgfsChannelGuestConnDestroy(connData); } } /* *----------------------------------------------------------------------------- * * HgfsChannelGuestConnInit -- * * Initializes the connection. * * Results: * TRUE always and the channel initialized. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsChannelGuestConnInit(HgfsGuestConn **connData, // IN/OUT: channel object const HgfsServerSessionCallbacks *serverCBTable) // IN: server callbacks { HgfsGuestConn *conn = NULL; conn = Util_SafeCalloc(1, sizeof *conn); /* Give ourselves a reference of one. */ HgfsChannelGuestConnGet(conn); conn->serverCbTable = serverCBTable; conn->state = HGFS_GST_CONN_NOTCONNECTED; *connData = conn; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsChannelGuestConnExit -- * * Teardown the connection. * * Removes the reference and if it is the last will cause the connection * to be destroyed. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsChannelGuestConnExit(HgfsGuestConn *connData) // IN/OUT: channel object { connData->state = HGFS_GST_CONN_UNINITIALIZED; HgfsChannelGuestConnPut(connData); } /* *----------------------------------------------------------------------------- * * HgfsChannelGuestConnDestroy -- * * Destroy the connection. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsChannelGuestConnDestroy(HgfsGuestConn *connData) // IN/OUT: channel object { /* Make sure the server closes it's own session data. */ if (NULL != connData->serverSession) { connData->serverCbTable->close(connData->serverSession); connData->serverSession = NULL; } free(connData); } /* *----------------------------------------------------------------------------- * * HgfsChannelGuestConnCreate -- * * Create's the RPC connection for the HGFS guest if asked. * * Create the pseudo connection for the guest - state transition. * (See the comment in the function where the RPC initialization * is expected to be added. * This entails is registering our callback to receive messages for the * connection object passed. We will have the ability to receive * requests until we unregister our callback.) * * NOTE: There is only handler and connction that can be used for * all HGFS guest requests. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsChannelGuestConnCreate(HgfsGuestConn *connData, // IN: connection void *rpc, // IN: Rpc channel unused void *rpcCallback) // IN: Rpc callback unused { ASSERT(connData->state == HGFS_GST_CONN_NOTCONNECTED); /* * Rpc may be NULL for some cases. For example, if we * just need to provide an HGFS server connection * not associated with an HGFS only RPC connection. */ if (connData->state == HGFS_GST_CONN_NOTCONNECTED) { /* XXX - Here is where we would register an RPC callback if required. */ connData->state = HGFS_GST_CONN_CONNECTED; HgfsChannelGuestConnGet(connData); } } /* *----------------------------------------------------------------------------- * * HgfsChannelGuestConnClose -- * * Closes the connection for the HGFS guest. * * If required unregisters the callback will prevent us from * receiving any more requests closing the connection. * * Results: * TRUE if closed, FALSE if was not connected. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static Bool HgfsChannelGuestConnClose(HgfsGuestConn *connData, // IN: Connection void *rpc, // IN: Rpc channel unused void *rpcCallback) // IN: Rpc callback unused { Bool result = FALSE; if (connData->state == HGFS_GST_CONN_CONNECTED) { /* XXX - Here is where we would unregister an RPC callback. */ /* Clear the connection object since we are unregistered. */ connData->state = HGFS_GST_CONN_NOTCONNECTED; HgfsChannelGuestConnPut(connData); result = TRUE; } return result; } /* *----------------------------------------------------------------------------- * * HgfsChannelGuestConnConnect -- * * Send connection to the server. * * Results: * TRUE if server returns a data object, FALSE if not. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsChannelGuestConnConnect(HgfsGuestConn *connData) // IN: our connection data { Bool result; static HgfsServerChannelData HgfsBdCapData = { 0, HGFS_LARGE_PACKET_MAX }; connData->channelCbTable.getWriteVa = NULL; connData->channelCbTable.getReadVa = NULL; connData->channelCbTable.putVa = NULL; connData->channelCbTable.send = HgfsChannelGuestBdSend; result = connData->serverCbTable->connect(connData, &connData->channelCbTable, &HgfsBdCapData, &connData->serverSession); if (result) { HgfsChannelGuestConnGet(connData); } return result; } /* *----------------------------------------------------------------------------- * * HgfsChannelGuestConnDisconnect -- * * Send disconnect to the server. * * NOTE: The server data will be maintained until * the connection is totally closed (last reference is gone). * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void HgfsChannelGuestConnDisconnect(HgfsGuestConn *connData) // IN: connection { if (connData->serverSession != NULL) { /* Tell the server to to disconnect the session. */ connData->serverCbTable->disconnect(connData->serverSession); HgfsChannelGuestConnPut(connData); } } /* *---------------------------------------------------------------------------- * * HgfsChannelGuestConnCloseInternal -- * * Close the client and send a disconnect to the server for the session. * * Results: * None. * * Side effects: * Closes the client connection and empties the queues. * *---------------------------------------------------------------------------- */ static void HgfsChannelGuestConnCloseInternal(HgfsGuestConn *connData, // IN: Connection data void *rpc, // IN: Rpc channel unused void *rpcCallback) // IN: Rpc callback unused { /* Close (unregister the backdoor RPC) connection. */ if (HgfsChannelGuestConnClose(connData, rpc, rpcCallback)) { /* Disconnect the connection from the server. */ HgfsChannelGuestConnDisconnect(connData); } } /* *---------------------------------------------------------------------------- * * HgfsChannelGuestReceiveInternal -- * * Process packet not associated with any session. * * This function is used in the HGFS server inside Tools. * * Create an internal session if not already created, and process the packet. * * Results: * TRUE if received packet ok and processed, FALSE otherwise. * * Side effects: * None * *---------------------------------------------------------------------------- */ static Bool HgfsChannelGuestReceiveInternal(HgfsGuestConn *connData, // IN: connection char const *packetIn, // IN: incoming packet size_t packetInSize, // IN: incoming packet size char *packetOut, // OUT: outgoing packet size_t *packetOutSize) // IN/OUT: outgoing packet size { HgfsPacket packet; ASSERT(packetIn); ASSERT(packetOut); ASSERT(packetOutSize); if (connData->state == HGFS_GST_CONN_UNINITIALIZED) { /* The connection was closed as we are exiting, so bail. */ *packetOutSize = 0; return FALSE; } /* This is just a ping, return nothing. */ if (*packetOutSize == 0) { return TRUE; } /* * Create the session if not already created. * This session is destroyed in HgfsServer_ExitState. */ if (connData->serverSession == NULL) { /* Do our guest connect now which will inform the server. */ if (!HgfsChannelGuestConnConnect(connData)) { *packetOutSize = 0; return FALSE; } } memset(&packet, 0, sizeof packet); /* For backdoor there is only one iov */ packet.iov[0].va = (void *)packetIn; packet.iov[0].len = packetInSize; packet.iovCount = 1; packet.metaPacket = (void *)packetIn; packet.metaPacketDataSize = packetInSize; packet.metaPacketSize = packetInSize; packet.replyPacket = packetOut; packet.replyPacketSize = *packetOutSize; packet.state |= HGFS_STATE_CLIENT_REQUEST; /* The server will perform a synchronous processing of requests. */ connData->serverCbTable->receive(&packet, connData->serverSession); *packetOutSize = connData->packetOutLen; return TRUE; } /* *---------------------------------------------------------------------------- * * REGISTERED CALLBACK FUNCTIONS * * XXX - Where we would have any internally registered callback routines. * This routine would call HgfsChannelGuestReceiveInternal to process the * request. * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * GUEST CHANNEL CALLBACKS * *---------------------------------------------------------------------------- */ /* *---------------------------------------------------------------------------- * * HgfsChannelGuestBdReceive -- * * Process packet not associated with our registered callback. * * * Results: * TRUE if received packet ok and processed, FALSE otherwise. * * Side effects: * None * *---------------------------------------------------------------------------- */ Bool HgfsChannelGuestBdReceive(HgfsGuestConn *connData, // IN: connection char const *packetIn, // IN: incoming packet size_t packetInSize, // IN: incoming packet size char *packetOut, // OUT: outgoing packet size_t *packetOutSize) // IN/OUT: outgoing packet size { Bool result = TRUE; ASSERT(NULL != packetIn); ASSERT(NULL != packetOut); ASSERT(NULL != packetOutSize); ASSERT(NULL != connData); if (NULL == connData) { result = FALSE; goto exit; } connData->packetOutLen = *packetOutSize; connData->clientPacketOut = packetOut; result = HgfsChannelGuestReceiveInternal(connData, packetIn, packetInSize, connData->clientPacketOut, packetOutSize); connData->clientPacketOut = NULL; connData->packetOutLen = sizeof connData->packetOut; exit: return result; } /* *---------------------------------------------------------------------------- * * HgfsChannelGuestBdInvalidateInactiveSessions -- * * Sends a request to invalidate all the inactive HGFS server sessions. * * Results: * Number of active sessions remaining inside the HGFS server. * * Side effects: * None * *---------------------------------------------------------------------------- */ uint32 HgfsChannelGuestBdInvalidateInactiveSessions(HgfsGuestConn *connData) // IN: connection { ASSERT(NULL != connData); if (NULL == connData) { return 0; } if (connData->state == HGFS_GST_CONN_UNINITIALIZED) { /* The connection was closed as we are exiting, so bail. */ return 0; } /* The server will perform a synchronous processing of requests. */ if (connData->serverSession) { return connData->serverCbTable->invalidateInactiveSessions(connData->serverSession); } return 0; } /* *----------------------------------------------------------------------------- * * HgfsChannelGuestBdSend -- * * Send reply to the request * * Results: * Always TRUE. * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsChannelGuestBdSend(void *conn, // IN: our connection data HgfsPacket *packet, // IN/OUT: Hgfs Packet HgfsSendFlags flags) // IN: Flags to say how to process { HgfsGuestConn *connData = conn; ASSERT(NULL != connData); ASSERT(NULL != packet); ASSERT(NULL != packet->replyPacket); ASSERT(packet->replyPacketDataSize <= connData->packetOutLen); ASSERT(packet->replyPacketSize == connData->packetOutLen); if (packet->replyPacketDataSize > connData->packetOutLen) { packet->replyPacketDataSize = connData->packetOutLen; } connData->packetOutLen = (uint32)packet->replyPacketDataSize; if (!(flags & HGFS_SEND_NO_COMPLETE)) { connData->serverCbTable->sendComplete(packet, connData->serverSession); } return TRUE; } /* *---------------------------------------------------------------------------- * * HgfsChannelGuestBdInit -- * * Called from channel manager. * * Initializes our channel connections. * * Results: * Always TRUE. * * Side effects: * Registers RPC call. * *---------------------------------------------------------------------------- */ static Bool HgfsChannelGuestBdInit(const HgfsServerSessionCallbacks *serverCBTable, // IN: server callbacks void *rpc, // IN: Rpc channel unused void *rpcCallback, // IN: Rpc callback unused HgfsGuestConn **connection) // OUT: connection object { HgfsGuestConn *connData = NULL; Bool result; ASSERT(NULL != connection); /* Create our connection object. */ result = HgfsChannelGuestConnInit(&connData, serverCBTable); if (!result) { Debug("%s: Error: guest connection initialized.\n", __FUNCTION__); goto exit; } /* * Create our connection now with any rpc handle and callback. */ HgfsChannelGuestConnCreate(connData, rpc, rpcCallback); exit: if (!result) { if (NULL != connData) { HgfsChannelGuestBdExit(connData); connData = NULL; } } *connection = connData; Debug("%s: guest initialized.\n", __FUNCTION__); return result; } /* *---------------------------------------------------------------------------- * * HgfsChannelGuestBdExit -- * * Tearsdown our channel connections. * * Results: * None. * * Side effects: * Unregisters RPC call. * *---------------------------------------------------------------------------- */ static void HgfsChannelGuestBdExit(HgfsGuestConn *connData) { ASSERT(NULL != connData); if (NULL != connData) { /* Currently no rpc to unregister. */ HgfsChannelGuestConnCloseInternal(connData, NULL, NULL); HgfsChannelGuestConnExit(connData); } } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerManagerGuest/hgfsChannelGuestInt.h000066400000000000000000000051151470176644300315660ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _HGFSCHANNELGUESTINT_H_ #define _HGFSCHANNELGUESTINT_H_ #if defined(VMTOOLS_USE_GLIB) #define G_LOG_DOMAIN "hgfsd" #define Debug g_debug #define Warning g_warning #else #include "debug.h" #endif #include "hgfsServer.h" #include "hgfsServerManager.h" /** * @file hgfsChannelGuestInt.h * * Prototypes of Hgfs channel packet process handler found in * hgfsChannelGuest.c */ /* * Opaque structure owned by the guest channel to hold the connection * data to the HGFS server. Only held by the channel manager to pass * back to the guest channel for requests and teardown. * (Or it would be used with any registered internal callback.) */ struct HgfsGuestConn; /* * Guest channel table of callbacks. */ typedef struct HgfsGuestChannelCBTable { Bool (*init)(const HgfsServerSessionCallbacks *, void *, void *, struct HgfsGuestConn **); void (*exit)(struct HgfsGuestConn *); Bool (*receive)(struct HgfsGuestConn *, char const *, size_t, char *, size_t *); uint32 (*invalidateInactiveSessions)(struct HgfsGuestConn *); } HgfsGuestChannelCBTable; /* The guest channels callback tables. */ extern const HgfsGuestChannelCBTable gGuestBackdoorOps; /* For use by HgfsServerManager. */ Bool HgfsChannelGuest_Init(HgfsServerMgrData *data, HgfsServerMgrCallbacks *cb); void HgfsChannelGuest_Exit(HgfsServerMgrData *data); Bool HgfsChannelGuest_Receive(HgfsServerMgrData *data, char const *packetIn, size_t packetInSize, char *packetOut, size_t *packetOutSize); uint32 HgfsChannelGuest_InvalidateInactiveSessions(HgfsServerMgrData *data); #endif /* _HGFSCHANNELGUESTINT_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerManagerGuest/hgfsServerManagerGuest.c000066400000000000000000000157661470176644300323140ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006,2014-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerManagerGuest.c -- * * Functionality to utilize the hgfs server in bora/lib from within * a guest application. * */ #include #include "hgfsServerPolicy.h" #include "hgfsChannelGuestInt.h" #include "hgfsServerManager.h" #include "vm_basic_defs.h" #include "vm_assert.h" #include "vm_atomic.h" #include "hgfs.h" /* * Local for now and will be used in conjunction with the manager data passed * on registration. */ typedef struct HgfsServerMgrCountedCallbacks { HgfsServerMgrCallbacks serverMgrCBTable; /* Hgfs server policy manager entry points. */ Atomic_uint32 refCount; /* Server data reference count. */ } HgfsServerMgrCountedCallbacks; static HgfsServerMgrCountedCallbacks gHgfsServerManagerGuestData; /* *---------------------------------------------------------------------------- * * HgfsServerManagerGet -- * * Increment server manager reference count. * * Results: * The value of the reference count before the increment. * * Side effects: * None. * *---------------------------------------------------------------------------- */ uint32 HgfsServerManagerGet(HgfsServerMgrCountedCallbacks *serverMgrData) // IN/OUT: ref count { ASSERT(NULL != serverMgrData); return Atomic_ReadInc32(&serverMgrData->refCount); } /* *---------------------------------------------------------------------------- * * HgfsServerManagerPut -- * * Decrement server manager reference count. * * Teardown server manager object if removed the final reference. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static void HgfsServerManagerPut(HgfsServerMgrCountedCallbacks *serverMgrData) // IN/OUT: ref count { ASSERT(NULL != serverMgrData); if (Atomic_ReadDec32(&serverMgrData->refCount) == 1) { HgfsServerPolicy_Cleanup(); memset(serverMgrData, 0, sizeof *serverMgrData); } } /* *---------------------------------------------------------------------------- * * HgfsServerManager_ProcessPacket -- * * Handles hgfs requests from a client not by our * registered RPC callback. * * Results: * TRUE on success, FALSE on error. * * Side effects: * None. * *---------------------------------------------------------------------------- */ Bool HgfsServerManager_ProcessPacket(HgfsServerMgrData *mgrData, // IN: hgfs mgr char const *packetIn, // IN: rqst size_t packetInSize, // IN: rqst size char *packetOut, // OUT: rep size_t *packetOutSize) // IN/OUT: rep buf/data size { Debug("%s: Processing Packet for %s.\n", __FUNCTION__, mgrData->appName); /* Pass to the channel to handle processing and the server. */ return HgfsChannelGuest_Receive(mgrData, packetIn, packetInSize, packetOut, packetOutSize); } /* *---------------------------------------------------------------------------- * * HgfsServerManager_Register -- * * Registers the hgfs server to be used in classic synchronous fashion. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * Hgfs packets sent to this channel will be handled. * *---------------------------------------------------------------------------- */ Bool HgfsServerManager_Register(HgfsServerMgrData *data) // IN: RpcIn channel { HgfsServerMgrCallbacks *serverMgrCallbacks = &gHgfsServerManagerGuestData.serverMgrCBTable; uint32 serverMgrRefCount; ASSERT(data); ASSERT(data->appName); Debug("%s: Register %s.\n", __FUNCTION__, data->appName); /* * Reference the global server manager data. Initialize only for the first * caller to register. */ serverMgrRefCount = HgfsServerManagerGet(&gHgfsServerManagerGuestData); if (0 == serverMgrRefCount) { Debug("%s: calling policy init %s.\n", __FUNCTION__, data->appName); /* * Passing NULL here is safe because the shares maintained by the guest * policy server never change, eliminating the need for an invalidate * function. */ if (!HgfsServerPolicy_Init(NULL, &serverMgrCallbacks->enumResources)) { HgfsServerManagerPut(&gHgfsServerManagerGuestData); return FALSE; } } /* * The channel will reference count itself, initializing once, but store the * channel in the manager data object passed to us and return it to the caller. */ if (!HgfsChannelGuest_Init(data, serverMgrCallbacks)) { HgfsServerManagerPut(&gHgfsServerManagerGuestData); return FALSE; } return TRUE; } /* *---------------------------------------------------------------------------- * * HgfsServerManager_InvalidateInactiveSessions -- * * Sends a request to invalidate all the inactive HGFS server sessions. * * Results: * Number of active sessions remaining inside the HGFS server. * * Side effects: * None. * *---------------------------------------------------------------------------- */ uint32 HgfsServerManager_InvalidateInactiveSessions(HgfsServerMgrData *mgrData) // IN: RpcIn channel { ASSERT(mgrData); Debug("%s: Invalidate Inactive Sessions for %s.\n", __FUNCTION__, mgrData->appName); return HgfsChannelGuest_InvalidateInactiveSessions(mgrData); } /* *---------------------------------------------------------------------------- * * HgfsServerManager_Unregister -- * * Cleans up the hgfs server. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ void HgfsServerManager_Unregister(HgfsServerMgrData *data) // IN: RpcIn channel { ASSERT(data); ASSERT(data->appName != NULL); Debug("%s: Unregister %s.\n", __FUNCTION__, data->appName); HgfsChannelGuest_Exit(data); HgfsServerManagerPut(&gHgfsServerManagerGuestData); } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerPolicyGuest/000077500000000000000000000000001470176644300253755ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerPolicyGuest/Makefile.am000066400000000000000000000020251470176644300274300ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libHgfsServerPolicyGuest.la libHgfsServerPolicyGuest_la_SOURCES = libHgfsServerPolicyGuest_la_SOURCES += hgfsServerPolicyGuest.c open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c000066400000000000000000000451301470176644300320520ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsServerPolicyGuest.c -- * * Implementation of access policy for hgfs server running in a * VM. All access is allowed. */ #ifdef sun # include # include #elif defined(__FreeBSD__) # include #endif #undef LOG #define LGLEVEL (10) #define LGPFX_FMT "%s:%s:" #define LGPFX "hgfsd" #if defined VMTOOLS_USE_GLIB #define G_LOG_DOMAIN LGPFX #define Debug g_debug #define Warning g_warning #else #include "debug.h" #endif #define DOLOG(_min) ((_min) <= LGLEVEL) #define LOG(_level, args) \ do { \ if (DOLOG(_level)) { \ Debug(LGPFX_FMT, LGPFX, __FUNCTION__); \ Debug args; \ } \ } while (0) #include "vmware.h" #include "hgfsServerPolicy.h" typedef struct HgfsServerPolicyState { /* * An empty list means that the policy server enforces the "deny all access * requests" policy --hpreg */ DblLnkLst_Links shares; } HgfsServerPolicyState; static HgfsServerPolicyState myState; static void * HgfsServerPolicyEnumSharesInit(void); static Bool HgfsServerPolicyEnumSharesGet(void *data, char const **name, size_t *len, Bool *done); static Bool HgfsServerPolicyEnumSharesExit(void *data); /* *----------------------------------------------------------------------------- * * HgfsServerPolicyDestroyShare -- * * Destroy the internal representation of a share --hpreg * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerPolicyDestroyShare(HgfsSharedFolder *share) // IN { ASSERT(share); free(share); } /* *----------------------------------------------------------------------------- * * HgfsServerPolicyDestroyShares -- * * Destroy the internal representation of all shares. The function is * idempotent --hpreg * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static void HgfsServerPolicyDestroyShares(DblLnkLst_Links *head) // IN { ASSERT(head); while (head->next != head) { HgfsSharedFolder *share; share = DblLnkLst_Container(head->next, HgfsSharedFolder, links); ASSERT(share); DblLnkLst_Unlink1(&share->links); HgfsServerPolicyDestroyShare(share); } } /* *----------------------------------------------------------------------------- * * HgfsServerPolicy_Init -- * * Initialize the HGFS security server state. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsServerPolicy_Init(HgfsInvalidateObjectsFunc invalidateObjects, // Unused HgfsServerResEnumCallbacks *enumResources) // OUT enum callbacks { HgfsSharedFolder *rootShare; /* * Currently these callbacks are not used, so make sure our caller doesn't pass * it in. */ ASSERT(invalidateObjects == NULL); LOG(8, ("HgfsServerPolicy_Init: enter\n")); DblLnkLst_Init(&myState.shares); /* For the guest, we hard code a "root" share */ rootShare = (HgfsSharedFolder *)malloc(sizeof *rootShare); if (!rootShare) { LOG(4, ("HgfsServerPolicy_Init: memory allocation failed\n")); return FALSE; } DblLnkLst_Init(&rootShare->links); /* * A path = "" has special meaning; it indicates that access is * granted to the root of the server filesystem, and in Win32 * causes everything after the share name in the request to be * interpreted as either a drive letter or UNC name. [bac] */ rootShare->path = ""; rootShare->name = HGFS_SERVER_POLICY_ROOT_SHARE_NAME; rootShare->readAccess = TRUE; rootShare->writeAccess = TRUE; /* These are strictly optimizations to save work later */ rootShare->pathLen = strlen(rootShare->path); rootShare->nameLen = strlen(rootShare->name); rootShare->handle = HGFS_INVALID_FOLDER_HANDLE; /* Add the root node to the end of the list */ DblLnkLst_LinkLast(&myState.shares, &rootShare->links); /* * Fill the share enumeration callback table. */ enumResources->init = HgfsServerPolicyEnumSharesInit; enumResources->get = HgfsServerPolicyEnumSharesGet; enumResources->exit = HgfsServerPolicyEnumSharesExit; LOG(8, ("HgfsServerPolicy_Init: exit\n")); return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicy_Cleanup -- * * Cleanup the HGFS security server state. * * Results: * TRUE on success * FALSE on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsServerPolicy_Cleanup(void) { LOG(8, ("HgfsServerPolicy_Cleanup: enter\n")); HgfsServerPolicyDestroyShares(&myState.shares); LOG(8, ("HgfsServerPolicy_Cleanup: exit\n")); return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicyGetShare -- * * Get the share whose name matches the given name (if any). * * Results: * The share, if a match is found. * NULL otherwise * * Side effects: * None * *----------------------------------------------------------------------------- */ static HgfsSharedFolder * HgfsServerPolicyGetShare(HgfsServerPolicyState *state, // IN char const *nameIn, // IN: Name to check size_t nameInLen) // IN: Length of nameIn { DblLnkLst_Links *l; ASSERT(state); ASSERT(nameIn); /* * First try to find a share that matches the given name exactly. * This is to handle the case where 2 share names differ in case only. */ for (l = state->shares.next; l != &state->shares; l = l->next) { HgfsSharedFolder *share; share = DblLnkLst_Container(l, HgfsSharedFolder, links); ASSERT(share); if (nameInLen == share->nameLen && !memcmp(nameIn, share->name, nameInLen)) { return share; } } /* * There was no match. As a fall back try a case insensitive match. * This is because some Windows applications uppercase or lowercase the * entire path before sending the request. */ for (l = state->shares.next; l != &state->shares; l = l->next) { HgfsSharedFolder *share; char *tempName; /* * Null terminate the input name before a case insensitive comparison. * This is just to protect against bad implementations of strnicmp. */ if (!(tempName = (char *)malloc(nameInLen + 1))) { LOG(4, ("HgfsServerPolicyGetShare: couldn't allocate tempName\n")); return NULL; } memcpy(tempName, nameIn, nameInLen); tempName[nameInLen] = 0; share = DblLnkLst_Container(l, HgfsSharedFolder, links); ASSERT(share); if (nameInLen == share->nameLen && #ifdef _WIN32 !strnicmp(tempName, share->name, nameInLen)) { #else !strncasecmp(tempName, share->name, nameInLen)) { #endif free(tempName); return share; } free(tempName); } return NULL; } /* State used by HgfsServerPolicyEnumSharesGet and friends */ typedef struct State { DblLnkLst_Links *next; } GetSharesState; /* *----------------------------------------------------------------------------- * * HgfsServerPolicyEnumSharesInit -- * * Setup state for HgfsServerPolicyEnumSharesGet * * Results: * Pointer to state on success. * NULL on failure. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void * HgfsServerPolicyEnumSharesInit(void) { GetSharesState *that; that = malloc(sizeof *that); if (!that) { LOG(4, ("HgfsServerPolicyEnumSharesInit: couldn't allocate state\n")); return NULL; } that->next = myState.shares.next; return that; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicyEnumSharesGet -- * * Enumerate share names one at a time. * * When finished, sets "done" to TRUE. * * Should be called with the results obtained by calling * HgfsServerPolicyEnumSharesInit. * * Results: * TRUE on success. * FALSE on failure (never happens). * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsServerPolicyEnumSharesGet(void *data, // IN: Callback data char const **name, // OUT: Share name size_t *len, // OUT: Name length Bool *done) // OUT: Completion status { GetSharesState *that; HgfsSharedFolder *share; that = (GetSharesState *)data; ASSERT(that); ASSERT(name); ASSERT(len); ASSERT(done); if (that->next == &myState.shares) { /* No more shares */ *done = TRUE; return TRUE; } share = DblLnkLst_Container(that->next, HgfsSharedFolder, links); ASSERT(share); that->next = share->links.next; *name = share->name; *len = share->nameLen; LOG(4, ("HgfsServerPolicyEnumSharesGet: Share name is \"%s\"\n", *name)); *done = FALSE; return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicyEnumSharesExit -- * * Cleanup state from HgfsServerPolicyEnumSharesGet * * Results: * TRUE on success. * FALSE on failure (never happens). * * Side effects: * None * *----------------------------------------------------------------------------- */ static Bool HgfsServerPolicyEnumSharesExit(void *data) // IN: Callback data { GetSharesState *that; that = (GetSharesState *)data; ASSERT(that); free(that); return TRUE; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicy_GetSharePath -- * * Get the local path for a share name by looking at the requested * name, finding the matching share (if any), checking access * permissions, and returning the share's local path. * * Results: * An HgfsNameStatus value indicating the result is returned. * * The local path for the shareName is also returned if a match is found and * access is permitted. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsNameStatus HgfsServerPolicy_GetSharePath(char const *nameIn, // IN: Name to check size_t nameInLen, // IN: Length of nameIn HgfsOpenMode mode, // IN: Requested access mode size_t *sharePathLen, // OUT: Length of share path char const **sharePath) // OUT: Share path { HgfsSharedFolder *myShare; ASSERT(nameIn); ASSERT(sharePathLen); ASSERT(sharePath); myShare = HgfsServerPolicyGetShare(&myState, nameIn, nameInLen); if (!myShare) { LOG(4, ("HgfsServerPolicy_GetSharePath: No matching share name\n")); return HGFS_NAME_STATUS_DOES_NOT_EXIST; } /* * See if access is allowed in the requested mode. * * XXX Yeah, this is retarded. We should be using bits instead of * an enum for HgfsOpenMode. Add it to the todo list. [bac] */ switch (HGFS_OPEN_MODE_ACCMODE(mode)) { case HGFS_OPEN_MODE_READ_ONLY: if (!myShare->readAccess) { LOG(4, ("HgfsServerPolicy_GetSharePath: Read access denied\n")); return HGFS_NAME_STATUS_ACCESS_DENIED; } break; case HGFS_OPEN_MODE_WRITE_ONLY: if (!myShare->writeAccess) { LOG(4, ("HgfsServerPolicy_GetSharePath: Write access denied\n")); return HGFS_NAME_STATUS_ACCESS_DENIED; } break; case HGFS_OPEN_MODE_READ_WRITE: if (!myShare->readAccess || !myShare->writeAccess) { LOG(4, ("HgfsServerPolicy_GetSharePath: Read/write access denied\n")); return HGFS_NAME_STATUS_ACCESS_DENIED; } break; default: LOG(0, ("HgfsServerPolicy_GetSharePath: Invalid mode\n")); return HGFS_NAME_STATUS_FAILURE; break; } *sharePathLen = myShare->pathLen; *sharePath = myShare->path; return HGFS_NAME_STATUS_COMPLETE; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicy_ProcessCPName -- * * Get the local path for a share name by looking at the requested * name, finding the matching share (if any) and returning the share's * local path local path and permissions. * * Results: * An HgfsNameStatus value indicating the result is returned. * * The local path for the shareName is also returned if a match is found. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsNameStatus HgfsServerPolicy_ProcessCPName(char const *nameIn, // IN: name in CPName form size_t nameInLen, // IN: length of the name Bool *readAccess, // OUT: Read permissions Bool *writeAccess, // OUT: Write permissions HgfsSharedFolderHandle *handle,// OUT: folder handle char const **shareBaseDir) // OUT: Shared directory { HgfsSharedFolder *myShare; ASSERT(nameIn); ASSERT(shareBaseDir); myShare = HgfsServerPolicyGetShare(&myState, nameIn, nameInLen); if (!myShare) { LOG(4, ("%s: No matching share name\n", __FUNCTION__)); return HGFS_NAME_STATUS_DOES_NOT_EXIST; } *readAccess = myShare->readAccess; *writeAccess = myShare->writeAccess; *shareBaseDir = myShare->path; *handle = myShare->handle; return HGFS_NAME_STATUS_COMPLETE; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicy_GetShareOptions -- * * Get the HGFS share config options by looking at the requested name, * finding the matching share (if any). * * Results: * HGFS_NAME_STATUS_COMPLETE on success, and HGFS_NAME_STATUS_DOES_NOT_EXIST * if no matching share. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsNameStatus HgfsServerPolicy_GetShareOptions(char const *nameIn, // IN: Share name size_t nameInLen, // IN: Share name length HgfsShareOptions *configOptions)// OUT: Config options { HgfsSharedFolder *share; char const *inEnd; char *next; int len; ASSERT(nameIn); ASSERT(configOptions); inEnd = nameIn + nameInLen; len = CPName_GetComponent(nameIn, inEnd, (char const **) &next); if (len < 0) { LOG(4, ("HgfsServerPolicy_GetShareOptions: get first component failed\n")); return HGFS_NAME_STATUS_FAILURE; } share = HgfsServerPolicyGetShare(&myState, nameIn, len); if (!share) { LOG(4, ("HgfsServerPolicy_GetShareOptions: No matching share name.\n")); return HGFS_NAME_STATUS_DOES_NOT_EXIST; } *configOptions = share->configOptions; return HGFS_NAME_STATUS_COMPLETE; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicy_IsShareOptionSet -- * * Check if the specified config option is set. * * Results: * TRUE if set. * FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ Bool HgfsServerPolicy_IsShareOptionSet(HgfsShareOptions configOptions, // IN: config options uint32 option) // IN: option to check { return (configOptions & option) == option; } /* *----------------------------------------------------------------------------- * * HgfsServerPolicy_GetShareMode -- * * Get the access mode for a share by looking at the requested * name, finding the matching share (if any), and returning * the share's access mode. * * Results: * An HgfsNameStatus value indicating the result is returned. * * The access mode for the shareName is also returned if a match is found. * * Side effects: * None * *----------------------------------------------------------------------------- */ HgfsNameStatus HgfsServerPolicy_GetShareMode(char const *nameIn, // IN: Share name to retrieve size_t nameInLen, // IN: Length of Share name HgfsOpenMode *mode) // OUT: Share's access mode { HgfsSharedFolder *share; ASSERT(nameIn); ASSERT(mode); share = HgfsServerPolicyGetShare(&myState, nameIn, nameInLen); if (!share) { LOG(4, ("HgfsServerPolicy_GetShareMode: No matching share name\n")); return HGFS_NAME_STATUS_DOES_NOT_EXIST; } /* * Get the access mode. */ if (share->readAccess && share->writeAccess) { *mode = HGFS_OPEN_MODE_READ_WRITE; } else if (share->readAccess) { *mode = HGFS_OPEN_MODE_READ_ONLY; } else if (share->writeAccess) { *mode = HGFS_OPEN_MODE_WRITE_ONLY; } else { /* Share should be at least read or write access. */ ASSERT(FALSE); LOG(4, ("HgfsServerPolicy_GetShareMode: Invalid access mode\n")); return HGFS_NAME_STATUS_FAILURE; } return HGFS_NAME_STATUS_COMPLETE; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsUri/000077500000000000000000000000001470176644300224765ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsUri/Makefile.am000066400000000000000000000020561470176644300245350ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2015-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libHgfsUri.la libHgfsUri_la_SOURCES = libHgfsUri_la_SOURCES += hgfsUriPosix.c AM_CFLAGS = AM_CFLAGS += -DVMTOOLS_USE_GLIB AM_CFLAGS += @GLIB2_CPPFLAGS@ open-vm-tools-stable-12.5.0/open-vm-tools/lib/hgfsUri/hgfsUriPosix.c000066400000000000000000000071651470176644300253050ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2015-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsPosix.c -- * * Provides a library for guest applications to convert local pathames to * x-vmware-share:// style URIs */ #if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ # error This file should not be compiled #endif #include "vmware.h" #include "debug.h" #include "str.h" #include #include "hgfsUri.h" #include "hgfsHelper.h" #include "util.h" #include "unicode.h" #include "hgfsEscape.h" #include "ghIntegrationCommon.h" // For GHI_HGFS_SHARE_URL_UTF8 /* *----------------------------------------------------------------------------- * * HgfsUri_ConvertFromPathToHgfsUri -- * * Test the UTF8 pathname to see if it's on an HGFS Share. If it is * construct a UTF8 URI in the form of x-vmware-share://share_name/item.txt. * If not, convert to a regular UTF8 URI string. * * Results: * Filename as UTF8 URI string if success, NULL if failed. * * Side effects: * Memory may be allocated for the returned string. * *----------------------------------------------------------------------------- */ char * HgfsUri_ConvertFromPathToHgfsUri(const char *pathName, // IN: path to convert Bool hgfsOnly) // IN { char *shareUri = NULL; Bool isHgfsName = FALSE; char *sharesDefaultRootPath = NULL; /* We can only operate on full paths. */ if (pathName[0] != DIRSEPC) { return shareUri; } /* Retrieve the servername & share name in use. */ if (!HgfsHlpr_QuerySharesDefaultRootPath(&sharesDefaultRootPath)) { Debug("%s: Unable to query shares default root path\n", __FUNCTION__); goto exit; } if (Unicode_StartsWith(pathName, sharesDefaultRootPath)) { char *relativeSharePath = NULL; char *escapedSharePath = NULL; UnicodeIndex relativePathStart = strlen(sharesDefaultRootPath); if ( strlen(pathName) > relativePathStart && pathName[relativePathStart] == DIRSEPC) { relativePathStart++; } relativeSharePath = Unicode_RemoveRange(pathName, 0, relativePathStart); HgfsEscape_Undo(relativeSharePath, strlen(relativeSharePath) + 1); escapedSharePath = g_uri_escape_string(relativeSharePath, "/", FALSE); shareUri = Unicode_Append(GHI_HGFS_SHARE_URL_UTF8, escapedSharePath); g_free(escapedSharePath); free(relativeSharePath); isHgfsName = TRUE; } exit: if (!isHgfsName && !hgfsOnly) { /* Only convert non-hgfs file name if hgfsOnly is not set. */ char *escapedPath = g_uri_escape_string(pathName, "/", FALSE); shareUri = Str_Asprintf(NULL, "file://%s", escapedPath); g_free(escapedPath); } HgfsHlpr_FreeSharesRootPath(sharesDefaultRootPath); return shareUri; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/impersonate/000077500000000000000000000000001470176644300234155ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/impersonate/Makefile.am000066400000000000000000000021051470176644300254470ustar00rootroot00000000000000################################################################################ ### Copyright (C) 2007-2016 VMware, Inc. All rights reserved. ### ### This program is free software; you can redistribute it and/or modify ### it under the terms of version 2 of the GNU General Public License as ### published by the Free Software Foundation. ### ### 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################################################################ noinst_LTLIBRARIES = libImpersonate.la libImpersonate_la_SOURCES = libImpersonate_la_SOURCES += impersonate.c libImpersonate_la_SOURCES += impersonatePosix.c AM_CFLAGS = @LIB_IMPERSONATE_CPPFLAGS@ open-vm-tools-stable-12.5.0/open-vm-tools/lib/impersonate/impersonate.c000066400000000000000000000235041470176644300261130ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * impersonate.c -- * * Description: * Code to impersonate as a user when running under a privileged account. * Nested impersonation is not supported. */ #include #include "vmware.h" #include "auth.h" #include "userlock.h" #include "mutexRankLib.h" #include "impersonateInt.h" static Atomic_Ptr impersonateLockStorage; Bool impersonationEnabled = FALSE; /* *---------------------------------------------------------------------- * * ImpersonateGetLock -- * * Get/create the impersonate lock. * * Results: * See above. * * Side effects: * See above. * *---------------------------------------------------------------------- */ static INLINE MXUserRecLock * ImpersonateGetLock(void) { MXUserRecLock *lock = MXUser_CreateSingletonRecLock(&impersonateLockStorage, "impersonateLock", RANK_impersonateLock); return lock; } /* *---------------------------------------------------------------------- * * ImpersonateLock -- * * Acquire or release the impersonate lock. Protects access to * the library's static and TLS states. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE void ImpersonateLock(Bool lock) // IN { MXUserRecLock *impersonateLock = ImpersonateGetLock(); if (lock) { MXUser_AcquireRecLock(impersonateLock); } else { MXUser_ReleaseRecLock(impersonateLock); } } /* *---------------------------------------------------------------------- * * Impersonate_Init -- * * Initialize the impersonation module. On windows also load * userenv.dll. * Without calling this, code calling into this module will * essentially be noops. * * Call when single-threaded. * * Side effects: * * Loads the library. We keep the library loaded thereafter. * *---------------------------------------------------------------------- */ void Impersonate_Init(void) { if (!impersonationEnabled) { ImpersonateInit(); impersonationEnabled = TRUE; } } /* *---------------------------------------------------------------------------- * * Impersonate_Runas -- * * Impersonate as the appropriate runas user. In linux this is always * the config file owner regardless the calling context. In windows, the * runas user is the caller passed into the method, except when the VM has * a preconfigured runas user, in which case we will impersonate using his * credentials instead. * * In windows, if caller is not set, fail if preconfigured runas user is * not found. * * Results: * TRUE if impersonation succeeds, FALSE otherwise. * * Side effects: * imp.impersonatedUser may be updated. * *---------------------------------------------------------------------------- */ Bool Impersonate_Runas(const char *cfg, // IN const char *caller, // IN AuthToken callerToken) // IN { Bool res; if (!impersonationEnabled) { return TRUE; } ImpersonateLock(TRUE); res = ImpersonateRunas(cfg, caller, callerToken); ImpersonateLock(FALSE); return res; } /* *---------------------------------------------------------------------------- * * Impersonate_Owner -- * * Impersonate as the owner of the specified file. * * Results: * TRUE if impersonation succeeds, FALSE otherwise. * * Side effects: * imp.impersonatedUser may be updated. * *---------------------------------------------------------------------------- */ Bool Impersonate_Owner(const char *file) // IN { Bool res; if (!impersonationEnabled) { return TRUE; } ImpersonateLock(TRUE); res = ImpersonateOwner(file); ImpersonateLock(FALSE); return res; } /* *---------------------------------------------------------------------------- * * Impersonate_Do -- * * Impersonate as user. Can be nested if impersonated as that same user * each time. Can switch back to root temporarily regardless of nesting * level via Impersonate_ForceRoot. Calling Impersonate_UnforceRoot will * return to original impersonation at the same nesting level. * * Results: * TRUE if impersonation succeeds, FALSE otherwise. * * Side effects: * imp.impersonatedUser may be updated. * imp.impersonatedToken(Win32 only) may be updated. * *---------------------------------------------------------------------------- */ Bool Impersonate_Do(const char *user, // IN AuthToken token) // IN { Bool res; if (!impersonationEnabled) { return TRUE; } ImpersonateLock(TRUE); res = ImpersonateDo(user, token); ImpersonateLock(FALSE); return res; } /* *---------------------------------------------------------------------------- * * Impersonate_Undo -- * * Undoes a previous impersonation. When we undo the last in the nesting * of impersonation ops, switch back to root. * * Results: * TRUE on success, FALSE otherwise * * Side effects: * On reverting back to root, * imp.impersonatedUser is freed. * imp.impersonatedToken (win32) is invalid. * *---------------------------------------------------------------------------- */ Bool Impersonate_Undo(void) { Bool res; ImpersonationState *imp = NULL; if (!impersonationEnabled) { return TRUE; } ImpersonateLock(TRUE); imp = ImpersonateGetTLS(); ASSERT(imp); WIN32_ONLY(ASSERT(!imp->forceRoot)); imp->refCount--; POSIX_ONLY(IMPWARN(("Impersonate_Undo (%x %x) drop refcount to %d\n", getpid(), imp, imp->refCount))); WIN32_ONLY(IMPWARN(("Impersonate_Undo (%x) drop refcount to %d\n", (int) imp, imp->refCount))); if (imp->refCount > 0) { ImpersonateLock(FALSE); return TRUE; } res = ImpersonateUndo(); ImpersonateLock(FALSE); return res; } /* *---------------------------------------------------------------------------- * * Impersonate_Who -- * * Returns currently impersonated user name. If not impersonated, * returns NULL. * * Results: * Currently impersonated user name. NULL if not impersonated. * * Side effects: * None. * *---------------------------------------------------------------------------- */ char * Impersonate_Who(void) { char *impUser; ImpersonationState *imp = NULL; if (!impersonationEnabled) { return strdup(""); } ImpersonateLock(TRUE); imp = ImpersonateGetTLS(); ASSERT(imp); impUser = strdup(imp->impersonatedUser); VERIFY(impUser); ImpersonateLock(FALSE); return impUser; } /* *---------------------------------------------------------------------------- * * Impersonate_ForceRoot -- * * Go back to base impersonate level (LocalSystem/root) for a brief period * of time. Doesnt do anything on linux. * Should only be used when already impersonated. This call is not nestable. * No other impersonation is permitted before calling Impersonate_UnforceRoot. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * imp.forceRoot is set to TRUE on success. * *---------------------------------------------------------------------------- */ Bool Impersonate_ForceRoot(void) { Bool res; if (!impersonationEnabled) { return TRUE; } ImpersonateLock(TRUE); res = ImpersonateForceRoot(); ImpersonateLock(FALSE); return res; } /* *---------------------------------------------------------------------------- * * Impersonate_UnforceRoot -- * * Go back to impersonate the user that we switched to root from. * See Impersonate_ForceRoot. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * imp.forceRoot is set to FALSE on success. * *---------------------------------------------------------------------------- */ Bool Impersonate_UnforceRoot(void) { Bool res; if (!impersonationEnabled) { return TRUE; } ImpersonateLock(TRUE); res = ImpersonateUnforceRoot(); ImpersonateLock(FALSE); return res; } #ifdef _WIN32 /* *---------------------------------------------------------------------------- * * Impersonate_CfgRunasOnly -- * * Impersonate as the preconfigured runas user for the VM. * Fails if runas user credentials are not found. * * Results: * TRUE if preconfigured runas user is found impersonation succeeds, * FALSE otherwise. * * Side effects: * imp.impersonatedUser may be updated. * *---------------------------------------------------------------------------- */ Bool Impersonate_CfgRunasOnly(const char *cfg) // IN { Bool res; ImpersonateLock(TRUE); res = Impersonate_Runas(cfg, NULL, NULL); ImpersonateLock(FALSE); return res; } #endif //_WIN32 open-vm-tools-stable-12.5.0/open-vm-tools/lib/impersonate/impersonateInt.h000066400000000000000000000037641470176644300266010ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * impersonateInt.h -- * * Header file shared by impersonate code */ #ifndef _IMPERSONATE_INT_H_ #define _IMPERSONATE_INT_H_ #include "vmware.h" #include "msg.h" #include "impersonate.h" #include "auth.h" //#define IMP_VERBOSE 1 #define INVALID_PTHREAD_KEY_VALUE (-1) #ifdef IMP_VERBOSE #define IMPWARN(x) Warning x #else #define IMPWARN(x) #endif typedef struct ImpersonationState { const char *impersonatedUser; // the user we are currently impersonating int refCount; // # of times we are impersonating as same user #ifdef _WIN32 HANDLE impersonatedToken; // the access token currently impersonated with Bool forceRoot; // are we temporarily switching back to root? #endif } ImpersonationState; void ImpersonateInit(void); ImpersonationState *ImpersonateGetTLS(void); Bool ImpersonateRunas(const char *cfg, const char *caller, AuthToken callerToken); Bool ImpersonateOwner(const char *file); Bool ImpersonateDo(const char *user, AuthToken token); Bool ImpersonateUndo(void); Bool ImpersonateForceRoot(void); Bool ImpersonateUnforceRoot(void); #endif // ImpersonateInt.h open-vm-tools-stable-12.5.0/open-vm-tools/lib/impersonate/impersonatePosix.c000066400000000000000000000271741470176644300271450ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * impersonatePosix.c -- * * Description: * Posix specific functions to impersonate as specific users. */ #include #include #include #include #include #include #include #include #if !defined(VMX86_TOOLS) #include #endif #include #include "impersonateInt.h" #include "su.h" #include "posix.h" #if !defined(VMX86_TOOLS) static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; static pthread_key_t threadLocalStorageKey = INVALID_PTHREAD_KEY_VALUE; static void ThreadLocalFree(void *ptr); #else static ImpersonationState *impLinux = NULL; #endif static Bool ImpersonateDoPosix(struct passwd *pwd); /* *---------------------------------------------------------------------------- * * ImpersonateInit -- * * Linux specific initialization (thread local storage for linux) * * Results: * None. * * Side effects: * Memory created. * *---------------------------------------------------------------------------- */ void ImpersonateInit(void) { #if !defined(VMX86_TOOLS) int status; status = pthread_key_create(&threadLocalStorageKey, ThreadLocalFree); if (status != 0) { Warning("Impersonate: key_create failed: %d\n", status); VERIFY(status == 0); return; } VERIFY(threadLocalStorageKey != INVALID_PTHREAD_KEY_VALUE); #endif } /* *---------------------------------------------------------------------- * * ThreadLocalFree -- * * A wrapper for "free()". This function is called when a thread * terminates so that the thread-local state can be deallocated. * *---------------------------------------------------------------------- */ #if !defined(VMX86_TOOLS) static void ThreadLocalFree(void *ptr) { ImpersonationState *imp = (ImpersonationState*) ptr; IMPWARN(("Impersonate: ThreadLocalFree(0x%08x)\n", imp)); ASSERT(imp); ASSERT(imp->impersonatedUser == NULL); ASSERT(imp->refCount == 0); free(imp); } #endif /* *---------------------------------------------------------------------------- * * ImpersonateGetTLS -- * * This function abstracts away the differences between Linux and * Windows for obtaining a pointer to thread-local state. * * Results: * Returns pointer to thread-local state. * * Side effects: * On Linux this function will allocate state on the first occasion * that a particular thread calls this function for the first time. * *---------------------------------------------------------------------------- */ ImpersonationState * ImpersonateGetTLS(void) { ImpersonationState *ptr = NULL; int status; /* If a prior call has already allocated state, then use it */ #if !defined(VMX86_TOOLS) /* If a prior call has already allocated state, then use it */ ptr = pthread_getspecific(threadLocalStorageKey); #else ptr = impLinux; #endif if (ptr != NULL) { return ptr; } /* No state allocated, so we need to allocate it */ ptr = calloc(1, sizeof *ptr); VERIFY(ptr); #if !defined(VMX86_TOOLS) status = pthread_setspecific(threadLocalStorageKey, ptr); #else impLinux = ptr; status = 0; #endif if (status != 0) { Warning("Impersonate: setspecific: %d\n", status); VERIFY(status == 0); } return ptr; } /* *---------------------------------------------------------------------------- * * ImpersonateRunas -- * * Impersonate as the appropriate runas user. In linux this is always * the config file owner regardless the calling context. * * Results: * TRUE if impersonation succeeds, FALSE otherwise. * * Side effects: * imp.impersonatedUser may be updated. * *---------------------------------------------------------------------------- */ Bool ImpersonateRunas(const char *cfg, // IN const char *caller, // IN AuthToken callerToken) // IN { /* * In linux, this call always impersonates as the owner of the config file. */ ASSERT(!caller && !callerToken); return ImpersonateOwner(cfg); } /* *---------------------------------------------------------------------------- * * ImpersonateOwner -- * * Impersonate the owner of the config file. Only makes sense on linux. * * Results: * TRUE if impersonation succeeds, false otherwise. * * Side effects: * imp.impersonatedUser may be updated. * *---------------------------------------------------------------------------- */ Bool ImpersonateOwner(const char *file) // IN { struct stat buf; char buffer[BUFSIZ]; struct passwd pw; struct passwd *ppw = &pw; int error; if (Posix_Stat(file, &buf) == -1) { Warning("Failed to lookup owner for: %s. Reason: %s\n", file, Err_Errno2String(errno)); return FALSE; } if ((error = Posix_Getpwuid_r(buf.st_uid, &pw, buffer, BUFSIZ, &ppw)) != 0 || !ppw) { if (error == 0) { error = ENOENT; } Warning("Failed to lookup user with uid: %" FMTUID ". Reason: %s\n", buf.st_uid, Err_Errno2String(error)); return FALSE; } return ImpersonateDoPosix(ppw); } /* *---------------------------------------------------------------------- * * ImpersonateUndo -- Linux specific * * Change back into the superuser * * Side effects: * * EUID is set back to the superuser, and environment variables are * updated back. * *---------------------------------------------------------------------- */ Bool ImpersonateUndo(void) { char buffer[BUFSIZ]; struct passwd pw; struct passwd *ppw = &pw; ImpersonationState *imp = NULL; int ret; int error; #if !defined(VMX86_TOOLS) pthread_mutex_lock(&mut); #endif imp = ImpersonateGetTLS(); ASSERT(imp); //ASSERT(imp->impersonatedUser); if ((error = Posix_Getpwuid_r(0, &pw, buffer, BUFSIZ, &ppw)) != 0 || !ppw) { if (error == 0) { error = ENOENT; } ret = error; Warning("Failed to get password entry for uid 0: %s\n", Err_Errno2String(error)); goto exit; } #if __APPLE__ NOT_IMPLEMENTED(); #else /* Return to root */ ret = Id_SetEUid(ppw->pw_uid); if (ret < 0) { goto exit; } #endif ret = Id_SetGid(ppw->pw_gid); if (ret < 0) { goto exit; } /* * The call to initgroups leaks memory in versions of glibc earlier than 2.1.93. * See bug 10042. -jhu */ ret = initgroups(ppw->pw_name, ppw->pw_gid); if (ret < 0) { goto exit; } /* Restore root's environment */ Posix_Setenv("USER", ppw->pw_name, 1); Posix_Setenv("HOME", ppw->pw_dir, 1); Posix_Setenv("SHELL", ppw->pw_shell, 1); free((char *)imp->impersonatedUser); imp->impersonatedUser = NULL; ret = 0; exit: VERIFY(ret == 0); #if !defined(VMX86_TOOLS) pthread_mutex_unlock(&mut); #endif return (ret ? FALSE : TRUE); } /* *---------------------------------------------------------------------------- * * ImpersonateDoPosix -- * * Impersonate as the user corresponding to the passwd entry * XXX: Mostly copied from vmsd_impersonate.c * * Results: * TRUE if impersonation succeeds, FALSE otherwise. * * Side effects: * imp.impersonatedUser is updated. * *---------------------------------------------------------------------------- */ Bool ImpersonateDoPosix(struct passwd *pwd) // IN { int ret = 0; ImpersonationState *imp = NULL; #if !defined(VMX86_TOOLS) pthread_mutex_lock(&mut); #endif imp = ImpersonateGetTLS(); ASSERT(imp); if (pwd->pw_uid == geteuid()) { imp->refCount++; IMPWARN(("ImpersonateDoPosix (%s : %x : %x) refcount = %d\n", imp->impersonatedUser, getpid(), imp, imp->refCount)); goto unlock; } ASSERT(getuid() == 0); VERIFY(geteuid() == 0); ret = Id_SetGid(pwd->pw_gid); if (ret < 0) { goto exit; } /* * The call to initgroups leaks memory in versions of glibc earlier than * 2.1.93.See bug 10042. -jhu */ ret = initgroups(pwd->pw_name, pwd->pw_gid); if (ret < 0) { goto exit; } #if __APPLE__ NOT_IMPLEMENTED(); #else ret = Id_SetEUid(pwd->pw_uid); if (ret < 0) { goto exit; } #endif /* Setup the user's environment */ Posix_Setenv("USER", pwd->pw_name, 1); Posix_Setenv("HOME", pwd->pw_dir, 1); Posix_Setenv("SHELL", pwd->pw_shell, 1); imp->impersonatedUser = strdup(pwd->pw_name); VERIFY(imp->impersonatedUser); exit: imp->refCount = 1; VERIFY(ret == 0); unlock: #if !defined(VMX86_TOOLS) pthread_mutex_unlock(&mut); #endif return (ret ? FALSE : TRUE); } /* *---------------------------------------------------------------------------- * * ImpersonateDo -- * * Impersonate as user. Can be nested if impersonated as that same user * each time. Can switch back to root temporarily regardless of nesting * level via Impersonate_ForceRoot. Calling Impersonate_UnforceRoot will * return to original impersonation at the same nesting level. * * Results: * TRUE if impersonation succeeds, FALSE otherwise. * * Side effects: * imp.impersonatedUser may be updated. * *---------------------------------------------------------------------------- */ Bool ImpersonateDo(const char *user, // IN AuthToken token) // IN { char buffer[BUFSIZ]; struct passwd pw; struct passwd *ppw = &pw; int error; if ((error = Posix_Getpwnam_r(user, &pw, buffer, BUFSIZ, &ppw)) != 0 || !ppw) { if (error == 0) { error = ENOENT; } Warning("Failed to get password entry for : %s. Reason: %s\n", user, Err_Errno2String(error)); return FALSE; } return ImpersonateDoPosix(ppw); } /* *---------------------------------------------------------------------------- * * ImpersonateForceRoot -- * * Go back to base impersonate level (LocalSystem/root) for a brief * period of time. * Should only be used when already impersonated. This call is not nestable. * No other impersonation is permitted before calling Impersonate_UnforceRoot. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * imp.forceRoot is set to TRUE on success. * *---------------------------------------------------------------------------- */ Bool ImpersonateForceRoot(void) { return TRUE; } /* *---------------------------------------------------------------------------- * * ImpersonateUnforceRoot -- * * Unforce from root to original impersonation context * * Results: * TRUE on success, FALSE otherwise. * * Side effects: * imp.forceRoot is set to FALSE on success * *---------------------------------------------------------------------------- */ Bool ImpersonateUnforceRoot(void) { return TRUE; } open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/000077500000000000000000000000001470176644300225125ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/asyncsocket.h000066400000000000000000001030271470176644300252140ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #ifndef __ASYNC_SOCKET_H__ #define __ASYNC_SOCKET_H__ /* * asyncsocket.h -- * * The AsyncSocket object is a fairly simple wrapper around a basic TCP * socket. It's potentially asynchronous for both read and write * operations. Reads are "requested" by registering a receive function * that is called once the requested amount of data has been read from * the socket. Similarly, writes are queued along with a send function * that is called once the data has been written. Errors are reported via * a separate callback. */ #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_USERLEVEL #ifdef _WIN32 #include #include #else #include #endif #include "includeCheck.h" #if defined(__cplusplus) extern "C" { #endif /* * Error codes */ #define ASOCKERR_SUCCESS 0 #define ASOCKERR_GENERIC 1 #define ASOCKERR_TIMEOUT 2 #define ASOCKERR_NOTCONNECTED 3 #define ASOCKERR_REMOTE_DISCONNECT 4 #define ASOCKERR_INVAL 5 #define ASOCKERR_CONNECT 6 #define ASOCKERR_ACCEPT 7 #define ASOCKERR_POLL 8 #define ASOCKERR_CLOSED 9 #define ASOCKERR_BIND 10 #define ASOCKERR_BINDADDRINUSE 11 #define ASOCKERR_LISTEN 12 #define ASOCKERR_CONNECTSSL 13 #define ASOCKERR_NETUNREACH 14 #define ASOCKERR_ADDRUNRESV 15 #define ASOCKERR_BUSY 16 #define ASOCKERR_PROXY_NEEDS_AUTHENTICATION 17 #define ASOCKERR_PROXY_CONNECT_FAILED 18 #define ASOCKERR_WEBSOCK_UPGRADE_NOT_FOUND 19 #define ASOCKERR_WEBSOCK_TOO_MANY_CONNECTION 20 #define ASOCKERR_PROXY_INVALID_OR_NOT_SUPPORTED 21 /* * Cross-platform codes for AsyncSocket_GetGenericError(): */ #ifdef _WIN32 #define ASOCK_ENOTCONN WSAENOTCONN #define ASOCK_ENOTSOCK WSAENOTSOCK #define ASOCK_EADDRINUSE WSAEADDRINUSE #define ASOCK_ECONNECTING WSAEWOULDBLOCK #define ASOCK_EWOULDBLOCK WSAEWOULDBLOCK #define ASOCK_ENETUNREACH WSAENETUNREACH #define ASOCK_ECONNRESET WSAECONNRESET #define ASOCK_ECONNABORTED WSAECONNABORTED #define ASOCK_EPIPE ERROR_NO_DATA #define ASOCK_EHOSTUNREACH WSAEHOSTUNREACH #define ASOCK_ETIMEDOUT WSAETIMEDOUT #define ASOCK_ECONNREFUSED WSAECONNREFUSED #define ASOCK_EACCES WSAEACCES #else #define ASOCK_ENOTCONN ENOTCONN #define ASOCK_ENOTSOCK ENOTSOCK #define ASOCK_EADDRINUSE EADDRINUSE #define ASOCK_ECONNECTING EINPROGRESS #define ASOCK_EWOULDBLOCK EWOULDBLOCK #define ASOCK_ENETUNREACH ENETUNREACH #define ASOCK_ECONNRESET ECONNRESET #define ASOCK_ECONNABORTED ECONNABORTED #define ASOCK_EPIPE EPIPE #define ASOCK_EHOSTUNREACH EHOSTUNREACH #define ASOCK_ETIMEDOUT ETIMEDOUT #define ASOCK_ECONNREFUSED ECONNREFUSED #define ASOCK_EACCES EACCES #endif /* * Websocket close status codes -- * * enum has numbers in names because RFC6455 refers to the numbers frequently. */ enum { WEB_SOCKET_CLOSE_STATUS_1000_NORMAL = 1000, WEB_SOCKET_CLOSE_STATUS_1001_GOING_AWAY = 1001, WEB_SOCKET_CLOSE_STATUS_1002_PROTOCOL_ERROR = 1002, WEB_SOCKET_CLOSE_STATUS_1003_INVALID_DATA = 1003, WEB_SOCKET_CLOSE_STATUS_1005_EMPTY = 1005, WEB_SOCKET_CLOSE_STATUS_1006_ABNORMAL = 1006, WEB_SOCKET_CLOSE_STATUS_1007_INCONSISTENT_DATA = 1007, WEB_SOCKET_CLOSE_STATUS_1008_POLICY_VIOLATION = 1008, WEB_SOCKET_CLOSE_STATUS_1009_MESSAGE_TOO_BIG = 1009, WEB_SOCKET_CLOSE_STATUS_1010_UNSUPPORTED_EXTENSIONS = 1010, WEB_SOCKET_CLOSE_STATUS_1015_TLS_HANDSHAKE_ERROR = 1015, }; /* * Flags passed into AsyncSocket_Connect*(). * Default value is '0'. * The first two flags allow explicitly selecting * an ESX network stack. They no longer make sense because the * COS is gone. The flags are left around just to ensure we don't have * any flag collisions from users of the library. * The 3rd is for code that uses inet_pton() to get an IP address. * inet_pton() returns address in network-byte-order, * instead of the expected host-byte-order. */ typedef enum { // ASOCKCONN_USE_ESX_SHADOW_STACK = 1<<0, // ASOCKCONN_USE_ESX_NATIVE_STACK = 1<<1, ASOCKCONN_ADDR_IN_NETWORK_BYTE_ORDER = 1<<2 } AsyncSocketConnectFlags; /* * SSL opaque type declarations (so we don't have to include ssl.h) */ struct SSLSockStruct; struct _SSLVerifyParam; /* * AsyncSocket type is opaque */ typedef struct AsyncSocket AsyncSocket; /* * AsyncSocket registers poll callbacks, so give client the opportunity * to control how this is done. * * All the AsyncSocket constructors (Listen, Connect, Attach) take an * optional AsyncSocketPollParam* argument; if NULL the default behavior is * used (callback is registered in POLL_CS_MAIN and locked by the BULL). * Or the client can specify its favorite poll class and locking behavior. * Use of IVmdbPoll is only supported for regular sockets and for Attach. */ #include "poll.h" struct IVmdbPoll; typedef struct AsyncSocketPollParams { int flags; /* Default 0, only POLL_FLAG_NO_BULL is valid */ MXUserRecLock *lock; /* Default: none but BULL */ PollClassSet pollClass; /* Default is POLL_CS_MAIN */ struct IVmdbPoll *iPoll; /* Default NULL: use Poll_Callback */ } AsyncSocketPollParams; /* * Initialize platform libraries */ int AsyncSocket_Init(void); /* * Check the current state of the socket */ typedef enum AsyncSocketState { AsyncSocketListening, AsyncSocketConnecting, AsyncSocketConnected, AsyncSocketCBCancelled, AsyncSocketClosed, AsyncSocketConnectedRdOnly, } AsyncSocketState; typedef struct AsyncSocketNetworkStats { uint32 cwndBytes; /* maximum outstanding bytes */ uint32 rttSmoothedAvgMillis; /* rtt average in milliseconds */ uint32 rttSmoothedVarMillis; /* rtt variance in milliseconds */ uint32 queuedBytes; /* unsent bytes in send queue */ uint32 inflightBytes; /* current outstanding bytes */ double packetLossPercent; /* packet loss percentage */ } AsyncSocketNetworkStats; /* * The following covers all facilities involving dynamic socket options w.r.t. * various async sockets, excluding the async socket options API on the * sockets themselves, which can be found in asyncSocketVTable.h and those * files implementing that API. * * Potential related future work is covered in * asyncsocket/README-asyncSocketOptions-future-work.txt. * * Summary of dynamic socket options: * * Dynamic socket option = setting settable by the async socket API user * including during the lifetime of the socket. An interface spiritually * similar to setsockopt()'s seemed appropriate. * * The option-setting API looks as follows: * * int ...SetOption(AsyncSocket *asyncSocket, * AsyncSocketOpts_Layer layer, // enum type * AsyncSocketOpts_ID optID, // an integer type * const void *valuePtr, * size_t inBufLen) * * Both native (setsockopt()) and non-native (usually, struct member) * options are supported. layer and optID arguments are conceptually similar * to setsockopt() level and option_name arguments, respectively. * * FOR NATIVE (setsockopt()) OPTIONS: * layer = setsockopt() level value. * optID = setsockopt() option_name value. * * FOR NON-NATIVE (struct member inside socket impl.) OPTIONS: * layer = ..._BASE, ..._TCP, ..._FEC, etc. * (pertains to the various AsyncSocket types); * optID = value from enum type appropriate to the chosen layer. * * Examples (prefixes omitted for space): * * -- NATIVE OPTIONS -- * optID | layer | <= | ssopt() level | ssopt() option_name * ---------------+-------------+----+---------------+-------------------- * == option_name | == level | <= | SOL_SOCKET | SO_SNDBUF * == option_name | == level | <= | IPPROTO_TCP | TCP_NODELAY * * -- NON-NATIVE OPTIONS -- * optID | layer | <= | AsyncSocket type(s) * -------------------------------+-------+----+-------------------- * _SEND_LOW_LATENCY_MODE | _BASE | <= | any * (enum AsyncSocket_OptID) | | | * _ALLOW_DECREASING_BUFFER_SIZE | _TCP | <= | AsyncTCPSocket * (enum AsyncTCPSocket_OptID) | | | * _MAX_CWND | _FEC | <= | FECAsyncSocket * (enum FECAsyncSocket_OptID) | | | * * Socket option lists for each non-native layer are just enums. Each socket * type should declare its own socket option enum in its own .h file; e.g., see * AsyncTCPSocket_OptID in this file. Some option lists apply to all async * sockets; these are also here in asyncsocket.h. * * The only way in which different socket option layers coexist in the same * file is the layer enum, AsyncSocketOpts_Layer, in the present file, * which enumerates all possible layers. * * The lack of any other cross-pollution between different non-native option * lists' containing files is a deliberate design choice. */ /* * Integral type used for the optID argument to ->setOption() async socket API. * * For a non-native option, use an enum value for your socket type. * (Example: ASYNC_TCP_SOCKET_OPT_ALLOW_DECREASING_BUFFER_SIZE * of type AsyncTCPSocket_OptID, which would apply to TCP sockets only.) * * For a native (setsockopt()) option, use the setsockopt() integer directly. * (Example: TCP_NODELAY.) * * Let's use a typedef as a small bit of abstraction and to be able to easily * change it to size_t, if (for example) we start indexing arrays with this * thing. */ typedef int AsyncSocketOpts_ID; /* * Enum type used for the layer argument to ->setOption() async socket API. * As explained in the summary comment above, this * informs the particular ->setOption() implementation how to interpret * the accompanying optID integer value, as it may refer to one of several * option lists; and possible different socket instances (not as of this * writing). * * If editing, see summary comment above first for background. * * The values explicitly in this enum are for non-native options. * For native options, simply use the level value as for setsockopt(). * * Ordinal values for all these non-native layers must not clash * with the native levels; hence the `LEVEL + CONSTANT` trick * just below. */ typedef enum { /* * Used when optID applies to a non-native socket option applicable to ANY * async socket type. */ ASYNC_SOCKET_OPTS_LAYER_BASE = SOL_SOCKET + 1000, /* * Next enums must follow the above ordinally, so just: * ASYNC_SOCKET_OPTS_LAYER_, * ASYNC_SOCKET_OPTS_LAYER_, ... */ ASYNC_SOCKET_OPTS_LAYER_BLAST_PROXY, } AsyncSocketOpts_Layer; /* * Enum type used for the OptId argument to ->setOption() async socket API, * when optID refers to a non-native option of any AsyncSocket regardless * of type. */ typedef enum { /* * Bool indicating whether to put the socket into a mode where we attempt * to issue sends directly from within ->send(). Ordinarily * (FALSE), we would set up a Poll callback from within ->send(), * which introduces some non-zero latency to the send path. In * low-latency-send mode (TRUE), that delay is potentially avoided. This * does introduce a behavioral change; the send completion * callback may be triggered before the call to ->send() returns. As * not all clients may be expecting this, we don't enable this mode * unless requested by the client. * * Default: FALSE. */ ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE, /* * This socket config option provides a way to set DSCP value * on the TOS field of IP packet which is a 6 bit value. * Permissible values to configure are 0x0 to 0x3F, although * there are only subset of these values which are widely used. * * Default: 0. */ ASYNC_SOCKET_OPT_DSCP } AsyncSocket_OptID; /* * Note: If you need to add a non-native option that applies to AsyncTCPSockets * only, you'd probably introduce an enum here named AsyncTCPSocket_OptID; and * at least one layer named ASYNC_SOCKET_OPTS_LAYER_TCP in the enum * AsyncSocketOpts_Layer. */ /* API functions for all AsyncSockets. */ AsyncSocketState AsyncSocket_GetState(AsyncSocket *sock); const char * AsyncSocket_Err2String(int err); const char * AsyncSocket_MsgError(int asyncSockErr); int AsyncSocket_GetGenericErrno(AsyncSocket *s); /* * Return a "unique" ID */ int AsyncSocket_GetID(AsyncSocket *asock); /* * Return the fd corresponding to the socket. */ int AsyncSocket_GetFd(AsyncSocket *asock); /* * Return the remote IP address associated with this socket if applicable */ int AsyncSocket_GetRemoteIPStr(AsyncSocket *asock, const char **ipStr); /* * Return the remote port associated with this socket if applicable */ int AsyncSocket_GetRemotePort(AsyncSocket *asock, uint32 *port); int AsyncSocket_GetLocalVMCIAddress(AsyncSocket *asock, uint32 *cid, uint32 *port); int AsyncSocket_GetRemoteVMCIAddress(AsyncSocket *asock, uint32 *cid, uint32 *port); int AsyncSocket_GetINETIPStr(AsyncSocket *asock, int socketFamily, char **ipRetStr); unsigned int AsyncSocket_GetPort(AsyncSocket *asock); /* * Recv callback fires once previously requested data has been received */ typedef void (*AsyncSocketRecvFn) (void *buf, int len, AsyncSocket *asock, void *clientData); /* * Send callback fires once previously queued data has been sent */ typedef void (*AsyncSocketSendFn) (void *buf, int len, AsyncSocket *asock, void *clientData); /* * Error callback fires on I/O errors during read/write operations */ typedef void (*AsyncSocketErrorFn) (int error, AsyncSocket *asock, void *clientData); typedef void (*AsyncSocketConnectFn) (AsyncSocket *asock, void *clientData); typedef void (*AsyncSocketSslAcceptFn) (Bool status, AsyncSocket *asock, void *clientData); typedef void (*AsyncSocketSslConnectFn) (Bool status, AsyncSocket *asock, void *clientData); typedef void (*AsyncSocketCloseFn) (AsyncSocket *asock, void *clientData); /* * Callback to handle http upgrade request header */ typedef int (*AsyncWebSocketHandleUpgradeRequestFn) (AsyncSocket *asock, void *clientData, const char *httpRequest, char **httpResponse); typedef int (*AsyncWebSocketHandoffSocketFn) (AsyncSocket *asock, void *cbData, void *buf, uint32 bufLen, uint32 currentPos); /* * Listen on port and fire callback with new asock */ AsyncSocket *AsyncSocket_Listen(const char *addrStr, unsigned int port, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketPollParams *pollParams, int *outError); AsyncSocket *AsyncSocket_ListenLoopback(unsigned int port, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketPollParams *pollParams, int *outError); AsyncSocket *AsyncSocket_ListenVMCI(unsigned int cid, unsigned int port, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketPollParams *pollParams, int *outError); AsyncSocket *AsyncSocket_ListenWebSocket(const char *addrStr, unsigned int port, Bool useSSL, const char *protocols[], AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketPollParams *pollParams, void *sslCtx, int *outError); AsyncSocket *AsyncSocket_PrepareListenWebSocket(Bool useSSL, const char *protocols[], AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketPollParams *pollParams, void *sslCtx, AsyncWebSocketHandleUpgradeRequestFn handleUpgradeRequestFn, AsyncWebSocketHandoffSocketFn alpnCb, const char* alpn); AsyncSocket *AsyncSocket_RegisterListenWebSocket(AsyncSocket *asock, const char *addrStr, unsigned int port, AsyncSocketPollParams *pollParams, int *outError); AsyncSocket* AsyncSocket_UpgradeToWebSocket(AsyncSocket *asock, const char *protocols[], AsyncSocketConnectFn connectFn, void *clientData, Bool useSSL, void *sslCtx, AsyncWebSocketHandleUpgradeRequestFn handleUpgradeRequestFn, int *outError); #ifndef _WIN32 AsyncSocket *AsyncSocket_ListenWebSocketUDS(const char *pipeName, Bool useSSL, const char *protocols[], AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketPollParams *pollParams, int *outError); AsyncSocket *AsyncSocket_ListenSocketUDS(const char *pipeName, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketPollParams *pollParams, int *outError); #endif /* * Connect to address:port and fire callback with new asock. * If a custom error handler is needed, call AsyncSocket_SetErrorFn immediately * after the new asock is created. If this is done on a thread that is not the * poll thread, both calls should be done under the asyncsocket lock (passed * via pollParams). */ AsyncSocket *AsyncSocket_Connect(const char *hostname, unsigned int port, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketConnectFlags flags, AsyncSocketPollParams *pollParams, int *error); AsyncSocket *AsyncSocket_ConnectWithFd(const char *hostname, unsigned int port, int tcpSocketFd, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketConnectFlags flags, AsyncSocketPollParams *pollParams, int *error); AsyncSocket *AsyncSocket_ConnectVMCI(unsigned int cid, unsigned int port, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketConnectFlags flags, AsyncSocketPollParams *pollParams, int *error); #ifndef _WIN32 AsyncSocket *AsyncSocket_ConnectUnixDomain(const char *path, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketConnectFlags flags, AsyncSocketPollParams *pollParams, int *error); #else AsyncSocket * AsyncSocket_ConnectNamedPipe(const char *pipeName, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketConnectFlags flags, AsyncSocketPollParams *pollParams, int *outError); #define ASOCK_NAMEDPIPE_ALLOW_DEFAULT (0) #define ASOCK_NAMEDPIPE_ALLOW_ADMIN_USER_VMWARE (SDPRIV_GROUP_ADMIN | \ SDPRIV_USER_CURRENT | \ SDPRIV_GROUP_VMWARE) #define ASOCK_NAMEDPIPE_ALLOW_ADMIN_USER (SDPRIV_GROUP_ADMIN | \ SDPRIV_USER_CURRENT) AsyncSocket* AsyncSocket_CreateNamedPipe(const char *pipeName, AsyncSocketConnectFn connectFn, void *clientData, DWORD openMode, DWORD pipeMode, uint32 numInstances, DWORD accessType, AsyncSocketPollParams *pollParams, int *error); AsyncSocket * AsyncSocket_AttachToNamedPipe(HANDLE handle, AsyncSocketPollParams *pollParams, int *outError); /* * Obtain the client process id of the given named pipe */ Bool AsyncSocket_GetNamedPipeClientProcessId(AsyncSocket* asock, PULONG clientPid); #endif AsyncSocket * AsyncSocket_ConnectWebSocket(const char *url, struct _SSLVerifyParam *sslVerifyParam, const char *httpProxy, const char *cookies, const char *protocols[], AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketConnectFlags flags, AsyncSocketPollParams *pollParams, int *error); /* * Initiate SSL connection on existing asock, with optional cert verification */ Bool AsyncSocket_ConnectSSL(AsyncSocket *asock, struct _SSLVerifyParam *verifyParam, const char *hostname, void *sslContext); int AsyncSocket_StartSslConnect(AsyncSocket *asock, struct _SSLVerifyParam *verifyParam, const char *hostname, void *sslCtx, AsyncSocketSslConnectFn sslConnectFn, void *clientData); Bool AsyncSocket_AcceptSSL(AsyncSocket *asock, void *sslCtx); int AsyncSocket_StartSslAccept(AsyncSocket *asock, void *sslCtx, AsyncSocketSslAcceptFn sslAcceptFn, void *clientData); /* * Create a new AsyncSocket from an existing socket */ AsyncSocket *AsyncSocket_AttachToFd(int fd, AsyncSocketPollParams *pollParams, int *error); AsyncSocket *AsyncSocket_AttachToSSLSock(struct SSLSockStruct *sslSock, AsyncSocketPollParams *pollParams, int *error); int AsyncSocket_UseNodelay(AsyncSocket *asyncSocket, Bool nodelay); int AsyncSocket_SetTCPTimeouts(AsyncSocket *asyncSocket, int keepIdleSec, int keepIntvlSec, int keepCnt); Bool AsyncSocket_EstablishMinBufferSizes(AsyncSocket *asyncSocket, int sendSz, int recvSz); int AsyncSocket_SetSendLowLatencyMode(AsyncSocket *asyncSocket, Bool enable); int AsyncSocket_SetOption(AsyncSocket *asyncSocket, AsyncSocketOpts_Layer layer, AsyncSocketOpts_ID optID, const void *valuePtr, socklen_t inBufLen); int AsyncSocket_GetOption(AsyncSocket *asyncSocket, AsyncSocketOpts_Layer layer, AsyncSocketOpts_ID optID, void *valuePtr, socklen_t *outBufLen); /* * Waits until at least one packet is received or times out. */ int AsyncSocket_DoOneMsg(AsyncSocket *s, Bool read, int timeoutMS); /* * Waits until at least one connect() is accept()ed or times out. */ int AsyncSocket_WaitForConnection(AsyncSocket *s, int timeoutMS); /* * Waits until a socket is ready with readable data or times out. */ int AsyncSocket_WaitForReadMultiple(AsyncSocket **asock, int numSock, int timeoutMS, int *outIdx); /* * Send all pending packets onto the wire or give up after timeoutMS msecs. */ int AsyncSocket_Flush(AsyncSocket *asock, int timeoutMS); /* * Drain recv for a remotely disconnected TCP socket. */ int AsyncSocket_TCPDrainRecv(AsyncSocket *base, int timeoutMS); /* * Specify the exact amount of data to receive and the receive function to call. */ int AsyncSocket_Recv(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); /* * Specify the maximum amount of data to receive and the receive function to call. */ int AsyncSocket_RecvPartial(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); int AsyncSocket_Peek(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); int AsyncSocket_PeekPartial(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); /* * Specify the amount of data to receive and the receive function to call. */ int AsyncSocket_RecvPassedFd(AsyncSocket *asock, void *buf, int len, void *cb, void *cbData); /* * Retrieve socket received via RecvPassedFd. */ int AsyncSocket_GetReceivedFd(AsyncSocket *asock); /* * Specify the amount of data to send/receive and how long to wait before giving * up. */ int AsyncSocket_RecvBlocking(AsyncSocket *asock, void *buf, int len, int *received, int timeoutMS); int AsyncSocket_RecvPartialBlocking(AsyncSocket *asock, void *buf, int len, int *received, int timeoutMS); int AsyncSocket_SendBlocking(AsyncSocket *asock, void *buf, int len, int *sent, int timeoutMS); /* * Specify the amount of data to send and the send function to call */ int AsyncSocket_Send(AsyncSocket *asock, void *buf, int len, AsyncSocketSendFn sendFn, void *clientData); int AsyncSocket_SendWithFd(AsyncSocket *asock, void *buf, int len, int passFd, AsyncSocketSendFn sendFn, void *clientData); int AsyncSocket_IsSendBufferFull(AsyncSocket *asock); int AsyncSocket_GetNetworkStats(AsyncSocket *asock, AsyncSocketNetworkStats *stats); int AsyncSocket_GetSNIHostname(AsyncSocket *asock, const char **sniHostname); int AsyncSocket_CancelRecv(AsyncSocket *asock, int *partialRecvd, void **recvBuf, void **recvFn); int AsyncSocket_CancelRecvEx(AsyncSocket *asock, int *partialRecvd, void **recvBuf, void **recvFn, Bool cancelOnSend); /* * Unregister asynchronous send and recv from poll */ int AsyncSocket_CancelCbForClose(AsyncSocket *asock); /* * Set the error handler to invoke on I/O errors (default is to close the * socket). This should be done immediately after an asyncsocket is created. * If this is done on a thread that is not the poll thread, the asyncsocket * lock (passed via pollParams) should be held throughout. */ int AsyncSocket_SetErrorFn(AsyncSocket *asock, AsyncSocketErrorFn errorFn, void *clientData); /* * Set optional AsyncSocket_Close() behaviors. */ int AsyncSocket_SetCloseOptions(AsyncSocket *asock, int flushEnabledMaxWaitMsec, AsyncSocketCloseFn closeCb); /* * Close the write side of the connection. */ int AsyncSocket_CloseWrite(AsyncSocket *asock); /* * Close the connection and destroy the asock. */ int AsyncSocket_Close(AsyncSocket *asock); /* * Retrieve the URI Supplied for a websocket connection */ char *AsyncSocket_GetWebSocketURI(AsyncSocket *asock); /* * Retrieve the Cookie Supplied for a websocket connection */ char *AsyncSocket_GetWebSocketCookie(AsyncSocket *asock); /* * Set the Cookie for a websocket connection */ int AsyncSocket_SetWebSocketCookie(AsyncSocket *asock, void *clientData, const char *path, const char *sessionId); /* * Retrieve the close status, if received, for a websocket connection */ uint16 AsyncSocket_GetWebSocketCloseStatus(AsyncSocket *asock); /* * Get negotiated websocket protocol */ const char *AsyncSocket_GetWebSocketProtocol(AsyncSocket *asock); /* * Set the flag for whether or not to delay websocket upgrade response */ int AsyncSocket_SetDelayWebSocketUpgradeResponse(AsyncSocket *asock, Bool delayWebSocketUpgradeResponse); /* * Send the websocket upgrade response */ void AsyncSocket_WebSocketServerSendUpgradeResponse(AsyncSocket *base, char *httpResponseTemp); /* * Get error code for websocket failure */ int AsyncSocket_GetWebSocketError(AsyncSocket *asock); const char * stristr(const char *s, const char *find); /* * Helper function to parse websocket URL */ Bool AsyncSocket_WebSocketParseURL(const char *url, char **hostname, unsigned int *port, Bool *useSSL, char **relativeURL, char **uriHostname); /* * Find and return the value for the given header key in the supplied buffer */ char *AsyncSocket_WebSocketGetHttpHeader(const char *request, const char *webKey); unsigned AsyncSocket_WebSocketGetNumAccepted(AsyncSocket *asock); Bool AsyncSocket_SetKeepAlive(AsyncSocket *asock, int keepIdle); /* * Send an HTTP error code, only valid on AsyncWebSockets */ void AsyncSocket_WebSocketServerSendError(AsyncSocket *asock, const char *text); /* * Some logging macros for convenience */ #define ASOCKPREFIX "SOCKET " /* Both gcc and msvc support ##__VA_ARGS__ to handle zero-length variadic arguments */ #define ASOCKWARN(_asock, fmt, ...) \ Warning(ASOCKPREFIX "%d (%d) " fmt, AsyncSocket_GetID(_asock), \ AsyncSocket_GetFd(_asock), ##__VA_ARGS__) #define ASOCKLG0(_asock, fmt, ...) \ Log(ASOCKPREFIX "%d (%d) " fmt, AsyncSocket_GetID(_asock), \ AsyncSocket_GetFd(_asock), ##__VA_ARGS__) #define ASOCKLOG(_level, _asock, fmt, ...) \ do { \ if (((_level) == 0) || DOLOG_BYNAME(asyncsocket, (_level))) { \ Log(ASOCKPREFIX "%d (%d) " fmt, AsyncSocket_GetID(_asock), \ AsyncSocket_GetFd(_asock), ##__VA_ARGS__); \ } \ } while (0) #if defined(__cplusplus) } // extern "C" #endif #endif // __ASYNC_SOCKET_H__ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/auth.h000066400000000000000000000047651470176644300236400ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _AUTH_H_ #define _AUTH_H_ /* * auth.h -- * * Defines for the authorization library. */ #include "vm_basic_types.h" #include "unicodeTypes.h" #if _WIN32 # include /* * This is quite possibly wrong, but fixes compile errors * for now. Come back to this when authentication is * properly implemented. */ typedef HANDLE AuthToken; #else # include //for getpwent, etc. # include //for initgroups typedef const struct passwd * AuthToken; #endif #if defined(__cplusplus) extern "C" { #endif #if _WIN32 BOOL Auth_StoreAccountInformation(const char *username, const char *password); BOOL Auth_DeleteAccountInformation(); BOOL Auth_RetrieveAccountInformation(char **username, char **password); #define AUTH_ATTRIBUTE_RUNAS_LOCAL_SYSTEM 0x1 #define AUTH_LOCAL_SYSTEM_USER "SYSTEM" BOOL Auth_StoreAccountInformationForVM(const char *filename, uint32 attributes, const char *username, const char *password); BOOL Auth_DeleteAccountInformationForVM(const char *filename); BOOL Auth_AccountInformationIsStoredForVMs(); BOOL Auth_DeleteAccountInformationStoredForVMs(); uint32 Auth_RetrieveAccountInformationForVM(const char *filename, uint32 *attributes, char **username, char **password); #else AuthToken Auth_GetPwnam(const char *user); AuthToken Auth_AuthenticateSelf(void); AuthToken Auth_AuthenticateUserPAM(const char *user, const char *pass, const char *service); #endif AuthToken Auth_AuthenticateUser(const char *user, const char *pass); void Auth_CloseToken(AuthToken token); #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/backdoor.h000066400000000000000000000042071470176644300244520ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1999-2017, 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * backdoor.h -- * * First layer of the internal communication channel between guest * applications and vmware */ #ifndef _BACKDOOR_H_ #define _BACKDOOR_H_ #include "vm_basic_types.h" #include "vm_assert.h" #include "backdoor_types.h" #if defined(__cplusplus) extern "C" { #endif void Backdoor(Backdoor_proto *bp); // IN/OUT void Backdoor_ForceLegacy(Bool force); // IN void Backdoor_InOut(Backdoor_proto *bp); // IN/OUT void Backdoor_Vmcall(Backdoor_proto *bp); // IN/OUT void Backdoor_Vmmcall(Backdoor_proto *bp); // IN/OUT void Backdoor_HbOut(Backdoor_proto_hb *bp); // IN/OUT void Backdoor_HbIn(Backdoor_proto_hb *bp); // IN/OUT #if defined(__cplusplus) } // extern "C" #endif #endif /* _BACKDOOR_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/backdoor_def.h000066400000000000000000000461011470176644300252670ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * backdoor_def.h -- * * This contains backdoor defines that can be included from * an assembly language file. */ #ifndef _BACKDOOR_DEF_H_ #define _BACKDOOR_DEF_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #if defined __cplusplus extern "C" { #endif /* * If you want to add a new low-level backdoor call for a guest userland * application, please consider using the GuestRpc mechanism instead. */ #define BDOOR_MAGIC 0x564D5868 /* Low-bandwidth backdoor port number for the IN/OUT interface. */ #define BDOOR_PORT 0x5658 /* Flags used by the hypercall interface. */ #define BDOOR_FLAGS_LB 0 #define BDOOR_FLAGS_READ 0 #define BDOOR_FLAGS_HB (1<<0) #define BDOOR_FLAGS_WRITE (1<<1) #define BDOOR_IS_LB(_flags) (((_flags) & BDOOR_FLAGS_HB) == 0) #define BDOOR_IS_HB(_flags) !BDOOR_IS_LB(_flags) #define BDOOR_IS_READ(_flags) (((_flags) & BDOOR_FLAGS_WRITE) == 0) #define BDOOR_IS_WRITE(_flags) !BDOOR_IS_READ(_flags) /* * Max number of BPNs that can be passed in a single call from monitor->VMX with * a HB backdoor request. This should be kept in parity with * IOSPACE_MAX_REP_BPNS to keep performance between the two HB backdoor * interfaces comparable. */ #define BDOOR_HB_MAX_BPNS 513 #define BDOOR_CMD_GETMHZ 1 /* * BDOOR_CMD_APMFUNCTION is used by: * * o The FrobOS code, which instead should either program the virtual chipset * (like the new BIOS code does, Matthias Hausner offered to implement that), * or not use any VM-specific code (which requires that we correctly * implement "power off on CLI HLT" for SMP VMs, Boris Weissman offered to * implement that) * * o The old BIOS code, which will soon be jettisoned */ #define BDOOR_CMD_APMFUNCTION 2 /* CPL0 only. */ #define BDOOR_CMD_GETDISKGEO 3 #define BDOOR_CMD_GETPTRLOCATION 4 #define BDOOR_CMD_SETPTRLOCATION 5 #define BDOOR_CMD_GETSELLENGTH 6 #define BDOOR_CMD_GETNEXTPIECE 7 #define BDOOR_CMD_SETSELLENGTH 8 #define BDOOR_CMD_SETNEXTPIECE 9 #define BDOOR_CMD_GETVERSION 10 #define BDOOR_CMD_GETDEVICELISTELEMENT 11 #define BDOOR_CMD_TOGGLEDEVICE 12 #define BDOOR_CMD_GETGUIOPTIONS 13 #define BDOOR_CMD_SETGUIOPTIONS 14 #define BDOOR_CMD_GETSCREENSIZE 15 #define BDOOR_CMD_MONITOR_CONTROL 16 /* Disabled by default. */ #define BDOOR_CMD_GETHWVERSION 17 #define BDOOR_CMD_OSNOTFOUND 18 /* CPL0 only. */ #define BDOOR_CMD_GETUUID 19 #define BDOOR_CMD_GETMEMSIZE 20 //#define BDOOR_CMD_HOSTCOPY 21 /* Not in use. Was devel only. */ //#define BDOOR_CMD_SERVICE_VM 22 /* Not in use. Never shipped. */ #define BDOOR_CMD_GETTIME 23 /* Deprecated -> GETTIMEFULL. */ #define BDOOR_CMD_STOPCATCHUP 24 #define BDOOR_CMD_PUTCHR 25 /* Disabled by default. */ //#define BDOOR_CMD_ENABLE_MSG 26 /* Not in use. Was devel only.*/ //#define BDOOR_CMD_GOTO_TCL 27 /* Not in use. Was devel only */ #define BDOOR_CMD_INITPCIOPROM 28 /* CPL 0 only. */ //#define BDOOR_CMD_INT13 29 /* Not in use. */ #define BDOOR_CMD_MESSAGE 30 #define BDOOR_CMD_SIDT 31 #define BDOOR_CMD_SGDT 32 #define BDOOR_CMD_SLDT_STR 33 #define BDOOR_CMD_ISACPIDISABLED 34 //#define BDOOR_CMD_TOE 35 /* Not in use. */ #define BDOOR_CMD_ISMOUSEABSOLUTE 36 #define BDOOR_CMD_PATCH_SMBIOS_STRUCTS 37 /* CPL 0 only. */ #define BDOOR_CMD_MAPMEM 38 /* Devel only */ #define BDOOR_CMD_ABSPOINTER_DATA 39 #define BDOOR_CMD_ABSPOINTER_STATUS 40 #define BDOOR_CMD_ABSPOINTER_COMMAND 41 //#define BDOOR_CMD_TIMER_SPONGE 42 /* Not in use. */ //#define BDOOR_CMD_PATCH_ACPI_TABLES 43 /* Not in use. */ //#define BDOOR_CMD_DEVEL_FAKEHARDWARE 44 /* Not in use. */ #define BDOOR_CMD_GETHZ 45 #define BDOOR_CMD_GETTIMEFULL 46 //#define BDOOR_CMD_STATELOGGER 47 /* Not in use. */ #define BDOOR_CMD_CHECKFORCEBIOSSETUP 48 /* CPL 0 only. */ #define BDOOR_CMD_LAZYTIMEREMULATION 49 /* CPL 0 only. */ #define BDOOR_CMD_BIOSBBS 50 /* CPL 0 only. */ //#define BDOOR_CMD_VASSERT 51 /* Not in use. */ #define BDOOR_CMD_ISGOSDARWIN 52 #define BDOOR_CMD_DEBUGEVENT 53 #define BDOOR_CMD_OSNOTMACOSXSERVER 54 /* CPL 0 only. */ #define BDOOR_CMD_GETTIMEFULL_WITH_LAG 55 #define BDOOR_CMD_ACPI_HOTPLUG_DEVICE 56 /* Devel only. */ #define BDOOR_CMD_ACPI_HOTPLUG_MEMORY 57 /* Devel only. */ #define BDOOR_CMD_ACPI_HOTPLUG_CBRET 58 /* Devel only. */ //#define BDOOR_CMD_GET_HOST_VIDEO_MODES 59 /* Not in use. */ #define BDOOR_CMD_ACPI_HOTPLUG_CPU 60 /* Devel only. */ //#define BDOOR_CMD_USB_HOTPLUG_MOUSE 61 /* Not in use. Never shipped. */ #define BDOOR_CMD_XPMODE 62 /* CPL 0 only. */ #define BDOOR_CMD_NESTING_CONTROL 63 #define BDOOR_CMD_FIRMWARE_INIT 64 /* CPL 0 only. */ #define BDOOR_CMD_FIRMWARE_ACPI_SERVICES 65 /* CPL 0 only. */ # define BDOOR_CMD_FAS_GET_TABLE_SIZE 0 # define BDOOR_CMD_FAS_GET_TABLE_DATA 1 # define BDOOR_CMD_FAS_GET_PLATFORM_NAME 2 # define BDOOR_CMD_FAS_GET_PCIE_OSC_MASK 3 # define BDOOR_CMD_FAS_GET_APIC_ROUTING 4 # define BDOOR_CMD_FAS_GET_TABLE_SKIP 5 # define BDOOR_CMD_FAS_GET_SLEEP_ENABLES 6 # define BDOOR_CMD_FAS_GET_HARD_RESET_ENABLE 7 # define BDOOR_CMD_FAS_GET_MOUSE_HID 8 # define BDOOR_CMD_FAS_GET_SMBIOS_VERSION 9 # define BDOOR_CMD_FAS_GET_64BIT_PCI_HOLE_SIZE 10 //#define BDOOR_CMD_FAS_GET_NVDIMM_FMT_CODE 11 /* Not in use. Never shipped. */ # define BDOOR_CMD_FAS_SRP_ENABLED 12 # define BDOOR_CMD_FAS_EXIT_BOOT_SERVICES 13 # define BDOOR_CMD_FAS_GET_API_ENABLES 14 # define BDOOR_CMD_FAS_UNACCEPTED_MEM_ENABLED 15 #define BDOOR_CMD_SENDPSHAREHINTS 66 /* Not in use. Deprecated. */ #define BDOOR_CMD_ENABLE_USB_MOUSE 67 #define BDOOR_CMD_GET_VCPU_INFO 68 //#define BDOOR_CMD_VCPU_SLC64 0 /* BT-is-dead. Deprecated. */ # define BDOOR_CMD_VCPU_SYNC_VTSCS 1 //#define BDOOR_CMD_VCPU_HV_REPLAY_OK 2 /* Replay-is-dead. Deprecated.*/ # define BDOOR_CMD_VCPU_LEGACY_X2APIC_OK 3 # define BDOOR_CMD_VCPU_MMIO_HONORS_PAT 4 # define BDOOR_CMD_VCPU_RESERVED 31 #define BDOOR_CMD_EFI_SERIALCON_CONFIG 69 /* CPL 0 only. */ //#define BDOOR_CMD_BUG328986 70 /* CPL 0 only. Deprecated. */ #define BDOOR_CMD_FIRMWARE_ERROR 71 /* CPL 0 only. */ # define BDOOR_CMD_FE_INSUFFICIENT_MEM 0 # define BDOOR_CMD_FE_EXCEPTION 1 # define BDOOR_CMD_FE_SGX 2 # define BDOOR_CMD_FE_PCI_MMIO 3 //#define BDOOR_CMD_FE_GMM 4 /* GMM is deprecated. */ #define BDOOR_CMD_VMK_INFO 72 #define BDOOR_CMD_EFI_BOOT_CONFIG 73 /* CPL 0 only. */ # define BDOOR_CMD_EBC_LEGACYBOOT_ENABLED 0 # define BDOOR_CMD_EBC_GET_ORDER 1 # define BDOOR_CMD_EBC_SHELL_ACTIVE 2 # define BDOOR_CMD_EBC_GET_NETWORK_BOOT_PROTOCOL 3 # define BDOOR_CMD_EBC_QUICKBOOT_ENABLED 4 # define BDOOR_CMD_EBC_GET_PXE_ARCH 5 # define BDOOR_CMD_EBC_SKIP_DELAYS 6 # define BDOOR_CMD_EBC_GET_NETWORK_BOOT_URI 7 #define BDOOR_CMD_GET_HW_MODEL 74 /* CPL 0 only. */ #define BDOOR_CMD_GET_SVGA_CAPABILITIES 75 /* CPL 0 only. */ #define BDOOR_CMD_GET_FORCE_X2APIC 76 /* CPL 0 only */ #define BDOOR_CMD_SET_PCI_HOLE 77 /* CPL 0 only */ #define BDOOR_CMD_GET_PCI_HOLE 78 /* CPL 0 only */ #define BDOOR_CMD_GET_PCI_BAR 79 /* CPL 0 only */ #define BDOOR_CMD_SHOULD_GENERATE_SYSTEMID 80 /* CPL 0 only */ #define BDOOR_CMD_READ_DEBUG_FILE 81 /* Devel only. */ #define BDOOR_CMD_SCREENSHOT 82 /* Devel only. */ #define BDOOR_CMD_INJECT_KEY 83 /* Devel only. */ #define BDOOR_CMD_INJECT_MOUSE 84 /* Devel only. */ #define BDOOR_CMD_MKS_GUEST_STATS 85 /* CPL 0 only. */ # define BDOOR_CMD_MKSGS_RESET 0 # define BDOOR_CMD_MKSGS_ADD_PPN 1 # define BDOOR_CMD_MKSGS_REMOVE_PPN 2 #define BDOOR_CMD_ABSPOINTER_RESTRICT 86 //#define BDOOR_CMD_GUEST_INTEGRITY 87 /* GI is deprecated. */ #define BDOOR_CMD_MKSTEST 88 /* Devel only. */ # define BDOOR_CMD_MKSTEST_STATS_START 0 # define BDOOR_CMD_MKSTEST_STATS_STOP 1 # define BDOOR_CMD_MKSTEST_CASE_START 2 # define BDOOR_CMD_MKSTEST_CASE_STOP 3 #define BDOOR_CMD_SECUREBOOT 89 #define BDOOR_CMD_COPY_PHYSMEM 90 /* Devel only. */ #define BDOOR_CMD_STEALCLOCK 91 /* CPL 0 only. */ # define BDOOR_STEALCLOCK_STATUS_DISABLED 0 # define BDOOR_STEALCLOCK_STATUS_ENABLED 1 #define BDOOR_CMD_GUEST_PAGE_HINTS 92 /* CPL 0 only */ #define BDOOR_CMD_FIRMWARE_UPDATE 93 /* CPL 0 only. */ # define BDOOR_CMD_FU_GET_HOST_VERSION 0 # define BDOOR_CMD_FU_UPDATE_FROM_HOST 1 # define BDOOR_CMD_FU_LOCK 2 #define BDOOR_CMD_FUZZER_HELPER 94 /* Devel only. */ # define BDOOR_CMD_FUZZER_INIT 0 # define BDOOR_CMD_FUZZER_NEXT 1 #define BDOOR_CMD_PUTCHR12 95 //#define BDOOR_CMD_GMM 96 /* GMM is deprecated. */ #define BDOOR_CMD_PRECISIONCLOCK 97 # define BDOOR_CMD_PRECISIONCLOCK_GETTIME 0 # define BDOOR_CMD_PRECISIONCLOCK_SETTIME 1 # define BDOOR_CMD_PRECISIONCLOCK_ADJTIME 2 # define BDOOR_CMD_PRECISIONCLOCK_ADJFREQ 3 # define BDOOR_CMD_PRECISIONCLOCK_NUMCMDS 4 //#define BDOOR_CMD_COREDUMP_UNSYNC 98 /* Not in use. PR 3328536. */ #define BDOOR_CMD_APPLE_GPU_RES_SET 99 #define BDOOR_CMD_GETBUILDNUM 100 #define BDOOR_CMD_GETENTROPY 101 /* Configurable, off by default. */ #define BDOOR_CMD_REPORTGUESTCRASH 102 #define BDOOR_CMD_MAX 103 /* * IMPORTANT NOTE: When modifying the behavior of an existing backdoor command, * you must adhere to the semantics expected by the oldest Tools who use that * command. Specifically, do not alter the way in which the command modifies * the registers. Otherwise backwards compatibility will be impacted. */ /* Nesting control operations */ #define NESTING_CONTROL_RESTRICT_BACKDOOR 0 #define NESTING_CONTROL_OPEN_BACKDOOR 1 #define NESTING_CONTROL_QUERY 2 #define NESTING_CONTROL_MAX 2 /* EFI Boot Order options, nibble-sized. */ #define EFI_BOOT_ORDER_TYPE_EFI 0x0 #define EFI_BOOT_ORDER_TYPE_LEGACY 0x1 #define EFI_BOOT_ORDER_TYPE_NONE 0xf #define BDOOR_NETWORK_BOOT_PROTOCOL_NONE 0x0 #define BDOOR_NETWORK_BOOT_PROTOCOL_IPV4 0x1 #define BDOOR_NETWORK_BOOT_PROTOCOL_IPV6 0x2 #define BDOOR_NETWORK_BOOT_PROTOCOL_HTTPV4 0x3 #define BDOOR_NETWORK_BOOT_PROTOCOL_HTTPV6 0x4 #define BDOOR_SECUREBOOT_STATUS_DISABLED 0xFFFFFFFFUL #define BDOOR_SECUREBOOT_STATUS_APPROVED 1 #define BDOOR_SECUREBOOT_STATUS_DENIED 2 #define BDOOR_FAS_API_ENABLE_FDT 0x00000001UL /* High-bandwidth backdoor port. */ #define BDOORHB_PORT 0x5659 #define BDOORHB_CMD_MESSAGE 0 #define BDOORHB_CMD_VASSERT 1 #define BDOORHB_CMD_MAX 2 /* * There is another backdoor which allows access to certain TSC-related * values using otherwise illegal PMC indices when the pseudo_perfctr * control flag is set. */ #define BDOOR_PMC_HW_TSC 0x10000 #define BDOOR_PMC_REAL_NS 0x10001 #define BDOOR_PMC_APPARENT_NS 0x10002 #define BDOOR_PMC_PSEUDO_TSC 0x10003 #define IS_BDOOR_PMC(index) (((index) | 3) == 0x10003) #define BDOOR_CMD(ecx) ((ecx) & 0xffff) /* Sub commands for BDOOR_CMD_VMK_INFO */ #define BDOOR_CMD_VMK_INFO_ENTRY 1 /* * Current format for the guest page hints is: * * Arg0: BDOOR_MAGIC, Arg3: BDOOR_PORT * * Arg1: (rbx on x86) * * 0 64 * | PPN | * * Arg2: (rcx on x86) * * 0 16 32 64 * | Command | Type | Reserved | * * Arg4: (rsi on x86) * * 0 16 64 * | numPages | Reserved | * */ #define BDOOR_GUEST_PAGE_HINTS_NOT_SUPPORTED ((unsigned)-1) #define BDOOR_GUEST_PAGE_HINTS_MAX_PAGES (0xffff) #define BDOOR_GUEST_PAGE_HINTS_TYPE_PSHARE (0) #define BDOOR_GUEST_PAGE_HINTS_TYPE(reg) (((reg) >> 16) & 0xffff) #ifdef VM_ARM_64 /* * VMware x86 I/O space virtualization on arm. * * Implementation goal * --- * The goal of this implementation is to precisely mimic the semantics of the * "VMware x86 I/O space virtualization on x86", in particular: * * o A vCPU can perform an N-byte access to an I/O port address that is not * N-byte aligned. * * o A vCPU can perform an N-byte access to I/O port address A without * impacting I/O port addresses [ A + 1; A + N ). * * o A vCPU can access the I/O space when running 32-bit or 64-bit code. * * o A vCPU running in unprivileged mode can use the backdoor. * * As a result, VMware virtual device drivers that were initially developed for * x86 can trivially be ported to arm. * * Mechanism * --- * In this section, we call W the 32-bit register which aliases the low 32 * bits of the 64-bit register X. * * A vCPU which wishes to use the "VMware x86 I/O space virtualization on arm" * must follow these 4 steps: * * 1) Write to general-purpose registers specific to the x86 I/O space * instruction. * * The vCPU writes to the arm equivalent of general-purpose x86 registers (see * the BDOOR_ARG* mapping below) that are used by the x86 I/O space instruction * it is about to perform. * * Examples: * o For an IN instruction without DX register, there is nothing to do. * o For an OUT instruction with DX register, the vCPU places the I/O port * address in bits W3<15:0> and the value to write in W0<7:0> (1 byte access) * or W0<15:0> (2 bytes access) or W0 (4 bytes access). * o For an REP OUTS instruction, the vCPU places the I/O port address in bits * W3<15:0>, the source virtual address in W4 (32-bit code) or X4 (64-bit * code) and the number of repetitions in W2 (32-bit code) or X2 (64-bit * code). * * 2) Write the x86 I/O space instruction to perform. * * The vCPU sets a value in W7, as described below: * * Transfer size, bits [1:0] * 00: 1 byte * 01: 2 bytes * 10: 4 bytes * 11: Invalid value * * Transfer direction, bit [2] * 0: Write (OUT/OUTS/REP OUTS instructions) * 1: Read (IN/INS/REP INS instructions) * * Instruction type, bits [4:3] * 00: Non-string instruction (IN/OUT) without DX register * The port address (8-bit immediate) is set in W7<12:5>. * * 01: Non-string instruction (IN/OUT) with DX register * * 10: String instruction without REP prefix (INS/OUTS) * The direction flag (EFLAGS.DF) is set in W7<5>. * * 11: String instruction with REP prefix (REP INS/REP OUTS) * The direction flag (EFLAGS.DF) is set in W7<5>. * * All other bits not described above are reserved for future use and must be * set to 0. * * 3) Perform the x86 I/O space instruction. * * Several mechanisms are available: * * o From EL1 * The vCPU executes the HVC instruction with the immediate X86_IO_MAGIC. * * This is the mechanism to favor from EL1 because it is architectural. * * o From EL1 and EL0 * The vCPU sets X7<63:32> to X86_IO_MAGIC and executes the * MRS XZR, MDCCSR_EL0 instruction. * * This is the mechanism to favor from EL0 because it has a negligible impact * on vCPU performance. * * o From EL1 and EL0, only when monitor_control.hv_hypercall = "TRUE" * The vCPU executes the BRK instruction with the immediate X86_IO_MAGIC. * * Pro: This mechanism cannot be intercepted by EL3 code. * Con: This mechanism has a significant impact on vCPU performance when * running a debugger in the guest. * * 4) Read from general-purpose registers specific to the x86 I/O space * instruction. * * The vCPU reads from the arm equivalent of general-purpose x86 registers (see * the BDOOR_ARG* mapping below) that are used by the x86 I/O space instruction * it has just performed. * * Examples: * o For an OUT instruction, there is nothing to do. * o For an IN instruction, retrieve the value that was read from W0<7:0> (1 * byte access) or W0<15:0> (2 bytes access) or W0 (4 bytes access). */ #define X86_IO_MAGIC 0x86 #define X86_IO_W7_SIZE_SHIFT 0 #define X86_IO_W7_SIZE_MASK (0x3 << X86_IO_W7_SIZE_SHIFT) #define X86_IO_W7_DIR (1 << 2) #define X86_IO_W7_WITH (1 << 3) #define X86_IO_W7_STR (1 << 4) #define X86_IO_W7_DF (1 << 5) #define X86_IO_W7_IMM_SHIFT 5 #define X86_IO_W7_IMM_MASK (0xff << X86_IO_W7_IMM_SHIFT) #define BDOOR_ARG0 REG_X0 #define BDOOR_ARG1 REG_X1 #define BDOOR_ARG2 REG_X2 #define BDOOR_ARG3 REG_X3 #define BDOOR_ARG4 REG_X4 #define BDOOR_ARG5 REG_X5 #define BDOOR_ARG6 REG_X6 #else #define BDOOR_ARG0 REG_RAX #define BDOOR_ARG1 REG_RBX #define BDOOR_ARG2 REG_RCX #define BDOOR_ARG3 REG_RDX #define BDOOR_ARG4 REG_RSI #define BDOOR_ARG5 REG_RDI #define BDOOR_ARG6 REG_RBP #endif #if defined __cplusplus } #endif #endif // _BACKDOOR_DEF_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/backdoor_types.h000066400000000000000000000107161470176644300257000ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1999-2016,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * backdoor_types.h -- * * Type definitions for backdoor interaction code. */ #ifndef _BACKDOOR_TYPES_H_ #define _BACKDOOR_TYPES_H_ #if !(defined __i386__ || defined __x86_64__ || defined __aarch64__ || defined _M_IX86 || defined _M_X64) #error The backdoor protocol is only supported on x86 and aarch64 architectures. #endif /* * The three different backdoor interfaces: the legacy IN/OUT interface, and the * hypercall interfaces for AMD and Intel. */ typedef enum { BACKDOOR_INTERFACE_NONE, BACKDOOR_INTERFACE_IO, BACKDOOR_INTERFACE_VMMCALL, BACKDOOR_INTERFACE_VMCALL } BackdoorInterface; /* * These #defines are intended for defining register structs as part of * existing named unions. If the union should encapsulate the register * (and nothing else), use DECLARE_REG_NAMED_STRUCT defined below. */ #define DECLARE_REG32_STRUCT \ struct { \ uint16 low; \ uint16 high; \ } halfs; \ uint32 word #define DECLARE_REG64_STRUCT \ DECLARE_REG32_STRUCT; \ struct { \ uint32 low; \ uint32 high; \ } words; \ uint64 quad #if defined (VM_X86_64) || defined (VM_ARM_64) #define DECLARE_REG_STRUCT DECLARE_REG64_STRUCT #else #define DECLARE_REG_STRUCT DECLARE_REG32_STRUCT #endif #define DECLARE_REG_NAMED_STRUCT(_r) \ union { DECLARE_REG_STRUCT; } _r /* * Some of the registers are expressed by semantic name, because if they were * expressed as register structs declared above, we could only address them * by fixed size (half-word, word, quad, etc.) instead of by varying size * (size_t, uintptr_t). * * To be cleaner, these registers are expressed ONLY by semantic name, * rather than by a union of the semantic name and a register struct. */ typedef union { struct { DECLARE_REG_NAMED_STRUCT(ax); size_t size; /* Register bx. */ DECLARE_REG_NAMED_STRUCT(cx); DECLARE_REG_NAMED_STRUCT(dx); DECLARE_REG_NAMED_STRUCT(si); DECLARE_REG_NAMED_STRUCT(di); } in; struct { DECLARE_REG_NAMED_STRUCT(ax); DECLARE_REG_NAMED_STRUCT(bx); DECLARE_REG_NAMED_STRUCT(cx); DECLARE_REG_NAMED_STRUCT(dx); DECLARE_REG_NAMED_STRUCT(si); DECLARE_REG_NAMED_STRUCT(di); } out; } Backdoor_proto; typedef union { struct { DECLARE_REG_NAMED_STRUCT(ax); DECLARE_REG_NAMED_STRUCT(bx); size_t size; /* Register cx. */ DECLARE_REG_NAMED_STRUCT(dx); uintptr_t srcAddr; /* Register si. */ uintptr_t dstAddr; /* Register di. */ DECLARE_REG_NAMED_STRUCT(bp); } in; struct { DECLARE_REG_NAMED_STRUCT(ax); DECLARE_REG_NAMED_STRUCT(bx); DECLARE_REG_NAMED_STRUCT(cx); DECLARE_REG_NAMED_STRUCT(dx); DECLARE_REG_NAMED_STRUCT(si); DECLARE_REG_NAMED_STRUCT(di); DECLARE_REG_NAMED_STRUCT(bp); } out; } Backdoor_proto_hb; MY_ASSERTS(BACKDOOR_STRUCT_SIZES, ASSERT_ON_COMPILE(sizeof(Backdoor_proto) == 6 * sizeof(uintptr_t)); ASSERT_ON_COMPILE(sizeof(Backdoor_proto_hb) == 7 * sizeof(uintptr_t)); ) #undef DECLARE_REG_STRUCT #endif /* _BACKDOOR_TYPES_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/base64.h000066400000000000000000000037361470176644300237600ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * base64.h -- * * Functions to base64 encode/decode buffers. Implemented in * lib/misc/base64.c. */ #ifndef _BASE64_H #define _BASE64_H #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif Bool Base64_Encode(uint8 const *src, size_t srcLength, char *target, size_t targSize, size_t *dataLength); Bool Base64_Decode(char const *src, uint8 *target, size_t targSize, size_t *dataLength); Bool Base64_ChunkDecode(char const *src, size_t inSize, uint8 *target, size_t targSize, size_t *dataLength); Bool Base64_ValidEncoding(char const *src, size_t srcLength); size_t Base64_EncodedLength(uint8 const *src, size_t srcLength); size_t Base64_DecodedLength(char const *src, size_t srcLength); Bool Base64_EasyEncode(const uint8 *src, size_t srcLength, char **target); Bool Base64_EasyDecode(const char *src, uint8 **target, size_t *targSize); Bool Base64_DecodeFixed(const char *src, char *outBuf, size_t outBufSize); #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/buildNumber.h000066400000000000000000000004371470176644300251370ustar00rootroot00000000000000#define BUILD_NUMBER \ "build-24276846" #define BUILD_NUMBER_NUMERIC \ 24276846 #define BUILD_NUMBER_NUMERIC_STRING \ "24276846" #define PRODUCT_BUILD_NUMBER \ "product-build-51152" #define PRODUCT_BUILD_NUMBER_NUMERIC \ 51152 #define PRODUCT_BUILD_NUMBER_NUMERIC_STRING \ "51152" open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/capsProvider.h000066400000000000000000000027661470176644300253370ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * capsProvider.h -- * * Interface implemented by dnd manager objects to obtain their * capabilities. Mainly needed by Windows host and guest code. */ #ifndef __CAPS_PROVIDER_H__ #define __CAPS_PROVIDER_H__ #if defined VMX86_TOOLS || COMPILE_WITHOUT_CUI # ifdef LIB_EXPORT # undef LIB_EXPORT # endif #define LIB_EXPORT #else #include "libExport.hh" #endif #if defined(SWIG) class CapsProvider #else class LIB_EXPORT CapsProvider #endif { public: virtual ~CapsProvider() {}; virtual Bool CheckCapability(uint32 caps) = 0; virtual uint64 GetDnDSizeThreshold() { return 0; } // 0 means no size control }; #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/circList.h000066400000000000000000000264151470176644300244470ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * circList.h -- * * macros, prototypes and struct definitions for double-linked * circular lists. */ #ifndef _CIRCLIST_H_ #define _CIRCLIST_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "vmware.h" #if defined(__cplusplus) extern "C" { #endif typedef struct ListItem { struct ListItem *prev; struct ListItem *next; } ListItem; /* *---------------------------------------------------------------------- * * CircList_IsEmpty -- * * A NULL list is an empty list. * * Result: * TRUE if list is empty, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE Bool CircList_IsEmpty(const ListItem *item) // IN { return item == NULL; } /* *---------------------------------------------------------------------- * * CircList_InitItem -- * * Initialize item as a single-element circular list. * * Result: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE void CircList_InitItem(ListItem *item) // OUT { item->prev = item->next = item; } /* *---------------------------------------------------------------------- * * CircList_First -- * * Return first item in the list. * * Result: * First item. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE ListItem * CircList_First(ListItem *item) // IN { return item; } /* *---------------------------------------------------------------------- * * CircList_Last -- * * Return last item in the list. * * Result: * Last item. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE ListItem * CircList_Last(ListItem *item) { return item->prev; } /* * CIRC_LIST_CONTAINER - get the struct for this entry (like list_entry) * @ptr: the &struct ListItem pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list struct within the struct. */ #define CIRC_LIST_CONTAINER(ptr, type, member) \ VMW_CONTAINER_OF(ptr, type, member) /* * Historical name, left here to reduce churn. * TODO: remove, all LIST_CONTAINER uses should be * VMW_CONTAINER_OF and stop depending on circList.h * to provide the definition. */ #define LIST_CONTAINER(ptr, type, member) VMW_CONTAINER_OF(ptr, type, member) /* * LIST_SCAN_FROM scans the list from "from" up until "until". * The loop variable p should not be destroyed in the process. * "from" is an element in the list where to start scanning. * "until" is the element where search should stop. * member is the field to use for the search - either "next" or "prev". */ #define CIRC_LIST_SCAN_FROM(p, from, until, member) \ for (p = (from); (p) != NULL; \ (p) = (((p)->member == (until)) ? NULL : (p)->member)) /* scan the entire list (non-destructively) */ #define CIRC_LIST_SCAN(p, l) \ CIRC_LIST_SCAN_FROM(p, CircList_First(l), CircList_First(l), next) /* scan the entire list where loop element may be destroyed */ #define CIRC_LIST_SCAN_SAFE(p, pn, l) \ if (!CircList_IsEmpty(l)) \ for (p = (l), (pn) = CircList_Next(p, l); (p) != NULL; \ (p) = (pn), (pn) = CircList_Next(p, l)) /* scan the entire list backwards where loop element may be destroyed */ #define CIRC_LIST_SCAN_BACK_SAFE(p, pn, l) \ if (!CircList_IsEmpty(l)) \ for (p = CircList_Last(l), (pn) = CircList_Prev(p, l); (p) != NULL; \ (p) = (pn), (pn) = CircList_Prev(p, l)) /* *---------------------------------------------------------------------- * * CircList_Next -- * * Returns the next member of a doubly linked list, or NULL if last. * Assumes: p is member of the list headed by head. * * Result: * If head or p is NULL, return NULL. Otherwise, * next list member (or null if last). * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE ListItem * CircList_Next(ListItem *p, // IN ListItem *head) // IN { if (head == NULL || p == NULL) { return NULL; } /* both p and head are non-null */ p = p->next; return p == head ? NULL : p; } /* *---------------------------------------------------------------------- * * CircList_Prev -- * * Returns the prev member of a doubly linked list, or NULL if first. * Assumes: p is member of the list headed by head. * * Result: * If head or prev is NULL, return NULL. Otherwise, * prev list member (or null if first). * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE ListItem * CircList_Prev(ListItem *p, // IN ListItem *head) // IN { if (head == NULL || p == NULL) { return NULL; } /* both p and head are non-null */ return p == head ? NULL : p->prev; } /* *---------------------------------------------------------------------- * * CircList_DeleteItem -- * * Deletes a member of a doubly linked list, possibly modifies the * list header itself. * Assumes neither p nor headp is null and p is a member of *headp. * * Result: * None * * Side effects: * Modifies *headp. * *---------------------------------------------------------------------- */ static INLINE void CircList_DeleteItem(ListItem *p, // IN ListItem **headp) // IN/OUT { ListItem *next; ASSERT(p != NULL); ASSERT(headp != NULL); next = p->next; if (p == next) { *headp = NULL; } else { next->prev = p->prev; p->prev->next = next; if (*headp == p) { *headp = next; } } } /* *---------------------------------------------------------------------- * * CircList_Queue -- * * Adds a new member to the back of a doubly linked list (queue) * Assumes neither p nor headp is null and p is not a member of *headp. * * Result: * None * * Side effects: * Modifies *headp. * *---------------------------------------------------------------------- */ static INLINE void CircList_Queue(ListItem *p, // IN ListItem **headp) // IN/OUT { ListItem *head; head = *headp; if (CircList_IsEmpty(head)) { CircList_InitItem(p); *headp = p; } else { p->prev = head->prev; p->next = head; p->prev->next = p; head->prev = p; } } /* *---------------------------------------------------------------------- * * CircList_Push -- * * Adds a new member to the front of a doubly linked list (stack) * Assumes neither p nor headp is null and p is not a member of *headp. * * Result: * None * * Side effects: * Modifies *headp. * *---------------------------------------------------------------------- */ static INLINE void CircList_Push(ListItem *p, // IN ListItem **headp) // IN/OUT { CircList_Queue(p, headp); *headp = p; } /* *---------------------------------------------------------------------- * * CircList_InsertAfter -- * * Adds a new member to the list after the provided item. Assumes p * is not a member of a list already. * * Result: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE void CircList_InsertAfter(ListItem *p, // IN: ListItem *after) // IN: { p->prev = after; p->next = after->next; p->next->prev = p; after->next = p; } /* *---------------------------------------------------------------------- * * CircList_Splice -- * * Make a single list {l1 l2} from {l1} and {l2} and return it. * It is okay for one or both lists to be NULL. * No checking is done. It is assumed that l1 and l2 are two * distinct lists. * * Result: * A list { l1 l2 }. * * Side effects: * Modifies l1 and l2 list pointers. * *---------------------------------------------------------------------- */ static INLINE ListItem * CircList_Splice(ListItem *l1, // IN ListItem *l2) // IN { ListItem *l1Last, *l2Last; if (CircList_IsEmpty(l1)) { return l2; } if (CircList_IsEmpty(l2)) { return l1; } l1Last = l1->prev; /* last elem of l1 */ l2Last = l2->prev; /* last elem of l2 */ /* * l1 -> ... -> l1Last l2 -> ... l2Last */ l1Last->next = l2; l2->prev = l1Last; l1->prev = l2Last; l2Last->next = l1; return l1; } #if 0 /* Presently unused, enable if a use is found */ /* *---------------------------------------------------------------------- * * CircList_Split -- * * Make a list l = {l1 l2} into two separate lists {l1} and {l2}, where: * l = { ... x -> p -> ... } split into: * l1 = { ... -> x } * l2 = { p -> ... } * Assumes neither p nor l is null and p is a member of l. * If p is the first element of l, then l1 will be NULL. * * Result: * None. * * Side effects: * Sets *l1p and *l2p to the resulting two lists. * Modifies l's pointers. * *---------------------------------------------------------------------- */ static INLINE void CircList_Split(ListItem *p, // IN ListItem *l, // IN ListItem **l1p, // OUT ListItem **l2p) // OUT { ListItem *last; if (p == CircList_First(l)) { /* first element */ *l1p = NULL; *l2p = l; return; } last = l->prev; *l1p = l; p->prev->next = l; l->prev = p->prev; *l2p = p; p->prev = last; last->next = p; } #endif /* *---------------------------------------------------------------------- * * CircList_Size -- * * Return the number of items in the list. * * Result: * The number of items in the list. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE int CircList_Size(ListItem *head) // IN { ListItem *li; int ret = 0; CIRC_LIST_SCAN(li, head) { ret++; } return ret; } #if defined(__cplusplus) } // extern "C" #endif #endif /* _CIRCLIST_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/clamped.h000066400000000000000000000244101470176644300242710ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * clamped.h -- * * Clamped arithmetic. This header file provides inline * arithmetic operations that don't overflow. Instead, they * saturate at the data type's max or min value. */ #ifndef _CLAMPED_H_ #define _CLAMPED_H_ #include "vm_basic_types.h" #include "vm_assert.h" #include "vm_basic_defs.h" #if defined __cplusplus extern "C" { #endif /* *----------------------------------------------------------------------------- * * Clamped_U64To32 -- * * Convert unsigned 64-bit to 32-bit, clamping instead of truncating. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_UINT32, returns FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_U64To32(uint32 *out, // OUT uint64 a) // IN { uint32 clamped = (uint32)a; if (UNLIKELY(a != clamped)) { *out = MAX_UINT32; return FALSE; } *out = clamped; return TRUE; } /* *----------------------------------------------------------------------------- * * Clamped_S64To32 -- * * Convert signed 64-bit to 32-bit, clamping instead of truncating. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_INT32 or MIN_INT32, returns FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_S64To32(int32 *out, // OUT int64 a) // IN { int32 clamped = (int32)a; if (UNLIKELY(a != clamped)) { *out = a < 0 ? MIN_INT32 : MAX_INT32; return FALSE; } *out = clamped; return TRUE; } /* *----------------------------------------------------------------------------- * * Clamped_S32To16 -- * * Convert signed 32-bit to 16-bit, clamping instead of truncating. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_INT16 or MIN_INT16, returns FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_S32To16(int16 *out, // OUT int32 a) // IN { int16 clamped = (int16)a; if (UNLIKELY(a != clamped)) { *out = a < 0 ? MIN_INT16 : MAX_INT16; return FALSE; } *out = clamped; return TRUE; } /* *---------------------------------------------------------------------- * * Clamped_SAdd32 -- * * Signed 32-bit addition. * * Add two integers, clamping the result to MAX_INT32 or * MIN_INT32 if it would have overflowed. * * Results: * On success, returns TRUE. * If the result would have overflowed and we clamped it, returns FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE Bool Clamped_SAdd32(int32 *out, // OUT int32 a, // IN int32 b) // IN { return Clamped_S64To32(out, (int64)a + b); } /* *----------------------------------------------------------------------------- * * Clamped_UMul32 -- * * Unsigned 32-bit multiplication. * * We're abusing the fact that 32x32-bit multiplication always * returns a 64-bit result on x86 anyway, and that the compiler * should be smart enough to optimize the code here into a * 32x32-bit multiply. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_UINT32, returns FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_UMul32(uint32 *out, // OUT uint32 a, // IN uint32 b) // IN { return Clamped_U64To32(out, (uint64)a * b); } /* *----------------------------------------------------------------------------- * * Clamped_SMul32 -- * * Signed 32-bit multiplication. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_INT32 or MIN_INT32, returns FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_SMul32(int32 *out, // OUT int32 a, // IN int32 b) // IN { return Clamped_S64To32(out, (int64)a * b); } /* *----------------------------------------------------------------------------- * * Clamped_UAdd32 -- * * Unsigned 32-bit addition. * * This is a utility function for 32-bit unsigned addition, * in which the result is clamped to MAX_UINT32 on overflow. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_UINT32, returns FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_UAdd32(uint32 *out, // OUT uint32 a, // IN uint32 b) // IN { uint32 c = a + b; /* * Checking against one src operand is sufficient. */ if (UNLIKELY(c < a)) { *out = MAX_UINT32; return FALSE; } *out = c; return TRUE; } /* *----------------------------------------------------------------------------- * * Clamped_UAdd64 -- * * Unsigned 64-bit addition. * * This is a utility function for 64-bit unsigned addition, * in which the result is clamped to MAX_UINT64 on overflow. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_UINT64, returns FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_UAdd64(uint64 *out, // OUT uint64 a, // IN uint64 b) // IN { uint64 c = a + b; /* * Checking against one src operand is sufficient. */ if (UNLIKELY(c < a)) { *out = MAX_UINT64; return FALSE; } *out = c; return TRUE; } /* *----------------------------------------------------------------------------- * * Clamped_URoundUpBits32 -- * * Round up an unsigned 32-bit number by the specified number * of bits. Clamp to MAX_UINT32 on overflow. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_UINT32, returns FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_URoundUpBits32(uint32 *out, // OUT uint32 x, // IN uint32 bits) // IN { uint32 mask = (1 << bits) - 1; uint32 c = (x + mask) & ~mask; ASSERT(bits < sizeof(uint32) * 8); if (UNLIKELY(x + mask < x)) { *out = MAX_UINT32; return FALSE; } *out = c; return TRUE; } /* *----------------------------------------------------------------------------- * * Clamped_UMul64 -- * * Unsigned 64-bit multiplication. * * Results: * On success, returns TRUE. If the result would have overflowed * and we clamped it to MAX_UINT64, returns FALSE. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_UMul64(uint64 *out, // OUT uint64 a, // IN uint64 b) // IN { uint32 aL = a & MASK64(32); uint32 aH = a >> 32; uint32 bL = b & MASK64(32); uint32 bH = b >> 32; ASSERT(out != NULL); if (UNLIKELY(aH > 0 && bH > 0)) { *out = MAX_UINT64; return FALSE; } else { uint64 s1 = (aH * (uint64)bL) << 32; uint64 s2 = (aL * (uint64)bH) << 32; uint64 s3 = (aL * (uint64)bL); uint64 sum; Bool clamped; ASSERT(s1 == 0 || s2 == 0); sum = s1 + s2; clamped = !Clamped_UAdd64(&sum, sum, s3); *out = sum; return !clamped; } } /* *----------------------------------------------------------------------------- * * Clamped_USub64 -- * * Unsigned 64-bit subtraction. * Compute (a - b), and clamp to 0 if the result would have underflowed. * * Results: * On success, returns TRUE. If the result would have underflowed * and we clamped it to 0, returns FALSE. * *----------------------------------------------------------------------------- */ static INLINE Bool Clamped_USub64(uint64 *out, // OUT uint64 a, // IN uint64 b) // IN { ASSERT(out != NULL); if (UNLIKELY(b > a)) { *out = 0; return FALSE; } else { *out = a - b; return TRUE; } } #if defined __cplusplus } // extern "C" #endif #endif // ifndef _CLAMPED_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/codeset.h000066400000000000000000000430741470176644300243210ustar00rootroot00000000000000/* ********************************************************** * Copyright (c) 2007-2022 VMware, Inc. All rights reserved. * **********************************************************/ /* * codeset.h -- * * UTF-16 handling macros. Based on utf16.h from ICU 1.8.1. * * ICU 1.8.1 license follows: * * ICU License - ICU 1.8.1 and later * * COPYRIGHT AND PERMISSION NOTICE * * Copyright (c) 1995-2006 International Business Machines Corporation * and others * * All rights reserved. * * Permission is hereby granted, free of charge, to any * person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all * copies of the Software and that both the above copyright * notice(s) and this permission notice appear in supporting * documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT * SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE * BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Except as contained in this notice, the name of a * copyright holder shall not be used in advertising or otherwise * to promote the sale, use or other dealings in this Software * without prior written authorization of the copyright holder. */ #ifndef __CODESET_H__ # define __CODESET_H__ #include "vm_basic_types.h" #include "vm_assert.h" #include "dynbuf.h" #if defined(__cplusplus) extern "C" { #endif /* * These platforms use UTF-8 (or pretend to): * FreeBSD: really UTF-8 * ESX: UTF-8 by policy decree * Mac: really UTF-8 */ #if defined(__FreeBSD__) || \ defined(VMX86_SERVER) || \ defined(__APPLE__) || \ defined __ANDROID__ #define CURRENT_IS_UTF8 #endif /* * Guard these defines, borrowed from ICU's utf16.h, so that source files * can include both. */ #ifndef __UTF16_H__ /** * Is this code point a surrogate (U+d800..U+dfff)? * @param c 32-bit code point * @return TRUE or FALSE * @stable ICU 2.4 */ #define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800) /** * Does this code unit alone encode a code point (BMP, not a surrogate)? * @param c 16-bit code unit * @return TRUE or FALSE * @stable ICU 2.4 */ #define U16_IS_SINGLE(c) (!U_IS_SURROGATE(c)) /** * Is this code unit a lead surrogate (U+d800..U+dbff)? * @param c 16-bit code unit * @return TRUE or FALSE * @stable ICU 2.4 */ #define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800) /** * Is this code unit a trail surrogate (U+dc00..U+dfff)? * @param c 16-bit code unit * @return TRUE or FALSE * @stable ICU 2.4 */ #define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00) /** * Is this code unit a surrogate (U+d800..U+dfff)? * @param c 16-bit code unit * @return TRUE or FALSE * @stable ICU 2.4 */ #define U16_IS_SURROGATE(c) U_IS_SURROGATE(c) /** * Assuming c is a surrogate code point (U16_IS_SURROGATE(c)), * is it a lead surrogate? * @param c 16-bit code unit * @return TRUE or FALSE * @stable ICU 2.4 */ #define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0) /** * Helper constant for U16_GET_SUPPLEMENTARY. * @internal */ #define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) /** * Get a supplementary code point value (U+10000..U+10ffff) * from its lead and trail surrogates. * The result is undefined if the input values are not * lead and trail surrogates. * * @param lead lead surrogate (U+d800..U+dbff) * @param trail trail surrogate (U+dc00..U+dfff) * @return supplementary code point (U+10000..U+10ffff) * @stable ICU 2.4 */ #define U16_GET_SUPPLEMENTARY(lead, trail) \ (((uint32)(lead)<<10UL)+(uint32)(trail)-U16_SURROGATE_OFFSET) /** * Get the lead surrogate (0xd800..0xdbff) for a * supplementary code point (0x10000..0x10ffff). * @param supplementary 32-bit code point (U+10000..U+10ffff) * @return lead surrogate (U+d800..U+dbff) for supplementary * @stable ICU 2.4 */ #define U16_LEAD(supplementary) ((utf16_t)(((supplementary)>>10)+0xd7c0)) /** * Get the trail surrogate (0xdc00..0xdfff) for a * supplementary code point (0x10000..0x10ffff). * @param supplementary 32-bit code point (U+10000..U+10ffff) * @return trail surrogate (U+dc00..U+dfff) for supplementary * @stable ICU 2.4 */ #define U16_TRAIL(supplementary) ((utf16_t)(((supplementary)&0x3ff)|0xdc00)) /** * How many 16-bit code units are used to encode this Unicode code point? (1 or 2) * The result is not defined if c is not a Unicode code point (U+0000..U+10ffff). * @param c 32-bit code point * @return 1 or 2 * @stable ICU 2.4 */ #define U16_LENGTH(c) ((uint32)(c)<=0xffff ? 1 : 2) /** * The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff). * @return 2 * @stable ICU 2.4 */ #define U16_MAX_LENGTH 2 /** * Get a code point from a string at a code point boundary offset, * and advance the offset to the next code point boundary. * (Post-incrementing forward iteration.) * "Safe" macro, handles unpaired surrogates and checks for string boundaries. * * The offset may point to the lead surrogate unit * for a supplementary code point, in which case the macro will read * the following trail surrogate as well. * If the offset points to a trail surrogate or * to a single, unpaired lead surrogate, then that itself * will be returned as the code point. * * @param s const utf16_t * string * @param i string offset, must be i(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \ --(i); \ (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \ } \ } \ } #endif // __UTF16_H__ /* * Use this instead of "UTF-16" to specify UTF-16 in native byte order. */ #define CODESET_NATIVE_UTF16 "UTF-16LE" /* * Flags for conversion functions */ #define CSGTG_NORMAL 0x0000 /* Without any information loss. */ #define CSGTG_TRANSLIT 0x0001 /* Transliterate unknown characters. */ #define CSGTG_IGNORE 0x0002 /* Skip over untranslatable characters. */ /* * XXX -- this function is a temporary fix. It should be removed once we fix * the 3rd party library pathname issue. */ char * CodeSet_GetAltPathName(const utf16_t *pathW); // IN Bool CodeSet_Init(const char *icuDataDir); // IN: ICU datafile directory in current page, // can be NULL. void CodeSet_DontUseIcu(void); Bool CodeSet_GenericToGenericDb(const char *codeIn, // IN const char *bufIn, // IN size_t sizeIn, // IN const char *codeOut, // IN unsigned int flags, // IN DynBuf *db); // IN/OUT Bool CodeSet_GenericToGeneric(const char *codeIn, // IN const char *bufIn, // IN size_t sizeIn, // IN const char *codeOut, // IN unsigned int flags, // IN char **bufOut, // IN/OUT size_t *sizeOut); // IN/OUT Bool CodeSet_Utf8ToCurrent(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT Bool CodeSet_CurrentToUtf8(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT Bool CodeSet_Utf16leToUtf8Db(const char *bufIn, // IN size_t sizeIn, // IN DynBuf *db); // IN Bool CodeSet_Utf16leToUtf8(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT/OPT Bool CodeSet_Utf8ToUtf16le(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT/OPT Bool CodeSet_CurrentToUtf16le(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT/OPT Bool CodeSet_Utf16leToCurrent(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT/OPT Bool CodeSet_Utf16beToCurrent(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT/OPT Bool CodeSetOld_Utf8Normalize(const char *bufIn, // IN size_t sizeIn, // IN Bool precomposed, // IN DynBuf *db); // OUT Bool CodeSet_Utf8FormDToUtf8FormC(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT/OPT Bool CodeSet_Utf8FormCToUtf8FormD(const char *bufIn, // IN size_t sizeIn, // IN char **bufOut, // OUT size_t *sizeOut); // OUT/OPT const char * CodeSet_GetCurrentCodeSet(void); Bool CodeSet_IsEncodingSupported(const char *name); // IN: Bool CodeSet_Validate(const char *buf, // IN: the string size_t size, // IN: length of string const char *code); // IN: encoding Bool CodeSet_UTF8ToUTF32(const char *utf8, // IN: char **utf32); // OUT: Bool CodeSet_UTF32ToUTF8(const char *utf32, // IN: char **utf8); // OUT: int CodeSet_LengthInCodePoints(const char *utf8); // IN: int CodeSet_CodePointOffsetToByteOffset(const char *utf8, // IN: int codePointOffset); // IN: int CodeSet_GetUtf8(const char *string, // IN: const char *end, // IN: uint32 *uchar); // OUT/OPT: Bool CodeSet_IsValidUTF8(const char *bufIn, // IN: size_t sizeIn); // IN: Bool CodeSet_IsStringValidUTF8(const char *string); // IN: Bool CodeSet_IsValidUTF8String(const char *bufIn, // IN: size_t sizeIn); // IN: char *CodeSet_JsonEscape(const char *utf8); // IN: char *CodeSet_JsonUnescape(const char *utf8); // IN: /* *----------------------------------------------------------------------------- * * CodeSet_Utf8ToUtf16 -- * * A convenience wrapper that accepts a NUL-terminated UTF-8 string * and returns an allocated UTF-16 (LE) string. ASSERTs on failure. * * Results: * The allocted UTF-16 (LE) string, free with free(). * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE utf16_t * CodeSet_Utf8ToUtf16(const char *str) // IN: { utf16_t *strW; if (!CodeSet_Utf8ToUtf16le(str, strlen(str), (char **) &strW, NULL)) { NOT_IMPLEMENTED(); } return strW; } /* *----------------------------------------------------------------------------- * * CodeSet_Utf16ToUtf8 -- * * A convenience wrapper that accepts a NUL-terminated UTF-16 (LE) * string and returns an allocated UTF-8 string. ASSERTs on failure. * * Results: * The allocted UTF-8 string, free with free(). * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * CodeSet_Utf16ToUtf8(const utf16_t *strW) // IN: { char *str; size_t len; for (len = 0; strW[len]; len++) ; if (!CodeSet_Utf16leToUtf8((const char *) strW, len * sizeof strW[0], (char **) &str, NULL)) { NOT_IMPLEMENTED(); } return str; } /* *----------------------------------------------------------------------------- * * CodeSet_Utf8FindCodePointBoundary * * Determine if buf[offset] is a valid UTF-8 code point boundary * and find the previous boundary if it is not. The contents of * buf[offset] need not be defined, only data prior to this * location is examined. Useful for finding a suitable place to * put a NUL terminator. * * Results: * * Returns the offset of the byte immediately following the last * complete UTF-8 code point in buf that is entirely within the * range [0, offset-1]. Note that if the final UTF-8 code point * is complete, the input offset will be returned unchanged. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE size_t CodeSet_Utf8FindCodePointBoundary(const char *buf, // IN size_t offset) // IN { size_t origOffset = offset; if (offset > 0) { signed char c; /* * Back up 1 byte and then find the start of the UTF-8 code * point occupying that location. */ offset--; while (offset > 0 && (buf[offset] & 0xc0) == 0x80) { offset--; } /* * Maximum UTF-8 code point length is 4 */ ASSERT(origOffset - offset <= 4); c = buf[offset]; /* * The first byte of a UTF-8 code point needs to be one of * 0b0XXXXXXX, 0b110XXXXX, 0b1110XXXX, 0b11110XXX */ ASSERT(c >= 0 || (c >> 5) == -2 || (c >> 4) == -2 || (c >> 3) == -2); /* * offset now points to the start of a UTF-8 code point. If it * is a single byte or if the length, as encoded in the first * byte, matches the number of bytes we have backed up, then the * entire code point is present, so the original offset is a * valid code point starting offset. * * Length is encoded as * 2 bytes: 0b110XXXXX * 3 bytes: 0b1110XXXX * 4 bytes: 0b11110XXX * Thus the first byte is -2 when shifted right (signed) by * (7 - length). */ if (c >= 0 || (c >> (7 - origOffset + offset)) == -2) { return origOffset; } /* * Else we truncated a code point. Return its starting point. */ } return offset; } /* *----------------------------------------------------------------------------- * * CodeSet_Utf16FindCodePointBoundary * * Determine if buf[offset] is a valid UTF-16 code point boundary * and find the previous boundary if it is not. The contents of * buf[offset] need not be defined, only data prior to this * location is examined. Useful for finding a suitable place to * put a NUL terminator. * * Results: * * Returns the offset of the byte immediately following the last * complete UTF-16 code point in buf that is entirely within the * range [0, offset-1]. Note that if the final UTF-16 code point * is complete, the input offset will be returned unchanged. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE size_t CodeSet_Utf16FindCodePointBoundary(const char *buf, // IN size_t offset) // IN { size_t origOffset; const utf16_t *utf16Buf = (const utf16_t *)buf; origOffset = offset / 2; offset = origOffset - 1; if (origOffset > 0 && U16_IS_LEAD(utf16Buf[offset])) { return offset * 2; } return origOffset * 2; } #if defined(__cplusplus) } // extern "C" #endif #endif /* __CODESET_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/community_source.h000066400000000000000000000050251470176644300262710ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * community_source.h -- * * Macros for excluding source code from community. */ #ifndef _COMMUNITY_SOURCE_H_ #define _COMMUNITY_SOURCE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" /* * Convenience macro for COMMUNITY_SOURCE */ #undef EXCLUDE_COMMUNITY_SOURCE #ifdef COMMUNITY_SOURCE #define EXCLUDE_COMMUNITY_SOURCE(x) #else #define EXCLUDE_COMMUNITY_SOURCE(x) x #endif #undef COMMUNITY_SOURCE_AMD_SECRET #if !defined(COMMUNITY_SOURCE) || defined(AMD_SOURCE) /* * It's ok to include AMD_SECRET source code for non-Community Source, * or for drops directed at AMD. */ #define COMMUNITY_SOURCE_AMD_SECRET #endif #undef COMMUNITY_SOURCE_INTEL_SECRET #if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE) /* * It's ok to include INTEL_SECRET source code for non-Community Source, * or for drops directed at Intel. */ #define COMMUNITY_SOURCE_INTEL_SECRET #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/compat/000077500000000000000000000000001470176644300237755ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/compat/compat_stdarg.h000066400000000000000000000050161470176644300267770ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2016,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * compat_stdarg.h -- * * Compatibility defines for systems that need the stdarg features. If your program * needs va_init, va_copy, va_end, etc. then include this file instead of including * stdarg.h directly. * * Note that the header guard for this file does not follow typical naming * convention as _COMPAT_STDARG_H conflicts with emscripten's compat/stdarg.h */ #ifndef _VMWARE_COMPAT_STDARG_H #define _VMWARE_COMPAT_STDARG_H 1 #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include #if !defined(va_copy) # if defined(__va_copy) # define va_copy __va_copy # elif defined(_WIN32) # define va_copy(ap1, ap2) (*(ap1) = *(ap2)) # elif defined(VA_LIST_IS_ARRAY) # define va_copy(ap1, ap2) memcpy(ap1, ap2, sizeof(va_list)) # else # define va_copy(ap1, ap2) ((ap1) = (ap2)) # endif #endif #endif /* _VMWARE_COMPAT_STDARG_H */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/conf.h000066400000000000000000000565641470176644300236300ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2002-2024 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * conf.h -- * * Manage the tools configuration file. * */ #ifndef __CONF_H__ #define __CONF_H__ #define CONF_FILE "tools.conf" #if ! defined(_WIN32) # define CONFVAL_POWERONSCRIPT_DEFAULT "poweron-vm-default" # define CONFVAL_POWEROFFSCRIPT_DEFAULT "poweroff-vm-default" # define CONFVAL_RESUMESCRIPT_DEFAULT "resume-vm-default" # define CONFVAL_SUSPENDSCRIPT_DEFAULT "suspend-vm-default" #else # define CONFVAL_POWERONSCRIPT_DEFAULT "poweron-vm-default.bat" # define CONFVAL_POWEROFFSCRIPT_DEFAULT "poweroff-vm-default.bat" # define CONFVAL_RESUMESCRIPT_DEFAULT "resume-vm-default.bat" # define CONFVAL_SUSPENDSCRIPT_DEFAULT "suspend-vm-default.bat" #endif #define CONFNAME_POWERONSCRIPT "poweron-script" #define CONFNAME_POWEROFFSCRIPT "poweroff-script" #define CONFNAME_RESUMESCRIPT "resume-script" #define CONFNAME_SUSPENDSCRIPT "suspend-script" #define CONFNAME_LOG "log" #define CONFNAME_LOGFILE "log.file" #define CONFNAME_LOGLEVEL "log.level" #define CONFNAME_DISABLETOOLSVERSION "disable-tools-version" #define CONFNAME_HIDETOOLSVERSION "hide-tools-version" #define CONFNAME_DISABLEPMTIMERWARNING "disable-pmtimerwarning" #define CONFGROUPNAME_VMTOOLS "vmtools" /* ****************************************************************************** * BEGIN AppInfo goodies. */ /** * Defines the string used for the AppInfo config file group. */ #define CONFGROUPNAME_APPINFO "appinfo" /** * Define a custom AppInfo poll interval (in seconds). * * @note Illegal values result in a @c g_warning and fallback to the default * poll interval. * * @param int User-defined poll interval. Set to 0 to disable polling. */ #define CONFNAME_APPINFO_POLLINTERVAL "poll-interval" /** * Defines the configuration to publish the application information or not. * * @note Illegal values result in a @c g_warning and fallback to the default * value. * * @param boolean Set to TRUE to disable publishing. * Set to FALSE to enable publishing. */ #define CONFNAME_APPINFO_DISABLED "disabled" /** * Defines the configuration to remove duplicate applications. * * @param boolean Set to TRUE to remove duplicate apps. * Set to FALSE to keep duplicate apps. */ #define CONFNAME_APPINFO_REMOVE_DUPLICATES "remove-duplicates" /** * Defines the configuration to use the WMI for getting the application * version information. * * @note Illegal values result in a @c g_warning and fallback to the default * value. * * @param boolean Set to TRUE to use WMI. * Set to FALSE to use native Win32 APIs. */ #define CONFNAME_APPINFO_USE_WMI "useWMI" /* * END AppInfo goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN containerInfo goodies. */ /** * Defines the string used for the ContainerInfo config file group. */ #define CONFGROUPNAME_CONTAINERINFO "containerinfo" /** * Define a custom ContainerInfo poll interval (in seconds). * * @note Illegal values result in a @c g_warning and fallback to the default * poll interval. * * @param int User-defined poll interval. Set to 0 to disable polling. */ #define CONFNAME_CONTAINERINFO_POLLINTERVAL "poll-interval" /** * Define the limit on the maximum number of containers to collect info from. * If the number of running containers exceeds the limit, only the most recently * created containers will be published. * * @note Illegal values result in a @c g_warning and fallback to the default * max container limit. * * @param int User-defined max limit for # of containers queried. */ #define CONFNAME_CONTAINERINFO_LIMIT "max-containers" /** * Defines the configuration to remove duplicate containers. * * @param boolean Set to TRUE to remove duplicate containers. * Set to FALSE to keep duplicate containers. */ #define CONFNAME_CONTAINERINFO_REMOVE_DUPLICATES "remove-duplicates" /** * Define the docker unix socket to use to communicate with the docker daemon. * * @note Illegal values result in a @c g_warning and fallback to docker's * default unix socket. * * @param string absolute file path of the docker unix socket in use. */ #define CONFNAME_CONTAINERINFO_DOCKERSOCKET "docker-unix-socket" /** * Define the containerd unix socket to connect with containerd gRPC server. * This should be used to get containers. * * @note Illegal values result in a @c g_warning and fallback to the containerd * default unix socket. * * @param string absolute file path of the containerd unix socket in use. */ #define CONFNAME_CONTAINERINFO_CONTAINERDSOCKET "containerd-unix-socket" /** * Define the list of namespaces to be queried for the running containers. * * @note Illegal values result in a @c g_warning and fallback to the default * list of namespaces. * * @param string Comma separated list of namespaces to be queried. */ #define CONFNAME_CONTAINERINFO_ALLOWED_NAMESPACES "allowed-namespaces" /* * END containerInfo goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN ServiceDiscovery goodies. */ /** * Defines the string used for the ServiceDiscovery config file group. */ #define CONFGROUPNAME_SERVICEDISCOVERY "servicediscovery" /** * Defines the configuration to perform service discovery or not. * * @note Illegal values result in a @c g_warning and fallback to the default * value. * * @param boolean Set to TRUE to disable publishing. * Set to FALSE to enable publishing. */ #define CONFNAME_SERVICEDISCOVERY_DISABLED "disabled" /* * END ServiceDiscovery goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN ComponentMgr goodies. */ /** * Defines the current poll interval (in seconds). * This value is controlled by the componentMgr.poll-interval config file * option. */ #define COMPONENTMGR_CONF_POLLINTERVAL "poll-interval" /** * Name of section of configuration to be read from tools.conf. */ #define COMPONENTMGR_CONF_GROUPNAME "componentmgr" /** * Defines the components managed by the componentMgr plugin. * This value is controlled by the componentMgr.included config file option. */ #define COMPONENTMGR_CONF_INCLUDEDCOMPONENTS "included" /* * END ComponentMgr goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN GuestStore upgrader goodies. ****************************************************************************** */ /** * Defines the string used for the GuestStore upgrade config file group. */ #define CONFGROUPNAME_GSUPGRADE "gueststoreupgrade" /** * Defines the value for GuestStore upgrade feature to be enabled or not. * * @note Illegal values result in a @c g_warning and fallback to the default * value. * * @param string Set to "off" no tools upgrade from GuestStore. * Set to "manual" tools upgrade from GuestStore manual start. * Set to "immediate" tools upgrade from GuestStore start * autoCONFNAME_GSUPGRADE_RESOURCEmatically checking on the poll-interval frequency. * Set to "powercycle" tools upgrade from GuestStore on system * power on. */ #define CONFNAME_GSUPGRADE_POLICY "policy" /** * Define a custom GuestStore check poll interval (in seconds). * * @note Illegal values result in a @c g_warning and fallback to the default * poll interval. * * @param int User-defined poll interval. Set to 0 to disable polling. */ #define CONFNAME_GSUPGRADE_POLLINTERVAL "poll-interval" /** * Define a custom GuestStore content path prefix. * * @note Illegal values result in a @c g_warning and fallback to the default * resource path. * * @param string User-defined GuestStore resource path. */ #define CONFNAME_GSUPGRADE_RESOURCE "resource" /** * Define a custom GuestStore content vmtools key. * * @note Illegal values result in a @c g_warning and fallback to the default * vmtools key. * * @param string User-defined GuestStore vmtools key. * Set to "vmtools" for the latest version. * Suggested examples for earlier versions are: * Set to "vmtools-11.0.0" for "vmtools-11.0.0/" * Set to "vmtools-11.1.0" for "vmtools-11.1.0/" * Set to "vmtools-11.2.0" for "vmtools-11.2.0/" * Set to "vmtools-11.3.0" for "vmtools-11.3.0/" */ #define CONFNAME_GSUPGRADE_VMTOOLS_VERSION "vmtools-version-key" /* * END GuestStore upgrader goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN GlobalConf goodies. */ /** * Defines the string used for the GlobalConf config file group. */ #define CONFGROUPNAME_GLOBALCONF "globalconf" /** * Defines the configuration to enable/disable the GlobalConf module. * * @note Illegal values result in @c g_warning and fallback to the default * value. * * @param boolean Set to TRUE to enable the module. * Set to FALSE to disable the module. */ #define CONFNAME_GLOBALCONF_ENABLED "enabled" /** * Define a custom GlobalConf poll interval (in seconds). * * @note Illegal values result in @c g_warning and fallback to the default * value. * * @param int User-defined poll interval. */ #define CONFNAME_GLOBALCONF_POLL_INTERVAL "poll-interval" /** * Define the global configuration resource in GuestStore. * * @note Illegal values result in @c g_warning and fallback to the default * value. * * @param string Resource identifier in GuestStore. */ #define CONFNAME_GLOBALCONF_RESOURCE "resource" /* * END GlobalConf goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN GuestInfo goodies. */ /** * Defines the string used for the GuestInfo config file group. */ #define CONFGROUPNAME_GUESTINFO "guestinfo" /** * Lets user disable just the perf monitor. */ #define CONFNAME_GUESTINFO_DISABLEPERFMON "disable-perf-mon" /** * Lets user disable just DiskInfo. * * If thinking of deprecating this, please read bug 535343 first. */ #define CONFNAME_GUESTINFO_DISABLEQUERYDISKINFO "disable-query-diskinfo" /** * Define a custom GuestInfo poll interval (in seconds). * * @note Illegal values result in a @c g_warning and fallback to the default * poll interval. * * @param int User-defined poll interval. Set to 0 to disable polling. */ #define CONFNAME_GUESTINFO_POLLINTERVAL "poll-interval" /** * Define a custom GuestStats poll interval (in seconds). * * @note Illegal values result in a @c g_warning and fallback to the default * stats interval. * * @param int User-defined poll interval for stats. Set to 0 to disable polling. */ #define CONFNAME_GUESTINFO_STATSINTERVAL "stats-interval" /** * Indicates whether stat results should be written to the log. */ #define CONFNAME_GUESTINFO_ENABLESTATLOGGING "enable-stat-logging" /** * Set a comma separated list of network interface names that can be the * primary one * * @note interface names can use wildcards like '*' and '?' * * @param string comma separated list of interface name patterns. */ #define CONFNAME_GUESTINFO_PRIMARYNICS "primary-nics" /** * Set a comma separated list of network interface names that have * low priority (so they will be sorted to the end). * * @note interface names can use wildcards like '*' and '?' * * @param string comma separated list of interface name patterns. */ #define CONFNAME_GUESTINFO_LOWPRIORITYNICS "low-priority-nics" /** * Set a comma separated list of network interface names that shall be ignored. * * @note interface names can use wildcards like '*' and '?' * * @param string comma separated list of interface name patterns. */ #define CONFNAME_GUESTINFO_EXCLUDENICS "exclude-nics" /** * Define a custom max IPv4 routes to gather. * * @note Illegal values result in a @c g_warning and fallback to the default * NICINFO_MAX_ROUTES. * * @param int User-defined max routes with range [0, NICINFO_MAX_ROUTES]. * Set to 0 to disable gathering. */ #define CONFNAME_GUESTINFO_MAXIPV4ROUTES "max-ipv4-routes" /** * Define a custom max IPv6 routes to gather. * * @note Illegal values result in a @c g_warning and fallback to the default * NICINFO_MAX_ROUTES. * * @param int User-defined max routes with range [0, NICINFO_MAX_ROUTES]. * Set to 0 to disable gathering. */ #define CONFNAME_GUESTINFO_MAXIPV6ROUTES "max-ipv6-routes" /** * Lets user include reserved space in diskInfo space metrics on Linux. * * @param boolean Set to true to include reserved space. */ #define CONFNAME_DISKINFO_INCLUDERESERVED "diskinfo-include-reserved" /** * Report UUID of disks for vmdk mapping via vim. * * @param boolean Set to true to report UUID to VMX. */ #define CONFNAME_DISKINFO_REPORT_UUID "diskinfo-report-uuid" /** * Avoid buggy USB driver when querying disks for UUID. * Turning this on can result in a major delay if the vmdk is * being replicated. See PR 2575285, 26539. * * @param boolean Set to true to work around buggy 3rd party driver. */ #define CONFNAME_DISKINFO_DRIVER_WORKAROUND "diskinfo-usb-workaround" /** * Report Linux disk device for vmdk mapping via vim. * * @param boolean Set to true to report devices to VMX. */ #define CONFNAME_DISKINFO_REPORT_DEVICE "diskinfo-report-device" /* * END GuestInfo goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN GuestOSInfo goodies. */ /** * Defines the string used for the GuestOSInfo config file group. */ #define CONFGROUPNAME_GUESTOSINFO "guestosinfo" /** * Lets users override the short OS name sent by Tools. */ #define CONFNAME_GUESTOSINFO_SHORTNAME "short-name" /** * Lets users override the long OS name sent by Tools. */ #define CONFNAME_GUESTOSINFO_LONGNAME "long-name" /* * END GuestOSInfo goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN Unity goodies. */ /** * Defines the string used for the Unity config file group. */ #define CONFGROUPNAME_UNITY "unity" /** * Lets users override system decisions about whether unity should be available. */ #define CONFNAME_UNITY_FORCEENABLE "forceEnable" /** * Lets users override the desktop background color when in Unity mode. */ #define CONFNAME_UNITY_BACKGROUNDCOLOR "desktop.backgroundColor" /** * Lets users enable (or disable) the Protocol Buffer enabled service */ #define CONFNAME_UNITY_ENABLEPBRPC "pbrpc.enable" /** * Lets users configure the socket type for the PBRPC Services */ #define CONFNAME_UNITY_PBRPCSOCKETTYPE "pbrpc.socketType" #define CONFNAME_UNITY_PBRPCSOCKETTYPE_IPSOCKET "ipsocket" #define CONFNAME_UNITY_PBRPCSOCKETTYPE_VSOCKET "vsocket" /* * END Unity goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN deployPkg goodies. */ /** * Defines the string used for the deployPkg config file group. */ #define CONFGROUPNAME_DEPLOYPKG "deployPkg" /** * Lets users configure the process timeout value in deployPkg * Valid value range: 1 ~ 3600 */ #define CONFNAME_DEPLOYPKG_PROCESSTIMEOUT "process-timeout" /** * The guest customization is allowed or not * Valid value: true / false */ #define CONFNAME_DEPLOYPKG_ENABLE_CUST "enable-customization" /** * How long does guest customization wait until cloud-init execution done * Valid value range: 0 ~ 1800 */ #define CONFNAME_DEPLOYPKG_WAIT_CLOUDINIT_TIMEOUT "wait-cloudinit-timeout" /* * END deployPkg goodies. ****************************************************************************** */ /** Where to find Tools data in the Win32 registry. */ #if defined(_WIN32) # ifndef WSTR # define WSTR_(X) L##X # define WSTR(X) WSTR_(X) # endif # define CONF_VMWARE_TOOLS_REGKEY "Software\\VMware, Inc.\\VMware Tools" # define CONF_VMWARE_TOOLS_INSTPATH_KEY "InstallPath" # define CONF_VMWARE_TOOLS_REGKEY_W WSTR(CONF_VMWARE_TOOLS_REGKEY) # define CONF_VMWARE_TOOLS_INSTPATH_KEY_W WSTR(CONF_VMWARE_TOOLS_INSTPATH_KEY) # ifdef UNITY_FOR_VIEW # define CONF_VMWARE_RDE_REGKEY "SOFTWARE\\VMware, Inc.\\VMware VDM\\RemoteExperienceAgent" # define CONF_VMWARE_RDE_INSTPATH_KEY "InstallPath" # define CONF_VMWARE_RDE_REGKEY_W WSTR(CONF_VMWARE_RDE_REGKEY) # define CONF_VMWARE_RDE_INSTPATH_KEY_W WSTR(CONF_VMWARE_RDE_INSTPATH_KEY) # endif #endif /* Wait 5 seconds between polls to see if the conf file has changed */ #define CONF_POLL_TIME 5 /* ****************************************************************************** * BEGIN upgrader goodies. */ #define CONFGROUPNAME_AUTOUPGRADE "autoupgrade" #define CONFNAME_AUTOUPGRADE_ALLOW_UPGRADE "allow-upgrade" #define CONFNAME_AUTOUPGRADE_ALLOW_ADD_FEATURE "allow-add-feature" #define CONFNAME_AUTOUPGRADE_ALLOW_REMOVE_FEATURE "allow-remove-feature" #define CONFNAME_AUTOUPGRADE_ALLOW_MSI_TRANSFORMS "allow-msi-transforms" /* * END upgrader goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN logging goodies. */ /** * Defines the string used for the logging config file group. */ #define CONFGROUPNAME_LOGGING "logging" #define CONFNAME_LOGGING_INSTALL_VMXGUESTLOGDISABLED "install-vmxGuestLogDisabled" /* * END logging goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN environment goodies. */ /** * Defines the strings used for setenvironment and unsetenvironment * config groups. * * These config groups are used for setting and unsetting environment * variables for the service. The keys in this config group can be * specified in following 2 formats: * * 1. = * 2. . = * * Variables specified in format #1 are applied to all services reading * the config file whereas variables specified in format #2 are applied * only to the specified service. */ #define CONFGROUPNAME_SET_ENVIRONMENT "setenvironment" #define CONFGROUPNAME_UNSET_ENVIRONMENT "unsetenvironment" /* * END environment goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN gitray goodies. */ #define CONFGROUPNAME_GITRAY "gitray" /* * END gitray goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN AMSI Fileless goodies. */ /** * Defines the string used for vsep plugin AMSI Fileless config file group */ #define CONFGROUPNAME_AMSI "giamsi" /* Default state of AMSI config*/ #define VSEP_DEFAULT_AMSI_STATE TRUE /** * Defines user-defined maximum AMSI client connections. */ #define CONFNAME_AMSI_MAX_CLIENT_CONNECTIONS "amsi-max-client-connections" /** * Defines user-defined maximum script size supported in fileless. */ #define CONFNAME_AMSI_MAX_SCRIPT_SIZE_IN_BYTES "amsi-max-script-size-in-bytes" /* * END Fileless goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN CarbonBlack helper plugin goodies. */ /** * Define the string used for cbhelper config file group */ #define CONFGROUPNAME_CBHELPER "cbhelper" /** * Defines user-defined polling interval in seconds. */ #define CONFNAME_CBHELPER_POLLINTERVAL "poll-interval" /* ****************************************************************************** * END CarbonBlack helper plugin goodies. */ /* ****************************************************************************** * BEGIN deviceHelper plugin goodies. */ /** * Defines the string used for the device helper config file group. */ #define CONFGROUPNAME_DEVICEHELPER "devicehelper" /** * Defines the configuration to perform device helper or not. * * @note Illegal values result in a @c g_warning and fallback to the default * value. * * @param boolean Set to TRUE to disable device helper feature. * Set to FALSE to enable device helper feature. */ #define CONFNAME_DEVICEHELPER_DISABLED "disabled" /* * END deviceHelper goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN gdp plugin goodies. */ /** * Defines the string used for the gdp config file group. */ #define CONFGROUPNAME_GDP "gdp" /** * Defines a custom history cache buffer size limit (in bytes). * * @note Illegal values result in a @c g_warning and fallback to the default * cache buffer size limit 1048576. * * @param int User-defined cache buffer size limit within [262144, 4194304]. * Set 0 to disable caching. */ #define CONFNAME_GDP_CACHE_SIZE "cacheSize" /** * Defines a custom history cache item count limit. * * @note Illegal values result in a @c g_warning and fallback to the default * cache item count limit 256. * * @param int User-defined cache item count limit within [64, 1024]. */ #define CONFNAME_GDP_CACHE_COUNT "cacheCount" /* * END gdp goodies. ****************************************************************************** */ /* ****************************************************************************** * BEGIN timeSync plugin goodies. */ /** * Defines the string used for the timeSync config file group. */ #define CONFGROUPNAME_TIMESYNC "timeSync" /** * Enable (or disable) the TimeInfo API. */ #define CONFNAME_TIMESYNC_TIMEINFO_ENABLED "timeInfo.enabled" /* * END timeSync goodies. ****************************************************************************** */ #endif /* __CONF_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/config.h000066400000000000000000000126221470176644300241330ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2018,2021-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _CONFIG_H_ #define _CONFIG_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_types.h" #include "preference.h" #if defined(__cplusplus) extern "C" { #endif /* * Well-known configuration variable names */ #define CONFIG_VMWAREDIR "libdir" struct CryptoKey; struct KeySafeUserRing; void Config_SetAny(const char *value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetAnySecure(const char *value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetString(const char *value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetStringPlain(const char *value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetStringSecure(const char *value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetBool(Bool value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetBoolPlain(Bool value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetBoolSecure(Bool value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetLong(int32 value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetInt64(int64 value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetLongPlain(int32 value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetLongSecure(int32 value, const char *fmt, ...) PRINTF_DECL(2, 3); void Config_SetDouble(double value, const char *fmt, ...) PRINTF_DECL(2, 3); char *Config_GetString(const char *defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); char *Config_GetStringPlain(const char *defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); char *Config_GetStringSecure(const char *defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); char *Config_GetAsString(const char *fmt, ...) PRINTF_DECL(1, 2); char *Config_GetStringEnum(const char *defaultValue, const char **choices, const char *fmt, ...) PRINTF_DECL(3, 4); int Config_CompareVersion(int version); int Config_CompareVersions(int version1, int version2); char *Config_GetPathName(const char *defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); Bool Config_GetBool(Bool defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); Bool Config_GetBoolPlain(Bool defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); Bool Config_GetBoolSecure(Bool defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); int32 Config_GetLong(int32 defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); int64 Config_GetInt64(int64 defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); int32 Config_GetLongPlain(int32 defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); int32 Config_GetLongSecure(int32 defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); int32 Config_GetTriState(int32 defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); double Config_GetDouble(double defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); Bool Config_NotSet(const char *fmt, ...) PRINTF_DECL(1, 2); Bool Config_Unset(const char *fmt, ...) PRINTF_DECL(1, 2); Bool Config_UnsetWithPrefix(const char *fmt, ...) PRINTF_DECL(1, 2); Bool Config_NeedSave(void); void Config_Set(void *value, int type, const char *fmt, ...) PRINTF_DECL(3, 4); /* * This is tricky to call because it returns allocated storage. Use * the typed wrappers instead (Config_Get*). */ void *Config_Get(const void *pDefaultValue, int type, const char *fmt, ...) PRINTF_DECL(3, 4); Bool Config_Load(const char *filename); Bool Config_Write(void); Bool Config_WriteNoMsg(void); Bool Config_FileIsWritable(void); uint32 Config_GetMask(uint32 defaultMask, const char *optionName); uint64 Config_GetMask64(uint64 defaultMask, const char *optionName); Bool Config_GetDataFileKey(struct CryptoKey **key, struct KeySafeUserRing **userRing); Bool Config_GetDataFileKeys(struct KeySafeUserRing **parentKeys, struct KeySafeUserRing **allKeys); Bool Config_TriToBool(Bool boolDefaultValue, int32 triValue); #if defined(__cplusplus) } // extern "C" #endif #endif // _CONFIG_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/cpName.h000066400000000000000000000107071470176644300240730ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpName.h -- * * Cross-platform name format used by hgfs. * */ #ifndef __CP_NAME_H__ #define __CP_NAME_H__ #ifdef __KERNEL__ # include "driver-config.h" # include #elif defined __FreeBSD__ # if defined _KERNEL # include # define strchr(s,c) index(s,c) # else # include # endif #elif defined __APPLE__ && defined KERNEL # include #elif !defined sun # include # include #endif #include "vm_basic_types.h" /* Status codes for processing share names */ typedef enum { HGFS_NAME_STATUS_COMPLETE, /* Name is complete */ HGFS_NAME_STATUS_FAILURE, /* Name processing failed */ HGFS_NAME_STATUS_INCOMPLETE_BASE, /* Name is base of namespace */ HGFS_NAME_STATUS_INCOMPLETE_ROOT, /* Name is "root" only */ HGFS_NAME_STATUS_INCOMPLETE_DRIVE, /* Name is "root drive" only */ HGFS_NAME_STATUS_INCOMPLETE_UNC, /* Name is "root unc" only */ HGFS_NAME_STATUS_INCOMPLETE_UNC_MACH, /* Name is "root unc " only */ HGFS_NAME_STATUS_DOES_NOT_EXIST, /* Name does not exist */ HGFS_NAME_STATUS_ACCESS_DENIED, /* Desired access to share denied */ HGFS_NAME_STATUS_SYMBOLIC_LINK, /* Name contains a symbolic link */ HGFS_NAME_STATUS_OUT_OF_MEMORY, /* Out of memory while processing */ HGFS_NAME_STATUS_TOO_LONG, /* Name has overly long component */ HGFS_NAME_STATUS_NOT_A_DIRECTORY, /* Name has path component not a dir */ } HgfsNameStatus; int CPName_ConvertTo(char const *nameIn, // IN: The buf to convert size_t bufOutSize, // IN: The size of the output buffer char *bufOut); // OUT: The output buffer int CPName_LinuxConvertTo(char const *nameIn, // IN: buf to convert size_t bufOutSize, // IN: size of the output buffer char *bufOut); // OUT: output buffer int CPName_WindowsConvertTo(char const *nameIn, // IN: buf to convert size_t bufOutSize, // IN: size of the output buffer char *bufOut); // OUT: output buffer int CPName_ConvertFrom(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input buffer size_t *outSize, // IN/OUT: Size of output buffer char **bufOut); // IN/OUT: Output buffer HgfsNameStatus CPName_ConvertFromRoot(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input size_t *outSize, // IN/OUT: Size of output buf char **bufOut); // IN/OUT: Output buffer int CPName_GetComponent(char const *begin, // IN: Beginning of buffer char const *end, // IN: End of buffer char const **next); // OUT: Next component char const * CPName_Print(char const *in, // IN: Name to print size_t size); // IN: Size of name #endif /* __CP_NAME_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/cpNameLite.h000066400000000000000000000043721470176644300247120ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpLiteName.h -- * * Cross-platform "lite" name format used by hgfs. * */ #ifndef __CP_NAME_LITE_H__ #define __CP_NAME_LITE_H__ #if defined __KERNEL__ && defined __linux__ # include "driver-config.h" # include #elif defined _KERNEL && defined __FreeBSD__ # include # define strchr(s,c) index(s,c) #else # include #endif #include "vm_basic_types.h" void CPNameLite_ConvertTo(char *bufIn, // IN/OUT: Input to convert size_t inSize, // IN: Size of input buffer char pathSep); // IN: Path separator void CPNameLite_ConvertFrom(char *bufIn, // IN/OUT: Input to convert size_t inSize, // IN: Size of input buffer char pathSep); // IN: Path separator #endif /* __CP_NAME_LITE_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/cpNameUtil.h000066400000000000000000000064351470176644300247340ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2005-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * cpNameUtil.h * * Utility functions for cross-platform name format. * */ #ifndef __CP_NAME_UTIL_H__ #define __CP_NAME_UTIL_H__ #include "vm_basic_types.h" #include "cpName.h" char *CPNameUtil_Strrchr(char const *cpNameIn, size_t cpNameInSize, char searchChar); int CPNameUtil_ConvertToRoot(char const *nameIn, size_t bufOutSize, char *bufOut); int CPNameUtil_LinuxConvertToRoot(char const *nameIn, size_t bufOutSize, char *bufOut); int CPNameUtil_WindowsConvertToRoot(char const *nameIn, size_t bufOutSize, char *bufOut); /* * Convert a set of files or directories CP names from current to form C. * In/out name lengths include a final nul-terminator to ensure * all the final name component is converted. */ Bool CPNameUtil_Utf8FormHostToUtf8FormC(const char *cpNameToConvert, size_t cpNameToConvertLen, char **cpUtf8FormCName, size_t *cpUtf8FormCNameLen); /* * Convert a set of files or directories CP names from current from form C. * In/out name lengths include a final nul-terminator to ensure * all the final name component is converted. */ Bool CPNameUtil_Utf8FormCToUtf8FormHost(const char *cpUtf8FormCName, size_t cpUtf8FormCNameLen, char **cpConvertedName, size_t *cpConvertedNameLen); void CPNameUtil_CharReplace(char *buf, size_t bufSize, char oldChar, char newChar); #endif /* __CP_NAME_UTIL_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/cryptoError.h000066400000000000000000000060701470176644300252200ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2005-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * cryptoError.h -- * * Error code for cryptographic infrastructure library. */ #ifndef VMWARE_CRYPTOERROR_H #define VMWARE_CRYPTOERROR_H 1 #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vmware.h" typedef int CryptoError; #if defined(__cplusplus) extern "C" { #endif /* * This set of errors should not be expanded beyond a maximum value of 15 * without also updating the code for AIOMgr errors, which allots only 4 bits * for sub-error codes. * * Adding a lot of error codes to describe particular errors is a bad idea * anyhow, because it can be a security hole in itself; see, for example, the * SSL vulnerability described at . * It is best to distinguish only those types of errors that the caller can * legitimately use to figure out how to fix the problem and try again. */ #define CRYPTO_ERROR_SUCCESS ((CryptoError) 0) #define CRYPTO_ERROR_OPERATION_FAILED ((CryptoError) 1) #define CRYPTO_ERROR_UNKNOWN_ALGORITHM ((CryptoError) 2) #define CRYPTO_ERROR_BAD_BUFFER_SIZE ((CryptoError) 3) #define CRYPTO_ERROR_INVALID_OPERATION ((CryptoError) 4) #define CRYPTO_ERROR_NOMEM ((CryptoError) 5) #define CRYPTO_ERROR_NEED_PASSWORD ((CryptoError) 6) #define CRYPTO_ERROR_BAD_PASSWORD ((CryptoError) 7) #define CRYPTO_ERROR_IO_ERROR ((CryptoError) 8) #define CRYPTO_ERROR_UNKNOWN_ERROR ((CryptoError) 9) #define CRYPTO_ERROR_NAME_NOT_FOUND ((CryptoError) 10) #define CRYPTO_ERROR_NO_CRYPTO ((CryptoError) 11) #define CRYPTO_ERROR_LOCK_FAILURE ((CryptoError) 12) const char * CryptoError_ToString(CryptoError error); const char * CryptoError_ToMsgString(CryptoError error); static INLINE int CryptoError_ToInteger(CryptoError error) { return (int) error; } static INLINE CryptoError CryptoError_FromInteger(int index) { return (CryptoError) index; } static INLINE Bool CryptoError_IsSuccess(CryptoError error) { return (CRYPTO_ERROR_SUCCESS == error); } static INLINE Bool CryptoError_IsFailure(CryptoError error) { return (CRYPTO_ERROR_SUCCESS != error); } #if defined(__cplusplus) } // extern "C" #endif #endif /* cryptoError.h */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/dataMap.h000066400000000000000000000134311470176644300242340ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2013-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #ifndef _DATA_MAP_H_ #define _DATA_MAP_H_ #include "hashMap.h" #ifdef __cplusplus extern "C" { #endif typedef int32 DMKeyType; /* * Error codes for DataMap APIs */ typedef enum { DMERR_SUCCESS, /* success code */ DMERR_NOT_FOUND, /* data does not exist */ DMERR_ALREADY_EXIST, /* field ID already exist */ DMERR_DUPLICATED_FIELD_IDS, /* duplicated IDs in deserilization */ DMERR_INSUFFICIENT_MEM, /* insufficient memory */ DMERR_TYPE_MISMATCH, /* type does not match */ DMERR_INVALID_ARGS, /* invalid arguments */ DMERR_UNKNOWN_TYPE, /* type unknow in decoding */ DMERR_TRUNCATED_DATA, /* more data expected during decoding */ DMERR_BUFFER_TOO_SMALL, /* a user buffer is too small */ DMERR_INTEGER_OVERFLOW, /* an integer overflow happened */ DMERR_BAD_DATA /* bad data during decoding */ } ErrorCode; /* * Data field types */ typedef enum { DMFIELDTYPE_EMPTY, DMFIELDTYPE_INT64, DMFIELDTYPE_STRING, DMFIELDTYPE_INT64LIST, DMFIELDTYPE_STRINGLIST, DMFIELDTYPE_MAX } DMFieldType; typedef struct { HashMap *map; uint64 cookie; /* so we know the datamap is not some garbage data */ } DataMap; typedef struct { DMKeyType fieldId; const char *fieldName; } FieldIdNameEntry; /* * Initializer */ ErrorCode DataMap_Create(DataMap *that); // IN/OUT ErrorCode DataMap_Destroy(DataMap *that); // IN/OUT ErrorCode DataMap_Copy(const DataMap *src, // IN DataMap *dst); // OUT ErrorCode DataMap_Serialize(const DataMap *that, //IN char **buf, // OUT uint32 *bufLen); // OUT ErrorCode DataMap_Deserialize(const char *bufIn, // IN const int32 bufLen, // IN DataMap *that); // OUT ErrorCode DataMap_DeserializeContent(const char *bufIn, // IN const int32 bufLen, // IN DataMap *that); // OUT /* * Setters */ ErrorCode DataMap_SetInt64(DataMap *that, // IN/OUT DMKeyType fieldId, // IN int64 value, // IN Bool replace); // IN ErrorCode DataMap_SetString(DataMap *that, // IN/OUT DMKeyType fieldId, // IN char *str, // IN int32 strLen, // IN Bool replace); // IN ErrorCode DataMap_SetInt64List(DataMap *that, // IN/OUT DMKeyType fieldId, // IN int64 *numList, // IN int32 listLen, // IN Bool replace); // IN ErrorCode DataMap_SetStringList(DataMap *that, // IN/OUT DMKeyType fieldId, // IN char **strList, // IN int32 *strLens, // IN Bool replace); // IN /* * Getters */ DMFieldType DataMap_GetType(const DataMap *that, // IN DMKeyType fieldId); // IN ErrorCode DataMap_GetInt64(const DataMap *that, // IN DMKeyType fieldId, // IN int64 *value); // OUT ErrorCode DataMap_GetString(const DataMap *that, // IN DMKeyType fieldId, // IN char **str, // OUT int32 *strLen); // OUT ErrorCode DataMap_GetInt64List(const DataMap *that, // IN DMKeyType fieldId, // IN int64 **numList, // OUT int32 *listLen); // OUT ErrorCode DataMap_GetStringList(const DataMap *that, // IN DMKeyType fieldId, // IN char ***strList, // OUT int32 **strLens); // OUT ErrorCode DataMap_ToString(const DataMap *that, // IN FieldIdNameEntry *fieldIdList, // IN int32 fieldIdListLen, // IN int32 maxNumElements, // IN int32 maxStrLen, // IN char **buf); // OUT #ifdef __cplusplus } /* end of extern "C" */ #endif #endif // #ifdef _DATA_MAP_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/dbllnklst.h000066400000000000000000000213611470176644300246570ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017,2020,2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * dbllnklst.h -- * * Double linked lists * * Both circular and anchored (linear) lists are supported. * See bora/lib/misc/dbllnklst.c for sample code showing both use cases. */ #ifndef _DBLLNKLST_H_ #define _DBLLNKLST_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif #define DblLnkLst_OffsetOf(type, field) ((intptr_t)&((type *)0)->field) #define DblLnkLst_Container(addr, type, field) \ ((type *)((char *)(addr) - DblLnkLst_OffsetOf(type, field))) #define DblLnkLst_ForEach(curr, head) \ for (curr = (head)->next; curr != (head); curr = (curr)->next) /* Safe from list element removal within loop body. */ #define DblLnkLst_ForEachSafe(curr, nextElem, head) \ for (curr = (head)->next, nextElem = (curr)->next; \ curr != (head); \ curr = nextElem, nextElem = (curr)->next) typedef struct DblLnkLst_Links { struct DblLnkLst_Links *prev; struct DblLnkLst_Links *next; } DblLnkLst_Links; /* * Functions * * DblLnkLst_LinkFirst, DblLnkLst_LinkLast, and DblLnkLst_Swap are specific * to anchored lists. The rest are for both circular and anchored lists. */ /* *---------------------------------------------------------------------- * * DblLnkLst_Init -- * * Initialize a member of a doubly linked list * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Init(DblLnkLst_Links *l) // OUT { l->prev = l->next = l; } /* *---------------------------------------------------------------------- * * DblLnkLst_Link -- * * Merge two doubly linked lists into one * * The operation is commutative * The operation is inversible (its inverse is DblLnkLst_Unlink) * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Link(DblLnkLst_Links *l1, // IN/OUT DblLnkLst_Links *l2) // IN/OUT { DblLnkLst_Links *tmp; (tmp = l1->prev)->next = l2; (l1->prev = l2->prev)->next = l1; l2->prev = tmp ; } /* *---------------------------------------------------------------------- * * DblLnkLst_Unlink -- * * Split one doubly linked list into two * * No check is performed: the caller must ensure that both members * belong to the same doubly linked list * * The operation is commutative * The operation is inversible (its inverse is DblLnkLst_Link) * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Unlink(DblLnkLst_Links *l1, // IN/OUT DblLnkLst_Links *l2) // IN/OUT { DblLnkLst_Links *tmp; tmp = l1->prev ; (l1->prev = l2->prev)->next = l1; (l2->prev = tmp )->next = l2; } /* *---------------------------------------------------------------------- * * DblLnkLst_Unlink1 -- * * Unlink an element from its list. * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Unlink1(DblLnkLst_Links *l) // IN/OUT { DblLnkLst_Unlink(l, l->next); } /* *---------------------------------------------------------------------------- * * DblLnkLst_IsLinked -- * * Determines whether an element is linked with any other elements. * * Results: * TRUE if link is linked, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static INLINE Bool DblLnkLst_IsLinked(DblLnkLst_Links const *l) // IN { /* * A DblLnkLst_Links is either linked to itself (not linked) or linked to * other elements in a list (linked). */ return l->prev != l; } /* *---------------------------------------------------------------------- * * DblLnkLst_LinkFirst -- * * Insert 'l' at the beginning of the list anchored at 'head' * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_LinkFirst(DblLnkLst_Links *head, // IN/OUT DblLnkLst_Links *l) // IN/OUT { DblLnkLst_Link(head->next, l); } /* *---------------------------------------------------------------------- * * DblLnkLst_LinkLast -- * * Insert 'l' at the end of the list anchored at 'head' * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_LinkLast(DblLnkLst_Links *head, // IN/OUT DblLnkLst_Links *l) // IN/OUT { DblLnkLst_Link(head, l); } /* *---------------------------------------------------------------------- * * DblLnkLst_Swap -- * * Swap all entries between the list anchored at 'head1' and the list * anchored at 'head2'. * * The operation is commutative * The operation is inversible (its inverse is itself) * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Swap(DblLnkLst_Links *head1, // IN/OUT DblLnkLst_Links *head2) // IN/OUT { DblLnkLst_Links const tmp = *head1; if (DblLnkLst_IsLinked(head2)) { (head1->prev = head2->prev)->next = head1; (head1->next = head2->next)->prev = head1; } else { DblLnkLst_Init(head1); } if (tmp.prev != head1) { (head2->prev = tmp.prev)->next = head2; (head2->next = tmp.next)->prev = head2; } else { DblLnkLst_Init(head2); } } #if defined(__cplusplus) } // extern "C" #endif #endif /* _DBLLNKLST_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/debug.h000066400000000000000000000021161470176644300237510ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * debug.h -- * * Platform specific debug routines * */ #ifndef __DEBUG_H__ # define __DEBUG_H__ # include "vm_basic_types.h" void Debug(char const *fmt, ...) PRINTF_DECL(1, 2); #endif /* __DEBUG_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/deployPkg/000077500000000000000000000000001470176644300244505ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/deployPkg/deployPkgFormat.h000066400000000000000000000123641470176644300277360ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2006-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * deployPkgFormat.h -- * * A deployment package format used primarily to * upload and install software in a guest OS. * * The package can be a file, or a section embedded inside * of another file or raw block device. */ #ifndef _DEPLOY_PKG_FORMAT_H_ #define _DEPLOY_PKG_FORMAT_H_ #define VMWAREDEPLOYPKG_SIGNATURE_LENGTH 16 #define VMWAREDEPLOYPKG_SIGNATURE "VMWAREDEPLOYPKG_" #define VMWAREDEPLOYPKG_CMD_LENGTH 456 #define VMWAREDEPLOYPKG_SEED_LENGTH 8 #define VMWAREDEPLOYPKG_PAYLOAD_TYPE_CAB 0 // cabinet file #define VMWAREDEPLOYPKG_PAYLOAD_TYPE_ZIP 1 // zip #define VMWAREDEPLOYPKG_PAYLOAD_TYPE_GZIPPED_TAR 2 // tar.gz // XXX Delete this - it's redundant typedef enum { Cabinet, // cabinet file Zip, GzippedTar // tar.gz } VMwareDeployPkgPayloadType; #define VMWAREDEPLOYPKG_CURRENT_MAJOR_VERSION 1 #define VMWAREDEPLOYPKG_CURRENT_MINOR_VERSION 0 #include "vm_basic_types.h" #define VMWAREDEPLOYPKG_HEADER_FLAGS_NONE 0 #define VMWAREDEPLOYPKG_HEADER_FLAGS_SKIP_REBOOT 1 #define VMWAREDEPLOYPKG_HEADER_FLAGS_IGNORE_CLOUD_INIT 2 #define VMWAREDEPLOYPKG_HEADER_FLAGS_RAW_CLOUD_INIT 4 #ifdef _WIN32 #include "pshpack4.h" // 4 byte alignment assumed. #endif /* * VMware deployment package header. 4 byte alignment assumed. * The header size is exactly 512 bytes to make it easier to * embed in a disk device, such as a partition. * * The payload is extracted and expanded into a temporary folder. * During expansion, original relative path names are preserved. * The specified command is then executed on the host. * Its working directory is the extraction folder. * The command string may contain OS-specific environment * variables. * In addition, the variable VMWAREPKGDIR is defined to be * the location of the extraction folder. * * (Request for comment: is VMWAREPKGDIR really necessary? * Remove from spec if not.) * * The field seed is used by the password obfuscation library to hide details * that are required for obfuscating password in the config file. * * Command string example: * deploy.bat -opt1 myfile.exe foo.xml "%WINDIR%\system32" * * Seed is a piece of information used by the obfuscation code to compute * cryptography keys. * * The extraction folder is deleted after the command returns. * A return value of zero indicates successful deployment. * * Here is the approximate layout. Do not make assumptions about the * exact location and relative position of the individual sections. * Use the offset and length fields from the header instead. * *
 *
 *         +-------------------------+
 *         |         header          |
 *         +-------------------------+
 *         |         padding         |
 *         +-------------------------+
 *         |        payload          |
 *         +-------------------------+
 *         |      (seed+command)     |
 *         |         padding         |
 *         +-------------------------+
 * 
*/ #pragma pack(push, 1) typedef struct { char signature[VMWAREDEPLOYPKG_SIGNATURE_LENGTH]; // Not null terminated. uint8 majorVersion; uint8 minorVersion; uint8 payloadType; uint8 reserved; uint16 pkgProcessTimeout; // timeout value for process execution in deployPkg /* * Structs are aligned to word length. For 32 bit architecture it is 4 bytes * aligned and for 64 bit it is 8 bytes aligned. Need to make sure package * created in 32 bit architecture can be read correctly in 64 bit architecture * and vice-versa. So when adding or removing fields, a padding field maybe * needed to enable the payload section to start at the same place in both 32 * and 64 bit architecture. */ uint16 archPadding; // offset 22 uint64 pkgLength; // Total length of package including header, offset 24. uint64 payloadOffset; // Relative to beginning of header, offset 32. uint64 payloadLength; // Length of payload, offset 40. /* * Command string and padding, null terminated. * This padding makes the header sector-aligned, making it easier * to embed in disks and disk partitions. * This string may contain OS-specific env variables, e.g. %SYSTEMDRIVE%. */ char seed[VMWAREDEPLOYPKG_SEED_LENGTH]; // offset 48 char command[VMWAREDEPLOYPKG_CMD_LENGTH]; // offset 56 } VMwareDeployPkgHdr; #pragma pack(pop) #ifdef _WIN32 #include "poppack.h" #endif #endif // _DEPLOY_PKG_FORMAT_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/deployPkg/linuxDeployment.h000066400000000000000000000117121470176644300300230ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2009-2019, 2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * linuxDeployment.h -- * * C interface to package deployment. */ #ifndef LINUX_DEPLOYMENT_H #define LINUX_DEPLOYMENT_H #include "vm_basic_types.h" #include "imgcust-common/log.h" #include "imgcust-common/imgcust-api.h" #define DEPLOYPKG_PROCESSTIMEOUT_DEFAULT 100 typedef enum { DEPLOYPKG_STATUS_SUCCESS, DEPLOYPKG_STATUS_CLOUD_INIT_DELEGATED, DEPLOYPKG_STATUS_ERROR, DEPLOYPKG_STATUS_CAB_ERROR } DeployPkgStatus; /* *------------------------------------------------------------------------------ * * DeployPkg_SetTimeout -- * * Give the deploy package an application specific timeout value. * Package deployment engines such as tools-deployPkg-plugin or standalone program * linuxDeployPkg can call this API to set gProcessTimeout. * This API should be called before DeployPkg_DeployPackageFromFile or * DeployPkg_DeployPackageFromFileEx. * If the package header includs valid 'timeout' value, then that value will * overwrite gProcessTimeout. * If no valid 'timeout' value from both package header and deployment engine, then * default value 100s will be used. * * @param logger [in] * timeout value to be used for process execution period control * *------------------------------------------------------------------------------ */ IMGCUST_API void DeployPkg_SetProcessTimeout(uint16 timeout); /* *------------------------------------------------------------------------------ * * DeployPkg_SetWaitForCloudinitDoneTimeout * * Set the timeout value of customization process waits for cloud-init * execution done before trigger reboot and after connect network adapters. * * @param timeout [in] * timeout value to be used for waiting for cloud-init execution done * *------------------------------------------------------------------------------ */ IMGCUST_API void DeployPkg_SetWaitForCloudinitDoneTimeout(uint16 timeout); /* *------------------------------------------------------------------------------ * * DeployPkg_SetLogger -- * * Give the deploy package an application specific logger. * * @param logger [in] logger to be used for deploy operation * *------------------------------------------------------------------------------ */ IMGCUST_API void DeployPkg_SetLogger(LogFunction log); /* *------------------------------------------------------------------------------ * * DeployPkg_DeployPackageFromFileEx -- * * C-style wrapper to decode a package from a file, extract its payload, * expand the payload into a temporary directory, and then execute * the command specified in the package. * * @param file IN: the package file * @return DEPLOYPKG_STATUS_SUCCESS on success * DEPLOYPKG_STATUS_CLOUD_INIT_DELEGATED if customization task is * delegated to cloud-init * DEPLOYPKG_STATUS_ERROR on failure * *------------------------------------------------------------------------------ */ IMGCUST_API DeployPkgStatus DeployPkg_DeployPackageFromFileEx(const char* file); /* *------------------------------------------------------------------------------ * * DeployPkg_DeployPackageFromFile -- * * C-style wrapper to decode a package from a file, extract its payload, * expand the payload into a temporary directory, and then execute * the command specified in the package. * * @param file IN: the package file * @return 0 on success, -1 on failure * *------------------------------------------------------------------------------ */ IMGCUST_API int DeployPkg_DeployPackageFromFile(const char* file); /* *------------------------------------------------------------------------------ * * ExtractCabPackage -- * * C-style wrapper to extract a package from a file using libmspack. * * @param[in] cabFileName the Cabinet file's path * @param[in] destDir a destination directory where to uncab * * @return TRUE on success, otherwise - FALSE. * *------------------------------------------------------------------------------ */ IMGCUST_API Bool ExtractCabPackage(const char* cabFileName, const char* destDir); #endif // LINUX_DEPLOYMENT_H open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/dictll.h000066400000000000000000000035501470176644300241410ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * dictll.h -- * * Low-level dictionary format --hpreg */ #ifndef __DICTLL_H__ # define __DICTLL_H__ #include "vm_basic_types.h" #include "dynbuf.h" #if defined(__cplusplus) extern "C" { #endif int DictLL_ReadLine(FILE *stream, // IN char **line, // OUT char **name, // OUT char **value); // OUT Bool DictLL_WriteLine(FILE *stream, // IN char const *name, // IN char const *value); // IN const char * DictLL_UnmarshalLine(const char *buf, // IN size_t bufSize, // IN char **line, // OUT char **name, // OUT char **value); // OUT Bool DictLL_MarshalLine(DynBuf *output, // IN/OUT char const *name, // IN/OPT char const *value); // IN Bool DictLL_ReadUTF8BOM(FILE *file); // IN/OUT #if defined(__cplusplus) } // extern "C" #endif #endif /* __DICTLL_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/dynarray.h000066400000000000000000000322141470176644300245160ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * dynarray.h -- * * Dynamic array of objects. * * Use a DynArray to hold a dynamically resizable array * of objects with a fixed width. */ #ifndef _DYNARRAY_H_ #define _DYNARRAY_H_ #include "dynbuf.h" #include "vm_basic_types.h" #include "vm_assert.h" #if defined(__cplusplus) extern "C" { #endif typedef struct DynArray { DynBuf buf; size_t width; } DynArray; /* * The SVGA drivers require the __cdecl calling convention. * The qsort comparison function is compiled with the __stdecl * convention by default, so if we are compiling SVGA (which defines * STD_CALL) we need to explicitly declare the function with __cdecl. */ #if defined(STD_CALL) #define CDECLCONV __cdecl #else #define CDECLCONV #endif typedef int (CDECLCONV *DynArrayCmp)(const void *, const void *); Bool DynArray_Init(DynArray *a, unsigned int count, size_t width); void DynArray_Destroy(DynArray *a); Bool DynArray_SetCount(DynArray *a, unsigned int c); void DynArray_QSort(DynArray *a, DynArrayCmp compare); unsigned int DynArray_AllocCount(const DynArray *a); /* *----------------------------------------------------------------------------- * * DynArray_Trim -- * * Resize the array to fit exactly DynArray_Count() elements. * * Results: * TRUE on success * FALSE on failure (why? who knows...) * * Side effects: * Resizes the array * *----------------------------------------------------------------------------- */ static INLINE Bool DynArray_Trim(DynArray *a) // IN/OUT { ASSERT(a); return DynBuf_Trim(&a->buf); } /* *----------------------------------------------------------------------------- * * DynArray_AddressOf -- * * Fetch a pointer to the address of the ith element. * * Results: * The pointer to the ith element or NULL if the index is out of * bounds. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void * DynArray_AddressOf(const DynArray *a, // IN unsigned int i) // IN { uintptr_t offset = i * a->width; ASSERT(a); if (offset + a->width <= DynBuf_GetSize(&a->buf)) { return offset + (uint8 *)DynBuf_Get(&a->buf); } return NULL; } /* *----------------------------------------------------------------------------- * * DynArray_AddressOfUnsafe -- * * Fetch a pointer to the address of the ith element. Only call * this if you already know that 'i' is valid. The index is not * checked against the size of the array. * * Results: * Always returns a pointer to the ith element. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void * DynArray_AddressOfUnsafe(const DynArray *a, // IN unsigned int i) // IN { uintptr_t offset = i * a->width; ASSERT(a); ASSERT(offset + a->width <= DynBuf_GetSize(&a->buf)); return offset + (uint8 *)DynBuf_Get(&a->buf); } /* *----------------------------------------------------------------------------- * * DynArray_Count -- * * Returns the number of elements in the array. * * XXX: This is relatively slow, since we do an integer division. * Avoid calling this in inner loops. * * Results: * See above. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE unsigned int DynArray_Count(const DynArray *a) // IN { ASSERT(a); return (unsigned int) (DynBuf_GetSize(&a->buf) / a->width); } /* *----------------------------------------------------------------------------- * * DynArray_Copy -- * * Copies all data and metadata from src Dynarray to dest DynArray. * * Dest should be an initialized DynArray of size zero. * * Results: * TRUE on success, FALSE on failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool DynArray_Copy(DynArray *src, // IN DynArray *dest) // OUT { ASSERT(src); ASSERT(dest); ASSERT(dest->width); ASSERT(dest->width == src->width); ASSERT(DynArray_AllocCount(dest) == 0); return DynBuf_Copy(&src->buf, &dest->buf); } /* * Use the following macros to define your own DynArray type to * make its usage less cumbersome. You also get type-checking * for free, as demonstrated by this example: * * Assume: * * typedef struct { int n, d; } Fraction; * typedef struct { float r, i; } Complex; * * Without DEFINE_DYNARRAY_TYPE: * * DynArray a1, a2; * DynArray_Init(&a1, 4, sizeof(Fraction)); * DynArray_Init(&a2, 16, sizeof(Complex)); * * Fraction *f2 = (Fraction *)DynArray_AddressOf(&a2, 3); // Runtime Error * * * With DEFINE_DYNARRAY_TYPE: * * DEFINE_DYNARRAY_TYPE(Fraction) * DEFINE_DYNARRAY_TYPE(Complex) * FractionArray a1; * ComplexArray a2; * FractionArray_Init(&a1, 4); * ComplexArray_Init(&a2, 16); * * Fraction *f2 = FractionArray_AddressOf(&a2, 3); // Compile Error * * Yes, it's a poor man's template (but better than nothing). * * Note that emscripten does not allow function pointer casting, and has a * compiler warning to enforce this, so we cannot use DEFINE_DYNARRAY_TYPE * as it relies on a function cast to define T##Array_QSort. * */ #ifndef __EMSCRIPTEN__ #define DEFINE_DYNARRAY_TYPE(T) DEFINE_DYNARRAY_NAMED_TYPE(T, T) #define DEFINE_DYNARRAY_NAMED_TYPE(T, TYPE) \ DECLARE_DYNARRAY_TYPE(T) \ DEFINEONLY_DYNARRAY_NAMED_TYPE(T, TYPE) #define DECLARE_DYNARRAY_TYPE(T) \ typedef DynArray T##Array; #define DEFINEONLY_DYNARRAY_NAMED_TYPE(T, TYPE) \ \ typedef int (CDECLCONV *DynArray##T##Cmp)(const TYPE *, \ const TYPE *); \ \ static INLINE Bool \ T##Array_Init(T##Array *a, unsigned int count) \ { \ return DynArray_Init((DynArray *)a, count, sizeof(TYPE)); \ } \ \ static INLINE void \ T##Array_Destroy(T##Array *a) \ { \ DynArray_Destroy((DynArray *)a); \ } \ \ static INLINE TYPE* \ T##Array_AddressOf(T##Array *a, unsigned int i) \ { \ return (TYPE*)DynArray_AddressOf((DynArray *)a, i); \ } \ \ static INLINE TYPE* \ T##Array_AddressOfUnsafe(T##Array *a, unsigned int i) \ { \ return (TYPE*)DynArray_AddressOfUnsafe((DynArray *)a, i); \ } \ \ static INLINE unsigned int \ T##Array_Count(const T##Array *a) \ { \ return DynArray_Count((const DynArray *)a); \ } \ \ static INLINE Bool \ T##Array_SetCount(T##Array *a, unsigned int c) \ { \ return DynArray_SetCount((DynArray *)a, c); \ } \ \ static INLINE Bool \ T##Array_Push(T##Array *a, TYPE val) \ { \ unsigned int count = T##Array_Count(a); \ if (!T##Array_SetCount(a, count + 1)) { \ return FALSE; \ } \ *T##Array_AddressOf(a, count) = val; \ return TRUE; \ } \ \ static INLINE Bool \ T##Array_PushFront(T##Array *a, TYPE val) \ { \ unsigned int count = T##Array_Count(a); \ if (!T##Array_SetCount(a, count + 1)) { \ return FALSE; \ } else { \ unsigned int i; \ for (i = count; i > 0; --i) { \ *T##Array_AddressOf(a, i) = *T##Array_AddressOf(a, i-1); \ } \ *T##Array_AddressOf(a, 0) = val; \ return TRUE; \ } \ } \ \ static INLINE unsigned int \ T##Array_AllocCount(T##Array *a) \ { \ return DynArray_AllocCount((DynArray *)a); \ } \ \ static INLINE Bool \ T##Array_Trim(T##Array *a) \ { \ return DynArray_Trim((DynArray *)a); \ } \ static INLINE void \ T##Array_QSort(T##Array *a, DynArray##T##Cmp compare) \ { \ DynArray_QSort((DynArray *)a, (DynArrayCmp)compare); \ } \ static INLINE Bool \ T##Array_Copy(T##Array *src, T##Array *dest) \ { \ return DynArray_Copy((DynArray *)src, (DynArray *)dest); \ } /* Define DynArray of DynBuf. */ DEFINE_DYNARRAY_TYPE(DynBuf) #endif // ifndef __EMSCRIPTEN__ #if defined(__cplusplus) } // extern "C" #endif #endif /* _DYNARRAY_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/dynbuf.h000066400000000000000000000233161470176644300241570ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * dynbuf.h -- * * Dynamic buffers */ #ifndef DYNBUF_H # define DYNBUF_H #include #include "vm_basic_types.h" #include "vm_assert.h" #if defined(__cplusplus) extern "C" { #endif typedef struct DynBuf { char *data; size_t size; size_t allocated; } DynBuf; void DynBuf_Init(DynBuf *b); // OUT void DynBuf_InitWithMemory(DynBuf *b, size_t dataSize, void *data); void DynBuf_InitWithString(DynBuf *b, char *str); void DynBuf_Destroy(DynBuf *b); // IN void DynBuf_Attach(DynBuf *b, // IN size_t size, // IN void *data); // IN void * DynBuf_Detach(DynBuf *b); // IN/OUT char * DynBuf_DetachString(DynBuf *b); // IN/OUT Bool DynBuf_Enlarge(DynBuf *b, // IN/OUT size_t min_size); // IN Bool DynBuf_Append(DynBuf *b, // IN/OUT void const *data, // IN size_t size); // IN MUST_CHECK_RETURN Bool DynBuf_Insert(DynBuf *b, // IN/OUT size_t offset, // IN void const *data, // IN size_t size); // IN Bool DynBuf_Trim(DynBuf *b); // IN/OUT Bool DynBuf_Copy(DynBuf *src, // IN DynBuf *dest); // OUT void DynBuf_SafeInternalAppend(DynBuf *b, // IN/OUT void const *data, // IN size_t size, // IN char const *file, // IN unsigned int lineno); // IN #define DynBuf_SafeAppend(_buf, _data, _size) \ DynBuf_SafeInternalAppend(_buf, _data, _size, __FILE__, __LINE__) void DynBuf_SafeInternalInsert(DynBuf *b, // IN/OUT size_t offset, // IN void const *data, // IN size_t size, // IN char const *file, // IN unsigned int lineno); // IN #define DynBuf_SafeInsert(_buf, _offset, _data, _size) \ DynBuf_SafeInternalInsert(_buf, _offset, _data, _size, __FILE__, __LINE__) void DynBuf_SafeInternalEnlarge(DynBuf *b, // IN/OUT size_t min_size, // IN char const *file, // IN unsigned int lineno); // IN #define DynBuf_SafeEnlarge(_buf, _min_size) \ DynBuf_SafeInternalEnlarge(_buf, _min_size, __FILE__, __LINE__) /* *----------------------------------------------------------------------------- * * DynBuf_Get -- * * Retrieve a pointer to the data contained in a dynamic buffer --hpreg * * Results: * The pointer to the data * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(SWIG) static void * #else static INLINE void * #endif DynBuf_Get(DynBuf const *b) // IN { ASSERT(b); return b->data; } /* *----------------------------------------------------------------------------- * * DynBuf_GetString -- * * Results: * Returns a pointer to the dynamic buffer data as a NUL-terminated * string. * * Side effects: * DynBuf might allocate additional memory and will panic if it fails to. * *----------------------------------------------------------------------------- */ #if defined(SWIG) static char * #else static INLINE char * #endif DynBuf_GetString(DynBuf *b) // IN { ASSERT(b); if (b->size == b->allocated) { ASSERT_MEM_ALLOC(DynBuf_Enlarge(b, b->size + 1)); } b->data[b->size] = '\0'; return b->data; } /* *----------------------------------------------------------------------------- * * DynBuf_GetSize -- * * Returns the current size of the dynamic buffer --hpreg * * Results: * The current size of the dynamic buffer * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(SWIG) static size_t #else static INLINE size_t #endif DynBuf_GetSize(DynBuf const *b) // IN { ASSERT(b); return b->size; } /* *----------------------------------------------------------------------------- * * DynBuf_SetSize -- * * Set the current size of a dynamic buffer --hpreg * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(SWIG) static void #else static INLINE void #endif DynBuf_SetSize(DynBuf *b, // IN/OUT: size_t size) // IN { ASSERT(b); ASSERT(size <= b->allocated); b->size = size; } /* *----------------------------------------------------------------------------- * * DynBuf_GetAllocatedSize -- * * Returns the current allocated size of the dynamic buffer --hpreg * * Results: * The current allocated size of the dynamic buffer * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(SWIG) static size_t #else static INLINE size_t #endif DynBuf_GetAllocatedSize(DynBuf const *b) // IN { ASSERT(b); return b->allocated; } /* *----------------------------------------------------------------------------- * * DynBuf_GetAvailableSize -- * * Returns the current available space in the dynamic buffer. * * Results: * Current available space in dynamic buffer * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(SWIG) static size_t #else static INLINE size_t #endif DynBuf_GetAvailableSize(DynBuf const *b) // IN { ASSERT(b); return b->allocated - b->size; } /* *---------------------------------------------------------------------------- * * DynBuf_AppendString -- * * Appends the string to the specified DynBuf object, including its NUL * terminator. Note that this is NOT like strcat; repeated calls will * leave embedded NULs in the middle of the buffer. (Compare to * DynBuf_Strcat.) * * Results: * TRUE on success * FALSE on failure (not enough memory) * * Side effects: * DynBuf may change its size or allocate additional memory. * *---------------------------------------------------------------------------- */ #if defined(SWIG) static Bool #else static INLINE Bool #endif DynBuf_AppendString(DynBuf *buf, // IN/OUT const char *string) // IN { return DynBuf_Append(buf, string, strlen(string) + 1 /* NUL */); } /* *---------------------------------------------------------------------------- * * DynBuf_SafeAppendString -- * * "Safe" version of the above that does not fail. * * Results: * None. * * Side effects: * DynBuf may change its size or allocate additional memory. * *---------------------------------------------------------------------------- */ #if defined(SWIG) static void #else static INLINE void #endif DynBuf_SafeAppendString(DynBuf *buf, // IN/OUT const char *string) // IN { DynBuf_SafeAppend(buf, string, strlen(string) + 1 /* NUL */); } /* *---------------------------------------------------------------------------- * * DynBuf_Strcat -- * * A DynBuf version of strcat. Unlike DynBuf_AppendString, does NOT * visibly NUL-terminate the DynBuf, thereby allowing future appends to * do proper string concatenation without leaving embedded NULs in the * middle. * * Results: * TRUE on success * FALSE on failure (not enough memory) * * Side effects: * DynBuf may change its size or allocate additional memory. * *---------------------------------------------------------------------------- */ #if defined(SWIG) static Bool #else static INLINE Bool #endif DynBuf_Strcat(DynBuf *buf, // IN/OUT const char *string) // IN { Bool success; ASSERT(buf != NULL); ASSERT(string != NULL); /* * We actually do NUL-terminate the buffer internally, but this is not * visible to callers, and they should not rely on this. */ success = DynBuf_AppendString(buf, string); if (LIKELY(success)) { ASSERT(buf->size > 0); buf->size--; } return success; } /* *---------------------------------------------------------------------------- * * DynBuf_EnsureMinSize -- * * Ensure that the size of the DynBuf is at least 'size'. * * Results: * TRUE on success * FALSE on failure (not enough memory) * * Side effects: * DynBuf may change its size or allocate additional memory. * *---------------------------------------------------------------------------- */ #if defined(SWIG) static Bool #else static INLINE Bool #endif DynBuf_EnsureMinSize(DynBuf *buf, // IN/OUT size_t size) // IN { return buf->allocated >= size ? TRUE : DynBuf_Enlarge(buf, size); } #if defined(__cplusplus) } // extern "C" #endif #endif /* DYNBUF_H */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/dynxdr.h000066400000000000000000000035011470176644300241720ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _DYNXDR_H_ #define _DYNXDR_H_ /* * dynxdr.h -- * * Functions for creating and destroying an XDR stream that is backed * by a dynamic memory buffer. Uses DynBuf, so requires code using it to * link lib/misc. * * This stream only does encoding. For decoding, we generally have data * already available in the form of a pre-allocated buffer, in which * case we can use the xdrmem_create() function. * * Note: xdr_destroy() is a no-op for this stream. Use DynXdr_Destroy() * instead. Also, XDR_SETPOS and XDR_INLINE are not supported. */ #include #include #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif XDR *DynXdr_Create(XDR *in); Bool DynXdr_AppendRaw(XDR *xdrs, const void *buf, size_t len); void *DynXdr_AllocGet(XDR *xdrs); void *DynXdr_Get(XDR *xdrs); void DynXdr_Destroy(XDR *xdrs, Bool release); #if defined(__cplusplus) } // extern "C" #endif #endif /* _DYNXDR_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/embed_version.h000066400000000000000000000036401470176644300255070ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * embed_version.h -- * * Embeds a version string in an ELF binary that is readable by modinfo. */ #ifndef _EMBED_VERSION_H_ #define _EMBED_VERSION_H_ /* * Using section attributes, embed the specified version in the "modinfo" * section of the ELF binary. We don't do this on Windows, where the PE format * already has version information stuffed inside it, nor on Mac OS X, which * doesn't use ELF. * * We can't declare vm_version as static, otherwise it may get optimized out. * I've seen this when building with gcc 4.1, but not with 3.3. * * The argument to the macro should be the base name for the version number * macros to embed in the final binary, as described in vm_version.h (see * declaration of VM_VERSION_TO_STR). */ #if !defined(_WIN32) && !defined(__APPLE__) #define VM_EMBED_VERSION(ver) \ const char vm_version[] \ __attribute__((section(".modinfo"), unused)) = "version=" ver #else #define VM_EMBED_VERSION(ver) #endif #endif /* _EMBED_VERSION_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/err.h000066400000000000000000000062541470176644300234620ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * err.h -- * * General error handling library */ #ifndef _ERR_H_ #define _ERR_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include #include "vm_basic_defs.h" #if defined(__cplusplus) extern "C" { #endif #if defined(_WIN32) typedef DWORD Err_Number; #else typedef int Err_Number; #endif #define ERR_INVALID ((Err_Number) -1) const char *Err_ErrString(void); const char *Err_Errno2String(Err_Number errorNumber); Err_Number Err_String2Errno(const char *string); #if defined(VMX86_DEBUG) Err_Number Err_String2ErrnoDebug(const char *string); #endif #if defined(_WIN32) char *Err_SanitizeMessage(const char *msg); #endif void Err_Exit(void); /* *---------------------------------------------------------------------- * * Err_Errno -- * * Gets last error in a platform independent way. * * Results: * Last error. * * Side effects: * None. * *---------------------------------------------------------------------- */ #if defined(_WIN32) #define Err_Errno() GetLastError() #else #define Err_Errno() errno #endif /* *---------------------------------------------------------------------- * * Err_SetErrno -- * * Set the last error in a platform independent way. * * Results: * None. * * Side effects: * Yes. * *---------------------------------------------------------------------- */ #if defined(_WIN32) #define Err_SetErrno(e) SetLastError(e) #else #define Err_SetErrno(e) (errno = (e)) #endif /* *---------------------------------------------------------------------- * * WITH_ERRNO -- * * Execute "body" with "e" bound to the last error number * and preserving the last error in surrounding code. * * Results: * None. * * Side effects: * Yes. * *---------------------------------------------------------------------- */ #if defined(_WIN32) #define WITH_ERRNO(e, body) do { \ Err_Number e = Err_Errno(); \ int __win__##e = errno; \ body; \ Err_SetErrno(e); \ errno = __win__##e; \ } while (0) #else #define WITH_ERRNO(e, body) do { \ Err_Number e = Err_Errno(); \ body; \ Err_SetErrno(e); \ } while (0) #endif #define WITH_ERRNO_FREE(p) WITH_ERRNO(__errNum__, free((void *)p)) #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/escape.h000066400000000000000000000051511470176644300241250ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * escape.h -- * * Buffer escaping --hpreg */ #ifndef __ESCAPE_H__ # define __ESCAPE_H__ #include "vmware.h" #if defined(__cplusplus) extern "C" { #endif void * Escape_DoString(const char *escStr, // IN int const *bytesToEsc, // IN void const *bufIn, // IN size_t sizeIn, // IN size_t *sizeOut); // OUT/OPT void * Escape_Do(char escByte, // IN int const *bytesToEsc, // IN void const *bufIn, // IN size_t sizeIn, // IN size_t *sizeOut); // OUT/OPT void * Escape_Undo(char escByte, // IN void const *bufIn, // IN size_t sizeIn, // IN size_t *sizeOut); // OUT/OPT Bool Escape_UndoFixed(char escByte, // IN void const *bufIn, // IN size_t sizeIn, // IN void *bufOut, // IN/OUT size_t bufOutSize); // IN const char * Escape_Strchr(char escByte, // IN const char *bufIn, // IN char c); // IN char * Escape_Unescape(char escByte, // IN const char *bufIn); // IN void * Escape_AnsiToUnix(void const *bufIn, // IN size_t sizeIn, // IN size_t *sizeOut); // OUT/OPT void * Escape_Sh(void const *bufIn, // IN size_t sizeIn, // IN size_t *sizeOut); // OUT/OPT void * Escape_BRE(void const *bufIn, // IN size_t sizeIn, // IN size_t *sizeOut); // OUT/OPT void Escape_UnescapeCString(char *buf); // IN/OUT char * Escape_Comma(const char *string); // IN #if defined(__cplusplus) } // extern "C" #endif #endif /* __ESCAPE_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/file.h000066400000000000000000000273461470176644300236160ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2020,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * file.h -- * * Interface to host file system and related utility functions. */ #ifndef _FILE_H_ #define _FILE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include #include "fileIO.h" #include "unicodeTypes.h" #include "err.h" #if defined(_WIN32) #define FILE_MAXPATH MAX_PATH #else # ifdef __FreeBSD__ # include // For __FreeBSD_version # endif # if defined(__FreeBSD__) # include // PATH_MAX # else # include // PATH_MAX # endif #define FILE_MAXPATH PATH_MAX #endif #if defined(__cplusplus) extern "C" { #endif #define FILE_SEARCHPATHTOKEN ";" #define FILE_UNLINK_DEFAULT_WAIT_MS 2000 /* * Opaque, platform-specific stucture for supporting the directory walking API. */ typedef struct WalkDirContextImpl WalkDirContextImpl; typedef WalkDirContextImpl *WalkDirContext; /* * When File_MakeTempEx2 is called, it creates a temporary file or a directory * in a specified directory. File_MakeTempEx2 calls a user-specified callback * function to get the filename. Callback function should be of type * File_MakeTempCreateNameFunc. * * 'num' specifies nth time this function is called. * * 'data' specifies the payload that the user specified when executing * File_MakeTempEx2 function. * * If successful, this function should return a dynamically allocated string * with the filename. * * File_MakeTempEx2 frees the pathName after a successful call to this * function. * */ typedef char *File_MakeTempCreateNameFunc(uint32 num, void *data); #if defined(__APPLE__) Bool FileMacos_IsOnSparseDmg(int fd); Bool FileMacOS_MakeSecureLibraryCopies(const char *inDir, const char **dylibName, unsigned numDylibs, char **outDir); #elif defined VMX86_SERVER struct FS_PartitionListResult; int File_GetVMFSAttributes(const char *pathName, struct FS_PartitionListResult **fsAttrs); int File_GetVMFSFSType(const char *pathName, int fd, uint16 *fsTypeNum); int File_GetVMFSVersion(const char *pathName, uint32 *versionNum); int File_GetVMFSBlockSize(const char *pathName, uint32 *blockSize); int File_GetVMFSMountInfo(const char *pathName, char **fsType, uint32 *version, char **remoteIP, char **remoteMountPoint, char **localMountPoint); int File_GetVMFSLockInfo(const char *path, uint32 *outOpenFlags, uint32 *outWorldID, char **outWorldName, char **outVMFSMacAddr, uint32 *outVMFSLockMode); #endif Bool File_SupportsZeroedThick(const char *pathName); Bool File_SupportsMultiWriter(const char *pathName); Bool File_SupportsOptimisticLock(const char *pathName); Bool File_SupportsMandatoryLock(const char *pathName); Bool File_Exists(const char *pathName); int File_Unlink(const char *pathName); int File_UnlinkIfExists(const char *pathName); int File_UnlinkDelayed(const char *pathName); int File_UnlinkNoFollow(const char *pathName); int File_UnlinkRetry(const char *pathName, uint32 maxWaitTimeMilliSec); void File_SplitName(const char *pathName, char **volume, char **dir, char **base); void File_GetPathName(const char *fullPath, char **pathName, char **base); char *File_StripSlashes(const char *path); char *File_PathJoin(const char *dirName, const char *baseName); Bool File_CreateDirectory(const char *pathName); Bool File_CreateDirectoryEx(const char *pathName, int mode); Bool File_EnsureDirectory(const char *pathName); Bool File_EnsureDirectoryEx(const char *pathName, int mode); Bool File_DeleteEmptyDirectory(const char *pathName); Bool File_CreateDirectoryHierarchy(const char *pathName, char **topmostCreated); Bool File_CreateDirectoryHierarchyEx(const char *pathName, int mode, char **topmostCreated); Bool File_DeleteDirectoryContent(const char *pathName); Bool File_DeleteDirectoryTree(const char *pathName); int File_ListDirectory(const char *dirName, char ***ids); Bool File_IsOsfsVolumeEmpty(const char *pathName); #ifndef _WIN32 char * File_StripFwdSlashes(const char *pathName); #endif /* * Simple file-system walk. */ WalkDirContext File_WalkDirectoryStart(const char *dirName); Bool File_WalkDirectoryNext(WalkDirContext context, char **fileName); void File_WalkDirectoryEnd(WalkDirContext context); Bool File_IsDirectory(const char *pathName); Bool File_IsFile(const char *pathName); Bool File_IsSymLink(const char *pathName); Bool File_ContainSymLink(const char *pathName); Bool File_IsCharDevice(const char *pathName); Bool File_GetParent(char **canPath); Bool File_IsRemote(const char *pathName); Bool File_IsEmptyDirectory(const char *pathName); char *File_Cwd(const char *drive); // XXX belongs to `process' module char *File_FullPath(const char *pathName); Bool File_IsFullPath(const char *pathName); uint64 File_GetFreeSpace(const char *pathName, Bool doNotAscend); uint64 File_GetCapacity(const char *pathName); #ifdef _WIN32 char *File_GetNTGlobalFinalPath(const char *pathName); #endif int File_MakeTempEx(const char *dir, const char *pathName, char **presult); int File_MakeTempEx2(const char *dir, Bool createTempFile, File_MakeTempCreateNameFunc *createNameFunc, void *createFuncData, char **presult); char *File_MakeSafeTempDir(const char *prefix); char *File_MakeSafeTempSubdir(const char *safeDir, const char *subdirName); int64 File_GetModTime(const char *pathName); char *File_GetModTimeString(const char *pathName); char *File_GetUniqueFileSystemID(const char *pathName); char *File_GetMountPath(const char *pathName, Bool checkEntirePath); #ifdef _WIN32 char *File_GetVolumeGUID(const char *pathName); #endif Bool File_GetTimes(const char *pathName, VmTimeType *createTime, VmTimeType *accessTime, VmTimeType *writeTime, VmTimeType *attrChangeTime); Bool File_SetTimes(const char *pathName, VmTimeType createTime, VmTimeType accessTime, VmTimeType writeTime, VmTimeType attrChangeTime); Bool File_GetFilePermissions(const char *pathName, int *mode); Bool File_SetFilePermissions(const char *pathName, int mode); Bool File_SupportsFileSize(const char *pathName, uint64 fileSize); Bool File_GetMaxFileSize(const char *pathName, uint64 *maxFileSize); Bool File_SupportsLargeFiles(const char *pathName); char *File_MapPathPrefix(const char *oldPath, const char **oldPrefixes, const char **newPrefixes, size_t numPrefixes); Bool File_CopyFromFdToFd(FileIODescriptor src, FileIODescriptor dst); Bool File_CopyFromFd(FileIODescriptor src, const char *dstName, Bool overwriteExisting); Bool File_Copy(const char *srcName, const char *dstName, Bool overwriteExisting); Bool File_MoveTree(const char *srcName, const char *dstName, Bool overwriteExisting, Bool *asMove); Bool File_CopyTree(const char *srcName, const char *dstName, Bool overwriteExisting, Bool followSymlinks); Bool File_Replace(const char *oldFile, const char *newFile); int File_Rename(const char *oldFile, const char *newFile); int File_RenameRetry(const char *oldFile, const char *newFile, uint32 msecMaxWaitTime); Bool File_Move(const char *oldFile, const char *newFile, Bool *asRename); void File_Rotate(const char *pathName, int n, Bool noRename, char **newFileName); int File_GetFSMountInfo(const char *pathName, char **fsType, uint32 *version, char **remoteIP, char **remoteMountPoint, char **localMountPoint); /* Get size only for regular file. */ int64 File_GetSize(const char *pathName); /* Get size for file or directory. */ int64 File_GetSizeEx(const char *pathName); int64 File_GetSizeByPath(const char *pathName); int64 File_GetSizeAlternate(const char *pathName); Bool File_IsSameFile(const char *path1, const char *path2); char *File_PrependToPath(const char *searchPath, const char *elem); Bool File_FindFileInSearchPath(const char *file, const char *searchPath, const char *cwd, char **result); char *File_ReplaceExtension(const char *pathName, const char *newExtension, uint32 numExtensions, ...); char *File_RemoveExtension(const char *pathName); Bool File_MakeCfgFileExecutable(const char *pathName); char *File_ExpandAndCheckDir(const char *dirName); char *File_GetSafeTmpDir(Bool useConf); char *File_GetSafeRandomTmpDir(Bool useConf); char *File_GetUacSafeRandomTmpDir(Bool useConf); int File_MakeSafeTemp(const char *tag, char **presult); Bool File_DoesVolumeSupportAcls(const char *pathName); Bool File_IsSubPathOf(const char *base, const char *path); Bool File_DoesVolumeSupportConvertBlocks(const char *pathName); /* *--------------------------------------------------------------------------- * * File_IsDirsep -- * * Is the argument character a directory separator? * * Results: * TRUE Yes * FALSE No * * Side effects: * None * *--------------------------------------------------------------------------- */ static INLINE Bool File_IsDirsep(int c) // IN: { #if defined(_WIN32) return (c == '/') || (c == '\\'); // Until util.h dependencies work out #else return c == '/'; #endif } #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _FILE_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/fileIO.h000066400000000000000000000417001470176644300240340ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2018, 2021-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * fileIO.h -- * * Host-independent wrapper for low-level fileIO functions. * */ /* * Note: * * . FileIO_[Read|Write]() [read|write]s exactly the number of bytes requested * unless an error occurs * . FileIO_Seek() supports files larger than 2 GB * . If a function returns a generic error, you can call your native function * to retrieve the last error code */ #ifndef _FILEIO_H_ #define _FILEIO_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include #include #if !defined(_WIN32) #include #include #endif #include "vm_basic_types.h" #include "unicodeTypes.h" #include "iovector.h" // for struct iovec #if defined(__cplusplus) extern "C" { #endif struct FileLockToken; #if defined(_WIN32) # include typedef struct FileIODescriptor { HANDLE win32; uint32 flags; char *fileName; struct FileLockToken *lockToken; } FileIODescriptor; #else typedef struct FileIODescriptor { int posix; int flags; char *fileName; struct FileLockToken *lockToken; } FileIODescriptor; #endif typedef enum { /* distance is relative to the beginning of the file */ FILEIO_SEEK_BEGIN, /* distance is relative to the current position in the file */ FILEIO_SEEK_CURRENT, /* distance is relative to the end of the file */ FILEIO_SEEK_END, } FileIOSeekOrigin; #define FILEIO_OPEN_ACCESS_READ (1 << 0) #define FILEIO_OPEN_ACCESS_WRITE (1 << 1) /* * Use synchronous writes (no lazy buffer cache flush) */ #define FILEIO_OPEN_SYNC (1 << 2) /* * Delete the file as soon as possible (i.e. when nobody uses it anymore) */ #define FILEIO_OPEN_DELETE_ASAP (1 << 3) #define FILEIO_OPEN_UNBUFFERED (1 << 4) /* * Lock the file on open */ #define FILEIO_OPEN_LOCKED (1 << 5) /* * Asynchronous file I/O */ #define FILEIO_ASYNCHRONOUS (1 << 6) /* * Open non-blocking mode */ #define FILEIO_OPEN_NONBLOCK (1 << 7) /* * Open with more privileges */ #define FILEIO_OPEN_PRIVILEGED (1 << 8) /* * Open exclusive. * On Windows host it doesn't pass the flag FILE_SHARE_(READ|WRITE) to * CreateFile. Right now, EXCLUSIVE_READ is not used and EXCLUSIVE_WRITE * is only used by the cdrom code to implement the exclusive option. * On Linux hosts, it passes O_EXCL if both are set. * By default, we share r/w. -Maxime */ #define FILEIO_OPEN_EXCLUSIVE_READ (1 << 9) #define FILEIO_OPEN_EXCLUSIVE_WRITE (1 << 10) /* * Open sequential. * This flag only changes the behavior on Windows host. It is off by default. */ #define FILEIO_OPEN_SEQUENTIAL_SCAN (1 << 11) /* * Make IOCTL be run by root. This flag only changes the behavior on Linux * host. It is off by default. * * XXX: This has nothing to do with fileIO, but since AIOMgr shares the flags * with fileIO, I had to add it here. In some future it would be nice to * unshare the flags between the two at which point this could be fixed. * --Tommy */ #define FILEIO_OPEN_PRIVILEGED_IOCTL (1 << 12) /* * Lock the file on open with a exclusive leased lock that can be broken * (supported on ESX file systems) */ #define FILEIO_OPEN_EXCLUSIVE_LOCK (1 << 13) /* * Lock the file on open with a multiwriter leased lock that can be broken * (supported on ESX file systems) */ #define FILEIO_OPEN_MULTIWRITER_LOCK (1 << 14) /* * Lock the file on open with an SWMR leased lock that can be broken * (supported on ESX file systems) */ #define FILEIO_OPEN_SWMR_LOCK (1 << 15) /* * Valid only for MacOS. It eventually results into O_EXLOCK flag passed to open * system call. * * O_EXLOCK, O_SHLOCK behavior is tested on Mac OS X Server 10.6, kernel 10.0.0. * * | | Block devices | Regular files * |----------------------|--------------------|---------------- * | Locking behavior | mandatory | advisory * | | | * | If O_NONBLOCK absent | open doesn't block | open blocks * | | on conflicts | on conflicts */ #define FILEIO_OPEN_EXCLUSIVE_LOCK_MACOS (1 << 16) /* * Open file in APPEND-only mode. All writes go to the current end of file, * not to the current file pointer location. */ #define FILEIO_OPEN_APPEND (1 << 17) /* * Valid only on POSIXen. Don't follow a symbolic link. */ #define FILEIO_OPEN_ACCESS_NOFOLLOW (1 << 18) /* * Valid only on Windows. Set FILE_SHARE_DELETE. */ #define FILEIO_OPEN_SHARE_DELETE (1 << 19) /* * Strengths of file lock. * Advisory: * Must use FileIO plus lock flags to get locking. * Never uses kernel/fs-level lock, so naked open() bypasses locking. * Mandatory: * Requires kernel/fs-level, so naked open() respects lock. * Kernel/fs-level locks are available on ESX but not hosted. * Best: * Adaptively picks between mandatory and advisory. * Almost all cases should use the "best" lock. */ #define FILEIO_OPEN_LOCK_BEST FILEIO_OPEN_LOCKED /* historical */ #define FILEIO_OPEN_LOCK_ADVISORY (1 << 20) #define FILEIO_OPEN_LOCK_MANDATORY (1 << 21) /* * Flag passed to open() to enable use of swmr-reader locks on VMFS. This * definition must match USEROBJ_OPEN_SWMR_LOCK in user_vsiTypes.h. */ #define O_SWMR_LOCK (1 << 21) // 0x00200000 /* * OPTIMISTIC is an alternative to EXCLUSIVE and MANDATORY. It applies * only on ESX, and gives VMkernel permission to use a type of lock * called "optimistic" to speed up opens. A general guideline is to use it * only for read-only opens of small files (< 1KB). */ #define FILEIO_OPEN_OPTIMISTIC_LOCK (1 << 22) // 0x00400000 /* * Flag passed to open() to enable use of oplocks on VMFS. This definition * must match USEROBJ_OPEN_OPTIMISTIC_LOCK in user_vsiTypes.h. */ #define O_OPTIMISTIC_LOCK (1 << 22) // 0x00400000 /* * POSIX specific close the file descriptor when the program uses a variant * of the exec system call capability. This is useful in fork/exec scenarios. */ #define FILEIO_OPEN_CLOSE_ON_EXEC (1 << 23) // 0x00800000 /* * Flag passed to open() to not attempt to get the LUN attributes as part of * the open operation. Applicable only to opening of SCSI devices. This * definition must match the definition of USEROBJ_OPEN_NOATTR in * user_vsiTypes.h and FS_OPEN_NOATTR in fs_public.h */ #define O_NOATTR (1 << 26) // 0x04000000 /* * Flag passed to open() to get multiwriter VMFS lock. This definition must * match USEROBJ_OPEN_MULTIWRITER_LOCK in user_vsiTypes.h. */ #define O_MULTIWRITER_LOCK (1 << 27) // 0x08000000 /* * Flag passed to open() to get exclusive VMFS lock. This definition must * match USEROBJ_OPEN_EXCLUSIVE_LOCK in user_vsiTypes.h. */ #define O_EXCLUSIVE_LOCK (1 << 28) // 0x10000000 /* File Access check args */ #define FILEIO_ACCESS_READ (1 << 0) #define FILEIO_ACCESS_WRITE (1 << 1) #define FILEIO_ACCESS_EXEC (1 << 2) #define FILEIO_ACCESS_EXISTS (1 << 3) typedef enum { // File doesn't exist File exists FILEIO_OPEN, // error FILEIO_OPEN_EMPTY, // error size = 0 FILEIO_OPEN_CREATE, // create FILEIO_OPEN_CREATE_SAFE, // create error FILEIO_OPEN_CREATE_EMPTY, // create size = 0 } FileIOOpenAction; typedef enum { /* * Generic status codes */ /* No error */ FILEIO_SUCCESS, /* The user cancelled the operation */ FILEIO_CANCELLED, /* Generic error */ FILEIO_ERROR, /* * Status codes specific to FileIO_Open() */ /* FILEIO_OPEN_CREATE_SAFE was used and the file already existed */ FILEIO_OPEN_ERROR_EXIST, /* Couldn't obtain the requested lock */ FILEIO_LOCK_FAILED, /* Status codes specific to FileIO_Read() */ /* Tried to read beyond the end of a file */ FILEIO_READ_ERROR_EOF, /* Couldnt locate file */ FILEIO_FILE_NOT_FOUND, /* Insufficient Permissions */ FILEIO_NO_PERMISSION, /* File name too long */ FILEIO_FILE_NAME_TOO_LONG, /* * Status codes specific for FileIO_Write() */ /* Attempts to write file that exceeds maximum file size */ FILEIO_WRITE_ERROR_FBIG, /* The device containint the file has no room for the data */ FILEIO_WRITE_ERROR_NOSPC, /* Attempts to write file that exceeds user's disk quota */ FILEIO_WRITE_ERROR_DQUOT, /* * NB: Until disklib error handling is changed, there must be no more * than 16 total error codes here. */ FILEIO_ERROR_LAST, /* Must be last! */ } FileIOResult; #if defined(__APPLE__) typedef int (FileIOPrivilegedOpener)(const char *path, int flags); #endif const char *FileIO_MsgError(FileIOResult status); void FileIO_Invalidate(FileIODescriptor *file); Bool FileIO_IsValid(const FileIODescriptor *fd); FileIOResult FileIO_Create(FileIODescriptor *file, const char *pathName, int access, FileIOOpenAction action, int mode); FileIOResult FileIO_CreateRetry(FileIODescriptor *file, const char *pathName, int access, FileIOOpenAction action, int mode, uint32 maxWaitTimeMsec); FileIOResult FileIO_Open(FileIODescriptor *file, const char *pathName, int access, FileIOOpenAction action); FileIOResult FileIO_OpenRetry(FileIODescriptor *file, const char *pathName, int access, FileIOOpenAction action, uint32 maxWaitTimeMsec); uint64 FileIO_Seek(const FileIODescriptor *file, int64 distance, FileIOSeekOrigin origin); FileIOResult FileIO_Read(FileIODescriptor *file, void *buf, size_t requested, size_t *actual); FileIOResult FileIO_Write(FileIODescriptor *file, const void *buf, size_t requested, size_t *actual); char *FileIO_AtomicTempPath(const char *path); FileIOResult FileIO_AtomicTempFile(FileIODescriptor *fileFD, FileIODescriptor *tempFD); Bool FileIO_AtomicUpdate(FileIODescriptor *newFD, FileIODescriptor *currFD); int FileIO_AtomicUpdateEx(FileIODescriptor *newFD, FileIODescriptor *currFD, Bool renameOnNFS); #if !defined(VMX86_TOOLS) || !defined(__FreeBSD__) FileIOResult FileIO_Readv(FileIODescriptor *fd, struct iovec const *v, int count, size_t totalSize, size_t *bytesRead); FileIOResult FileIO_Writev(FileIODescriptor *fd, struct iovec const *v, int count, size_t totalSize, size_t *bytesWritten); #endif FileIOResult FileIO_Preadv( FileIODescriptor *fd, // IN: File descriptor struct iovec const *entries, // IN: Vector to read into int numEntries, // IN: Number of vector entries uint64 offset, // IN: Offset to start reading size_t totalSize, // IN: totalSize (bytes) in entries size_t *actual); // OUT: number of bytes read FileIOResult FileIO_Pwritev( FileIODescriptor *fd, // IN: File descriptor struct iovec const *entries, // IN: Vector to write from int numEntries, // IN: Number of vector entries uint64 offset, // IN: Offset to start writing size_t totalSize, // IN: Total size (bytes) in entries size_t *actual); // OUT: number of bytes written FileIOResult FileIO_Pread( FileIODescriptor *fd, // IN: File descriptor void *buf, // IN: Buffer to read into size_t len, // IN: Length of the buffer uint64 offset); // IN: Offset to start reading FileIOResult FileIO_Pwrite( FileIODescriptor *fd, // IN: File descriptor void const *buf, // IN: Buffer to write from size_t len, // IN: Length of the buffer uint64 offset); // IN: Offset to start writing FileIOResult FileIO_Access(const char *pathName, int accessMode); Bool FileIO_Truncate(FileIODescriptor *file, uint64 newSize); FileIOResult FileIO_Sync(const FileIODescriptor *file); FileIOResult FileIO_GetAllocSize(const FileIODescriptor *fd, uint64 *logicalBytes, uint64 *allocedBytes); int64 FileIO_GetSize(const FileIODescriptor *fd); Bool FileIO_SetAllocSize(const FileIODescriptor *fd, uint64 size); FileIOResult FileIO_GetAllocSizeByPath(const char *pathName, uint64 *logicalBytes, uint64 *allocedBytes); int64 FileIO_GetSizeByPath(const char *pathName); FileIOResult FileIO_Close(FileIODescriptor *file); FileIOResult FileIO_CloseAndUnlink(FileIODescriptor *file); uint32 FileIO_GetFlags(FileIODescriptor *file); #if defined(_WIN32) Bool FileIO_GetVolumeSectorSize(const char *name, uint32 *sectorSize); #endif Bool FileIO_SupportsFileSize(const FileIODescriptor *file, uint64 testSize); int64 FileIO_GetModTime(const FileIODescriptor *fd); FileIOResult FileIO_Lock(FileIODescriptor *file, int access); FileIOResult FileIO_Unlock(FileIODescriptor *file); /* Only users not using FileIO_Open should use these two */ void FileIO_Init(FileIODescriptor *fd, const char *pathName); void FileIO_Cleanup(FileIODescriptor *fd); const char *FileIO_ErrorEnglish(FileIOResult status); void FileIO_OptionalSafeInitialize(void); #if defined(_WIN32) FileIODescriptor FileIO_CreateFDWin32(HANDLE win32, DWORD access, DWORD attributes); #else FileIODescriptor FileIO_CreateFDPosix(int posix, int flags); int FileIO_PrivilegedPosixOpen(const char *pathName, int flags); #endif FILE *FileIO_DescriptorToStream(FileIODescriptor *fd, Bool textMode); const char *FileIO_Filename(FileIODescriptor *fd); #ifdef VMX86_SERVER FileIOResult FileIO_CreateDeviceFileNoPrompt(FileIODescriptor *fd, const char *pathName, int openMode, FileIOOpenAction action, int perms, const char *device); #endif /* *------------------------------------------------------------------------- * * FileIO_IsSuccess -- * * Returns TRUE if the error code is success. * * Result: * TRUE/FALSE. * * Side effects: * None. * *------------------------------------------------------------------------- */ static INLINE Bool FileIO_IsSuccess(FileIOResult res) // IN { return res == FILEIO_SUCCESS; } Bool FileIO_SupportsPrealloc(const char *pathName, Bool fsCheck); #if defined(__APPLE__) void FileIO_SetPrivilegedOpener(FileIOPrivilegedOpener *opener); #endif #if defined(__cplusplus) } // extern "C" #endif #endif // _FILEIO_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/fileLock.h000066400000000000000000000050221470176644300244120ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * fileLock.h -- * * Interface to file locking functions */ #ifndef _FILELOCK_H_ #define _FILELOCK_H_ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #include "unicodeTypes.h" #include "msgList.h" #if defined(__cplusplus) extern "C" { #endif /* The default time, in milliseconds, to wait for a lock before giving up */ #define FILELOCK_DEFAULT_WAIT (vmx86_server ? 7000 : 3500) /* The wait time that provides "try lock" functionality */ #define FILELOCK_TRYLOCK_WAIT 0 /* Wait "forever" to acquire the lock (maximum uint32) */ #define FILELOCK_INFINITE_WAIT 0xFFFFFFFF /* * This is the maximum path length overhead that the file locking code * may introduce via all of its components. */ #define FILELOCK_OVERHEAD 15 /* File locking functions */ typedef struct FileLockToken FileLockToken; char *FileLock_TokenPathName(const FileLockToken *fileLockToken); FileLockToken *FileLock_Lock(const char *filePath, const Bool readOnly, const uint32 maxWaitTimeMsec, int *err, MsgList **msgs); Bool FileLock_Unlock(const FileLockToken *lockToken, int *err, MsgList **msgs); Bool FileLock_IsLocked(const char *filePath, int *err, MsgList **msgs); Bool FileLock_Remove(const char *filePath, int *err, MsgList **msgs); Bool FileLock_CleanupVM(const char *cfgfilePath, int *err, MsgList **msgs); #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _FILELOCK_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/file_extensions.h000066400000000000000000000100621470176644300260600ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016, 2020-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _FILE_EXTENSIONS_H_ #define _FILE_EXTENSIONS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" /* * Virtual disk and related file types. */ #define DISK_FILE_EXTENSION "vmdk" #define REDO_FILE_EXTENSION "REDO" #define SWAP_FILE_EXTENSION "vswp" /* * VM configuration and related file types. */ #define CONFIG_FILE_EXTENSION "vmx" // VM configuration file #define CONFIG_ALT_FILE_EXTENSION "cfg" // Obsolete synonym for .vmx #define EXTENDED_CONFIG_FILE_EXTENSION "vmxf" // Foundry metadata #define MANAGED_CONFIG_FILE_EXTENSION "vmxa" // ACE Top Level #define VRM_CONFIG_FILE_EXTENSION "vmx" // ACE Instance #define VPX_TEMPLATE_EXTENSION "vmtx" // VirtualCenter template #define TEAM_FILE_EXTENSION "vmtm" // Foundry VM team #define POLICY_FILE_EXTENSION "vmpl" // ACE/VRM policy file #define BUNDLE_FILE_EXTENSION "vmwarevm" // VM configuration bundle directory #define SIDECAR_FILE_EXTENSION "vmfd" // Virtual machine filter data aka sidecar #define HBRPERSIST_FILE_EXTENSION "psf" // HBR/VR persistent state file /* * Snapshot and related file types. */ #define MAINMEM_FILE_EXTENSION "vmem" #define SUSPEND_FILE_EXTENSION "vmss" #define CHECKPOINT_FILE_EXTENSION "vmsn" #define VPLAY_FILE_EXTENSION "vmlog" #define SNAPSHOT_METADATA_EXTENSION "vmsd" #define CHECKPOINT_FILE_EXTENSION_OLD "cpt" // Obsolete synonym for vmsn /* * Foundry scripts. */ #define VIX_ACTION_FILE_EXTENSION "vmac" // Foundry action #define VIX_BATCH_FILE_EXTENSION "vmba" // Foundry batch script /* * ACE/VRM management transit files. */ #define VRM_HOTFIXREQ_FILE_EXTENSION "vmhr" // ACE hotfix request #define VRM_HOTFIX_FILE_EXTENSION "vmhf" // ACE hotfix response /* * VM Download. */ #define RVM_DOWNLOAD_FILE_EXTENSION "vmdownload" // Downloaded file #define RVM_STATE_FILE_EXTENSION "vmstate" // Download metadata #define DOWNLOAD_BUNDLE_FILE_EXTENSION "vmdownload" // VM download bundle directory /* * Other file types. */ #define SCREENSHOT_EXTENSION "png" #define NVRAM_EXTENSION "nvram" #define LOCK_FILE_EXTENSION "lck" #define VIRTUALPC_EXTENSION "vmc" #define SYMANTEC_LIVESTATE_EXTENSION "sv2i" #define STORAGECRAFT_SHADOWSTOR_EXTENSION "spf" #define ACRONIS_EXTENSION "tib" #define OPEN_VM_FORMAT_EXTENSION "ovf" #define ARCHIVED_OPEN_VM_FORMAT_EXTENSION "ova" #define NAMESPACEDB_EXTENSION "db" #define DATASETSSTORE_DISKMODE_EXTENSION "dsd" #define DATASETSSTORE_VMMODE_EXTENSION "dsv" // "xvm" // VMware console configuration file /* * Extensions repeated with leading period. * Moved from bora/public/dumper.h. */ #define STDPATH_EXT "." SUSPEND_FILE_EXTENSION #define CPTPATH_EXT "." CHECKPOINT_FILE_EXTENSION #define CPTPATH_EXT_OLD "." CHECKPOINT_FILE_EXTENSION_OLD #define CONFIG_EXT "." CONFIG_FILE_EXTENSION #define CONFIG_EXT_ALT "." CONFIG_ALT_FILE_EXTENSION #define CONFIG_EXT_MGD "." MANAGED_CONFIG_FILE_EXTENSION #define CONFIG_EXT_TEAM "." TEAM_FILE_EXTENSION #define VPX_TEMPL_EXT "." VPX_TEMPLATE_EXTENSION #define SCREENSHOT_EXT "." SCREENSHOT_EXTENSION #define SWAPPATH_EXT "." SWAP_FILE_EXTENSION #endif /* _FILE_EXTENSIONS_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/ghIntegrationCommon.h000066400000000000000000000247371470176644300266530ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2008-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * ghIntegrationCommon.h -- * * Common data structures and definitions used by Guest/Host Integration. */ #ifndef _GHINTEGRATIONCOMMON_H_ #define _GHINTEGRATIONCOMMON_H_ /* * Common data structures and definitions used by Guest/Host Integration. */ #define GHI_HGFS_SHARE_URL_SCHEME_UTF8 "x-vmware-share" #define GHI_HGFS_SHARE_URL_UTF8 "x-vmware-share://" #define GHI_HGFS_SHARE_URL _T(GHI_HGFS_SHARE_URL_UTF8) /* * Messages over different channels will be handled by * different modules. */ #define GHI_CHANNEL_TOOLS_USER 0 // Handled by tools module // in local VM (TOOLS_DND_NAME guestRPC) // or by VDPUnityMKSControl module // in View RMKS #define GHI_CHANNEL_TOOLS_MAIN 1 // Handled by tools module // in local VM (TOOLS_DAEMON_NAME guestRPC) #define GHI_CHANNEL_VIEW_REMOTE_SHARED_FOLDER 2 // VDPSharedFolderMgrMKSControl module // in View RMKS #define GHI_CHANNEL_DND 3 // DnD for both local VM and View RMKS. #define GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON 4 // VDPRdeCommonMKSControl module // in View RMKS #define GHI_CHANNEL_VIEW_USB_REDIRECTION 5 // VDPUsbRedirectionMKSControl module in // View RMKS #define GHI_CHANNEL_VIEW_REMOTE_VDP_COMMON 6 // Handled by View VDP core module #define GHI_CHANNEL_VIEW_PROTOCOL 7 // Interactions with different protocols // in View RMKS #define GHI_CHANNEL_FCP 8 // FCP for View RMKS #define GHI_CHANNEL_VIEW_SDR 9 // Handled by View SDR #define GHI_CHANNEL_VIEW_WHFB_REDIRECTION 10 // WhfbRedirectionMKSControl module in // View RMKS #define GHI_CHANNEL_VIEW_SCREEN_CAPTURE 11 // ScreenCapture in View RMKS #define GHI_CHANNEL_COUNT 12 typedef uint32 GHIChannelType; #define GHI_REQUEST_SUCCESS_OK 0 // Guest received the message and returned OK. #define GHI_REQUEST_SUCCESS_ERROR 1 // Guest received the message but returned ERROR. #define GHI_REQUEST_GUEST_RPC_FAILED 2 // Not sent to guest // or guest failed to return, // including timeout. #define GHI_REQUEST_GENERAL_ERROR 3 // General error, can be guest error // or prc error. #define GHI_REQUEST_FAILED_WITH_UTF8_MESSAGE 4 // Failed and with utf8 error message returned. typedef uint32 GHIRequestResult; #define GHI_GUEST_CHANNEL_BITS(channel) ((channel) << 24) #define GHI_GUEST_GET_MSG_CHANNEL(msg) (((msg) >> 24) & 0xff) typedef uint32 GHIGuestToHostMessageType; /* * MKS->UI messages over GHI_CHANNEL_VIEW_REMOTE_SHARED_FOLDER. * * Only for View product. */ #define GHI_CHANNEL_VIEW_REMOTE_SHARED_FOLDER_BITS \ GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_VIEW_REMOTE_SHARED_FOLDER) #define GHI_GUEST_RDPDR_CAP (GHI_CHANNEL_VIEW_REMOTE_SHARED_FOLDER_BITS | 0x000001) /* * UI->MKS Messages over GHI_CHANNEL_DND. */ #define GHI_DND_DND_HOST_GUEST_CMD "ghi.dnd.dnd.hostguest" #define GHI_DND_COPYPASTE_HOST_GUEST_CMD "ghi.dnd.copypaste.hostguest" #define GHI_DND_HOST_SHAKEHAND_CMD "ghi.dnd.shakehand" #define GHI_DND_HOST_GETFILES_CMD "ghi.dnd.host.getfiles" #define GHI_DND_HOST_GETFILES_ANSWER_OVERWRITE "ghi.dnd.host.getfiles.answer.overwrite" #define GHI_DND_HOST_SENDFILES_CMD "ghi.dnd.host.sendfiles" #define GHI_DND_HOST_TRANSFERFILES_CANCEL_CMD "ghi.dnd.host.transferfiles.cancel" #define GHI_DND_HOST_ADDBLOCK_CMD "ghi.dnd.host.addblock" #define GHI_DND_HOST_REMOVEBLOCK_CMD "ghi.dnd.host.removeblock" /* * Results of UI->MKS Messages over GHI_CHANNEL_DND. */ #define GHI_DND_GUEST_RET_MAX_LEN 64 #define GHI_DND_GUEST_RET_ERROR "error" #define GHI_DND_GUEST_RET_INPROGRESS "inProgress" #define GHI_DND_GUEST_RET_DONE "done" /* * MKS->UI messages over GHI_CHANNEL_DND. */ #define GHI_CHANNEL_DND_BITS GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_DND) #define GHI_GUEST_DND_DND_CMD (GHI_CHANNEL_DND_BITS | 0x000001) #define GHI_GUEST_DND_COPYPASTE_CMD (GHI_CHANNEL_DND_BITS | 0x000002) #define GHI_GUEST_DND_NOTIFY_BLOCKROOT (GHI_CHANNEL_DND_BITS | 0x000003) #define GHI_GUEST_DND_TRANSFERFILES_PROGRESS (GHI_CHANNEL_DND_BITS | 0x000004) #define GHI_GUEST_DND_GETFILE_OVERWRITE_QUESTION (GHI_CHANNEL_DND_BITS | 0x000005) #define GHI_GUEST_DND_CAPABILITY (GHI_CHANNEL_DND_BITS | 0x000006) /* * UI->MKS Messages over GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON. */ #define GHI_RDE_COMMON_GENERIC_CMD "ghi.rde.generic" #define GHI_RDE_COMMON_SET_IME_ENABLED_CMD "ghi.rde.set.ime.enabled" #define GHI_RDE_COMMON_SET_IME_HOST_KEYS_CMD "ghi.rde.set.ime.host.keys" /* * MKS->UI messages over GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON. */ #define GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON_BITS \ GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON) #define GHI_GUEST_RDE_COMMON_HOST_SET_DPI \ (GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON_BITS | 0x000001) #define GHI_GUEST_RDE_COMMON_UNLOCK_DESKTOP \ (GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON_BITS | 0x000002) #define GHI_GUEST_RDE_COMMON_CLIPBOARD_DATA_SENT_DONE \ (GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON_BITS | 0x000003) #define GHI_GUEST_RDE_COMMON_GENERIC \ (GHI_CHANNEL_VIEW_REMOTE_RDE_COMMON_BITS | 0x000004) /* * MKS->UI messages over GHI_CHANNEL_VIEW_USB_REDIRECTION. */ #define GHI_CHANNEL_VIEW_USB_REDIRECTION_BITS \ GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_VIEW_USB_REDIRECTION) #define GHI_GUEST_USB_REDIRECTION_USB_INSTANCE_ID \ (GHI_CHANNEL_VIEW_USB_REDIRECTION_BITS | 0x000001) #define GHI_GUEST_USB_REDIRECTION_DEVICES_FILTER_STATUS \ (GHI_CHANNEL_VIEW_USB_REDIRECTION_BITS | 0x000002) /* * UI->MKS messages over GHI_CHANNEL_VIEW_USB_REDIRECTION. */ #define GHI_HOST_USB_REDIRECTION_STARTUSBD_CMD "ghi.usb.redirection.startusbd" /* * UI->MKS messages over GHI_CHANNEL_VIEW_PROTOCOL. */ #define GHI_SET_BUFFER_WITHOUT_AUDIO_CMD \ "ghi.view.protocol.set.buffer.without.audio" /* * MKS->UI messages over GHI_CHANNEL_FCP, used by View FCP. */ #define GHI_CHANNEL_FCP_BITS GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_FCP) #define GHI_GUEST_FCP_TRANSFERFILES_PROGRESS (GHI_CHANNEL_FCP_BITS | 0x000001) /* * UI->MKS Messages over GHI_CHANNEL_FCP, used by View FCP. */ #define GHI_FCP_HOST_TRANSFERFILES_CANCEL_CMD "ghi.fcp.host.transferfiles.cancel" /* * MKS->UI messages over GHI_CHANNEL_VIEW_REMOTE_VDP_COMMON. */ #define GHI_CHANNEL_VIEW_REMOTE_VDP_COMMON_BITS \ GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_VIEW_REMOTE_VDP_COMMON) #define GHI_GUEST_VDP_COMMON_CAP_FEATURES \ (GHI_CHANNEL_VIEW_REMOTE_VDP_COMMON_BITS | 0x000001) #define GHI_GUEST_VDP_COMMON_CAP_RECEIVED \ (GHI_CHANNEL_VIEW_REMOTE_VDP_COMMON_BITS | 0x000002) /* * UI->MKS messages over GHI_CHANNEL_VIEW_REMOTE_VDP_COMMON. */ #define GHI_HOST_VDP_COMMON_SYNC_GUEST_LEDS_CMD "ghi.mks.common.sync.guest.leds" #define GHI_HOST_VDP_COMMON_GET_GUEST_CAPS_CMD "ghi.mks.common.get.guest.caps" /* * MKS->UI messages over GHI_CHANNEL_VIEW_WHFB_REDIRECTION */ #define GHI_CHANNEL_VIEW_WHFB_REDIRECTION_BITS \ GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_VIEW_WHFB_REDIRECTION) #define GHI_GUEST_WHFB_REDIRECTION_UNLOCK_REQUEST \ (GHI_CHANNEL_VIEW_WHFB_REDIRECTION_BITS | 0x000001) /* * UI->MKS messages over GHI_CHANNEL_VIEW_WHFB_REDIRECTION. */ #define GHI_WHFB_REDIRECTION_SET_SESSIONPIN_CMD "ghi.whfb.set.sessionpin" #define GHI_WHFB_REDIRECTION_SET_USERVERIFICATIONRESULT_CMD "ghi.whfb.set.userverificationresult" /* * Capabilities for the message GHI_GUEST_VDP_COMMON_CAP_FEATURES */ typedef enum { VDP_COMMON_SET_KEYBOARD_STATE_CAP = 0, VDP_COMMON_CAP_ITEM_COUNT } VDPCommonCapType; /* * UI->MKS messages over GHI_CHANNEL_VIEW_SDR */ #define GHI_VIEW_SDR_ADD_DRIVE "ghi.view.sdr.add.drive" #define GHI_VIEW_SDR_REMOVE_DRIVE "ghi.view.sdr.remove.drive" /* * MKS->UI messages over GHI_CHANNEL_VIEW_SDR. */ #define GHI_CHANNEL_VIEW_SDR_BITS GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_VIEW_SDR) #define GHI_VIEW_SDR_VDP_CONNECTED (GHI_CHANNEL_VIEW_SDR_BITS | 0x000001) #define GHI_VIEW_SDR_VDP_DISCONNECTED (GHI_CHANNEL_VIEW_SDR_BITS | 0x000002) #define GHI_VIEW_SDR_VDP_SDRPOLICY (GHI_CHANNEL_VIEW_SDR_BITS | 0x000003) /* * UI->MKS messages over GHI_CHANNEL_VIEW_SCREEN_CAPTURE */ #define GHI_VIEW_SCREEN_CAPTURE_TAKE_SNAPSHOT "ghi.view.screen.capture.take.snapshot" #define GHI_VIEW_SCREEN_CAPTURE_ENUM_TOPOLOGY "ghi.view.screen.capture.enum.topology" /* * MKS->UI messages over GHI_CHANNEL_VIEW_SCREEN_CAPTURE. */ #define GHI_CHANNEL_VIEW_SCREEN_CAPTURE_BITS \ GHI_GUEST_CHANNEL_BITS(GHI_CHANNEL_VIEW_SCREEN_CAPTURE) #define GHI_GUEST_SCREEN_CAPTURE_FUNC_READY (GHI_CHANNEL_VIEW_SCREEN_CAPTURE_BITS | 0x000001) #define GHI_GUEST_SCREEN_CAPTURE_TOPOLOGY (GHI_CHANNEL_VIEW_SCREEN_CAPTURE_BITS | 0x000002) #endif // ifndef _GHINTEGRATIONCOMMON_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/glibUtils.h000066400000000000000000000053671470176644300246340ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2011-2017,2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _GLIBUTILS_H_ #define _GLIBUTILS_H_ #if defined(__cplusplus) extern "C" { #endif /** * @file glibUtils.h * * A collection of utility functions that depend only on glib. * * These functions are guaranteed to have no dependencies on bora/lib libraries * or headers. */ #include #if defined(_WIN32) # include #endif /** * @brief Description for a logger. * * Contains information about a logger. The properties here are aimed at * helping the logging code using this library to construct and appropriate * log message depending on the output being used. * * For example, some sinks (like syslog) already add a timestamp to every log * message. So if the @a addsTimestamp field is TRUE, the logging code can * choose to rely on that and not add a redundant timestamp field to the log * message. */ typedef struct GlibLogger { gboolean shared; /**< Output is shared with other processes. */ gboolean addsTimestamp; /**< Output adds timestamp automatically. */ GLogFunc logfn; /**< The function that writes to the output. */ GDestroyNotify dtor; /**< Destructor. */ gboolean logHeader; /**< Header needs to be logged. */ } GlibLogger; GlibLogger * GlibUtils_CreateFileLogger(const char *path, gboolean append, guint maxSize, guint maxFiles); GlibLogger * GlibUtils_CreateStdLogger(void); #if defined(_WIN32) gboolean GlibUtils_AttachConsole(void); GlibLogger * GlibUtils_CreateDebugLogger(void); GlibLogger * GlibUtils_CreateEventLogger(const wchar_t *source, DWORD eventId); #else GlibLogger * GlibUtils_CreateSysLogger(const char *domain, const char *facility); #endif #if defined(__cplusplus) } // extern "C" #endif #endif /* _GLIBUTILS_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/globalConfig.h000066400000000000000000000033211470176644300252500ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2020-2021,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _GLOBAL_CONFIG_H_ #define _GLOBAL_CONFIG_H_ #if (defined(_WIN32) && !defined(_ARM64_)) || \ (defined(__linux__) && !defined(USERWORLD)) #define GLOBALCONFIG_SUPPORTED 1 #include "vmware/tools/plugin.h" #include #include "guestStoreClient.h" /** * @file globalConfig.h * * Interface of the module to fetch the tools.conf file from GuestStore. */ gboolean GlobalConfig_Start(ToolsAppCtx *ctx); gboolean GlobalConfig_LoadConfig(GKeyFile **config, time_t *mtime); gboolean GlobalConfig_GetEnabled(GKeyFile *conf); void GlobalConfig_SetEnabled(gboolean enabled, GKeyFile *conf); gboolean GlobalConfig_DeleteConfig(void); GuestStoreClientError GlobalConfig_DownloadConfig(GKeyFile *config); #else #undef GLOBALCONFIG_SUPPORTED #endif #endif /* _GLOBAL_CONFIG_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guestApp.h000066400000000000000000000025651470176644300244630ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * guestApp.h -- * * Utility functions common to all guest applications */ #ifndef __GUESTAPP_H__ # define __GUESTAPP_H__ #include "vm_basic_types.h" #if defined(_WIN32) #include #endif #ifdef __cplusplus extern "C" { #endif const char * GuestApp_GetDefaultScript(const char *confName); // IN #ifdef _WIN32 LPWSTR GuestApp_GetInstallPathW(void); #endif char * GuestApp_GetInstallPath(void); char * GuestApp_GetConfPath(void); #ifdef __cplusplus } #endif #endif /* __GUESTAPP_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guestInfo.h000066400000000000000000000071321470176644300246310ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /** * @file guestInfo.h * * Common declarations that aid in sending guest information to the host. */ /** * @defgroup vmtools_guestInfoAPI GuestInfo API Reference * @{ * * @brief APIs implementing the GuestInfo feature. * * Definitions below are used for communication across the backdoor between * the VMware Tools Service (running in the guest) and the VMX (running in * the host). * * @sa @ref vmtools_guestInfo for a high level overview. */ #ifndef _GUEST_INFO_H_ #define _GUEST_INFO_H_ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #include "vm_basic_types.h" #include "dbllnklst.h" #include "guestrpc/nicinfo.h" #define GUEST_INFO_COMMAND "SetGuestInfo" #define GUEST_DISK_INFO_COMMAND "SetGuestDiskInfo" #define MAX_VALUE_LEN 100 #define MAX_NICS 16 #define MAX_IPS 8 // Max number of IP addresses for a single NIC #define INFO_IPADDRESS_V2_MAX_IPS 64 #define MAC_ADDR_SIZE 19 #define IP_ADDR_SIZE 16 #define PARTITION_NAME_SIZE MAX_VALUE_LEN #define FSTYPE_SIZE 260 // Windows fs types can be up to MAX_PATH chars #define DISK_DEVICE_NAME_SIZE 15 // Max size for disk device name - scsi?:? /* Value to be used when "primary" IP address is indeterminable. */ #define GUESTINFO_IP_UNKNOWN "unknown" typedef enum { INFO_ERROR, /* Zero is unused so that errors in atoi can be caught. */ INFO_DNS_NAME, INFO_IPADDRESS, INFO_DISK_FREE_SPACE, INFO_BUILD_NUMBER, INFO_OS_NAME_FULL, INFO_OS_NAME, INFO_UPTIME, INFO_MEMORY, INFO_IPADDRESS_V2, INFO_IPADDRESS_V3, INFO_OS_DETAILED, INFO_MAX } GuestInfoType; typedef enum { INFO_IP_ADDRESS_FAMILY_IPV4, INFO_IP_ADDRESS_FAMILY_IPV6 } GuestInfoIPAddressFamilyType; typedef struct NicEntryV1 { unsigned int numIPs; char macAddress[MAC_ADDR_SIZE]; // In the format "12-23-34-45-56-67" char ipAddress[MAX_IPS][IP_ADDR_SIZE]; } NicEntryV1; typedef struct GuestNicInfoV1 { unsigned int numNicEntries; NicEntryV1 nicList[MAX_NICS]; } GuestNicInfoV1; #pragma pack(push, 1) typedef struct _PartitionEntry { uint64 freeBytes; uint64 totalBytes; char name[PARTITION_NAME_SIZE]; } PartitionEntry, *PPartitionEntry; #pragma pack(pop) typedef struct _DiskInfo { unsigned int numEntries; PPartitionEntry partitionList; } GuestDiskInfo, *PGuestDiskInfo; #define DISK_INFO_VERSION_1 1 /* Disk info json keys */ #define DISK_INFO_KEY_VERSION "version" #define DISK_INFO_KEY_DISKS "disks" #define DISK_INFO_KEY_DISK_NAME "name" #define DISK_INFO_KEY_DISK_FREE "free" #define DISK_INFO_KEY_DISK_SIZE "size" #define DISK_INFO_KEY_DISK_UUID "uuid" #define DISK_INFO_KEY_DISK_FSTYPE "fstype" #define DISK_INFO_KEY_DISK_DEVICE_ARR "devices" /** * @} */ #endif // _GUEST_INFO_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guestStats.h000066400000000000000000000410731470176644300250360ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2018,2020-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /** * @file guestStats.h * * Common declarations that aid in sending guest statistics to the vmx * and may be further to vmkernel. */ #ifndef _GUEST_STATS_H_ #define _GUEST_STATS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "vm_assert.h" #include "vm_basic_types.h" #define PUBLISH_EXPERIMENTAL_STATS 0 #define ADD_NEW_STATS 0 /* * Version 1: Legacy data * Version 2: Dead * Version 3: Dead * Version 4: Dead * Version 5: Legacy structure followed by one or more GuestStat * structures and data. */ #define GUESTMEMINFO_V1 1 #define GUESTMEMINFO_V2 2 #define GUESTMEMINFO_V3 3 #define GUESTMEMINFO_V4 4 #define GUESTMEMINFO_V5 5 /* * Flags for GuestMemInfoLegacy * * !!! DON'T ADD/CHANGE FLAGS !!! * * This is deprecated. All new values are returned via a GuestStat list. */ #define MEMINFO_MEMTOTAL (1 << 0) #define MEMINFO_DEPRECATED1 (1 << 1) #define MEMINFO_DEPRECATED2 (1 << 2) #define MEMINFO_DEPRECATED3 (1 << 3) #define MEMINFO_DEPRECATED4 (1 << 4) #define MEMINFO_DEPRECATED5 (1 << 5) #define MEMINFO_DEPRECATED6 (1 << 6) #define MEMINFO_DEPRECATED7 (1 << 7) #define MEMINFO_DEPRECATED8 (1 << 8) #define MEMINFO_DEPRECATED9 (1 << 9) #define MEMINFO_HUGEPAGESTOTAL (1 << 10) #define MEMINFO_DEPRECATED10 (1 << 11) #define MEMINFO_DEPRECATED11 (1 << 12) #define MEMINFO_MEMNEEDED (1 << 13) /* * Legacy GuestMemInfo structure. * * !!! DON'T CHANGE IT !!! * * It should stay the same to ensure binary compatibility. */ #pragma pack(push, 1) typedef struct GuestMemInfoLegacy { uint32 version; ///< MemInfo structure version. uint32 flags; ///< Indicates which stats are valid. uint64 memTotal; ///< Total physical memory in Kb. uint64 deprecated1[9]; ///< No longer used. uint64 hugePagesTotal; ///< Total number of huge pages. uint64 deprecated2[2]; ///< No longer used. } GuestMemInfoLegacy; #pragma pack(pop) /* * A stat begins with a header. The header has a mask which says what data * follows. Each datum has a size field which says how much data follows so it * can be used or ignored. The order of the data that follows is that of the * bits, lowest order bit to highest. */ typedef enum { GUEST_DATUM_PRAGMA = 0x0001, // escape hatch (future expansion) GUEST_DATUM_NAMESPACE = 0x0002, // UTF8 string GUEST_DATUM_ID = 0x0004, // uint8 - uint64 GUEST_DATUM_VALUE_TYPE_ENUM = 0x0008, // uint8 - uint32 GUEST_DATUM_VALUE_TYPE_STRING = 0x0010, // UTF8 string GUEST_DATUM_VALUE_UNIT_ENUM = 0x0020, // uint8 - uint32 GUEST_DATUM_VALUE_UNIT_STRING = 0x0040, // UTF8 string GUEST_DATUM_VALUE = 0x0080, // value data } GuestDatum; #pragma pack(push, 1) typedef struct GuestStatHeader { GuestDatum datumFlags; // Indicates how many and which data follow } GuestStatHeader; #pragma pack(pop) #ifdef _MSC_VER #pragma warning (disable :4200) // non-std extension: zero-sized array in struct #endif #pragma pack(push, 1) typedef struct GuestDatumHeader { uint16 dataSize; // dataSize - May be zero char data[0]; // data - if dataSize is not zero. } GuestDatumHeader; #pragma pack(pop) /* * Units datum enum. * Note: The entirety (all bits) of the units must always be understood by a client. * * First we define some modifiers, then the enum itself * * bits 0-5 define base types (information, time, etc.) * bits 6-10 are modifiers, four of which are reserved (in the future, we could * define two of them as custom modifiers, for things like changing the radix from 2^10 * to 10^3 for storage, or for denoting rates are in 100ns units). */ #define GuestUnitsModifier_Rate 0x0040 #define GuestUnitsModifier_Reserved0 0x0080 #define GuestUnitsModifier_Reserved1 0x0100 #define GuestUnitsModifier_Reserved2 0x0200 #define GuestUnitsModifier_Reserved3 0x0400 /* * bits 11-15 are scale modifiers: * This includes common scales: (P)ositive powers, (N)egative powers, * and (C)ustom scales (bits, pages, etc.), which are always type specific. */ #define GuestUnitsScale_P0 0x0000 #define GuestUnitsScale_P1 0x0800 #define GuestUnitsScale_P2 0x1000 #define GuestUnitsScale_P3 0x1800 #define GuestUnitsScale_P4 0x2000 #define GuestUnitsScale_P5 0x2800 #define GuestUnitsScale_P6 0x3000 #define GuestUnitsScale_Reserved0 0x3800 #define GuestUnitsScale_N1 0x4000 #define GuestUnitsScale_N2 0x4800 #define GuestUnitsScale_N3 0x5000 #define GuestUnitsScale_N4 0x5800 #define GuestUnitsScale_N5 0x6000 #define GuestUnitsScale_N6 0x6800 #define GuestUnitsScale_Reserved1 0x7000 #define GuestUnitsScale_Reserved2 0x7800 #define GuestUnitsScale_C0 0x8000 #define GuestUnitsScale_C1 0x8800 #define GuestUnitsScale_C2 0x9000 #define GuestUnitsScale_C3 0x9800 // 0xA000-0xF800 are reserved. typedef enum { GuestUnitsInvalid = 0, // Must never be sent GuestUnitsNone = 1, // A valid value, but not any of the below units. GuestUnitsNumber = 2, // default radix is 1000 GuestUnitsInformation = 3, // default radix is 1024 GuestUnitsDuration = 4, // default radix is 1000 GuestUnitsCycles = 5, // default radix is 1000 GuestUnitsBytes = GuestUnitsInformation | GuestUnitsScale_P0, GuestUnitsKiB = GuestUnitsInformation | GuestUnitsScale_P1, GuestUnitsMiB = GuestUnitsInformation | GuestUnitsScale_P2, GuestUnitsPages = GuestUnitsInformation | GuestUnitsScale_C0, GuestUnitsHugePages = GuestUnitsInformation | GuestUnitsScale_C1, GuestUnitsBytesPerSecond = GuestUnitsBytes | GuestUnitsModifier_Rate, GuestUnitsKiBPerSecond = GuestUnitsKiB | GuestUnitsModifier_Rate, GuestUnitsMiBPerSecond = GuestUnitsMiB | GuestUnitsModifier_Rate, GuestUnitsPagesPerSecond = GuestUnitsPages | GuestUnitsModifier_Rate, GuestUnitsHugePagesPerSecond = GuestUnitsHugePages | GuestUnitsModifier_Rate, GuestUnitsAttoSeconds = GuestUnitsDuration | GuestUnitsScale_N6, GuestUnitsFemtoSeconds = GuestUnitsDuration | GuestUnitsScale_N5, GuestUnitsPicoSeconds = GuestUnitsDuration | GuestUnitsScale_N4, GuestUnitsNanoSeconds = GuestUnitsDuration | GuestUnitsScale_N3, GuestUnitsMicroSeconds = GuestUnitsDuration | GuestUnitsScale_N2, GuestUnitsMilliSeconds = GuestUnitsDuration | GuestUnitsScale_N1, GuestUnitsSeconds = GuestUnitsDuration | GuestUnitsScale_P0, GuestUnitsHz = GuestUnitsCycles | GuestUnitsScale_P0 | GuestUnitsModifier_Rate, GuestUnitsKiloHz = GuestUnitsCycles | GuestUnitsScale_P1 | GuestUnitsModifier_Rate, GuestUnitsMegaHz = GuestUnitsCycles | GuestUnitsScale_P2 | GuestUnitsModifier_Rate, GuestUnitsGigaHz = GuestUnitsCycles | GuestUnitsScale_P3 | GuestUnitsModifier_Rate, GuestUnitsTeraHz = GuestUnitsCycles | GuestUnitsScale_P4 | GuestUnitsModifier_Rate, GuestUnitsPercent = GuestUnitsNumber | GuestUnitsScale_C0, // integers: must be 0...100; FP: 0.0...1.0 GuestUnitsNumberPerSecond = GuestUnitsNumber | GuestUnitsModifier_Rate, } GuestValueUnits; /* * Data type datum enum. * Note: The entirety (all bits) of the type must always be understood by a client. * * Bits 0-5 are for types. * Bits 6-15 are reserved. In the future, one bit will denote arrays. */ #define GuestTypeModifier_Reserved0 0x0040 // More Reserved1-9 not shown. typedef enum { GuestTypeInvalid, // Must never be sent GuestTypeNil, // A stat that has no value GuestTypeInt8, // Little endian GuestTypeUint8, // Little endian GuestTypeInt16, // Little endian GuestTypeUint16, // Little endian GuestTypeInt32, // Little endian GuestTypeUint32, // Little endian GuestTypeInt64, // Little endian GuestTypeUint64, // Little endian GuestTypeFloat, // IEEE 754 GuestTypeDouble, // IEEE 754 GuestTypeString, // NUL terminated UTF8 GuestTypeBinary, // Binary blob } GuestValueType; /* * Defines the namespace used for guest tools buildin query. */ #define GUEST_TOOLS_NAMESPACE "_tools/v1" /* * Defined stat IDs for guest tools builtin query. * See vmx/vigorapi/GuestStats.java for documentation * * NOTE: These IDs are relative to GUEST_TOOLS_NAMESPACE * NOTE: DO NOT re-order or remove the IDs. IDs can only be added to the end, * unless you make the totally backward-compatibility breaking change * of bumping the namespace version. */ #define GUEST_STAT_TOOLS_IDS \ /* 6.0u1 stats */ \ DEFINE_GUEST_STAT(GuestStatID_Invalid, 0, "__INVALID__") \ DEFINE_GUEST_STAT(GuestStatID_None, 1, "__NONE__") \ DEFINE_GUEST_STAT(GuestStatID_ContextSwapRate, 2, "guest.contextSwapRate") \ DEFINE_GUEST_STAT(GuestStatID_MemActiveFileCache, 3, "guest.mem.activeFileCache") \ DEFINE_GUEST_STAT(GuestStatID_MemFree, 4, "guest.mem.free") \ DEFINE_GUEST_STAT(GuestStatID_MemNeeded, 5, "guest.mem.needed") \ DEFINE_GUEST_STAT(GuestStatID_MemPhysUsable, 6, "guest.mem.physUsable") \ DEFINE_GUEST_STAT(GuestStatID_PageInRate, 7, "guest.page.inRate") \ DEFINE_GUEST_STAT(GuestStatID_PageOutRate, 8, "guest.page.outRate") \ DEFINE_GUEST_STAT(GuestStatID_SwapSpaceRemaining, 9, "guest.swap.spaceRemaining") \ DEFINE_GUEST_STAT(GuestStatID_PhysicalPageSize, 10, "guest.page.size") \ DEFINE_GUEST_STAT(GuestStatID_HugePageSize, 11, "guest.hugePage.size") \ DEFINE_GUEST_STAT(GuestStatID_Linux_HugePagesTotal, 12, "guest.hugePage.total") \ /* 6.5 stats */ \ DEFINE_GUEST_STAT(GuestStatID_MemNeededReservation, 13, "guest.mem.neededReservation") \ DEFINE_GUEST_STAT(GuestStatID_PageSwapInRate, 14, "guest.swap.pageInRate") \ DEFINE_GUEST_STAT(GuestStatID_PageSwapOutRate, 15, "guest.swap.pageOutRate") \ DEFINE_GUEST_STAT(GuestStatID_ProcessCreationRate, 16, "guest.processCreationRate") \ DEFINE_GUEST_STAT(GuestStatID_SwapSpaceUsed, 17, "guest.swap.used") \ DEFINE_GUEST_STAT(GuestStatID_SwapFilesCurrent, 18, "guest.swap.filesCurrent") \ DEFINE_GUEST_STAT(GuestStatID_SwapFilesMax, 19, "guest.swap.filesMax") \ DEFINE_GUEST_STAT(GuestStatID_ThreadCreationRate, 20, "guest.threadCreationRate") \ DEFINE_GUEST_STAT(GuestStatID_Linux_HugePagesFree, 21, "guest.hugePage.free") \ DEFINE_GUEST_STAT(GuestStatID_Linux_LowWaterMark, 22, "guest.mem.lowWaterMark") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemActive, 23, "guest.mem.active") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemActiveAnon, 24, "guest.mem.activeAnon") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemAvailable, 25, "guest.mem.available") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemBuffers, 26, "guest.mem.buffers") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemCached, 27, "guest.mem.cached") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemCommitted, 28, "guest.mem.committed") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemDirty, 29, "guest.mem.dirty") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemInactive, 30, "guest.mem.inactive") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemInactiveAnon, 31, "guest.mem.inactiveAnon") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemInactiveFile, 32, "guest.mem.inactiveFile") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemPinned, 33, "guest.mem.pinned") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemSlabReclaim, 34, "guest.mem.slabReclaim") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemSwapCached, 35, "guest.mem.swap.cached") \ DEFINE_GUEST_STAT(GuestStatID_Linux_PageDirectScanRate, 36, "guest.page.directScanRate") \ DEFINE_GUEST_STAT(GuestStatID_Linux_PageFaultRate, 37, "guest.page.faultRate") \ DEFINE_GUEST_STAT(GuestStatID_Linux_PageFreeRate, 38, "guest.page.freeRate") \ DEFINE_GUEST_STAT(GuestStatID_Linux_PageMajorFaultRate, 39, "guest.page.majorFaultRate") \ DEFINE_GUEST_STAT(GuestStatID_Linux_PageStealRate, 40, "guest.page.stealRate") \ DEFINE_GUEST_STAT(GuestStatID_Linux_PageSwapScanRate, 41, "guest.page.swapScanRate") \ DEFINE_GUEST_STAT(GuestStatID_Linux_Swappiness, 42, "guest.swappiness") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemModifiedPages, 43, "guest.mem.modifiedPages") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemAvailableToMm, 44, "guest.mem.availableToMm") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemStandbyCore, 45, "guest.mem.standby.core") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemStandbyNormal, 46, "guest.mem.standby.normal") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemStandbyReserve, 47, "guest.mem.standby.reserve") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemPagedPoolResident, 48, "guest.mem.pagedPool.resident") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemSystemCodeResident, 49, "guest.system.codeResident") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemSystemDriverResident, 50, "guest.system.driverResident") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemNonPagedPool, 51, "guest.mem.nonPagedPool.size") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemCache, 52, "guest.mem.cache") \ DEFINE_GUEST_STAT(GuestStatID_Windows_FreeSystemPtes, 53, "guest.system.freePtes") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemCommitLimit, 54, "guest.mem.commitLimit") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemCommitted, 55, "guest.mem.committed") \ DEFINE_GUEST_STAT(GuestStatID_Windows_MemPrivateWorkingSet, 56, "guest.mem.privateWorkingSet") \ DEFINE_GUEST_STAT(GuestStatID_Windows_DiskReadRate, 57, "guest.disk.readRate") \ DEFINE_GUEST_STAT(GuestStatID_Windows_DiskWriteRate, 58, "guest.disk.writeRate") \ DEFINE_GUEST_STAT(GuestStatID_Windows_AutomaticSwapFileMax, 59, "guest.swap.automaticFileMax") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemTotal, 60, "guest.mem.total") \ /* (6.7, ] stats */ \ DEFINE_GUEST_STAT(GuestStatID_Linux_CpuRunQueue, 61, "guest.cpu.runQueue") \ DEFINE_GUEST_STAT(GuestStatID_Linux_DiskRequestQueue, 62, "guest.disk.requestQueue") \ DEFINE_GUEST_STAT(GuestStatID_Linux_DiskRequestQueueAvg, 63, "guest.disk.requestQueueAvg") \ DEFINE_GUEST_STAT(GuestStatID_Windows_ProcessorQueue, 64, "guest.processor.queue") \ DEFINE_GUEST_STAT(GuestStatID_Windows_DiskQueue, 65, "guest.disk.queue") \ DEFINE_GUEST_STAT(GuestStatID_Windows_DiskQueueAvg, 66, "guest.disk.queueAvg") \ DEFINE_GUEST_STAT(GuestStatID_Max, 67, "__MAX__") /* * Define stats enumeration */ #undef DEFINE_GUEST_STAT #define DEFINE_GUEST_STAT(x,y,z) x, typedef enum GuestStatToolsID { GUEST_STAT_TOOLS_IDS } GuestStatToolsID; /* * Enforce ordering and compactness of the enumeration */ #undef DEFINE_GUEST_STAT #define DEFINE_GUEST_STAT(x,y,z) ASSERT_ON_COMPILE(x==y); MY_ASSERTS(GUEST_STAT_IDS_ARE_WELL_ORDERED, GUEST_STAT_TOOLS_IDS) #undef DEFINE_GUEST_STAT #endif // _GUEST_STATS_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guestStoreClient.h000066400000000000000000000032511470176644300261670ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * guestStoreClient.h -- * * Wrapper functions to load the GuestStore libraries. */ #ifndef _GUEST_STORE_CLIENT_H_ #define _GUEST_STORE_CLIENT_H_ #include "vmware/tools/guestStoreClientLib.h" typedef GuestStoreLibError GuestStoreClientError; /* * Caller provided callback to get total content size in bytes and so far * received bytes. Return FALSE to cancel content download. */ typedef GuestStore_GetContentCallback GuestStoreClient_GetContentCb; gboolean GuestStoreClient_Init(void); gboolean GuestStoreClient_DeInit(void); GuestStoreClientError GuestStoreClient_GetContent(const char *contentPath, const char *outputPath, GuestStoreClient_GetContentCb getContentCb, void *clientCbData); #endif /* _GUEST_STORE_CLIENT_H_ */open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guestStoreConst.h000066400000000000000000000044651470176644300260470ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2019-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * guestStoreConst.h -- * * GuestStore common constant definitions. */ #ifndef _GUESTSTORE_CONST_H_ #define _GUESTSTORE_CONST_H_ /* * GuestStore maximum content path length, set it * to be less than USERLINUX_PATH_MAX. */ #define GUESTSTORE_CONTENT_PATH_MAX 1024 /* * Buffer size to handle GuestStore content request. The request is * a content path encoded in HTTP protocol or DataMap. */ #define GUESTSTORE_REQUEST_BUFFER_SIZE (1024 * 4) /* * Buffer size to receive and forward GuestStore content bytes, set to * the maximum size of an IP packet. */ #define GUESTSTORE_RESPONSE_BUFFER_SIZE (1024 * 64) /* * GuestStore vmx to guest connection pending timeout value. */ #define GUESTSTORE_VMX_TO_GUEST_CONN_TIMEOUT 5 // seconds /* * GuestStore default connection inactivity timeout value. This value shall * be greater than gstored timeout value which is currently 60 seconds. */ #define GUESTSTORE_DEFAULT_CONN_TIMEOUT 900 // seconds /* * NOTE: changing the following IDs may break data map encoding compatibility. */ /* Tools to VMX field IDs */ enum { GUESTSTORE_REQ_FLD_CMD = 1, GUESTSTORE_REQ_FLD_PATH = 2, GUESTSTORE_REQ_FLD_MAX }; /* Command Types */ enum { GUESTSTORE_REQ_CMD_GET = 1, GUESTSTORE_REQ_CMD_CLOSE = 2, }; /* VMX to tools field IDs */ enum { GUESTSTORE_RES_FLD_ERROR_CODE = 1, GUESTSTORE_RES_FLD_CONTENT_SIZE = 2, }; #endif /* _GUESTSTORE_CONST_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guestStoreDefs.h000066400000000000000000000054141470176644300256350ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2019-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * guestStoreDefs.h -- * Common definitions for VMware Tools guestStore plugin and client library. */ #ifndef __GUESTSTOREDEFS_H__ #define __GUESTSTOREDEFS_H__ #include "vm_basic_defs.h" /* * GuestStore client connection definitions. */ #ifdef _WIN32 #define GUESTSTORE_LOOPBACK_PORT_MIN 7332 #define GUESTSTORE_LOOPBACK_PORT_MAX 7342 #else #define GUESTSTORE_PIPE_DIR "/var/run/vmware" #define GUESTSTORE_PIPE_NAME GUESTSTORE_PIPE_DIR "/guestStorePipe" #endif /* * HTTP definitions. */ #define HTTP_VER "HTTP/1.1" #define HTTP_LINE_END "\r\n" #define HTTP_HEADER_END HTTP_LINE_END HTTP_LINE_END #define HTTP_HEADER_END_LEN (sizeof HTTP_HEADER_END - 1) #define HTTP_REQ_METHOD_GET "GET" #define HTTP_STATUS_CODE_OK 200 #define HTTP_STATUS_CODE_FORBIDDEN 403 #define HTTP_STATUS_CODE_NOT_FOUND 404 #define HTTP_RES_OK_LINE HTTP_VER " " \ XSTR(HTTP_STATUS_CODE_OK) " OK" HTTP_LINE_END #define HTTP_RES_FORBIDDEN_LINE HTTP_VER " " \ XSTR(HTTP_STATUS_CODE_FORBIDDEN) " Forbidden" HTTP_LINE_END #define HTTP_RES_NOT_FOUND_LINE HTTP_VER " " \ XSTR(HTTP_STATUS_CODE_NOT_FOUND) " Not Found" HTTP_LINE_END #define CONTENT_LENGTH_HEADER "Content-Length: " #define CONTENT_LENGTH_HEADER_LEN ((int)(sizeof(CONTENT_LENGTH_HEADER) - 1)) #define HTTP_RES_COMMON_HEADERS "Date: %s" HTTP_LINE_END \ "Server: VMGuestStore" HTTP_LINE_END \ "Accept-Ranges: bytes" HTTP_LINE_END \ CONTENT_LENGTH_HEADER "%" FMT64 "d" HTTP_LINE_END \ "Content-Type: application/octet-stream" HTTP_LINE_END \ "Connection: close" HTTP_LINE_END \ HTTP_LINE_END #define HTTP_RES_OK HTTP_RES_OK_LINE HTTP_RES_COMMON_HEADERS #define HTTP_RES_FORBIDDEN HTTP_RES_FORBIDDEN_LINE HTTP_RES_COMMON_HEADERS #define HTTP_RES_NOT_FOUND HTTP_RES_NOT_FOUND_LINE HTTP_RES_COMMON_HEADERS #endif /* __GUESTSTOREDEFS_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guest_msg_def.h000066400000000000000000000073551470176644300255100ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2016,2022-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * guest_msg_def.h -- * * Second layer of the internal communication channel between guest * applications and vmware * */ #ifndef _GUEST_MSG_DEF_H_ #define _GUEST_MSG_DEF_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" /* Basic request types */ typedef enum { MESSAGE_TYPE_OPEN, MESSAGE_TYPE_SENDSIZE, MESSAGE_TYPE_SENDPAYLOAD, MESSAGE_TYPE_RECVSIZE, MESSAGE_TYPE_RECVPAYLOAD, MESSAGE_TYPE_RECVSTATUS, MESSAGE_TYPE_CLOSE, } MessageType; /* Reply statuses */ /* The basic request succeeded */ #define MESSAGE_STATUS_SUCCESS 0x0001 /* vmware has a message available for its party */ #define MESSAGE_STATUS_DORECV 0x0002 /* The channel has been closed */ #define MESSAGE_STATUS_CLOSED 0x0004 /* vmware removed the message before the party fetched it */ #define MESSAGE_STATUS_UNSENT 0x0008 /* A checkpoint occurred */ #define MESSAGE_STATUS_CPT 0x0010 /* An underlying device is powering off */ #define MESSAGE_STATUS_POWEROFF 0x0020 /* vmware has detected a timeout on the channel */ #define MESSAGE_STATUS_TIMEOUT 0x0040 /* vmware supports high-bandwidth for sending and receiving the payload */ #define MESSAGE_STATUS_HB 0x0080 /* * This mask defines the status bits that the guest is allowed to set; * we use this to mask out all other bits when receiving the status * from the guest. Otherwise, the guest can manipulate VMX state by * setting status bits that are only supposed to be changed by the * VMX. See bug 45385. */ #define MESSAGE_STATUS_GUEST_MASK MESSAGE_STATUS_SUCCESS /* * Max number of channels. * Unfortunately this has to be public because the monitor part * of the backdoor needs it for its trivial-case optimization. [greg] * * It would be nice to have as many as 1024 channels however, as we discovered * in PR 2978984, it becomes particularly difficult to raise the number beyond * 250. After much discussion, 128 was chosen. */ #define GUESTMSG_MAX_CHANNEL 128 /* Flags to open a channel. --hpreg */ #define GUESTMSG_FLAG_COOKIE 0x80000000 #define GUESTMSG_FLAG_ALL GUESTMSG_FLAG_COOKIE /* * Maximum size of incoming message. This is to prevent denial of host service * attacks from guest applications. */ #define GUESTMSG_MAX_IN_SIZE (64 * 1024) #endif /* _GUEST_MSG_DEF_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guest_os.h000066400000000000000000000763541470176644300245320ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _GUEST_OS_H_ #define _GUEST_OS_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_types.h" #include "guest_os_tables.h" #if defined(__cplusplus) extern "C" { #endif /* * There's no practical max to the number of guests that can be defined in * the list below (guest IDs are limited to 2^32), but there is a maximum * of MAXGOSSET guests that can comprise a set, such as ALLLINUX, ALLDARWIN, * or ALLWIN64. * * Be conservative and only declare entries in this list if you need to refer * to the guest specifically in vmx/main/guest_os.c, * vmcore/vmx/main/monitorControl.c, or similar. Don't rely on every supported * guest having an entry in this list. */ typedef enum GuestOSType { GUEST_OS_BASE = 0x5000, GUEST_OS_BASE_MINUS_ONE = 0x4fff, /* So that ANY is equal to BASE */ #define GOT(_name) _name, GUEST_OS_TYPE_GEN #undef GOT } GuestOSType; /* * Maximum number of guests in a set, must be <= LIST_SIZE in geninfo.h */ #define MAXGOSSET 128 typedef enum GuestOSFamilyType { GUEST_OS_FAMILY_ANY = 0x0000, GUEST_OS_FAMILY_LINUX = 0x0001, GUEST_OS_FAMILY_WINDOWS = 0x0002, GUEST_OS_FAMILY_WIN9X = 0x0004, GUEST_OS_FAMILY_WINNT = 0x0008, GUEST_OS_FAMILY_WIN2000 = 0x0010, GUEST_OS_FAMILY_WINXP = 0x0020, GUEST_OS_FAMILY_WINNET = 0x0040, GUEST_OS_FAMILY_NETWARE = 0x0080, GUEST_OS_FAMILY_DARWIN = 0x0100 } GuestOSFamilyType; #define ALLOS GUEST_OS_ANY #define BS(suf) GUEST_OS_##suf #define GOS_IN_SET(gos, ...) Gos_InSet(gos, __VA_ARGS__, 0) #define GOS_IN_SET_ARRAY(gos, set) Gos_InSetArray(gos, set) Bool Gos_InSet(uint32 gos, ...); Bool Gos_InSetArray(uint32 gos, const uint32 *set); #define ALLWIN9X BS(WIN95), BS(WIN98), BS(WINME) #define ALLWIN2000 BS(WIN2000) #define ALLWINXP32 BS(WINXP) #define ALLWINXP64 BS(WINXPPRO_64) #define ALLWINXP ALLWINXP32, ALLWINXP64 #define ALLFREEBSD32 BS(FREEBSD), BS(FREEBSD11), \ BS(FREEBSD12), BS(FREEBSD13), \ BS(FREEBSD14), BS(FREEBSD15) #define ALLFREEBSD64 BS(FREEBSD_64), \ BS(FREEBSD11_64), BS(FREEBSD12_64), \ BS(FREEBSD13_64), BS(FREEBSD13_ARM_64), \ BS(FREEBSD14_64), BS(FREEBSD14_ARM_64), \ BS(FREEBSD15_64), BS(FREEBSD15_ARM_64) #define ALLFREEBSD ALLFREEBSD32, ALLFREEBSD64 #define ALLWINNET32 BS(WINNET) #define ALLWINNET64 BS(WINNET_64) #define ALLWINNET ALLWINNET32, ALLWINNET64 #define ALLWINLONGHORN32 BS(LONGHORN) #define ALLWINLONGHORN64 BS(LONGHORN_64) #define ALLWINLONGHORN ALLWINLONGHORN32, ALLWINLONGHORN64 #define ALLWINVISTA32 BS(WINVISTA) #define ALLWINVISTA64 BS(WINVISTA_64) #define ALLWINVISTA ALLWINVISTA32, ALLWINVISTA64 #define ALLWIN2008R2_64 BS(WIN2008R2_64) #define ALLWIN2008R2 ALLWIN2008R2_64 #define ALLWINSEVEN32 BS(WIN_7) #define ALLWINSEVEN64 BS(WIN_7_64) #define ALLWINSEVEN ALLWINSEVEN32, ALLWINSEVEN64 #define ALLWINEIGHTSERVER64 BS(WIN_8_SERVER_64) #define ALLWINEIGHTSERVER ALLWINEIGHTSERVER64 #define ALLWINEIGHTCLIENT32 BS(WIN_8) #define ALLWINEIGHTCLIENT64 BS(WIN_8_64) #define ALLWINEIGHTCLIENT ALLWINEIGHTCLIENT32, ALLWINEIGHTCLIENT64 #define ALLWINEIGHT ALLWINEIGHTSERVER, ALLWINEIGHTCLIENT #define ALLWIN_10_SERVER64 BS(WIN_2016SRV_64), BS(WIN_2019SRV_64) #define ALLWIN_10_SERVER ALLWIN_10_SERVER64 #define ALLWIN_10_CLIENT32 BS(WIN_10) #define ALLWIN_10_CLIENT64 BS(WIN_10_64), BS(WIN_10_ARM_64) #define ALLWIN_10_CLIENT ALLWIN_10_CLIENT32, ALLWIN_10_CLIENT64 #define ALLWIN_10_32 ALLWIN_10_CLIENT32 #define ALLWIN_10_64 ALLWIN_10_CLIENT64, ALLWIN_10_SERVER #define ALLWIN_10 ALLWIN_10_CLIENT, ALLWIN_10_SERVER #define ALLWIN_11_SERVER64 BS(WIN_2022SRV_64), BS(WIN_2025SRV_64) #define ALLWIN_11_SERVER ALLWIN_11_SERVER64 #define ALLWIN_11_CLIENT64 BS(WIN_11_64), BS(WIN_11_ARM_64) #define ALLWIN_11_CLIENT ALLWIN_11_CLIENT64 #define ALLWIN_11_64 ALLWIN_11_CLIENT64, ALLWIN_11_SERVER #define ALLWIN_11 ALLWIN_11_CLIENT64, ALLWIN_11_SERVER #define ALLWIN_12_CLIENT64 BS(WIN_12_64), BS(WIN_12_ARM_64) #define ALLWIN_12_CLIENT ALLWIN_12_CLIENT64 #define ALLWIN_12 ALLWIN_12_CLIENT64 #define ALLHYPER_V BS(HYPER_V) #define ALLWINVISTA_OR_HIGHER ALLWINVISTA, ALLWINLONGHORN, \ ALLWIN2008R2, ALLWINSEVEN, \ ALLWINEIGHTSERVER, ALLWINEIGHTCLIENT, \ ALLWIN_10_SERVER, ALLWIN_10_CLIENT, \ ALLWIN_11_SERVER, ALLWIN_11_CLIENT, \ ALLWIN_12_CLIENT, ALLHYPER_V #define ALLWINNT32 BS(WINNT), ALLWIN2000, \ ALLWINXP32, ALLWINNET32, \ ALLWINVISTA32, ALLWINLONGHORN32, \ ALLWINSEVEN32, ALLWINEIGHTCLIENT32, \ ALLWIN_10_CLIENT32 #define ALLWINNT64 ALLWINXP64, ALLWINNET64, \ ALLWINVISTA64, ALLWINLONGHORN64, \ ALLWINSEVEN64, ALLWIN2008R2_64, \ ALLWINEIGHTCLIENT64, ALLWINEIGHTSERVER, \ ALLWIN_10_CLIENT64, ALLWIN_10_SERVER, \ ALLWIN_11_CLIENT64, ALLWIN_11_SERVER, \ ALLWIN_12_CLIENT64, ALLHYPER_V #define ALLWINNT ALLWINNT32, ALLWINNT64 #define ALLWIN32 ALLWIN9X, ALLWINNT32 #define ALLWIN64 ALLWINNT64 #define ALLWIN ALLWIN32, ALLWIN64 #define ALLOTHER BS(OTHER), BS(OTHER_64) #define ALLSOLARIS11_OR_HIGHER \ BS(SOLARIS11_64) #define ALLSOLARIS10_OR_HIGHER \ BS(SOLARIS10), BS(SOLARIS10_64), \ ALLSOLARIS11_OR_HIGHER #define ALLSOLARIS BS(SOLARIS_6_AND_7), \ BS(SOLARIS8), \ BS(SOLARIS9), \ ALLSOLARIS10_OR_HIGHER #define ALLNETWARE BS(NETWARE4), BS(NETWARE5), BS(NETWARE6) #define ALLPHOTON BS(PHOTON_64), BS(PHOTON_ARM_64) #define ALL26XLINUX32 BS(DEBIAN), BS(RHEL), \ BS(UBUNTU), BS(CENTOS), \ BS(ORACLE), BS(OTHER26XLINUX) #define ALL26XLINUX64 BS(DEBIAN_64), BS(RHEL_64), \ BS(UBUNTU_64), BS(CENTOS_64), \ BS(ORACLE_64), BS(OTHER26XLINUX_64) #define ALL3XLINUX32 BS(OTHER3XLINUX), BS(CENTOS6), BS(ORACLE6) #define ALL3XLINUX64 BS(OTHER3XLINUX_64), \ BS(CENTOS6_64), BS(CENTOS7_64), \ BS(ORACLE6_64), BS(ORACLE7_64) #define ALL4XLINUX32 BS(OTHER4XLINUX) #define ALL4XLINUX64 BS(OTHER4XLINUX_64), BS(PHOTON_64), \ BS(CENTOS8_64), BS(CENTOS9_64), \ BS(ORACLE8_64), BS(ORACLE9_64), \ BS(CRXSYS1_64), BS(CRXPOD1_64), \ BS(AMAZONLINUX2_64), BS(AMAZONLINUX3_64), \ BS(LINUX_MINT_64) #define ALL5XLINUX32 BS(OTHER5XLINUX) #define ALL5XLINUX64 BS(OTHER5XLINUX_64), BS(OTHER5XLINUX_ARM_64), \ BS(DEBIAN_ARM_64), BS(UBUNTU_ARM_64), \ BS(RHEL9_64), BS(RHEL9_ARM_64), \ BS(ROCKY_LINUX_64), BS(ROCKY_LINUX_ARM_64), \ BS(ALMA_LINUX_64), BS(ALMA_LINUX_ARM_64), \ BS(CRXSYS1_ARM_64), BS(CRXPOD1_ARM_64), \ BS(CRXSYS2_64), BS(CRXSYS2_ARM_64) #define ALL6XLINUX32 BS(OTHER6XLINUX) #define ALL6XLINUX64 BS(OTHER6XLINUX_64), BS(OTHER6XLINUX_ARM_64), \ BS(RHEL10_64), BS(RHEL10_ARM_64), \ BS(ORACLE10_64), BS(PROLINUX_64), \ BS(PARDUS_64) #define ALL7XLINUX32 BS(OTHER7XLINUX) #define ALL7XLINUX64 BS(OTHER7XLINUX_64), BS(OTHER7XLINUX_ARM_64) #define ALLVMKERNEL BS(VMKERNEL), BS(VMKERNEL5), \ BS(VMKERNEL6), BS(VMKERNEL65), \ BS(VMKERNEL7), BS(VMKERNEL7_ARM), \ BS(VMKERNEL8), BS(VMKERNEL8_ARM), \ BS(VMKERNEL9), BS(VMKERNEL9_ARM) #define ALLLINUX32 BS(VMKERNEL), BS(OTHERLINUX), \ BS(OTHER24XLINUX), ALL26XLINUX32, \ ALL3XLINUX32, ALL4XLINUX32, \ ALL5XLINUX32, ALL6XLINUX32, \ ALL7XLINUX32 #define ALLLINUX64 BS(OTHERLINUX_64), BS(OTHER24XLINUX_64), \ ALL26XLINUX64, ALL3XLINUX64, \ ALL4XLINUX64, ALL5XLINUX64, \ ALL6XLINUX64, ALL7XLINUX64, \ ALLPHOTON #define ALLLINUX ALLLINUX32, ALLLINUX64 #define ALLDARWIN32 BS(DARWIN9), BS(DARWIN10), BS(DARWIN11) #define ALLDARWIN64 BS(DARWIN9_64), BS(DARWIN10_64), \ BS(DARWIN11_64), BS(DARWIN12_64), \ BS(DARWIN13_64), BS(DARWIN14_64), \ BS(DARWIN15_64), BS(DARWIN16_64), \ BS(DARWIN17_64), BS(DARWIN18_64), \ BS(DARWIN19_64), BS(DARWIN20_64), \ BS(DARWIN21_64), BS(DARWIN22_64), \ BS(DARWIN23_64), BS(DARWIN24_64) #define ALLDARWIN ALLDARWIN32, ALLDARWIN64 #define ALL64 ALLLINUX64, ALLWIN64, \ ALLFREEBSD64, ALLDARWIN64, \ ALLPHOTON, ALLVMKERNEL, \ BS(SOLARIS10_64), BS(SOLARIS11_64), \ BS(OTHER_64), BS(OTHER_ARM_64) #define ALLECOMSTATION BS(ECOMSTATION), BS(ECOMSTATION2) #define ALLOS2 BS(OS2), ALLECOMSTATION #define ALLCRX BS(CRXSYS1_64), BS(CRXPOD1_64), \ BS(CRXSYS1_ARM_64), BS(CRXPOD1_ARM_64), \ BS(CRXSYS2_64), BS(CRXSYS2_ARM_64) #define ALLARM BS(WIN_10_ARM_64), BS(WIN_11_ARM_64), \ BS(WIN_12_ARM_64), \ BS(UBUNTU_ARM_64), BS(PHOTON_ARM_64), \ BS(VMKERNEL7_ARM), BS(VMKERNEL8_ARM), \ BS(VMKERNEL9_ARM), \ BS(OTHER_ARM_64), BS(DEBIAN_ARM_64), \ BS(OTHER5XLINUX_ARM_64), BS(OTHER6XLINUX_ARM_64), \ BS(OTHER7XLINUX_ARM_64), \ BS(FREEBSD13_ARM_64), BS(FREEBSD14_ARM_64), \ BS(FREEBSD15_ARM_64), \ BS(ALMA_LINUX_ARM_64), BS(ROCKY_LINUX_ARM_64), \ BS(CRXSYS1_ARM_64), BS(CRXSYS2_ARM_64), \ BS(CRXPOD1_ARM_64), \ BS(RHEL9_ARM_64), BS(RHEL10_ARM_64) /* * Architecture prefixes. No prefix implies the X86 architecture. */ #define STR_OS_ARM_PREFIX "arm-" #define STR_OS_RISCV_PREFIX "riscv-" /* vmkernel (ESX) */ #define STR_OS_VMKERNEL "vmkernel" /* Linux */ #define STR_OS_ALMA_LINUX "almaLinux" #define STR_OS_AMAZON_LINUX "amazonlinux" #define STR_OS_ANNVIX "Annvix" #define STR_OS_ARCH "Arch" #define STR_OS_ARKLINUX "Arklinux" #define STR_OS_ASIANUX "asianux" #define STR_OS_AUROX "Aurox" #define STR_OS_BLACKCAT "BlackCat" #define STR_OS_CENTOS "centos" #define STR_OS_CRXPOD "CRXPod" #define STR_OS_CRXSYS "CRXSys" #define STR_OS_COBALT "Cobalt" #define STR_OS_CONECTIVA "Conectiva" #define STR_OS_DEBIAN "debian" #define STR_OS_FEDORA "Fedora" #define STR_OS_FLATCAR "flatcar" #define STR_OS_FUSION_OS "fusionos" #define STR_OS_GENTOO "Gentoo" #define STR_OS_IMMUNIX "Immunix" #define STR_OS_KYLIN_LINUX "kylinlinux" #define STR_OS_LINUX "linux" #define STR_OS_LINUX_FROM_SCRATCH "Linux-From-Scratch" #define STR_OS_LINUX_FULL "Other Linux" #define STR_OS_LINUX_MINT "linuxMint" #define STR_OS_LINUX_PPC "Linux-PPC" #define STR_OS_MANDRAKE "mandrake" #define STR_OS_MANDRAKE_FULL "Mandrake Linux" #define STR_OS_MANDRIVA "mandriva" #define STR_OS_MIRACLE_LINUX "miraclelinux" #define STR_OS_MKLINUX "MkLinux" #define STR_OS_NOVELL "nld" #define STR_OS_NOVELL_FULL "Novell Linux Desktop 9" #define STR_OS_ORACLE "oraclelinux" #define STR_OS_OTHER_LINUX "otherlinux" #define STR_OS_OTHER_LINUX_FULL "Other Linux" #define STR_OS_OTHER "other" #define STR_OS_OTHER_FULL "Other OSes" #define STR_OS_OTHER_LINUX "otherlinux" #define STR_OS_OTHER_LINUXFULL "Other Linux" #define STR_OS_OTHER_24 "other24xlinux" #define STR_OS_OTHER_24_FULL "Other Linux 2.4.x kernel" #define STR_OS_OTHER_26 "other26xlinux" #define STR_OS_OTHER_26_FULL "Other Linux 2.6.x kernel" #define STR_OS_OTHER_3X "other3xlinux" #define STR_OS_OTHER_3X_FULL "Other Linux 3.x kernel" #define STR_OS_OTHER_4X "other4xlinux" #define STR_OS_OTHER_4X_FULL "Other Linux 4.x kernel" #define STR_OS_OTHER_5X "other5xlinux" #define STR_OS_OTHER_5X_FULL "Other Linux 5.x kernel" #define STR_OS_OTHER_6X "other6xlinux" #define STR_OS_OTHER_6X_FULL "Other Linux 6.x kernel" #define STR_OS_OTHER_7X "other7xlinux" #define STR_OS_OTHER_7X_FULL "Other Linux 7.x and later kernel" #define STR_OS_PARDUS "pardus" #define STR_OS_PHOTON "vmware-photon" #define STR_OS_PHOTON_FULL "VMware Photon OS" #define STR_OS_PROLINUX "prolinux" #define STR_OS_PROLINUX_FULL "ProLinux" #define STR_OS_PLD "PLD" #define STR_OS_RED_HAT "redhat" #define STR_OS_RED_HAT_EN "rhel" #define STR_OS_RED_HAT_FULL "Red Hat Linux" #define STR_OS_ROCKY_LINUX "rockyLinux" #define STR_OS_SLACKWARE "Slackware" #define STR_OS_SLES "sles" #define STR_OS_SUSE "suse" #define STR_OS_SUSE_FULL "SUSE Linux" #define STR_OS_OPENSUSE "opensuse" #define STR_OS_SMESERVER "SMEServer" #define STR_OS_SUN_DESK "sjds" #define STR_OS_SUN_DESK_FULL "Sun Java Desktop System" #define STR_OS_TINYSOFA "Tiny Sofa" #define STR_OS_TURBO "turbolinux" #define STR_OS_TURBO_FULL "Turbolinux" #define STR_OS_UBUNTU "ubuntu" #define STR_OS_ULTRAPENGUIN "UltraPenguin" #define STR_OS_UNITEDLINUX "UnitedLinux" #define STR_OS_VALINUX "VALinux" #define STR_OS_YELLOW_DOG "Yellow Dog" #define STR_OS_ECOMSTATION "eComStation" /* Windows */ #define STR_OS_WIN_31 "win31" #define STR_OS_WIN_31_FULL "Windows 3.1" #define STR_OS_WIN_95 "win95" #define STR_OS_WIN_95_FULL "Windows 95" #define STR_OS_WIN_98 "win98" #define STR_OS_WIN_98_FULL "Windows 98" #define STR_OS_WIN_ME "winMe" #define STR_OS_WIN_ME_FULL "Windows Me" #define STR_OS_WIN_NT "winNT" #define STR_OS_WIN_NT_FULL "Windows NT" #define STR_OS_WIN_2000_PRO "win2000Pro" #define STR_OS_WIN_2000_PRO_FULL "Windows 2000 Professional" #define STR_OS_WIN_2000_SERV "win2000Serv" #define STR_OS_WIN_2000_SERV_FULL "Windows 2000 Server" #define STR_OS_WIN_2000_ADV_SERV "win2000AdvServ" #define STR_OS_WIN_2000_ADV_SERV_FULL "Windows 2000 Advanced Server" #define STR_OS_WIN_2000_DATACENT_SERV "win2000DataCentServ" #define STR_OS_WIN_2000_DATACENT_SERV_FULL "Windows 2000 Data Center Server" #define STR_OS_WIN_XP_HOME "winXPHome" #define STR_OS_WIN_XP_HOME_FULL "Windows XP Home Edition" #define STR_OS_WIN_XP_PRO "winXPPro" #define STR_OS_WIN_XP_PRO_FULL "Windows XP Professional" #define STR_OS_WIN_XP_PRO_X64 "winXPPro-64" #define STR_OS_WIN_XP_PRO_X64_FULL "Windows XP Professional x64 Edition" #define STR_OS_WIN_NET_WEB "winNetWeb" #define STR_OS_WIN_NET_WEB_FULL "Windows Server 2003 Web Edition" #define STR_OS_WIN_NET_ST "winNetStandard" #define STR_OS_WIN_NET_ST_FULL "Windows Server 2003 Standard Edition" #define STR_OS_WIN_NET_EN "winNetEnterprise" #define STR_OS_WIN_NET_EN_FULL "Windows Server 2003 Enterprise Edition" #define STR_OS_WIN_NET_BUS "winNetBusiness" #define STR_OS_WIN_NET_BUS_FULL "Windows Server 2003 Small Business" #define STR_OS_WIN_NET_COMPCLUSTER "winNetComputeCluster" #define STR_OS_WIN_NET_COMPCLUSTER_FULL "Windows Server 2003 Compute Cluster Edition" #define STR_OS_WIN_NET_STORAGESERVER "winNetStorageSvr" #define STR_OS_WIN_NET_STORAGESERVER_FULL "Windows Storage Server 2003" #define STR_OS_WIN_NET_DC_FULL "Windows Server 2003 Datacenter Edition" #define STR_OS_WIN_NET_DC "winNetDatacenter" #define STR_OS_WIN_LONG "longhorn" #define STR_OS_WIN_VISTA "winVista" #define STR_OS_WIN_VISTA_FULL "Windows Vista" #define STR_OS_WIN_VISTA_X64 "winVista-64" #define STR_OS_WIN_VISTA_X64_FULL "Windows Vista x64 Edition" #define STR_OS_WIN_VISTA_ULTIMATE "winVistaUltimate-32" #define STR_OS_WIN_VISTA_ULTIMATE_FULL "Windows Vista Ultimate Edition" #define STR_OS_WIN_VISTA_HOME_PREMIUM "winVistaHomePremium-32" #define STR_OS_WIN_VISTA_HOME_PREMIUM_FULL "Windows Vista Home Premium Edition" #define STR_OS_WIN_VISTA_HOME_BASIC "winVistaHomeBasic-32" #define STR_OS_WIN_VISTA_HOME_BASIC_FULL "Windows Vista Home Basic Edition" #define STR_OS_WIN_VISTA_ENTERPRISE "winVistaEnterprise-32" #define STR_OS_WIN_VISTA_ENTERPRISE_FULL "Windows Vista Enterprise Edition" #define STR_OS_WIN_VISTA_BUSINESS "winVistaBusiness-32" #define STR_OS_WIN_VISTA_BUSINESS_FULL "Windows Vista Business Edition" #define STR_OS_WIN_VISTA_STARTER "winVistaStarter-32" #define STR_OS_WIN_VISTA_STARTER_FULL "Windows Vista Starter Edition" #define STR_OS_WIN_2008_CLUSTER "winServer2008Cluster-32" #define STR_OS_WIN_2008_CLUSTER_FULL "Windows Server 2008 Cluster Server Edition" #define STR_OS_WIN_2008_DATACENTER "winServer2008Datacenter-32" #define STR_OS_WIN_2008_DATACENTER_FULL "Windows Server 2008 Datacenter Edition" #define STR_OS_WIN_2008_DATACENTER_CORE "winServer2008DatacenterCore-32" #define STR_OS_WIN_2008_DATACENTER_CORE_FULL "Windows Server 2008 Datacenter Edition (core installation)" #define STR_OS_WIN_2008_ENTERPRISE "winServer2008Enterprise-32" #define STR_OS_WIN_2008_ENTERPRISE_FULL "Windows Server 2008 Enterprise Edition" #define STR_OS_WIN_2008_ENTERPRISE_CORE "winServer2008EnterpriseCore-32" #define STR_OS_WIN_2008_ENTERPRISE_CORE_FULL "Windows Server 2008 Enterprise Edition (core installation)" #define STR_OS_WIN_2008_ENTERPRISE_ITANIUM "winServer2008EnterpriseItanium-32" #define STR_OS_WIN_2008_ENTERPRISE_ITANIUM_FULL "Windows Server 2008 Enterprise Edition for Itanium-based Systems" #define STR_OS_WIN_2008_MEDIUM_MANAGEMENT "winServer2008MediumManagement-32" #define STR_OS_WIN_2008_MEDIUM_MANAGEMENT_FULL "Windows Essential Business Server Management Server" #define STR_OS_WIN_2008_MEDIUM_MESSAGING "winServer2008MediumMessaging-32" #define STR_OS_WIN_2008_MEDIUM_MESSAGING_FULL "Windows Essential Business Server Messaging Server" #define STR_OS_WIN_2008_MEDIUM_SECURITY "winServer2008MediumSecurity-32" #define STR_OS_WIN_2008_MEDIUM_SECURITY_FULL "Windows Essential Business Server Security Server" #define STR_OS_WIN_2008_SERVER_FOR_SMALLBUSINESS "winServer2008ForSmallBusiness-32" #define STR_OS_WIN_2008_SERVER_FOR_SMALLBUSINESS_FULL "Windows Server 2008 for Windows Essential Server Solutions" #define STR_OS_WIN_2008_SMALL_BUSINESS "winServer2008SmallBusiness-32" #define STR_OS_WIN_2008_SMALL_BUSINESS_FULL "Windows Server 2008 Small Business Server" #define STR_OS_WIN_2008_SMALL_BUSINESS_PREMIUM "winServer2008SmallBusinessPremium-32" #define STR_OS_WIN_2008_SMALL_BUSINESS_PREMIUM_FULL "Windows Server 2008 Small Business Server Premium Edition" #define STR_OS_WIN_2008_STANDARD "winServer2008Standard-32" #define STR_OS_WIN_2008_STANDARD_FULL "Windows Server 2008 Standard Edition" #define STR_OS_WIN_2008_STANDARD_CORE "winServer2008StandardCore-32" #define STR_OS_WIN_2008_STANDARD_CORE_FULL "Windows Server 2008 Standard Edition (core installation)" #define STR_OS_WIN_2008_STORAGE_ENTERPRISE "winServer2008StorageEnterprise-32" #define STR_OS_WIN_2008_STORAGE_ENTERPRISE_FULL "Windows Server 2008 Storage Server Enterprise" #define STR_OS_WIN_2008_STORAGE_EXPRESS "winServer2008StorageExpress-32" #define STR_OS_WIN_2008_STORAGE_EXPRESS_FULL "Windows Server 2008 Storage Server Express" #define STR_OS_WIN_2008_STORAGE_STANDARD "winServer2008StorageStandard-32" #define STR_OS_WIN_2008_STORAGE_STANDARD_FULL "Windows Server 2008 Storage Server Standard" #define STR_OS_WIN_2008_STORAGE_WORKGROUP "winServer2008StorageWorkgroup-32" #define STR_OS_WIN_2008_STORAGE_WORKGROUP_FULL "Windows Server 2008 Storage Server Workgroup" #define STR_OS_WIN_2008_WEB_SERVER "winServer2008Web-32" #define STR_OS_WIN_2008_WEB_SERVER_FULL "Windows Server 2008 Web Server Edition" /* Windows 64-bit */ #define STR_OS_WIN_VISTA_ULTIMATE_X64 "winVistaUltimate-64" #define STR_OS_WIN_VISTA_HOME_PREMIUM_X64 "winVistaHomePremium-64" #define STR_OS_WIN_VISTA_HOME_BASIC_X64 "winVistaHomeBasic-64" #define STR_OS_WIN_VISTA_ENTERPRISE_X64 "winVistaEnterprise-64" #define STR_OS_WIN_VISTA_BUSINESS_X64 "winVistaBusiness-64" #define STR_OS_WIN_VISTA_STARTER_X64 "winVistaStarter-64" #define STR_OS_WIN_2008_CLUSTER_X64 "winServer2008Cluster-64" #define STR_OS_WIN_2008_DATACENTER_X64 "winServer2008Datacenter-64" #define STR_OS_WIN_2008_DATACENTER_CORE_X64 "winServer2008DatacenterCore-64" #define STR_OS_WIN_2008_ENTERPRISE_X64 "winServer2008Enterprise-64" #define STR_OS_WIN_2008_ENTERPRISE_CORE_X64 "winServer2008EnterpriseCore-64" #define STR_OS_WIN_2008_MEDIUM_MANAGEMENT_X64 "winServer2008MediumManagement-64" #define STR_OS_WIN_2008_MEDIUM_MESSAGING_X64 "winServer2008MediumMessaging-64" #define STR_OS_WIN_2008_MEDIUM_SECURITY_X64 "winServer2008MediumSecurity-64" #define STR_OS_WIN_2008_SERVER_FOR_SMALLBUSINESS_X64 "winServer2008ForSmallBusiness-64" #define STR_OS_WIN_2008_SMALL_BUSINESS_X64 "winServer2008SmallBusiness-64" #define STR_OS_WIN_2008_SMALL_BUSINESS_PREMIUM_X64 "winServer2008SmallBusinessPremium-64" #define STR_OS_WIN_2008_STANDARD_X64 "winServer2008Standard-64" #define STR_OS_WIN_2008_STANDARD_CORE_X64 "winServer2008StandardCore-64" #define STR_OS_WIN_2008_STORAGE_ENTERPRISE_X64 "winServer2008StorageEnterprise-64" #define STR_OS_WIN_2008_STORAGE_EXPRESS_X64 "winServer2008StorageExpress-64" #define STR_OS_WIN_2008_STORAGE_STANDARD_X64 "winServer2008StorageStandard-64" #define STR_OS_WIN_2008_STORAGE_WORKGROUP_X64 "winServer2008StorageWorkgroup-64" #define STR_OS_WIN_2008_WEB_SERVER_X64 "winServer2008Web-64" /* All */ #define STR_OS_64BIT_SUFFIX "-64" #define STR_OS_64BIT_SUFFIX_FULL " (64 bit)" #define STR_OS_EMPTY "" /* Windows 7 */ #define STR_OS_WINDOWS "windows" #define STR_OS_WIN_SEVEN STR_OS_WINDOWS "7" #define STR_OS_WIN_SEVEN_X64 STR_OS_WIN_SEVEN STR_OS_64BIT_SUFFIX #define STR_OS_WIN_SEVEN_GENERIC "Windows 7" #define STR_OS_WIN_SEVEN_STARTER_FULL "Windows 7 Starter" #define STR_OS_WIN_SEVEN_HOME_BASIC_FULL "Windows 7 Home Basic" #define STR_OS_WIN_SEVEN_HOME_PREMIUM_FULL "Windows 7 Home Premium" #define STR_OS_WIN_SEVEN_ULTIMATE_FULL "Windows 7 Ultimate" #define STR_OS_WIN_SEVEN_PROFESSIONAL_FULL "Windows 7 Professional" #define STR_OS_WIN_SEVEN_ENTERPRISE_FULL "Windows 7 Enterprise" /* Windows Server 2008 R2 (based on Windows 7) */ #define STR_OS_WIN_2008R2_X64 STR_OS_WINDOWS "7srv" STR_OS_64BIT_SUFFIX #define STR_OS_WIN_2008R2_FOUNDATION_FULL "Windows Server 2008 R2 Foundation Edition" #define STR_OS_WIN_2008R2_STANDARD_FULL "Windows Server 2008 R2 Standard Edition" #define STR_OS_WIN_2008R2_ENTERPRISE_FULL "Windows Server 2008 R2 Enterprise Edition" #define STR_OS_WIN_2008R2_DATACENTER_FULL "Windows Server 2008 R2 Datacenter Edition" #define STR_OS_WIN_2008R2_WEB_SERVER_FULL "Windows Web Server 2008 R2 Edition" /* Windows 8 */ #define STR_OS_WIN_EIGHT STR_OS_WINDOWS "8" #define STR_OS_WIN_EIGHT_X64 STR_OS_WIN_EIGHT STR_OS_64BIT_SUFFIX #define STR_OS_WIN_EIGHT_GENERIC_FULL "Windows 8%s" #define STR_OS_WIN_EIGHTSERVER_GENERIC_FULL "Windows Server%s 2012" #define STR_OS_WIN_EIGHT_FULL "Windows 8%s" #define STR_OS_WIN_EIGHT_PRO_FULL "Windows 8%s Pro" #define STR_OS_WIN_EIGHT_ENTERPRISE_FULL "Windows 8%s Enterprise" /* Windows Server 2012 */ #define STR_OS_WIN_EIGHTSERVER_X64 STR_OS_WINDOWS "8srv" STR_OS_64BIT_SUFFIX #define STR_OS_WIN_2012_FOUNDATION_FULL "Windows Server 2012%s Foundation Edition" #define STR_OS_WIN_2012_ESSENTIALS_FULL "Windows Server 2012%s Essentials Edition" #define STR_OS_WIN_2012_STANDARD_FULL "Windows Server 2012%s Standard Edition" #define STR_OS_WIN_2012_ENTERPRISE_FULL "Windows Server 2012%s Enterprise Edition" #define STR_OS_WIN_2012_DATACENTER_FULL "Windows Server 2012%s Datacenter Edition" #define STR_OS_WIN_2012_STORAGESERVER_FULL "Windows Server 2012%s Storage Server" #define STR_OS_WIN_2012_WEB_SERVER_FULL "Windows Web Server 2012%s Edition" #define STR_OS_WIN_2012_MULTIPOINT_STANDARD_FULL "Windows MultiPoint Server 2012%s Standard" #define STR_OS_WIN_2012_MULTIPOINT_PREMIUM_FULL "Windows MultiPoint Server 2012%s Premium" /* * Windows on Arm * * Window on Arm support starts with Windows 10. */ #define STR_OS_ARM_WIN "arm-windows" /* * Windows 10 * * Microsoft renamed Windows 9 to Windows 10 at the last minute; Windows 9 was * never officially released. We retain the Windows 9 identifier strings as * Windows 10 to ensure that things continue to work. */ #define STR_OS_WIN_10 STR_OS_WINDOWS "9" #define STR_OS_WIN_10_X64 STR_OS_WIN_10 STR_OS_64BIT_SUFFIX #define STR_OS_WIN_10_GENERIC_FULL "Windows 10" #define STR_OS_WIN_10_HOME_FULL "Windows 10 Home" #define STR_OS_WIN_10_EDUCATION_FULL "Windows 10 Education" #define STR_OS_WIN_10_ENTERPRISE_FULL "Windows 10 Enterprise" #define STR_OS_WIN_10_PRO_WORKSTATION_FULL "Windows 10 Pro for Workstations" #define STR_OS_WIN_10_PRO_FULL "Windows 10 Pro" #define STR_OS_WIN_10_IOTCORE_FULL "Windows 10 IoT Core" /* * Windows 11 */ #define STR_OS_WIN_11 STR_OS_WINDOWS "11" #define STR_OS_WIN_11_X64 STR_OS_WIN_11 STR_OS_64BIT_SUFFIX #define STR_OS_WIN_11_GENERIC_FULL "Windows 11" #define STR_OS_WIN_11_HOME_FULL "Windows 11 Home" #define STR_OS_WIN_11_EDUCATION_FULL "Windows 11 Education" #define STR_OS_WIN_11_ENTERPRISE_FULL "Windows 11 Enterprise" #define STR_OS_WIN_11_PRO_WORKSTATION_FULL "Windows 11 Pro for Workstations" #define STR_OS_WIN_11_PRO_FULL "Windows 11 Pro" #define STR_OS_WIN_11_IOTCORE_FULL "Windows 11 IoT Core" /* * Windows 12 */ #define STR_OS_WIN_12 STR_OS_WINDOWS "12" #define STR_OS_WIN_12_X64 STR_OS_WIN_12 STR_OS_64BIT_SUFFIX /* No full names known yet */ /* Windows Server 2016 */ #define STR_OS_WIN_2016SRV_X64 STR_OS_WINDOWS "9srv" STR_OS_64BIT_SUFFIX /* Windows Server 2019 */ #define STR_OS_WIN_2019SRV_X64 STR_OS_WINDOWS "2019srv" STR_OS_64BIT_SUFFIX /* Windows Server 2022 */ #define STR_OS_WIN_2022SRV_X64 STR_OS_WINDOWS "2019srvNext" STR_OS_64BIT_SUFFIX /* Windows Server 2025 */ #define STR_OS_WIN_2025SRV_X64 STR_OS_WINDOWS "2022srvNext" STR_OS_64BIT_SUFFIX /* THIS SPACE FOR RENT (Windows 10 and later official server variant names) */ #define STR_OS_WIN_10_SERVER_2016_GENERIC_FULL "Windows Server 2016" #define STR_OS_WIN_10_SERVER_2019_GENERIC_FULL "Windows Server 2019" #define STR_OS_WIN_11_SERVER_2022_GENERIC_FULL "Windows Server 2022" #define STR_OS_WIN_11_SERVER_2025_GENERIC_FULL "Windows Server 2025" /* Microsoft Hyper-V */ #define STR_OS_HYPER_V "winHyperV" #define STR_OS_HYPER_V_FULL "Hyper-V Server" /* Windows Future/Unknown */ #define STR_OS_WIN_UNKNOWN "windowsUnknown" #define STR_OS_WIN_UNKNOWN_X64 STR_OS_WIN_UNKNOWN STR_OS_64BIT_SUFFIX #define STR_OS_WIN_UNKNOWN_GENERIC "Windows Unknown" /* Modifiers for Windows Vista, Windows Server 2008, and later. */ #define STR_OS_WIN_32_BIT_EXTENSION ", 32-bit" #define STR_OS_WIN_64_BIT_EXTENSION ", 64-bit" /* FreeBSD */ #define STR_OS_FREEBSD "freeBSD" /* Solaris */ #define STR_OS_SOLARIS "solaris" /* Netware */ #define STR_OS_NETWARE "netware" /* Mac OS */ #define STR_OS_MACOS "darwin" #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/guest_os_tables.h000066400000000000000000001042501470176644300260470ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _GUEST_OS_TABLES_H_ #define _GUEST_OS_TABLES_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #if defined(__cplusplus) extern "C" { #endif /* * Unless explicitly specified (i.e. _ARM_), all guests are assumed to be * Intel architecture. */ #define GUEST_OS_TYPE_GEN \ GOT(GUEST_OS_ANY) \ GOT(GUEST_OS_DOS) \ GOT(GUEST_OS_WIN31) \ GOT(GUEST_OS_WIN95) \ GOT(GUEST_OS_WIN98) \ GOT(GUEST_OS_WINME) \ GOT(GUEST_OS_WINNT) \ GOT(GUEST_OS_WIN2000) \ GOT(GUEST_OS_WINXP) \ GOT(GUEST_OS_WINXPPRO_64) \ GOT(GUEST_OS_WINNET) \ GOT(GUEST_OS_WINNET_64) \ GOT(GUEST_OS_LONGHORN) \ GOT(GUEST_OS_LONGHORN_64) \ GOT(GUEST_OS_WINVISTA) \ GOT(GUEST_OS_WINVISTA_64) \ GOT(GUEST_OS_WIN_7) /* Windows 7 32-bit */ \ GOT(GUEST_OS_WIN_7_64) /* Windows 7 64-bit */ \ GOT(GUEST_OS_WIN_8) /* Windows 8 32-bit */ \ GOT(GUEST_OS_WIN_8_64) /* Windows 8 64-bit */ \ GOT(GUEST_OS_WIN_10) /* Windows 10 32-bit */ \ GOT(GUEST_OS_WIN_10_64) /* Windows 10 64-bit */ \ GOT(GUEST_OS_WIN_10_ARM_64) /* Windows 10 Arm 64-bit */ \ GOT(GUEST_OS_WIN_11_64) /* Windows 11 64-bit */ \ GOT(GUEST_OS_WIN_11_ARM_64) /* Windows 11 Arm 64-bit */ \ GOT(GUEST_OS_WIN_12_64) /* Windows 12 64-bit */ \ GOT(GUEST_OS_WIN_12_ARM_64) /* Windows 12 Arm 64-bit */ \ GOT(GUEST_OS_WIN2008R2_64) /* Server 2008 R2 64-bit */ \ GOT(GUEST_OS_WIN_8_SERVER_64) /* Windows 8 Server 64-bit */ \ GOT(GUEST_OS_WIN_2016SRV_64) /* Windows Server 2016 64-bit */ \ GOT(GUEST_OS_WIN_2019SRV_64) /* Windows Server 2019 64-bit */ \ GOT(GUEST_OS_WIN_2022SRV_64) /* Windows Server 2022 64-bit */ \ GOT(GUEST_OS_WIN_2025SRV_64) /* Windows Server 2025 64-bit */ \ GOT(GUEST_OS_HYPER_V) /* Microsoft Hyper-V */ \ GOT(GUEST_OS_OS2) \ GOT(GUEST_OS_ECOMSTATION) /* OS/2 variant; 1.x */ \ GOT(GUEST_OS_ECOMSTATION2) /* OS/2 variant; 2.x */ \ GOT(GUEST_OS_OTHERLINUX) \ GOT(GUEST_OS_OTHERLINUX_64) \ GOT(GUEST_OS_OTHER24XLINUX) \ GOT(GUEST_OS_OTHER24XLINUX_64) \ GOT(GUEST_OS_OTHER26XLINUX) \ GOT(GUEST_OS_OTHER26XLINUX_64) \ GOT(GUEST_OS_OTHER3XLINUX) /* Linux 3.x 32-bit */ \ GOT(GUEST_OS_OTHER3XLINUX_64) /* Linux 3.x 64-bit */ \ GOT(GUEST_OS_OTHER4XLINUX) /* Linux 4.x 32-bit */ \ GOT(GUEST_OS_OTHER4XLINUX_64) /* Linux 4.x 64-bit */ \ GOT(GUEST_OS_OTHER5XLINUX) /* Linux 5.x 32-bit */ \ GOT(GUEST_OS_OTHER5XLINUX_64) /* Linux 5.x 64-bit */ \ GOT(GUEST_OS_OTHER5XLINUX_ARM_64) /* Linux 5.x Arm 64-bit */ \ GOT(GUEST_OS_OTHER6XLINUX) /* Linux 6.x 32-bit */ \ GOT(GUEST_OS_OTHER6XLINUX_64) /* Linux 6.x 64-bit */ \ GOT(GUEST_OS_OTHER6XLINUX_ARM_64) /* Linux 6.x Arm 64-bit */ \ GOT(GUEST_OS_OTHER7XLINUX) /* Linux 7.x and later 32-bit */ \ GOT(GUEST_OS_OTHER7XLINUX_64) /* Linux 7.x and later 64-bit */ \ GOT(GUEST_OS_OTHER7XLINUX_ARM_64) /* Linux 7.x and later Arm 64-bit */ \ GOT(GUEST_OS_OTHER) /* Other 32-bit */ \ GOT(GUEST_OS_OTHER_64) /* Other 64-bit */ \ GOT(GUEST_OS_OTHER_ARM_64) /* Other Arm 64-bit */ \ GOT(GUEST_OS_UBUNTU) \ GOT(GUEST_OS_UBUNTU_64) \ GOT(GUEST_OS_UBUNTU_ARM_64) \ GOT(GUEST_OS_DEBIAN) \ GOT(GUEST_OS_DEBIAN_64) \ GOT(GUEST_OS_DEBIAN_ARM_64) \ GOT(GUEST_OS_RHEL) \ GOT(GUEST_OS_RHEL_64) \ GOT(GUEST_OS_RHEL9_64) \ GOT(GUEST_OS_RHEL9_ARM_64) \ GOT(GUEST_OS_RHEL10_64) \ GOT(GUEST_OS_RHEL10_ARM_64) \ GOT(GUEST_OS_FREEBSD) \ GOT(GUEST_OS_FREEBSD_64) \ GOT(GUEST_OS_FREEBSD11) \ GOT(GUEST_OS_FREEBSD11_64) \ GOT(GUEST_OS_FREEBSD12) \ GOT(GUEST_OS_FREEBSD12_64) \ GOT(GUEST_OS_FREEBSD13) \ GOT(GUEST_OS_FREEBSD13_64) \ GOT(GUEST_OS_FREEBSD13_ARM_64) \ GOT(GUEST_OS_FREEBSD14) \ GOT(GUEST_OS_FREEBSD14_64) \ GOT(GUEST_OS_FREEBSD14_ARM_64) \ GOT(GUEST_OS_FREEBSD15) \ GOT(GUEST_OS_FREEBSD15_64) \ GOT(GUEST_OS_FREEBSD15_ARM_64) \ GOT(GUEST_OS_SOLARIS_6_AND_7) \ GOT(GUEST_OS_SOLARIS8) \ GOT(GUEST_OS_SOLARIS9) \ GOT(GUEST_OS_SOLARIS10) \ GOT(GUEST_OS_SOLARIS10_64) \ GOT(GUEST_OS_SOLARIS11_64) \ GOT(GUEST_OS_DARWIN9) /* Mac OS 10.5 */ \ GOT(GUEST_OS_DARWIN9_64) \ GOT(GUEST_OS_DARWIN10) /* Mac OS 10.6 */ \ GOT(GUEST_OS_DARWIN10_64) \ GOT(GUEST_OS_DARWIN11) /* Mac OS 10.7 */ \ GOT(GUEST_OS_DARWIN11_64) \ GOT(GUEST_OS_DARWIN12_64) /* Mac OS 10.8 */ \ GOT(GUEST_OS_DARWIN13_64) /* Mac OS 10.9 */ \ GOT(GUEST_OS_DARWIN14_64) /* Mac OS 10.10 */ \ GOT(GUEST_OS_DARWIN15_64) /* Mac OS 10.11 */ \ GOT(GUEST_OS_DARWIN16_64) /* Mac OS 10.12 */ \ GOT(GUEST_OS_DARWIN17_64) /* Mac OS 10.13 */ \ GOT(GUEST_OS_DARWIN18_64) /* Mac OS 10.14 */ \ GOT(GUEST_OS_DARWIN19_64) /* Mac OS 10.15 */ \ GOT(GUEST_OS_DARWIN20_64) /* Mac OS 11 */ \ GOT(GUEST_OS_DARWIN21_64) /* Mac OS 12 */ \ GOT(GUEST_OS_DARWIN22_64) /* Mac OS 13 */ \ GOT(GUEST_OS_DARWIN23_64) /* Mac OS 14 */ \ GOT(GUEST_OS_DARWIN24_64) /* Mac OS 15 */ \ GOT(GUEST_OS_OPENSERVER_5_AND_6) \ GOT(GUEST_OS_UNIXWARE7) \ GOT(GUEST_OS_NETWARE4) \ GOT(GUEST_OS_NETWARE5) \ GOT(GUEST_OS_NETWARE6) \ GOT(GUEST_OS_VMKERNEL) /* ESX 4.x 64-bit */ \ GOT(GUEST_OS_VMKERNEL5) /* ESX 5.x 64-bit */ \ GOT(GUEST_OS_VMKERNEL6) /* ESX 6 64-bit */ \ GOT(GUEST_OS_VMKERNEL65) /* ESX 6.5 and 6.7 64-bit */ \ GOT(GUEST_OS_VMKERNEL7) /* ESX 7 64-bit */ \ GOT(GUEST_OS_VMKERNEL7_ARM) /* ESX 7 Arm 64-bit */ \ GOT(GUEST_OS_VMKERNEL8) /* ESX 8 64-bit */ \ GOT(GUEST_OS_VMKERNEL8_ARM) /* ESX 8 Arm 64-bit */ \ GOT(GUEST_OS_VMKERNEL9) /* ESX 9 and later 64-bit */ \ GOT(GUEST_OS_VMKERNEL9_ARM) /* ESX 9 and later Arm 64-bit */ \ GOT(GUEST_OS_PHOTON_64) /* VMware Photon 64-bit */ \ GOT(GUEST_OS_PHOTON_ARM_64) /* VMware Photon Arm 64-bit */ \ GOT(GUEST_OS_ORACLE) \ GOT(GUEST_OS_ORACLE_64) \ GOT(GUEST_OS_ORACLE6) \ GOT(GUEST_OS_ORACLE6_64) \ GOT(GUEST_OS_ORACLE7_64) \ GOT(GUEST_OS_ORACLE8_64) \ GOT(GUEST_OS_ORACLE9_64) \ GOT(GUEST_OS_ORACLE10_64) \ GOT(GUEST_OS_CENTOS) \ GOT(GUEST_OS_CENTOS_64) \ GOT(GUEST_OS_CENTOS6) \ GOT(GUEST_OS_CENTOS6_64) \ GOT(GUEST_OS_CENTOS7_64) \ GOT(GUEST_OS_CENTOS8_64) \ GOT(GUEST_OS_CENTOS9_64) \ GOT(GUEST_OS_AMAZONLINUX2_64) \ GOT(GUEST_OS_AMAZONLINUX3_64) \ GOT(GUEST_OS_CRXSYS1_64) /* VMware CRX system VM 1.0 64-bit */ \ GOT(GUEST_OS_CRXSYS1_ARM_64) /* VMware CRX system VM 1.0 Arm 64-bit */ \ GOT(GUEST_OS_CRXSYS2_64) /* VMware CRX system VM 2.0 64-bit */ \ GOT(GUEST_OS_CRXSYS2_ARM_64) /* VMware CRX system VM 2.0 Arm 64-bit */ \ GOT(GUEST_OS_CRXPOD1_64) /* VMware CRX pod VM 1.0 64-bit */ \ GOT(GUEST_OS_CRXPOD1_ARM_64) /* VMware CRX pod VM 1.0 Arm 64-bit */ \ GOT(GUEST_OS_LINUX_MINT_64) \ GOT(GUEST_OS_ROCKY_LINUX_64) \ GOT(GUEST_OS_ROCKY_LINUX_ARM_64) \ GOT(GUEST_OS_ALMA_LINUX_64) \ GOT(GUEST_OS_ALMA_LINUX_ARM_64) \ GOT(GUEST_OS_PROLINUX_64) \ GOT(GUEST_OS_PARDUS_64) /* * Mappings between VIM guest OS keys and the rest of the civilized world. * * Format: GOKM(vmxKey, vimKey, reversible) */ #define GUEST_OS_KEY_MAP \ /* Windows guests */ \ GOKM("win31", win31Guest, TRUE) \ GOKM("win95", win95Guest, TRUE) \ GOKM("win98", win98Guest, TRUE) \ GOKM("winMe", winMeGuest, TRUE) \ GOKM("winNT", winNTGuest, TRUE) \ GOKM("nt4", winNTGuest, FALSE) \ GOKM("win2000", win2000ProGuest, FALSE) \ GOKM("win2000Pro", win2000ProGuest, TRUE) \ GOKM("win2000Serv", win2000ServGuest, TRUE) \ GOKM("win2000AdvServ", win2000AdvServGuest, TRUE) \ GOKM("winXPHome", winXPHomeGuest, TRUE) \ GOKM("whistler", winXPHomeGuest, FALSE) \ GOKM("winXPPro", winXPProGuest, TRUE) \ GOKM("winXPPro-64", winXPPro64Guest, TRUE) \ GOKM("winNetWeb", winNetWebGuest, TRUE) \ GOKM("winNetStandard", winNetStandardGuest, TRUE) \ GOKM("winNetEnterprise", winNetEnterpriseGuest, TRUE) \ GOKM("winNetDatacenter", winNetDatacenterGuest, TRUE) \ GOKM("winNetBusiness", winNetBusinessGuest, TRUE) \ GOKM("winNetStandard-64", winNetStandard64Guest, TRUE) \ GOKM("winNetEnterprise-64", winNetEnterprise64Guest, TRUE) \ GOKM("winNetDatacenter-64", winNetDatacenter64Guest, TRUE) \ GOKM("longhorn", winLonghornGuest, TRUE) \ GOKM("longhorn-64", winLonghorn64Guest, TRUE) \ GOKM("winvista", winVistaGuest, TRUE) \ GOKM("winvista-64", winVista64Guest, TRUE) \ GOKM("windows7", windows7Guest, TRUE) \ GOKM("windows7-64", windows7_64Guest, TRUE) \ GOKM("windows7srv-64", windows7Server64Guest, TRUE) \ GOKM("windows8", windows8Guest, TRUE) \ GOKM("windows8-64", windows8_64Guest, TRUE) \ GOKM("windows8srv-64", windows8Server64Guest, TRUE) \ GOKM("windows9", windows9Guest, TRUE) \ GOKM("windows9-64", windows9_64Guest, TRUE) \ GOKM("windows11-64", windows11_64Guest, TRUE) \ GOKM("windows12-64", windows12_64Guest, TRUE) \ GOKM("windows9srv-64", windows9Server64Guest, TRUE) \ GOKM("windows2019srv-64", windows2019srv_64Guest, TRUE) \ GOKM("windows2019srvNext-64", windows2019srvNext_64Guest, TRUE) \ GOKM("windows2022srvNext-64", windows2022srvNext_64Guest, TRUE) \ GOKM("winHyperV", windowsHyperVGuest, TRUE) \ GOKM("winServer2008Cluster-32", winLonghornGuest, FALSE) \ GOKM("winServer2008Datacenter-32", winLonghornGuest, FALSE) \ GOKM("winServer2008DatacenterCore-32", winLonghornGuest, FALSE) \ GOKM("winServer2008Enterprise-32", winLonghornGuest, FALSE) \ GOKM("winServer2008EnterpriseCore-32", winLonghornGuest, FALSE) \ GOKM("winServer2008EnterpriseItanium-32", winLonghornGuest, FALSE) \ GOKM("winServer2008SmallBusiness-32", winLonghornGuest, FALSE) \ GOKM("winServer2008SmallBusinessPremium-32", winLonghornGuest, FALSE) \ GOKM("winServer2008Standard-32", winLonghornGuest, FALSE) \ GOKM("winServer2008StandardCore-32", winLonghornGuest, FALSE) \ GOKM("winServer2008MediumManagement-32", winLonghornGuest, FALSE) \ GOKM("winServer2008MediumMessaging-32", winLonghornGuest, FALSE) \ GOKM("winServer2008MediumSecurity-32", winLonghornGuest, FALSE) \ GOKM("winServer2008ForSmallBusiness-32", winLonghornGuest, FALSE) \ GOKM("winServer2008StorageEnterprise-32", winLonghornGuest, FALSE) \ GOKM("winServer2008StorageExpress-32", winLonghornGuest, FALSE) \ GOKM("winServer2008StorageStandard-32", winLonghornGuest, FALSE) \ GOKM("winServer2008StorageWorkgroup-32", winLonghornGuest, FALSE) \ GOKM("winServer2008Web-32", winLonghornGuest, FALSE) \ GOKM("winServer2008Cluster-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008Datacenter-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008DatacenterCore-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008Enterprise-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008EnterpriseCore-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008EnterpriseItanium-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008SmallBusiness-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008SmallBusinessPremium-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008Standard-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008StandardCore-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008MediumManagement-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008MediumMessaging-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008MediumSecurity-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008ForSmallBusiness-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008StorageEnterprise-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008StorageExpress-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008StorageStandard-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008StorageWorkgroup-64", winLonghorn64Guest, FALSE) \ GOKM("winServer2008Web-64", winLonghorn64Guest, FALSE) \ GOKM("winVistaUltimate-32", winVistaGuest, FALSE) \ GOKM("winVistaHomePremium-32", winVistaGuest, FALSE) \ GOKM("winVistaHomeBasic-32", winVistaGuest, FALSE) \ GOKM("winVistaEnterprise-32", winVistaGuest, FALSE) \ GOKM("winVistaBusiness-32", winVistaGuest, FALSE) \ GOKM("winVistaStarter-32", winVistaGuest, FALSE) \ GOKM("winVistaUltimate-64", winVista64Guest, FALSE) \ GOKM("winVistaHomePremium-64", winVista64Guest, FALSE) \ GOKM("winVistaHomeBasic-64", winVista64Guest, FALSE) \ GOKM("winVistaEnterprise-64", winVista64Guest, FALSE) \ GOKM("winVistaBusiness-64", winVista64Guest, FALSE) \ GOKM("winVistaStarter-64", winVista64Guest, FALSE) \ /* Linux guests */ \ GOKM("redhat", redhatGuest, TRUE) \ GOKM("rhel2", rhel2Guest, TRUE) \ GOKM("rhel3", rhel3Guest, TRUE) \ GOKM("rhel3-64", rhel3_64Guest, TRUE) \ GOKM("rhel4", rhel4Guest, TRUE) \ GOKM("rhel4-64", rhel4_64Guest, TRUE) \ GOKM("rhel5", rhel5Guest, TRUE) \ GOKM("rhel5-64", rhel5_64Guest, TRUE) \ GOKM("rhel6", rhel6Guest, TRUE) \ GOKM("rhel6-64", rhel6_64Guest, TRUE) \ GOKM("rhel7", rhel7Guest, TRUE) \ GOKM("rhel7-64", rhel7_64Guest, TRUE) \ GOKM("rhel8-64", rhel8_64Guest, TRUE) \ GOKM("rhel9-64", rhel9_64Guest, TRUE) \ GOKM("rhel10-64", rhel10_64Guest, TRUE) \ GOKM("centos", centosGuest, TRUE) \ GOKM("centos-64", centos64Guest, TRUE) \ GOKM("centos6", centos6Guest, TRUE) \ GOKM("centos6-64", centos6_64Guest, TRUE) \ GOKM("centos7", centos7Guest, FALSE) \ GOKM("centos7-64", centos7_64Guest, TRUE) \ GOKM("centos8-64", centos8_64Guest, TRUE) \ GOKM("centos9-64", centos9_64Guest, TRUE) \ GOKM("oraclelinux", oracleLinuxGuest, TRUE) \ GOKM("oraclelinux-64", oracleLinux64Guest, TRUE) \ GOKM("oraclelinux6", oracleLinux6Guest, TRUE) \ GOKM("oraclelinux6-64", oracleLinux6_64Guest, TRUE) \ GOKM("oraclelinux7", oracleLinux7Guest, FALSE) \ GOKM("oraclelinux7-64", oracleLinux7_64Guest, TRUE) \ GOKM("oraclelinux8-64", oracleLinux8_64Guest, TRUE) \ GOKM("oraclelinux9-64", oracleLinux9_64Guest, TRUE) \ GOKM("oraclelinux10-64", oracleLinux10_64Guest, TRUE) \ GOKM("suse", suseGuest, TRUE) \ GOKM("suse-64", suse64Guest, TRUE) \ GOKM("sles", slesGuest, TRUE) \ GOKM("sles-64", sles64Guest, TRUE) \ GOKM("sles10", sles10Guest, TRUE) \ GOKM("sles10-64", sles10_64Guest, TRUE) \ GOKM("sles11", sles11Guest, TRUE) \ GOKM("sles11-64", sles11_64Guest, TRUE) \ GOKM("sles12", sles12Guest, TRUE) \ GOKM("sles12-64", sles12_64Guest, TRUE) \ GOKM("sles15-64", sles15_64Guest, TRUE) \ GOKM("sles16-64", sles16_64Guest, TRUE) \ GOKM("mandrake", mandrakeGuest, TRUE) \ GOKM("mandrake-64", mandriva64Guest, FALSE) \ GOKM("mandriva", mandrivaGuest, TRUE) \ GOKM("mandriva-64", mandriva64Guest, TRUE) \ GOKM("turbolinux", turboLinuxGuest, TRUE) \ GOKM("turbolinux-64", turboLinux64Guest, TRUE) \ GOKM("ubuntu", ubuntuGuest, TRUE) \ GOKM("ubuntu-64", ubuntu64Guest, TRUE) \ GOKM("debian4", debian4Guest, TRUE) \ GOKM("debian4-64", debian4_64Guest, TRUE) \ GOKM("debian5", debian5Guest, TRUE) \ GOKM("debian5-64", debian5_64Guest, TRUE) \ GOKM("debian6", debian6Guest, TRUE) \ GOKM("debian6-64", debian6_64Guest, TRUE) \ GOKM("debian7", debian7Guest, TRUE) \ GOKM("debian7-64", debian7_64Guest, TRUE) \ GOKM("debian8", debian8Guest, TRUE) \ GOKM("debian8-64", debian8_64Guest, TRUE) \ GOKM("debian9", debian9Guest, TRUE) \ GOKM("debian9-64", debian9_64Guest, TRUE) \ GOKM("debian10", debian10Guest, TRUE) \ GOKM("debian10-64", debian10_64Guest, TRUE) \ GOKM("debian11", debian11Guest, TRUE) \ GOKM("debian11-64", debian11_64Guest, TRUE) \ GOKM("debian12", debian12Guest, TRUE) \ GOKM("debian12-64", debian12_64Guest, TRUE) \ GOKM("debian13", debian13Guest, TRUE) \ GOKM("debian13-64", debian13_64Guest, TRUE) \ GOKM("asianux3", asianux3Guest, TRUE) \ GOKM("asianux3-64", asianux3_64Guest, TRUE) \ GOKM("asianux4", asianux4Guest, TRUE) \ GOKM("asianux4-64", asianux4_64Guest, TRUE) \ GOKM("asianux5-64", asianux5_64Guest, TRUE) \ GOKM("asianux7-64", asianux7_64Guest, TRUE) \ GOKM("asianux8-64", asianux8_64Guest, TRUE) \ GOKM("asianux9-64", asianux9_64Guest, TRUE) \ GOKM("nld9", nld9Guest, TRUE) \ GOKM("oes", oesGuest, TRUE) \ GOKM("sjds", sjdsGuest, TRUE) \ GOKM("opensuse", opensuseGuest, TRUE) \ GOKM("opensuse-64", opensuse64Guest, TRUE) \ GOKM("fedora", fedoraGuest, TRUE) \ GOKM("fedora-64", fedora64Guest, TRUE) \ GOKM("coreos-64", coreos64Guest, TRUE) \ GOKM("vmware-photon-64", vmwarePhoton64Guest, TRUE) \ GOKM("other24xlinux", other24xLinuxGuest, TRUE) \ GOKM("other24xlinux-64", other24xLinux64Guest, TRUE) \ GOKM("other26xlinux", other26xLinuxGuest, TRUE) \ GOKM("other26xlinux-64", other26xLinux64Guest, TRUE) \ GOKM("other3xlinux", other3xLinuxGuest, TRUE) \ GOKM("other3xlinux-64", other3xLinux64Guest, TRUE) \ GOKM("other4xlinux", other4xLinuxGuest, TRUE) \ GOKM("other4xlinux-64", other4xLinux64Guest, TRUE) \ GOKM("other5xlinux", other5xLinuxGuest, TRUE) \ GOKM("other5xlinux-64", other5xLinux64Guest, TRUE) \ GOKM("other6xlinux", other6xLinuxGuest, TRUE) \ GOKM("other6xlinux-64", other6xLinux64Guest, TRUE) \ GOKM("other7xlinux", other7xLinuxGuest, TRUE) \ GOKM("other7xlinux-64", other7xLinux64Guest, TRUE) \ GOKM("linux", otherLinuxGuest, FALSE) \ GOKM("otherlinux", otherLinuxGuest, TRUE) \ GOKM("otherlinux-64", otherLinux64Guest, TRUE) \ GOKM("genericlinux", genericLinuxGuest, TRUE) \ GOKM("amazonlinux2-64", amazonlinux2_64Guest, TRUE) \ GOKM("amazonlinux3-64", amazonlinux3_64Guest, TRUE) \ GOKM("almalinux-64", almalinux_64Guest, TRUE) \ GOKM("rockylinux-64", rockylinux_64Guest, TRUE) \ GOKM("CRXPod1-64", crxPod1Guest, TRUE) \ GOKM("CRXSys1-64", crxSys1Guest, TRUE) \ /* Netware guests */ \ GOKM("netware4", netware4Guest, TRUE) \ GOKM("netware5", netware5Guest, TRUE) \ GOKM("netware6", netware6Guest, TRUE) \ /* Solaris guests */ \ GOKM("solaris6", solaris6Guest, TRUE) \ GOKM("solaris7", solaris7Guest, TRUE) \ GOKM("solaris8", solaris8Guest, TRUE) \ GOKM("solaris9", solaris9Guest, TRUE) \ GOKM("solaris10", solaris10Guest, TRUE) \ GOKM("solaris10-64", solaris10_64Guest, TRUE) \ GOKM("solaris11-64", solaris11_64Guest, TRUE) \ /* macOS guests */ \ GOKM("darwin", darwinGuest, TRUE) \ GOKM("darwin-64", darwin64Guest, TRUE) \ GOKM("darwin10", darwin10Guest, TRUE) \ GOKM("darwin10-64", darwin10_64Guest, TRUE) \ GOKM("darwin11", darwin11Guest, TRUE) \ GOKM("darwin11-64", darwin11_64Guest, TRUE) \ GOKM("darwin12-64", darwin12_64Guest, TRUE) \ GOKM("darwin13-64", darwin13_64Guest, TRUE) \ GOKM("darwin14-64", darwin14_64Guest, TRUE) \ GOKM("darwin15-64", darwin15_64Guest, TRUE) \ GOKM("darwin16-64", darwin16_64Guest, TRUE) \ GOKM("darwin17-64", darwin17_64Guest, TRUE) \ GOKM("darwin18-64", darwin18_64Guest, TRUE) \ GOKM("darwin19-64", darwin19_64Guest, TRUE) \ GOKM("darwin20-64", darwin20_64Guest, TRUE) \ GOKM("darwin21-64", darwin21_64Guest, TRUE) \ GOKM("darwin22-64", darwin22_64Guest, TRUE) \ GOKM("darwin23-64", darwin23_64Guest, TRUE) \ /* ESX guests */ \ GOKM("vmkernel", vmkernelGuest, TRUE) \ GOKM("vmkernel5", vmkernel5Guest, TRUE) \ GOKM("vmkernel6", vmkernel6Guest, TRUE) \ GOKM("vmkernel65", vmkernel65Guest, TRUE) \ GOKM("vmkernel7", vmkernel7Guest, TRUE) \ GOKM("vmkernel8", vmkernel8Guest, TRUE) \ /* Other guests */ \ GOKM("dos", dosGuest, TRUE) \ GOKM("os2", os2Guest, TRUE) \ GOKM("os2experimental", os2Guest, FALSE) \ GOKM("eComStation", eComStationGuest, TRUE) \ GOKM("eComStation2", eComStation2Guest, TRUE) \ GOKM("freeBSD", freebsdGuest, TRUE) \ GOKM("freeBSD-64", freebsd64Guest, TRUE) \ GOKM("freeBSD11", freebsd11Guest, TRUE) \ GOKM("freeBSD11-64", freebsd11_64Guest, TRUE) \ GOKM("freeBSD12", freebsd12Guest, TRUE) \ GOKM("freeBSD12-64", freebsd12_64Guest, TRUE) \ GOKM("freeBSD13", freebsd13Guest, TRUE) \ GOKM("freeBSD13-64", freebsd13_64Guest, TRUE) \ GOKM("freeBSD14", freebsd14Guest, TRUE) \ GOKM("freeBSD14-64", freebsd14_64Guest, TRUE) \ GOKM("freeBSD15", freebsd15Guest, TRUE) \ GOKM("freeBSD15-64", freebsd15_64Guest, TRUE) \ GOKM("openserver5", openServer5Guest, TRUE) \ GOKM("openserver6", openServer6Guest, TRUE) \ GOKM("unixware7", unixWare7Guest, TRUE) \ GOKM("other", otherGuest, TRUE) \ GOKM("other-64", otherGuest64, TRUE) \ #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hashMap.h000066400000000000000000000057011470176644300242470ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #ifndef _HASHMAP_H_ #define _HASHMAP_H_ #include #ifdef VMX86_SERVER #include "aioMgr.h" #endif #if defined(__cplusplus) extern "C" { #endif typedef struct HashMap HashMap; /* * ---------------------------------------------------------------------------- * * HashMapIteratorFn -- * * A function pointer definition that should be passed to HashMap_Iterate, * it will be called for all entries in the hashmap. The key and data will * be set appropriately and the user data pointer will be passed untouched * from the HashMap_Iterate call. * * Results: * void * * Side Effects: * Implementation dependent. * * ---------------------------------------------------------------------------- */ typedef void (* HashMapIteratorFn)(void *key, void *data, void *userData); HashMap *HashMap_AllocMap(uint32 numEntries, size_t keySize, size_t dataSize); HashMap *HashMap_AllocMapAlpha(uint32 numEntries, uint32 alpha, size_t keySize, size_t dataSize); void HashMap_DestroyMap(HashMap *map); Bool HashMap_Put(HashMap *map, const void *key, const void *data); void *HashMap_Get(HashMap *map, const void *key); void *HashMap_ConstTimeGet(struct HashMap *map, const void *key); void HashMap_Clear(HashMap *map); Bool HashMap_Remove(HashMap *map, const void *key); uint32 HashMap_Count(HashMap *map); void HashMap_Iterate(HashMap* map, HashMapIteratorFn mapFn, Bool clear, void *userData); Bool HashMap_DoTests(void); #if defined(__cplusplus) } // extern "C" #endif #endif /* _HASHMAP_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hashTable.h000066400000000000000000000136661470176644300245720ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2017,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hashTable.h -- * * Hash table. */ #ifndef _HASH_TABLE_H_ #define _HASH_TABLE_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_defs.h" #include "vm_atomic.h" #if defined(__cplusplus) extern "C" { #endif typedef struct HashTable HashTable; typedef struct PtrHashTable PtrHashTable; typedef void (*HashTableFreeEntryFn)(void *clientData); typedef int (*HashTableForEachCallback)(const char *key, void *value, void *clientData); #define HASH_STRING_KEY 0 // case-sensitive string key #define HASH_ISTRING_KEY 1 // case-insensitive string key #define HASH_INT_KEY 2 // uintptr_t or pointer key /* * The flag bits are ored into the type field. * Atomic hash tables only support insert, lookup, and replace. */ #define HASH_TYPE_MASK 7 #define HASH_FLAG_MASK (~HASH_TYPE_MASK) #define HASH_FLAG_ATOMIC 0x08 // thread-safe hash table #define HASH_FLAG_COPYKEY 0x10 // copy string key HashTable * HashTable_Alloc(uint32 numEntries, // IN: int keyType, // IN: HashTableFreeEntryFn fn); // IN/OPT: HashTable * HashTable_AllocOnce(Atomic_Ptr *var, // IN/OUT: uint32 numEntries, // IN: int keyType, // IN: HashTableFreeEntryFn fn); // IN/OPT: void HashTable_Free(HashTable *hashTable); // IN/OUT: void HashTable_FreeUnsafe(HashTable *hashTable); // IN/OUT: Bool HashTable_Insert(HashTable *hashTable, // IN/OUT: const void *keyStr, // IN: void *clientData); // IN/OPT: Bool HashTable_Lookup(const HashTable *hashTable, // IN: const void *keyStr, // IN: void **clientData); // OUT/OPT: void * HashTable_LookupOrInsert(HashTable *hashTable, // IN/OUT: const void *keyStr, // IN: void *clientData); // IN/OPT: Bool HashTable_ReplaceOrInsert(HashTable *hashTable, // IN/OUT: const void *keyStr, // IN: void *clientData); // IN/OPT Bool HashTable_ReplaceIfEqual(HashTable *hashTable, // IN/OUT: const void *keyStr, // IN: void *oldClientData, // IN/OPT void *newClientData); // IN/OPT Bool HashTable_Delete(HashTable *hashTable, // IN/OUT: const void *keyStr); // IN: Bool HashTable_LookupAndDelete(HashTable *hashTable, // IN/OUT: const void *keyStr, // IN: void **clientData); // OUT: void HashTable_Clear(HashTable *ht); // IN/OUT: void HashTable_ToArray(const HashTable *ht, // IN: void ***clientDatas, // OUT: size_t *size); // OUT: void HashTable_KeyArray(const HashTable *ht, // IN: const void ***keys, // OUT: size_t *size); // OUT: size_t HashTable_GetNumElements(const HashTable *ht); // IN: int HashTable_ForEach(const HashTable *ht, // IN: HashTableForEachCallback cb, // IN: void *clientData); // IN: /* * Specialize hash table that uses the callers data structure as its * hash entry as well, the hash key being an address that must be unique. */ typedef struct PtrHashEntry { struct PtrHashEntry *next; void *ptr; } PtrHashEntry; /* * PTRHASH_CONTAINER - get the struct for this entry (like PtrHashEntry) * @ptr: the &struct PtrHashEntry pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list struct within the struct. */ #define PTRHASH_CONTAINER(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member))) typedef int (*PtrHashForEachCallback)(PtrHashEntry *entry, const void *clientData); PtrHashTable *PtrHash_Alloc(uint32 numBuckets); void PtrHash_Free(PtrHashTable *hashTable); size_t PtrHash_AllocSize(PtrHashTable *ht); size_t PtrHash_GetNumElements(const PtrHashTable *ht); int PtrHash_ForEach(const PtrHashTable *ht, PtrHashForEachCallback cb, const void *clientData); PtrHashEntry *PtrHash_Lookup(const PtrHashTable *hashTable, const void *keyPtr); PtrHashEntry *PtrHash_LookupAndDelete(PtrHashTable *hashTable, const void *keyPtr); Bool PtrHash_Insert(PtrHashTable *hashTable, PtrHashEntry *entry); Bool PtrHash_Delete(PtrHashTable *hashTable, const void *keyPtr); #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfs.h000066400000000000000000000276261470176644300236270ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfs.h -- * * Header file for public common data types used in the VMware * Host/Guest File System (hgfs). * * This file is included by hgfsProto.h, which defines message formats * used in the hgfs protocol, and by hgfsDev.h, which defines the * interface between the kernel and the hgfs pserver. [bac] */ #ifndef _HGFS_H_ #define _HGFS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #include "includeCheck.h" #ifdef VMX86_TOOLS # include "rpcvmx.h" #else # include "config.h" #endif #include "vm_assert.h" /* Page size for HGFS packet (4K). */ #define HGFS_PAGE_SIZE 4096 /* * Maximum allowed header size in bytes. */ #define HGFS_HEADER_SIZE_MAX 2048 /* * Maximum number of pages to transfer to/from the HGFS server for V3 protocol * operations that support large requests/replies, e.g. reads and writes. */ #define HGFS_LARGE_IO_MAX_PAGES 127 /* Maximum number of bytes to read or write to a hgfs server in a single packet. */ #define HGFS_IO_MAX HGFS_PAGE_SIZE /* * Maximum allowed packet size in bytes. All hgfs code should be made * safe with respect to this limit. */ #define HGFS_PACKET_MAX 6144 /* Maximum number of bytes to read or write to a V3 server in a single hgfs packet. */ #define HGFS_LARGE_IO_MAX (HGFS_PAGE_SIZE * HGFS_LARGE_IO_MAX_PAGES) /* * The HGFS_LARGE_PACKET_MAX size is used to allow guests to make * read / write requests of sizes larger than HGFS_PACKET_MAX. The larger size * can only be used with server operations that are specified to be large packet * capable in hgfsProto.h. */ #define HGFS_LARGE_PACKET_MAX (HGFS_LARGE_IO_MAX + HGFS_HEADER_SIZE_MAX) /* * Legacy definitions for HGFS_LARGE_IO_MAX_PAGES, HGFS_LARGE_IO_MAX and * HGFS_LARGE_PACKET_MAX. They are used both in Windows client and hgFileCopy * library for performing vmrun CopyFileFromHostToGuest/GuestToHost. */ #define HGFS_LEGACY_LARGE_IO_MAX_PAGES 15 #define HGFS_LEGACY_LARGE_IO_MAX (HGFS_PAGE_SIZE * HGFS_LEGACY_LARGE_IO_MAX_PAGES) #define HGFS_LEGACY_LARGE_PACKET_MAX (HGFS_LEGACY_LARGE_IO_MAX + HGFS_HEADER_SIZE_MAX) static size_t gHgfsLargeIoMax = 0; static size_t gHgfsLargePacketMax = 0; /* *----------------------------------------------------------------------------- * * HgfsLargeIoMax -- * * Gets the maximum number of bytes to read or write to a V3 server in a * single hgfs packet. * By default, a caller should pass useLegacy=FALSE to get its value with the * control of feature switch. Passing useLegacy=TRUE means you want to * directly use the legacy value. * * Results: * Returns the maximum number of bytes to read or write to a V3 server in a * single hgfs packet. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE size_t HgfsLargeIoMax(Bool useLegacy) // IN { if (useLegacy) { return HGFS_LEGACY_LARGE_IO_MAX; } if (gHgfsLargeIoMax > 0) { return gHgfsLargeIoMax; } #ifdef VMX86_TOOLS if (!RpcVMX_ConfigGetBool(TRUE, "hgfs.packetSize.large")) { #else if (!Config_GetBool(TRUE, "hgfs.packetSize.large")) { #endif gHgfsLargeIoMax = HGFS_LEGACY_LARGE_IO_MAX; } else { gHgfsLargeIoMax = HGFS_LARGE_IO_MAX; } return gHgfsLargeIoMax; } /* *----------------------------------------------------------------------------- * * HgfsLargePacketMax -- * * Gets the maximum number of bytes to allow guests to make read / write * requests. * By default, a caller should pass useLegacy=FALSE to get its value with the * control of feature switch. Passing useLegacy=TRUE means you want to * directly use the legacy value. * * Results: * Returns the maximum number of bytes to allow guests to make read / write * requests. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE size_t HgfsLargePacketMax(Bool useLegacy) // IN { if (useLegacy) { return HGFS_LEGACY_LARGE_PACKET_MAX; } if (gHgfsLargePacketMax > 0) { return gHgfsLargePacketMax; } #ifdef VMX86_TOOLS if (!RpcVMX_ConfigGetBool(TRUE, "hgfs.packetSize.large")) { #else if (!Config_GetBool(TRUE, "hgfs.packetSize.large")) { #endif gHgfsLargePacketMax = HGFS_LEGACY_LARGE_PACKET_MAX; } else { gHgfsLargePacketMax = HGFS_LARGE_PACKET_MAX; } return gHgfsLargePacketMax; } /* * File type * * File types, used in HgfsAttr. We support regular files, * directories, and symlinks. * * Changing the order of this enum will break the protocol; new types * should be added at the end. * * * This definition is used in some places that don't include * hgfsProto.h, which is why it is here instead of there. */ typedef enum { HGFS_FILE_TYPE_REGULAR, HGFS_FILE_TYPE_DIRECTORY, HGFS_FILE_TYPE_SYMLINK, } HgfsFileType; /* * Open mode * * These are equivalent to the O_RDONLY, O_WRONLY, O_RDWR open flags * in Unix; they specify which type of access is being requested. These three * modes are mutually exclusive and one is required; all other flags are * modifiers to the mode and must come afterwards as a bitmask. Beware that * HGFS_OPEN_MODE_READ_ONLY contains the value 0 so simply masking another * variable with it to detect its presence is not safe. The _ACCMODES entry in * the enum serves as a bitmask for the others. * * Changing the order of this enum will break stuff. * * This definition is used in some places that don't include * hgfsProto.h, which is why it is here instead of there. */ typedef enum { HGFS_OPEN_MODE_READ_ONLY, HGFS_OPEN_MODE_WRITE_ONLY, HGFS_OPEN_MODE_READ_WRITE, HGFS_OPEN_MODE_ACCMODES, /* You cannot add anything else here. Really. */ } HgfsOpenMode; /* * Open flags. * * Each should be shifted left by HGFS_OPEN_MODE_READ_WRITE plus whatever flag * number they are, starting with zero. * * The sequential flag indicates that reads and writes on this handle should * not seek on each operation; instead, the system's file pointer will be used * so each operation is performed where the last one finished. This flag is * necessary when reading from or writing to non-seekable files (such as procfs * nodes on Linux) but can also lead to inconsistent results if a client shares * a handle amongst several of its callers. This flag should only be used when * the client knows the file is non-seekable and the burden of ensuring file * handles aren't shared falls upon the hgfs client, not the server. */ #define HGFS_OPEN_SEQUENTIAL (1 << HGFS_OPEN_MODE_READ_WRITE) /* Masking helpers. */ #define HGFS_OPEN_MODE_ACCMODE(mode) (mode & HGFS_OPEN_MODE_ACCMODES) #define HGFS_OPEN_MODE_FLAGS(mode) (mode & ~HGFS_OPEN_MODE_ACCMODES) #define HGFS_OPEN_MODE_IS_VALID_MODE(mode) \ (HGFS_OPEN_MODE_ACCMODE(mode) == HGFS_OPEN_MODE_READ_ONLY || \ HGFS_OPEN_MODE_ACCMODE(mode) == HGFS_OPEN_MODE_WRITE_ONLY || \ HGFS_OPEN_MODE_ACCMODE(mode) == HGFS_OPEN_MODE_READ_WRITE) /* * Return status for replies from the server. * * Changing the order of this enum will break the protocol; new status * types should be added at the end. * * This definition is used in some places that don't include * hgfsProto.h, which is why it is here instead of there. * * XXX: So we have a problem here. At some point, HGFS_STATUS_INVALID_NAME was * added to the list of errors. Later, HGFS_STATUS_GENERIC_ERROR was added, but * it was added /before/ HGFS_STATUS_INVALID_NAME. Nobody noticed because the * error codes travelled from hgfsProto.h to hgfs.h in that same change. Worse, * we GA'ed a product (Server 1.0) this way. * * XXX: I've reversed the order because otherwise new HGFS clients working * against WS55-era HGFS servers will think they got HGFS_STATUS_GENERIC_ERROR * when the server sent them HGFS_STATUS_INVALID_NAME. This was a problem * the Linux client converts HGFS_STATUS_GENERIC_ERROR to -EIO, which causes * HgfsLookup to fail unexpectedly (normally HGFS_STATUS_INVALID_NAME is * converted to -ENOENT, an expected result in HgfsLookup). */ typedef enum { HGFS_STATUS_SUCCESS, HGFS_STATUS_NO_SUCH_FILE_OR_DIR, HGFS_STATUS_INVALID_HANDLE, HGFS_STATUS_OPERATION_NOT_PERMITTED, HGFS_STATUS_FILE_EXISTS, HGFS_STATUS_NOT_DIRECTORY, HGFS_STATUS_DIR_NOT_EMPTY, HGFS_STATUS_PROTOCOL_ERROR, HGFS_STATUS_ACCESS_DENIED, HGFS_STATUS_INVALID_NAME, HGFS_STATUS_GENERIC_ERROR, HGFS_STATUS_SHARING_VIOLATION, HGFS_STATUS_NO_SPACE, HGFS_STATUS_OPERATION_NOT_SUPPORTED, HGFS_STATUS_NAME_TOO_LONG, HGFS_STATUS_INVALID_PARAMETER, HGFS_STATUS_NOT_SAME_DEVICE, /* * Following error codes are for V4 and above protocol only. * Server must never retun these codes for legacy clients. */ HGFS_STATUS_STALE_SESSION, HGFS_STATUS_TOO_MANY_SESSIONS, HGFS_STATUS_TRANSPORT_ERROR, } HgfsStatus; /* * HGFS RPC commands * * HGFS servers can run in a variety of places across several different * transport layers. These definitions constitute all known RPC commands. * * For each definition, there is both the server string (the command itself) * as well as a client "prefix", which is the command followed by a space. * This is provided for convenience, since clients will need to copy both * the command and the space into some buffer that is then sent over the * backdoor. * * In Host --> Guest RPC traffic, the host endpoint is TCLO and the guest * endpoint is RpcIn. TCLO is a particularly confusing name choice which dates * back to when the host was to send raw TCL code to the guest (TCL Out == * TCLO). * * In Guest --> Host RPC traffic, the guest endpoint is RpcOut and the host * endpoint is RPCI. */ /* * When an RPCI listener registers for this command, HGFS requests are expected * to be synchronously sent from the guest and replies are expected to be * synchronously returned. * * When an RpcIn listener registers for this command, requests are expected to * be asynchronously sent from the host and synchronously returned from the * guest. * * In short, an endpoint sending this command is sending a request whose reply * should be returned synchronously. */ #define HGFS_SYNC_REQREP_CMD "f" #define HGFS_SYNC_REQREP_CLIENT_CMD HGFS_SYNC_REQREP_CMD " " #define HGFS_SYNC_REQREP_CLIENT_CMD_LEN (sizeof HGFS_SYNC_REQREP_CLIENT_CMD - 1) /* * This is just for the sake of macro naming. Since we are guaranteed * equal command lengths, defining command length via a generalized macro name * will prevent confusion. */ #define HGFS_CLIENT_CMD_LEN HGFS_SYNC_REQREP_CLIENT_CMD_LEN #endif // _HGFS_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsBd.h000066400000000000000000000040331470176644300240600ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #ifndef _HGFS_BD_H_ # define _HGFS_BD_H_ /* * hgfsBd.h -- * * Backdoor calls used by hgfs clients. */ #include "rpcout.h" char *HgfsBd_GetBuf(void); char *HgfsBd_GetLargeBuf(void); void HgfsBd_PutBuf(char *); RpcOut *HgfsBd_GetChannel(void); Bool HgfsBd_CloseChannel(RpcOut *out); int HgfsBd_Dispatch(RpcOut *out, char *packetIn, size_t *packetSize, char const **packetOut); Bool HgfsBd_Enabled(RpcOut *out, char *requestPacket); Bool HgfsBd_OpenBackdoor(RpcOut **out); Bool HgfsBd_CloseBackdoor(RpcOut **out); #endif // _HGFS_BD_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsDevLinux.h000066400000000000000000000117571470176644300253040ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfsDev.h -- * * Header for code shared between the hgfs linux kernel module driver * and the pserver. */ #ifndef _HGFS_DEV_H_ #define _HGFS_DEV_H_ #include "vm_basic_types.h" #include "hgfs.h" #define HGFS_NAME "vmhgfs" // Name of FS (e.g. "mount -t vmhgfs") #define HGFS_FUSENAME "vmhgfs-fuse" // Name of FS (e.g. "-o subtype=vmhgfs-fuse") #define HGFS_FUSETYPE "fuse." HGFS_FUSENAME // Type of FS (e.g. "fuse.vmhgfs-fuse") #define HGFS_MOUNT_POINT "/mnt/hgfs" // Type of FS (e.g. vmhgfs-fuse ) #define HGFS_DEVICE_NAME "dev" // Name of our device under /proc/fs/HGFS_NAME/ #define HGFS_SUPER_MAGIC 0xbacbacbc // Superblock magic number #define HGFS_DEFAULT_TTL 1 // Default TTL for dentries typedef enum { HGFS_MOUNTINFO_VERSION_NONE, HGFS_MOUNTINFO_VERSION_1, HGFS_MOUNTINFO_VERSION_2, } HgfsMountInfoVersion; /* * The mount info flags. * These specify flags from options parsed on the mount command line. */ #define HGFS_MNTINFO_SERVER_INO (1 << 0) /* Use server inode numbers? */ /* * Mount information, passed from pserver process to kernel * at mount time. * * XXX: I'm hijacking this struct. In the future, when the Solaris HGFS driver * loses its pserver, the struct will be used by /sbin/mount.vmhgfs solely. * As is, it is also used by the Solaris pserver. */ typedef struct HgfsMountInfo { uint32 magicNumber; // hgfs magic number uint32 infoSize; // HgfsMountInfo structure size HgfsMountInfoVersion version; // HgfsMountInfo structure version uint32 fd; // file descriptor of client file uint32 flags; // hgfs specific mount flags #ifndef sun uid_t uid; // desired owner of files Bool uidSet; // is the owner actually set? gid_t gid; // desired group of files Bool gidSet; // is the group actually set? unsigned short fmask; // desired file mask unsigned short dmask; // desired directory mask uint32 ttl; // number of seconds before revalidating dentries #if defined __APPLE__ char shareNameHost[MAXPATHLEN]; // must be ".host" char shareNameDir[MAXPATHLEN]; // desired share name for mounting #else const char *shareNameHost; // must be ".host" const char *shareNameDir; // desired share name for mounting #endif #endif } #if __GNUC__ __attribute__((__packed__)) #else # error Compiler packing... #endif HgfsMountInfo; /* * Version 1 of the MountInfo object. * This is used so that newer kernel clients can allow mounts using * older versions of the mounter application for backwards compatibility. */ typedef struct HgfsMountInfoV1 { uint32 magicNumber; // hgfs magic number uint32 version; // protocol version uint32 fd; // file descriptor of client file #ifndef sun uid_t uid; // desired owner of files Bool uidSet; // is the owner actually set? gid_t gid; // desired group of files Bool gidSet; // is the group actually set? unsigned short fmask; // desired file mask unsigned short dmask; // desired directory mask uint32 ttl; // number of seconds before revalidating dentries #if defined __APPLE__ char shareNameHost[MAXPATHLEN]; // must be ".host" char shareNameDir[MAXPATHLEN]; // desired share name for mounting #else const char *shareNameHost; // must be ".host" const char *shareNameDir; // desired share name for mounting #endif #endif } HgfsMountInfoV1; #endif //ifndef _HGFS_DEV_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsEscape.h000066400000000000000000000036261470176644300247420ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfsEscape.h -- * * Escape and unescape filenames that are not legal on a particular * platform. * */ #ifndef __HGFS_ESCAPE_H__ #define __HGFS_ESCAPE_H__ int HgfsEscape_GetSize(char const *bufIn, uint32 sizeIn); int HgfsEscape_Do(char const *bufIn, uint32 sizeIn, uint32 sizeBufOut, char *bufOut); uint32 HgfsEscape_Undo(char *bufIn, uint32 sizeIn); #endif // __HGFS_ESCAPE_H__ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsHelper.h000066400000000000000000000024551470176644300247600ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsClient.h * * Provides a helper library for guest applications to access * the HGFS file system. */ #ifndef _HGFS_HELPER_H_ #define _HGFS_HELPER_H_ #include "vm_basic_types.h" #include "unicode.h" Bool HgfsHlpr_QuerySharesDefaultRootPath(char **hgfsRootPath); void HgfsHlpr_FreeSharesRootPath(char *hgfsRootPath); #if defined(_WIN32) Bool HgfsHlpr_ReadRegistryDefaultRootPath(char **hgfsRootPath); #endif // _WIN32 #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsProto.h000066400000000000000000002534431470176644300246510ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfsProto.h -- * * Header file for data types and message formats used in the * Host/Guest File System (hgfs) protocol. */ #ifndef _HGFS_PROTO_H_ # define _HGFS_PROTO_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #include "includeCheck.h" #include "vm_basic_types.h" #include "hgfs.h" /* * Handle used by the server to identify files and searches. Used * by the driver to match server replies with pending requests. */ typedef uint32 HgfsHandle; #define HGFS_INVALID_HANDLE ((HgfsHandle)~((HgfsHandle)0)) /* * Opcodes for server operations. * * Changing the ordering of this enum will break the protocol; new ops * should be added at the end (but before HGFS_OP_MAX). */ typedef enum { HGFS_OP_OPEN, /* Open file */ HGFS_OP_READ, /* Read from file */ HGFS_OP_WRITE, /* Write to file */ HGFS_OP_CLOSE, /* Close file */ HGFS_OP_SEARCH_OPEN, /* Start new search */ HGFS_OP_SEARCH_READ, /* Get next search response */ HGFS_OP_SEARCH_CLOSE, /* End a search */ HGFS_OP_GETATTR, /* Get file attributes */ HGFS_OP_SETATTR, /* Set file attributes */ HGFS_OP_CREATE_DIR, /* Create new directory */ HGFS_OP_DELETE_FILE, /* Delete a file */ HGFS_OP_DELETE_DIR, /* Delete a directory */ HGFS_OP_RENAME, /* Rename a file or directory */ HGFS_OP_QUERY_VOLUME_INFO, /* Query volume information */ /* * The following operations are only available in version 2 of the hgfs * protocol. The corresponding version 1 opcodes above are deprecated. */ HGFS_OP_OPEN_V2, /* Open file */ HGFS_OP_GETATTR_V2, /* Get file attributes */ HGFS_OP_SETATTR_V2, /* Set file attributes */ HGFS_OP_SEARCH_READ_V2, /* Get next search response */ HGFS_OP_CREATE_SYMLINK, /* Create a symlink */ HGFS_OP_SERVER_LOCK_CHANGE, /* Change the oplock on a file */ HGFS_OP_CREATE_DIR_V2, /* Create a directory */ HGFS_OP_DELETE_FILE_V2, /* Delete a file */ HGFS_OP_DELETE_DIR_V2, /* Delete a directory */ HGFS_OP_RENAME_V2, /* Rename a file or directory */ /* * Operations for version 3, deprecating version 2 operations. */ HGFS_OP_OPEN_V3, /* Open file */ HGFS_OP_READ_V3, /* Read from file */ HGFS_OP_WRITE_V3, /* Write to file */ HGFS_OP_CLOSE_V3, /* Close file */ HGFS_OP_SEARCH_OPEN_V3, /* Start new search */ HGFS_OP_SEARCH_READ_V3, /* Read V3 directory entries */ HGFS_OP_SEARCH_CLOSE_V3, /* End a search */ HGFS_OP_GETATTR_V3, /* Get file attributes */ HGFS_OP_SETATTR_V3, /* Set file attributes */ HGFS_OP_CREATE_DIR_V3, /* Create new directory */ HGFS_OP_DELETE_FILE_V3, /* Delete a file */ HGFS_OP_DELETE_DIR_V3, /* Delete a directory */ HGFS_OP_RENAME_V3, /* Rename a file or directory */ HGFS_OP_QUERY_VOLUME_INFO_V3, /* Query volume information */ HGFS_OP_CREATE_SYMLINK_V3, /* Create a symlink */ HGFS_OP_SERVER_LOCK_CHANGE_V3, /* Change the oplock on a file */ HGFS_OP_WRITE_WIN32_STREAM_V3, /* Write WIN32_STREAM_ID format data to file */ /* * Operations for version 4, deprecating version 3 operations. */ HGFS_OP_CREATE_SESSION_V4, /* Create a session and return host capabilities. */ HGFS_OP_DESTROY_SESSION_V4, /* Destroy/close session. */ HGFS_OP_READ_FAST_V4, /* Read */ HGFS_OP_WRITE_FAST_V4, /* Write */ HGFS_OP_SET_WATCH_V4, /* Start monitoring directory changes. */ HGFS_OP_REMOVE_WATCH_V4, /* Stop monitoring directory changes. */ HGFS_OP_NOTIFY_V4, /* Notification for a directory change event. */ HGFS_OP_SEARCH_READ_V4, /* Read V4 directory entries. */ HGFS_OP_OPEN_V4, /* Open file */ HGFS_OP_ENUMERATE_STREAMS_V4, /* Enumerate alternative named streams for a file. */ HGFS_OP_GETATTR_V4, /* Get file attributes */ HGFS_OP_SETATTR_V4, /* Set file attributes */ HGFS_OP_DELETE_V4, /* Delete a file or a directory */ HGFS_OP_LINKMOVE_V4, /* Rename/move/create hard link. */ HGFS_OP_FSCTL_V4, /* Sending FS control requests. */ HGFS_OP_ACCESS_CHECK_V4, /* Access check. */ HGFS_OP_FSYNC_V4, /* Flush all cached data to the disk. */ HGFS_OP_QUERY_VOLUME_INFO_V4, /* Query volume information. */ HGFS_OP_OPLOCK_ACQUIRE_V4, /* Acquire OPLOCK. */ HGFS_OP_OPLOCK_BREAK_V4, /* Break or downgrade OPLOCK. */ HGFS_OP_LOCK_BYTE_RANGE_V4, /* Acquire byte range lock. */ HGFS_OP_UNLOCK_BYTE_RANGE_V4, /* Release byte range lock. */ HGFS_OP_QUERY_EAS_V4, /* Query extended attributes. */ HGFS_OP_SET_EAS_V4, /* Add or modify extended attributes. */ HGFS_OP_MAX, /* Dummy op, must be last in enum */ HGFS_OP_NEW_HEADER = 0xff, /* Header op, must be unique, distinguishes packet headers. */ } HgfsOp; /* * If we get to where the OP table has grown such that we hit the invalid opcode to * distinguish between header structures in the packet, then we must ensure that there * is no valid HGFS opcode with that same value. * The following assert is designed to force anyone who adds new opcodes which cause the * above condition to occur to verify the opcode values and then can remove this check. */ MY_ASSERTS(hgfsOpValuesAsserts, ASSERT_ON_COMPILE(HGFS_OP_MAX < HGFS_OP_NEW_HEADER); ) /* HGFS protocol versions. */ typedef enum { HGFS_PROTOCOL_VERSION_NONE, HGFS_PROTOCOL_VERSION_1, HGFS_PROTOCOL_VERSION_2, HGFS_PROTOCOL_VERSION_3, HGFS_PROTOCOL_VERSION_4, } HgfsProtocolVersion; /* XXX: Needs change when VMCI is supported. */ #define HGFS_REQ_PAYLOAD_SIZE_V3(hgfsReq) (sizeof *hgfsReq + sizeof(HgfsRequest)) #define HGFS_REP_PAYLOAD_SIZE_V3(hgfsRep) (sizeof *hgfsRep + sizeof(HgfsReply)) /* XXX: Needs change when VMCI is supported. */ #define HGFS_REQ_GET_PAYLOAD_V3(hgfsReq) ((char *)(hgfsReq) + sizeof(HgfsRequest)) #define HGFS_REP_GET_PAYLOAD_V3(hgfsRep) ((char *)(hgfsRep) + sizeof(HgfsReply)) /* * Open flags. * * Changing the order of this enum will break stuff. Do not add any flags to * this enum: it has been frozen and all new flags should be added to * HgfsOpenMode. This was done because HgfsOpenMode could still be converted * to a bitmask (so that it's easier to add flags to) whereas this enum was * already too large. */ typedef enum { // File doesn't exist File exists HGFS_OPEN, // error HGFS_OPEN_EMPTY, // error size = 0 HGFS_OPEN_CREATE, // create HGFS_OPEN_CREATE_SAFE, // create error HGFS_OPEN_CREATE_EMPTY, // create size = 0 } HgfsOpenFlags; /* * Write flags. */ typedef uint8 HgfsWriteFlags; #define HGFS_WRITE_APPEND 1 /* * Permissions bits. * * These are intentionally similar to Unix permissions bits, and we * convert to/from Unix permissions using simple shift operations, so * don't change these or you will break things. */ typedef uint8 HgfsPermissions; #define HGFS_PERM_READ 4 #define HGFS_PERM_WRITE 2 #define HGFS_PERM_EXEC 1 /* * Access mode bits. * * Different operating systems have different set of file access mode. * Here are constants that are rich enough to describe all access modes in an OS * independent way. */ typedef uint32 HgfsAccessMode; /* * Generic access rights control coarse grain access for the file. * A particular generic rigth can be expanded into different set of specific rights * on different OS. */ /* * HGFS_MODE_GENERIC_READ means ability to read file data and read various file * attributes and properties. */ #define HGFS_MODE_GENERIC_READ (1 << 0) /* * HGFS_MODE_GENERIC_WRITE means ability to write file data and updaate various file * attributes and properties. */ #define HGFS_MODE_GENERIC_WRITE (1 << 1) /* * HGFS_MODE_GENERIC_EXECUE means ability to execute file. For network redirectors * ability to execute usualy implies ability to read data; for local file systems * HGFS_MODE_GENERIC_EXECUTE does not imply ability to read data. */ #define HGFS_MODE_GENERIC_EXECUTE (1 << 2) /* Specific rights define fine grain access modes. */ #define HGFS_MODE_READ_DATA (1 << 3) // Ability to read file data #define HGFS_MODE_WRITE_DATA (1 << 4) // Ability to writge file data #define HGFS_MODE_APPEND_DATA (1 << 5) // Appending data to the end of file #define HGFS_MODE_DELETE (1 << 6) // Ability to delete the file #define HGFS_MODE_TRAVERSE_DIRECTORY (1 << 7) // Ability to access files in a directory #define HGFS_MODE_LIST_DIRECTORY (1 << 8) // Ability to list file names #define HGFS_MODE_ADD_SUBDIRECTORY (1 << 9) // Ability to create a new subdirectory #define HGFS_MODE_ADD_FILE (1 << 10) // Ability to create a new file #define HGFS_MODE_DELETE_CHILD (1 << 11) // Ability to delete file/subdirectory #define HGFS_MODE_READ_ATTRIBUTES (1 << 12) // Ability to read attributes #define HGFS_MODE_WRITE_ATTRIBUTES (1 << 13) // Ability to write attributes #define HGFS_MODE_READ_EXTATTRIBUTES (1 << 14) // Ability to read extended attributes #define HGFS_MODE_WRITE_EXTATTRIBUTES (1 << 15) // Ability to write extended attributes #define HGFS_MODE_READ_SECURITY (1 << 16) // Ability to read permissions/ACLs/owner #define HGFS_MODE_WRITE_SECURITY (1 << 17) // Ability to change permissions/ACLs #define HGFS_MODE_TAKE_OWNERSHIP (1 << 18) // Ability to change file owner/group /* * Server-side locking (oplocks and leases). * * The client can ask the server to acquire opportunistic locking/leasing * from the host FS on its behalf. This is communicated as part of an open request. * * HGFS_LOCK_OPPORTUNISTIC means that the client trusts the server * to decide what kind of locking to request from the host FS. * All other values tell the server explicitly the type of lock to * request. * * The server will attempt to acquire the desired lock and will notify the client * which type of lock was acquired as part of the reply to the open request. * Note that HGFS_LOCK_OPPORTUNISTIC should not be specified as the type of * lock acquired by the server, since HGFS_LOCK_OPPORTUNISTIC is not an * actual lock. */ typedef enum { HGFS_LOCK_NONE, HGFS_LOCK_OPPORTUNISTIC, HGFS_LOCK_EXCLUSIVE, HGFS_LOCK_SHARED, HGFS_LOCK_BATCH, HGFS_LOCK_LEASE, } HgfsLockType; /* * Flags to indicate in a setattr request which fields should be * updated. Deprecated. */ typedef uint8 HgfsAttrChanges; #define HGFS_ATTR_SIZE (1 << 0) #define HGFS_ATTR_CREATE_TIME (1 << 1) #define HGFS_ATTR_ACCESS_TIME (1 << 2) #define HGFS_ATTR_WRITE_TIME (1 << 3) #define HGFS_ATTR_CHANGE_TIME (1 << 4) #define HGFS_ATTR_PERMISSIONS (1 << 5) #define HGFS_ATTR_ACCESS_TIME_SET (1 << 6) #define HGFS_ATTR_WRITE_TIME_SET (1 << 7) /* * Hints to indicate in a getattr or setattr which attributes * are valid for the request. * For setattr only, attributes should be set by host even if * no valid values are specified by the guest. */ typedef uint64 HgfsAttrHint; #define HGFS_ATTR_HINT_SET_ACCESS_TIME (1 << 0) #define HGFS_ATTR_HINT_SET_WRITE_TIME (1 << 1) #define HGFS_ATTR_HINT_USE_FILE_DESC (1 << 2) /* * Hint to determine using a name or a handle to determine * what to delete. */ typedef uint64 HgfsDeleteHint; #define HGFS_DELETE_HINT_USE_FILE_DESC (1 << 0) /* * Hint to determine using a name or a handle to determine * what to renames. */ typedef uint64 HgfsRenameHint; #define HGFS_RENAME_HINT_USE_SRCFILE_DESC (1 << 0) #define HGFS_RENAME_HINT_USE_TARGETFILE_DESC (1 << 1) #define HGFS_RENAME_HINT_NO_REPLACE_EXISTING (1 << 2) #define HGFS_RENAME_HINT_NO_COPY_ALLOWED (1 << 3) /* * File attributes. * * The four time fields below are in Windows NT format, which is in * units of 100ns since Jan 1, 1601, UTC. */ /* * Version 1 attributes. Deprecated. * Version 2 should be using HgfsAttrV2. */ #pragma pack(push, 1) typedef struct HgfsAttr { HgfsFileType type; /* File type */ uint64 size; /* File size (in bytes) */ uint64 creationTime; /* Creation time. Ignored by POSIX */ uint64 accessTime; /* Time of last access */ uint64 writeTime; /* Time of last write */ uint64 attrChangeTime; /* Time file attributess were last * changed. Ignored by Windows */ HgfsPermissions permissions; /* Permissions bits */ } HgfsAttr; #pragma pack(pop) /* Various flags and Windows attributes. */ typedef uint64 HgfsAttrFlags; #define HGFS_ATTR_HIDDEN (1 << 0) #define HGFS_ATTR_SYSTEM (1 << 1) #define HGFS_ATTR_ARCHIVE (1 << 2) #define HGFS_ATTR_HIDDEN_FORCED (1 << 3) #define HGFS_ATTR_REPARSE_POINT (1 << 4) /* V4 additional definitions for hgfsAttrFlags. */ #define HGFS_ATTR_COMPRESSED (1 << 5) #define HGFS_ATTR_ENCRYPTED (1 << 6) #define HGFS_ATTR_OFFLINE (1 << 7) #define HGFS_ATTR_READONLY (1 << 8) #define HGFS_ATTR_SPARSE (1 << 9) #define HGFS_ATTR_TEMPORARY (1 << 10) #define HGFS_ATTR_SEQUENTIAL_ONLY (1 << 11) /* * Specifies which open request fields contain * valid values. */ typedef uint64 HgfsOpenValid; #define HGFS_OPEN_VALID_NONE 0 #define HGFS_OPEN_VALID_MODE (1 << 0) #define HGFS_OPEN_VALID_FLAGS (1 << 1) #define HGFS_OPEN_VALID_SPECIAL_PERMS (1 << 2) #define HGFS_OPEN_VALID_OWNER_PERMS (1 << 3) #define HGFS_OPEN_VALID_GROUP_PERMS (1 << 4) #define HGFS_OPEN_VALID_OTHER_PERMS (1 << 5) #define HGFS_OPEN_VALID_FILE_ATTR (1 << 6) #define HGFS_OPEN_VALID_ALLOCATION_SIZE (1 << 7) #define HGFS_OPEN_VALID_DESIRED_ACCESS (1 << 8) #define HGFS_OPEN_VALID_SHARE_ACCESS (1 << 9) #define HGFS_OPEN_VALID_SERVER_LOCK (1 << 10) #define HGFS_OPEN_VALID_FILE_NAME (1 << 11) /* V4 additional open mask flags. */ #define HGFS_OPEN_VALID_EA (1 << 12) #define HGFS_OPEN_VALID_ACL (1 << 13) #define HGFS_OPEN_VALID_STREAM_NAME (1 << 14) /* * Specifies which attribute fields contain * valid values. */ typedef uint64 HgfsAttrValid; #define HGFS_ATTR_VALID_NONE 0 #define HGFS_ATTR_VALID_TYPE (1 << 0) #define HGFS_ATTR_VALID_SIZE (1 << 1) #define HGFS_ATTR_VALID_CREATE_TIME (1 << 2) #define HGFS_ATTR_VALID_ACCESS_TIME (1 << 3) #define HGFS_ATTR_VALID_WRITE_TIME (1 << 4) #define HGFS_ATTR_VALID_CHANGE_TIME (1 << 5) #define HGFS_ATTR_VALID_SPECIAL_PERMS (1 << 6) #define HGFS_ATTR_VALID_OWNER_PERMS (1 << 7) #define HGFS_ATTR_VALID_GROUP_PERMS (1 << 8) #define HGFS_ATTR_VALID_OTHER_PERMS (1 << 9) #define HGFS_ATTR_VALID_FLAGS (1 << 10) #define HGFS_ATTR_VALID_ALLOCATION_SIZE (1 << 11) #define HGFS_ATTR_VALID_USERID (1 << 12) #define HGFS_ATTR_VALID_GROUPID (1 << 13) #define HGFS_ATTR_VALID_FILEID (1 << 14) #define HGFS_ATTR_VALID_VOLID (1 << 15) /* * Add our file and volume identifiers. * NOTE: On Windows hosts, the file identifier is not guaranteed to be valid * particularly with FAT. A defrag operation could cause it to change. * Therefore, to not confuse older clients, and non-Windows * clients we have added a separate flag. * The Windows client will check for both flags for the * file ID, and return the information to the guest application. * However, it will use the ID internally, when it has an open * handle on the server. * Non-Windows clients need the file ID to be always guaranteed, * which is to say, that the ID remains constant over the course of the * file's lifetime, and will use the HGFS_ATTR_VALID_FILEID flag * only to determine if the ID is valid. */ #define HGFS_ATTR_VALID_NON_STATIC_FILEID (1 << 16) /* * File permissions that are in effect for the user which runs HGFS server. * Client needs to know effective permissions in order to implement access(2). * Client can't derive it from group/owner/other permissions because of two resaons: * 1. It does not know user/group id of the user which runs HGFS server * 2. Effective permissions account for additional restrictions that may be imposed * by host file system, for example by ACL. */ #define HGFS_ATTR_VALID_EFFECTIVE_PERMS (1 << 17) #define HGFS_ATTR_VALID_EXTEND_ATTR_SIZE (1 << 18) #define HGFS_ATTR_VALID_REPARSE_POINT (1 << 19) #define HGFS_ATTR_VALID_SHORT_NAME (1 << 20) /* * Specifies which create dir request fields contain * valid values. */ typedef uint64 HgfsCreateDirValid; #define HGFS_CREATE_DIR_VALID_NONE 0 #define HGFS_CREATE_DIR_VALID_SPECIAL_PERMS (1 << 0) #define HGFS_CREATE_DIR_VALID_OWNER_PERMS (1 << 1) #define HGFS_CREATE_DIR_VALID_GROUP_PERMS (1 << 2) #define HGFS_CREATE_DIR_VALID_OTHER_PERMS (1 << 3) #define HGFS_CREATE_DIR_VALID_FILE_NAME (1 << 4) #define HGFS_CREATE_DIR_VALID_FILE_ATTR (1 << 5) /* * Version 2 of HgfsAttr */ #pragma pack(push, 1) typedef struct HgfsAttrV2 { HgfsAttrValid mask; /* A bit mask to determine valid attribute fields */ HgfsFileType type; /* File type */ uint64 size; /* File size (in bytes) */ uint64 creationTime; /* Creation time. Ignored by POSIX */ uint64 accessTime; /* Time of last access */ uint64 writeTime; /* Time of last write */ uint64 attrChangeTime; /* Time file attributes were last * changed. Ignored by Windows */ HgfsPermissions specialPerms; /* Special permissions bits (suid, etc.). * Ignored by Windows */ HgfsPermissions ownerPerms; /* Owner permissions bits */ HgfsPermissions groupPerms; /* Group permissions bits. Ignored by * Windows */ HgfsPermissions otherPerms; /* Other permissions bits. Ignored by * Windows */ HgfsAttrFlags flags; /* Various flags and Windows 'attributes' */ uint64 allocationSize; /* Actual size of file on disk */ uint32 userId; /* User identifier, ignored by Windows */ uint32 groupId; /* group identifier, ignored by Windows */ uint64 hostFileId; /* File Id of the file on host: inode_t on Linux */ uint32 volumeId; /* volume identifier, non-zero is valid. */ uint32 effectivePerms; /* Permissions in effect for the user on the host. */ uint64 reserved2; /* Reserved for future use */ } HgfsAttrV2; #pragma pack(pop) /* * Cross-platform filename representation * * Cross-platform (CP) names are represented by a string with each * path component separated by NULs, and terminated with a final NUL, * but with no leading path separator. * * For example, the representations of a POSIX and Windows name * are as follows, with "0" meaning NUL. * * Original name Cross-platform name * ----------------------------------------------------- * "/home/bac/temp" -> "home0bac0temp0" * "C:\temp\file.txt" -> "C0temp0file.txt0" * * Note that as in the example above, Windows should strip the colon * off of drive letters as part of the conversion. Aside from that, * all characters in each path component should be left unescaped and * unmodified. Each OS is responsible for escaping any characters that * are not legal in its filenames when converting FROM the CP name * format, and unescaping them when converting TO the CP name format. * * In some requests (OPEN, GETATTR, SETATTR, DELETE, CREATE_DIR) the * CP name is used to represent a particular file, but it is also used * to represent a search pattern for looking up files using * SEARCH_OPEN. * * In the current HGFS server implementation, each request has a minimum packet * size that must be met for it to be considered valid. This minimum is simply * the sizeof the particular request, which includes the solitary byte from the * HgfsFileName struct. For these particular requests, clients add an extra * byte to their payload size, without that byte being present anywhere. * * It isn't clear that this behavior is correct, but the end result is that * neither end malfunctions, as an extra byte gets sent by the client and is * ignored by the server. Unfortunately, it cannot be easily fixed. The * server's minimum packet size can be changed, but the client should continue * to send an extra byte, otherwise older servers with a slightly longer * minimum packet size may consider the new client's packets to be too short. * * UTF-8 representation * -------------------- * XXX: It is expected that file names in the HGFS protocol will be a valid UTF-8 * encoding. * See RFC 3629 (http://tools.ietf.org/html/rfc3629) * * Unicode Format * -------------- * HGFS protocol requests that contain file names as in the structure below, * should contain unicode normal form C (precomposed see explanation below) * characters therefore hosts such as Mac OS which * use HFS+ and unicode form D should convert names before * processing or sending HGFS requests. * * Precomposed (normal form C) versus Decomposed (normal form D) * ------------------------------------------------------------- * Certain Unicode characters can be encoded in more than one way. * For example, an (A acute) can be encoded either precomposed, * as U+00C1 (LATIN CAPITAL LETTER A WITH ACUTE), or decomposed, * as U+0041 U+0301 (LATIN CAPITAL LETTER A followed by a COMBINING ACUTE ACCENT). * Precomposed characters are more common in the Windows world, * whereas decomposed characters are more common on the Mac. * * See UAX 15 (http://unicode.org/reports/tr15/) */ #pragma pack(push, 1) typedef struct HgfsFileName { uint32 length; /* Does NOT include terminating NUL */ char name[1]; } HgfsFileName; #pragma pack(pop) /* * Windows hosts only: the server may return the DOS 8 dot 3 format * name as part of the directory entry. */ #pragma pack(push, 1) typedef struct HgfsShortFileName { uint32 length; /* Does NOT include terminating NUL */ char name[12 * 4]; /* UTF8 max char size is 4 bytes. */ } HgfsShortFileName; #pragma pack(pop) /* * Case-sensitiviy flags are only used when any lookup is * involved on the server side. */ typedef enum { HGFS_FILE_NAME_DEFAULT_CASE, HGFS_FILE_NAME_CASE_SENSITIVE, HGFS_FILE_NAME_CASE_INSENSITIVE, } HgfsCaseType; /* * HgfsFileNameV3 - new header to incorporate case-sensitivity flags along with * Hgfs file handle. */ #pragma pack(push, 1) typedef struct HgfsFileNameV3 { uint32 length; /* Does NOT include terminating NUL */ uint32 flags; /* Flags described below. */ HgfsCaseType caseType; /* Case-sensitivity type. */ HgfsHandle fid; char name[1]; } HgfsFileNameV3; #pragma pack(pop) /* * HgfsFileNameV3 flags. Case-sensitiviy flags are only used when any lookup is * involved on the server side. */ #define HGFS_FILE_NAME_USE_FILE_DESC (1 << 0) /* Case type ignored if set. */ /* * Request/reply structs. These are the first members of all * operation request and reply messages, respectively. */ #pragma pack(push, 1) typedef struct HgfsRequest { HgfsHandle id; /* Opaque request ID used by the requestor */ HgfsOp op; } HgfsRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReply { HgfsHandle id; /* Opaque request ID used by the requestor */ HgfsStatus status; } HgfsReply; #pragma pack(pop) /* * Messages for our file operations. */ /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestOpen { HgfsRequest header; HgfsOpenMode mode; /* Which type of access is requested */ HgfsOpenFlags flags; /* Which flags to open the file with */ HgfsPermissions permissions; /* Which permissions to *create* a new file with */ HgfsFileName fileName; } HgfsRequestOpen; #pragma pack(pop) /* Version 2 of HgfsRequestOpen */ #pragma pack(push, 1) typedef struct HgfsRequestOpenV2 { HgfsRequest header; HgfsOpenValid mask; /* Bitmask that specified which fields are valid. */ HgfsOpenMode mode; /* Which type of access requested. See desiredAccess */ HgfsOpenFlags flags; /* Which flags to open the file with */ HgfsPermissions specialPerms; /* Desired 'special' permissions for file creation */ HgfsPermissions ownerPerms; /* Desired 'owner' permissions for file creation */ HgfsPermissions groupPerms; /* Desired 'group' permissions for file creation */ HgfsPermissions otherPerms; /* Desired 'other' permissions for file creation */ HgfsAttrFlags attr; /* Attributes, if any, for file creation */ uint64 allocationSize; /* How much space to pre-allocate during creation */ uint32 desiredAccess; /* Extended support for windows access modes */ uint32 shareAccess; /* Windows only, share access modes */ HgfsLockType desiredLock; /* The type of lock desired by the client */ uint64 reserved1; /* Reserved for future use */ uint64 reserved2; /* Reserved for future use */ HgfsFileName fileName; } HgfsRequestOpenV2; #pragma pack(pop) /* Version 3 of HgfsRequestOpen */ #pragma pack(push, 1) typedef struct HgfsRequestOpenV3 { HgfsOpenValid mask; /* Bitmask that specified which fields are valid. */ HgfsOpenMode mode; /* Which type of access requested. See desiredAccess */ HgfsOpenFlags flags; /* Which flags to open the file with */ HgfsPermissions specialPerms; /* Desired 'special' permissions for file creation */ HgfsPermissions ownerPerms; /* Desired 'owner' permissions for file creation */ HgfsPermissions groupPerms; /* Desired 'group' permissions for file creation */ HgfsPermissions otherPerms; /* Desired 'other' permissions for file creation */ HgfsAttrFlags attr; /* Attributes, if any, for file creation */ uint64 allocationSize; /* How much space to pre-allocate during creation */ uint32 desiredAccess; /* Extended support for windows access modes */ uint32 shareAccess; /* Windows only, share access modes */ HgfsLockType desiredLock; /* The type of lock desired by the client */ uint64 reserved1; /* Reserved for future use */ uint64 reserved2; /* Reserved for future use */ HgfsFileNameV3 fileName; } HgfsRequestOpenV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplyOpen { HgfsReply header; HgfsHandle file; /* Opaque file ID used by the server */ } HgfsReplyOpen; #pragma pack(pop) /* Version 2 of HgfsReplyOpen */ #pragma pack(push, 1) typedef struct HgfsReplyOpenV2 { HgfsReply header; HgfsHandle file; /* Opaque file ID used by the server */ HgfsLockType acquiredLock; /* The type of lock acquired by the server */ } HgfsReplyOpenV2; #pragma pack(pop) /* Version 3 of HgfsReplyOpen */ /* * The HGFS open V3 can acquire locks and reserve disk space when requested. * However, current versions of the server don't implement the locking or allocation of * disk space on a create. These results flags indicate to the client if the server * implements handling those fields and so the clients can respond accordingly. */ typedef uint32 HgfsReplyOpenFlags; #define HGFS_OPEN_REPLY_ALLOC_DISK_SPACE (1 << 0) #define HGFS_OPEN_REPLY_LOCKED_FILE (1 << 1) #pragma pack(push, 1) typedef struct HgfsReplyOpenV3 { HgfsHandle file; /* Opaque file ID used by the server */ HgfsLockType acquiredLock; /* The type of lock acquired by the server */ HgfsReplyOpenFlags flags; /* Opened file flags */ uint32 reserved; /* Reserved for future use */ } HgfsReplyOpenV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestRead { HgfsRequest header; HgfsHandle file; /* Opaque file ID used by the server */ uint64 offset; uint32 requiredSize; } HgfsRequestRead; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplyRead { HgfsReply header; uint32 actualSize; char payload[1]; } HgfsReplyRead; #pragma pack(pop) /* * Version 3 of HgfsRequestRead. * Server must support HGFS_LARGE_PACKET_MAX to implement this op. */ #pragma pack(push, 1) typedef struct HgfsRequestReadV3 { HgfsHandle file; /* Opaque file ID used by the server */ uint64 offset; uint32 requiredSize; uint64 reserved; /* Reserved for future use */ } HgfsRequestReadV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyReadV3 { uint32 actualSize; uint64 reserved; /* Reserved for future use */ char payload[1]; } HgfsReplyReadV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestWrite { HgfsRequest header; HgfsHandle file; /* Opaque file ID used by the server */ HgfsWriteFlags flags; uint64 offset; uint32 requiredSize; char payload[1]; } HgfsRequestWrite; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplyWrite { HgfsReply header; uint32 actualSize; } HgfsReplyWrite; #pragma pack(pop) /* * Version 3 of HgfsRequestWrite. * Server must support HGFS_LARGE_PACKET_MAX to implement this op. */ #pragma pack(push, 1) typedef struct HgfsRequestWriteV3 { HgfsHandle file; /* Opaque file ID used by the server */ HgfsWriteFlags flags; uint64 offset; uint32 requiredSize; uint64 reserved; /* Reserved for future use */ char payload[1]; } HgfsRequestWriteV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyWriteV3 { uint32 actualSize; uint64 reserved; /* Reserved for future use */ } HgfsReplyWriteV3; #pragma pack(pop) /* Stream write flags */ typedef enum { HGFS_WIN32_STREAM_IGNORE_SECURITY = (1<<0), } HgfsWin32StreamFlags; /* * HgfsRequestWriteWin32Stream. * Server must support HGFS_LARGE_PACKET_MAX to implement this op. */ #pragma pack(push, 1) typedef struct HgfsRequestWriteWin32StreamV3 { HgfsHandle file; /* Opaque file ID used by the server */ HgfsWin32StreamFlags flags; uint32 reserved1; uint32 requiredSize; uint64 reserved2; /* Reserved for future use */ char payload[1]; } HgfsRequestWriteWin32StreamV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyWriteWin32StreamV3 { uint32 actualSize; uint64 reserved; /* Reserved for future use */ } HgfsReplyWriteWin32StreamV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestClose { HgfsRequest header; HgfsHandle file; /* Opaque file ID used by the server */ } HgfsRequestClose; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplyClose { HgfsReply header; } HgfsReplyClose; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestCloseV3 { HgfsHandle file; /* Opaque file ID used by the server */ uint64 reserved; /* Reserved for future use */ } HgfsRequestCloseV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyCloseV3 { uint64 reserved; } HgfsReplyCloseV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestSearchOpen { HgfsRequest header; HgfsFileName dirName; } HgfsRequestSearchOpen; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestSearchOpenV3 { uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 dirName; } HgfsRequestSearchOpenV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplySearchOpen { HgfsReply header; HgfsHandle search; /* Opaque search ID used by the server */ } HgfsReplySearchOpen; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplySearchOpenV3 { HgfsHandle search; /* Opaque search ID used by the server */ uint64 reserved; /* Reserved for future use */ } HgfsReplySearchOpenV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestSearchRead { HgfsRequest header; HgfsHandle search; /* Opaque search ID used by the server */ uint32 offset; /* The first result is offset 0 */ } HgfsRequestSearchRead; #pragma pack(pop) /* Version 2 of HgfsRequestSearchRead */ #pragma pack(push, 1) typedef struct HgfsRequestSearchReadV2 { HgfsRequest header; HgfsHandle search; /* Opaque search ID used by the server */ uint32 offset; /* The first result is offset 0 */ } HgfsRequestSearchReadV2; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestSearchReadV3 { HgfsHandle search; /* Opaque search ID used by the server */ uint32 offset; /* The first result is offset 0 */ uint32 flags; /* Reserved for reading multiple directory entries. */ uint64 reserved; /* Reserved for future use */ } HgfsRequestSearchReadV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplySearchRead { HgfsReply header; HgfsAttr attr; HgfsFileName fileName; /* fileName.length = 0 means "no entry at this offset" */ } HgfsReplySearchRead; #pragma pack(pop) /* Version 2 of HgfsReplySearchRead */ #pragma pack(push, 1) typedef struct HgfsReplySearchReadV2 { HgfsReply header; HgfsAttrV2 attr; /* * fileName.length = 0 means "no entry at this offset" * If the file is a symlink (as specified in attr) * this name is the name of the symlink, not the target. */ HgfsFileName fileName; } HgfsReplySearchReadV2; #pragma pack(pop) /* Directory entry structure. */ typedef struct HgfsDirEntry { uint32 nextEntry; HgfsAttrV2 attr; /* * fileName.length = 0 means "no entry at this offset" * If the file is a symlink (as specified in attr) * this name is the name of the symlink, not the target. */ HgfsFileNameV3 fileName; } HgfsDirEntry; #pragma pack(push, 1) typedef struct HgfsReplySearchReadV3 { uint64 count; /* Number of directory entries. */ uint64 reserved; /* Reserved for future use. */ char payload[1]; /* Directory entries. */ } HgfsReplySearchReadV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestSearchClose { HgfsRequest header; HgfsHandle search; /* Opaque search ID used by the server */ } HgfsRequestSearchClose; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplySearchClose { HgfsReply header; } HgfsReplySearchClose; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestSearchCloseV3 { HgfsHandle search; /* Opaque search ID used by the server */ uint64 reserved; /* Reserved for future use */ } HgfsRequestSearchCloseV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplySearchCloseV3 { uint64 reserved; /* Reserved for future use */ } HgfsReplySearchCloseV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestGetattr { HgfsRequest header; HgfsFileName fileName; } HgfsRequestGetattr; #pragma pack(pop) /* Version 2 of HgfsRequestGetattr */ #pragma pack(push, 1) typedef struct HgfsRequestGetattrV2 { HgfsRequest header; HgfsAttrHint hints; /* Flags for file handle valid. */ HgfsHandle file; /* Opaque file ID used by the server. */ HgfsFileName fileName; /* Filename used when file handle invalid. */ } HgfsRequestGetattrV2; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestGetattrV3 { HgfsAttrHint hints; /* Flags for file handle valid. */ uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 fileName; /* Filename used when file handle invalid. */ } HgfsRequestGetattrV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplyGetattr { HgfsReply header; HgfsAttr attr; } HgfsReplyGetattr; #pragma pack(pop) /* Version 2 of HgfsReplyGetattr */ #pragma pack(push, 1) typedef struct HgfsReplyGetattrV2 { HgfsReply header; HgfsAttrV2 attr; /* * If the file is a symlink, as specified in attr.type, then this is * the target for the symlink. If the file is not a symlink, this should * be ignored. * * This filename is in "CPNameLite" format. See CPNameLite.c for details. */ HgfsFileName symlinkTarget; } HgfsReplyGetattrV2; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyGetattrV3 { HgfsAttrV2 attr; /* * If the file is a symlink, as specified in attr.type, then this is * the target for the symlink. If the file is not a symlink, this should * be ignored. * * This filename is in "CPNameLite" format. See CPNameLite.c for details. */ uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 symlinkTarget; } HgfsReplyGetattrV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestSetattr { HgfsRequest header; HgfsAttrChanges update; /* Which fields need to be updated */ HgfsAttr attr; HgfsFileName fileName; } HgfsRequestSetattr; #pragma pack(pop) /* Version 2 of HgfsRequestSetattr */ #pragma pack(push, 1) typedef struct HgfsRequestSetattrV2 { HgfsRequest header; HgfsAttrHint hints; HgfsAttrV2 attr; HgfsHandle file; /* Opaque file ID used by the server. */ HgfsFileName fileName; /* Filename used when file handle invalid. */ } HgfsRequestSetattrV2; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestSetattrV3 { HgfsAttrHint hints; HgfsAttrV2 attr; uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 fileName; /* Filename used when file handle invalid. */ } HgfsRequestSetattrV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplySetattr { HgfsReply header; } HgfsReplySetattr; #pragma pack(pop) /* Version 2 of HgfsReplySetattr */ #pragma pack(push, 1) typedef struct HgfsReplySetattrV2 { HgfsReply header; } HgfsReplySetattrV2; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplySetattrV3 { uint64 reserved; /* Reserved for future use */ } HgfsReplySetattrV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestCreateDir { HgfsRequest header; HgfsPermissions permissions; HgfsFileName fileName; } HgfsRequestCreateDir; #pragma pack(pop) /* Version 2 of HgfsRequestCreateDir */ #pragma pack(push, 1) typedef struct HgfsRequestCreateDirV2 { HgfsRequest header; HgfsCreateDirValid mask; HgfsPermissions specialPerms; HgfsPermissions ownerPerms; HgfsPermissions groupPerms; HgfsPermissions otherPerms; HgfsFileName fileName; } HgfsRequestCreateDirV2; #pragma pack(pop) /* Version 3 of HgfsRequestCreateDir */ #pragma pack(push, 1) typedef struct HgfsRequestCreateDirV3 { HgfsCreateDirValid mask; HgfsPermissions specialPerms; HgfsPermissions ownerPerms; HgfsPermissions groupPerms; HgfsPermissions otherPerms; HgfsAttrFlags fileAttr; HgfsFileNameV3 fileName; } HgfsRequestCreateDirV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplyCreateDir { HgfsReply header; } HgfsReplyCreateDir; #pragma pack(pop) /* Version 2 of HgfsReplyCreateDir */ #pragma pack(push, 1) typedef struct HgfsReplyCreateDirV2 { HgfsReply header; } HgfsReplyCreateDirV2; #pragma pack(pop) /* Version 3 of HgfsReplyCreateDir */ #pragma pack(push, 1) typedef struct HgfsReplyCreateDirV3 { uint64 reserved; /* Reserved for future use */ } HgfsReplyCreateDirV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsRequestDelete { HgfsRequest header; HgfsFileName fileName; } HgfsRequestDelete; #pragma pack(pop) /* Version 2 of HgfsRequestDelete */ #pragma pack(push, 1) typedef struct HgfsRequestDeleteV2 { HgfsRequest header; HgfsDeleteHint hints; HgfsHandle file; /* Opaque file ID used by the server. */ HgfsFileName fileName; /* Name used if the file is HGFS_HANDLE_INVALID */ } HgfsRequestDeleteV2; #pragma pack(pop) /* Version 3 of HgfsRequestDelete */ #pragma pack(push, 1) typedef struct HgfsRequestDeleteV3 { HgfsDeleteHint hints; uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 fileName; /* Name used if the file is HGFS_HANDLE_INVALID */ } HgfsRequestDeleteV3; #pragma pack(pop) /* Deprecated */ #pragma pack(push, 1) typedef struct HgfsReplyDelete { HgfsReply header; } HgfsReplyDelete; #pragma pack(pop) /* Version 2 of HgfsReplyDelete */ #pragma pack(push, 1) typedef struct HgfsReplyDeleteV2 { HgfsReply header; } HgfsReplyDeleteV2; #pragma pack(pop) /* Version 2 of HgfsReplyDelete */ #pragma pack(push, 1) typedef struct HgfsReplyDeleteV3 { uint64 reserved; /* Reserved for future use */ } HgfsReplyDeleteV3; #pragma pack(pop) /* * The size of the HgfsFileName struct is variable depending on the * length of the name, so you can't use request->newName to get the * actual address of the new name, because where it starts is * dependant on how long the oldName is. To get the address of * newName, use this: * * &oldName + sizeof(HgfsFileName) + oldName.length */ #pragma pack(push, 1) typedef struct HgfsRequestRename { HgfsRequest header; HgfsFileName oldName; HgfsFileName newName; } HgfsRequestRename; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyRename { HgfsReply header; } HgfsReplyRename; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestRenameV2 { HgfsRequest header; HgfsRenameHint hints; HgfsHandle srcFile; /* Opaque file ID to "old name" used by the server. */ HgfsHandle targetFile; /* Opaque file ID to "old name" used by the server. */ HgfsFileName oldName; HgfsFileName newName; } HgfsRequestRenameV2; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyRenameV2 { HgfsReply header; } HgfsReplyRenameV2; #pragma pack(pop) /* HgfsRequestRename and HgfsReplyRename for v3. */ #pragma pack(push, 1) typedef struct HgfsRequestRenameV3 { HgfsRenameHint hints; uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 oldName; HgfsFileNameV3 newName; } HgfsRequestRenameV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyRenameV3 { uint64 reserved; /* Reserved for future use */ } HgfsReplyRenameV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestQueryVolume { HgfsRequest header; HgfsFileName fileName; } HgfsRequestQueryVolume; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyQueryVolume { HgfsReply header; uint64 freeBytes; uint64 totalBytes; } HgfsReplyQueryVolume; #pragma pack(pop) /* HgfsRequestQueryVolume and HgfsReplyQueryVolume for v3. */ #pragma pack(push, 1) typedef struct HgfsRequestQueryVolumeV3 { uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 fileName; } HgfsRequestQueryVolumeV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyQueryVolumeV3 { uint64 freeBytes; uint64 totalBytes; uint64 reserved; /* Reserved for future use */ } HgfsReplyQueryVolumeV3; #pragma pack(pop) /* New operations for Version 2 */ #pragma pack(push, 1) typedef struct HgfsRequestServerLockChange { HgfsRequest header; HgfsHandle file; HgfsLockType newServerLock; } HgfsRequestServerLockChange; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyServerLockChange { HgfsReply header; HgfsLockType serverLock; } HgfsReplyServerLockChange; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestSymlinkCreate { HgfsRequest header; HgfsFileName symlinkName; /* This filename is in "CPNameLite" format. See CPNameLite.c for details. */ HgfsFileName targetName; } HgfsRequestSymlinkCreate; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplySymlinkCreate { HgfsReply header; } HgfsReplySymlinkCreate; #pragma pack(pop) /* HgfsRequestSymlinkCreate and HgfsReplySymlinkCreate for v3. */ #pragma pack(push, 1) typedef struct HgfsRequestSymlinkCreateV3 { uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 symlinkName; /* This filename is in "CPNameLite" format. See CPNameLite.c for details. */ HgfsFileNameV3 targetName; } HgfsRequestSymlinkCreateV3; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplySymlinkCreateV3 { uint64 reserved; /* Reserved for future use */ } HgfsReplySymlinkCreateV3; #pragma pack(pop) /* HGFS protocol version 4 definitions. */ #define HGFS_HEADER_VERSION_1 1 #define HGFS_HEADER_VERSION HGFS_HEADER_VERSION_1 /* * Flags to indicate the type of packet following the header and * the overall state of the operation. */ #define HGFS_PACKET_FLAG_REQUEST (1 << 0) // Request packet #define HGFS_PACKET_FLAG_REPLY (1 << 1) // Reply packet #define HGFS_PACKET_FLAG_INFO_EXTERROR (1 << 2) // Info has ext error #define HGFS_PACKET_FLAG_VALID_FLAGS (0x7) // Mask for valid values #pragma pack(push, 1) typedef struct HgfsHeader { uint8 version; /* Header version. */ uint8 reserved1[3]; /* Reserved for future use. */ HgfsOp dummy; /* Needed to distinguish between older and newer header. */ uint32 packetSize; /* Size of the packet, including the header size. */ uint32 headerSize; /* Size of the Hgfs header. */ uint32 requestId; /* Request ID. */ HgfsOp op; /* Operation. */ uint32 status; /* Return value. */ uint32 flags; /* Flags. See above. */ uint32 information; /* Generic field, used e.g. for native error code. */ uint64 sessionId; /* Session ID. */ uint64 reserved; /* Reserved for future use. */ } HgfsHeader; #pragma pack(pop) typedef uint32 HgfsOpCapFlags; /* * The operation capability flags. * * These flags apply to all operations and occupy the least significant * 16 bits of the HgfsOpCapFlags type. */ /* * HGFS_OP_CAPFLAG_NOT_SUPPORTED * If no flags are set then the capability is not supported by the host. */ #define HGFS_OP_CAPFLAG_NOT_SUPPORTED 0 /* * HGFS_OP_CAPFLAG_IS_SUPPORTED * Set for each request that is supported by a host or client. * To be set for an Hgfs session both host and client must have the capability. */ #define HGFS_OP_CAPFLAG_IS_SUPPORTED (1 << 0) /* * HGFS_OP_CAPFLAG_ASYNCHRONOUS * Set for each request that can be handled asynchronously by a host or client. * By default all operations are handled synchronously but if this flag is set * by a client and a host then the operation can be handled in an asynchronous manner too. */ #define HGFS_OP_CAPFLAG_ASYNCHRONOUS (1 << 1) /* * The operation specific capability flags. * * These flags apply only to the operation given by the name and occupy the * most significant 16 bits of the HgfsOpCapFlags type. */ /* * Following flags define which optional parameters for file open * requests are supported by the host. * HGFS_OP_CAPFLAG_OPENV4_EA - host is capable of setting EA when creating * a new file. * HGFS_OP_CAPFLAG_OPENV4_ACL - host is capable of setting ACLs when creating * a new file. * HGFS_OP_CAPFLAG_OPENV4_NAMED_STREAMS - opening/enumerating named streams * is supported. * HGFS_OP_CAPFLAG_OPENV4_SHARED_ACCESS - host supports file sharing restrictions. * HGFS_OP_CAPFLAG_OPENV4_UNIX_PERMISSIONS - host stores POSIX permissions with * file. * HGFS_OP_CAPFLAG_OPENV4_POSIX_DELETION - host supports POSIX file deletion semantics. */ #define HGFS_OP_CAPFLAG_OPENV4_EA (1 << 16) #define HGFS_OP_CAPFLAG_OPENV4_ACL (1 << 17) #define HGFS_OP_CAPFLAG_OPENV4_NAMED_STREAMS (1 << 18) #define HGFS_OP_CAPFLAG_OPENV4_SHARED_ACCESS (1 << 19) #define HGFS_OP_CAPFLAG_OPENV4_UNIX_PERMISSIONS (1 << 20) #define HGFS_OP_CAPFLAG_OPENV4_POSIX_DELETION (1 << 21) /* * There is a significant difference in byte range locking semantics between Windows * and POSIX file systems. Windows implements mandatory locking which means that every * read or write request that conflicts with byte range locks is rejected. POSIX has * an advisory locking which means that locks are validated only when another lock is * requested and are not enforced for read/write operations. * Applications in guest OS may expect byte range locking semantics that matches guest * OS which may be different from semantics that is natively supported by host OS. In * this case either HGFS server or HGFS client should provide compensation for the host * OS semantics to maintain application compatibility. * Client must know if the server is capable to provide appropriate byte range locking * semantics to perform some compensation on behalf of server when necessary. * * Following flags define various capabilities of byte range lock implementation on * the host. * * HGFS_OP_CAPFLAG_BYTE_RANGE_LOCKS_64 means that server is capable of locking 64 bit * length ranges. * HGFS_OP_CAPFLAG_BYTE_RANGE_LOCKS_32 means that server is limited to 32-bit ranges. * HGFS_OP_CAPFLAG_BYTE_RANGE_LOCKS_MANDATORY means that server is capable of enforcing * read/write restrictions for locked ranges. * HGFS_OP_CAPFLAG_BYTE_RANGE_LOCKS_ADVISORY means that server supports advisory locking; * locks are validated only for other bytes * range locking and are not enforced * for read/write operations. */ #define HGFS_OP_CAPFLAG_BYTE_RANGE_LOCKS_64 (1 << 16) #define HGFS_OP_CAPFLAG_BYTE_RANGE_LOCKS_32 (1 << 17) #define HGFS_OP_CAPFLAG_BYTE_RANGE_LOCKS_MANDATORY (1 << 18) #define HGFS_OP_CAPFLAG_BYTE_RANGE_LOCKS_ADVISORY (1 << 19) /* HGFS_SUPPORTS_HARD_LINKS is set when the host supports hard links. */ #define HGFS_OP_CAPFLAG_LINKMOVE_HARD_LINKS (1 << 16) /* * HGFS_SET_WATCH_SUPPORTS_FINE_GRAIN_EVENTS is set when host supports * fine grain event reporting for directory notification. */ #define HGFS_OP_CAPFLAG_SET_WATCH_FINE_GRAIN_EVENTS (1 << 16) #pragma pack(push, 1) typedef struct HgfsOpCapability { HgfsOp op; /* Op. */ HgfsOpCapFlags flags; /* Flags. */ } HgfsOpCapability; #pragma pack(pop) typedef HgfsFileName HgfsUserName; typedef HgfsFileName HgfsGroupName; /* Following structures describe user identity on the host which runs HGFS service. */ #pragma pack(push, 1) typedef struct HgfsIdentity { uint32 uid; /* user id. */ uint32 gid; /* Primary group id. */ HgfsUserName user; /* User name in form specified in RFC 3530. */ HgfsGroupName group; /* Group name in form specified in RFC 3530. */ } HgfsIdentity; #pragma pack(pop) #define HGFS_INVALID_SESSION_ID (~((uint64)0)) /* * The HGFS session flags. These determine the state and validity of the session * information. * It is envisaged that flags will be set for notifying the clients of file system * feature support that transcend multiple request types i.e., HGFS opcodes. */ typedef uint32 HgfsSessionFlags; #define HGFS_SESSION_MAXPACKETSIZE_VALID (1 << 0) #define HGFS_SESSION_CHANGENOTIFY_ENABLED (1 << 1) #define HGFS_SESSION_OPLOCK_ENABLED (1 << 2) #define HGFS_SESSION_ASYNC_IO_ENABLED (1 << 3) #pragma pack(push, 1) typedef struct HgfsRequestCreateSessionV4 { uint32 numCapabilities; /* Number of capabilities to follow. */ uint32 maxPacketSize; /* Maximum packet size supported. */ HgfsSessionFlags flags; /* Session capability flags. */ uint32 reserved; /* Reserved for future use. */ HgfsOpCapability capabilities[1]; /* Array of HgfsCapabilities. */ } HgfsRequestCreateSessionV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyCreateSessionV4 { uint64 sessionId; /* Session ID. */ uint32 numCapabilities; /* Number of capabilities to follow. */ uint32 maxPacketSize; /* Maximum packet size supported. */ uint32 identityOffset; /* Offset to HgfsIdentity or 0 if no identity. */ HgfsSessionFlags flags; /* Flags. */ uint32 reserved; /* Reserved for future use. */ HgfsOpCapability capabilities[1]; /* Array of HgfsCapabilities. */ } HgfsReplyCreateSessionV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestDestroySessionV4 { uint64 reserved; /* Reserved for future use. */ } HgfsRequestDestroySessionV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyDestroySessionV4 { uint64 reserved; /* Reserved for future use. */ } HgfsReplyDestroySessionV4; #pragma pack(pop) /* Adds new error status: HGFS_STATUS_INVALID_SESSION. */ /* * If file handle is used to set watch (HGFS_FILE_NAME_USE_FILE_DESC * is set in the fileName), closing this handle implicitly removes the watch. */ #pragma pack(push, 1) typedef struct HgfsRequestSetWatchV4 { uint64 events; /* What events to watch? */ uint32 flags; /* Flags. */ uint64 reserved; /* Reserved for future use. */ HgfsFileNameV3 fileName; /* Filename to watch. */ } HgfsRequestSetWatchV4; #pragma pack(pop) /* * Coarse grain notification event types. */ #define HGFS_ACTION_ADDED (1 << 0) /* File was added. */ #define HGFS_ACTION_REMOVED (1 << 1) /* File was removed. */ #define HGFS_ACTION_MODIFIED (1 << 2) /* File attributes were changed. */ #define HGFS_ACTION_RENAMED (1 << 3) /* File was renamed. */ /* * Fine grain notification event types. * HgfsRequestSetWatch events. */ #define HGFS_NOTIFY_ACCESS (1 << 0) /* File accessed (read) */ #define HGFS_NOTIFY_ATTRIB (1 << 1) /* File attributes changed. */ #define HGFS_NOTIFY_SIZE (1 << 2) /* File size changed. */ #define HGFS_NOTIFY_ATIME (1 << 3) /* Access time changed. */ #define HGFS_NOTIFY_MTIME (1 << 4) /* Modification time changed. */ #define HGFS_NOTIFY_CTIME (1 << 5) /* Attribute time changed. */ #define HGFS_NOTIFY_CRTIME (1 << 6) /* Creation time changed. */ #define HGFS_NOTIFY_NAME (1 << 7) /* File / Directory name. */ #define HGFS_NOTIFY_OPEN (1 << 8) /* File opened */ #define HGFS_NOTIFY_CLOSE_WRITE (1 << 9) /* Modified file closed. */ #define HGFS_NOTIFY_CLOSE_NOWRITE (1 << 10) /* Non-modified file closed. */ #define HGFS_NOTIFY_CREATE_FILE (1 << 11) /* File created */ #define HGFS_NOTIFY_CREATE_DIR (1 << 12) /* Directory created */ #define HGFS_NOTIFY_DELETE_FILE (1 << 13) /* File deleted */ #define HGFS_NOTIFY_DELETE_DIR (1 << 14) /* Directory deleted */ #define HGFS_NOTIFY_DELETE_SELF (1 << 15) /* Watched directory deleted */ #define HGFS_NOTIFY_MODIFY (1 << 16) /* File modified. */ #define HGFS_NOTIFY_MOVE_SELF (1 << 17) /* Watched directory moved. */ #define HGFS_NOTIFY_OLD_FILE_NAME (1 << 18) /* Rename: old file name. */ #define HGFS_NOTIFY_NEW_FILE_NAME (1 << 19) /* Rename: new file name. */ #define HGFS_NOTIFY_OLD_DIR_NAME (1 << 20) /* Rename: old dir name. */ #define HGFS_NOTIFY_NEW_DIR_NAME (1 << 21) /* Rename: new dir name. */ #define HGFS_NOTIFY_CHANGE_EA (1 << 22) /* Extended attributes. */ #define HGFS_NOTIFY_CHANGE_SECURITY (1 << 23) /* Security/permissions. */ #define HGFS_NOTIFY_ADD_STREAM (1 << 24) /* Named stream created. */ #define HGFS_NOTIFY_DELETE_STREAM (1 << 25) /* Named stream deleted. */ #define HGFS_NOTIFY_CHANGE_STREAM_SIZE (1 << 26) /* Named stream size changed. */ #define HGFS_NOTIFY_CHANGE_STREAM_LAST_WRITE (1 << 27) /* Stream timestamp changed. */ #define HGFS_NOTIFY_WATCH_DELETED (1 << 28) /* Dir with watch deleted. */ #define HGFS_NOTIFY_EVENTS_DROPPED (1 << 29) /* Notifications dropped. */ /* HgfsRequestSetWatch flags. */ #define HGFS_NOTIFY_FLAG_WATCH_TREE (1 << 0) /* Watch the entire directory tree. */ #define HGFS_NOTIFY_FLAG_DONT_FOLLOW (1 << 1) /* Don't follow symlinks. */ #define HGFS_NOTIFY_FLAG_ONE_SHOT (1 << 2) /* Generate only one notification. */ #define HGFS_NOTIFY_FLAG_POSIX_HINT (1 << 3) /* Client is POSIX and thus expects * fine grain notification. Server * may provide coarse grain * notification even if this flag is * set. */ typedef uint64 HgfsSubscriberHandle; #define HGFS_INVALID_SUBSCRIBER_HANDLE ((HgfsSubscriberHandle)~((HgfsSubscriberHandle)0)) #pragma pack(push, 1) typedef struct HgfsReplySetWatchV4 { HgfsSubscriberHandle watchId; /* Watch identifier for subsequent references. */ uint64 reserved; /* Reserved for future use. */ } HgfsReplySetWatchV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestRemoveWatchV4 { HgfsSubscriberHandle watchId; /* Watch identifier to remove. */ } HgfsRequestRemoveWatchV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyRemoveWatchV4 { uint64 reserved; /* Reserved for future use. */ } HgfsReplyRemoveWatchV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsNotifyEventV4 { uint32 nextOffset; /* Offset of next event; 0 if it i sthe last one. */ uint64 mask; /* Event occurred. */ uint64 reserved; /* Reserved for future use. */ HgfsFileName fileName; /* Filename. */ } HgfsNotifyEventV4; #pragma pack(pop) /* Too many events, some or all event were dropped by the server. */ #define HGFS_NOTIFY_FLAG_OVERFLOW (1 << 0) /* Watch had been removed either explicitly or implicitly. */ #define HGFS_NOTIFY_FLAG_REMOVED (1 << 1) /* Server generated coasrse grain events. */ #define HGFS_NOTIFY_FLAG_COARSE_GRAIN (1 << 2) #pragma pack(push, 1) typedef struct HgfsRequestNotifyV4 { HgfsSubscriberHandle watchId; /* Watch identifier. */ uint32 flags; /* Various flags. */ uint32 count; /* Number of events occured. */ uint64 reserved; /* Reserved for future use. */ HgfsNotifyEventV4 events[1]; /* Events. HgfsNotifyEvent(s). */ } HgfsRequestNotifyV4; #pragma pack(pop) // Query EA flags values. #define HGFS_QUERY_EA_INDEX_SPECIFIED (1 << 0) #define HGFS_QUERY_EA_SINGLE_ENTRY (1 << 1) #define HGFS_QUERY_EA_RESTART_SCAN (1 << 2) #pragma pack(push, 1) typedef struct HgfsRequestQueryEAV4 { uint32 flags; /* EA flags. */ uint32 index; uint64 reserved; /* Reserved for future use. */ uint32 eaNameLength; /* EA name length. */ uint32 eaNameOffset; /* Offset of the eaName field. */ HgfsFileNameV3 fileName; /* File to watch. */ char eaNames[1]; /* List of NULL terminated EA names. * Actual location of the data depends on * fileName length and defined by eaNameOffset. */ } HgfsRequestQueryEAV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyQueryEAV4 { uint32 nextOffset; /* Offset of the next structure when more then * one record is returned. */ uint32 flags; /* EA flags. */ uint32 index; /* Index needed to resume scan. */ uint64 reserved; /* Reserved for future use. */ uint32 eaDataLength; /* EA value length. */ char eaData[1]; /* NULL termianed EA name followed by EA value. */ } HgfsReplyQueryEAV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsEAV4 { uint32 nextOffset; /* Offset of the next structure in the chain. */ uint32 valueLength; /* EA value length. */ char data[1]; /* NULL terminated EA name followed by EA value. */ } HgfsEAV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestSetEAV4 { uint32 flags; /* Flags, see below. */ uint64 reserved; /* Reserved for future use. */ uint32 numEAs; /* Number of EAs in this request. */ HgfsEAV4 attributes[1]; /* Array of attributes. */ } HgfsRequestSetEAV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplySetEAV4 { uint64 reserved; /* Reserved for future use. */ } HgfsReplySetEAV4; #pragma pack(pop) /* * EA Flags. When both flags are set EA is either created or replaced if it exists. * HGFS_EA_FLAG_CREATE - create if EA is not present, error otherwise. * HGFS_EA_FLAG_REPLACE - Replace exisitng EA. Error if EA not already present. */ #define HGFS_EA_FLAG_CREATE (1 << 0) #define HGFS_EA_FLAG_REPLACE (1 << 1) /* * Byte range lock flag values: * HGFS_RANGE_LOCK_EXCLUSIVE - Requested lock is exclusive when this flag is set, * otherwise it is a shared lock. * HGFS_RANGE_LOCK_FAIL_IMMEDIATLY - If the flag is not set server waits until the * lock becomes available. */ #define HGFS_RANGE_LOCK_EXCLUSIVE (1 << 0) #define HGFS_RANGE_LOCK_FAIL_IMMEDIATLY (1 << 1) #pragma pack(push, 1) typedef struct HgfsRequestLockRangeV4 { HgfsHandle fid; /* File to take lock on. */ uint32 flags; /* Various flags. */ uint64 start; /* Starting offset in the file. */ uint64 length; /* Number of bytes to lock. */ uint64 reserved; /* Reserved for future use. */ } HgfsRequestLockRangeV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyLockRangeV4 { uint64 reserved; /* Reserved for future use. */ } HgfsReplyLockRangeV4; #pragma pack(pop) #define HGFS_RANGE_LOCK_UNLOCK_ALL (1 << 0) #pragma pack(push, 1) typedef struct HgfsRequestUnlockRangeV4 { HgfsHandle fid; /* File to take lock on. */ uint32 flags; /* Various flags. */ uint64 start; /* Starting offset in the file. */ uint64 length; /* Number of bytes to lock. */ uint64 reserved; /* Reserved for future use. */ } HgfsRequestUnlockRangeV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyUnlockRangeV4 { uint64 reserved; /* Reserved for future use. */ } HgfsReplyUnlockRangeV4; #pragma pack(pop) /* * There are three types of oplocks: level 1, batch, and level 2. Both the level 1 and * batch oplocks are "exclusive access" opens. They are used slightly differently, * however, and hence have somewhat different semantics. A level 2 oplock is a "shared * access" grant on the file. * Level 1 is used by a remote client that wishes to modify the data. Once granted a * Level 1 oplock, the remote client may cache the data, modify the data in its cache * and need not write it back to the server immediately. * Batch oplocks are used by remote clients for accessing script files where the file is * opened, read or written, and then closed repeatedly. Thus, a batch oplock * corresponds not to a particular application opening the file, but rather to a remote * clients network file system caching the file because it knows something about the * semantics of the given file access. The name "batch" comes from the fact that this * behavior was observed by Microsoft with "batch files" being processed by command line * utilities. Log files especially exhibit this behavior when a script it being * processed each command is executed in turn. If the output of the script is redirected * to a log file the file fits the pattern described earlier, namely open/write/close. * With many lines in a file this pattern can be repeated hundreds of times. * Level 2 is used by a remote client that merely wishes to read the data. Once granted * a Level 2 oplock, the remote client may cache the data and need not worry that the * data on the remote file server will change without it being advised of that change. * An oplock must be broken whenever the cache consistency guarantee provided by the * oplock can no longer be provided. Thus, whenever a second network client attempts to * access data in the same file across the network, the file server is responsible for * "breaking" the oplocks and only then allowing the remote client to access the file. * This ensures that the data is guaranteed to be consistent and hence we have preserved * the consistency guarantees essential to proper operation. * * HGFS_OPLOCK_NONE: no oplock. No caching on client side. * HGFS_OPLOCK_SHARED: shared (or LEVEL II) oplock. Read caching is allowed. * HGFS_OPLOCK_EXCLUSIVE: exclusive (or LEVEL I) oplock. Read/write caching is allowed. * HGFS_OPLOCK_BATCH: batch oplock. Read/Write and Open caching is allowed. */ #pragma pack(push, 1) typedef struct HgfsRequestServerLockChangeV2 { HgfsHandle fid; /* File to take lock on. */ HgfsLockType serverLock; /* Lock type. */ uint64 reserved; } HgfsRequestServerLockChangeV2; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyServerLockChangeV2 { HgfsLockType serverLock; /* Lock granted. */ uint64 reserved; } HgfsReplyServerLockChangeV2; #pragma pack(pop) /* * This request is sent from server to the client to notify that oplock * is revoked or downgraded. */ #pragma pack(push, 1) typedef struct HgfsRequestOplockBreakV4 { HgfsHandle fid; /* File handle. */ HgfsLockType serverLock; /* Lock downgraded to this type. */ uint64 reserved; /* Reserved for future use. */ } HgfsRequestOplockBreakV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyOplockBreakV4 { HgfsHandle fid; /* File handle. */ HgfsLockType serverLock; /* Lock type. */ uint64 reserved; /* Reserved for future use. */ } HgfsReplyOplockBreakV4; #pragma pack(pop) /* * Flusing of a whole volume is not supported. * Flusing of reqular files is supported on all hosts. * Flusing of directories is supproted on POSIX hosts and is * NOOP on Windows hosts. */ #pragma pack(push, 1) typedef struct HgfsRequestFsyncV4 { HgfsHandle fid; /* File to sync. */ uint64 reserved; } HgfsRequestFsyncV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyFsyncV4 { uint64 reserved; } HgfsReplyFsyncV4; #pragma pack(pop) /* * This request is name based only. * Server fails this request if HGFS_FILE_E_USE_FILE_DESC is set in the fileName. */ #pragma pack(push, 1) typedef struct HgfsRequestAccessCheckV4 { HgfsFileNameV3 fileName; /* File concerned. */ HgfsPermissions perms; /* Permissions to check for. */ uint64 reserved; /* Reserved for future use. */ } HgfsRequestAccessCheckV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyAccessCheckV4 { uint64 reserved; /* Reserved for future use. */ } HgfsReplyAccessCheckV4; #pragma pack(pop) /* * Additional HgfsPersmissions type: checks file existense without * requesting any particular access. * Matches F_OK mode parameter for POSIX access (2) API. */ #define HGFS_PERM_EXISTS 8 /* * HGFS_PLATFORM_ALL is a HGFS specific platform independent FSCTL * that correspond to different OS specific codes. * Other types of FSCTL are platform specific to allow better user * experience when guest and host OS are the same. HGFS does not interpret * platform specific FSCTL in any way, it just passes it through to the * host. If the host run appropriate OS it executes FSCTL on user's behalf, * otherwise it fails the request. */ typedef enum HgfsPlatformType { HGFS_PLATFORM_ALL, HGFS_PLATFORM_WINDOWS, HGFS_PLATFORM_LINUX, HGFS_PLATFORM_MAC }HgfsPlatformType; #define HGFS_FSCTL_SET_SPARSE 1 /* Platform independent FSCTL to make file sparse. */ /* Platform together with the code define exact meaning of the operation. */ #pragma pack(push, 1) typedef struct HgfsRequestFsctlV4 { HgfsHandle fid; uint32 code; HgfsPlatformType platform; uint32 dataLength; char data[1]; } HgfsRequestFsctlV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyFsctlV4 { uint32 dataLength; char data[1]; } HgfsReplyFsctlV4; #pragma pack(pop) /* * Creating a new file or reading file attributes involves ACL. There is a good * definition of multi-platform ACLs in RFC 3530, section 5.11. HGFS should use * ACLs defined in this document (http://tools.ietf.org/html/rfc3530#section-5.11). * ACL support is not mandatory. If a request to create file with ACL comes to a host * that does not support ACL, the request should succeed and setting ACL is ignored. * Such behavior is consistent with other file systems. */ typedef uint64 HgfsOpenCreateOptions; /* O_SYMLINK in Mac OS or FILE_FLAG_OPEN_REPARSE_POINT in Windows. */ #define HGFS_OPENCREATE_OPTION_SYMLINK (1 << 0) /* O_SHLOCK in Mac OS or obtain shared range lock for the whole file. */ #define HGFS_OPENCREATE_OPTION_SHLOCK (1 << 1) /* O_EXLOCK in Mac OS or obtain exclusive range lock for the whole file. */ #define HGFS_OPENCREATE_OPTION_EXLOCK (1 << 2) /* O_SYNC in Linux, ignored in Mac, FILE_FLAG_WRITE_THROUGH in Windows. */ #define HGFS_OPENCREATE_OPTION_WRITETHROUGH (1 << 3) /* FILE_FLAG_NO_BUFFERING in Windows, O_SYNC in Linux, ignored on Mac OS. */ #define HGFS_OPENCREATE_OPTION_NO_BUFERING (1 << 4) /* * O_NOFOLLOW in POSIX. Windows server checks for reparse point * and fails the request if file has one. */ #define HGFS_OPENCREATE_OPTION_NO_FOLLOW (1 << 5) /* FILE_FLAG_NO_RECALL in Windows. Ignored by POSIX host. */ #define HGFS_OPENCREATE_OPTION_NO_RECALL (1 << 6) /* FILE_FLAG_RANDOM_ACCESS in Windows. Ignored by POSIX host. */ #define HGFS_OPENCREATE_OPTION_RANDOM (1 << 7) /* FILE_FLAG_SEQUENTIAL_SCAN in Windows. Ignored by POSIX host. */ #define HGFS_OPENCREATE_OPTION_SEQUENTIAL (1 << 8) /* FILE_FLAG_BACKUP_SEMANTICS in Windows. Ignored by POSIX host. */ #define HGFS_OPENCREATE_OPTION_BACKUP_SEMANTICS (1 << 9) /* Fail opening if the file already exists and it is not a directory. */ #define HGFS_OPENCREATE_OPTION_DIRECTORY (1 << 10) /* Fail opening if the file already exists and it is a directory. */ #define HGFS_OPENCREATE_OPTION_NON_DIRECTORY (1 << 11) #pragma pack(push, 1) typedef struct HgfsRequestOpenV4 { HgfsOpenValid mask; /* Bitmask that specified which fields are valid. */ HgfsOpenMode mode; /* Which type of access requested. See desiredAccess */ HgfsOpenFlags flags; /* Which flags to open the file with */ HgfsPermissions specialPerms; /* Desired 'special' permissions for file creation */ HgfsPermissions ownerPerms; /* Desired 'owner' permissions for file creation */ HgfsPermissions groupPerms; /* Desired 'group' permissions for file creation */ HgfsPermissions otherPerms; /* Desired 'other' permissions for file creation */ HgfsAttrFlags attr; /* Attributes, if any, for file creation */ uint64 allocationSize; /* How much space to pre-allocate during creation */ uint32 desiredAccess; /* Extended support for windows access modes */ uint32 shareAccess; /* Windows only, share access modes */ HgfsOpenCreateOptions createOptions; /* Various options. */ HgfsLockType requestedLock; /* The type of lock desired by the client */ HgfsFileNameV3 fileName; /* fid can be used only for relative open, * i.e. to open named stream. */ HgfsFileName streamName; /* Name of the alternative named stream. * All flags are the same as defined in fileName. * The name is used in conjuction with fileName * field, for example if Windows opens file * "abc.txt:stream" then fileName contains * "abc.txt" and streamName contains "stream" */ /* * EA to set if the file is created or overwritten. The parameter should be ignored * if the file already exists. * It is needed to correctly implement Windows semantics for opening files. * It should work atomically - failure to add EA should result in failure to create * the new file. * If the host file system does not support EA server should fail the request rather * then succeeding and silently dropping EA. */ HgfsRequestSetEAV4 extendedAttributes; uint32 aclLength; /* Length of the acl field. */ char acl[1]; /* Multi-platform ACL as defined in RFC 3530. */ } HgfsRequestOpenV4; #pragma pack(pop) typedef enum HgfsOpenResult { HGFS_FILE_OPENED, HGFS_FILE_CREATED, HGFS_FILE_OVERWRITTEN, HGFS_FILE_SUPERSIDED, } HgfsOpenResult; /* * Win32 API has a special value for the desired access - MAXIMUM_ALLOWED. * Such desired access means that file system must grant as much rights for the file * as it is allowed for the current user. * HGFS client must know what access rights were granted to properly communicate this * information to the IoManager; grantedAccess field is used for this purpose. */ #pragma pack(push, 1) typedef struct HgfsReplyOpenV4 { HgfsHandle file; /* Opaque file ID used by the server */ HgfsLockType grantedLock; /* The type of lock acquired by the server */ HgfsOpenResult openResult; /* Opened/overwritten or a new file created? */ uint32 grantedAccess; /* Granted access rights. */ uint64 fileId; /* Persistent volume-wide unique file id. */ uint64 volumeId; /* Persistent unique volume id. */ } HgfsReplyOpenV4; #pragma pack(pop) /* * Flags that define behaviour of the move/creating hard link operation. */ typedef uint64 HgfsMoveLinkFlags; #define HGFS_LINKMOVE_FLAG_REPLACE_EXISTING (1 << 0) /* Delete existing target. */ #define HGFS_LINKMOVE_FLAG_HARD_LINK (1 << 1) /* Create hard link. */ #pragma pack(push, 1) typedef struct HgfsRequestLinkMoveV4 { HgfsFileNameV3 oldFileName; /* Path to the exisitng source file.*/ HgfsFileNameV3 newFileName; /* Path to the destinatio name.*/ HgfsMoveLinkFlags flags; /* Flags that define behaviour of the operation.*/ } HgfsRequestLinkMoveV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyLinkMove4 { uint64 reserved; /* Reserved for future use. */ } HgfsReplyLinkMove4; #pragma pack(pop) /* * HgfsQueryVolumeMaskV4 mask in a request defines which volume properties client needs; * mask in a reply defines which properties were actually returned by the host. * * HGFS_QUERY_VOLUME_MASK_SIZE controls totalBytes, freeBytes and availableBytes. * HGFS_QUERY_VOLUME_MASK_FS_CAPABILITIES controls capabilities. * HGFS_QUERY_VOLUME_MASK_ATTRIBUTES controls creationTime. * HGFS_QUERY_VOLUME_MASK_VOLUME_GEOMETRY controls bytesPerSector and sectorPerCluster. * HGFS_QUERY_VOLUME_MASK_VOLUME_LABEL controls volume label. * HGFS_QUERY_VOLUME_MASK_FS_NAME controls fileSystemName. */ typedef uint64 HgfsQueryVolumeMaskV4; #define HGFS_QUERY_VOLUME_MASK_SIZE (1 << 0) #define HGFS_QUERY_VOLUME_MASK_ATTRIBUTES (1 << 1) #define HGFS_QUERY_VOLUME_MASK_FS_CAPABILITIES (1 << 2) #define HGFS_QUERY_VOLUME_MASK_VOLUME_LABEL (1 << 3) #define HGFS_QUERY_VOLUME_MASK_VOLUME_GEOMETRY (1 << 4) #define HGFS_QUERY_VOLUME_MASK_FS_NAME (1 << 5) typedef uint64 HgfsFileSystemCapabilities; #define HGFS_VOLUME_CASE_SENSITIVE (1 << 0) #define HGFS_VOLUME_SUPPORTS_EA (1 << 1) #define HGFS_VOLUME_SUPPORTS_COMPRESSION (1 << 2) #define HGFS_VOLUME_SUPPORTS_SHORT_NAMES (1 << 3) #define HGFS_VOLUME_SUPPORTS_ACL (1 << 4) #define HGFS_VOLUME_READ_ONLY (1 << 5) #define HGFS_VOLUME_SUPPORTS_ENCRYPTION (1 << 6) #define HGFS_VOLUME_SUPPORTS_OBJECT_ID (1 << 7) #define HGFS_VOLUME_SUPPORTS_REMOTE_STORAGE (1 << 8) #define HGFS_VOLUME_SUPPORTS_SYMLINKS (1 << 9) #define HGFS_VOLUME_SUPPORTS_SPARSE_FILES (1 << 10) #define HGFS_VOLUME_SUPPORTS_UNICODE (1 << 11) #define HGFS_VOLUME_SUPPORTS_QUOTA (1 << 12) #define HGFS_VOLUME_SUPPORTS_NAMED_STREAMS (1 << 13) #pragma pack(push, 1) typedef struct HgfsRequestQueryVolumeV4 { HgfsQueryVolumeMaskV4 mask; HgfsFileNameV3 name; } HgfsRequestQueryVolumeV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyQueryVolumeV4 { HgfsQueryVolumeMaskV4 mask; /* Identifies which values were set by the host. */ uint64 totalBytes; /* Total volume capacity. */ uint64 freeBytes; /* Free space on the volume. */ uint64 availableBytes; /* Free space available for the user. */ HgfsFileSystemCapabilities capabilities; /* File system capabilities. */ uint64 creationTime; /* Volume creation time. */ uint32 bytesPerSector; /* Sector size for the volume. */ uint32 sectorsPerCluster; /* Cluster size for the volume. */ HgfsFileName volumeLabel; /* Volume name or label. */ HgfsFileName fileSystemName;/* File system name. */ } HgfsReplyQueryVolumeV4; #pragma pack(pop) typedef uint32 HgfsSearchReadMask; #define HGFS_SEARCH_READ_NAME (1 << 0) #define HGFS_SEARCH_READ_SHORT_NAME (1 << 1) #define HGFS_SEARCH_READ_FILE_SIZE (1 << 2) #define HGFS_SEARCH_READ_ALLOCATION_SIZE (1 << 3) #define HGFS_SEARCH_READ_EA_SIZE (1 << 4) #define HGFS_SEARCH_READ_TIME_STAMP (1 << 5) #define HGFS_SEARCH_READ_FILE_ATTRIBUTES (1 << 6) #define HGFS_SEARCH_READ_FILE_NODE_TYPE (1 << 7) #define HGFS_SEARCH_READ_REPARSE_TAG (1 << 8) #define HGFS_SEARCH_READ_FILE_ID (1 << 9) typedef uint32 HgfsSearchReadFlags; #define HGFS_SEARCH_READ_INITIAL_QUERY (1 << 1) #define HGFS_SEARCH_READ_SINGLE_ENTRY (1 << 2) #define HGFS_SEARCH_READ_FID_OPEN_V4 (1 << 3) #define HGFS_SEARCH_READ_REPLY_FINAL_ENTRY (1 << 4) /* * Read directory request can be used to enumerate files in a directory. * File handle used in the request can be either from HgfsRequestOpenV4 or * HgfsRequestSearchOpenV3. * searchPattern parameter allows filter out file names in the server for optimization. * It is optional - host may ignore patterns and return entries that do not match * the pattern. It is client responsibility to filter out names that do not match * the pattern. * * The mask field in request allows client to specify which properties it is * interested in. It allows to implement optimization in the server by skipping * parameters which client does not need. * * The HGFS Server fills mask field in the reply buffer to specify which * of the requested properties it supports, which may be a subset of the * requested properties. */ #pragma pack(push, 1) typedef struct HgfsRequestSearchReadV4 { HgfsSearchReadMask mask; HgfsSearchReadFlags flags; HgfsHandle fid; uint32 replyDirEntryMaxSize; uint32 restartIndex; uint64 reserved; HgfsFileName searchPattern; } HgfsRequestSearchReadV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsDirEntryV4 { uint32 nextEntryOffset; uint32 fileIndex; HgfsSearchReadMask mask; /* Returned mask: may be a subset of requested mask. */ HgfsAttrFlags attrFlags; /* File system attributes of the entry */ HgfsFileType fileType; uint64 fileSize; uint64 allocationSize; uint64 creationTime; uint64 accessTime; uint64 writeTime; uint64 attrChangeTime; uint64 hostFileId; /* File Id of the file on host: inode_t on Linux */ uint32 eaSize; /* Byte size of any extended attributes. */ uint32 reparseTag; /* Windows only: reparse point tag. */ uint64 reserved; /* Reserved for future use. */ HgfsShortFileName shortName; /* Windows only: 8 dot 3 format name. */ HgfsFileName fileName; /* Entry file name. */ } HgfsDirEntryV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplySearchReadV4 { uint32 numberEntriesReturned; /* number of directory entries in this reply. */ uint32 offsetToContinue; /* Entry index of the directory entry. */ HgfsSearchReadFlags flags; /* Flags to indicate reply specifics */ uint64 reserved; /* Reserved for future use. */ HgfsDirEntryV4 entries[1]; /* Unused as entries transfered using shared memory. */ } HgfsReplySearchReadV4; #pragma pack(pop) /* * File handle returned by HgfsRequestOpenV4 or later. Descriptors returned by * HgfsHandle fid; earlier versions of HgfsRequestOpen are not supported. */ #pragma pack(push, 1) typedef struct HgfsRequestEnumerateStreamsV4 { uint32 restartIndex; } HgfsRequestEnumerateStreamsV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestStreamEntryV4 { uint32 nextEntryOffset; uint32 fileIndex; HgfsFileName fileName; } HgfsRequestStreamEntryV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyEnumerateStreamsV4 { uint32 numberEntriesReturned; uint32 offsetToContinue; uint64 reserved; HgfsRequestStreamEntryV4 entries[1]; } HgfsReplyEnumerateStreamsV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestGetattrV4 { uint32 mask; uint32 flags; uint64 reserved; HgfsFileNameV3 name; } HgfsRequestGetattrV4; #pragma pack(pop) /* * V4 reports different file size for symlinks then V3 or V2. * It does not return file name length as EOF - it reports actual EOF. * On POSIX the value is always 0 and on Windows it is an actual EOF of * a file with a reparse point. * Each client must adjust the value for file size according to guest OS rules. * * Mask in HgfsAttr2V2 should be extended to include short name, symlink target and ACL. * If the host does not support a requested feature it is free to clear the * correspondent bit in the mask and ignore the feature. * * Multi-platform notice: symbolic link is represented by a file with REPARSE_POINT * on Windows. Thus Windows supports swtiching a file type between * regular or directory => symlink and back. * Setting symlinkTarget attribute on Windows host results in assigning * reparse point to the host file. */ #pragma pack(push, 1) typedef struct HgfsAttrV4 { HgfsAttrV2 attr; uint32 numberOfLinks; HgfsFileName shortName; HgfsFileName symlinkTarget; uint32 aclLength; uint64 reserved; char acl[1]; } HgfsAttrV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyGetattrV4 { HgfsAttrV4 attr; } HgfsReplyGetattrV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsRequestSetattrV4 { HgfsAttrHint hints; HgfsAttrV2 attr; uint64 reserved; /* Reserved for future use */ HgfsFileNameV3 fileName; /* Filename used when file handle invalid. */ } HgfsRequestSetattrV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplySetattrV4 { uint32 mask; /* Defines which attributes were set. */ } HgfsReplySetattrV4; #pragma pack(pop) /* * Unlike V3 deletion this command can be used to delete both files and directories. * Its semantics depends on whether fid or file path is specified in the fileName. * When path is used it implements/emulates POSIX semantics - name is deleted from * the directory however if the file is opened it is still accessible. When fid is used * the file name disappears from the folder only when the last handle for the file is * closed - Windows style deletion. */ #pragma pack(push, 1) typedef struct HgfsRequestDeleteFileV4 { HgfsFileNameV3 fileName; } HgfsRequestDeleteFileV4; #pragma pack(pop) #pragma pack(push, 1) typedef struct HgfsReplyDeleteFileV4 { uint64 reserved; } HgfsReplyDeleteFileV4; #pragma pack(pop) #endif /* _HGFS_PROTO_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsServer.h000066400000000000000000000170511470176644300250050ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2020,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _HGFS_SERVER_H_ #define _HGFS_SERVER_H_ #include "dbllnklst.h" #include "hgfs.h" /* for HGFS_PACKET_MAX */ #include "vm_basic_defs.h" /* for vmx86_debug */ #if defined(__cplusplus) extern "C" { #endif #define HGFS_VMX_IOV_CONTEXT_SIZE (vmx86_debug ? 112 : 96) typedef struct HgfsVmxIov { void *va; /* Virtual addr */ uint64 pa; /* Physical address passed by the guest */ uint32 len; /* length of data; should be <= PAGE_SIZE for VMCI; arbitrary for backdoor */ union { void *ptr; char clientStorage[HGFS_VMX_IOV_CONTEXT_SIZE]; } context; /* Mapping context */ } HgfsVmxIov; typedef enum { BUF_READABLE, /* Establish readable mappings */ BUF_WRITEABLE, /* Establish writeable mappings */ BUF_READWRITEABLE, /* Establish read-writeable mappings */ } MappingType; typedef uint64 HgfsStateFlags; #define HGFS_STATE_CLIENT_REQUEST (1 << 0) #define HGFS_STATE_ASYNC_REQUEST (1 << 1) typedef struct HgfsPacket { uint64 id; HgfsStateFlags state; /* For metapacket we always establish writeable mappings */ void *metaPacket; size_t metaPacketSize; uint32 metaPacketMappedIov; size_t metaPacketDataSize; Bool metaPacketIsAllocated; MappingType metaMappingType; void *dataPacket; size_t dataPacketSize; uint32 dataPacketMappedIov; size_t dataPacketDataSize; uint32 dataPacketIovIndex; Bool dataPacketIsAllocated; /* What type of mapping was established - readable/ writeable ? */ MappingType dataMappingType; void *replyPacket; size_t replyPacketSize; size_t replyPacketDataSize; Bool replyPacketIsAllocated; /* Iov for the packet private to the channel. */ HgfsVmxIov channelIov[2]; uint32 iovCount; HgfsVmxIov iov[1]; } HgfsPacket; /* * Function used for sending replies to the client for a session. * Passed by the caller at session connect time. */ /* * Send flags. * * Contains a bitwise OR of a combination of the following flags: * HGFS_SEND_CAN_DELAY - directs the channel to try and optimize * otherwise it will send the data immediately. * HGFS_SEND_NO_COMPLETE - directs the channel to not call the * send complete callback. Caller does not call completion notification * callback, for example to free buffers. */ typedef uint32 HgfsSendFlags; #define HGFS_SEND_CAN_DELAY (1 << 0) #define HGFS_SEND_NO_COMPLETE (1 << 1) // Channel capability flags typedef uint32 HgfsChannelFlags; #define HGFS_CHANNEL_SHARED_MEM (1 << 0) #define HGFS_CHANNEL_ASYNC (1 << 1) typedef struct HgfsServerChannelData { HgfsChannelFlags flags; uint32 maxPacketSize; }HgfsServerChannelData; /* Default maximum number of open nodes. */ #define HGFS_MAX_CACHED_FILENODES 30 typedef uint32 HgfsConfigFlags; #define HGFS_CONFIG_USE_HOST_TIME (1 << 0) #define HGFS_CONFIG_NOTIFY_ENABLED (1 << 1) #define HGFS_CONFIG_VOL_INFO_MIN (1 << 2) #define HGFS_CONFIG_OPLOCK_ENABLED (1 << 3) #define HGFS_CONFIG_SHARE_ALL_HOST_DRIVES_ENABLED (1 << 4) #define HGFS_CONFIG_THREADPOOL_ENABLED (1 << 5) #define HGFS_CONFIG_OPLOCK_MONITOR_ENABLED (1 << 6) typedef struct HgfsServerConfig { HgfsConfigFlags flags; uint32 maxCachedOpenNodes; }HgfsServerConfig; /* * Function used to notify HGFS server that a shared folder has been created or updated. * It allows HGFS server to maintain up-to-date list of shared folders and its * properties. */ typedef uint32 HgfsSharedFolderHandle; #define HGFS_INVALID_FOLDER_HANDLE ((HgfsSharedFolderHandle)~((HgfsSharedFolderHandle)0)) /* * Callback functions to enumerate the share resources. * Filled in by the HGFS server policy and passed in to the HGFS server * so that it can call out to them to enumerate the shares. */ typedef void * (*HgfsServerResEnumInitFunc)(void); typedef Bool (*HgfsServerResEnumGetFunc)(void *data, char const **name, size_t *len, Bool *done); typedef Bool (*HgfsServerResEnumExitFunc)(void *); typedef struct HgfsServerResEnumCallbacks { HgfsServerResEnumInitFunc init; HgfsServerResEnumGetFunc get; HgfsServerResEnumExitFunc exit; } HgfsServerResEnumCallbacks; /* * Server Manager callback functions to enumerate the share resources and state logging. * Passed to the HGFS server on initialization. */ typedef struct HgfsServerMgrCallbacks { HgfsServerResEnumCallbacks enumResources; } HgfsServerMgrCallbacks; typedef enum { HGFS_QUIESCE_CHANNEL_FREEZE, /*Op sent before the channel device quiesce*/ HGFS_QUIESCE_FREEZE, HGFS_QUIESCE_THAW, } HgfsQuiesceOp; /* * Function used for invalidating nodes and searches that fall outside of a * share when the list of shares changes. */ typedef void (*HgfsInvalidateObjectsFunc)(DblLnkLst_Links *shares); typedef Bool (*HgfsChannelSendFunc)(void *opaqueSession, HgfsPacket *packet, HgfsSendFlags flags); typedef void * (*HgfsChannelMapVirtAddrFunc)(HgfsVmxIov *iov); typedef void (*HgfsChannelUnmapVirtAddrFunc)(void *context); typedef void (*HgfsChannelRegisterThreadFunc)(void); typedef void (*HgfsChannelUnregisterThreadFunc)(void); typedef struct HgfsServerChannelCallbacks { HgfsChannelMapVirtAddrFunc getReadVa; HgfsChannelMapVirtAddrFunc getWriteVa; HgfsChannelUnmapVirtAddrFunc putVa; HgfsChannelSendFunc send; }HgfsServerChannelCallbacks; typedef struct HgfsServerSessionCallbacks { Bool (*connect)(void *, HgfsServerChannelCallbacks *, HgfsServerChannelData *,void **); void (*disconnect)(void *); void (*close)(void *); void (*receive)(HgfsPacket *packet, void *); void (*invalidateObjects)(void *, DblLnkLst_Links *); uint32 (*invalidateInactiveSessions)(void *); void (*sendComplete)(HgfsPacket *, void *); void (*quiesce)(void *, HgfsQuiesceOp); } HgfsServerSessionCallbacks; /* XXX: TODO delete this layer if no other non-session callbacks are required. */ typedef struct HgfsServerCallbacks { HgfsServerSessionCallbacks session; } HgfsServerCallbacks; Bool HgfsServer_InitState(const HgfsServerCallbacks **, HgfsServerConfig *, HgfsServerMgrCallbacks *); void HgfsServer_ExitState(void); Bool HgfsServer_ShareAccessCheck(HgfsOpenMode accessMode, Bool shareWriteable, Bool shareReadable); uint32 HgfsServer_GetHandleCounter(void); void HgfsServer_SetHandleCounter(uint32 newHandleCounter); #if defined(__cplusplus) } // extern "C" #endif #endif // _HGFS_SERVER_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsServerManager.h000066400000000000000000000052231470176644300262760ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _HGFS_SERVER_MANAGER_H_ # define _HGFS_SERVER_MANAGER_H_ #if defined(__cplusplus) extern "C" { #endif /* * hgfsServerManager.h -- * * Common routines needed to register an HGFS server. */ #ifndef VMX86_TOOLS #include "device_shared.h" // For DeviceLock and functions Bool Hgfs_PowerOn(void); void HgfsServerManager_GetDeviceLock(DeviceLock **lock); Bool HgfsServerManager_ChangeState(Bool enable); #else /* VMX86_TOOLS */ //#include "hgfsServer.h" // For HgfsReceiveFlags typedef struct HgfsServerMgrData { const char *appName; // Application name to register void *rpc; // RpcChannel unused void *rpcCallback; // RpcChannelCallback unused void *connection; // Connection object returned on success } HgfsServerMgrData; #define HgfsServerManager_DataInit(mgr, _name, _rpc, _rpcCallback) \ do { \ (mgr)->appName = (_name); \ (mgr)->rpc = (_rpc); \ (mgr)->rpcCallback = (_rpcCallback); \ (mgr)->connection = NULL; \ } while (0) Bool HgfsServerManager_Register(HgfsServerMgrData *data); void HgfsServerManager_Unregister(HgfsServerMgrData *data); Bool HgfsServerManager_ProcessPacket(HgfsServerMgrData *mgrData, char const *packetIn, size_t packetInSize, char *packetOut, size_t *packetOutSize); uint32 HgfsServerManager_InvalidateInactiveSessions(HgfsServerMgrData *mgrData); #endif #if defined(__cplusplus) } // extern "C" #endif #endif // _HGFS_SERVER_MANAGER_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsServerPolicy.h000066400000000000000000000120031470176644300261550ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _HGFS_SERVER_POLICY_H_ #define _HGFS_SERVER_POLICY_H_ #include "vm_basic_types.h" #include "hgfs.h" #include "dbllnklst.h" #include "cpName.h" #include "hgfsServer.h" #if defined(__cplusplus) extern "C" { #endif /* * Name of share that corresponds to the root of the server's * filesystem. */ #define HGFS_SERVER_POLICY_ROOT_SHARE_NAME "root" typedef uint32 HgfsShareOptions; /* * Structure representing one shared folder. We maintain a list of * these to check accesses against. */ typedef struct HgfsSharedFolder { DblLnkLst_Links links; const char *name; /* Name of share */ const char *path; /* * Path of share in server's filesystem. Should * not include final path separator. */ const char *shareTags;/* Tags associated with this share (comma delimited). */ size_t shareTagsLen; /* Length of shareTag string */ size_t nameLen; /* Length of name string */ size_t pathLen; /* Length of path string */ Bool readAccess; /* Read permission for this share */ Bool writeAccess; /* Write permission for this share */ HgfsShareOptions configOptions; /* User-config options. */ HgfsSharedFolderHandle handle; /* Handle assigned by HGFS server * when the folder was registered with it. * Policy package keeps the context and returns * it along with other shared folder properties. * Keeping it here ensures consistent lookup all * properties of the shared folder which takes into * account such details like case sensitive/case * insensitive name lookup. */ } HgfsSharedFolder; /* Per share user configurable options. */ #define HGFS_SHARE_HOST_DEFAULT_CASE (1 << 0) #define HGFS_SHARE_FOLLOW_SYMLINKS (1 << 1) typedef struct HgfsServerPolicy_ShareList { size_t count; char **shareNames; } HgfsServerPolicy_ShareList; Bool HgfsServerPolicy_Init(HgfsInvalidateObjectsFunc invalidateObjects, HgfsServerResEnumCallbacks *enumResources); Bool HgfsServerPolicy_Cleanup(void); HgfsNameStatus HgfsServerPolicy_GetSharePath(char const *nameIn, // IN: size_t nameInLen, // IN: HgfsOpenMode mode, // IN: size_t *sharePathLen, // OUT: char const **sharePath); // OUT: HgfsNameStatus HgfsServerPolicy_GetShareMode(char const *nameIn, // IN: Share name to retrieve size_t nameInLen, // IN: Length of Share name HgfsOpenMode *mode); // OUT: Share's access mode HgfsNameStatus HgfsServerPolicy_GetShareOptions(char const *nameIn, // IN: Share name size_t nameInLen, // IN: Share name length HgfsShareOptions *configOptions); // OUT: Share config options Bool HgfsServerPolicy_IsShareOptionSet(HgfsShareOptions shareOptions, // IN: Config options uint32 option); // IN: Option to check HgfsNameStatus HgfsServerPolicy_ProcessCPName(char const *nameIn, // IN: name in CPName form size_t nameInLen, // IN: length of the name Bool *readAccess, // OUT: Read permissions Bool *writeAccess, // OUT: Write permissions HgfsSharedFolderHandle *handle,// OUT: folder handle char const **shareBaseDir); // OUT: Shared directory void HgfsServerPolicy_FreeShareList(HgfsServerPolicy_ShareList *shareList); // IN: list to free HgfsServerPolicy_ShareList * HgfsServerPolicy_GetSharesWithTag(const char *tag); // IN: tag to search for #if defined(__cplusplus) } // extern "C" #endif #endif // _HGFS_SERVER_POLICY_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsUri.h000066400000000000000000000025321470176644300242740ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hgfsUri.h * * Provides a library for guest applications to convert local pathames to * x-vmware-share:// style URIs */ #ifndef _HGFS_URI_H_ #define _HGFS_URI_H_ #include "vm_basic_types.h" #include "unicode.h" #if defined(_WIN32) char *HgfsUri_ConvertFromUtf16ToHgfsUri(wchar_t *pathNameUtf16, Bool hgfsOnly); #endif // _WIN32 #if defined __linux__ || defined __APPLE__ char *HgfsUri_ConvertFromPathToHgfsUri(const char *pathName, Bool hgfsOnly); #endif // POSIX #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsUtil.h000066400000000000000000000145141470176644300244550ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfsUtil.h -- * * Utility functions and macros used by hgfs. */ #ifndef _HGFSUTIL_H_ # define _HGFSUTIL_H_ # if defined __linux__ && defined __KERNEL__ # include "driver-config.h" # include // for time_t and timespec /* Include time.h in userspace code, but not in Solaris kernel code. */ # elif defined __FreeBSD__ && defined _KERNEL /* Do nothing. */ # elif defined __APPLE__ && defined KERNEL # include # else # include # endif # include "vm_basic_types.h" # if !defined _STRUCT_TIMESPEC && \ !defined _TIMESPEC_DECLARED && \ !defined __timespec_defined && \ !defined sun && \ !defined __FreeBSD__ && \ !__APPLE__ && \ !defined _WIN32 struct timespec { time_t tv_sec; long tv_nsec; }; # endif # include "hgfs.h" /* Cross-platform representation of a platform-specific error code. */ #ifndef _WIN32 # if defined __KERNEL__ || defined _KERNEL || defined KERNEL # if defined __linux__ # include # elif defined sun || defined __FreeBSD__ || defined __APPLE__ # include # endif # else # include # endif typedef int HgfsInternalStatus; /* * There is no internal error in Linux. * Define a const that is converted to HGFS_INTERNAL_STATUS_ERROR. */ # define EINTERNAL 1001 #else # include typedef DWORD HgfsInternalStatus; #endif #if defined _WIN32 #define HGFS_ERROR_SUCCESS ERROR_SUCCESS #define HGFS_ERROR_IO ERROR_IO_DEVICE #define HGFS_ERROR_ACCESS_DENIED ERROR_ACCESS_DENIED #define HGFS_ERROR_INVALID_PARAMETER ERROR_INVALID_PARAMETER #define HGFS_ERROR_INVALID_HANDLE ERROR_INVALID_HANDLE #define HGFS_ERROR_PROTOCOL RPC_S_PROTOCOL_ERROR #define HGFS_ERROR_STALE_SESSION ERROR_CONNECTION_INVALID #define HGFS_ERROR_BUSY ERROR_RETRY #define HGFS_ERROR_PATH_BUSY ERROR_RETRY #define HGFS_ERROR_FILE_NOT_FOUND ERROR_FILE_NOT_FOUND #define HGFS_ERROR_FILE_EXIST ERROR_ALREADY_EXISTS #define HGFS_ERROR_NOT_SUPPORTED ERROR_NOT_SUPPORTED #define HGFS_ERROR_NOT_ENOUGH_MEMORY ERROR_NOT_ENOUGH_MEMORY #define HGFS_ERROR_TOO_MANY_SESSIONS ERROR_MAX_SESSIONS_REACHED #define HGFS_ERROR_INTERNAL ERROR_INTERNAL_ERROR #else #define HGFS_ERROR_SUCCESS 0 #define HGFS_ERROR_IO EIO #define HGFS_ERROR_ACCESS_DENIED EACCES #define HGFS_ERROR_INVALID_PARAMETER EINVAL #define HGFS_ERROR_INVALID_HANDLE EBADF #define HGFS_ERROR_PROTOCOL EPROTO #define HGFS_ERROR_STALE_SESSION ENETRESET #define HGFS_ERROR_BUSY EBUSY #define HGFS_ERROR_PATH_BUSY EBUSY #define HGFS_ERROR_FILE_NOT_FOUND ENOENT #define HGFS_ERROR_FILE_EXIST EEXIST #define HGFS_ERROR_NOT_SUPPORTED EOPNOTSUPP #define HGFS_ERROR_NOT_ENOUGH_MEMORY ENOMEM #define HGFS_ERROR_TOO_MANY_SESSIONS ECONNREFUSED #define HGFS_ERROR_INTERNAL EINTERNAL #endif // _WIN32 /* * Unfortunately, we need a catch-all "generic error" to use with * HgfsInternalStatus, because there are times when cross-platform code needs * to return its own errors along with errors from platform specific code. * * Using -1 should be safe because we expect our platforms to use zero as * success and a positive range of numbers as error values. */ #define HGFS_INTERNAL_STATUS_ERROR (-1) #ifndef _WIN32 /* * This error code is used to notify the client that some of the parameters passed * (e.g. file handles) are not supported. Clients are expected to correct * the parameter (e.g. pass file name instead) and retry. * * Note that this error code is artificially made up and in future may conflict * with an "official" error code when added. */ #define EPARAMETERNOTSUPPORTED (MAX_INT32 - 1) #endif /* * FreeBSD (pre-6.0) does not define EPROTO, so we'll define our own error code. */ #if defined __FreeBSD__ && !defined EPROTO #define EPROTO (ELAST + 1) #endif #define HGFS_NAME_BUFFER_SIZE(packetSize, request) (packetSize - (sizeof *request - 1)) #define HGFS_NAME_BUFFER_SIZET(packetSize, sizet) (packetSize - ((sizet) - 1)) #ifndef _WIN32 /* * Routines for converting between Win NT and unix time formats. The * hgfs attributes use the NT time formats, so the linux driver and * server have to convert back and forth. [bac] */ uint64 HgfsConvertToNtTime(time_t unixTime, // IN long nsec); // IN static INLINE uint64 HgfsConvertTimeSpecToNtTime(const struct timespec *unixTime) // IN { return HgfsConvertToNtTime(unixTime->tv_sec, unixTime->tv_nsec); } int HgfsConvertFromNtTime(time_t * unixTime, // OUT uint64 ntTime); // IN int HgfsConvertFromNtTimeNsec(struct timespec *unixTime, // OUT uint64 ntTime); // IN #endif /* !def(_WIN32) */ HgfsStatus HgfsConvertFromInternalStatus(HgfsInternalStatus status); // IN #endif /* _HGFSUTIL_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hgfsVirtualDir.h000066400000000000000000000034741470176644300256300ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * hgfsVirtualDir.h -- * * Defines for virtual directory names in hgfs. */ #ifndef _HGFSVIRTUALDIR_H_ # define _HGFSVIRTUALDIR_H_ /* * These are the names of the virtual directories for accessing UNC * names and drives on the host machine. */ # define HGFS_DRIVE_DIR_NAME "drive" # define HGFS_UNC_DIR_NAME "unc" #define HGFS_STR_LEN(str) (sizeof str - 1) #endif /* _HGFSVIRTUALDIR_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hostType.h000066400000000000000000000026721470176644300245110ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hostType.h -- * * Interface to host-specific information functions * */ #ifndef _HOSTTYPE_H_ #define _HOSTTYPE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif Bool HostType_OSIsVMK(void); Bool HostType_OSIsSimulator(void); /* Old name. TODO: remove */ static INLINE Bool HostType_OSIsPureVMK(void) { return HostType_OSIsVMK(); } #if defined(__cplusplus) } // extern "C" #endif #endif /* ifndef _HOSTTYPE_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/hostinfo.h000066400000000000000000000214061470176644300245170ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2024 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * hostinfo.h -- * * Interface to host-specific information functions * */ #if !defined(_HOSTINFO_H_) #define _HOSTINFO_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_types.h" #include "vm_basic_defs.h" #include "x86vendor.h" #include "unicodeTypes.h" #include "x86cpuid.h" #if defined(__cplusplus) extern "C" { #endif #define MAX_OS_NAME_LEN 128 #define MAX_OS_FULLNAME_LEN 512 typedef enum { HOSTINFO_PROCESS_QUERY_DEAD, // Procss is dead (does not exist) HOSTINFO_PROCESS_QUERY_ALIVE, // Process is alive (does exist) HOSTINFO_PROCESS_QUERY_UNKNOWN // Process existence cannot be determined } HostinfoProcessQuery; typedef struct HostinfoProcessSnapshot HostinfoProcessSnapshot; HostinfoProcessSnapshot *Hostinfo_AcquireProcessSnapshot(void); void Hostinfo_ReleaseProcessSnapshot(HostinfoProcessSnapshot *s); HostinfoProcessQuery Hostinfo_QueryProcessSnapshot(HostinfoProcessSnapshot *s, int pid); HostinfoProcessQuery Hostinfo_QueryProcessExistence(int pid); HostinfoProcessQuery Hostinfo_QueryProcessReaped(int pid); /* This macro defines the current version of the structured header. */ #define HOSTINFO_STRUCT_HEADER_VERSION 1 /* * This struct is used to build a detailed OS data. The detailed OS data will * be composed of two parts. The first part is the header and the second part * will be a string that is appended to this header in memory. */ typedef struct HostinfoDetailedDataHeader { uint32 version; char shortName[MAX_OS_NAME_LEN + 1]; char fullName[MAX_OS_FULLNAME_LEN + 1]; } HostinfoDetailedDataHeader; char *Hostinfo_NameGet(void); // Don't free result char *Hostinfo_HostName(void); // free result char *Hostinfo_GetOSName(void); // free result char *Hostinfo_GetOSGuestString(void); // free result char *Hostinfo_GetOSDetailedData(void); // free result void Hostinfo_MachineID(uint32 *hostNameHash, uint64 *hostHardwareID); Bool Hostinfo_GetMemoryInfoInPages(unsigned int *minSize, unsigned int *maxSize, unsigned int *currentSize); #ifdef __linux__ Bool Hostinfo_GetSwapInfoInPages(unsigned int *totalSwap, unsigned int *freeSwap); #endif Bool Hostinfo_GetRatedCpuMhz(int32 cpuNumber, uint32 *mHz); char *Hostinfo_GetCpuDescription(uint32 cpuNumber); void Hostinfo_GetTimeOfDay(VmTimeType *time); VmTimeType Hostinfo_SystemUpTime(void); VmTimeType Hostinfo_SystemTimerNS(void); static INLINE VmTimeType Hostinfo_SystemTimerUS(void) { return Hostinfo_SystemTimerNS() / 1000ULL; } static INLINE VmTimeType Hostinfo_SystemTimerMS(void) { return Hostinfo_SystemTimerNS() / 1000000ULL; } /* * Apple's kernel major versions are the same as their marketed * minor versions + 4. (E.g. Marketed 10.8.0 == Kernel 12.0.0) * These constants simplify this and make code easier to read / understand. */ enum { HOSTINFO_OS_VERSION_MACOS_10_5 = 9, HOSTINFO_OS_VERSION_MACOS_10_6 = 10, HOSTINFO_OS_VERSION_MACOS_10_7 = 11, HOSTINFO_OS_VERSION_MACOS_10_8 = 12, HOSTINFO_OS_VERSION_MACOS_10_9 = 13, HOSTINFO_OS_VERSION_MACOS_10_10 = 14, HOSTINFO_OS_VERSION_MACOS_10_11 = 15, HOSTINFO_OS_VERSION_MACOS_10_12 = 16, HOSTINFO_OS_VERSION_MACOS_10_13 = 17, HOSTINFO_OS_VERSION_MACOS_10_14 = 18, HOSTINFO_OS_VERSION_MACOS_10_15 = 19, HOSTINFO_OS_VERSION_MACOS_11 = 20, }; int Hostinfo_OSVersion(unsigned int i); int Hostinfo_GetSystemBitness(void); const char *Hostinfo_OSVersionString(void); #if defined(_WIN32) Bool Hostinfo_OSIsWinNT(void); Bool Hostinfo_OSIsWow64(void); int Hostinfo_EnumerateAllProcessPids(uint32 **processIds); #else void Hostinfo_ResetProcessState(const int *keepFds, size_t numKeepFds); int Hostinfo_Execute(const char *path, char * const *args, Bool wait, const int *keepFds, size_t numKeepFds); typedef enum HostinfoDaemonizeFlags { HOSTINFO_DAEMONIZE_DEFAULT = 0, HOSTINFO_DAEMONIZE_NOCHDIR = (1 << 0), HOSTINFO_DAEMONIZE_NOCLOSE = (1 << 1), HOSTINFO_DAEMONIZE_EXIT = (1 << 2), HOSTINFO_DAEMONIZE_LOCKPID = (1 << 3), } HostinfoDaemonizeFlags; Bool Hostinfo_Daemonize(const char *path, char * const *args, HostinfoDaemonizeFlags flags, const char *pidPath, const int *keepFds, size_t numKeepFds); #endif Bool Hostinfo_NestingSupported(void); Bool Hostinfo_VCPUInfoBackdoor(unsigned bit); Bool Hostinfo_TouchBackDoor(void); Bool Hostinfo_TouchVirtualPC(void); Bool Hostinfo_TouchXen(void); Bool Hostinfo_HyperV(void); char *Hostinfo_HypervisorCPUIDSig(void); void Hostinfo_LogHypervisorCPUID(void); char *Hostinfo_HypervisorInterfaceSig(void); uint32 Hostinfo_GetNestedBuildNum(void); #define HGMP_PRIVILEGE 0 #define HGMP_NO_PRIVILEGE 1 char *Hostinfo_GetModulePath(uint32 priv); char *Hostinfo_GetLibraryPath(void *addr); char *Hostinfo_GetUser(void); void Hostinfo_LogMemUsage(void); /* * HostInfoCpuIdInfo -- * * Contains cpuid information for a CPU. */ typedef struct { CpuidVendor vendor; uint32 version; uint8 family; uint8 model; uint8 stepping; uint8 type; uint32 features; uint32 extfeatures; } HostinfoCpuIdInfo; #define AMDVBSSupport(eax) (CPUID_MODEL_IS_ZEN2(eax) || \ CPUID_MODEL_IS_ZEN3(eax) || \ CPUID_MODEL_IS_ZEN4(eax) || \ CPUID_MODEL_IS_ZEN5(eax)) uint32 Hostinfo_NumCPUs(void); char *Hostinfo_GetCpuidStr(void); Bool Hostinfo_GetCpuid(HostinfoCpuIdInfo *info); #if defined(_WIN32) typedef enum { OS_WIN95 = 1, OS_WIN98 = 2, OS_WINME = 3, OS_WINNT = 4, OS_WIN2K = 5, OS_WINXP = 6, OS_WIN2K3 = 7, OS_VISTA = 8, OS_WINSEVEN = 9, OS_WIN8 = 10, OS_WIN10 = 11, OS_WIN11 = 12, OS_UNKNOWN = 99999 // last, highest value } OS_TYPE; typedef enum { OS_DETAIL_WIN95 = 1, OS_DETAIL_WIN98 = 2, OS_DETAIL_WINME = 3, OS_DETAIL_WINNT = 4, OS_DETAIL_WIN2K = 5, OS_DETAIL_WIN2K_PRO = 6, OS_DETAIL_WIN2K_SERV = 7, OS_DETAIL_WIN2K_ADV_SERV = 8, OS_DETAIL_WINXP = 9, OS_DETAIL_WINXP_HOME = 10, OS_DETAIL_WINXP_PRO = 11, OS_DETAIL_WINXP_X64_PRO = 12, OS_DETAIL_WIN2K3 = 13, OS_DETAIL_WIN2K3_WEB = 14, OS_DETAIL_WIN2K3_ST = 15, OS_DETAIL_WIN2K3_EN = 16, OS_DETAIL_WIN2K3_BUS = 17, OS_DETAIL_VISTA = 18, OS_DETAIL_WIN2K8 = 19, OS_DETAIL_WINSEVEN = 20, OS_DETAIL_WIN2K8R2 = 21, OS_DETAIL_WIN8 = 22, OS_DETAIL_WIN8SERVER = 23, OS_DETAIL_WIN10 = 24, OS_DETAIL_WIN10SERVER = 25, OS_DETAIL_WIN11 = 26, OS_DETAIL_WIN11SERVER = 27, OS_DETAIL_UNKNOWN = 99999 // last, highest value } OS_DETAIL_TYPE; /* generic names (to protect the future) but Windows specific for now */ OS_TYPE Hostinfo_GetOSType(void); OS_DETAIL_TYPE Hostinfo_GetOSDetailType(void); Bool Hostinfo_GetMhzOfProcessor(int32 processorNumber, uint32 *currentMhz, uint32 *maxMhz); uint64 Hostinfo_SystemIdleTime(void); #endif void Hostinfo_LogLoadAverage(void); Bool Hostinfo_GetLoadAverage(uint32 *l); #ifdef __APPLE__ size_t Hostinfo_GetKernelZoneElemSize(char const *name); char *Hostinfo_GetHardwareModel(void); int Hostinfo_ProcessIsRosetta(void); #endif #if defined(__cplusplus) } // extern "C" #endif #endif /* ifndef _HOSTINFO_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/imgcust-common/000077500000000000000000000000001470176644300254535ustar00rootroot00000000000000open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/imgcust-common/imgcust-api.h000066400000000000000000000031341470176644300300470ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * imgcust-api.h -- * * C interface to package deployment. */ #ifndef IMGCUST_API_H #define IMGCUST_API_H #ifdef WIN32 /* * We get warnings c4251 and c4275 when exporting c++ classes that * inherit from STL classes or use them as members. We can't * export these classes or the client will get duplicate symbols, * so we disable the warning. */ #pragma warning( disable : 4251 ) #pragma warning( disable : 4275 ) // if _IMGCUST_DLL is defined, we export functions/classes with this prefix #ifdef _IMGCUST_DLL #define IMGCUST_API __declspec(dllexport) #else #define IMGCUST_API __declspec(dllimport) #endif #else // linux #define IMGCUST_API __attribute__ ((visibility ("default"))) #endif // WIN32 #endif // IMGCUST_API_H open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/imgcust-common/log.h000066400000000000000000000025431470176644300264110ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * log.h -- * * Logging method that need to be provided by the client of the * library to enable logging. */ #ifndef IMGCUST_COMMON_LOG_H #define IMGCUST_COMMON_LOG_H #define GUESTCUST_LOG_DIRNAME "vmware-imc" #ifdef __cplusplus namespace ImgCustCommon { #endif enum LogLevel {log_debug, log_info, log_warning, log_error}; typedef void (*LogFunction) (int level, const char *fmtstr, ...); #ifdef __cplusplus } // namespace ImgCustCommon #endif #endif // IMGCUST_COMMON_LOG_H open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/imgcust-common/process.h000066400000000000000000000066511470176644300273120ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * process.h -- * * Functions to launch an external process. */ #ifndef IMGCUST_COMMON_PROCESS_H #define IMGCUST_COMMON_PROCESS_H #ifdef __cplusplus extern "C" { #endif typedef struct ProcessOpaque *ProcessHandle; typedef enum _ProcessError { PROCESS_SUCCESS, PROCESS_FAILED } ProcessError; /* *------------------------------------------------------------------------------ * * Process_Create -- * * Creates a process and returns result of the operation. * * Since this file can be included in a c++ file that already has the * namespaced c++ definition of LogFunction defined, we can't use the c * version of LogFunction as an input. Only choice is to make it a raw * pointer and cast it in the processXXX.c file which can use the C * definition of LogFunction. * *------------------------------------------------------------------------------ */ ProcessError Process_Create(ProcessHandle *h, char *args[], void *log); /* *------------------------------------------------------------------------------ * * Process_RunToComplete -- * * Runs the process to completion and returns its result. * *------------------------------------------------------------------------------ */ ProcessError Process_RunToComplete(ProcessHandle h, unsigned long timeout); /* *------------------------------------------------------------------------------ * * Process_GetStdout -- * * Returns process's standard output. * *------------------------------------------------------------------------------ */ const char * Process_GetStdout(ProcessHandle h); /* *------------------------------------------------------------------------------ * * Process_GetStderr -- * * Returns process's standard error output. * *------------------------------------------------------------------------------ */ const char * Process_GetStderr(ProcessHandle h); /* *------------------------------------------------------------------------------ * * Process_GetExitCode -- * * Returns process's exit code. * *------------------------------------------------------------------------------ */ int Process_GetExitCode(ProcessHandle h); /* *------------------------------------------------------------------------------ * * Process_Destroy -- * * Destroys the process and returns result of the operation. * *------------------------------------------------------------------------------ */ ProcessError Process_Destroy(ProcessHandle h); #ifdef __cplusplus } // extern "C" #endif #endif // IMGCUST_COMMON_PROCESS_H open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/impersonate.h000066400000000000000000000032351470176644300252140ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * impersonate.h -- * * Provides functions to assist in impersonating and unimpersonating * as a given user. */ #ifndef _IMPERSONATE_H_ #define _IMPERSONATE_H_ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #include "auth.h" #if defined(__cplusplus) extern "C" { #endif void Impersonate_Init(void); Bool Impersonate_Owner(const char *file); Bool Impersonate_Do(const char *user, AuthToken token); Bool Impersonate_Undo(void); char *Impersonate_Who(void); Bool Impersonate_ForceRoot(void); Bool Impersonate_UnforceRoot(void); Bool Impersonate_Runas(const char *cfg, const char *caller, AuthToken callerToken); #ifdef _WIN32 Bool Impersonate_CfgRunasOnly(const char *cfg); #endif #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _IMPERSONATE_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/includeCheck.h000066400000000000000000000125341470176644300252510ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2019, 2021-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * includeCheck.h -- * * Restrict include file use. * * In every .h file, define one or more of these * * INCLUDE_ALLOW_VMX * INCLUDE_ALLOW_USERLEVEL * INCLUDE_ALLOW_VMCORE * INCLUDE_ALLOW_MODULE * INCLUDE_ALLOW_VMKERNEL * INCLUDE_ALLOW_DISTRIBUTE * INCLUDE_ALLOW_VMK_MODULE * INCLUDE_ALLOW_VMKDRIVERS * INCLUDE_ALLOW_MKS * * Then include this file. * * Any file that has INCLUDE_ALLOW_DISTRIBUTE defined will potentially * be distributed in source form along with GPLed code. Ensure * that this is acceptable. */ #if defined VMM && defined ULM #error "VMM and ULM cannot be defined at the same time." #endif #if defined ULM && !defined USERLEVEL #error "All ULM code must be compiled with USERLEVEL set." #endif #if defined VMCORE && !defined INCLUDE_ALLOW_VMCORE #error "The surrounding include file is not allowed in vmcore." #endif #undef INCLUDE_ALLOW_VMCORE #if defined VMX86_VMX && !defined VMCORE && \ !defined INCLUDE_ALLOW_VMX && !defined INCLUDE_ALLOW_USERLEVEL && \ !defined INCLUDE_ALLOW_MKS #error "The surrounding include file is not allowed in the VMX." #endif #undef INCLUDE_ALLOW_VMX #if defined USERLEVEL && !defined VMX86_VMX && !defined VMCORE && \ !defined ULM && !defined INCLUDE_ALLOW_USERLEVEL && \ !defined INCLUDE_ALLOW_MKS && !defined VSAN_USERLEVEL #error "The surrounding include file is not allowed at userlevel." #endif #undef INCLUDE_ALLOW_USERLEVEL #if defined MODULE && !defined VMKERNEL_MODULE && \ !defined VMMON && !defined INCLUDE_ALLOW_MODULE #error "The surrounding include file is not allowed in driver modules." #endif #undef INCLUDE_ALLOW_MODULE #if defined VMMON && !defined INCLUDE_ALLOW_VMMON #error "The surrounding include file is not allowed in vmmon." #endif #undef INCLUDE_ALLOW_VMMON #if defined VMKERNEL && !defined INCLUDE_ALLOW_VMKERNEL #error "The surrounding include file is not allowed in the vmkernel." #endif #undef INCLUDE_ALLOW_VMKERNEL #if defined GPLED_CODE && !defined INCLUDE_ALLOW_DISTRIBUTE #error "The surrounding include file is not allowed in GPL code." #endif #undef INCLUDE_ALLOW_DISTRIBUTE #if defined VMKERNEL_MODULE && !defined VMKERNEL && \ !defined INCLUDE_ALLOW_VMK_MODULE && !defined INCLUDE_ALLOW_VMKDRIVERS #error "The surrounding include file is not allowed in vmkernel modules." #endif #undef INCLUDE_ALLOW_VMK_MODULE #undef INCLUDE_ALLOW_VMKDRIVERS #if defined INCLUDE_ALLOW_MKS && !(defined COREMKS) #error "The surrounding include file is not allowed outside of the MKS." #endif #undef INCLUDE_ALLOW_MKS open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/ioplGet.h000066400000000000000000000024211470176644300242650ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2012-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * ioplGet.h -- * * A utility function to retrieve the IOPL level of the current thread * Compiles on x86, x64 of Linux and Windows */ #ifndef _IOPL_GET_H_ #define _IOPL_GET_H_ #include "x86_basic_defs.h" #include "vm_basic_asm.h" #if defined(__cplusplus) extern "C" { #endif #define Iopl_Get() ((GetCallerEFlags() >> EFLAGS_IOPL_SHIFT) & 0x3) #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/iovector.h000066400000000000000000000106461470176644300245240ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * iovector.h -- * * iov management code API. */ #ifndef _IOVECTOR_H_ #define _IOVECTOR_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #if defined(__cplusplus) extern "C" { #endif /* * Ugly definition of struct iovec. */ #if defined(__linux__) || defined(sun) || defined(__APPLE__) || \ defined(__FreeBSD__) || defined(__EMSCRIPTEN__) #include // for struct iovec #else #ifndef HAS_IOVEC struct iovec { void *iov_base; /* Starting address. */ size_t iov_len; /* Length in bytes. */ }; #endif // HAS_IOVEC #endif /* * An I/O Vector. */ typedef struct VMIOVec { SectorType startSector; SectorType numSectors; uint64 numBytes; /* Total bytes from all of the entries */ uint32 numEntries; /* Total number of entries */ Bool read; /* is it a readv operation? else it's write */ struct iovec *entries; /* Array of entries (dynamically allocated) */ struct iovec *allocEntries; /* The original array that can be passed to free(). * NULL if entries is on a stack. */ } VMIOVec; #define LAZY_ALLOC_MAGIC ((void*)0xF0F0) VMIOVec* IOV_Split(VMIOVec *regionV, SectorType numSectors, uint32 sectorSize); void IOV_Log(const VMIOVec *iov); void IOV_Zero(VMIOVec *iov); Bool IOV_IsZero(VMIOVec* iov); VMIOVec* IOV_Duplicate(VMIOVec* iovIn); VMIOVec* IOV_Allocate(int numEntries); void IOV_Free(VMIOVec* iov); void IOV_DuplicateStatic(VMIOVec *iovIn, int numStaticEntries, struct iovec *staticEntries, VMIOVec *iovOut); void IOV_MakeSingleIOV(VMIOVec* v, struct iovec* iov, SectorType startSector, SectorType dataLen, uint32 sectorSize, uint8* buffer, Bool read); void IOV_WriteIovToBuf(struct iovec const *entries, int numEntries, uint8 *bufOut, size_t bufSize); void IOV_WriteBufToIov(const uint8 *bufIn, size_t bufSize, struct iovec const *entries, int numEntries); size_t IOV_WriteIovToBufPlus(struct iovec* entries, int numEntries, uint8* bufOut, size_t bufSize, size_t iovOffset); size_t IOV_WriteBufToIovPlus(uint8* bufIn, size_t bufSize, struct iovec* entries, int numEntries, size_t iovOffset); size_t IOV_WriteIovToIov(VMIOVec *srcIov, VMIOVec *dstIov, uint32 sectorSizeShift); /* *----------------------------------------------------------------------------- * * IOV_ASSERT, IOV_Assert -- * * Checks that the 'numEntries' iovecs in 'iov' are non-null and have * nonzero lengths. * * Results: * None. * * Side effects: * Assert-fails if the iovec is invalid. * *----------------------------------------------------------------------------- */ #if VMX86_DEBUG #define IOV_ASSERT(IOVEC, NUM_ENTRIES) IOV_Assert(IOVEC, NUM_ENTRIES) void IOV_Assert(struct iovec *iov, // IN: iovector uint32 numEntries); // IN: # of entries in 'iov' #else #define IOV_ASSERT(IOVEC, NUM_ENTRIES) ((void) 0) #endif #if defined(__cplusplus) } // extern "C" #endif #endif /* #ifndef _IOVECTOR_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/jsmn.h000066400000000000000000000056651470176644300236460ustar00rootroot00000000000000/* ********************************************************** * Copyright (c) 2019,2021 VMware, Inc. All rights reserved. * **********************************************************/ /* * Copyright (c) 2010 Serge A. Zaitsev * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __JSMN_H_ #define __JSMN_H_ #include #ifdef __cplusplus extern "C" { #endif /** * JSON type identifier. Basic types are: * o Object * o Array * o String * o Other primitive: number, boolean (true/false) or null */ typedef enum { JSMN_UNDEFINED = 0, JSMN_OBJECT = 1, JSMN_ARRAY = 2, JSMN_STRING = 3, JSMN_PRIMITIVE = 4 } jsmntype_t; enum jsmnerr { /* Not enough tokens were provided */ JSMN_ERROR_NOMEM = -1, /* Invalid character inside JSON string */ JSMN_ERROR_INVAL = -2, /* The string is not a full JSON packet, more bytes expected */ JSMN_ERROR_PART = -3 }; /** * JSON token description. * type type (object, array, string etc.) * start start position in JSON data string * end end position in JSON data string */ typedef struct { jsmntype_t type; int start; int end; int size; #ifdef JSMN_PARENT_LINKS int parent; #endif } jsmntok_t; /** * JSON parser. Contains an array of token blocks available. Also stores * the string being parsed now and current position in that string */ typedef struct { unsigned int pos; /* offset in the JSON string */ unsigned int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; /** * Create JSON parser over an array of tokens */ void jsmn_init(jsmn_parser *parser); /** * Run JSON parser. It parses a JSON data string into and array of tokens, each describing * a single JSON object. */ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens); #ifdef __cplusplus } #endif #endif /* __JSMN_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/libExport.hh000066400000000000000000000031001470176644300247750ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2016,2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * libExport.hh -- * * Declares proper decorations for dll-export interface * for all modules in libs. */ #ifndef LIB_EXPORT_HH #define LIB_EXPORT_HH #include "vm_api.h" #ifndef LIB_EXPORT #ifdef LIB_EXPORT_SOURCE #define LIB_EXPORT VMW_LIB_DYNAMIC #else #define LIB_EXPORT VMW_LIB_CLIENT #endif #endif #ifndef LIB_EXPORT_WUI #ifdef LIB_EXPORT_WUI_SOURCE #define LIB_EXPORT_WUI VMW_LIB_DYNAMIC #else #define LIB_EXPORT_WUI VMW_LIB_CLIENT #endif #endif #ifndef VMSTRING_EXPORT #ifdef VMSTRING_EXPORT_SOURCE #define VMSTRING_EXPORT VMW_LIB_DYNAMIC #else #define VMSTRING_EXPORT VMW_LIB_CLIENT #endif #endif #endif // LIB_EXPORT_HH open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/localconfig.h000066400000000000000000000025711470176644300251500ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _LOCALCONFIG_H_ #define _LOCALCONFIG_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "preference.h" #if defined(__cplusplus) extern "C" { #endif #define LocalConfig_GetBool Preference_GetBool #define LocalConfig_GetTriState Preference_GetTriState #define LocalConfig_GetLong Preference_GetLong #define LocalConfig_GetString Preference_GetString #define LocalConfig_GetPathName Preference_GetPathName #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/log.h000066400000000000000000000475751470176644300234660ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef VMWARE_LOG_H #define VMWARE_LOG_H #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "productState.h" #include #if defined(_WIN32) #include #endif #if defined(__cplusplus) extern "C" { #endif /** * Log Facility * ------------ * * The Log Facility exists to record events of program execution for purposes * of auditing, debugging, and monitoring. Any non-trivial program should use * logging, to enable those purposes. * * Events recorded by the Log Facility (i.e. calls to here-declared functions) * are automatically filtered, time-stamped, and persisted. * * Configuration for field engineers is documented at * https://wiki.eng.vmware.com/PILogFacility * * For full details on configurable parameters and their semantics, * use the source, Luke -- starting at lib/log/logFacility.c * * The events are explicitly annotated by the developer (i.e. you) * with a level, an optional group, and a message. * * Notes: * - Log() is defined as Log_Info() * - Warning() is defined as Log_Warning() * * Log Level * --------- * * The Log Level indicates the (in)significance of the event, with larger * numbers indicating lesser significance. The level, whether explicit * (e.g. Log_Level(level, ...)) or implicit (e.g. Log_Info(...)), * should be chosen with some care. A Log_Info() message containing the word * "warning" or "error" is almost certainly mis-routed. * * The following rules of thumb provide a rough guide to choice of level. * * * VMW_LOG_AUDIT -- always logged, for auditing purposes * + change to authorization * + change to configuration * * * VMW_LOG_PANIC -- system broken; cannot exit gracefully * + wild pointer; corrupt arena * + error during error exit * * * VMW_LOG_ERROR -- system broken; must exit * + required resource inaccessible (memory; storage; network) * + incorrigible internal inconsistency * * * VMW_LOG_WARNING -- unexpected condition; may require immediate attention * + inconsistency corrected or ignored * + timeout or slow operation * * * VMW_LOG_NOTICE -- unexpected condition; may require eventual attention * + missing config; default used * + lower level error ignored * * * VMW_LOG_INFO -- expected condition * + non-standard configuration * + alternate path taken (e.g. on lower level error) * * * VMW_LOG_VERBOSE -- normal operation; potentially useful information * + system health observation, for monitoring * + unexpected non-error state * * * VMW_LOG_TRIVIA -- normal operation; excess information * + vaguely interesting note * + anything else the developer thinks might be useful * * * VMW_LOG_DEBUG_* -- flow and logic tracing * + routine entry, with parameters; routine exit, with return value * + intermediate values or decisions * * Log Facility Message Groups * --------------------------- * * For information about Log Facility Message Groups visit * lib/log/logFacility.c. * * Log Facility Message Filtering * ------------------------------ * * For information about Log Facility message filtering visit * lib/log/logFacility.c. * * Log Message Guidelines * ---------------------- * * Every Log message should be unique, unambiguously describing the event * being logged, and should include all relevant data, in human-readable form. * Source line number is *not* useful. * + printf-style arguments * + function name as prefix (controversial) * + format pure number (e.g. error number) in decimal * + format bitfield (e.g. compound error code) in hex * + format disk size or offset in hex; specify units if not bytes * + quote string arguments (e.g. pathnames) which can contain spaces * * Level Value Comments *--------------------------------------------------------------------------- */ typedef enum { VMW_LOG_AUDIT = 0, // Always output; never to stderr VMW_LOG_PANIC = 1, // Desperation VMW_LOG_ERROR = 2, // Irremediable error VMW_LOG_WARNING = 3, // Unexpected condition; may need immediate attention VMW_LOG_NOTICE = 4, // Unexpected condition; may need eventual attention VMW_LOG_INFO = 5, // Expected condition VMW_LOG_VERBOSE = 6, // Extra information VMW_LOG_TRIVIA = 7, // Excess information VMW_LOG_DEBUG_00 = 8, VMW_LOG_DEBUG_01 = 9, VMW_LOG_DEBUG_02 = 10, VMW_LOG_DEBUG_03 = 11, VMW_LOG_DEBUG_04 = 12, VMW_LOG_DEBUG_05 = 13, VMW_LOG_DEBUG_06 = 14, VMW_LOG_DEBUG_07 = 15, VMW_LOG_DEBUG_08 = 16, VMW_LOG_DEBUG_09 = 17, VMW_LOG_DEBUG_10 = 18, VMW_LOG_DEBUG_11 = 19, VMW_LOG_DEBUG_12 = 20, VMW_LOG_DEBUG_13 = 21, VMW_LOG_DEBUG_14 = 22, VMW_LOG_DEBUG_15 = 23, VMW_LOG_MAX = 24, } VmwLogLevel; #if defined(VMX86_DEBUG) #define LOG_FILTER_DEFAULT_LEVEL VMW_LOG_VERBOSE #else #define LOG_FILTER_DEFAULT_LEVEL VMW_LOG_INFO #endif #if defined(VMX86_SERVER) /* WORLD_MAX_OPID_STRING_SIZE */ #define LOG_MAX_OPID_LENGTH 128 #else /* We do not expect long opIDs in non-ESX environments. 32 should be enough. */ #define LOG_MAX_OPID_LENGTH 32 #endif #define LOG_NO_KEEPOLD 0 // Keep no old log files #define LOG_NO_ROTATION_SIZE 0 // Do not rotate based on file size #define LOG_NO_THROTTLE_THRESHOLD 0 // No threshold before throttling #define LOG_NO_BPS_LIMIT 0xFFFFFFFF // unlimited input rate /* * The defaults for how many older log files to kept around, and what to do * with rotation-by-size. */ #if defined(VMX86_SERVER) #define LOG_DEFAULT_KEEPOLD 10 #define LOG_DEFAULT_ROTATION_SIZE 2048000 #else #define LOG_DEFAULT_KEEPOLD 3 #define LOG_DEFAULT_ROTATION_SIZE LOG_NO_ROTATION_SIZE #endif /* * The "routing" parameter contains the level in the low order bits; * the higher order bits specify the group of the log call. */ #define VMW_LOG_LEVEL_BITS 5 // Log level bits (32 levels max) #define VMW_LOG_LEVEL_MASK ((int)(1 << VMW_LOG_LEVEL_BITS) - 1) #define VMW_LOG_LEVEL(routing) ((routing) & VMW_LOG_LEVEL_MASK) #define VMW_LOG_MODULE(routing) (((routing) >> VMW_LOG_LEVEL_BITS)) void LogV(uint32 routing, const char *fmt, va_list args); void Log_Level(uint32 routing, const char *fmt, ...) PRINTF_DECL(2, 3); /* * Log = Log_Info * Warning = Log_Warning */ static INLINE void PRINTF_DECL(1, 2) Log_Panic(const char *fmt, ...) { va_list ap; va_start(ap, fmt); LogV(VMW_LOG_PANIC, fmt, ap); va_end(ap); } static INLINE void PRINTF_DECL(1, 2) Log_Audit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); LogV(VMW_LOG_AUDIT, fmt, ap); va_end(ap); } static INLINE void PRINTF_DECL(1, 2) Log_Error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); LogV(VMW_LOG_ERROR, fmt, ap); va_end(ap); } static INLINE void PRINTF_DECL(1, 2) Log_Warning(const char *fmt, ...) { va_list ap; va_start(ap, fmt); LogV(VMW_LOG_WARNING, fmt, ap); va_end(ap); } static INLINE void PRINTF_DECL(1, 2) Log_Notice(const char *fmt, ...) { va_list ap; va_start(ap, fmt); LogV(VMW_LOG_NOTICE, fmt, ap); va_end(ap); } static INLINE void PRINTF_DECL(1, 2) Log_Info(const char *fmt, ...) { va_list ap; va_start(ap, fmt); LogV(VMW_LOG_INFO, fmt, ap); va_end(ap); } static INLINE void PRINTF_DECL(1, 2) Log_Verbose(const char *fmt, ...) { va_list ap; va_start(ap, fmt); LogV(VMW_LOG_VERBOSE, fmt, ap); va_end(ap); } static INLINE void PRINTF_DECL(1, 2) Log_Trivia(const char *fmt, ...) { va_list ap; va_start(ap, fmt); LogV(VMW_LOG_TRIVIA, fmt, ap); va_end(ap); } #if !defined(VMM) typedef struct { int32 legalLevelValue; const char *legalName; const char *levelIdStr; } LogLevelData; const LogLevelData * Log_MapByLevel(VmwLogLevel level); const LogLevelData * Log_MapByName(const char *name); typedef struct LogOutput LogOutput; /* Forward decl */ struct Dictionary; struct CfgInterface; struct CfgInterface * Log_CfgInterface(void); int32 Log_SetStderrLevel(uint32 group, int32 level); int32 Log_GetStderrLevel(uint32 group); int32 Log_SetLogLevel(uint32 group, int32 level); int32 Log_GetLogLevel(uint32 group); int32 Log_LookupGroupNumber(const char *groupName); const char * Log_LookupGroupName(uint32 group); LogOutput * Log_NewStdioOutput(const char *appPrefix, struct Dictionary *params, struct CfgInterface *cfgIf); LogOutput * Log_NewSyslogOutput(const char *appPrefix, const char *instanceName, struct Dictionary *params, struct CfgInterface *cfgIf); LogOutput * Log_NewFileOutput(const char *appPrefix, const char *instanceName, struct Dictionary *params, struct CfgInterface *cfgIf); typedef struct { uint32 keepOld; uint32 rotateSize; uint32 throttleThreshold; uint32 throttleBPS; Bool useTimeStamp; Bool useMilliseconds; Bool useThreadName; Bool useLevelDesignator; Bool useOpID; Bool append; Bool syncAfterWrite; Bool fastRotation; } LogFileParameters; Bool Log_GetFileParameters(const LogOutput *output, LogFileParameters *parms); typedef void (LogCustomMsgFunc)(int level, const char *msg); LogOutput * Log_NewCustomOutput(const char *instanceName, LogCustomMsgFunc *msgFunc, int minLogLevel); typedef struct { uint8 level; uint32 group; Bool additionalLine; size_t msgLen; char timeStamp[64]; char threadName[32]; char opID[LOG_MAX_OPID_LENGTH + 1]; // Will be empty string on hosted products } LogLineMetadata; typedef void (LogCustomMsgFuncEx)(const LogLineMetadata * const metadata, const char *msg); LogOutput * Log_NewCustomOutputEx(const char *instanceName, LogCustomMsgFuncEx *msgFunc, int minLogLevel); #if defined(VMX86_SERVER) LogOutput * Log_NewEsxKernelLogOutput(const char *appPrefix, struct Dictionary *params, struct CfgInterface *cfgIf); LogOutput * Log_NewCrxSyslogOutput(const char *appPrefix, struct Dictionary *params, struct CfgInterface *cfgIf); #endif Bool Log_FreeOutput(LogOutput *toOutput); Bool Log_AddOutput(LogOutput *output); Bool Log_ReplaceOutput(LogOutput *fromOutput, LogOutput *toOutput, Bool copyOver); int32 Log_SetOutputLevel(LogOutput *output, int32 level); /* * Structure contains all the pointers to where value can be updated. * Making VmxStatsInfo as a struct has its own advantage, such as updating * 'droppedChars' from the struct instead within LogFile. */ struct StatFileMinMax64; typedef struct { uint64 *logMsgsDropped; // Number of dropped messages uint64 *logBytesDropped; // Number of drop bytes uint64 *logBytesLogged; // Bytes logged struct StatsFileMinMax64 *logWriteMinMaxTime; // Min/max write time in US uint64 *logWriteAvgTime; // Average time to write in US } VmxStatsInfo; Bool Log_SetVmxStatsData(LogOutput *output, VmxStatsInfo *vmxStats); /* * The most common Log Facility client usage is via the "InitWith" functions. * These functions - not the "Int" versions - handle informing the Log * Facility of the ProductState (product description) via inline code. This is * done to avoid making the Log Facility depend on the ProductState library - * the product should have the dependency, not an underlying library. * * In complex cases, where an "InitWith" is not sufficient and Log_AddOutput * must be used directly, the client should call Log_SetProductInfo, passing * the appropriate parameters, so the log file header information will be * correct. */ void Log_SetProductInfo(const char *appName, const char *appVersion, const char *buildNumber, const char *compilationOption); static INLINE void Log_SetProductInfoSimple(void) { Log_SetProductInfo(ProductState_GetName(), ProductState_GetVersion(), ProductState_GetBuildNumberString(), ProductState_GetCompilationOption()); } LogOutput * Log_InitWithCustomInt(struct CfgInterface *cfgIf, LogCustomMsgFunc *msgFunc, int minLogLevel); static INLINE LogOutput * Log_InitWithCustom(struct CfgInterface *cfgIf, LogCustomMsgFunc *msgFunc, int minLogLevel) { Log_SetProductInfoSimple(); return Log_InitWithCustomInt(cfgIf, msgFunc, minLogLevel); } LogOutput * Log_InitWithCustomIntEx(struct CfgInterface *cfgIf, LogCustomMsgFuncEx *msgFunc, int minLogLevel); static INLINE LogOutput * Log_InitWithCustomEx(struct CfgInterface *cfgIf, LogCustomMsgFuncEx *msgFunc, int minLogLevel) { Log_SetProductInfoSimple(); return Log_InitWithCustomIntEx(cfgIf, msgFunc, minLogLevel); } LogOutput * Log_InitWithFileInt(const char *appPrefix, struct Dictionary *dict, struct CfgInterface *cfgIf, Bool boundNumFiles); static INLINE LogOutput * Log_InitWithFile(const char *appPrefix, struct Dictionary *dict, struct CfgInterface *cfgIf, Bool boundNumFiles) { Log_SetProductInfoSimple(); return Log_InitWithFileInt(appPrefix, dict, cfgIf, boundNumFiles); } LogOutput * Log_InitWithFileSimpleInt(const char *appPrefix, struct CfgInterface *cfgIf, const char *fileName); static INLINE LogOutput * Log_InitWithFileSimple(const char *appPrefix, const char *fileName) { Log_SetProductInfoSimple(); return Log_InitWithFileSimpleInt(appPrefix, Log_CfgInterface(), fileName); } LogOutput * Log_InitWithSyslogInt(const char *appPrefix, struct Dictionary *dict, struct CfgInterface *cfgIf); static INLINE LogOutput * Log_InitWithSyslog(const char *appPrefix, struct Dictionary *dict, struct CfgInterface *cfgIf) { Log_SetProductInfoSimple(); return Log_InitWithSyslogInt(appPrefix, dict, cfgIf); } LogOutput * Log_InitWithSyslogSimpleInt(const char *appPrefix, struct CfgInterface *cfgIf, const char *syslogID); static INLINE LogOutput * Log_InitWithSyslogSimple(const char *appPrefix, const char *syslogID) { Log_SetProductInfoSimple(); return Log_InitWithSyslogSimpleInt(appPrefix, Log_CfgInterface(), syslogID); } LogOutput * Log_InitWithStdioSimpleInt(const char *appPrefix, struct CfgInterface *cfgIf, const char *minLevel, Bool withLinePrefix); static INLINE LogOutput * Log_InitWithStdioSimple(const char *appPrefix, const char *minLevel, Bool withLinePrefix) { Log_SetProductInfoSimple(); return Log_InitWithStdioSimpleInt(appPrefix, Log_CfgInterface(), minLevel, withLinePrefix); } void Log_Exit(void); Bool Log_Outputting(void); Bool Log_IsEnabled(uint32 routing); const char * Log_GetFileName(void); const char * Log_GetOutputFileName(LogOutput *output); void Log_SkipLocking(Bool skipLocking); void Log_DisableThrottling(void); uint32 Log_MaxLineLength(void); size_t Log_MakeTimeString(Bool millisec, char *buf, size_t max); typedef Bool (LogMayDeleteFunc)(void *userData, const char *fileName, uint32 *pid); Bool Log_BoundNumFiles(const LogOutput *output, LogMayDeleteFunc *mayDeleteFunc, void *userData); typedef struct { #if defined(_WIN32) HANDLE handle; #else int fd; #endif } LogFileObject; Bool Log_GetFileObject(const LogOutput *output, LogFileObject *result); /* * Assemble a line. */ void * Log_BufBegin(void); void Log_BufAppend(void *acc, const char *fmt, ...) PRINTF_DECL(2, 3); void Log_BufEndLevel(void *acc, uint32 routing); /* * Debugging */ void Log_HexDump(const char *prefix, const void *data, size_t size); void Log_HexDumpLevel(uint32 routing, const char *prefix, const void *data, size_t size); void Log_Time(VmTimeType *time, int count, const char *message); void Log_Histogram(uint32 n, uint32 histo[], int nbuckets, const char *message, int *count, int limit); typedef Bool (GetOpId)(size_t maxStringLen, char *opId); void Log_RegisterOpIdFunction(GetOpId *getOpIdFunc); void Log_LoadGroupFilters(const char *appPrefix, struct CfgInterface *cfgIf); long Log_OffsetUtc(void); /* * log throttling: * * throttleThreshold = start log throttling only after this many bytes have * been logged (allows initial vmx startup spew). * * throttleBPS = start throttling if more than this many bytes per second are * logged. Continue throttling until rate drops below this value. * * bytesLogged = total bytes logged. * * logging rate = (bytesLogged - lastBytesSample)/(curTime - lastSampleTime) */ typedef struct { uint64 throttleThreshold; uint64 bytesLogged; uint64 lastBytesSample; VmTimeType lastTimeSample; uint32 throttleBPS; Bool throttled; } LogThrottleInfo; Bool Log_IsThrottled(LogThrottleInfo *info, size_t msgLen); #endif /* !VMM */ #if defined(__cplusplus) } // extern "C" #endif #endif /* VMWARE_LOG_H */ /* * Log Facility Message Group macros */ #if !defined(VMW_LOG_GROUP_LEVELS) #include "vm_basic_defs.h" #include "loglevel_userVars.h" #define LOGFACILITY_GROUPVAR(group) XCONC(_logFacilityGroup_, group) enum LogFacilityGroupValue { LOGLEVEL_USER(LOGFACILITY_GROUPVAR) }; #define VMW_LOG_GROUP_LEVELS #endif /* * Legacy VMW_LOG_ROUTING macro * * Group name is "inherited" from the LOGLEVEL_MODULE define. */ #if defined(VMW_LOG_ROUTING) #undef VMW_LOG_ROUTING #endif #if defined(LOGLEVEL_MODULE) #define VMW_LOG_ROUTING(level) \ (((LOGFACILITY_GROUPVAR(LOGLEVEL_MODULE) + 1) << VMW_LOG_LEVEL_BITS) | (level)) #else #define VMW_LOG_ROUTING(level) (level) #endif /* * VMW_LOG_ROUTING_EX macro * * Group name is specified in the macro. */ #if defined(VMW_LOG_ROUTING_EX) #undef VMW_LOG_ROUTING_EX #endif #define VMW_LOG_ROUTING_EX(name, level) \ (((LOGFACILITY_GROUPVAR(name) + 1) << VMW_LOG_LEVEL_BITS) | (level)) open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/logFixed.h000066400000000000000000000031721470176644300244270ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _LOGFIXED_H_ #define _LOGFIXED_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #if defined(__cplusplus) extern "C" { #endif /* * LogFixed_Base2 and LogFixed_Base10 provide their values expressed * as a ration of two uint32 numbers with an accuracy of better than 1%. * * Reminder: A log, base x, of zero is undefined. These routines will assert * in development builds when a zero value is passed to them. */ void LogFixed_Base2(uint64 value, uint32 *numerator, uint32 *denominator); void LogFixed_Base10(uint64 value, uint32 *numerator, uint32 *denominator); #if defined(__cplusplus) } // extern "C" #endif #endif // _LOGFIXED_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/logToHost.h000066400000000000000000000022161470176644300246060ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * logToHost.h -- * * Log function prototypes to discretionarily direct log to the host or the * guest. */ #ifndef __LOG_TO_HOST_H__ #define __LOG_TO_HOST_H__ void WarningToGuest(const char *fmt, ...); void WarningToHost(const char *fmt, ...); #endif /* __LOG_TO_HOST_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/loglevel_defs.h000066400000000000000000000071061470176644300255010ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _LOGLEVEL_DEFS_H_ #define _LOGLEVEL_DEFS_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #ifndef LOGLEVEL_MODULE #error "loglevel_defs.h must be included with LOGLEVEL_MODULE defined" #endif #ifndef LOGLEVEL_EXTENSION #error "loglevel_defs.h must be included with LOGLEVEL_EXTENSION defined" #endif #include "vm_basic_types.h" #include "vm_basic_defs.h" #if defined __cplusplus #define LOGLEVEL_EXTERN_C_BEGIN extern "C" { #define LOGLEVEL_EXTERN_C_END } #else #define LOGLEVEL_EXTERN_C_BEGIN #define LOGLEVEL_EXTERN_C_END #endif LOGLEVEL_EXTERN_C_BEGIN /* * CPP variable name hacks */ #define LOGLEVEL_EXTOFFSET(ext) XCONC(_loglevel_offset_, ext) #define LOGLEVEL_EXTNAME(ext) XSTR(ext) #define LOGLEVEL_MODULEVAR(mod) XCONC(_loglevel_mod_, mod) /* * LogLevel declaration */ #define LOGLEVEL_EXTENSION_DECLARE(list) \ LOGLEVEL_EXTERN_C_BEGIN \ VMX86_EXTERN_DATA const int8 *logLevelPtr; \ VMX86_EXTERN_DATA int LOGLEVEL_EXTOFFSET(LOGLEVEL_EXTENSION); \ LOGLEVEL_EXTERN_C_END \ enum { list(LOGLEVEL_MODULEVAR) } #ifdef VMX86_LOG /* * Cross extension */ int LogLevel_Set(const char *extension, const char *module, int val); /* * Intra extension */ #define LOGLEVEL_BYNAME(_mod) \ logLevelPtr[LOGLEVEL_EXTOFFSET(LOGLEVEL_EXTENSION) + \ LOGLEVEL_MODULEVAR(_mod)] #define DOLOG_BYNAME(_mod, _min) \ UNLIKELY(LOGLEVEL_BYNAME(_mod) >= (_min)) /* * Variadic macro wrinkle: C99 says "one or more arguments"; some compilers * (gcc+clang+msvc) support zero arguments, but differ in tolerating a trailing * comma. Solution: include format string in variadic arguments. * * C++2a introduces __VA_OPT__, which would allow this definition instead: * define LOG_BYNAME(_mod, _min, _fmt, ...) \ * (DOLOG_BYNAME(_mod, _min) ? Log(_fmt __VA_OPT__(,) __VA_ARGS__) \ * : (void) 0) * MSVC has always ignored a spurious trailing comma, so does not need this. */ #define LOG_BYNAME(_mod, _min, ...) \ (DOLOG_BYNAME(_mod, _min) ? Log(__VA_ARGS__) : (void) 0) /* * Default */ #define LOGLEVEL() LOGLEVEL_BYNAME(LOGLEVEL_MODULE) #define DOLOG(_min) DOLOG_BYNAME(LOGLEVEL_MODULE, _min) #define LOG(_min, ...) LOG_BYNAME(LOGLEVEL_MODULE, _min, __VA_ARGS__) #else /* VMX86_LOG */ #define LOGLEVEL_BYNAME(_mod) 0 #define DOLOG_BYNAME(_mod, _min) (FALSE) #define LOG_BYNAME(_mod, _min, ...) #define LOGLEVEL() 0 #define DOLOG(_min) (FALSE) #define LOG(_min, ...) #endif /* VMX86_LOG */ #ifdef VMX86_DEVEL #define LOG_DEVEL(...) Log(__VA_ARGS__) #else #define LOG_DEVEL(...) #endif LOGLEVEL_EXTERN_C_END #endif /* _LOGLEVEL_DEFS_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/loglevel_user.h000066400000000000000000000022441470176644300255340ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _LOGLEVEL_USER_H_ #define _LOGLEVEL_USER_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #define LOGLEVEL_EXTENSION user #include "loglevel_defs.h" #include "loglevel_userVars.h" LOGLEVEL_EXTENSION_DECLARE(LOGLEVEL_USER); #endif /* _LOGLEVEL_USER_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/loglevel_userVars.h000066400000000000000000000247671470176644300264060ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _LOGLEVEL_USER_VARS_H_ #define _LOGLEVEL_USER_VARS_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" /* KEEP IN SORTED ORDER! */ #define LOGLEVEL_USER(LOGLEVEL_VAR) \ LOGLEVEL_VAR(9pfs), \ LOGLEVEL_VAR(acpi), \ LOGLEVEL_VAR(acpiGPE), \ LOGLEVEL_VAR(ahci), \ LOGLEVEL_VAR(aio), \ LOGLEVEL_VAR(aioGeneric), \ LOGLEVEL_VAR(aioHttp), \ LOGLEVEL_VAR(aioKernel), \ LOGLEVEL_VAR(aioMgr), \ LOGLEVEL_VAR(aioWin32), \ LOGLEVEL_VAR(aioWin32Completion), \ LOGLEVEL_VAR(amdIommu), \ LOGLEVEL_VAR(appstate), \ LOGLEVEL_VAR(assignHw), \ LOGLEVEL_VAR(asyncsocket), \ LOGLEVEL_VAR(atapiCdrom), \ LOGLEVEL_VAR(authenticode), \ LOGLEVEL_VAR(automation), \ LOGLEVEL_VAR(AVCapture), \ LOGLEVEL_VAR(backdoor), \ LOGLEVEL_VAR(barrier), \ LOGLEVEL_VAR(battery), \ LOGLEVEL_VAR(blit), /* lib/blit */ \ LOGLEVEL_VAR(brtalk), \ LOGLEVEL_VAR(buslogic), \ LOGLEVEL_VAR(buslogicMdev), \ LOGLEVEL_VAR(button), \ LOGLEVEL_VAR(cdrom), \ LOGLEVEL_VAR(checkpoint), \ LOGLEVEL_VAR(checksum), \ LOGLEVEL_VAR(chipset), \ LOGLEVEL_VAR(cmos), \ LOGLEVEL_VAR(cptOps), \ LOGLEVEL_VAR(cpucount), \ LOGLEVEL_VAR(CpuidInfo), \ LOGLEVEL_VAR(crc32), \ LOGLEVEL_VAR(crtbora), /* apps/crtbora */ \ LOGLEVEL_VAR(cui), \ LOGLEVEL_VAR(dataCache), \ LOGLEVEL_VAR(dataSetsMgr), \ LOGLEVEL_VAR(dataSetsStore),\ LOGLEVEL_VAR(device), \ LOGLEVEL_VAR(deviceGroup), \ LOGLEVEL_VAR(devicePowerOn), \ LOGLEVEL_VAR(deviceSwap), \ LOGLEVEL_VAR(deviceThread), \ LOGLEVEL_VAR(dict), \ LOGLEVEL_VAR(digestlib), \ LOGLEVEL_VAR(directBoot), \ LOGLEVEL_VAR(disk), \ LOGLEVEL_VAR(disklib), \ LOGLEVEL_VAR(diskVmnix), \ LOGLEVEL_VAR(dma), \ LOGLEVEL_VAR(dmg), \ LOGLEVEL_VAR(dnd), \ LOGLEVEL_VAR(docker), \ LOGLEVEL_VAR(dui), \ LOGLEVEL_VAR(duiDevices), \ LOGLEVEL_VAR(duiLocalization), \ LOGLEVEL_VAR(duiMKS), \ LOGLEVEL_VAR(duiProxyApps), \ LOGLEVEL_VAR(dumper), \ LOGLEVEL_VAR(dvx), \ LOGLEVEL_VAR(e1000), \ LOGLEVEL_VAR(efinv), \ LOGLEVEL_VAR(efivarstore), \ LOGLEVEL_VAR(ehci), \ LOGLEVEL_VAR(enableDetTimer), \ LOGLEVEL_VAR(epd), \ LOGLEVEL_VAR(extcfgdevice), \ LOGLEVEL_VAR(fakeDma), \ LOGLEVEL_VAR(filtlib), \ LOGLEVEL_VAR(FiltLibTestLog), \ LOGLEVEL_VAR(flashram), \ LOGLEVEL_VAR(floppy), \ LOGLEVEL_VAR(fsresx), \ LOGLEVEL_VAR(ftConfig), /*lib/ftConfig */ \ LOGLEVEL_VAR(ftcpt), \ LOGLEVEL_VAR(grainTrack), \ LOGLEVEL_VAR(grm), \ LOGLEVEL_VAR(guestAppMonitor), \ LOGLEVEL_VAR(guestInstall), \ LOGLEVEL_VAR(guest_msg), \ LOGLEVEL_VAR(guest_rpc), \ LOGLEVEL_VAR(guestVars), \ LOGLEVEL_VAR(gui), \ LOGLEVEL_VAR(guiWin32), \ LOGLEVEL_VAR(Heap), \ LOGLEVEL_VAR(hbaCommon), \ LOGLEVEL_VAR(hbr), \ LOGLEVEL_VAR(hdaudio), \ LOGLEVEL_VAR(hdaudio_alsa), \ LOGLEVEL_VAR(hgfs), \ LOGLEVEL_VAR(hgfsServer), \ LOGLEVEL_VAR(hidQueue), \ LOGLEVEL_VAR(hostctl), \ LOGLEVEL_VAR(hostonly), \ LOGLEVEL_VAR(hpet), \ LOGLEVEL_VAR(http), \ LOGLEVEL_VAR(ich7m), \ LOGLEVEL_VAR(inputdevtap), \ LOGLEVEL_VAR(ipc), \ LOGLEVEL_VAR(ipcMgr), \ LOGLEVEL_VAR(keyboard), \ LOGLEVEL_VAR(keymap), \ LOGLEVEL_VAR(keypersist), \ LOGLEVEL_VAR(largepage), \ LOGLEVEL_VAR(libconnect), \ LOGLEVEL_VAR(license), \ LOGLEVEL_VAR(llc), \ LOGLEVEL_VAR(lsilogic), \ LOGLEVEL_VAR(lwdFilter), \ LOGLEVEL_VAR(macbw), \ LOGLEVEL_VAR(macfi), \ LOGLEVEL_VAR(macfilter), \ LOGLEVEL_VAR(machPoll), \ LOGLEVEL_VAR(maclatency), \ LOGLEVEL_VAR(main), \ LOGLEVEL_VAR(mainMem), \ LOGLEVEL_VAR(mainMemReplayCheck), \ LOGLEVEL_VAR(masReceipt), /* lib/masReceipt */ \ LOGLEVEL_VAR(memoryHotplug), \ LOGLEVEL_VAR(memspace), \ LOGLEVEL_VAR(migrate), \ LOGLEVEL_VAR(migrateVM), \ LOGLEVEL_VAR(mirror), \ LOGLEVEL_VAR(mks), \ LOGLEVEL_VAR(mksBasicOps), \ LOGLEVEL_VAR(mksClient), \ LOGLEVEL_VAR(mksControl), \ LOGLEVEL_VAR(mksCursorPosition), \ LOGLEVEL_VAR(mksDX11Window), \ LOGLEVEL_VAR(mksDX11Renderer), \ LOGLEVEL_VAR(mksDX11Basic), \ LOGLEVEL_VAR(mksDX11ResourceView), \ LOGLEVEL_VAR(mksDX11ShimOps), \ LOGLEVEL_VAR(mksDX12Renderer), \ LOGLEVEL_VAR(mksFrame), \ LOGLEVEL_VAR(mksGLBasic), \ LOGLEVEL_VAR(mksGLContextMux), \ LOGLEVEL_VAR(mksGLDraw), \ LOGLEVEL_VAR(mksGLFBO), \ LOGLEVEL_VAR(mksGLManager), \ LOGLEVEL_VAR(mksGLQuery), \ LOGLEVEL_VAR(mksGLShader), \ LOGLEVEL_VAR(mksGLState), \ LOGLEVEL_VAR(mksGLTextureView), \ LOGLEVEL_VAR(mksGLWindow), \ LOGLEVEL_VAR(mksHostCursor), \ LOGLEVEL_VAR(mksInput), \ LOGLEVEL_VAR(mksKeyboard), \ LOGLEVEL_VAR(mksMouse), \ LOGLEVEL_VAR(mksMTLRenderer), \ LOGLEVEL_VAR(mksRenderOps), \ LOGLEVEL_VAR(mksServer), \ LOGLEVEL_VAR(mksSWB), \ LOGLEVEL_VAR(mksVulkanRenderer), \ LOGLEVEL_VAR(mksVulkanCmds), \ LOGLEVEL_VAR(mksWinBSOD), \ LOGLEVEL_VAR(mor), \ LOGLEVEL_VAR(mstat), \ LOGLEVEL_VAR(msvga), \ LOGLEVEL_VAR(mvnc), \ LOGLEVEL_VAR(namespaceDb), \ LOGLEVEL_VAR(namespaceMgr), \ LOGLEVEL_VAR(netPkt), \ LOGLEVEL_VAR(numa), \ LOGLEVEL_VAR(numaHost), \ LOGLEVEL_VAR(nvdimm), \ LOGLEVEL_VAR(nvme), \ LOGLEVEL_VAR(nvramMgr), \ LOGLEVEL_VAR(objc), /* lib/objc */ \ LOGLEVEL_VAR(objlib), \ LOGLEVEL_VAR(oemDevice), \ LOGLEVEL_VAR(opNotification), \ LOGLEVEL_VAR(oprom), \ LOGLEVEL_VAR(ovhdmem), \ LOGLEVEL_VAR(parallel), \ LOGLEVEL_VAR(passthrough), \ LOGLEVEL_VAR(pci), \ LOGLEVEL_VAR(pcibridge), \ LOGLEVEL_VAR(pci_e1000), \ LOGLEVEL_VAR(pci_ehci), \ LOGLEVEL_VAR(pci_hdaudio), \ LOGLEVEL_VAR(pci_hyper), \ LOGLEVEL_VAR(pciPassthru), \ LOGLEVEL_VAR(pciPlugin), \ LOGLEVEL_VAR(pci_scsi), \ LOGLEVEL_VAR(pci_svga), \ LOGLEVEL_VAR(pci_uhci), \ LOGLEVEL_VAR(pci_vide), \ LOGLEVEL_VAR(pci_vlance), \ LOGLEVEL_VAR(pci_vmci), \ LOGLEVEL_VAR(pci_vmxnet3), \ LOGLEVEL_VAR(pci_xhci), \ LOGLEVEL_VAR(pmemobj), \ LOGLEVEL_VAR(policy), \ LOGLEVEL_VAR(poll), \ LOGLEVEL_VAR(precisionclock), \ LOGLEVEL_VAR(promotedisk), \ LOGLEVEL_VAR(pvnvram), \ LOGLEVEL_VAR(pvscsi), \ LOGLEVEL_VAR(qat), \ LOGLEVEL_VAR(remoteDevice), \ LOGLEVEL_VAR(replayVMX), \ LOGLEVEL_VAR(sbx), \ LOGLEVEL_VAR(scsi), \ LOGLEVEL_VAR(secureBoot), \ LOGLEVEL_VAR(serial), \ LOGLEVEL_VAR(serviceImpl), /* lib/serviceImpl */ \ LOGLEVEL_VAR(serviceUser), /* lib/serviceUser */ \ LOGLEVEL_VAR(sg), /* lib/sg */ \ LOGLEVEL_VAR(sgx), \ LOGLEVEL_VAR(sgxmpa), \ LOGLEVEL_VAR(sgxRegistrationTool), \ LOGLEVEL_VAR(shader), \ LOGLEVEL_VAR(sharedFolderMgr), /* mks/remote/vdpFolderSharedMgrVmdb */ \ LOGLEVEL_VAR(shim3D), \ LOGLEVEL_VAR(slotfs), \ LOGLEVEL_VAR(smbios), \ LOGLEVEL_VAR(smc), \ LOGLEVEL_VAR(smram), \ LOGLEVEL_VAR(snapshot), \ LOGLEVEL_VAR(sound), \ LOGLEVEL_VAR(sparseChecker), \ LOGLEVEL_VAR(ssl), \ LOGLEVEL_VAR(state3d), \ LOGLEVEL_VAR(stats), \ LOGLEVEL_VAR(svga), \ LOGLEVEL_VAR(svgadevtap), \ LOGLEVEL_VAR(svga_rect), \ LOGLEVEL_VAR(syncWaitQ), \ LOGLEVEL_VAR(tarReader),\ LOGLEVEL_VAR(timer), \ LOGLEVEL_VAR(tools), \ LOGLEVEL_VAR(toolsIso), \ LOGLEVEL_VAR(toolsversion), \ LOGLEVEL_VAR(tpm2emu), \ LOGLEVEL_VAR(tpm2Verification), \ LOGLEVEL_VAR(txt), \ LOGLEVEL_VAR(udpfec), /* lib/udpfec */ \ LOGLEVEL_VAR(uhci), \ LOGLEVEL_VAR(undopoint), \ LOGLEVEL_VAR(unityMsg), /* mks/remote/vdpUnityVmdb */ \ LOGLEVEL_VAR(upitbe), \ LOGLEVEL_VAR(upitd), \ LOGLEVEL_VAR(usb), \ LOGLEVEL_VAR(usb_xhci), \ LOGLEVEL_VAR(util), \ LOGLEVEL_VAR(uwt), /* lib/unityWindowTracker */ \ LOGLEVEL_VAR(vaBasicOps), \ LOGLEVEL_VAR(vcpuhotplug), \ LOGLEVEL_VAR(vcpuNUMA), \ LOGLEVEL_VAR(vdfs), \ LOGLEVEL_VAR(vdfs_9p), \ LOGLEVEL_VAR(vdpPlugin), \ LOGLEVEL_VAR(vdtiPciCfgSpc), \ LOGLEVEL_VAR(vflash), \ LOGLEVEL_VAR(vg), \ LOGLEVEL_VAR(vga), \ LOGLEVEL_VAR(vide), \ LOGLEVEL_VAR(viewClient), \ LOGLEVEL_VAR(vigor), \ LOGLEVEL_VAR(viommu), \ LOGLEVEL_VAR(vlance), \ LOGLEVEL_VAR(vmcf), \ LOGLEVEL_VAR(vmci), \ LOGLEVEL_VAR(vmgenc), \ LOGLEVEL_VAR(vmGL), \ LOGLEVEL_VAR(vmhs), \ LOGLEVEL_VAR(vmIPC), \ LOGLEVEL_VAR(vmkcfg), \ LOGLEVEL_VAR(vmkEvent), \ LOGLEVEL_VAR(vmkmgmtlib), \ LOGLEVEL_VAR(vmLock), \ LOGLEVEL_VAR(vmmouse), \ LOGLEVEL_VAR(vmname), /* lib/vmname */ \ LOGLEVEL_VAR(vmnetBridge), \ LOGLEVEL_VAR(vmOvhd), \ LOGLEVEL_VAR(vmUpsellController), \ LOGLEVEL_VAR(vmva), \ LOGLEVEL_VAR(vmWindowController), \ LOGLEVEL_VAR(vmxnet), \ LOGLEVEL_VAR(vmxnet3), \ LOGLEVEL_VAR(vmxvmdbCallbacks), \ LOGLEVEL_VAR(vncBlit), \ LOGLEVEL_VAR(vncDecode), \ LOGLEVEL_VAR(vncEncode), \ LOGLEVEL_VAR(vncRegEnc), \ LOGLEVEL_VAR(vncServer), \ LOGLEVEL_VAR(vncServerOS), \ LOGLEVEL_VAR(vnet), \ LOGLEVEL_VAR(vprobe), \ LOGLEVEL_VAR(VProbeClient), \ LOGLEVEL_VAR(vrdma), \ LOGLEVEL_VAR(vsanobj), \ LOGLEVEL_VAR(vsock), \ LOGLEVEL_VAR(vsockProxy), \ LOGLEVEL_VAR(vthread), \ LOGLEVEL_VAR(vtpm), \ LOGLEVEL_VAR(vui), \ LOGLEVEL_VAR(vusbaudio), \ LOGLEVEL_VAR(vusbccid), \ LOGLEVEL_VAR(vusbhid), \ LOGLEVEL_VAR(vusbkeyboard), \ LOGLEVEL_VAR(vusbmouse), \ LOGLEVEL_VAR(vusbrng),\ LOGLEVEL_VAR(vusbtablet), \ LOGLEVEL_VAR(vusbvideo),\ LOGLEVEL_VAR(vvolbe), \ LOGLEVEL_VAR(vvtd), \ LOGLEVEL_VAR(vwdt), \ LOGLEVEL_VAR(wifi), /* macWireless and wpa_supplicant */ \ LOGLEVEL_VAR(win32util), \ LOGLEVEL_VAR(worker), \ LOGLEVEL_VAR(xled), \ LOGLEVEL_VAR(xpmode) /* end of list */ #endif /* _LOGLEVEL_USER_VARS_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/memaligned.h000066400000000000000000000227531470176644300247760ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * memaligned.h -- * * misc util functions */ #ifndef _MEMALIGNED_H_ #define _MEMALIGNED_H_ #ifdef __linux__ #include #else #include #ifdef __FreeBSD__ #include #endif #endif #include "vmware.h" #if defined(__cplusplus) extern "C" { #endif #if defined __APPLE__ && !vm_x86_64 /* * Bug 471584: Mac OS X 10.6's valloc() implementation for 32-bit * processes can exhaust our process's memory space. * * Work around this by using our own simple page-aligned memory * allocation implementation based on malloc() for 32-bit processes. */ #define MEMALIGNED_USE_INTERNAL_IMPL 1 #endif #ifdef MEMALIGNED_USE_INTERNAL_IMPL /* *----------------------------------------------------------------------------- * * AlignedMallocImpl -- * * Internal implementation of page-aligned memory for operating systems * that lack a working page-aligned allocation function. * * Resulting pointer needs to be freed with AlignedFreeImpl. * * Result: * A pointer. NULL on out of memory condition. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void * AlignedMallocImpl(size_t size) // IN { size_t paddedSize; void **buf; void **alignedResult; #undef PAGE_MASK #define PAGE_MASK (PAGE_SIZE - 1) #define PAGE_ROUND_DOWN(_value) ((uintptr_t)(_value) & ~PAGE_MASK) #define PAGE_ROUND_UP(_value) PAGE_ROUND_DOWN((uintptr_t)(_value) + PAGE_MASK) /* * This implementation allocates PAGE_SIZE extra bytes with * malloc() to ensure the buffer spans a page-aligned memory * address, which we return. (We could use PAGE_SIZE - 1 to save a * byte if we ensured 'size' was non-zero.) * * After padding, we allocate an extra pointer to hold the original * pointer returned by malloc() (stored immediately preceding the * page-aligned address). We free this in AlignedFreeImpl(). * * Finally, we allocate enough space to hold 'size' bytes. */ paddedSize = PAGE_SIZE + sizeof *buf + size; // Check for overflow. if (paddedSize < size) { return NULL; } buf = (void **)malloc(paddedSize); if (!buf) { return NULL; } alignedResult = (void **)PAGE_ROUND_UP(buf + 1); *(alignedResult - 1) = buf; return alignedResult; } /* *----------------------------------------------------------------------------- * * AlignedReallocImpl -- * * Internal implementation of page-aligned memory for operating systems * that lack a working page-aligned allocation function. * * Resulting pointer needs to be freed with AlignedFreeImpl. * * Result: * A pointer. NULL on out of memory condition. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void * AlignedReallocImpl(void *oldbuf, // IN size_t newsize) // IN { size_t paddedSize; void **buf; void **alignedResult; void *oldptr = NULL; if (oldbuf) { oldptr = (*((void **)oldbuf - 1)); } paddedSize = PAGE_SIZE + sizeof *buf + newsize; // Check for overflow. if (paddedSize < newsize) { return NULL; } buf = (void **)realloc(oldptr, paddedSize); if (!buf) { return NULL; } alignedResult = (void **)PAGE_ROUND_UP(buf + 1); *(alignedResult - 1) = buf; return alignedResult; } /* *----------------------------------------------------------------------------- * * AlignedFreeImpl -- * * Internal implementation to free a page-aligned buffer allocated * with AlignedMallocImpl. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void AlignedFreeImpl(void *buf) // IN { if (!buf) { return; } free(*((void **)buf - 1)); } #endif // MEMALIGNED_USE_INTERNAL_IMPL /* *--------------------------------------------------------------------------- * * Aligned_UnsafeMalloc -- * * Alloc a chunk of memory aligned on a page boundary. Resulting pointer * needs to be freed with Aligned_Free. * * Result: * A pointer. NULL on out of memory condition. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static INLINE void* Aligned_UnsafeMalloc(size_t size) // IN { void *buf; #if defined MEMALIGNED_USE_INTERNAL_IMPL buf = AlignedMallocImpl(size); #elif defined _WIN32 buf = _aligned_malloc(size, PAGE_SIZE); #elif __linux__ buf = memalign(PAGE_SIZE, size); #else // Apple, BSD, Solaris (tools) buf = valloc(size); #endif ASSERT(((uintptr_t)buf % PAGE_SIZE) == 0); return buf; } /* *--------------------------------------------------------------------------- * * Aligned_Malloc -- * * Alloc a chunk of memory aligned on a page boundary. Resulting pointer * needs to be freed with Aligned_Free. You should never use this * function. Especially if size was derived from guest provided data. * * Result: * A pointer. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static INLINE void* Aligned_Malloc(size_t size) // IN { void *buf; buf = Aligned_UnsafeMalloc(size); VERIFY(buf); return buf; } /* *--------------------------------------------------------------------------- * * Aligned_Calloc -- * * Alloc a chunk of memory aligned on a page boundary. Resulting pointer * needs to be freed with Aligned_Free. * * Result: * A pointer. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static INLINE void* Aligned_Calloc(size_t nmemb, // IN size_t size) // IN { void *buf = Aligned_Malloc(nmemb * size); VERIFY(buf); memset(buf, 0, nmemb * size); return buf; } /* *--------------------------------------------------------------------------- * * Aligned_Free -- * * Free a chunk of memory allocated using the 2 functions above. * * Result: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static INLINE void Aligned_Free(void *buf) // IN { #if defined MEMALIGNED_USE_INTERNAL_IMPL AlignedFreeImpl(buf); #elif defined _WIN32 _aligned_free(buf); #else free(buf); #endif } /* *--------------------------------------------------------------------------- * * Aligned_UnsafeRealloc -- * * This function is not implemented because it cannot be done safely and * portably. See https://reviewboard.eng.vmware.com/r/284303/ for * discussion. * *--------------------------------------------------------------------------- */ /* *--------------------------------------------------------------------------- * * Aligned_Realloc -- * * Realloc a chunk of memory aligned on a page boundary, potentially * copying the previous data to a new buffer if necessary. Resulting * pointer needs to be freed with Aligned_Free. You should never use this * function. Especially if size was derived from guest provided data. * * Result: * A pointer. * * Side effects: * Old buf may be freed. * *--------------------------------------------------------------------------- */ static INLINE void* Aligned_Realloc(void *buf, // IN size_t size) // IN { #if defined MEMALIGNED_USE_INTERNAL_IMPL return AlignedReallocImpl(buf, size); #elif defined _WIN32 return _aligned_realloc(buf, size, PAGE_SIZE); #else /* * Some valloc(3) manpages claim that realloc(3) on a buffer allocated by * valloc() will return an aligned buffer. If so, we have a fast path; * simply realloc, validate the alignment, and return. For realloc()s that * do not maintain the alignment (such as glibc 2.13 x64 for allocations of * 16 pages or less) then we fall back to a slowpath and copy the data. * Note that we can't avoid the realloc overhead in this case: on entry to * Aligned_Realloc we have no way to find out how big the source buffer is! * Only after the realloc do we know a safe range to copy. We may copy more * data than necessary -- consider the case of resizing from one page to * 100 pages -- but that is safe, just slow. */ buf = realloc(buf, size); if (((uintptr_t)buf % PAGE_SIZE) != 0) { void *newbuf; newbuf = Aligned_UnsafeMalloc(size); VERIFY(newbuf); memcpy(newbuf, buf, size); free(buf); return newbuf; } return buf; #endif } #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/message.h000066400000000000000000000047531470176644300243200ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1999-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * message.h -- * * Second layer of the internal communication channel between guest * applications and vmware */ #ifndef __MESSAGE_H__ # define __MESSAGE_H__ #include "vm_basic_types.h" #ifdef __cplusplus extern "C" { #endif /* The channel object */ typedef struct Message_Channel { /* Identifier */ uint16 id; /* Reception buffer */ /* Data */ unsigned char *in; /* Allocated size */ size_t inAlloc; Bool inPreallocated; /* The cookie */ uint32 cookieHigh; uint32 cookieLow; } Message_Channel; Bool Message_OpenAllocated(uint32 proto, Message_Channel *chan, char *receiveBuffer, size_t receiveBufferSize); Message_Channel* Message_Open(uint32 proto); Bool Message_Send(Message_Channel *chan, const unsigned char *buf, size_t bufSize); Bool Message_Receive(Message_Channel *chan, unsigned char **buf, size_t *bufSize); Bool Message_CloseAllocated(Message_Channel *chan); Bool Message_Close(Message_Channel *chan); #ifdef __cplusplus } #endif #endif /* __MESSAGE_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/mntinfo.h000066400000000000000000000165331470176644300243450ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * mntinfo.h -- * * Macros to abstract differences between structures and functions used in * accessing information about mounted file systems. * */ #ifndef __MNTINFO_H__ #define __MNTINFO_H__ #ifdef sun # include # include # include #elif defined(__linux__) # include #elif defined(__FreeBSD__) # include #endif #include "posix.h" /* *---------------------------------------------------------------------------- * * DECLARE_MNTINFO, MNTINFO * OPEN_MNTFILE, GETNEXT_MNTINFO, CLOSE_MNTFILE, * MNTINFO_NAME, MNTINFO_FSTYPE, MNTINFO_MNTPT -- * * Cross-platform macros for accessing information about the mounted file * systems. This is necessary since the interfaces for getmntent(3) are * slightly different on Linux and Solaris. * * DECLARE_MNTINFO() is used to declare the variable used when invoking * GETNEXT_MNTINFO(). MNTINFO is the type that can be used when passing * between functions. * * OPEN_MNTFILE() and CLOSE_MNTFILE() must be called before and after * a series of GETNEXT_MNTINFO() calls, respectively. GETNEXT_MNTINFO() is * called successively to retrieve information about the next mounted file * system. * * MNTINFO_NAME, MNTINFO_FSTYPE, and MNTINFO_MNTPT retrieve the name, file * system type, and mount point of the provided MNTINFO, respectively. * * MNTFILE is a string with the name of the file containing mount * information. * * Results: * OPEN_MNTFILE: MNTHANDLE on success, NULL on failure * GETNEXT_MNTINFO: on success, TRUE and mnt is filled with file system's * information; FALSE when no mounts left or on failure * CLOSE_MNTFILE: TRUE on success, FALSE on failure * * MNTINFO_NAME: mount's name on success, NULL on failure * MNTINFO_FSTYPE: mount's file system type on success, NULL on failure * MNTINFO_MNTPT: mount's mount point on success, NULL on failure * * Side effects: * None. * *---------------------------------------------------------------------------- */ #ifdef sun # define MNTFILE MNTTAB # define MNTHANDLE FILE * # define MNTINFO struct mnttab # define DECLARE_MNTINFO(name) struct mnttab __ ## name; \ struct mnttab *name = &__ ## name # define OPEN_MNTFILE(mode) Posix_Fopen(MNTFILE, mode) # define GETNEXT_MNTINFO(fp, mnt) (Posix_Getmntent(fp, mnt) == 0) # define CLOSE_MNTFILE(fp) (fclose(fp) == 0) # define MNTINFO_NAME(mnt) mnt->mnt_special # define MNTINFO_FSTYPE(mnt) mnt->mnt_fstype # define MNTINFO_MNTPT(mnt) mnt->mnt_mountp # define MNTINFO_MNT_IS_RO(mnt) (hasmntopt((mnt), "rw") == NULL) #elif defined(__linux__) # define MNTFILE MOUNTED # define MNTHANDLE FILE * # define MNTINFO struct mntent # define DECLARE_MNTINFO(name) struct mntent *name # define OPEN_MNTFILE(mode) Posix_Setmntent(MNTFILE, mode) # define GETNEXT_MNTINFO(fp, mnt) ((mnt = Posix_Getmntent(fp)) != NULL) # define CLOSE_MNTFILE(fp) (endmntent(fp) == 1) # define MNTINFO_NAME(mnt) mnt->mnt_fsname # define MNTINFO_FSTYPE(mnt) mnt->mnt_type # define MNTINFO_MNTPT(mnt) mnt->mnt_dir # define MNTINFO_MNT_IS_RO(mnt) (hasmntopt((mnt), "rw") == NULL) #elif defined(__FreeBSD__) || defined(__APPLE__) struct mntHandle { struct statfs *mountPoints; // array of mountpoints per getmntinfo(3) int numMountPoints; // number of elements in mntArray int mountIndex; // current location within mountPoints array }; # define MNTFILE _PATH_FSTAB # define MNTHANDLE struct mntHandle * # define MNTINFO struct statfs # define DECLARE_MNTINFO(name) struct statfs __ ## name; \ struct statfs *name = &__ ## name # define OPEN_MNTFILE(mode) \ ({ \ MNTHANDLE mntHandle; \ mntHandle = malloc(sizeof *mntHandle); \ if (mntHandle != NULL) { \ mntHandle->numMountPoints = getmntinfo(&mntHandle->mountPoints, \ MNT_NOWAIT); \ mntHandle->mountIndex = 0; \ } \ mntHandle; \ }) # define GETNEXT_MNTINFO(mntHandle, mnt) \ ({ \ /* Avoid multiple evaluations/expansions. */ \ MNTHANDLE thisHandle = (mntHandle); \ MNTINFO *thisMnt = (mnt); \ Bool boolVal = FALSE; \ ASSERT(thisHandle); \ if (thisHandle->mountIndex < thisHandle->numMountPoints) { \ memcpy(thisMnt, \ &thisHandle->mountPoints[thisHandle->mountIndex], \ sizeof *thisMnt); \ ++thisHandle->mountIndex; \ boolVal = TRUE; \ } \ boolVal; \ }) # define CLOSE_MNTFILE(mntHandle) \ ({ \ free(mntHandle); \ TRUE; \ }) # define MNTINFO_NAME(mnt) mnt->f_mntfromname # define MNTINFO_FSTYPE(mnt) mnt->f_fstypename # define MNTINFO_MNTPT(mnt) mnt->f_mntonname # define MNTINFO_MNT_IS_RO(mnt) ((mnt)->f_flags & MNT_RDONLY) #else # error "Define mount information macros for your OS type" #endif #endif /* __MNTINFO_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/msg.h000066400000000000000000000176121470176644300234600ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * msg.h -- * * user interaction through (non-modal) messages and (modal) dialogs */ #ifndef _MSG_H_ #define _MSG_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include #include #include "err.h" #include "vm_basic_types.h" #include "msgid.h" #include "msgfmt.h" #include "msgList.h" #if defined VMX86_SERVER && !defined VMCORE #include "voblib.h" #endif #if defined(__cplusplus) extern "C" { #endif #define INVALID_MSG_CODE (-1) /* * Data structures, types, and constants */ typedef struct Msg_String { const char *idFmt; } Msg_String; typedef enum MsgSeverity { MSG_INFO, MSG_INFO_TIMEOUT, MSG_WARNING, MSG_ERROR, MSG_CONFIG_EDITOR, MSG_WEB_LINK_GET_LICENSE_ERROR, MSG_WEB_LINK_EXTEND_LICENSE_ERROR, MSG_WEB_LINK_EXTEND_LICENSE_INFO, MSG_WEB_LINK_HOME_PAGE_INFO, MSG_NUM_SEVERITIES } MsgSeverity; typedef enum HintResult { HINT_CONTINUE, HINT_CANCEL, HINT_NOT_SHOWN } HintResult; typedef enum HintOptions { HINT_OK, HINT_OKCANCEL } HintOptions; typedef struct MsgCallback { void (*post)(MsgSeverity severity, const char *msgID, const char *message); int (*question)(char const * const *names, int defaultAnswer, const char *msgID, const char *message); int (*progress)(const char *msgID, const char *message, int percent, Bool cancelButton); HintResult (*hint)(HintOptions options, const char *msgID, const char *message); void *(*lazyProgressStart)(const char *msgID, const char *message, Bool allowCancel); Bool (*lazyProgress)(void *handle, const char *msgID, const char *message, Bool allowCancel, int percent); void (*lazyProgressEnd)(void *handle); void (*postList)(MsgSeverity severity, MsgList *messages); int (*questionList)(const Msg_String *buttons, int defaultAnswer, MsgList *messages); int (*progressList)(MsgList *messages, int percent, Bool cancelButton); HintResult (*hintList)(HintOptions options, MsgList *messages); void *(*lazyProgressStartList)(MsgList *messages); void (*forceUnblock)(void); void (*msgPostHook)(int severity, const MsgList *msgs); } MsgCallback; #define MSG_QUESTION_MAX_BUTTONS 10 #define MSG_PROGRESS_START (-1) #define MSG_PROGRESS_STOP 101 VMX86_EXTERN_DATA Msg_String const Msg_YesNoButtons[]; VMX86_EXTERN_DATA Msg_String const Msg_OKButtons[]; VMX86_EXTERN_DATA Msg_String const Msg_RetryCancelButtons[]; VMX86_EXTERN_DATA Msg_String const Msg_OKCancelButtons[]; VMX86_EXTERN_DATA Msg_String const Msg_RetryAbortButtons[]; VMX86_EXTERN_DATA Msg_String const Msg_Severities[]; /* * Functions */ void Msg_Append(const char *idFmt, ...) PRINTF_DECL(1, 2); void Msg_VAppend(const char *idFmt, va_list args); void Msg_AppendStr(const char *id); void Msg_AppendMsgList(const MsgList *msgs); static INLINE void Msg_AppendVobContext(void) { #if defined VMX86_SERVER && !defined VMCORE /* inline to avoid lib/vob dependency unless necessary */ MsgList *msgs = NULL; VobLib_CurrentContextMsgAppend(&msgs); Msg_AppendMsgList(msgs); MsgList_Free(msgs); #endif } void Msg_Post(MsgSeverity severity, const char *idFmt, ...) PRINTF_DECL(2, 3); void Msg_PostMsgList(MsgSeverity severity, const MsgList *msgs); char *Msg_Format(const char *idFmt, ...) PRINTF_DECL(1, 2); char *Msg_VFormat(const char *idFmt, va_list arguments); unsigned Msg_Question(Msg_String const *buttons, int defaultAnswer, const char *idFmt, ...) PRINTF_DECL(3, 4); /* * Unfortunately, gcc warns about both NULL and "" being passed as format * strings, and callers of Msg_Progress() like to do that. So I'm removing * the PRINTF_DECL() for now. --Jeremy. */ int Msg_Progress(int percentDone, Bool cancelButton, const char *idFmt, ...); int Msg_ProgressScaled(int percentDone, int opsDone, int opsTotal, Bool cancelButton); void *Msg_LazyProgressStart(Bool allowCancel, const char *idFmt, ...) PRINTF_DECL(2, 3); Bool Msg_LazyProgress(void *handle, Bool allowCancel, int percent, const char *idFmt, ...) PRINTF_DECL(4, 5); void Msg_LazyProgressEnd(void *handle); HintResult Msg_Hint(Bool defaultShow, HintOptions options, const char *idFmt, ...) PRINTF_DECL(3, 4); HintResult Msg_HintMsgList(Bool defaultShow, HintOptions options, MsgList *msg); int Msg_CompareAnswer(Msg_String const *buttons, unsigned answer, const char *string); Bool Msg_IsAnswered(Msg_String const *buttons, int defaultAnswer, const char *id, unsigned int *reply); char *Msg_GetString(const char *idString); char *Msg_GetStringSafe(const char *idString); char *Msg_GetPlainButtonText(const char *idString); char *Msg_GetLocale(void); void Msg_SetLocale(const char *locale, const char *binaryName); void Msg_SetLocaleEx(const char *locale, const char *binaryName, const char *baseDirPath); char *Msg_FormatFloat(double value, unsigned int precision); char *Msg_FormatSizeInBytes(uint64 size); Bool Msg_LoadMessageFile(const char *locale, const char *fileName); void Msg_ForceUnblock(void); /* * Message buffer management */ const char *Msg_GetMessages(void); const char *Msg_GetMessagesAndReset(void); void Msg_LogAndReset(void); MsgList *Msg_GetMsgList(void); MsgList *Msg_GetMsgListAndReset(void); char *Msg_LocalizeList(const MsgList *messages); void Msg_Reset(Bool log); Bool Msg_Present(void); void Msg_ExitThread(void); void Msg_Exit(void); /* * Don't know, don't care. -- edward */ #define MSG_POST_NOMEM() \ Msg_Post(MSG_ERROR, MSGID(msg.noMem) "Cannot allocate memory.\n") #ifndef VMX86_DEBUG #define MSG_CHECK_ORPHANED_MESSAGES(id, fmt, arg) #elif defined VMX86_DEVEL #define MSG_CHECK_ORPHANED_MESSAGES(id, fmt, arg) ( \ Msg_Present() ? \ Msg_Post(MSG_INFO, \ id fmt "THIS MESSAGE ON DEVEL BUILDS only - " \ "Please file bug about orphan Msg_Append\n", \ arg) : \ (void) 0 \ ) #else #define MSG_CHECK_ORPHANED_MESSAGES(id, fmt, arg) ( \ Msg_Present() ? \ (Log(fmt, arg), \ Msg_Reset(TRUE)) : \ (void) 0 \ ) #endif /* * To implement message dialogs */ void Msg_SetCallback(MsgCallback *cb); void Msg_SetThreadCallback(MsgCallback *cb); void Msg_GetCallback(MsgCallback *cb); void Msg_GetThreadCallback(MsgCallback *cb); /* * Conversion functions */ #define Msg_ErrString() (Err_ErrString()) #define Msg_Errno2String(errorNumber) ( \ Err_Errno2String(errorNumber) ) #ifdef _WIN32 const char *Msg_HResult2String(long hr); #endif #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _MSG_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/msgList.h000066400000000000000000000045521470176644300243130ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * msgList.h -- * * Utilities to manipulate (stateless) lists of messages. */ #ifndef _MSGLIST_H_ #define _MSGLIST_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include #include #include "vm_basic_types.h" #include "msgid.h" #include "msgfmt.h" #if defined(__cplusplus) extern "C" { #endif /* * Data structures, types, and constants */ typedef struct MsgList MsgList; struct MsgList { MsgList *next; char *id; char *format; MsgFmt_Arg *args; int numArgs; }; /* * Functions */ MsgList *MsgList_Create(const char *idFmt, ...) PRINTF_DECL(1, 2); MsgList *MsgList_VCreate(const char *idFmt, va_list args); MsgList *MsgList_CreateStr(const char *id); void MsgList_Append(MsgList **tail, const char *idFmt, ...) PRINTF_DECL(2, 3); void MsgList_VAppend(MsgList **tail, const char *idFmt, va_list args); void MsgList_AppendStr(MsgList **tail, const char *id); void MsgList_AppendMsgList(MsgList **tail, MsgList *messages); void MsgList_Log(const MsgList *messages); char *MsgList_ToEnglishString(const MsgList *messages); MsgList *MsgList_Copy(const MsgList *src); void MsgList_Free(MsgList *messages); const char *MsgList_GetMsgID(const MsgList *messages); Bool MsgList_Present(const MsgList *messages); static INLINE void MsgList_LogAndFree(MsgList *messages) { MsgList_Log(messages); MsgList_Free(messages); } #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _MSGLIST_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/msgfmt.h000066400000000000000000000126071470176644300241660ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * msgfmg.h -- * * MsgFmt: format messages for the Msg module */ #ifndef _MSGFMT_H_ #define _MSGFMT_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #ifndef VMKERNEL #include "str.h" // for HAS_BSD_PRINTF #endif #if defined(__cplusplus) extern "C" { #endif /* * Format parser callback functions */ typedef int MsgFmt_LitFunc(void *clientData, // IN char const *buf, // IN int bufSize); // IN typedef int MsgFmt_SpecFunc(void *clientData, // IN char const *pos, // IN unsigned int posSize, // IN char const *type, // IN unsigned int typeSize); // IN /* * Format specifier flags from MsgFmt_ParseSpec() */ #define MSGFMT_FLAG_ALT 0x0001 #define MSGFMT_FLAG_ZERO 0x0002 #define MSGFMT_FLAG_MINUS 0x0004 #define MSGFMT_FLAG_SPACE 0x0008 #define MSGFMT_FLAG_PLUS 0x0010 #define MSGFMT_FLAG_QUOTE 0x0020 /* * A format argument * * In addition to being a internal data structure, * MsgFmt_Arg defines the Vob (vmkernel observations) protocol * between vmkernel and vmx. As such, it must be carefully aligned, * so that all the fields (except the pointers) have fixed sizes * and the same offsets in the 64-bit vmkernel, the 32-bit vmx, * and the 64-bit vmx. */ typedef enum MsgFmt_ArgType { MSGFMT_ARG_INVALID, // must be 0 MSGFMT_ARG_INT32, MSGFMT_ARG_INT64, MSGFMT_ARG_PTR32, MSGFMT_ARG_PTR64, MSGFMT_ARG_FLOAT64, MSGFMT_ARG_STRING8, MSGFMT_ARG_STRING16, MSGFMT_ARG_STRING32, MSGFMT_ARG_ERRNO, } MsgFmt_ArgType; typedef enum MsgFmt_ArgPlatform { MSGFMT_PLATFORM_UNKNOWN, MSGFMT_PLATFORM_LINUX, MSGFMT_PLATFORM_WINDOWS, MSGFMT_PLATFORM_MACOS, } MsgFmt_ArgPlatform; typedef struct MsgFmt_Arg { int32 type; int32 pad; union { int32 signed32; int64 signed64; uint32 unsigned32; uint64 unsigned64; double float64; char *string8char; // same as string8, different type int8 *string8; int16 *string16; int32 *string32; int32 offset; void *ptr; // private } v; struct { int32 platform; int32 number; } e; union { // private int32 precision; char *localString; uint64 pad; } p; } MsgFmt_Arg; #if defined __linux__ #define MSGFMT_CURRENT_PLATFORM MSGFMT_PLATFORM_LINUX #elif defined _WIN32 #define MSGFMT_CURRENT_PLATFORM MSGFMT_PLATFORM_WINDOWS #elif defined __APPLE__ #define MSGFMT_CURRENT_PLATFORM MSGFMT_PLATFORM_MACOS #else #define MSGFMT_CURRENT_PLATFORM MSGFMT_PLATFORM_UNKNOWN #endif /* * Global functions */ typedef int MsgFmt_ParseFunc(MsgFmt_LitFunc *litFunc, // IN MsgFmt_SpecFunc *specFunc, // IN void *clientData, // IN char const *in); // IN MsgFmt_ParseFunc MsgFmt_Parse; MsgFmt_ParseFunc MsgFmt_ParseWin32; int MsgFmt_ParseSpec(char const *pos, // IN: n$ location unsigned int posSize, // IN: n$ length char const *type, // IN: flags, width, etc. unsigned int typeSize, // IN: size of above int *position, // OUT: argument position int *flags, // OUT: flags, see MSGFMT_FLAG_* int *width, // OUT: width int *precision, // OUT: precision char *lengthMod, // OUT: length modifier char *conversion); // OUT: conversion specifier Bool MsgFmt_GetArgs(const char *fmt, va_list va, MsgFmt_Arg **args, int *numArgs, char **error); Bool MsgFmt_GetArgsWithBuf(const char *fmt, va_list va, MsgFmt_Arg **args, int *numArgs, char **error, void *buf, size_t *bufSize); void MsgFmt_FreeArgs(MsgFmt_Arg *args, int numArgs); void MsgFmt_SwizzleArgs(MsgFmt_Arg *args, int numArgs); int MsgFmt_GetSwizzledString(const MsgFmt_Arg *args, int numArgs, int idx, const void *bufEnd, const int8 **str); int MsgFmt_UnswizzleArgs(MsgFmt_Arg *args, int numArgs, void *bufEnd); MsgFmt_Arg* MsgFmt_CopyArgs(MsgFmt_Arg* copyArgs, int numArgs); int MsgFmt_Snprintf(char *buf, size_t size, const char *format, const MsgFmt_Arg *args, int numArgs); char *MsgFmt_Asprintf(size_t *length, const char *format, const MsgFmt_Arg *args, int numArgs); #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _MSGFMT_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/msgid.h000066400000000000000000000054671470176644300240020ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * msgid.h -- * * Message ID magic */ #ifndef _MSGID_H_ #define _MSGID_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "msgid_defs.h" #include "vm_basic_defs.h" #ifndef VMKERNEL #include #endif #if defined(__cplusplus) extern "C" { #endif // the X hides MSG_MAGIC so it won't appear in the object file #define MSG_MAGICAL(s) \ (s != NULL && strncmp(s, MSG_MAGIC"X", MSG_MAGIC_LEN) == 0) // Start after MSG_MAGIC so it won't appear in the object file either. #define MSG_HAS_BUTTONID(s) \ (MSG_MAGICAL(s) && \ (strncmp(&(s)[MSG_MAGIC_LEN], MSG_BUTTON_ID, MSG_BUTTON_ID_LEN) == 0)) /* *----------------------------------------------------------------------------- * * Msg_HasMsgID -- * * Check that a string has a message ID. * The full "MSG_MAGIC(...)" prefix is required, not just MSG_MAGIC. * * Results: * True if string has a message ID. * * Side Effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Msg_HasMsgID(const char *s) { return MSG_MAGICAL(s) && *(s += MSG_MAGIC_LEN) == '(' && strchr(s + 1, ')') != NULL; } /* *----------------------------------------------------------------------------- * * Msg_StripMSGID -- * * Returns the string that is inside the MSGID() or if it doesn't * have a MSGID just return the string. * * Results: * The unlocalized string. * * Side Effects: * None * *----------------------------------------------------------------------------- */ static INLINE const char * Msg_StripMSGID(const char *idString) // IN { const char *s = idString; if (MSG_MAGICAL(s) && *(s += MSG_MAGIC_LEN) == '(' && (s = strchr(s + 1, ')')) != NULL) { return s + 1; } return idString; } #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _MSGID_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/msgid_defs.h000066400000000000000000000035421470176644300247730ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2011-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * msgid_defs.h -- * * Message ID magic definitions */ #ifndef _MSGID_DEFS_H_ #define _MSGID_DEFS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" /* * Message ID macros * * Use as in * Msg_Append(MSGID(file.openFailed) "Failed to open file %s: %s.\n" * fileName, Msg_ErrString()) * Msg_Append(MSGID(mks.powerOnFailed) "Power on failed.\n") * or * Msg_Hint(TRUE, HINT_OK, * MSGID(mks.noDGA) "No full screen mode.\n"). * * Don't make MSG_MAGIC_LEN (sizeof MSG_MAGIC - 1), since * that may cause the string to be in the object file, even * when it's not used at run time. And we are trying * to avoid littering the output with the magic string. * * -- edward */ #define MSG_MAGIC "@&!*@*@" #define MSG_MAGIC_LEN 7 #define MSGID(id) MSG_MAGIC "(msg." #id ")" #define MSG_BUTTON_ID "(button." #define MSG_BUTTON_ID_LEN 8 #define BUTTONID(id) MSG_MAGIC MSG_BUTTON_ID #id ")" #endif // ifndef _MSGID_DEFS_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/mul64.h000066400000000000000000000103461470176644300236360ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2014,2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * mul64.h * * Integer by fixed point multiplication, with rounding. * * These routines are implemented in assembly language for most * supported platforms. This file has plain C fallback versions. */ #ifndef _MUL64_H_ #define _MUL64_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_asm.h" #if defined __cplusplus extern "C" { #endif #ifdef MUL64_NO_ASM /* *----------------------------------------------------------------------------- * * Mul64x3264 -- * * Unsigned integer by fixed point multiplication, with rounding: * result = floor(multiplicand * multiplier * 2**(-shift) + 0.5) * * Unsigned 64-bit integer multiplicand. * Unsigned 32-bit fixed point multiplier, represented as * (multiplier, shift), where shift < 64. * * Result: * Unsigned 64-bit integer product. * *----------------------------------------------------------------------------- */ static INLINE uint64 Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) { uint64 lo, hi, lo2, hi2; unsigned carry; // ASSERT(shift >= 0 && shift < 64); lo = (multiplicand & 0xffffffff) * multiplier; hi = (multiplicand >> 32) * multiplier; lo2 = lo + (hi << 32); carry = lo2 < lo; hi2 = (hi >> 32) + carry; if (shift == 0) { return lo2; } else { return (lo2 >> shift) + (hi2 << (64 - shift)) + ((lo2 >> (shift - 1)) & 1); } } /* *----------------------------------------------------------------------------- * * Muls64x32s64 -- * * Signed integer by fixed point multiplication, with rounding: * result = floor(multiplicand * multiplier * 2**(-shift) + 0.5) * * Signed 64-bit integer multiplicand. * Unsigned 32-bit fixed point multiplier, represented as * (multiplier, shift), where shift < 64. * * Result: * Signed 64-bit integer product. * *----------------------------------------------------------------------------- */ static INLINE int64 Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) { uint64 lo, hi, lo2, hi2; unsigned carry; // ASSERT(shift >= 0 && shift < 64); hi = ((uint64)multiplicand >> 32) * multiplier; if (multiplicand < 0) { hi -= (uint64)multiplier << 32; } lo = ((uint64)multiplicand & 0xffffffff) * multiplier; lo2 = lo + (hi << 32); carry = lo2 < lo; hi2 = (((int64)hi >> 32) + carry); if (shift == 0) { return lo2; } else { return (lo2 >> shift) + (hi2 << (64 - shift)) + ((lo2 >> (shift - 1)) & 1); } } #endif #if defined __cplusplus } // extern "C" #endif #endif // _MUL64_NOASM_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/mutexRank.h000066400000000000000000000060621470176644300246450ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2010-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * mutexRank.h -- * * Base lock rank defines. See userlock.h for the related APIs. */ #ifndef _MUTEXRANK_H_ #define _MUTEXRANK_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #if defined(__cplusplus) extern "C" { #endif /* * Core rank defines. * * ANY RANK USAGE ABOVE RANK_LEAF IS RESERVED BY THE PI GROUP. */ #define RANK_UNRANKED 0 #define RANK_LEAF 0xFF000000 #define RANK_INVALID 0xFFFFFFFF /* * For situations where we need to create locks on behalf of * third-party code, but we don't know what ranking scheme, if any, * that code uses. For now, the only usage is in bora/lib/ssl. */ #define RANK_THIRDPARTY RANK_UNRANKED /* * Log lock rank. * * Very special case. Don't change it. The effect is that critical * logging code cannot call anything else which requires a lock, but * everyone else can safely Log() while holding a leaf lock. */ #define RANK_logLock (RANK_LEAF + 2) /* * overheadMem lock rank. * * Very special case. Don't change it. One must be able to enter * the overheadMem Facility at any rank (RANK_LEAF or lower) and * still be able to acquire a lock in overheadMem *AND* be able * to Log(). */ #define RANK_overheadMem (RANK_LEAF + 1) /* * bora/lib/allocTrack rank (not really). * * This is another special case. It hooks malloc/free and the like, * and thus can basically sneak in underneath anyone. To that end * allocTrack uses unranked, native locks internally to avoid any * complications. */ /* * VMX/VMM/device lock rank space. * * This rank space is at the bottom, from 1 to RANK_VMX_LEAF. See * vmx/public/mutexRankVMX.h for definitions. */ /* * Foundry lock rank space. * * This rank space is from RANK_foundryLockBase on up to * RANK_foundryLockLeaf. See apps/lib/foundry/mutexRankFoundry.h for * definitions. */ #define RANK_foundryLockBase 0x80000000 /* * bora/lib lock rank space. * * This rank space is from RANK_libLockBase on up to RANK_LEAF. See * lib/public/mutexRankLib.h for definitions. */ #define RANK_libLockBase 0xF0000000 #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _MUTEXRANK_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/mutexRankLib.h000066400000000000000000000214741470176644300253000ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2010-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _LIBMUTEXRANK_H #define _LIBMUTEXRANK_H #include "mutexRank.h" #if defined(__cplusplus) extern "C" { #endif /* * MXUser mutex ranks for bora/lib code. * * The ranks define the ordering in which locks are allowed to be acquired. * * Only locks with higher rank numbers (generally more localized) * can be acquired while a lock with a lower rank number is active. * * bora/lib lock rank space is from RANK_libLockBase on up to * RANK_LEAF (see vm_basic_defs).asdf * * (Keep all of the below offsets in hex). */ /* * hostDeviceInfo HAL lock * * Must be < vmhs locks since this is held around the RANK_vmhsHDILock * callback lock which vmhs passes into that library. */ #define RANK_hdiHALLock (RANK_libLockBase + 0x1005) /* * vmhs locks (must be < vigor) */ #define RANK_vmhsHDILock (RANK_libLockBase + 0x3002) #define RANK_vmhsThrMxLock (RANK_libLockBase + 0x3005) #define RANK_vmhsVmxMxLock (RANK_libLockBase + 0x3005) /* * hgfs locks */ #define RANK_hgfsSessionArrayLock (RANK_libLockBase + 0x4010) #define RANK_hgfsSharedFolders (RANK_libLockBase + 0x4030) #define RANK_hgfsNotifyLock (RANK_libLockBase + 0x4040) #define RANK_hgfsFileIOLock (RANK_libLockBase + 0x4050) #define RANK_hgfsSearchArrayLock (RANK_libLockBase + 0x4060) #define RANK_hgfsNodeArrayLock (RANK_libLockBase + 0x4070) #define RANK_hgfsActivateLock (RANK_libLockBase + 0x4080) #define RANK_hgfsThreadpoolLock (RANK_libLockBase + 0x4090) #define RANK_nfcLibAioCtxLock (RANK_libLockBase + 0x4300) /* * vigor (must be < VMDB range and < disklib, see bug 741290) */ #define RANK_vigorOnlineLock (RANK_libLockBase + 0x4400) #define RANK_vigorOfflineLock (RANK_libLockBase + 0x4410) /* * The lock range for IO filters: * [RANK_libLockBase + 0x4420 , RANK_libLockBase + 0x442F] * * (must be > vigor and < filtlib, see PR 2613901) * Inbox filters may need to use lock ranks and these filters can be loaded * under Vigor-Offline. Therefore, any lock used by a filter in its callbacks * should have a rank greater than RANK_vigorOfflineLock. IO filter lock ranks * should also be lower than RANK_filtLibPollLock because this allows * VMIOF/filtlib APIs that hold filtLibPollLock to be invoked while holding an * IO filter lock. */ #define RANK_ioFiltersBase (RANK_libLockBase + 0x4420) /* * filtlib (must be > vigor and < disklib and workercmlp, PR 1340298) */ #define RANK_filtLibPollLock (RANK_libLockBase + 0x4430) /* * filtib lock which protects a disk's allocation bitmap state. * Must be > filtLibPollLock, as it could be acquire with the poll lock held. * And as evidenced by PR1437159, it must also be lower than workerLibCmplLock. */ #define RANK_filtLibAllocBitmapLock (RANK_filtLibPollLock + 1) /* * remoteUSB (must be < workerCmpl) */ #define RANK_remoteUSBGlobalLock (RANK_filtLibAllocBitmapLock + 1) /* * workerLib default completion lock * * Used for workerLib callers who don't provide their own lock. Held * around arbitrary completion callbacks so it makes sense to be of * a low rank. * * Must be > RANK_vigorOfflineLock because we may queue work in Vigor * offline. * * Must be < RANK_nfcLibLock, because NFC uses AIO Generic to perform * async writes to the virtual disk. * * Must be > RANK_filtLibPollLock so that filtlib timers can wait * for queued work. * * Must be > RANK_filtLibAllocBitmapLock due to PR1437159. * * Must be > RANK_remoteUSBGlobalLock so that virtual CCID can wait for * queued work. */ #define RANK_workerLibCmplLock (RANK_remoteUSBGlobalLock + 1) /* * NFC lib lock */ #define RANK_nfcLibInitLock (RANK_libLockBase + 0x4505) #define RANK_nfcLibLock (RANK_libLockBase + 0x4506) #define RANK_nfcLibSessionListLock (RANK_libLockBase + 0x4507) #define RANK_nfcLibAioLock (RANK_libLockBase + 0x4508) #define RANK_nfcLibLastErrorLock (RANK_libLockBase + 0x4509) /* * Policy lib lock */ #define RANK_policyLibLock (RANK_libLockBase + 0x4605) /* * disklib and I/O related locks */ #define RANK_diskLibLock (RANK_libLockBase + 0x5001) #define RANK_digestLibLock (RANK_libLockBase + 0x5004) #define RANK_nasPluginLock (RANK_libLockBase + 0x5007) #define RANK_nasPluginMappingLock (RANK_libLockBase + 0x5008) #define RANK_diskLibPluginLock (RANK_libLockBase + 0x5010) #define RANK_vmioPluginRootLock (RANK_libLockBase + 0x5020) #define RANK_vmioPluginSysLock (RANK_libLockBase + 0x5040) #define RANK_fsCmdLock (RANK_libLockBase + 0x5050) #define RANK_scsiStateLock (RANK_libLockBase + 0x5060) #define RANK_parInitLock (RANK_libLockBase + 0x5070) #define RANK_datasetsLock (RANK_libLockBase + 0x5075) #define RANK_namespaceLock (RANK_libLockBase + 0x5080) #define RANK_objLibInitLock (RANK_libLockBase + 0x5085) #define RANK_vvolLibLock (RANK_libLockBase + 0x5090) #define RANK_aioMgrInitLock (RANK_libLockBase + 0x5095) /* * Persistent-memory logical and hardware management locks */ /* The nvdimm layer is the hardware layer */ #define RANK_nvdHandleLock (RANK_libLockBase + 0x5300) /* The pmem layer is the logical layer */ #define RANK_pmemHandleLock (RANK_libLockBase + 0x5310) /* * VMDB range: * (RANK_libLockBase + 0x5500, RANK_libLockBase + 0x5600) */ #define RANK_vmuSecPolicyLock (RANK_libLockBase + 0x5505) #define RANK_vmdbCnxRpcLock (RANK_libLockBase + 0x5510) #define RANK_vmdbCnxRpcBarrierLock (RANK_libLockBase + 0x5520) #define RANK_vmdbCnxLock (RANK_libLockBase + 0x5530) #define RANK_vmdbSecureLock (RANK_libLockBase + 0x5540) #define RANK_vmdbDbLock (RANK_libLockBase + 0x5550) #define RANK_vmdbW32HookLock (RANK_libLockBase + 0x5560) #define RANK_vmdbWQPoolLock (RANK_libLockBase + 0x5570) #define RANK_vmdbMemMapLock (RANK_libLockBase + 0x5580) /* * USB range: * (RANK_libLockBase + 0x6500, RANK_libLockBase + 0x6600) */ #define RANK_usbArbLibGlobalLock (RANK_libLockBase + 0x6505) #define RANK_usbEnumGlobalLock (RANK_libLockBase + 0x6506) #define RANK_usbArbLibAsockLock (RANK_libLockBase + 0x6507) #define RANK_usbEnumBackendLock (RANK_libLockBase + 0x6508) #define RANK_sensorQueueLock (RANK_libLockBase + 0x6509) #define RANK_ccidListLock (RANK_libLockBase + 0x650A) #define RANK_readerLock (RANK_libLockBase + 0x650B) #define RANK_ccidLock (RANK_libLockBase + 0x650C) /* * misc locks * * Assuming ordering is important here for the listed locks. Other * non-leaf locks are usually defined with RANK_LEAF - 1. * * At least: * impersonate < pollDefault * keyLocator < preference (for checking AESNI) * keyLocator < sslState (bug 743010) * configDb < keyLocator (for unlocking dictionaries) * battery/button < preference * workerLib < something for sure under VThread_Create * licenseCheck < preference * sslState < sslCrlCache * sslCrlCache < getSafeTmpDir */ #define RANK_vigorTransportListLock (RANK_libLockBase + 0x7010) #define RANK_batteryLock (RANK_libLockBase + 0x7030) #define RANK_buttonLock (RANK_libLockBase + 0x7040) #define RANK_impersonateLock (RANK_libLockBase + 0x7045) #define RANK_pollDefaultLock (RANK_libLockBase + 0x7050) #define RANK_workerLibLock (RANK_libLockBase + 0x7060) #define RANK_configDbLock (RANK_libLockBase + 0x7070) #define RANK_keyLocatorLock (RANK_libLockBase + 0x7080) #define RANK_sslStateLock (RANK_libLockBase + 0x7085) #define RANK_sslCrlCacheLock (RANK_libLockBase + 0x7086) #define RANK_getSafeTmpDirLock (RANK_libLockBase + 0x7087) #define RANK_licenseCheckLock (RANK_libLockBase + 0x7090) #define RANK_preferenceLock (RANK_libLockBase + 0x7100) #if defined(__cplusplus) } // extern "C" #endif #endif /* _LIBMUTEXRANK_H */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/netutil.h000066400000000000000000000073521470176644300243560ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * netutil.h -- * * Utility network functions. * */ #ifndef __NETUTIL_H__ #define __NETUTIL_H__ #ifdef _WIN32 # include # include # include "vmware/iphlpapi_packed.h" # include # include #else # include #endif #include "vm_basic_types.h" #include "guestInfo.h" /* * Interface types as assigned by IANA. * See http://www.iana.org/assignments/ianaiftype-mib for more details. */ typedef enum { IANA_IFTYPE_OTHER = 1, IANA_IFTYPE_ETHERNETCSMACD = 6, } IanaIfType; /* * Modified from iptypes.h... */ char *NetUtil_GetPrimaryIP(void); GuestNic *NetUtil_GetPrimaryNic(void); #ifdef _WIN32 /* * Brute-force this. Trying to do it "properly" with * WINVER/NTDDI_VERSION checks/manips in a way that compiles for both * VC8 and VC9 didn't work. */ #ifndef FIXED_INFO typedef FIXED_INFO_W2KSP1 FIXED_INFO; typedef FIXED_INFO_W2KSP1 *PFIXED_INFO; #endif DWORD NetUtil_LoadIpHlpApiDll(void); DWORD NetUtil_FreeIpHlpApiDll(void); /* Wrappers for functions in iphlpapi.dll */ PFIXED_INFO NetUtil_GetNetworkParams(void); PIP_ADAPTER_INFO NetUtil_GetAdaptersInfo(void); ULONG NetUtil_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID rsvd, PIP_ADAPTER_ADDRESSES adap_addresses, PULONG SizePointer); PMIB_IPFORWARDTABLE NetUtilWin32_GetIpForwardTable(void); PMIB_IPFORWARD_TABLE2 NetUtilWin32_GetIpForwardTable2(void); void NetUtilWin32_FreeMibTable(PMIB_IPFORWARD_TABLE2); #endif #ifdef WIN32 int NetUtil_InetPToN(int af, const char *src, void *dst); const char *NetUtil_InetNToP(int af, const void *src, char *dst, socklen_t size); #else // ifdef WIN32 # define NetUtil_InetPToN inet_pton # define NetUtil_InetNToP inet_ntop #endif #if defined(__linux__) # ifdef DUMMY_NETUTIL /* * Dummy interface table to enable other tools'/libraries' unit tests. */ typedef struct { int ifIndex; const char *ifName; } NetUtilIfTableEntry; /* * {-1, NULL}-terminated array of NetUtilIfTableEntry pointers. * * (Test) applications wishing to use the dummy NetUtil_GetIf{Index,Name} * functions must define this variable somewhere. It allows said apps * to work with a priori knowledge of interface name <=> index mappings * returned by said APIs. */ EXTERN NetUtilIfTableEntry netUtilIfTable[]; int NetUtil_GetIfIndex(const char *ifName); char *NetUtil_GetIfName(int ifIndex); # endif // ifdef DUMMY_NETUTIL #endif // if defined(__linux__) size_t NetUtil_GetHardwareAddress(int ifIndex, // IN char *hwAddr, // OUT size_t hwAddrSize, // IN IanaIfType *ifType); // OUT #endif // ifndef _NETUTIL_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/nicInfo.h000066400000000000000000000056411470176644300242560ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2014-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * nicInfo.h -- * * Functions used to communicate guest networking information to the host. * */ #ifndef NICINFO_H #define NICINFO_H #include #include "guestInfo.h" typedef enum { NICINFO_PRIORITY_PRIMARY, NICINFO_PRIORITY_NORMAL, NICINFO_PRIORITY_LOW, NICINFO_PRIORITY_MAX } NicInfoPriority; Bool GuestInfo_GetFqdn(int outBufLen, char fqdn[]); Bool GuestInfo_GetNicInfo(unsigned int maxIPv4Routes, unsigned int maxIPv6Routes, NicInfoV3 **nicInfo, Bool *maxNicsError); void GuestInfo_FreeNicInfo(NicInfoV3 *nicInfo); char *GuestInfo_GetPrimaryIP(void); /* * Comparison routines -- handy for caching, unit testing. */ Bool GuestInfo_IsEqual_DhcpConfigInfo(const DhcpConfigInfo *a, const DhcpConfigInfo *b); Bool GuestInfo_IsEqual_DnsConfigInfo(const DnsConfigInfo *a, const DnsConfigInfo *b); Bool GuestInfo_IsEqual_DnsHostname(const DnsHostname *a, const DnsHostname *b); Bool GuestInfo_IsEqual_InetCidrRouteEntry(const InetCidrRouteEntry *a, const InetCidrRouteEntry *b, const NicInfoV3 *aInfo, const NicInfoV3 *bInfo); Bool GuestInfo_IsEqual_IpAddressEntry(const IpAddressEntry *a, const IpAddressEntry *b); Bool GuestInfo_IsEqual_NicInfoV3(const NicInfoV3 *a, const NicInfoV3 *b); Bool GuestInfo_IsEqual_TypedIpAddress(const TypedIpAddress *a, const TypedIpAddress *b); Bool GuestInfo_IsEqual_WinsConfigInfo(const WinsConfigInfo *a, const WinsConfigInfo *b); void GuestInfo_SetIfaceExcludeList(char **list); void GuestInfo_SetIfacePrimaryList(char **list); void GuestInfo_SetIfaceLowPriorityList(char **list); Bool GuestInfo_IfaceIsExcluded(const char *name); NicInfoPriority GuestInfo_IfaceGetPriority(const char *name); #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/panic.h000066400000000000000000000064601470176644300237630ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2003-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * panic.h -- * * Module to encapsulate common Panic behavior. */ #ifndef _PANIC_H_ #define _PANIC_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif /* * Initialize module to read custom behavior from config files. */ void Panic_Init(void); /* * If you want the Panic module to just handle everything: implement Panic() * as a call to Panic_Panic(). If you want to implement your own Panic(), * you can still use functions below to query whether certain features are * desired and get the default implementation of each feature. */ NORETURN void Panic_Panic(const char *format, va_list args); /* * On panic, post a UI dialog about the panic and how to diagnose it: */ void Panic_SetPanicMsgPost(Bool postMsg); Bool Panic_GetPanicMsgPost(void); void Panic_PostPanicMsg(const char *format, ...); /* * On panic, break into a debugger or enter an infinite loop until a * debugger stops it: */ typedef enum { PanicBreakAction_Never, PanicBreakAction_IfDebuggerAttached, PanicBreakAction_Always } PanicBreakAction; void Panic_SetBreakAction(PanicBreakAction action); PanicBreakAction Panic_GetBreakAction(void); Bool Panic_GetBreakOnPanic(void); void Panic_BreakOnPanic(void); void Panic_LoopOnPanic(void); /* *----------------------------------------------------------------------------- * * Panic_SetBreakOnPanic -- * * Allow the debug breakpoint on panic to be suppressed. If passed FALSE, * then any subsequent Panics will not attempt to attract a debugger. * * Results: * void. * * Side effects: * Enables/Disables break into debugger on Panic(). * *----------------------------------------------------------------------------- */ static INLINE void Panic_SetBreakOnPanic(Bool breakOnPanic) // IN: { Panic_SetBreakAction(breakOnPanic ? PanicBreakAction_Always : PanicBreakAction_Never); } /* * On panic, dump core; Panic is also the place where various pieces of * back end stash information about the core dump. */ void Panic_SetCoreDumpOnPanic(Bool dumpCore); Bool Panic_GetCoreDumpOnPanic(void); int Panic_GetCoreDumpFlags(void); void Panic_SetCoreDumpFlags(int flags); /* * Extra debugging information that Panic module knows how to dump. */ void Panic_DumpGuiResources(void); #if defined(__cplusplus) } // extern "C" #endif #endif // _PANIC_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/poll.h000066400000000000000000000250071470176644300236350ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ #ifndef _POLL_H_ #define _POLL_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_types.h" #include "vm_basic_defs.h" #include "vmware.h" #include "userlock.h" #if defined(__cplusplus) extern "C" { #endif #ifdef _WIN32 #define HZ 100 #elif defined __linux__ #include #elif __APPLE__ #include /* * Old SDKs don't define TARGET_OS_IPHONE at all. * New ones define it to 0 on Mac OS X, 1 on iOS. */ #if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0 #include #endif #include #define HZ 100 #endif #ifdef __ANDROID__ /* * of android should be included, but its name is same * with this file. So its content is put here to avoid conflict. */ #include #define HZ 100 typedef unsigned int nfds_t; int poll(struct pollfd *, nfds_t, long); #endif /* * Poll event types: each type has a different reason for firing, * or condition that must be met before firing. */ typedef enum { /* * Actual Poll queue types against which you can register callbacks. */ POLL_VIRTUALREALTIME = -1, /* Negative because it doesn't have its own Q */ POLL_VTIME = 0, POLL_REALTIME, POLL_DEVICE, POLL_MAIN_LOOP, POLL_NUM_QUEUES } PollEventType; /* * Classes of events * * These are the predefined classes. More can be declared * with Poll_AllocClass(). */ typedef enum PollClass { POLL_CLASS_MAIN, POLL_CLASS_PAUSE, POLL_CLASS_IPC, POLL_CLASS_CPT, POLL_CLASS_MKS, POLL_FIXED_CLASSES, POLL_DEFAULT_FIXED_CLASSES, /* Size enum to maximum */ POLL_MAX_CLASSES = 31, } PollClass; /* * Do not use; Special pseudo private poll class supported by * PollDefault only */ #define POLL_DEFAULT_CLASS_NET POLL_FIXED_CLASSES #define POLL_DEFAULT_CS_NET PollClassSet_Singleton(POLL_DEFAULT_CLASS_NET) /* * Each callback is registered in a set of classes */ typedef struct PollClassSet { uintptr_t bits; } PollClassSet; /* An empty PollClassSet. */ static INLINE PollClassSet PollClassSet_Empty(void) { PollClassSet set = { 0 }; return set; } /* A PollClassSet with the single member. */ static INLINE PollClassSet PollClassSet_Singleton(PollClass c) { PollClassSet s = PollClassSet_Empty(); ASSERT_ON_COMPILE(POLL_MAX_CLASSES < sizeof s.bits * 8); ASSERT(c < POLL_MAX_CLASSES); s.bits = CONST3264U(1) << c; return s; } /* Combine two PollClassSets. */ static INLINE PollClassSet PollClassSet_Union(PollClassSet lhs, PollClassSet rhs) { PollClassSet set; set.bits = lhs.bits | rhs.bits; return set; } /* Add single class to PollClassSet. */ static INLINE PollClassSet PollClassSet_Include(PollClassSet set, PollClass c) { return PollClassSet_Union(set, PollClassSet_Singleton(c)); } #define POLL_CS_MAIN PollClassSet_Singleton(POLL_CLASS_MAIN) #define POLL_CS_PAUSE PollClassSet_Union(POLL_CS_MAIN, \ PollClassSet_Singleton(POLL_CLASS_PAUSE)) #define POLL_CS_CPT PollClassSet_Union(POLL_CS_PAUSE, \ PollClassSet_Singleton(POLL_CLASS_CPT)) #define POLL_CS_IPC PollClassSet_Union(POLL_CS_CPT, \ PollClassSet_Singleton(POLL_CLASS_IPC)) #define POLL_CS_VMDB POLL_CS_PAUSE /* POLL_CLASS_VMDB is retired */ #define POLL_CS_MKS PollClassSet_Singleton(POLL_CLASS_MKS) /* * DANGER. You don't need POLL_CS_ALWAYS. Really. So don't use it. */ #define POLL_CS_ALWAYS PollClassSet_Union(POLL_CS_CPT, POLL_CS_IPC) /* * Poll class-set taxonomy: * POLL_CS_MAIN * - Unless you NEED another class, use POLL_CS_MAIN. * POLL_CS_PAUSE * - For callbacks that must occur even if the guest is paused. * Most VMDB or Foundry commands are in this category. * POLL_CS_CPT * - Only for callbacks which can trigger intermediate Checkpoint * transitions. * The ONLY such callback is Migrate. * POLL_CS_IPC * - Only for callbacks which can contain Msg_(Post|Hint|Question) * responses, and for signal handlers (why)? * Vigor, VMDB, and Foundry can contain Msg_* responses. * POLL_CS_MKS * - Callback runs in MKS thread. * POLL_CS_ALWAYS * - Only for events that must be processed immediately. * The ONLY such callback is OvhdMemVmxSizeCheck. */ /* * Poll_Callback flags */ #define POLL_FLAG_PERIODIC 0x01 // keep after firing #define POLL_FLAG_REMOVE_AT_POWEROFF 0x02 // self-explanatory #define POLL_FLAG_READ 0x04 // device is ready for reading #define POLL_FLAG_WRITE 0x08 // device is ready for writing #define POLL_FLAG_SOCKET 0x10 // device is a Windows socket #define POLL_FLAG_NO_BULL 0x20 // callback does its own locking #define POLL_FLAG_WINSOCK 0x40 // Winsock style write events #define POLL_FLAG_FD 0x80 // device is a Windows file descriptor. #define POLL_FLAG_ACCEPT_INVALID_FDS 0x100 // For broken 3rd party libs, e.g. curl #define POLL_FLAG_THUNK_TO_WND 0x200 // thunk callback to window message loop typedef void (*PollerFunction)(void *clientData); typedef void (*PollerFireWrapper)(PollerFunction func, void *funcData, void *wrapperData); typedef Bool (*PollerErrorFn)(const char *errorStr); /* * Initialisers: * * For the sake of convenience, we declare the initialisers * for custom implmentations here, even though the actual * implementations are distinct from the core poll code. */ /* Socket pair created with non-blocking mode */ #define POLL_OPTIONS_SOCKET_PAIR_NONBLOCK_CONN 0x01 typedef unsigned int SocketSpecialOpts; typedef struct PollOptions { Bool locked; // Use internal MXUser for locking Bool allowFullQueue; // Don't assert when device event queue is full. VThreadID windowsMsgThread; // thread that processes Windows messages PollerFireWrapper fireWrapperFn; // optional; may be useful for stats void *fireWrapperData; // optional PollerErrorFn errorFn; // optional; called upon unrecoverable error SocketSpecialOpts pollSocketOpts; } PollOptions; void Poll_InitDefault(void); void Poll_InitDefaultEx(const PollOptions *opts); void Poll_InitGtk(void); // On top of glib for Linux void Poll_InitCF(void); // On top of CoreFoundation for OSX Bool Poll_IsInitialized(void); /* * Functions */ int Poll_SocketPair(Bool vmci, Bool stream, int fds[2], SocketSpecialOpts opts); void Poll_Loop(Bool loop, Bool *exit, PollClass c); void Poll_LoopTimeout(Bool loop, Bool *exit, PollClass c, int timeout); Bool Poll_LockingEnabled(void); void Poll_Exit(void); /* * Poll_Callback adds a callback regardless of whether an identical one exists. * The exception to this rule is POLL_DEVICE callbacks: there is a maximum of * one read and one write callback per fd. * * Poll_CallbackRemove removes one callback. If there are multiple identical * callbacks, which one is removed is an implementation detail. Note that in * the case of POLL_DEVICE and POLL_REALTIME callbacks, the fd/delay used to * create the callback is not specified when removing, so all callbacks * of those types with the same flags, function, and clientData are considered * "identical" even if their fd/delay differed. */ VMwareStatus Poll_Callback(PollClassSet classSet, int flags, PollerFunction f, void *clientData, PollEventType type, PollDevHandle info, // fd/microsec delay MXUserRecLock *lck); Bool Poll_CallbackRemove(PollClassSet classSet, int flags, PollerFunction f, void *clientData, PollEventType type); Bool Poll_CallbackRemoveOneByCB(PollClassSet classSet, int flags, PollerFunction f, PollEventType type, void **clientData); void Poll_NotifyChange(PollClassSet classSet); /* * Wrappers for Poll_Callback and Poll_CallbackRemove that present * simpler subsets of those interfaces. */ VMwareStatus Poll_CB_Device(PollerFunction f, void *clientData, PollDevHandle device, Bool periodic); Bool Poll_CB_DeviceRemove(PollerFunction f, void *clientData, Bool periodic); VMwareStatus Poll_CB_RTime(PollerFunction f, void *clientData, int64 delay, // microseconds Bool periodic, MXUserRecLock *lock); Bool Poll_CB_RTimeRemove(PollerFunction f, void *clientData, Bool periodic); #ifdef _WIN32 void Poll_SetPumpsWindowsMessages(Bool pumps); void Poll_SetWindowMessageRecipient(HWND hWnd, UINT msg, Bool alwaysThunk); Bool Poll_FireWndCallback(void *lparam); #endif #if defined(__cplusplus) } // extern "C" #endif #endif // _POLL_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/pollImpl.h000066400000000000000000000107341470176644300244600ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * pollImpl.h -- * * Header file for poll implementations. Poll consumers should not * include is file. */ #ifndef _POLLIMPL_H_ #define _POLLIMPL_H_ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #include "poll.h" #include "vm_basic_asm.h" #if defined(__cplusplus) extern "C" { #endif /* * PollImpl: * * A Poll implementation should provide a filled in PollImpl * to pass to Poll_Init. */ typedef struct PollImpl { void (*Init) (void); void (*Exit) (void); void (*LoopTimeout) (Bool loop, Bool *exit, PollClass c, int timeout); VMwareStatus (*Callback) (PollClassSet classSet, int flags, PollerFunction f, void *clientData, PollEventType type, PollDevHandle info, MXUserRecLock *lock); Bool (*CallbackRemove) (PollClassSet classSet, int flags, PollerFunction f, void *clientData, PollEventType type); Bool (*CallbackRemoveOneByCB)(PollClassSet classSet, int flags, PollerFunction f, PollEventType type, void **clientData); Bool (*LockingEnabled) (void); void (*NotifyChange) (PollClassSet classSet); } PollImpl; void Poll_InitWithImpl(const PollImpl *impl); /* Check if a PollClass is part of the set. */ static INLINE Bool PollClassSet_IsMember(PollClassSet set, PollClass c) { return (set.bits & PollClassSet_Singleton(c).bits) != 0; } /* Compare two PollClassSets. */ static INLINE Bool PollClassSet_Equals(PollClassSet lhs, PollClassSet rhs) { return lhs.bits == rhs.bits; } /* Verifies if the class set is empty. */ static INLINE Bool PollClassSet_IsEmpty(PollClassSet cs) { return PollClassSet_Equals(cs, PollClassSet_Empty()); } /* Remove from a PollClassSet. */ static INLINE void PollClassSet_Remove(PollClassSet *set, PollClass c) { set->bits &= ~PollClassSet_Singleton(c).bits; } /* Find first set. POLL_MAX_CLASSES for none set. */ static INLINE PollClass PollClassSet_FFS(PollClassSet *set) { if (set->bits != 0) { return (PollClass)lssbPtr_0(set->bits); } return POLL_MAX_CLASSES; } /* *---------------------------------------------------------------------------- * * PollLockingAlwaysEnabled -- * PollLockingNotAvailable -- * * Simple LockingEnabled() functions for poll implementation that does * not dynamically enable locking. * * Results: * Bool. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static INLINE Bool PollLockingAlwaysEnabled(void) { return TRUE; } static INLINE Bool PollLockingNotAvailable(void) { return FALSE; } #if defined(__cplusplus) } // extern "C" #endif #endif /* _POLLIMPL_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/posix.h000066400000000000000000000510021470176644300240230ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef VMWARE_POSIX_H #define VMWARE_POSIX_H #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include #include #if !defined(_WIN32) #include #include #include #endif #include "vm_basic_types.h" #include "unicodeTypes.h" #include "unicodeBase.h" #include "codeset.h" #include "err.h" #if defined(__cplusplus) extern "C" { #endif /* * Require the _FILE_OFFSET_BITS=64 interface, where all Posix file * structures and functions are transparently 64-bit. * * Some OSes (FreeBSD, OS X) natively use 64-bit file offsets and * will never be a problem. Other OSes (Linux, Solaris) default * to 32-bit offsets in 32-bit mode. Android ... does its own thing. * Windows only offers the Posix APIs as 32-bit. * * There are two ways of getting 64-bit offsets, defined by the LFS standard: * _LARGEFILE64_SOURCE, which defines xxx64 types and functions * _FILE_OFFSET_BITS=64, which replaces all types and functions * The _LARGEFILE64_SOURCE strategy was transitional (late 90s) and is now * deprecated. All modern code should use _FILE_OFFSET_BITS=64. * * Instead of checking for the exact details, check for what matters * for the purposes of this file: types (e.g. off_t) must be 64-bit. */ #if !defined(_WIN32) && !defined(__ANDROID__) MY_ASSERTS(_file_offset_bits64, ASSERT_ON_COMPILE(sizeof(off_t) == 8);) #endif struct stat; #if defined(_WIN32) typedef int mode_t; #else struct statfs; struct utimbuf; struct timeval; struct passwd; #if !defined(sun) struct mntent; #else struct mnttab; #endif #endif int Posix_Creat(const char *pathName, mode_t mode); int Posix_Open(const char *pathName, int flags, ...); FILE *Posix_Fopen(const char *pathName, const char *mode); FILE *Posix_Popen(const char *pathName, const char *mode); int Posix_Rename(const char *fromPathName, const char *toPathName); int Posix_Rmdir(const char *pathName); int Posix_Unlink(const char *pathName); FILE *Posix_Freopen(const char *pathName, const char *mode, FILE *stream); int Posix_Access(const char *pathName, int mode); int Posix_EuidAccess(const char *pathName, int mode); int Posix_Stat(const char *pathName, struct stat *statbuf); int Posix_Chmod(const char *pathName, mode_t mode); void Posix_Perror(const char *str); int Posix_Printf(const char *format, ...); int Posix_Fprintf(FILE *stream, const char *format, ...); int Posix_Mkdir(const char *pathName, mode_t mode); int Posix_Chdir(const char *pathName); char *Posix_Getenv(const char *name); long Posix_Pathconf(const char *pathName, int name); int Posix_Lstat(const char *pathName, struct stat *statbuf); char *Posix_MkTemp(const char *pathName); /* *----------------------------------------------------------------------------- * * Posix_Free -- * * Wrapper around free() that preserves errno. * * C11 (and earlier) does not prohibit free() implementations from * modifying errno. That is undesirable since it can clobber errno along * cleanup paths, and it is expected to be prohibited by a future (as of * January 2017) version of the POSIX standard. See: * * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ #define Posix_Free(p) WITH_ERRNO_FREE(p) #if !defined(_WIN32) /* * These Windows APIs actually work with non-ASCII (MBCS) strings. * Make them NULL wrappers for all other platforms. */ #define Posix_GetHostName gethostname #if defined(__APPLE__) #define Posix_GetHostByName gethostbyname #endif #define Posix_GetAddrInfo getaddrinfo #define Posix_FreeAddrInfo freeaddrinfo #define Posix_GetNameInfo getnameinfo void *Posix_Dlopen(const char *pathName, int flags); int Posix_Utime(const char *pathName, const struct utimbuf *times); int Posix_Mknod(const char *pathName, mode_t mode, dev_t dev); int Posix_Chown(const char *pathName, uid_t owner, gid_t group); int Posix_Lchown(const char *pathName, uid_t owner, gid_t group); int Posix_Link(const char *oldPath, const char *newPath); int Posix_Symlink(const char *oldPath, const char *newPath); int Posix_Mkfifo(const char *pathName, mode_t mode); int Posix_Truncate(const char *pathName, off_t length); int Posix_Utimes(const char *pathName, const struct timeval *time); int Posix_Execl(const char *pathName, const char *arg0, ...); int Posix_Execlp(const char *fileName, const char *arg0, ...); int Posix_Execv(const char *pathName, char *const argVal[]); int Posix_Execve(const char *pathName, char *const argVal[], char *const envPtr[]); int Posix_Execvp(const char *fileName, char *const argVal[]); DIR *Posix_OpenDir(const char *pathName); int Posix_System(const char *command); int Posix_Putenv(char *name); int Posix_Unsetenv(const char *name); /* * These functions return dynamically allocated stings that have to be * freed by the caller so they must be used in the ESX environment. They * are different than their POSIX "base" functions. */ char *Posix_RealPath(const char *pathName); char *Posix_ReadLink(const char *pathName); struct passwd *Posix_Getpwnam(const char *name); struct passwd *Posix_Getpwuid(uid_t uid); int Posix_Setenv(const char *name, const char *value, int overWrite); int Posix_Getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size, struct passwd **ppw); int Posix_Getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **ppw); struct passwd *Posix_Getpwent(void); void Posix_Endpwent(void); struct group *Posix_Getgrnam(const char *name); int Posix_Getgrnam_r(const char *name, struct group *gr, char *buf, size_t size, struct group **pgr); #if !defined(sun) int Posix_Statfs(const char *pathName, struct statfs *statfsbuf); int Posix_GetGroupList(const char *user, gid_t group, gid_t *groups, int *ngroups); #if !defined(__APPLE__) && !defined(__FreeBSD__) int Posix_Mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data); int Posix_Umount(const char *target); FILE *Posix_Setmntent(const char *pathName, const char *mode); struct mntent *Posix_Getmntent(FILE *fp); struct mntent *Posix_Getmntent_r(FILE *fp, struct mntent *m, char *buf, int size); #endif // !defined(__APPLE__) && !defined(__FreeBSD__) #else // !defined(sun) int Posix_Getmntent(FILE *fp, struct mnttab *mp); #endif // !defined(sun) #if !defined(__APPLE__) /* *---------------------------------------------------------------------- * * Posix_GetHostByName -- * * Wrapper for gethostbyname(). Caller should release memory * allocated for the hostent structure returned by calling * Posix_FreeHostent(). * * Results: * NULL Error * !NULL Pointer to hostent structure * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE struct hostent* Posix_GetHostByName(const char *name) // IN { struct hostent *newhostent; int error; struct hostent he; char buffer[1024]; struct hostent *phe = &he; char **p; int i; int naddrs; ASSERT(name); if ((gethostbyname_r(name, &he, buffer, sizeof buffer, #if !defined(sun) && !defined(SOLARIS) && !defined(SOL10) &phe, #endif &error) == 0) && phe) { newhostent = (struct hostent *)Util_SafeMalloc(sizeof *newhostent); newhostent->h_name = Unicode_Alloc(phe->h_name, STRING_ENCODING_DEFAULT); if (phe->h_aliases) { newhostent->h_aliases = Unicode_AllocList(phe->h_aliases, -1, STRING_ENCODING_DEFAULT); } else { newhostent->h_aliases = NULL; } newhostent->h_addrtype = phe->h_addrtype; newhostent->h_length = phe->h_length; naddrs = 1; for (p = phe->h_addr_list; *p; p++) { naddrs++; } newhostent->h_addr_list = (char **)Util_SafeMalloc(naddrs * sizeof(*(phe->h_addr_list))); for (i = 0; i < naddrs - 1; i++) { newhostent->h_addr_list[i] = (char *)Util_SafeMalloc(phe->h_length); memcpy(newhostent->h_addr_list[i], phe->h_addr_list[i], phe->h_length); } newhostent->h_addr_list[naddrs - 1] = NULL; return newhostent; } /* There has been an error */ return NULL; } #endif // !define(__APPLE__) /* *---------------------------------------------------------------------- * * Posix_FreeHostent -- * * Free the memory allocated for an hostent structure returned * by Posix_GetHostByName. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE void Posix_FreeHostent(struct hostent *he) { #if !defined(__APPLE__) char **p; if (he) { // See Posix_Free. int err = errno; free(he->h_name); if (he->h_aliases) { Util_FreeStringList(he->h_aliases, -1); } p = he->h_addr_list; while (*p) { free(*p++); } free(he->h_addr_list); free(he); errno = err; } #else (void) he; #endif } #else // !define(_WIN32) #if defined(_WINSOCKAPI_) || defined(_WINSOCK2API_) #include #include "vm_atomic.h" #if defined(VM_WIN_UWP) /* UWP use the network definition in winsock2.h */ #include #endif /* *---------------------------------------------------------------------- * * Posix_GetHostName -- * * Wrapper for gethostname(). * * Results: * 0 Success * -1 Error * * Side effects: * On error, error code returned by WSAGetLastError() is updated. * *---------------------------------------------------------------------- */ static INLINE int Posix_GetHostName(char *name, // OUT int namelen) // IN { char *nameMBCS = (char *)Util_SafeMalloc(namelen); char *nameUTF8; int retval; ASSERT(name); retval = gethostname(nameMBCS, namelen); if (retval == 0) { nameUTF8 = Unicode_Alloc(nameMBCS, STRING_ENCODING_DEFAULT); if (!Unicode_CopyBytes(name, nameUTF8, namelen, NULL, STRING_ENCODING_UTF8)) { retval = -1; WSASetLastError(WSAEFAULT); } Posix_Free(nameUTF8); } Posix_Free(nameMBCS); return retval; } /* *---------------------------------------------------------------------- * * Posix_GetHostByName -- * * Wrapper for gethostbyname(). Caller should release memory * allocated for the hostent structure returned by calling * Posix_FreeHostent(). * * Results: * NULL Error * !NULL Pointer to hostent structure * * Side effects: * On error, error code returned by WSAGetLastError() is updated. * *---------------------------------------------------------------------- */ static INLINE struct hostent* Posix_GetHostByName(const char *name) // IN { struct hostent *newhostent; char *nameMBCS; struct hostent *hostentMBCS; struct hostent *ret = NULL; ASSERT(name); nameMBCS = (char *)Unicode_GetAllocBytes(name, STRING_ENCODING_DEFAULT); if (nameMBCS != NULL) { hostentMBCS = gethostbyname(nameMBCS); Posix_Free(nameMBCS); if (hostentMBCS != NULL) { newhostent = (struct hostent *)Util_SafeMalloc(sizeof *newhostent); newhostent->h_name = Unicode_Alloc(hostentMBCS->h_name, STRING_ENCODING_DEFAULT); if (hostentMBCS->h_aliases) { newhostent->h_aliases = Unicode_AllocList(hostentMBCS->h_aliases, -1, STRING_ENCODING_DEFAULT); } else { newhostent->h_aliases = NULL; } newhostent->h_addrtype = hostentMBCS->h_addrtype; newhostent->h_length = hostentMBCS->h_length; newhostent->h_addr_list = hostentMBCS->h_addr_list; ret = newhostent; } } else { /* There has been an error converting from UTF-8 to local encoding. */ WSASetLastError(WSANO_RECOVERY); } return ret; } /* *---------------------------------------------------------------------- * * Posix_FreeHostent -- * * Free the memory allocated for an hostent structure returned * by Posix_GetHostByName. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE void Posix_FreeHostent(struct hostent *he) { if (he) { Posix_Free(he->h_name); if (he->h_aliases) { Util_FreeStringList(he->h_aliases, -1); } Posix_Free(he); } } #endif // defined(_WINSOCKAPI_) || defined(_WINSOCK2API_) #ifdef _WS2TCPIP_H_ /* *---------------------------------------------------------------------- * * Posix_GetAddrInfo -- * * Wrapper for getaddrinfo(). * * Inlined to match Ws2tcpip.h inclusion. * * Results: * 0 Success * != 0 Error * * Side effects: * On error, error code returned by WSAGetLastError() is updated. * *---------------------------------------------------------------------- */ static INLINE int Posix_GetAddrInfo(const char *nodename, // IN const char *servname, // IN const struct addrinfo *hints, // IN struct addrinfo **res) // OUT { int retval; struct addrinfoW *resW; utf16_t *nodenameW = Unicode_GetAllocUTF16(nodename); utf16_t *servnameW = Unicode_GetAllocUTF16(servname); ASSERT(nodename || servname); ASSERT(res); /* * The string conversion required is between UTF-8 and UTF-16 encodings. * Note that struct addrinfo and ADDRINFOW are identical except for the * fields ai_canonname (char * vs. PWSTR) and ai_next (obviously), * and those fields must be NULL, so hints can be cast to UTF-16. */ retval = GetAddrInfoW(nodenameW, servnameW, (struct addrinfoW *)hints, &resW); if (retval == 0) { struct addrinfoW *cur; struct addrinfo **pres = res; for (cur = resW; cur != NULL; cur = cur->ai_next) { *pres = (struct addrinfo *)Util_SafeMalloc(sizeof **pres); (*pres)->ai_flags = cur->ai_flags; (*pres)->ai_family = cur->ai_family; (*pres)->ai_socktype = cur->ai_socktype; (*pres)->ai_protocol = cur->ai_protocol; (*pres)->ai_addrlen = cur->ai_addrlen; if (cur->ai_canonname) { (*pres)->ai_canonname = Unicode_AllocWithUTF16(cur->ai_canonname); } else { (*pres)->ai_canonname = NULL; } (*pres)->ai_addr = (struct sockaddr *) Util_SafeMalloc((*pres)->ai_addrlen); memcpy((*pres)->ai_addr, cur->ai_addr, (*pres)->ai_addrlen); pres = &((*pres)->ai_next); } *pres = NULL; FreeAddrInfoW(resW); } Posix_Free(nodenameW); Posix_Free(servnameW); return retval; } /* *---------------------------------------------------------------------------- * * Posix_FreeAddrInfo -- * * Free the addrinfo structure allocated by Posix_GetAddrInfo. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static INLINE void Posix_FreeAddrInfo(struct addrinfo *ai) { struct addrinfo *temp; // See Posix_Free. int err = errno; while (ai) { temp = ai; ai = ai->ai_next; free(temp->ai_canonname); free(temp->ai_addr); free(temp); } errno = err; } /* *---------------------------------------------------------------------- * * Posix_GetNameInfo -- * * Wrapper for getnameinfo(). * * Inlined to match Ws2tcpip.h inclusion. * * Results: * 0 Success * != 0 Error * * Side effects: * On error, error code returned by WSAGetLastError() is updated. * *---------------------------------------------------------------------- */ static INLINE int Posix_GetNameInfo(const struct sockaddr *sa, // IN socklen_t salen, // IN char *host, // OUT DWORD hostlen, // IN char *serv, // OUT DWORD servlen, // IN int flags) // IN { int retval; utf16_t *hostW = NULL; utf16_t *servW = NULL; char *hostUTF8 = NULL; char *servUTF8 = NULL; if (host) { hostW = (utf16_t *)Util_SafeMalloc(hostlen * sizeof *hostW); } if (serv) { servW = (utf16_t *)Util_SafeMalloc(servlen * sizeof *servW); } retval = GetNameInfoW(sa, salen, hostW, hostlen, servW, servlen, flags); if (retval == 0) { if (host) { hostUTF8 = Unicode_AllocWithUTF16(hostW); if (!Unicode_CopyBytes(host, hostUTF8, hostlen, NULL, STRING_ENCODING_UTF8)) { retval = EAI_MEMORY; WSASetLastError(WSA_NOT_ENOUGH_MEMORY); goto exit; } } if (serv) { servUTF8 = Unicode_AllocWithUTF16(servW); if (!Unicode_CopyBytes(serv, servUTF8, servlen, NULL, STRING_ENCODING_UTF8)) { retval = EAI_MEMORY; WSASetLastError(WSA_NOT_ENOUGH_MEMORY); goto exit; } } } exit: Posix_Free(hostW); Posix_Free(servW); Posix_Free(hostUTF8); Posix_Free(servUTF8); return retval; } #endif // ifdef _WS2TCPIP_H_ #endif // !define(_WIN32) #if (defined(VMX86_SERVER) || defined(__APPLE__)) && \ !defined(UNICODE_BUILDING_POSIX_WRAPPERS) /* * ESX and Mac OS are UTF-8 environments so these functions can be * "defined away" - the POSIX wrapper call can be directly mapped to the * POSIX function avoiding unneccesary (call and handling) overhead. * * NOTE: PLEASE KEEP THESE IN SORTED ORDER */ #define Posix_Access access #define Posix_Chdir chdir #define Posix_Chmod chmod #define Posix_Chown chown #define Posix_Creat creat #define Posix_Dlopen dlopen #define Posix_Execl execl #define Posix_Execlp execlp #define Posix_Execv execv #define Posix_Execve execve #define Posix_Execvp execvp #define Posix_Fopen fopen #define Posix_Fprintf fprintf #define Posix_Freopen freopen #define Posix_Getenv getenv #define Posix_GetGroupList getgrouplist #define Posix_Getmntent getmntent #define Posix_Getmntent_r getmntent_r #define Posix_Getpwnam getpwnam #define Posix_Getpwnam_r getpwnam_r #define Posix_Getpwuid getpwuid #define Posix_Getpwuid_r getpwuid_r #define Posix_Getgrnam getgrnam #define Posix_Getgrnam_r getgrnam_r #define Posix_Lchown lchown #define Posix_Link link #define Posix_Lstat lstat #define Posix_Mkdir mkdir #define Posix_Mkfifo mkfifo #define Posix_Mknod mknod #define Posix_Mount mount #define Posix_Open open #define Posix_OpenDir opendir #define Posix_Pathconf pathconf #define Posix_Perror perror #define Posix_Popen popen #define Posix_Printf printf #define Posix_Putenv putenv #define Posix_Rename rename #define Posix_Rmdir rmdir #define Posix_Setenv setenv #define Posix_Setmntent setmntent #define Posix_Stat stat #define Posix_Statfs statfs #define Posix_Symlink symlink #define Posix_System system #define Posix_Truncate truncate #define Posix_Umount umount #define Posix_Unlink unlink #define Posix_Unsetenv unsetenv #define Posix_Utime utime #define Posix_Utimes utimes #endif #if defined(__cplusplus) } // extern "C" #endif #endif // VMWARE_POSIX_H open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/preference.h000066400000000000000000000034741470176644300250110ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _PREFERENCE_H_ #define _PREFERENCE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif void Preference_DisableUserPreferences(void); Bool Preference_Init(void); void Preference_Exit(void); Bool Preference_GetBool(Bool defaultValue, const char *fmt); int32 Preference_GetTriState(int32 defaultValue, const char *fmt); int32 Preference_GetLong(int32 defaultValue, const char *fmt); int64 Preference_GetInt64(int64 defaultvalue, const char *fmt); double Preference_GetDouble(double defaultValue, const char *fmt); char *Preference_GetString(const char *defaultValue, const char *fmt); void Preference_Log(void); char *Preference_GetPathName(const char *defaultValue, const char *fmt); void Preference_SetFromString(const char *string, Bool overwrite); Bool Preference_NotSet(const char *fmt); #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/procMgr.h000066400000000000000000000127161470176644300243030ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2002-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * procMgr.h -- * * Process management library. * */ #ifndef __PROCMGR_H__ # define __PROCMGR_H__ #include "vm_basic_types.h" #include "auth.h" #include "dynarray.h" #if !defined(_WIN32) # include #endif #include /* * Keeps track of the platform-specific handle(s) to an asynchronous process. */ typedef struct ProcMgr_AsyncProc ProcMgr_AsyncProc; #if defined(_WIN32) typedef DWORD ProcMgr_Pid; #else /* POSIX */ typedef pid_t ProcMgr_Pid; #endif /* * Process information structure. * This holds basic information we return per process * when listing process information inside the guest. */ typedef struct ProcMgrProcInfo { ProcMgr_Pid procId; char *procCmdName; // UTF-8 #if defined(__linux__) || defined(_WIN32) char *procCmdAbsPath; // UTF-8 #endif char *procCmdLine; // UTF-8 char *procOwner; // UTF-8 #if defined(_WIN32) Bool procDebugged; #endif time_t procStartTime; } ProcMgrProcInfo; DEFINE_DYNARRAY_TYPE(ProcMgrProcInfo); typedef struct ProcMgr_ProcArgs { #if defined(_WIN32) /* * If a caller needs to use a non-default set of arguments for * CreateProcess[AsUser] in ProcMgr_Exec[A]sync, this structure should be used. * * - If 'userArgs' is NULL, defaults are used: * - bInheritHandles defaults to TRUE * - lpStartupInfo is instantiated and initialized with: * - cb initialized to size of the object * - dwFlags initialized to STARTF_USESHOWWINDOW * - wShowWindow initialized to SW_MINIMIZE. * - defaults for all other parameters are NULL/FALSE * * - If 'userArgs' is not NULL, the values in the 'userArgs' object are used * according to the following rules: * - If lpStartupInfo is NULL, it is instantiated and initialized with: * - cb initialized to size of the object * - dwFlags initialized to STARTF_USESHOWWINDOW * - wShowWindow initialized to SW_MINIMIZE. * - The caller would need to do some of this initialization if they set * lpStartupInfo. * - If hToken is set: * - if lpStartupInfo->lpDesktop is not NULL, then it is used directly. Otherwise, * lpStartupInfo->lpDesktop is initialized appropriately. * * XXX: Make it more convenient for callers(like ToolsDaemonTcloRunProgramImpl) * to set just wShowWindow without needing to instantiate and initialize a * STARTUPINFO object. */ HANDLE hToken; LPCWSTR lpApplicationName; LPSECURITY_ATTRIBUTES lpProcessAttributes; LPSECURITY_ATTRIBUTES lpThreadAttributes; BOOL bInheritHandles; DWORD dwCreationFlags; LPVOID lpEnvironment; LPCWSTR lpCurrentDirectory; LPSTARTUPINFO lpStartupInfo; #else /* * The environment variables to run the program with. If NULL, use the current * environment. */ char **envp; /* * If non-NULL, the directory to be changed to before the process is * started. */ char *workingDirectory; #endif } ProcMgr_ProcArgs; typedef void ProcMgr_Callback(Bool status, void *clientData); #if defined(_WIN32) typedef HANDLE Selectable; #else typedef int Selectable; #endif ProcMgrProcInfoArray *ProcMgr_ListProcesses(void); #if defined(_WIN32) ProcMgrProcInfoArray *ProcMgr_ListProcessesEx(Bool useRemoteThreadForCmdLine, Bool useWMIForCmdLine); #endif void ProcMgr_FreeProcList(ProcMgrProcInfoArray *procList); Bool ProcMgr_KillByPid(ProcMgr_Pid procId); Bool ProcMgr_ExecSync(char const *cmd, // UTF-8 ProcMgr_ProcArgs *userArgs); ProcMgr_AsyncProc *ProcMgr_ExecAsync(char const *cmd, // UTF-8 ProcMgr_ProcArgs *userArgs); #if defined(__linux__) Bool ProcMgr_ExecSyncWithExitCode(char const *cmd, ProcMgr_ProcArgs *userArgs, Bool *validExitCode, int *exitCode); #endif void ProcMgr_Kill(ProcMgr_AsyncProc *asyncProc); Selectable ProcMgr_GetAsyncProcSelectable(ProcMgr_AsyncProc *asyncProc); ProcMgr_Pid ProcMgr_GetPid(ProcMgr_AsyncProc *asyncProc); Bool ProcMgr_IsAsyncProcRunning(ProcMgr_AsyncProc *asyncProc); int ProcMgr_GetExitCode(ProcMgr_AsyncProc *asyncProc, int *result); void ProcMgr_Free(ProcMgr_AsyncProc *asyncProc); #if !defined(_WIN32) Bool ProcMgr_ImpersonateUserStart(const char *user, // UTF-8 AuthToken token); Bool ProcMgr_ImpersonateUserStop(void); #endif Bool ProcMgr_GetImpersonatedUserInfo(char **username, char **homeDir); #endif /* __PROCMGR_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/product.h000066400000000000000000000033261470176644300243470ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2017-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * product.h -- * * This file contains the Product enum. * * Products that don't want to include productState and vm_basic_types.h * and want to know about the magic values for various products should * include this file. */ #ifndef _PRODUCT_H_ #define _PRODUCT_H_ #if defined(__cplusplus) extern "C" { #endif /* * Public types. */ typedef enum { PRODUCT_GENERIC = 0, PRODUCT_WORKSTATION = 1 << 0, PRODUCT_ESX = 1 << 1, PRODUCT_PLAYER = 1 << 2, PRODUCT_TOOLS = 1 << 3, PRODUCT_VDM_CLIENT = 1 << 4, PRODUCT_CVP = 1 << 5, PRODUCT_FUSION = 1 << 6, PRODUCT_VIEW = 1 << 7, PRODUCT_VMRC = 1 << 8, PRODUCT_VMACORETESTS = 1 << 9, PRODUCT_SRM = 1 << 10, /* etc */ } Product; #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/productState.h000066400000000000000000000100731470176644300253450ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * productState.h -- * * ProductState is a runtime encapsulation of the identity of a product * and product dependent characteristics. */ #ifndef _PRODUCT_STATE_H_ #define _PRODUCT_STATE_H_ #include "vm_basic_types.h" #include "product.h" #if defined(__cplusplus) extern "C" { #endif typedef uint64 ProductMask; #define PRODUCTMASK_HOSTED (PRODUCT_WORKSTATION |\ PRODUCT_PLAYER |\ PRODUCT_CVP |\ PRODUCT_FUSION |\ PRODUCT_VMRC) typedef uint64 ProductCaps; /* * Define as needed. * * #define PRODUCT_CAP_FOO (1 << 0) */ typedef enum { PRODUCTSTATE_FLAG_NONE = 0, PRODUCTSTATE_FLAG_PRODUCT = 1 << 0, PRODUCTSTATE_FLAG_NAME = 1 << 1, PRODUCTSTATE_FLAG_VERSION = 1 << 2, PRODUCTSTATE_FLAG_BUILDNUMBER = 1 << 3, PRODUCTSTATE_FLAG_CAPABILITIES = 1 << 4, PRODUCTSTATE_FLAG_LICENSENAME = 1 << 5, PRODUCTSTATE_FLAG_LICENSEVERSION = 1 << 6, PRODUCTSTATE_FLAG_BUNDLEIDENTIFIER = 1 << 7, } ProductStateSerializationFlags; /* * Public functions. * * PR 567850 * ProductState_Set should only be called once. Subsequent calls will be * ignored. */ void ProductState_Set(Product product, const char *name, const char *version, unsigned int buildNumber, ProductCaps capabilities, const char *licenseName, const char *licenseVersion, const char *bundleIdentifier); void ProductState_SetProduct(uint64 product); void ProductState_SetName(const char *name); void ProductState_SetLicenseName(const char *licenseName); unsigned int ProductState_GetBuildNumber(void); const char *ProductState_GetBuildNumberString(void); const char *ProductState_GetBundleIdentifier(void); ProductCaps ProductState_GetCapabilities(void); const char *ProductState_GetCompilationOption(void); const char *ProductState_GetConfigName(void); const char *ProductState_GetFullVersion(void); void ProductState_GetHelp(Product *helpProduct, const char **helpVersion); const char *ProductState_GetLicenseName(void); const char *ProductState_GetLicenseVersion(void); const char *ProductState_GetName(void); Product ProductState_GetProduct(void); const char *ProductState_GetRegistryPath(void); char *ProductState_GetRegistryPathForProduct(const char *productName); const char *ProductState_GetVersion(void); void ProductState_GetVersionNumber(unsigned int *major, unsigned int *minor, unsigned int *patchLevel); Bool ProductState_IsProduct(ProductMask product); Bool ProductState_AllowUnlicensedVMX(void); void ProductState_SetConfigName(const char *configName); /* etc */ void ProductState_SetHelp(Product helpProduct, const char *helpVersion); char *ProductState_Serialize(ProductStateSerializationFlags flags); ProductStateSerializationFlags ProductState_Deserialize(const char *state); #if defined(__cplusplus) } // extern "C" #endif #endif /* _PRODUCT_STATE_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/random.h000066400000000000000000000065651470176644300241570ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * random.h -- * * Random bits generation. Please use CryptoRandom_GetBytes if * you require a FIPS-compliant source of random data. */ #ifndef __RANDOM_H__ # define __RANDOM_H__ #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif /* * OS-native random number generator based on one-way hashes. * * Good enough for any non-cryptographic use, but slower than * alternative algorithms. Recommended for generating seeds. * * Period: infinite * Speed: slow */ Bool Random_Crypto(size_t size, void *buffer); /* * The next call to Random_Crypto will fail after this function is called. * This function does nothing in a release build. */ void Random_CryptoFail(void); /* * Research grade Mersenne Twister random number generator. * * Period: 2^800 * Speed: ~23 cycles */ typedef struct rqContext rqContext; rqContext *Random_QuickSeed(uint32 seed); uint32 Random_Quick(rqContext *context); /* * Good quality non-deterministic random number generator. * * This generator uses &(*state) as the seed to go beyond 64-bits without * additional storage space; the low-grade entropy makes seeding * non-deterministic. Multiple generators in the same address space * with the same seed will produce unique streams, but using the same * seed will NOT produce the same sequence (due to ASLR). See * Raondom_FastStream for a deterministic generator. * * Initialize by setting *state to any seed (including zero) and calling * Random_Fast TWICE. (Unless the seed is very good, the first two values * are not very random). * * Period: 2^64 * Speed: ~10 cycles */ uint32 Random_Fast(uint64 *state); uint64 Random_Fast64(uint64 *state); static INLINE void Random_FastSeed(uint64 *state, // OUT: uint64 seed) // IN: { *state = seed; (void) Random_Fast(state); (void) Random_Fast(state); } /* * Good quality deterministic random number generator. * * Period: 2^64 * Speed: ~10 cycles */ typedef struct { uint64 state; uint64 sequence; } RandomFastContext; uint32 Random_FastStream(RandomFastContext *rfc); uint64 Random_FastStream64(RandomFastContext *rfc); void Random_FastStreamSeed(RandomFastContext *rfc, uint64 seed, uint64 seq); /* * Simple multiplicative congruential RNG. * * Deprecated; prefer Random_Fast for better quality. * Period: 2^31-1 * Speed: ~9 cycles */ int Random_Simple(int seed); #if defined(__cplusplus) } // extern "C" #endif #endif /* __RANDOM_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/removable_device.h000066400000000000000000000022171470176644300261600ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _REMOVABLE_DEVICE_H_ #define _REMOVABLE_DEVICE_H_ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #define REMOVABLE_DEVICE_PRETTY_NAME_LENGTH 32 typedef struct { char name[REMOVABLE_DEVICE_PRETTY_NAME_LENGTH]; uint32 uid; Bool enabled; } RD_Info; #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/rpcin.h000066400000000000000000000056731470176644300240110ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * rpcin.h -- * * Remote Procedure Call between VMware and guest applications * C declarations */ #ifndef __RPCIN_H__ # define __RPCIN_H__ #ifdef __cplusplus extern "C" { #endif typedef void RpcIn_ErrorFunc(void *clientData, char const *status); typedef void RpcIn_ClearErrorFunc(void *clientData); typedef struct RpcIn RpcIn; #if defined(VMTOOLS_USE_GLIB) /* { */ #include "vmware/tools/guestrpc.h" RpcIn *RpcIn_Construct(GMainContext *mainCtx, RpcIn_Callback dispatch, gpointer clientData); Bool RpcIn_start(RpcIn *in, unsigned int delay, RpcIn_ErrorFunc *errorFunc, RpcIn_ClearErrorFunc *clearErrorFunc, void *errorData); #else /* } { */ #include "dbllnklst.h" /* * Type for old RpcIn callbacks. Don't use this anymore - this is here * for backwards compatibility. */ typedef Bool (*RpcIn_Callback)(char const **result, // OUT size_t *resultLen, // OUT const char *name, // IN const char *args, // IN size_t argsSize, // IN void *clientData); // IN RpcIn *RpcIn_Construct(DblLnkLst_Links *eventQueue); Bool RpcIn_start(RpcIn *in, unsigned int delay, RpcIn_Callback resetCallback, void *resetClientData, RpcIn_ErrorFunc *errorFunc, RpcIn_ClearErrorFunc *clearErrorFunc, void *errorData); /* * Don't use this function anymore - it's here only for backwards compatibility. * Use RpcIn_RegisterCallbackEx() instead. */ void RpcIn_RegisterCallback(RpcIn *in, const char *name, RpcIn_Callback callback, void *clientData); void RpcIn_UnregisterCallback(RpcIn *in, const char *name); unsigned int RpcIn_SetRetVals(char const **result, size_t *resultLen, const char *resultVal, Bool retVal); #endif /* } */ void RpcIn_Destruct(RpcIn *in); void RpcIn_stop(RpcIn *in); #ifdef __cplusplus } // extern "C" #endif #endif /* __RPCIN_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/rpcout.h000066400000000000000000000055521470176644300242060ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2016,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * rpcout.h -- * * Remote Procedure Call between VMware and guest applications * C declarations */ #ifndef __RPCOUT_H__ # define __RPCOUT_H__ #include "vm_basic_types.h" #define RPCI_PROTOCOL_NUM 0x49435052 /* 'RPCI' ;-) */ typedef struct RpcOut RpcOut; RpcOut *RpcOut_Construct(void); void RpcOut_Destruct(RpcOut *out); Bool RpcOut_start(RpcOut *out); Bool RpcOut_send(RpcOut *out, char const *request, size_t reqLen, Bool *rpcStatus, char const **reply, size_t *repLen); Bool RpcOut_stop(RpcOut *out); /* * This is the only method needed to send a message to vmware for * 99% of uses. I'm leaving the others defined here so people know * they can be exported again if the need arises. [greg] */ Bool RpcOut_sendOne(char **reply, size_t *repLen, char const *reqFmt, ...); /* * A version of the RpcOut_sendOne function that works with UTF-8 * strings and other data that would be corrupted by Win32's * FormatMessage function (which is used by RpcOut_sendOne()). */ Bool RpcOut_SendOneRaw(void *request, size_t reqLen, char **reply, size_t *repLen); /* * A variant of the RpcOut_SendOneRaw in which the caller supplies the * receive buffer so as to avoid the need to call malloc internally. * Useful in situations where calling malloc is not allowed. */ Bool RpcOut_SendOneRawPreallocated(void *request, size_t reqLen, char *reply, size_t repLen); #endif /* __RPCOUT_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/rpcvmx.h000066400000000000000000000050111470176644300241770ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * rpcvmx.h -- * * Simple utility library (usable by guest drivers as well as userlevel * Tools code) that provides some useful VMX interaction capability, e.g. * logging to the VM's VMX log, querying config variables, etc. * * NB: This library is *NOT* threadsafe, so if you want to avoid * corrupting your log statements or other screwups, add your own * locking around calls to RpcVMX_Log. */ #ifndef _RPCVMX_H_ #define _RPCVMX_H_ #include #include "vm_basic_types.h" #include "rpcvmxext.h" #define RPCVMX_MAX_LOG_LEN (2048) /* 2kb max - make it dynamic? */ /* * Set a prefix to prepend to any future log statements. */ void RpcVMX_LogSetPrefix(const char *prefix); /* * Get the currently set prefix (returns empty string if no prefix set) */ const char *RpcVMX_LogGetPrefix(const char *prefix); /* * Save as RpcVMX_Log but takes a va_list instead of inline arguments. */ void RpcVMX_LogV(const char *fmt, va_list args); /* * Get the value of "guestinfo.$key" in the host VMX dictionary and return it. * Returns the default if the key is not set. */ char *RpcVMX_ConfigGetString(const char *defval, const char *key); /* * Same as _ConfigGetString, but convert the value to a 32-bit quantity. * XXX Returns 0, *NOT* the default, if the key was set but the value could * not be converted to an int32. */ int32 RpcVMX_ConfigGetLong(int32 defval, const char *key); /* * Same as _ConfigGetString, but convert the value to a Bool. Returns the * default value if the key was set but could not be converted. */ Bool RpcVMX_ConfigGetBool(Bool defval, const char *key); #endif /* _VMXRPC_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/rpcvmxext.h000066400000000000000000000034501470176644300247250ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * rpcvmxext.h -- * * Extension of the utility library (usable by guest drivers as well as userlevel * Tools code) that provides some useful VMX interaction capability, e.g. * logging to the VM's VMX log, querying config variables, etc. * * NB: This library is *NOT* threadsafe, so if you want to avoid * corrupting your log statements or other screwups, add your own * locking around calls to RpcVMX_Log. */ #ifndef _RPCVMXEXT_H_ #define _RPCVMXEXT_H_ #include "vm_basic_types.h" /* * Format the provided string with the provided arguments, and post it to the * VMX logfile via RPC. */ void RpcVMX_Log(const char *fmt, ...) PRINTF_DECL(1, 2); /* * Report driver name and driver version to vmx to store the key-value in * GuestVars, and write a log in vmware.log using RpcVMX_Log. */ void RpcVMX_ReportDriverVersion(const char *drivername, const char *versionString); #endif /* _RPCVMXEXT_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/sha1.h000066400000000000000000000100731470176644300235200ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * sha1.h -- * * SHA1 encryption */ #ifndef _SHA1_H_ #define _SHA1_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" /* for uint32 */ #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif #if defined __APPLE__ && defined USERLEVEL /* * Apple provides basic crypto functions in its system runtime that are * maintained for both speed and security. Use those instead. */ #include #define SHA1_HASH_LEN CC_SHA1_DIGEST_LENGTH #define SHA1_CTX CC_SHA1_CTX #define SHA1Init CC_SHA1_Init #define SHA1Update CC_SHA1_Update #define SHA1Final CC_SHA1_Final #else /* * Prevent linkage conflicts with the SHA1 APIs brought in from * OpenSSL. (Pro tip: If you're doing anything security-related, you * _must_ be using lib/crypto hash routines to preserve FIPS * compatibility.) */ #define SHA1Init VMW_SHA1Init #define SHA1Update VMW_SHA1Update #define SHA1Final VMW_SHA1Final /* SHA-1 in C By Steve Reid 100% Public Domain Test Vectors (from FIPS PUB 180-1) "abc" A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 A million repetitions of "a" 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ /* 12/15/98: JEB: Removed main and moved prototypes to sha1.h Made SHA1Transform a static function */ #define SHA1_HASH_LEN 20 typedef struct SHA1_CTX { uint32 state[5]; uint32 count[2]; unsigned char buffer[64]; } SHA1_CTX; void SHA1Init(SHA1_CTX* context); void SHA1Update(SHA1_CTX* context, const unsigned char *data, size_t len); void SHA1Final(unsigned char digest[SHA1_HASH_LEN], SHA1_CTX* context); #endif // defined __APPLE__ && defined USERLEVEL /* Opaque handle */ typedef union { #if defined __APPLE__ uint8 _private[104 + 8]; // sizeof CC_SHA256_CTX + extra field, // where SHA256 is largest CTX #elif defined _WIN32 uint8 _private[384]; // see CryptoHashInitCommon #else uintptr_t _private; #endif } CryptoHash_SHA1_CTX; void CryptoHash_InitSHA1(CryptoHash_SHA1_CTX *ctx); void CryptoHash_UpdateSHA1(CryptoHash_SHA1_CTX *ctx, const void *data, size_t len); void CryptoHash_FinalSHA1(CryptoHash_SHA1_CTX *ctx, unsigned char digest[SHA1_HASH_LEN]); void CryptoHash_ComputeSHA1(const void *data, size_t len, unsigned char digest[SHA1_HASH_LEN]); #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _SHA1_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/sigPosixRegs.h000066400000000000000000000344511470176644300253200ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2017,2020-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * sigPosixRegs.h -- * * Platform-specific definitions for saved CPU registers inside * ucontext_t. These aren't part of sigPosix.h since few source * files need them, and this header is a bit invasive, and it must * be defined before system headers. */ #ifndef _SIGPOSIXREGS_H_ #define _SIGPOSIXREGS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #if defined(__cplusplus) extern "C" { #endif #if __linux__ // We need the REG_foo offsets in the gregset_t; # define _GNU_SOURCE // _GNU_SOURCE maps to __USE_GNU /* And, the REG_foo definitions conflict with our own in x86/regname_arch.h */ # if defined(__x86_64__) # define REG_RAX GNU_REG_RAX # define REG_RBX GNU_REG_RBX # define REG_RCX GNU_REG_RCX # define REG_RDX GNU_REG_RDX # define REG_RSI GNU_REG_RSI # define REG_RDI GNU_REG_RDI # define REG_RSP GNU_REG_RSP # define REG_RBP GNU_REG_RBP # define REG_RIP GNU_REG_RIP # define REG_R8 GNU_REG_R8 # define REG_R9 GNU_REG_R9 # define REG_R10 GNU_REG_R10 # define REG_R11 GNU_REG_R11 # define REG_R12 GNU_REG_R12 # define REG_R13 GNU_REG_R13 # define REG_R14 GNU_REG_R14 # define REG_R15 GNU_REG_R15 # elif defined(__i386__) # define REG_EAX GNU_REG_EAX # define REG_EBX GNU_REG_EBX # define REG_ECX GNU_REG_ECX # define REG_EDX GNU_REG_EDX # define REG_ESI GNU_REG_ESI # define REG_EDI GNU_REG_EDI # define REG_ESP GNU_REG_ESP # define REG_EBP GNU_REG_EBP # define REG_EIP GNU_REG_EIP # endif #endif #include #include #if __linux__ && !defined __ANDROID__ # if defined(__x86_64__) # undef REG_RAX # undef REG_RBX # undef REG_RCX # undef REG_RDX # undef REG_RSI # undef REG_RDI # undef REG_RSP # undef REG_RBP # undef REG_RIP # undef REG_R8 # undef REG_R9 # undef REG_R10 # undef REG_R11 # undef REG_R12 # undef REG_R13 # undef REG_R14 # undef REG_R15 # elif defined(__i386__) # undef REG_EAX # undef REG_EBX # undef REG_ECX # undef REG_EDX # undef REG_ESI # undef REG_EDI # undef REG_ESP # undef REG_EBP # undef REG_EIP # endif #endif #if defined(__APPLE__) #if __DARWIN_UNIX03 #ifdef __x86_64__ #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rax) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rbx) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rcx) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rdx) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rdi) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rsi) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rbp) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rsp) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__rip) #define SC_R8(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r8) #define SC_R9(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r9) #define SC_R10(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r10) #define SC_R11(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r11) #define SC_R12(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r12) #define SC_R13(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r13) #define SC_R14(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r14) #define SC_R15(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r15) #elif defined(__arm__) #define SC_R0(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[0]) #define SC_R1(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[1]) #define SC_R2(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[2]) #define SC_R3(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[3]) #define SC_R4(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[4]) #define SC_R5(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[5]) #define SC_R6(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[6]) #define SC_R7(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[7]) #define SC_R8(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[8]) #define SC_R9(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[9]) #define SC_R10(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[10]) #define SC_FP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[11]) #define SC_IP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__r[12]) #define SC_SP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__sp) #define SC_LR(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__lr) #define SC_PC(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__pc) #elif defined(__aarch64__) #define SC_X(uc,n) ((unsigned long) (uc)->uc_mcontext->__ss.__x[n]) #define SC_FP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__x[29]) #define SC_SP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__sp) #define SC_PC(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__pc) #define SC_PSR(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__cpsr) #else #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__eax) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__ebx) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__ecx) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__edx) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__edi) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__esi) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__ebp) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__esp) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext->__ss.__eip) #endif #else #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext->ss.eax) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext->ss.ebx) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext->ss.ecx) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext->ss.edx) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext->ss.edi) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext->ss.esi) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext->ss.ebp) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext->ss.esp) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext->ss.eip) #endif #elif defined(__FreeBSD__) #ifdef __x86_64__ #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext.mc_rax) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext.mc_rbx) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext.mc_rcx) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext.mc_rdx) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext.mc_rdi) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext.mc_rsi) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext.mc_rbp) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext.mc_rsp) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext.mc_rip) #define SC_R8(uc) ((unsigned long) (uc)->uc_mcontext.mc_r8) #define SC_R9(uc) ((unsigned long) (uc)->uc_mcontext.mc_r9) #define SC_R10(uc) ((unsigned long) (uc)->uc_mcontext.mc_r10) #define SC_R11(uc) ((unsigned long) (uc)->uc_mcontext.mc_r11) #define SC_R12(uc) ((unsigned long) (uc)->uc_mcontext.mc_r12) #define SC_R13(uc) ((unsigned long) (uc)->uc_mcontext.mc_r13) #define SC_R14(uc) ((unsigned long) (uc)->uc_mcontext.mc_r14) #define SC_R15(uc) ((unsigned long) (uc)->uc_mcontext.mc_r15) #elif defined(__aarch64__) #define SC_X(uc,n) ((unsigned long) (uc)->uc_mcontext.mc_gpregs.gp_x[n]) #else #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext.mc_eax) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext.mc_ebx) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext.mc_ecx) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext.mc_edx) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext.mc_edi) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext.mc_esi) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext.mc_ebp) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext.mc_esp) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext.mc_eip) #endif #elif defined (sun) #ifdef __x86_64__ #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RAX]) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RBX]) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RCX]) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RDX]) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RDI]) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RSI]) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RBP]) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RSP]) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_RIP]) #define SC_R8(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_R8]) #define SC_R9(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_R9]) #define SC_R10(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_R10]) #define SC_R11(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_R11]) #define SC_R12(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_R12]) #define SC_R13(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_R13]) #define SC_R14(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_R14]) #define SC_R15(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_R15]) #else #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[EAX]) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[EBX]) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[ECX]) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[EDX]) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[EDI]) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[ESI]) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[EBP]) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[ESP]) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[EIP]) #endif #elif defined(ANDROID_X86) #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_EAX]) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_EBX]) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_ECX]) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_EDX]) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_EDI]) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_ESI]) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_EBP]) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_ESP]) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[REG_EIP]) #else #ifdef __x86_64__ #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RAX]) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RBX]) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RCX]) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RDX]) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RDI]) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RSI]) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RBP]) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RSP]) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_RIP]) #define SC_R8(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_R8]) #define SC_R9(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_R9]) #define SC_R10(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_R10]) #define SC_R11(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_R11]) #define SC_R12(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_R12]) #define SC_R13(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_R13]) #define SC_R14(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_R14]) #define SC_R15(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_R15]) #elif defined(__arm__) #define SC_R0(uc) ((unsigned long) (uc)->uc_mcontext.arm_r0) #define SC_R1(uc) ((unsigned long) (uc)->uc_mcontext.arm_r1) #define SC_R2(uc) ((unsigned long) (uc)->uc_mcontext.arm_r2) #define SC_R3(uc) ((unsigned long) (uc)->uc_mcontext.arm_r3) #define SC_R4(uc) ((unsigned long) (uc)->uc_mcontext.arm_r4) #define SC_R5(uc) ((unsigned long) (uc)->uc_mcontext.arm_r5) #define SC_R6(uc) ((unsigned long) (uc)->uc_mcontext.arm_r6) #define SC_R7(uc) ((unsigned long) (uc)->uc_mcontext.arm_r7) #define SC_R8(uc) ((unsigned long) (uc)->uc_mcontext.arm_r8) #define SC_R9(uc) ((unsigned long) (uc)->uc_mcontext.arm_r9) #define SC_R10(uc) ((unsigned long) (uc)->uc_mcontext.arm_r10) #define SC_FP(uc) ((unsigned long) (uc)->uc_mcontext.arm_fp) #define SC_IP(uc) ((unsigned long) (uc)->uc_mcontext.arm_ip) #define SC_SP(uc) ((unsigned long) (uc)->uc_mcontext.arm_sp) #define SC_LR(uc) ((unsigned long) (uc)->uc_mcontext.arm_lr) #define SC_PC(uc) ((unsigned long) (uc)->uc_mcontext.arm_pc) #elif defined(__aarch64__) #define SC_X(uc,n) ((unsigned long) (uc)->uc_mcontext.regs[n]) #define SC_FP(uc) ((unsigned long) (uc)->uc_mcontext.regs[29]) #define SC_SP(uc) ((unsigned long) (uc)->uc_mcontext.sp) #define SC_PC(uc) ((unsigned long) (uc)->uc_mcontext.pc) #define SC_PSR(uc) ((unsigned long) (uc)->uc_mcontext.pstate) #else #define SC_EAX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_EAX]) #define SC_EBX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_EBX]) #define SC_ECX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_ECX]) #define SC_EDX(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_EDX]) #define SC_EDI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_EDI]) #define SC_ESI(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_ESI]) #define SC_EBP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_EBP]) #define SC_ESP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_ESP]) #define SC_EIP(uc) ((unsigned long) (uc)->uc_mcontext.gregs[GNU_REG_EIP]) #endif #endif #if defined(__cplusplus) } // extern "C" #endif #endif // ifndef _SIGPOSIXREGS_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/sigc++2to3.h000066400000000000000000000147671470176644300244650ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * sigc++2to3.h -- * * A header file that contain definations that will allow some sigc++2 APIs * to work when builing with sigc++3. */ #pragma once #include #include #include #if SIGCXX_MAJOR_VERSION >= 3 namespace sigc { // Bridge slot syntax change template class slot : public slot { private: using _true_slot = slot; public: inline slot() = default; inline slot(const _true_slot& src) : _true_slot(src) {} template inline slot(const T_functor& func) : _true_slot(func) {} }; template using slot0 = slot; template using slot1 = slot; template using slot2 = slot; template using slot3 = slot; template using slot4 = slot; template using slot5 = slot; template using slot6 = slot; template using slot7 = slot; // Bridge signal syntax change template class signal : public signal, public trackable { public: signal() = default; decltype(auto) make_slot() const { return mem_fun(*this, &signal::emit); } }; template using signal0 = signal; template using signal1 = signal; template using signal2 = signal; template using signal3 = signal; template using signal4 = signal; template using signal5 = signal; template using signal6 = signal; template using signal7 = signal; //Bridge bound_mem_functor template using bound_mem_functor0 = bound_mem_functor; template using bound_mem_functor1 = bound_mem_functor; template using bound_mem_functor2 = bound_mem_functor; template using bound_mem_functor3 = bound_mem_functor; template using bound_mem_functor4 = bound_mem_functor; template using bound_mem_functor5 = bound_mem_functor; template using bound_mem_functor6 = bound_mem_functor; template using bound_mem_functor7 = bound_mem_functor; // Add old mem_fun API for pointer template inline decltype(auto) mem_fun(T_obj *obj, T_return (T_obj::*func)(T_arg...)) { return bound_mem_functor(*obj, func); } template inline decltype(auto) mem_fun(const T_obj *obj, T_return (T_obj::*func)(T_arg...) const) { return bound_mem_functor(*obj, func); } // Stub sigc::ref impl template inline decltype(auto) ref(T& t) { return std::ref(t); } template inline decltype(auto) ref(const T& t) { return std::cref(t); } } //namespace sigc #endif // SIGCXX_MAJOR_VERSION >= 3 open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/slashProc.h000066400000000000000000000026041470176644300246230ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2009-2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /** * @file slashProc.h */ #ifndef _SLASHPROC_H_ #define _SLASHPROC_H_ #include #include /* * Global functions */ EXTERN GHashTable *SlashProcNet_GetSnmp(void); EXTERN GHashTable *SlashProcNet_GetSnmp6(void); EXTERN GPtrArray *SlashProcNet_GetRoute(unsigned int, unsigned short); EXTERN void SlashProcNet_FreeRoute(GPtrArray *); EXTERN GPtrArray *SlashProcNet_GetRoute6(unsigned int, unsigned int); EXTERN void SlashProcNet_FreeRoute6(GPtrArray *); #endif // ifndef _SLASHPROC_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/sslDirect.h000066400000000000000000000044351470176644300246250ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2014-2016,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * sslDirect.h -- * * declarations in ssl.h that are required by AsyncSocket. * */ #ifndef _SSLDIRECT_H_ #define _SSLDIRECT_H_ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" typedef struct _SSLVerifyParam SSLVerifyParam; typedef struct SSLSockStruct *SSLSock; typedef char* (SSLLibFn)(const char*, const char*); void SSL_Init(SSLLibFn *getLibFn, const char *defaultLib, const char *name); SSLSock SSL_New(int fd,Bool closeFdOnShutdown); void SSL_SetCloseOnShutdownFlag(SSLSock ssl); Bool SSL_SetupAcceptWithContext(SSLSock sSock, void *ctx); int SSL_TryCompleteAccept(SSLSock sSock); ssize_t SSL_Read(SSLSock ssl, char *buf, size_t num); ssize_t SSL_RecvDataAndFd(SSLSock ssl, char *buf, size_t num, int *fd); ssize_t SSL_Write(SSLSock ssl, const char *buf, size_t num); int SSL_Shutdown(SSLSock ssl); int SSL_GetFd(SSLSock sSock); int SSL_Pending(SSLSock ssl); int SSL_WantRead(const SSLSock ssl); #ifdef _WIN32 #define SSLGeneric_read(sock,buf,num) recv(sock,buf,num,0) #define SSLGeneric_write(sock,buf,num) send(sock,buf,num,0) #define SSLGeneric_recvmsg(sock,msg,flags) recvmsg(sock,msg,flags) #define SSLGeneric_close(sock) closesocket(sock) #else #define SSLGeneric_read(sock,buf,num) read(sock, buf, num) #define SSLGeneric_write(sock,buf,num) write(sock, buf,num) #define SSLGeneric_recvmsg(sock,msg,flags) recvmsg(sock,msg,flags) #define SSLGeneric_close(sock) close(sock) #endif #endif // ifndef _SSLDIRECT_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/str.h000066400000000000000000000215201470176644300234730ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2020,2022-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * str.h -- * * string wrapping functions */ #ifndef _STR_H_ #define _STR_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #if defined(__linux__) #include #elif defined(_WIN32) #include #elif __APPLE__ #include #endif #include "compat/compat_stdarg.h" // Provides stdarg.h plus va_copy #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif /* * These platforms use bsd_vsnprintf(). * * XXX: open-vm-tools does not use bsd_vsnprintf because bsd_vsnprintf uses * convertutf.{h,c}, and the license for those files does not meet the * redistribution requirements for Debian. * */ #if !defined(VMX86_TOOLS) || defined(_WIN32) #if (defined _WIN32 && !defined STR_NO_WIN32_LIBS) || \ (defined __linux__ && !defined __UCLIBC__ && !defined __ANDROID__) || \ defined __APPLE__ || defined __EMSCRIPTEN__ #define HAS_BSD_PRINTF 1 #endif #endif /* * ASCII/UTF-8 versions * * NOTE: All size_t arguments and integer returns values are in bytes. * * NOTE: Str_Asprintf/Str_Vasprintf return NULL on failure, while * Str_SafeAsprintf/Str_SafeVasprintf VERIFY. * * NOTE: "%s" refers to strings of "char" units, while "%S" refers to * strings of "wchar_t" units, regardless of platform. */ #ifdef HAS_BSD_PRINTF int Str_Sprintf_C_Locale(char *buf, // OUT: size_t max, // IN: const char *fmt, // IN: ...) PRINTF_DECL(3, 4); // IN: #endif int Str_Sprintf(char *buf, // OUT: size_t max, // IN: const char *fmt, // IN: ...) PRINTF_DECL(3, 4); // IN: int Str_Snprintf(char *buf, // OUT: size_t len, // IN: const char *fmt, // IN: ...) PRINTF_DECL(3, 4); // IN: int Str_Vsnprintf(char *buf, // OUT: size_t len, // IN: const char *fmt, // IN: va_list args); // IN: size_t Str_Strlen(const char *src, // IN: size_t maxLen); // IN: char *Str_Strnstr(const char *src, // IN: const char *sub, // IN: size_t n); // IN: char *Str_Strcpy(char *dst, // OUT: const char *src, // IN: size_t maxLen); // IN: char *Str_Strncpy(char *dest, // OUT: size_t destSize, // IN: const char *src, // IN: size_t n); // IN: char *Str_Strcat(char *dst, // IN/OUT: const char *src, // IN: size_t maxLen); // IN: char *Str_Strncat(char *buf, // IN/OUT: size_t bufSize, // IN: const char *src, // IN: size_t n); // IN: char *Str_Asprintf(size_t *length, // OUT/OPT: const char *format, // IN: ...) PRINTF_DECL(2, 3); // IN: char *Str_Vasprintf(size_t *length, // OUT/OPT: const char *format, // IN: va_list arguments); // IN: char *Str_SafeAsprintf(size_t *length, // OUT/OPT: const char *format, // IN: ...) PRINTF_DECL(2, 3); // IN: char *Str_SafeVasprintf(size_t *length, // OUT/OPT: const char *format, // IN: va_list arguments); // IN: #if defined(_WIN32) // { /* * wchar_t versions * * NOTE: All size_t arguments and integer return values are in * wchar_ts, not bytes. * * NOTE: Str_Aswprintf/Str_Vaswprintf return NULL on failure, while * Str_SafeAswprintf/Str_SafeVaswprintf VERIFY. * * NOTE: "%s" refers to strings of "char" units, while "%S" refers to * strings of "wchar_t" units, regardless of platform. */ int Str_Swprintf(wchar_t *buf, // OUT: size_t max, // IN: const wchar_t *fmt, // IN: ...); int Str_Snwprintf(wchar_t *buf, // OUT: size_t len, // IN: const wchar_t *fmt, // IN: ...); int Str_Vsnwprintf(wchar_t *buf, // OUT: size_t len, // IN: const wchar_t *fmt, // IN: va_list args); wchar_t *Str_Wcscpy(wchar_t *dst, // OUT: const wchar_t *src, // IN: size_t maxLen); // IN: wchar_t *Str_Wcscat(wchar_t *dst, // IN/OUT: const wchar_t *src, // IN: size_t maxLen); // IN: wchar_t *Str_Wcsncat(wchar_t *buf, // IN/OUT: size_t bufSize, // IN: const wchar_t *src, // IN: size_t n); // IN: wchar_t *Str_Aswprintf(size_t *length, // OUT/OPT: const wchar_t *format, // IN: ...); // IN: wchar_t *Str_Vaswprintf(size_t *length, // OUT/OPT: const wchar_t *format, // IN: va_list arguments); // IN: wchar_t *Str_SafeAswprintf(size_t *length, // OUT/OPT: const wchar_t *format, // IN: ...); // IN: wchar_t *Str_SafeVaswprintf(size_t *length, // OUT/OPT: const wchar_t *format, // IN: va_list arguments); // IN: /* * These are handly for Windows programmers. They are like * the _tcs functions, but with Str_Strcpy-style bounds checking. */ #ifdef UNICODE #define Str_Tcscpy(s1, s2, n) Str_Wcscpy(s1, s2, n) #define Str_Tcscat(s1, s2, n) Str_Wcscat(s1, s2, n) #else #define Str_Tcscpy(s1, s2, n) Str_Strcpy(s1, s2, n) #define Str_Tcscat(s1, s2, n) Str_Strcat(s1, s2, n) #endif #endif // } defined(_WIN32) /* * Wrappers for standard string functions * * These are either for Windows-Posix compatibility, * or just gratuitous wrapping for consistency. */ #define Str_Strcmp(s1, s2) strcmp(s1, s2) #define Str_Strncmp(s1, s2, n) strncmp(s1, s2, n) #define Str_Strequal(s1,s2) (0 == (Str_Strcmp(s1, s2))) #define Str_Strchr(s, c) strchr(s, c) #define Str_Strrchr(s, c) strrchr(s, c) #define Str_Strspn(s1, s2) strspn(s1, s2) #define Str_Strcspn(s1, s2) strcspn(s1, s2) #if defined(_WIN32) #define Str_Strcasecmp(s1, s2) _stricmp(s1, s2) #define Str_Strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) #define Str_ToUpper(s) _strupr(s) #define Str_ToLower(s) _strlwr(s) #else #define Str_Strcasecmp(s1, s2) strcasecmp(s1, s2) #define Str_Strncasecmp(s1, s2, n) strncasecmp(s1, s2, n) char *Str_ToUpper(char *string); char *Str_ToLower(char *string); #endif #ifdef _WIN32 #define Str_Tcscmp(s1, s2) _tcscmp(s1, s2) #define Str_Tcsncmp(s1, s2, n) _tcsncmp(s1, s2, n) #define Str_Tcsicmp(s1, s2) _tcsicmp(s1, s2) #define Str_Tcsnicmp(s1, s2, n) _tcsnicmp(s1, s2, n) #define Str_Tcschr(s, c) _tcschr(s, c) #define Str_Tcsrchr(s, c) _tcsrchr(s, c) #define Str_Tcsspn(s1, s2) _tcsspn(s1, s2) #define Str_Tcscspn(s1, s2) _tcscspn(s1, s2) #define Str_Tcsupr(s) _tcsupr(s) #define Str_Tcslwr(s) _tcslwr(s) #endif #if defined(__cplusplus) } // extern "C" #endif #endif /* _STR_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/strutil.h000066400000000000000000000100131470176644300243640ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2018, 2021-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * strutil.h -- * * String utility functions. */ #ifndef STRUTIL_H #define STRUTIL_H #include #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif struct DynBuf; char *StrUtil_GetNextToken(unsigned int *index, const char *str, const char *delimiters); #if defined(_WIN32) wchar_t *StrUtil_GetNextTokenW(unsigned int *index, const wchar_t *str, const wchar_t *delimiters); #endif Bool StrUtil_GetNextIntToken(int32 *out, unsigned int *index, const char *str, const char *delimiters); Bool StrUtil_GetNextUintToken(uint32 *out, unsigned int *index, const char *str, const char *delimiters); Bool StrUtil_GetNextInt64Token(int64 *out, unsigned int *index, const char *str, const char *delimiters); Bool StrUtil_DecimalStrToUint(unsigned int *out, const char **str); Bool StrUtil_StrToInt(int32 *out, const char *str); Bool StrUtil_StrToUint(uint32 *out, const char *str); Bool StrUtil_StrToInt64(int64 *out, const char *str); Bool StrUtil_StrToUint64(uint64 *out, const char *str); Bool StrUtil_StrToSizet(size_t *out, const char *str); Bool StrUtil_StrToDouble(double *out, const char *str); Bool StrUtil_CapacityToBytes(SectorType *out, const char *str, unsigned int bytes); Bool StrUtil_CapacityToSectorType(SectorType *out, const char *str, unsigned int bytes); char *StrUtil_FormatSizeInBytesUnlocalized(uint64 size); size_t StrUtil_GetLongestLineLength(const char *buf, size_t bufLength); Bool StrUtil_StartsWith(const char *s, const char *prefix); Bool StrUtil_CaselessStartsWith(const char *s, const char *prefix); Bool StrUtil_EndsWith(const char *s, const char *suffix); Bool StrUtil_CaselessEndsWith(const char *s, const char *suffix); const char * StrUtil_CaselessStrstr(const char *str, const char *strSearch); Bool StrUtil_IsASCII(const char *s); Bool StrUtil_VDynBufPrintf(struct DynBuf *b, const char *fmt, va_list args); Bool StrUtil_DynBufPrintf(struct DynBuf *b, const char *fmt, ...) PRINTF_DECL(2, 3); void StrUtil_SafeDynBufPrintf(struct DynBuf *b, const char *fmt, ...) PRINTF_DECL(2, 3); void StrUtil_SafeStrcat(char **prefix, const char *str); void StrUtil_SafeStrcatFV(char **prefix, const char *fmt, va_list args); void StrUtil_SafeStrcatF(char **prefix, const char *fmt, ...) PRINTF_DECL(2, 3); char *StrUtil_TrimWhitespace(const char *str); char *StrUtil_ReplaceAll(const char *orig, const char *what, const char *with); char *StrUtil_GetNextItem(char **list, char delim); char *StrUtil_GetLastItem(char **list, char delim); Bool StrUtil_HasListItem(char const *list, char delim, char const *item); Bool StrUtil_HasListItemCase(char const *list, char delim, char const *item); char *StrUtil_AppendListItem(char const *list, char delim, char const *item); void StrUtil_RemoveListItem(char * const list, char delim, char const *item); void StrUtil_RemoveListItemCase(char * const list, char delim, char const *item); #if defined(__cplusplus) } // extern "C" #endif #endif /* STRUTIL_H */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/su.h000066400000000000000000000071261470176644300233200ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * su.h -- * * Manage super-user priviledges * */ #ifndef USER_SU_H #define USER_SU_H #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_types.h" #include "vm_assert.h" #if defined(__cplusplus) extern "C" { #endif #if defined(__APPLE__) #include #include int Id_SetGid(gid_t egid); int Id_SetREUid(uid_t ruid, uid_t euid); int Id_SetRESUid(uid_t ruid, uid_t euid, uid_t suid); #define Id_GetEUid() geteuid() void *Id_AuthGetLocal(); void *Id_AuthGetExternal(size_t *size); Bool Id_AuthSet(void const *buf, size_t size); Bool Id_AuthCheck(char const *right, char const *localizedDescription, Bool showDialogIfNeeded); #elif defined(__linux__) || defined(sun) || defined(__FreeBSD__) || \ defined(__EMSCRIPTEN__) #include #include /* Our set of set*id functions which affect current thread only */ int Id_SetUid(uid_t euid); int Id_SetGid(gid_t egid); int Id_SetREUid(uid_t ruid, uid_t euid); int Id_SetREGid(gid_t rgid, gid_t egid); int Id_SetRESUid(uid_t ruid, uid_t euid, uid_t suid); int Id_SetRESGid(gid_t rgid, gid_t egid, gid_t sgid); /* For symmetry */ #define Id_GetEUid() geteuid() /* *---------------------------------------------------------------------------- * * Id_SetEUid -- * * Set specified effective uid for current thread. Does not affect * real uid or saved uid. * * Results: * 0 on success, -1 on failure, errno set * * Side effects: * errno may be modified on success * *---------------------------------------------------------------------------- */ static INLINE int Id_SetEUid(uid_t euid) { return Id_SetRESUid((uid_t)-1, euid, (uid_t)-1); } /* *---------------------------------------------------------------------------- * * Id_SetEGid -- * * Set specified effective gid for current thread. Does not affect * real gid or saved gid. * * Results: * 0 on success, -1 on failure, errno set * * Side effects: * errno may be modified on success * *---------------------------------------------------------------------------- */ static INLINE int Id_SetEGid(gid_t egid) { return Id_SetRESGid((gid_t)-1, egid, (gid_t)-1); } #endif /* linux */ #if defined(_WIN32) static INLINE int Id_BeginSuperUser(void) { return -1; } static INLINE void Id_EndSuperUser(int id) { } static INLINE Bool Id_IsSuperUser(void) { return TRUE; } static INLINE Bool Id_IsSetUGid(void) { return FALSE; } #else static INLINE Bool Id_IsSuperUser(void) { return 0 == geteuid(); } uid_t Id_BeginSuperUser(void); void Id_EndSuperUser(uid_t uid); Bool Id_IsSetUGid(void); #endif #if defined(__cplusplus) } // extern "C" #endif #endif /* USER_SU_H */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/syncDriver.h000066400000000000000000000037771470176644300250310ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2005-2018, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * syncDriver.h -- * * Interface to the Sync Driver. */ #ifndef _SYNC_DRIVER_H_ #define _SYNC_DRIVER_H_ #include "vm_basic_types.h" #if defined(_WIN32) /* { */ # include # define SYNCDRIVER_INVALID_HANDLE INVALID_HANDLE_VALUE typedef HANDLE SyncDriverHandle; #else /* }{ POSIX */ # define INFINITE -1 # define SYNCDRIVER_INVALID_HANDLE NULL typedef struct SyncHandle * SyncDriverHandle; #endif /* } */ typedef enum { SYNCDRIVER_IDLE, SYNCDRIVER_BUSY, SYNCDRIVER_ERROR } SyncDriverStatus; Bool SyncDriver_Init(void); Bool SyncDriver_Freeze(const char *drives, Bool enableNullDriver, SyncDriverHandle *handle, const char *excludedFileSystems, Bool ignoreFrozenFS); Bool SyncDriver_Thaw(const SyncDriverHandle handle); SyncDriverStatus SyncDriver_QueryStatus(const SyncDriverHandle handle, int32 timeout); void SyncDriver_CloseHandle(SyncDriverHandle *handle); #if defined(__linux__) void SyncDriver_GetAttr(const SyncDriverHandle handle, const char **name, Bool *quiesces); #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/syncDriverIoc.h000066400000000000000000000030521470176644300254460ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2016,2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * syncDriverIoc.h -- * * ioctl commands used by the sync driver on Unix systems. * * SYNC_IOC_FREEZE: Freezes the provided paths. * SYNC_IOC_THAW: Thaws frozen block devices after a FREEZE ioctl. * SYNC_IOC_QUERY: Returns the total number of frozen devices (not * specific to the fd used). */ #ifndef _SYNCDRIVERIOC_H_ #define _SYNCDRIVERIOC_H_ #ifdef __linux__ # include # define SYNC_IOC_FREEZE _IOW(0xF5,0x01,const char *) # define SYNC_IOC_THAW _IO(0xF5,0x02) # define SYNC_IOC_QUERY _IOR(0xF5,0x03,int) #else # error "Driver not yet implemented for this OS." #endif #endif /* _SYNCDRIVERIOC_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/system.h000066400000000000000000000060671470176644300242200ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2016,2018,2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * system.h -- * * System-specific routines used by the tools daemon. * */ #ifndef __SYSTEM_H__ # define __SYSTEM_H__ #include "vm_basic_types.h" #ifdef _WIN32 #include "dbllnklst.h" #endif #include "unicode.h" uint64 System_GetTimeMonotonic(void); uint64 System_Uptime(void); void System_Shutdown(Bool reboot); Bool System_GetNodeName(size_t outBufSize, char *outBuf); char *System_GetEnv(Bool global, const char *valueName); int System_SetEnv(Bool global, const char *valueName, const char *value); Bool System_IsUserAdmin(void); #ifdef _WIN32 /* * Representation of monitors gathered by System_GetMonitors. */ typedef struct MonListNode { RECT rect; RECT work; BOOL isPrimary; DWORD bpp; BOOL isActive; uint32 srcId; DblLnkLst_Links l; } MonListNode; /* * The value returned by System_GetServiceState if the current state of the * vmtools service can't be determined. We need to use a value that is not * already used for a real state. The current values run from 0x1 to 0x7, so * 0xffffffff should be fairly safe (cf. winsvc.h). */ #define VM_SERVICE_STATE_UNKNOWN 0xffffffff BOOL System_SetProcessPrivilege(wchar_t *privName, Bool enable); Bool System_IsScreenSaverActive(void); Bool System_IsScreenSaverRunning(void); Bool System_IsSecureDesktopActive(void); Bool System_DisableAndKillScreenSaver(void); DWORD System_GetServiceState(LPCWSTR szServiceName); DblLnkLst_Links *System_GetMonitors(); void System_SetFocusedWindow(HWND windowToFocus, Bool force); Bool System_EnableDesktopComposition(BOOL enabled); LPWSTR System_GetImageFilePathForWindow(HWND hwnd); HANDLE System_OpenProcessForHWND(DWORD mask, BOOL inherit, HWND hwnd); LONG System_VerifyTrust(const char *filePath); LPWSTR System_GetProcessCmdLine(DWORD pId); #endif /* * TODO: Targets' make/SCons files, or perhaps the entire build infrastructure * as a whole, should define a POSIX_LIKE_ENVIRONMENT variable which is * then acted upon and translates to a -DPOSIX_LIKE_ENVIRONMENT * preprocessor option. */ #if !defined(_WIN32) const char **System_GetNativeEnviron(const char **compatEnviron); void System_FreeNativeEnviron(const char **nativeEnviron); #endif #endif /* __SYSTEM_H__ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/timeutil.h000066400000000000000000000103021470176644300245130ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2017,2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * timeutil.h -- * * Miscellaneous time related utility functions. * */ #ifndef _TIMEUTIL_H_ #define _TIMEUTIL_H_ #include #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #include "vm_basic_types.h" #include "vm_basic_defs.h" #include "vm_assert.h" #if defined(__cplusplus) extern "C" { #endif #define MAX_DAYSLEFT 4096 struct timeval; /*struct timespec is not supported on UWP*/ #if defined(_WIN32) && !defined(VM_WIN_UWP) && _MSC_VER < 1900 struct timespec { time_t tv_sec; long tv_nsec; }; #endif /* Similar to a struct tm but with slightly less weird semantics. */ typedef struct TimeUtil_Date { unsigned int year; /* e.g. 1970 */ unsigned int month; /* [1, 12] */ unsigned int day; /* [1, 31] */ unsigned int hour; /* [0, 23] */ unsigned int minute; /* [0, 59] */ unsigned int second; /* [0, 61] (for leap seconds) */ } TimeUtil_Date; typedef struct TimeUtil_TimeOfDay { unsigned long seconds; unsigned long useconds; } TimeUtil_TimeOfDay; typedef struct TimeUtil_Expiration { /* * Does it expire? */ Bool expires; /* * When does it expire? (valid only if 'expires' == TRUE) * * Note: TimeUtil_Expiration only uses the 'year', 'month' * and 'day' fields of 'when'. */ TimeUtil_Date when; /* * Compute this once for all, to avoid problems when the current day changes * (valid only if 'expires' == TRUE). */ unsigned int daysLeft; } TimeUtil_Expiration; time_t TimeUtil_MakeTime(const TimeUtil_Date *d); // IN Bool TimeUtil_StringToDate(TimeUtil_Date *d, // IN/OUT char const *date); // IN: 'YYYYMMDD' or 'YYYY/MM/DD' or 'YYYY-MM-DD' Bool TimeUtil_DaysSubtract(TimeUtil_Date *d, // IN/OUT unsigned int nr); // IN int TimeUtil_DeltaDays(TimeUtil_Date const *left, // IN TimeUtil_Date const *right); // IN void TimeUtil_DaysAdd(TimeUtil_Date *d, // IN/OUT unsigned int nr); // IN void TimeUtil_PopulateWithCurrent(Bool local, // IN TimeUtil_Date *d); // OUT void TimeUtil_GetTimeOfDay(TimeUtil_TimeOfDay *d); // OUT unsigned int TimeUtil_DaysLeft(TimeUtil_Date const *d); // IN Bool TimeUtil_ExpirationLowerThan(TimeUtil_Expiration const *left, // IN TimeUtil_Expiration const *right); // IN Bool TimeUtil_DateLowerThan(TimeUtil_Date const *left, // IN TimeUtil_Date const *right); // IN void TimeUtil_ProductExpiration(TimeUtil_Expiration *e); // OUT char * TimeUtil_GetTimeFormat(int64 utcTime, // IN Bool showDate, // IN Bool showTime); // IN int TimeUtil_NtTimeToUnixTime(struct timespec *unixTime, // OUT VmTimeType ntTime); // IN VmTimeType TimeUtil_UnixTimeToNtTime(struct timespec unixTime); // IN Bool TimeUtil_IsValidDate(TimeUtil_Date const *d); // IN #ifdef _WIN32 Bool TimeUtil_UTCTimeToSystemTime(const __time64_t utcTime, // IN SYSTEMTIME *systemTime); // OUT #endif int TimeUtil_GetLocalWindowsTimeZoneIndexAndName(char **ptzName); time_t TimeUtil_SecondsSinceEpoch(TimeUtil_Date *d); // IN #if defined(__cplusplus) } // extern "C" #endif #endif // _TIMEUTIL_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/tracer.hh000066400000000000000000000027651470176644300243250ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2013-2017,2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * tracer.hh -- * * A dumb object to trace function enter/exit. (Devel-only.) */ #ifndef TRACER_HH #define TRACER_HH #include "vm_basic_defs.h" #include "glib.h" #ifdef VMX86_DEVEL # define TRACE_CALL() Tracer _fn_tracer (__FUNCTION__) class Tracer { public: Tracer(const char* fnName) : mFnName(fnName) { g_debug("> %s: enter\n", mFnName); } ~Tracer() { g_debug("< %s: exit\n", mFnName); } private: Tracer(); // = delete Tracer(const Tracer&); // = delete const char* mFnName; }; #else # define TRACE_CALL() #endif #endif // ifndef TRACER_HH open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/unicode.h000066400000000000000000000030201470176644300243040ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * unicode.h -- * * Unicode-aware string library. */ #ifndef _UNICODE_H_ #define _UNICODE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" // Start here: string creation, destruction, and encoding conversion. #include "unicodeBase.h" // Basic string operations: length, append, find, insert, replace. #include "unicodeOperations.h" // Character transformations: upper/lower/title case, case folding, etc. #include "unicodeTransforms.h" #ifdef USE_ICU // Unicode functionality depending on the third-party ICU library. #include "unicodeICU.h" #endif // USE_ICU #endif // _UNICODE_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/unicodeBase.h000066400000000000000000000237271470176644300251170ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * unicodeBase.h -- * * Basic Unicode string creation and encoding conversion. */ #ifndef _UNICODE_BASE_H_ #define _UNICODE_BASE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include #include #include "util.h" #include "unicodeTypes.h" #include "err.h" #if defined(__cplusplus) extern "C" { #endif #define UNICODE_SUBSTITUTION_CHAR "\xEF\xBF\xBD" /* * Unescapes \\uABCD in string literals to Unicode code point * U+ABCD, and \\U001FABCD to Unicode code point U+1FABCD. * * The resulting string is never freed, so this is not to be used for * general runtime Unicode string creation. * * Use to replace: * * const char *utf8Copyright = "Copyright \302\251 COMPANY_NAME"; * * with: * * const char *copyright = U_UNESCAPE("Copyright \\u00A9 COMPANY_NAME"); */ #define U_UNESCAPE(x) Unicode_GetStatic(x, TRUE) /* * In contexts where an errno makes sense, use this to report conversion * failure. ERANGE is chosen since no Unicode routines deal with math; this * avoids overloading an errno that may a specific meaning for a certain * routine. */ #ifndef _WIN32 #define UNICODE_CONVERSION_ERRNO ERANGE #endif /* * Allocates a Unicode string given a buffer of the specified length * (not necessarily NUL-terminated) in the specified encoding. * * Returns NULL if the buffer was invalid or memory could not be * allocated. */ char *Unicode_AllocWithLength(const void *buffer, ssize_t lengthInBytes, StringEncoding encoding); /* *----------------------------------------------------------------------------- * * Unicode_Alloc -- * * Allocates a new Unicode string given a NUL-terminated buffer * of bytes in the specified string encoding. * * If buffer is NULL, then NULL is returned. * * Note that regardless of the encoding of the buffer passed to this * function, the returned string can hold any Unicode characters. * * Results: * An allocated Unicode string containing the decoded characters * in buffer, or NULL if input is NULL. Caller must pass to * free to free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_Alloc(const void *buffer, // IN StringEncoding encoding) // IN { return Unicode_AllocWithLength(buffer, -1, encoding); } /* *----------------------------------------------------------------------------- * * Unicode_AllocWithUTF8 -- * * Allocates a new Unicode string given a NUL-terminated UTF-8 string. * * If utf8String is NULL, then NULL is returned. * * Results: * An allocated Unicode string containing the characters in * utf8String, or NULL if utf8String is NULL. Caller must pass to * free to free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_AllocWithUTF8(const char *utf8String) // IN { return Unicode_AllocWithLength(utf8String, -1, STRING_ENCODING_UTF8); } /* *----------------------------------------------------------------------------- * * Unicode_AllocWithUTF16 -- * * Allocates a new Unicode string given a NUL-terminated UTF-16 * string in host-endian order. * * If utf16String is NULL, then NULL is returned. * * Results: * An allocated Unicode string containing the characters in * utf16String, or NULL if utf16String is NULL. Caller must pass to * free to free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_AllocWithUTF16(const utf16_t *utf16String) // IN { return Unicode_AllocWithLength(utf16String, -1, STRING_ENCODING_UTF16); } char *Unicode_Duplicate(const char *str); char **Unicode_AllocList(char **srcList, ssize_t length, StringEncoding encoding); char **Unicode_GetAllocList(char *const srcList[], ssize_t length, StringEncoding encoding); /* *----------------------------------------------------------------------------- * * Unicode_AllocListWithUTF16 -- * * Allocates a list (actually a vector) of Unicode strings from a list * (vector) of UTF-16 strings. The input list has a specified length or * can be an argv-style NULL-terminated list (if length is negative). * * Results: * An allocated list (vector) of Unicode strings. * The result must be freed with Util_FreeStringList. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char ** Unicode_AllocListWithUTF16(utf16_t **utf16list, // IN: ssize_t length) // IN: { return Unicode_AllocList((char **) utf16list, length, STRING_ENCODING_UTF16); } /* * Compute the number of bytes in a string. */ ssize_t Unicode_LengthInBytes(const void *buffer, StringEncoding encoding); /* * Gets the number of UTF-16 code units in the NUL-terminated UTF-16 array. */ ssize_t Unicode_UTF16Strlen(const utf16_t *utf16); /* * Duplicates a UTF-16 string. */ utf16_t *Unicode_UTF16Strdup(const utf16_t *utf16); /* * Tests if the buffer's bytes are valid in the specified encoding. */ Bool Unicode_IsBufferValid(const void *buffer, ssize_t lengthInBytes, StringEncoding encoding); Bool Unicode_IsStringValidUTF8(const char *str); /* * Tests if the buffer's unicode contents can be converted to the * specified encoding. */ Bool Unicode_CanGetBytesWithEncoding(const char *ustr, StringEncoding encoding); /* * Escape non-printable bytes of the buffer with \xAB, where 0xAB * is the non-printable byte value. */ char *Unicode_EscapeBuffer(const void *buffer, ssize_t lengthInBytes, StringEncoding encoding); /* * Returns the length in number of native code units (UTF-8 bytes or * UTF-16 words) of the string. */ UnicodeIndex Unicode_LengthInCodeUnits(const char *str); /* *----------------------------------------------------------------------------- * * Unicode_IsEmpty -- * * Test if the Unicode string is empty. * * Results: * TRUE if the string has length 0, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Unicode_IsEmpty(const char *str) // IN: { ASSERT(str != NULL); return str[0] == '\0'; } /* * Efficiently returns the upper bound on the number of bytes required * to encode the Unicode string in the specified encoding, including * NUL termination. */ size_t Unicode_BytesRequired(const char *str, StringEncoding encoding); /* * Extracts the contents of the Unicode string into a NUL-terminated * buffer using the specified encoding. Copies at most * maxLengthInBytes including NUL termination. Returns FALSE if * truncation occurred, TRUE otherwise. If retLength is not NULL, * *retLength holds the number of bytes actually copied, not including * the NUL termination, upon return. */ Bool Unicode_CopyBytes(void *destBuffer, const char *srcBuffer, size_t maxLengthInBytes, size_t *retLength, StringEncoding encoding); void *Unicode_GetAllocBytes(const char *str, StringEncoding encoding); void *Unicode_GetAllocBytesWithLength(const char *str, StringEncoding encoding, ssize_t lengthInBytes); /* *----------------------------------------------------------------------------- * * Unicode_GetAllocUTF16 -- * * Allocates and returns a NUL terminated buffer into which the contents * of the unicode string are extracted using the (host native) UTF-16 * encoding. (Note that UTF-16 NUL is two bytes: "\0\0".) * * NULL is returned for NULL argument. * * Results: * Pointer to the dynamically allocated memory, * or NULL on NULL argument. * * Caller is responsible to free the memory allocated by this routine. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE utf16_t * Unicode_GetAllocUTF16(const char *str) // IN: { /* Cast for compatibility with C++ compilers. */ return (utf16_t *) Unicode_GetAllocBytes(str, STRING_ENCODING_UTF16); } /* * Helper function for Unicode string literal macros. */ const char *Unicode_GetStatic(const char *asciiBytes, Bool unescape); /* * Helper macros for Win32 Unicode string transition. */ #if defined(_WIN32) #define UNICODE_GET_UTF16(s) Unicode_GetAllocUTF16(s) #define UNICODE_RELEASE_UTF16(s) WITH_ERRNO_FREE(s) #endif #if defined(__cplusplus) } // extern "C" #endif #endif // _UNICODE_BASE_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/unicodeICU.h000066400000000000000000000056621470176644300246630ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2008-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * unicodeICU.h -- * * Unicode operations that depend on the third-party ICU support * library. */ #ifndef _UNICODE_ICU_H_ #define _UNICODE_ICU_H_ #define INCLUDE_ALLOW_USERLEVEL #ifndef USE_ICU #error These interfaces require the ICU library (define USE_ICU). #endif #include "includeCheck.h" #include "unicodeBase.h" #if defined(__cplusplus) extern "C" { #endif typedef enum { UNICODE_COMPARE_DEFAULT = 0, UNICODE_COMPARE_IGNORE_ACCENTS, UNICODE_COMPARE_IGNORE_CASE, UNICODE_COMPARE_IGNORE_PUNCTUATION } UnicodeCompareOption; /* * Different languages and cultures have unique rules for how strings * are compared and sorted. For example: * * Swedish: z < "o with umlaut" * German: "o with umlaut" < z * * When producing a result visible to the user (like a sorted list of * virtual machine names) string comparsion must obey the rules set by * the user's language and culture, collectively called the "locale". */ int Unicode_CompareWithLocale(const char *str1, const char *str2, const char *locale, UnicodeCompareOption compareOption); /* * Transforms the case of the string using the given locale's rules. * * Pass in a NULL locale to use the process's default locale. * * Changing the case of a string can change its length, so don't * assume the string is the same length after calling these functions. */ char *Unicode_ToLower(const char *str, const char *locale); char *Unicode_ToUpper(const char *str, const char *locale); #ifdef HAVE_ICU_38 char *Unicode_ToTitle(const char *str, const char *locale); #endif typedef enum { UNICODE_NORMAL_FORM_C, // "e with acute accent" -> U+00E9 UNICODE_NORMAL_FORM_D // "e with acute accent" -> U+0065 U+0302 } UnicodeNormalizationForm; /* * Normalizes Unicode characters composed of multiple parts into a * standard form. */ char *Unicode_Normalize(const char *str, UnicodeNormalizationForm form); #if defined(__cplusplus) } // extern "C" #endif #endif // _UNICODE_ICU_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/unicodeOperations.h000066400000000000000000000526631470176644300263710ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * unicodeOperations.h -- * * Basic Unicode string operations. * * UnicodeIndex index and length arguments are in terms of code * units, not characters. The size of a code unit depends on the * implementation (one byte for UTF-8, one 16-bit word for * UTF-16). Do not store these values on disk, modify them, or * do arithmetic operations on them. * * Instead of iterating over the code units in a string to do * character operations, use the library functions provided to * search and transform strings. * * If the functionality you need is not present, email the * i18n-dev mailing list. */ #ifndef _UNICODE_OPERATIONS_H_ #define _UNICODE_OPERATIONS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include #include "unicodeBase.h" #include "vm_assert.h" #if defined(__cplusplus) extern "C" { #endif /* * Primitive operations. All other Unicode operations are implemented * in terms of these. * * Pass -1 for any length parameter to indicate "from start until end * of string". */ int Unicode_CompareRange(const char *str1, UnicodeIndex str1Start, UnicodeIndex str1Length, const char *str2, UnicodeIndex str2Start, UnicodeIndex str2Length, Bool ignoreCase); UnicodeIndex Unicode_FindSubstrInRange(const char *str, UnicodeIndex strStart, UnicodeIndex strLength, const char *strToFind, UnicodeIndex strToFindStart, UnicodeIndex strToFindLength); UnicodeIndex Unicode_FindLastSubstrInRange(const char *str, UnicodeIndex strStart, UnicodeIndex strLength, const char *strToFind, UnicodeIndex strToFindStart, UnicodeIndex strToFindLength); char *Unicode_Substr(const char *str, UnicodeIndex start, UnicodeIndex length); char *Unicode_ReplaceRange(const char *destination, UnicodeIndex destinationStart, UnicodeIndex destinationLength, const char *source, UnicodeIndex sourceStart, UnicodeIndex sourceLength); char *Unicode_Join(const char *first, ...); char *Unicode_Format(const char *fmt, ...); UnicodeIndex Unicode_LengthInCodePoints(const char *str); /* * Simple in-line functions that may be used below. */ /* *----------------------------------------------------------------------------- * * Unicode_IsIndexAtCodePointBoundary -- * * Check a string index (in bytes) for code point boundary. * * The index must be valid (>= 0 and <= string length). * The end of the string is considered a valid boundary. * * Results: * TRUE if index is at a code point boundary. * * Side effects: * Panic if index is not valid. * *----------------------------------------------------------------------------- */ static INLINE Bool Unicode_IsIndexAtCodePointBoundary(const char *str, // IN: UnicodeIndex index) // IN: { ASSERT(index >= 0 && index <= Unicode_LengthInCodeUnits(str)); return (str[index] & 0xc0) != 0x80; } /* * Other operations, each based upon calls to primitives. */ /* *----------------------------------------------------------------------------- * * Unicode_Append -- * * Allocates and returns a new string containing 'destination' * followed by 'source'. * * Results: * The newly-allocated string. Caller must free with free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_Append(const char *destination, // IN const char *source) // IN { return Unicode_ReplaceRange(destination, -1, 0, source, 0, -1); } /* *----------------------------------------------------------------------------- * * Unicode_AppendRange -- * * Allocates and returns a new string containing 'destination' * followed by the specified range of 'source'. * * Results: * The newly-allocated string. Caller must free with free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_AppendRange(const char *dest, // IN: const char *src, // IN: UnicodeIndex srcStart, // IN: UnicodeIndex srcLength) // IN: { return Unicode_ReplaceRange(dest, Unicode_LengthInCodePoints(dest), 0, src, srcStart, srcLength); } /* *----------------------------------------------------------------------------- * * Unicode_Compare -- * * Compares two Unicode strings for canonical equivalence in code * point order. * * If the result is to be visible in a user interface, use * Unicode_CompareWithLocale to support language and * culture-specific comparison and sorting rules. * * Results: * -1 if str1 < str2, 0 if str1 == str2, 1 if str1 > str2. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE int Unicode_Compare(const char *str1, // IN const char *str2) // IN { return Unicode_CompareRange(str1, 0, -1, str2, 0, -1, FALSE); } /* *----------------------------------------------------------------------------- * * Unicode_CompareIgnoreCase -- * * Compares two Unicode strings for case-insensitive canonical * equivalence in code point order. * * If the result is to be visible in a user interface, use * Unicode_CompareWithLocale to support language and * culture-specific comparison and sorting rules. * * Results: * -1 if str1 < str2, 0 if str1 == str2, 1 if str1 > str2. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE int Unicode_CompareIgnoreCase(const char *str1, // IN const char *str2) // IN { return Unicode_CompareRange(str1, 0, -1, str2, 0, -1, TRUE); } /* *----------------------------------------------------------------------------- * * UnicodeEndsWith -- * Unicode_EndsWith -- * Unicode_EndsWithIgnoreCase -- * * Tests if 'str' ends with 'suffix'. * * Results: * TRUE if 'str' ends with 'suffix', FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool UnicodeEndsWith(const char *str, // IN: const char *suffix, // IN: Bool ignoreCase) // IN: { UnicodeIndex strLength = Unicode_LengthInCodePoints(str); UnicodeIndex suffixLength = Unicode_LengthInCodePoints(suffix); UnicodeIndex offset = strLength - suffixLength; if (suffixLength > strLength) { return FALSE; } return Unicode_CompareRange(str, offset, suffixLength, suffix, 0, suffixLength, ignoreCase) == 0; } static INLINE Bool Unicode_EndsWith(const char *str, // IN const char *suffix) // IN { return UnicodeEndsWith(str, suffix, FALSE); } static INLINE Bool Unicode_EndsWithIgnoreCase(const char *str, // IN const char *suffix) // IN { return UnicodeEndsWith(str, suffix, TRUE); } /* *----------------------------------------------------------------------------- * * Unicode_Find -- * * Finds the first occurrence of 'strToFind' inside 'str'. * * Results: * If 'strToFind' exists inside 'str', returns the first starting * index of 'strToFind' in that range. * * Otherwise, returns UNICODE_INDEX_NOT_FOUND. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE UnicodeIndex Unicode_Find(const char *str, // IN const char *strToFind) // IN { return Unicode_FindSubstrInRange(str, 0, -1, strToFind, 0, -1); } /* *----------------------------------------------------------------------------- * * Unicode_FindFromIndex -- * * Finds the first occurrence of 'strToFind' inside 'str' in the range * [fromIndex, lengthOfStr). * * Results: * If 'strToFind' exists inside 'str' in the specified range, * returns the first starting index of 'strToFind' in that range. * * Otherwise, returns UNICODE_INDEX_NOT_FOUND. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE UnicodeIndex Unicode_FindFromIndex(const char *str, // IN const char *strToFind, // IN UnicodeIndex fromIndex) // IN { return Unicode_FindSubstrInRange(str, fromIndex, -1, strToFind, 0, -1); } /* *----------------------------------------------------------------------------- * * Unicode_FindInRange -- * * Finds the first occurrence of 'strToFind' inside 'str' in the range * [start, start+length). * * Results: * If 'strToFind' exists inside 'str' in the specified range, * returns the first starting index of 'strToFind' in that range. * * Otherwise, returns UNICODE_INDEX_NOT_FOUND. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE UnicodeIndex Unicode_FindInRange(const char *str, // IN const char *strToFind, // IN UnicodeIndex start, // IN UnicodeIndex length) // IN { return Unicode_FindSubstrInRange(str, start, length, strToFind, 0, -1); } /* *----------------------------------------------------------------------------- * * Unicode_FindLast -- * * Finds the last occurrence of 'strToFind' inside 'str'. * * Results: * If 'strToFind' exists inside 'str', returns the last starting * index of 'strToFind' in that range. * * Otherwise, returns UNICODE_INDEX_NOT_FOUND. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE UnicodeIndex Unicode_FindLast(const char *str, // IN const char *strToFind) // IN { return Unicode_FindLastSubstrInRange(str, 0, -1, strToFind, 0, -1); } /* *----------------------------------------------------------------------------- * * Unicode_FindLastFromIndex -- * * Finds the last occurrence of 'strToFind' inside 'str' in the range * [fromIndex, lengthOfStr). * * Results: * If 'strToFind' exists inside 'str' in the specified range, * returns the last starting index of 'strToFind' in that range. * * Otherwise, returns UNICODE_INDEX_NOT_FOUND. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE UnicodeIndex Unicode_FindLastFromIndex(const char *str, // IN const char *strToFind, // IN UnicodeIndex fromIndex) // IN { return Unicode_FindLastSubstrInRange(str, fromIndex, -1, strToFind, 0, -1); } /* *----------------------------------------------------------------------------- * * Unicode_FindLastInRange -- * * Finds the last occurrence of 'strToFind' inside 'str' in the range * [start, start+length). * * Results: * If 'strToFind' exists inside 'str' in the specified range, * returns the last starting index of 'strToFind' in that range. * * Otherwise, returns UNICODE_INDEX_NOT_FOUND. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE UnicodeIndex Unicode_FindLastInRange(const char *str, // IN const char *strToFind, // IN UnicodeIndex start, // IN UnicodeIndex length) // IN { return Unicode_FindLastSubstrInRange(str, start, length, strToFind, 0, -1); } /* *----------------------------------------------------------------------------- * * Unicode_Insert -- * * Allocates and returns a new copy of 'destination', with the * string 'source' inserted at the index 'destinationStart'. * * Results: * The newly-allocated string. Caller must free with free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_Insert(const char *destination, // IN UnicodeIndex destinationStart, // IN const char *source) // IN { return Unicode_ReplaceRange(destination, destinationStart, 0, source, 0, -1); } /* *----------------------------------------------------------------------------- * * Unicode_InsertRange -- * * Allocates and returns a new copy of 'destination', with the * specified range of the string 'source' inserted at the index * 'destinationStart'. * * Results: * The newly-allocated string. Caller must free with free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_InsertRange(const char *destination, UnicodeIndex destinationStart, const char *source, UnicodeIndex sourceStart, UnicodeIndex sourceLength) { return Unicode_ReplaceRange(destination, destinationStart, 0, source, sourceStart, sourceLength); } /* *----------------------------------------------------------------------------- * * Unicode_IsEqual -- * * Tests two strings for canonical equivalence. * * Results: * TRUE if the two strings are canonically equivalent, FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Unicode_IsEqual(const char *str1, // IN const char *str2) // IN { return Unicode_CompareRange(str1, 0, -1, str2, 0, -1, FALSE) == 0; } /* *----------------------------------------------------------------------------- * * Unicode_RemoveRange -- * * Allocates and returns a new string that contains a copy of * 'destination' with the code units in the range [start, start + length) * removed. * * Results: * The newly-allocated string. Caller must free with free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_RemoveRange(const char *destination, UnicodeIndex start, UnicodeIndex length) { return Unicode_ReplaceRange(destination, start, length, "", 0, 0); } /* *----------------------------------------------------------------------------- * * Unicode_Replace -- * * Allocates and returns a new string that contains a copy of * 'destination' with the code units in the range * [destinationStart, destinarionStart + destinationLength) replaced * with 'source'. * * Results: * The newly-allocated string. Caller must free with free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_Replace(const char *destination, UnicodeIndex destinationStart, UnicodeIndex destinationLength, const char *source) { return Unicode_ReplaceRange(destination, destinationStart, destinationLength, source, 0, -1); } /* *----------------------------------------------------------------------------- * * UnicodeStartsWith -- * Unicode_StartsWith -- * Unicode_StartsWithIgnoreCase -- * * Tests if 'str' starts with 'prefix'. * * Results: * TRUE if 'str' starts with 'prefix', FALSE otherwise. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool UnicodeStartsWith(const char *str, // IN: const char *prefix, // IN: Bool ignoreCase) // IN: { UnicodeIndex strLength = Unicode_LengthInCodePoints(str); UnicodeIndex prefixLength = Unicode_LengthInCodePoints(prefix); if (prefixLength > strLength) { return FALSE; } return Unicode_CompareRange(str, 0, prefixLength, prefix, 0, prefixLength, ignoreCase) == 0; } static INLINE Bool Unicode_StartsWith(const char *str, // IN const char *prefix) // IN { return UnicodeStartsWith(str, prefix, FALSE); } static INLINE Bool Unicode_StartsWithIgnoreCase(const char *str, // IN const char *prefix) // IN { return UnicodeStartsWith(str, prefix, TRUE); } /* *----------------------------------------------------------------------------- * * Unicode_Truncate -- * * Allocates and returns a new copy of 'str' truncated to the * specified length in code units. * * Results: * The newly-allocated truncated copy of 'str'. Caller must free * with free. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE char * Unicode_Truncate(const char *str, // IN UnicodeIndex length) // IN { return Unicode_Substr(str, 0, length); } #if defined(__cplusplus) } // extern "C" #endif #endif // _UNICODE_OPERATIONS_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/unicodeTransforms.h000066400000000000000000000034621470176644300263750ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * unicodeTransforms.h -- * * Operations that transform all the characters in a string. * * Transform operations like uppercase and lowercase are * locale-sensitive (depending on the user's country and language * preferences). */ #ifndef _UNICODE_TRANSFORMS_H_ #define _UNICODE_TRANSFORMS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "unicodeTypes.h" #if defined(__cplusplus) extern "C" { #endif /* * Standardizes the case of the string by doing a locale-agnostic * uppercase operation, then a locale-agnostic lowercase operation. */ char *Unicode_FoldCase(const char *str); /* * Trims whitespace from either side of the string. */ char *Unicode_Trim(const char *str); char *Unicode_TrimLeft(const char *str); char *Unicode_TrimRight(const char *str); #if defined(__cplusplus) } // extern "C" #endif #endif // _UNICODE_TRANSFORMS_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/unicodeTypes.h000066400000000000000000000331671470176644300253500ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2017, 2019 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * unicodeTypes.h -- * * Types used throughout the Unicode library. */ #ifndef _UNICODE_TYPES_H_ #define _UNICODE_TYPES_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "vm_basic_types.h" #include "vm_assert.h" #if defined(__cplusplus) extern "C" { #endif typedef ssize_t UnicodeIndex; /* * Special UnicodeIndex value returned when a string is not found. */ enum { UNICODE_INDEX_NOT_FOUND = -1 }; /* * Encodings passed to convert encoded byte strings to and from * Unicode. * * Keep this enum synchronized with ICU_ENCODING_LIST in unicodeICU.cc! */ typedef enum { STRING_ENCODING_FIRST, /* * Byte string encodings that support all characters in Unicode. * * If you don't know what to use for bytes in a new system, use * STRING_ENCODING_UTF8. */ STRING_ENCODING_UTF8 = STRING_ENCODING_FIRST, STRING_ENCODING_UTF16_LE, // Little-endian UTF-16. STRING_ENCODING_UTF16_BE, // Big-endian UTF-16. STRING_ENCODING_UTF16_XE, // UTF-16 with BOM. STRING_ENCODING_UTF32_LE, // Little-endian UTF-32. STRING_ENCODING_UTF32_BE, // Big-endian UTF-32. STRING_ENCODING_UTF32_XE, // UTF-32 with BOM. /* * Legacy byte string encodings that only support a subset of Unicode. */ /* * Latin encodings */ STRING_ENCODING_US_ASCII, STRING_ENCODING_ISO_8859_1, STRING_ENCODING_ISO_8859_2, STRING_ENCODING_ISO_8859_3, STRING_ENCODING_ISO_8859_4, STRING_ENCODING_ISO_8859_5, STRING_ENCODING_ISO_8859_6, STRING_ENCODING_ISO_8859_7, STRING_ENCODING_ISO_8859_8, STRING_ENCODING_ISO_8859_9, STRING_ENCODING_ISO_8859_10, // ISO-8859-11 is unused. // Oddly, there is no ISO-8859-12. STRING_ENCODING_ISO_8859_13, STRING_ENCODING_ISO_8859_14, STRING_ENCODING_ISO_8859_15, /* * Chinese encodings */ STRING_ENCODING_GB_18030, STRING_ENCODING_BIG_5, STRING_ENCODING_BIG_5_HK, STRING_ENCODING_GBK, STRING_ENCODING_GB_2312, STRING_ENCODING_ISO_2022_CN, /* * Japanese encodings */ STRING_ENCODING_SHIFT_JIS, STRING_ENCODING_EUC_JP, STRING_ENCODING_ISO_2022_JP, STRING_ENCODING_ISO_2022_JP_1, STRING_ENCODING_ISO_2022_JP_2, /* * Korean encodings */ STRING_ENCODING_ISO_2022_KR, /* * Windows encodings */ STRING_ENCODING_WINDOWS_1250, STRING_ENCODING_WINDOWS_1251, STRING_ENCODING_WINDOWS_1252, STRING_ENCODING_WINDOWS_1253, STRING_ENCODING_WINDOWS_1254, STRING_ENCODING_WINDOWS_1255, STRING_ENCODING_WINDOWS_1256, STRING_ENCODING_WINDOWS_1257, STRING_ENCODING_WINDOWS_1258, STRING_ENCODING_ISO_6937_2_ADD, STRING_ENCODING_JIS_X0201, STRING_ENCODING_JIS_ENCODING, STRING_ENCODING_EXTENDED_UNIX_CODE_FIXED_WIDTH_FOR_JAPANESE, STRING_ENCODING_BS_4730, STRING_ENCODING_SEN_850200_C, STRING_ENCODING_IT, STRING_ENCODING_ES, STRING_ENCODING_DIN_66003, STRING_ENCODING_NS_4551_1, STRING_ENCODING_NF_Z_62_010, STRING_ENCODING_ISO_10646_UTF_1, STRING_ENCODING_ISO_646_BASIC_1983, STRING_ENCODING_INVARIANT, STRING_ENCODING_ISO_646_IRV_1983, STRING_ENCODING_NATS_SEFI, STRING_ENCODING_NATS_SEFI_ADD, STRING_ENCODING_NATS_DANO, STRING_ENCODING_NATS_DANO_ADD, STRING_ENCODING_SEN_850200_B, STRING_ENCODING_KS_C_5601_1987, STRING_ENCODING_JIS_C6220_1969_JP, STRING_ENCODING_JIS_C6220_1969_RO, STRING_ENCODING_PT, STRING_ENCODING_GREEK7_OLD, STRING_ENCODING_LATIN_GREEK, STRING_ENCODING_NF_Z_62_010__1973_, STRING_ENCODING_LATIN_GREEK_1, STRING_ENCODING_ISO_5427, STRING_ENCODING_JIS_C6226_1978, STRING_ENCODING_BS_VIEWDATA, STRING_ENCODING_INIS, STRING_ENCODING_INIS_8, STRING_ENCODING_INIS_CYRILLIC, STRING_ENCODING_ISO_5427_1981, STRING_ENCODING_ISO_5428_1980, STRING_ENCODING_GB_1988_80, STRING_ENCODING_GB_2312_80, STRING_ENCODING_NS_4551_2, STRING_ENCODING_VIDEOTEX_SUPPL, STRING_ENCODING_PT2, STRING_ENCODING_ES2, STRING_ENCODING_MSZ_7795_3, STRING_ENCODING_JIS_C6226_1983, STRING_ENCODING_GREEK7, STRING_ENCODING_ASMO_449, STRING_ENCODING_ISO_IR_90, STRING_ENCODING_JIS_C6229_1984_A, STRING_ENCODING_JIS_C6229_1984_B, STRING_ENCODING_JIS_C6229_1984_B_ADD, STRING_ENCODING_JIS_C6229_1984_HAND, STRING_ENCODING_JIS_C6229_1984_HAND_ADD, STRING_ENCODING_JIS_C6229_1984_KANA, STRING_ENCODING_ISO_2033_1983, STRING_ENCODING_ANSI_X3_110_1983, STRING_ENCODING_T_61_7BIT, STRING_ENCODING_T_61_8BIT, STRING_ENCODING_ECMA_CYRILLIC, STRING_ENCODING_CSA_Z243_4_1985_1, STRING_ENCODING_CSA_Z243_4_1985_2, STRING_ENCODING_CSA_Z243_4_1985_GR, STRING_ENCODING_ISO_8859_6_E, STRING_ENCODING_ISO_8859_6_I, STRING_ENCODING_T_101_G2, STRING_ENCODING_ISO_8859_8_E, STRING_ENCODING_ISO_8859_8_I, STRING_ENCODING_CSN_369103, STRING_ENCODING_JUS_I_B1_002, STRING_ENCODING_IEC_P27_1, STRING_ENCODING_JUS_I_B1_003_SERB, STRING_ENCODING_JUS_I_B1_003_MAC, STRING_ENCODING_GREEK_CCITT, STRING_ENCODING_NC_NC00_10_81, STRING_ENCODING_ISO_6937_2_25, STRING_ENCODING_GOST_19768_74, STRING_ENCODING_ISO_8859_SUPP, STRING_ENCODING_ISO_10367_BOX, STRING_ENCODING_LATIN_LAP, STRING_ENCODING_JIS_X0212_1990, STRING_ENCODING_DS_2089, STRING_ENCODING_US_DK, STRING_ENCODING_DK_US, STRING_ENCODING_KSC5636, STRING_ENCODING_UNICODE_1_1_UTF_7, STRING_ENCODING_ISO_2022_CN_EXT, STRING_ENCODING_ISO_8859_16, STRING_ENCODING_OSD_EBCDIC_DF04_15, STRING_ENCODING_OSD_EBCDIC_DF03_IRV, STRING_ENCODING_OSD_EBCDIC_DF04_1, STRING_ENCODING_ISO_11548_1, STRING_ENCODING_KZ_1048, STRING_ENCODING_ISO_10646_UCS_2, STRING_ENCODING_ISO_10646_UCS_4, STRING_ENCODING_ISO_10646_UCS_BASIC, STRING_ENCODING_ISO_10646_UNICODE_LATIN1, STRING_ENCODING_ISO_10646_J_1, STRING_ENCODING_ISO_UNICODE_IBM_1261, STRING_ENCODING_ISO_UNICODE_IBM_1268, STRING_ENCODING_ISO_UNICODE_IBM_1276, STRING_ENCODING_ISO_UNICODE_IBM_1264, STRING_ENCODING_ISO_UNICODE_IBM_1265, STRING_ENCODING_UNICODE_1_1, STRING_ENCODING_SCSU, STRING_ENCODING_UTF_7, STRING_ENCODING_CESU_8, STRING_ENCODING_BOCU_1, STRING_ENCODING_ISO_8859_1_WINDOWS_3_0_LATIN_1, STRING_ENCODING_ISO_8859_1_WINDOWS_3_1_LATIN_1, STRING_ENCODING_ISO_8859_2_WINDOWS_LATIN_2, STRING_ENCODING_ISO_8859_9_WINDOWS_LATIN_5, STRING_ENCODING_HP_ROMAN8, STRING_ENCODING_ADOBE_STANDARD_ENCODING, STRING_ENCODING_VENTURA_US, STRING_ENCODING_VENTURA_INTERNATIONAL, STRING_ENCODING_DEC_MCS, STRING_ENCODING_IBM_850, STRING_ENCODING_PC8_DANISH_NORWEGIAN, STRING_ENCODING_IBM_862, STRING_ENCODING_PC8_TURKISH, STRING_ENCODING_IBM_SYMBOLS, STRING_ENCODING_IBM_THAI, STRING_ENCODING_HP_LEGAL, STRING_ENCODING_HP_PI_FONT, STRING_ENCODING_HP_MATH8, STRING_ENCODING_ADOBE_SYMBOL_ENCODING, STRING_ENCODING_HP_DESKTOP, STRING_ENCODING_VENTURA_MATH, STRING_ENCODING_MICROSOFT_PUBLISHING, STRING_ENCODING_WINDOWS_31J, STRING_ENCODING_MACINTOSH, STRING_ENCODING_IBM_037, STRING_ENCODING_IBM_038, STRING_ENCODING_IBM_273, STRING_ENCODING_IBM_274, STRING_ENCODING_IBM_275, STRING_ENCODING_IBM_277, STRING_ENCODING_IBM_278, STRING_ENCODING_IBM_280, STRING_ENCODING_IBM_281, STRING_ENCODING_IBM_284, STRING_ENCODING_IBM_285, STRING_ENCODING_IBM_290, STRING_ENCODING_IBM_297, STRING_ENCODING_IBM_420, STRING_ENCODING_IBM_423, STRING_ENCODING_IBM_424, STRING_ENCODING_IBM_437, STRING_ENCODING_IBM_500, STRING_ENCODING_IBM_851, STRING_ENCODING_IBM_852, STRING_ENCODING_IBM_855, STRING_ENCODING_IBM_857, STRING_ENCODING_IBM_860, STRING_ENCODING_IBM_861, STRING_ENCODING_IBM_863, STRING_ENCODING_IBM_864, STRING_ENCODING_IBM_865, STRING_ENCODING_IBM_868, STRING_ENCODING_IBM_869, STRING_ENCODING_IBM_870, STRING_ENCODING_IBM_871, STRING_ENCODING_IBM_880, STRING_ENCODING_IBM_891, STRING_ENCODING_IBM_903, STRING_ENCODING_IBM_904, STRING_ENCODING_IBM_905, STRING_ENCODING_IBM_918, STRING_ENCODING_IBM_1026, STRING_ENCODING_EBCDIC_AT_DE, STRING_ENCODING_EBCDIC_AT_DE_A, STRING_ENCODING_EBCDIC_CA_FR, STRING_ENCODING_EBCDIC_DK_NO, STRING_ENCODING_EBCDIC_DK_NO_A, STRING_ENCODING_EBCDIC_FI_SE, STRING_ENCODING_EBCDIC_FI_SE_A, STRING_ENCODING_EBCDIC_FR, STRING_ENCODING_EBCDIC_IT, STRING_ENCODING_EBCDIC_PT, STRING_ENCODING_EBCDIC_ES, STRING_ENCODING_EBCDIC_ES_A, STRING_ENCODING_EBCDIC_ES_S, STRING_ENCODING_EBCDIC_UK, STRING_ENCODING_EBCDIC_US, STRING_ENCODING_UNKNOWN_8BIT, STRING_ENCODING_MNEMONIC, STRING_ENCODING_MNEM, STRING_ENCODING_VISCII, STRING_ENCODING_VIQR, STRING_ENCODING_KOI8_R, STRING_ENCODING_HZ_GB_2312, STRING_ENCODING_IBM_866, STRING_ENCODING_IBM_775, STRING_ENCODING_KOI8_U, STRING_ENCODING_IBM_00858, STRING_ENCODING_IBM_00924, STRING_ENCODING_IBM_01140, STRING_ENCODING_IBM_01141, STRING_ENCODING_IBM_01142, STRING_ENCODING_IBM_01143, STRING_ENCODING_IBM_01144, STRING_ENCODING_IBM_01145, STRING_ENCODING_IBM_01146, STRING_ENCODING_IBM_01147, STRING_ENCODING_IBM_01148, STRING_ENCODING_IBM_01149, STRING_ENCODING_IBM_1047, STRING_ENCODING_PTCP154, STRING_ENCODING_AMIGA_1251, STRING_ENCODING_KOI7_SWITCHED, STRING_ENCODING_BRF, STRING_ENCODING_TSCII, STRING_ENCODING_TIS_620, STRING_ENCODING_WINDOWS_709, STRING_ENCODING_WINDOWS_710, STRING_ENCODING_WINDOWS_720, STRING_ENCODING_WINDOWS_737, STRING_ENCODING_WINDOWS_875, STRING_ENCODING_WINDOWS_1361, STRING_ENCODING_WINDOWS_10000, STRING_ENCODING_WINDOWS_10001, STRING_ENCODING_WINDOWS_10002, STRING_ENCODING_WINDOWS_10003, STRING_ENCODING_WINDOWS_10004, STRING_ENCODING_WINDOWS_10005, STRING_ENCODING_WINDOWS_10006, STRING_ENCODING_WINDOWS_10007, STRING_ENCODING_WINDOWS_10008, STRING_ENCODING_WINDOWS_10010, STRING_ENCODING_WINDOWS_10017, STRING_ENCODING_WINDOWS_10021, STRING_ENCODING_WINDOWS_10029, STRING_ENCODING_WINDOWS_10079, STRING_ENCODING_WINDOWS_10081, STRING_ENCODING_WINDOWS_10082, STRING_ENCODING_WINDOWS_20000, STRING_ENCODING_WINDOWS_20001, STRING_ENCODING_WINDOWS_20002, STRING_ENCODING_WINDOWS_20003, STRING_ENCODING_WINDOWS_20004, STRING_ENCODING_WINDOWS_20005, STRING_ENCODING_WINDOWS_20105, STRING_ENCODING_WINDOWS_20106, STRING_ENCODING_WINDOWS_20107, STRING_ENCODING_WINDOWS_20108, STRING_ENCODING_WINDOWS_20269, STRING_ENCODING_WINDOWS_20833, STRING_ENCODING_WINDOWS_20949, STRING_ENCODING_WINDOWS_21025, STRING_ENCODING_WINDOWS_21027, STRING_ENCODING_WINDOWS_29001, STRING_ENCODING_WINDOWS_38598, STRING_ENCODING_WINDOWS_50221, STRING_ENCODING_WINDOWS_50222, STRING_ENCODING_WINDOWS_50229, STRING_ENCODING_WINDOWS_50930, STRING_ENCODING_WINDOWS_50931, STRING_ENCODING_WINDOWS_50933, STRING_ENCODING_WINDOWS_50935, STRING_ENCODING_WINDOWS_50936, STRING_ENCODING_WINDOWS_50937, STRING_ENCODING_WINDOWS_50939, STRING_ENCODING_WINDOWS_51936, STRING_ENCODING_WINDOWS_51950, STRING_ENCODING_WINDOWS_57002, STRING_ENCODING_WINDOWS_57003, STRING_ENCODING_WINDOWS_57004, STRING_ENCODING_WINDOWS_57005, STRING_ENCODING_WINDOWS_57006, STRING_ENCODING_WINDOWS_57007, STRING_ENCODING_WINDOWS_57008, STRING_ENCODING_WINDOWS_57009, STRING_ENCODING_WINDOWS_57010, STRING_ENCODING_WINDOWS_57011, STRING_ENCODING_IBM_813, STRING_ENCODING_IBM_943_P130_1999, STRING_ENCODING_IBM_33722, STRING_ENCODING_WINDOWS_949, STRING_ENCODING_IBM_1363, STRING_ENCODING_IBM_1386, STRING_ENCODING_IBM_1373, STRING_ENCODING_IBM_5471, STRING_ENCODING_IBM_874, // Add more encodings here. // Sentinel value after the last explicitly specified encoding. STRING_ENCODING_MAX_SPECIFIED, /* * The environment-specified "default" encoding for this process. */ STRING_ENCODING_DEFAULT = -1, STRING_ENCODING_UNKNOWN = -2, /* * UTF-16 and UTF-32 in native byte order. */ STRING_ENCODING_UTF16 = STRING_ENCODING_UTF16_LE, STRING_ENCODING_UTF32 = STRING_ENCODING_UTF32_LE, } StringEncoding; const char *Unicode_EncodingEnumToName(StringEncoding encoding); StringEncoding Unicode_EncodingNameToEnum(const char *encodingName); Bool Unicode_IsEncodingValid(StringEncoding encoding); void Unicode_Init(int argc, char ***argv, char ***envp); void Unicode_InitEx(int argc, char ***argv, char ***envp, const char *icuDataDir); #if defined (_WIN32) void Unicode_InitW(int argc, utf16_t **wargv, utf16_t **wenvp, char ***argv, char ***envp); #endif void Unicode_Shutdown(int argc, char **argv, char **envp); StringEncoding Unicode_GetCurrentEncoding(void); StringEncoding Unicode_ResolveEncoding(StringEncoding encoding); #if defined(__cplusplus) } // extern "C" #endif #endif // _UNICODE_TYPES_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/userlock.h000066400000000000000000000271261470176644300245220ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2009-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _USERLOCK_H_ #define _USERLOCK_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include #include "vm_atomic.h" #include "vm_basic_types.h" #include "vm_basic_defs.h" #include "mutexRank.h" #include "vthreadBase.h" #if defined(__cplusplus) extern "C" { #endif typedef struct MXUserExclLock MXUserExclLock; typedef struct MXUserRecLock MXUserRecLock; typedef struct MXUserRWLock MXUserRWLock; typedef struct MXUserRankLock MXUserRankLock; typedef struct MXUserCondVar MXUserCondVar; typedef struct MXUserSemaphore MXUserSemaphore; typedef struct MXUserBinSemaphore MXUserBinSemaphore; typedef struct MXUserEvent MXUserEvent; typedef struct MXUserBarrier MXUserBarrier; /* * Exclusive ownership lock */ MXUserExclLock *MXUser_CreateExclLock(const char *name, MX_Rank rank); void MXUser_AcquireExclLock(MXUserExclLock *lock); Bool MXUser_TryAcquireExclLock(MXUserExclLock *lock); void MXUser_ReleaseExclLock(MXUserExclLock *lock); void MXUser_DestroyExclLock(MXUserExclLock *lock); Bool MXUser_IsCurThreadHoldingExclLock(MXUserExclLock *lock); /* Use only when necessary */ MXUserExclLock *MXUser_CreateSingletonExclLockInt(Atomic_Ptr *lockStorage, const char *name, MX_Rank rank); /* This is the public interface */ static INLINE MXUserExclLock * MXUser_CreateSingletonExclLock(Atomic_Ptr *lockStorage, const char *name, MX_Rank rank) { MXUserExclLock *lock; ASSERT(lockStorage); lock = (MXUserExclLock *) Atomic_ReadPtr(lockStorage); if (UNLIKELY(lock == NULL)) { lock = MXUser_CreateSingletonExclLockInt(lockStorage, name, rank); } return lock; } MXUserCondVar *MXUser_CreateCondVarExclLock(MXUserExclLock *lock); void MXUser_WaitCondVarExclLock(MXUserExclLock *lock, MXUserCondVar *condVar); void MXUser_TimedWaitCondVarExclLock(MXUserExclLock *lock, MXUserCondVar *condVar, uint32 waitTimeMS); Bool MXUser_EnableStatsExclLock(MXUserExclLock *lock, Bool trackAcquisitionTime, Bool trackHeldTime); Bool MXUser_DisableStatsExclLock(MXUserExclLock *lock); Bool MXUser_SetContentionRatioFloorExclLock(MXUserExclLock *lock, double ratio); Bool MXUser_SetContentionCountFloorExclLock(MXUserExclLock *lock, uint64 count); Bool MXUser_SetContentionDurationFloorExclLock(MXUserExclLock *lock, uint64 count); /* * Recursive lock. */ MXUserRecLock *MXUser_CreateRecLock(const char *name, MX_Rank rank); void MXUser_AcquireRecLock(MXUserRecLock *lock); Bool MXUser_TryAcquireRecLock(MXUserRecLock *lock); void MXUser_ReleaseRecLock(MXUserRecLock *lock); void MXUser_DestroyRecLock(MXUserRecLock *lock); Bool MXUser_IsCurThreadHoldingRecLock(MXUserRecLock *lock); /* Use only when necessary */ MXUserRecLock *MXUser_CreateSingletonRecLockInt(Atomic_Ptr *lockStorage, const char *name, MX_Rank rank); /* This is the public interface */ static INLINE MXUserRecLock * MXUser_CreateSingletonRecLock(Atomic_Ptr *lockStorage, const char *name, MX_Rank rank) { MXUserRecLock *lock; ASSERT(lockStorage); lock = (MXUserRecLock *) Atomic_ReadPtr(lockStorage); if (UNLIKELY(lock == NULL)) { lock = MXUser_CreateSingletonRecLockInt(lockStorage, name, rank); } return lock; } void MXUser_DumpRecLock(MXUserRecLock *lock); MXUserCondVar *MXUser_CreateCondVarRecLock(MXUserRecLock *lock); void MXUser_WaitCondVarRecLock(MXUserRecLock *lock, MXUserCondVar *condVar); void MXUser_TimedWaitCondVarRecLock(MXUserRecLock *lock, MXUserCondVar *condVar, uint32 waitTimeMS); void MXUser_IncRefRecLock(MXUserRecLock *lock); void MXUser_DecRefRecLock(MXUserRecLock *lock); Bool MXUser_EnableStatsRecLock(MXUserRecLock *lock, Bool trackAcquisitionTime, Bool trackHeldTime); Bool MXUser_DisableStatsRecLock(MXUserRecLock *lock); Bool MXUser_SetContentionRatioFloorRecLock(MXUserRecLock *lock, double ratio); Bool MXUser_SetContentionCountFloorRecLock(MXUserRecLock *lock, uint64 count); Bool MXUser_SetContentionDurationFloorRecLock(MXUserRecLock *lock, uint64 count); /* * Read-write lock */ MXUserRWLock *MXUser_CreateRWLock(const char *name, MX_Rank rank); void MXUser_AcquireForRead(MXUserRWLock *lock); void MXUser_AcquireForWrite(MXUserRWLock *lock); void MXUser_ReleaseRWLock(MXUserRWLock *lock); void MXUser_DestroyRWLock(MXUserRWLock *lock); #define MXUSER_RW_FOR_READ 0 #define MXUSER_RW_FOR_WRITE 1 #define MXUSER_RW_LOCKED 2 Bool MXUser_IsCurThreadHoldingRWLock(MXUserRWLock *lock, uint32 queryType); /* Use only when necessary */ MXUserRWLock *MXUser_CreateSingletonRWLockInt(Atomic_Ptr *lockStorage, const char *name, MX_Rank rank); /* This is the public interface */ static INLINE MXUserRWLock * MXUser_CreateSingletonRWLock(Atomic_Ptr *lockStorage, const char *name, MX_Rank rank) { MXUserRWLock *lock; ASSERT(lockStorage); lock = (MXUserRWLock *) Atomic_ReadPtr(lockStorage); if (UNLIKELY(lock == NULL)) { lock = MXUser_CreateSingletonRWLockInt(lockStorage, name, rank); } return lock; } /* * Stateful auto-reset event */ MXUserEvent *MXUser_CreateEvent(const char *name, MX_Rank rank); void MXUser_SignalEvent(MXUserEvent *event); void MXUser_WaitEvent(MXUserEvent *event); Bool MXUser_TryWaitEvent(MXUserEvent *event); PollDevHandle MXUser_GetHandleForEvent(MXUserEvent *event); void MXUser_DestroyEvent(MXUserEvent *event); MXUserEvent *MXUser_CreateSingletonEvent(Atomic_Ptr *eventStorage, const char *name, MX_Rank rank); /* * Computational barrier */ MXUserBarrier *MXUser_CreateBarrier(const char *name, MX_Rank rank, uint32 count); void MXUser_DestroyBarrier(MXUserBarrier *barrier); void MXUser_EnterBarrier(MXUserBarrier *barrier); MXUserBarrier *MXUser_CreateSingletonBarrier(Atomic_Ptr *barrierStorage, const char *name, MX_Rank rank, uint32 count); /* * Counting semaphore */ MXUserSemaphore *MXUser_CreateSemaphore(const char *name, MX_Rank rank); void MXUser_DestroySemaphore(MXUserSemaphore *sema); void MXUser_UpSemaphore(MXUserSemaphore *sema); void MXUser_DownSemaphore(MXUserSemaphore *sema); Bool MXUser_TryDownSemaphore(MXUserSemaphore *sema); Bool MXUser_TimedDownSemaphore(MXUserSemaphore *sema, uint32 waitTimeMS); Bool MXUser_TimedDownSemaphoreNS(MXUserSemaphore *sema, uint64 waitTimeNS); MXUserSemaphore *MXUser_CreateSingletonSemaphore(Atomic_Ptr *semaStorage, const char *name, MX_Rank rank); /* * Binary semaphore */ MXUserBinSemaphore *MXUser_CreateBinSemaphore(const char *name, MX_Rank rank); void MXUser_DestroyBinSemaphore(MXUserBinSemaphore *binSema); void MXUser_UpBinSemaphore(MXUserBinSemaphore *binSema); void MXUser_DownBinSemaphore(MXUserBinSemaphore *binSema); Bool MXUser_TryDownBinSemaphore(MXUserBinSemaphore *binSema); Bool MXUser_TimedDownBinSemaphore(MXUserBinSemaphore *binSema, uint32 waitTimeMS); Bool MXUser_TimedDownBinSemaphoreNS(MXUserBinSemaphore *binSema, uint64 waitTimeNS); /* * Rank lock * * Rank "locks" are entities that perform rank checking but do not provide * any form of mutual exclusion. Their main use is for protecting certain * situations involving Poll and friends/enemies. */ MXUserRankLock *MXUser_CreateRankLock(const char *name, MX_Rank rank); void MXUser_AcquireRankLock(MXUserRankLock *lock); void MXUser_ReleaseRankLock(MXUserRankLock *lock); void MXUser_DestroyRankLock(MXUserRankLock *lock); /* * Generic conditional variable functions. */ #define MXUSER_WAIT_INFINITE 0xFFFFFFFF void MXUser_SignalCondVar(MXUserCondVar *condVar); void MXUser_BroadcastCondVar(MXUserCondVar *condVar); void MXUser_DestroyCondVar(MXUserCondVar *condVar); void MXUser_LockingTreeCollection(Bool enabled); Bool MXUser_IsLockingTreeAvailable(void); void MXUser_DumpLockTree(const char *fileName, const char *timeStamp); void MXUser_EmptyLockTree(void); #if defined(VMX86_DEBUG) && !defined(DISABLE_MXUSER_DEBUG) #define MXUSER_DEBUG // debugging "everywhere" when requested #endif #if defined(MXUSER_DEBUG) void MXUser_TryAcquireFailureControl(Bool (*func)(const char *lockName)); Bool MXUser_IsCurThreadHoldingLocks(void); #endif void MXUser_StatisticsControl(double contentionRatioFloor, uint64 minAccessCountFloor, uint64 contentionDurationFloor); void MXUser_PerLockData(void); void MXUser_SetStatsFunc(void *context, uint32 maxLineLength, Bool trackHeldTime, void (*statsFunc)(void *context, const char *fmt, va_list ap)); void MXUser_SetInPanic(void); Bool MXUser_InPanic(void); struct MX_MutexRec; MXUserRecLock *MXUser_BindMXMutexRec(struct MX_MutexRec *mutex, MX_Rank rank); struct MX_MutexRec *MXUser_GetRecLockVmm(MXUserRecLock *lock); MX_Rank MXUser_GetRecLockRank(MXUserRecLock *lock); #if defined(__cplusplus) } // extern "C" #endif #endif // _USERLOCK_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/util.h000066400000000000000000000304721470176644300236460ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * util.h -- * * misc util functions */ #ifndef UTIL_H #define UTIL_H #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #ifndef VMKBOOT #include #include #include #ifdef _WIN32 #ifdef USERLEVEL #include /* Needed for MBCS string functions */ #include /* for definition of HANDLE */ #endif #else #include #include #include "errno.h" #endif #endif #include "vm_assert.h" #include "vm_basic_defs.h" #include "unicodeTypes.h" #include "utilZero.h" #if defined(__cplusplus) extern "C" { #endif uint32 CRC_Compute(const uint8 *buf, int len); uint32 Util_Checksum32(const uint32 *buf, int len); uint32 Util_Checksum(const uint8 *buf, int len); uint32 Util_Checksumv(void *iov, int numEntries); uint32 Util_HashString(const char *str); char *Util_ExpandString(const char *fileName); void Util_ExitThread(int); NORETURN void Util_ExitProcessAbruptly(int); int Util_HasAdminPriv(void); #if defined _WIN32 && defined USERLEVEL int Util_TokenHasAdminPriv(HANDLE token); #endif Bool Util_Data2Buffer(char *buf, size_t bufSize, const void *data0, size_t dataSize); Bool Util_Data2BufferEx(char *buf, size_t bufSize, const void *data0, size_t dataSize, char sep); char *Util_GetCanonicalPath(const char *path); #ifdef _WIN32 char *Util_CompatGetCanonicalPath(const char *path); char *Util_GetCanonicalPathForHash(const char *path); char *Util_CompatGetLowerCaseCanonicalPath(const char* path); #endif int Util_BumpNoFds(uint32 *cur, uint32 *wanted); Bool Util_CanonicalPathsIdentical(const char *path1, const char *path2); Bool Util_IsAbsolutePath(const char *path); char *Util_DeriveFileName(const char *source, const char *name, const char *ext); typedef struct UtilSingleUseResource UtilSingleUseResource; UtilSingleUseResource *Util_SingleUseAcquire(const char *name); void Util_SingleUseRelease(UtilSingleUseResource *res); #ifndef _WIN32 Bool Util_IPv4AddrValid(const char *addr); Bool Util_IPv6AddrValid(const char *addr); Bool Util_IPAddrValid(const char *addr); #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(sun) Bool Util_GetProcessName(pid_t pid, char *bufOut, size_t bufOutSize); #endif #if defined __linux__ && !defined VMX86_SERVER Bool Util_IsPhysicalSSD(const char* device); #endif // backtrace functions and utilities #define UTIL_BACKTRACE_LINE_LEN (511) typedef void (*Util_OutputFunc)(void *data, const char *fmt, ...); void Util_Backtrace(int bugNr); void Util_BacktraceWithFunc(int bugNr, Util_OutputFunc outFunc, void *outFuncData); // sleep functions void Util_Usleep(long usec); void Util_Sleep(unsigned int sec); int Util_CompareDotted(const char *s1, const char *s2); /* * This enum defines how Util_GetOpt should handle non-option arguments: * * UTIL_NONOPT_PERMUTE: Permute argv so that all non-options are at the end. * UTIL_NONOPT_STOP: Stop when first non-option argument is seen. (This is * the standard POSIX behavior.) * UTIL_NONOPT_ALL: Return each non-option argument as if it were * an option with character code 1. */ typedef enum { UTIL_NONOPT_PERMUTE, UTIL_NONOPT_STOP, UTIL_NONOPT_ALL } Util_NonOptMode; struct option; int Util_GetOpt(int argc, char * const *argv, const struct option *opts, Util_NonOptMode mode, Bool manualErrorHandling); #if defined(VMX86_STATS) Bool Util_QueryCStResidency(uint32 *numCpus, uint32 *numCStates, uint64 **transitns, uint64 **residency, uint64 **transTime, uint64 **residTime); #endif #define UTIL_FASTRAND_SEED_MAX (0x7fffffff) Bool Util_Throttle(uint32 count); uint32 Util_FastRand(uint32 seed); // Not thread safe! void Util_OverrideHomeDir(const char *path); Bool Util_MakeSureDirExistsAndAccessible(char const *path, unsigned int mode); #if _WIN32 # define DIRSEPS "\\" # define DIRSEPS_W L"\\" # define DIRSEPC '\\' # define DIRSEPC_W L'\\' # define VALID_DIRSEPS "\\/" # define VALID_DIRSEPS_W L"\\/" # define CUR_DIRS_W L"." # define CUR_DIRC_W L'.' #else # define DIRSEPS "/" # define DIRSEPC '/' # define VALID_DIRSEPS DIRSEPS #endif #define CURR_DIRS "." #define CURR_DIRC '.' /* *----------------------------------------------------------------------- * * Util_Safe[Malloc, Realloc, Calloc, Strdup] and * Util_Safe[Malloc, Realloc, Calloc, Strdup]Bug -- * * These functions work just like the standard C library functions * (except Util_SafeStrdup[,Bug]() accept NULL, see below), * but will not fail. Instead they Panic(), printing the file and * line number of the caller, if the underlying library function * fails. The Util_SafeFnBug functions print bugNumber in the * Panic() message. * * These functions should only be used when there is no way to * gracefully recover from the error condition. * * The internal versions of these functions expect a bug number * as the first argument. If that bug number is something other * than -1, the panic message will include the bug number. * * Since Util_SafeStrdup[,Bug]() do not need to return NULL * on error, they have been extended to accept the null pointer * (and return it). The competing view is that they should * panic on NULL. This is a convenience vs. strictness argument. * Convenience wins. -- edward * * Results: * The freshly allocated memory. * * Side effects: * Panic() if the library function fails. * *-------------------------------------------------------------------------- */ void *UtilSafeMalloc0(size_t size); void *UtilSafeMalloc1(size_t size, int bugNumber, const char *file, int lineno); void *UtilSafeRealloc0(void *ptr, size_t size); void *UtilSafeRealloc1(void *ptr, size_t size, int bugNumber, const char *file, int lineno); void *UtilSafeCalloc0(size_t nmemb, size_t size); void *UtilSafeCalloc1(size_t nmemb, size_t size, int bugNumber, const char *file, int lineno); char *UtilSafeStrdup0(const char *s); char *UtilSafeStrdup1(const char *s, int bugNumber, const char *file, int lineno); char *UtilSafeStrndup0(const char *s, size_t n); char *UtilSafeStrndup1(const char *s, size_t n, int bugNumber, const char *file, int lineno); /* * Debug builds carry extra arguments into the allocation functions for * better error reporting. Non-debug builds don't pay this extra overhead. */ #ifdef VMX86_DEBUG #define Util_SafeMalloc(_size) \ UtilSafeMalloc1((_size), -1, __FILE__, __LINE__) #define Util_SafeMallocBug(_bugNr, _size) \ UtilSafeMalloc1((_size),(_bugNr), __FILE__, __LINE__) #define Util_SafeRealloc(_ptr, _size) \ UtilSafeRealloc1((_ptr), (_size), -1, __FILE__, __LINE__) #define Util_SafeReallocBug(_bugNr, _ptr, _size) \ UtilSafeRealloc1((_ptr), (_size), (_bugNr), __FILE__, __LINE__) #define Util_SafeCalloc(_nmemb, _size) \ UtilSafeCalloc1((_nmemb), (_size), -1, __FILE__, __LINE__) #define Util_SafeCallocBug(_bugNr, _nmemb, _size) \ UtilSafeCalloc1((_nmemb), (_size), (_bugNr), __FILE__, __LINE__) #define Util_SafeStrndup(_str, _size) \ UtilSafeStrndup1((_str), (_size), -1, __FILE__, __LINE__) #define Util_SafeStrndupBug(_bugNr, _str, _size) \ UtilSafeStrndup1((_str), (_size), (_bugNr), __FILE__, __LINE__) #define Util_SafeStrdup(_str) \ UtilSafeStrdup1((_str), -1, __FILE__, __LINE__) #define Util_SafeStrdupBug(_bugNr, _str) \ UtilSafeStrdup1((_str), (_bugNr), __FILE__, __LINE__) #else /* VMX86_DEBUG */ #define Util_SafeMalloc(_size) \ UtilSafeMalloc0((_size)) #define Util_SafeMallocBug(_bugNr, _size) \ UtilSafeMalloc0((_size)) #define Util_SafeRealloc(_ptr, _size) \ UtilSafeRealloc0((_ptr), (_size)) #define Util_SafeReallocBug(_ptr, _size) \ UtilSafeRealloc0((_ptr), (_size)) #define Util_SafeCalloc(_nmemb, _size) \ UtilSafeCalloc0((_nmemb), (_size)) #define Util_SafeCallocBug(_bugNr, _nmemb, _size) \ UtilSafeCalloc0((_nmemb), (_size)) #define Util_SafeStrndup(_str, _size) \ UtilSafeStrndup0((_str), (_size)) #define Util_SafeStrndupBug(_bugNr, _str, _size) \ UtilSafeStrndup0((_str), (_size)) #define Util_SafeStrdup(_str) \ UtilSafeStrdup0((_str)) #define Util_SafeStrdupBug(_bugNr, _str) \ UtilSafeStrdup0((_str)) #endif /* VMX86_DEBUG */ void *Util_Memdup(const void *src, size_t size); void *Util_Memcpy(void *dest, const void *src, size_t count); void Util_Memfree(void *ptr); Bool Util_ConstTimeMemDiff(const void *secret, const void *guess, size_t len); Bool Util_ConstTimeStrDiff(const char *secret, const char *guess); #ifndef VMKBOOT /* *----------------------------------------------------------------------------- * * Util_FreeList -- * Util_FreeStringList -- * * Free a list (actually a vector) of allocated objects. * The list (vector) itself is also freed. * * The list either has a specified length or is * argv-style NULL terminated (if length is negative). * * The list can be NULL, in which case no operation is performed. * * Results: * None * * Side effects: * errno or Windows last error is preserved. * *----------------------------------------------------------------------------- */ static INLINE void Util_FreeList(void **list, // IN/OUT/OPT: the list to free ssize_t length) // IN: the length { // See Posix_Free. int err; if (list == NULL) { ASSERT(length <= 0); return; } err = errno; if (length >= 0) { ssize_t i; for (i = 0; i < length; i++) { free(list[i]); DEBUG_ONLY(list[i] = NULL); } } else { void **s; for (s = list; *s != NULL; s++) { free(*s); DEBUG_ONLY(*s = NULL); } } free(list); errno = err; } static INLINE void Util_FreeStringList(char **list, // IN/OUT/OPT: the list to free ssize_t length) // IN: the length { Util_FreeList((void **) list, length); } #endif /* VMKBOOT */ /* *----------------------------------------------------------------------------- * * Util_Memcpy32 -- * * Special purpose version of memcpy that requires nbytes be a * multiple of 4. This assumption lets us have a very small, * inlineable implementation. * * Results: * dst * * Side effects: * See above. * *----------------------------------------------------------------------------- */ static INLINE void * Util_Memcpy32(void *dst, const void *src, size_t nbytes) { ASSERT((nbytes % 4) == 0); #if defined __GNUC__ && (defined(__i386__) || defined(__x86_64__)) do { int dummy0, dummy1, dummy2; __asm__ __volatile__( "cld \n\t" "rep ; movsl" "\n\t" : "=&c" (dummy0), "=&D" (dummy1), "=&S" (dummy2) : "0" (nbytes / 4), "1" ((long) dst), "2" ((long) src) : "memory", "cc" ); return dst; } while (0); #else return memcpy(dst, src, nbytes); #endif } #if defined(__cplusplus) } // extern "C" #endif #endif /* UTIL_H */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/utilZero.h000066400000000000000000000154351470176644300245100ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2017-2024 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * utilZero.h -- * * Utility functions for zeroing memory, and verifying memory is * zeroed. */ #ifndef UTIL_ZERO_H #define UTIL_ZERO_H #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #ifdef VMKBOOT #include "vm_libc.h" #else #include #include #ifndef _WIN32 #include #include #include #endif #endif #include "vm_assert.h" #include "vm_basic_defs.h" #include "unicodeTypes.h" #if defined(__cplusplus) extern "C" { #endif /* *----------------------------------------------------------------------------- * * Util_ValidateBytes -- * * Check that memory is filled with the specified value. * * Results: * NULL No error * !NULL First address that doesn't have the proper value * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void * Util_ValidateBytes(const void *ptr, // IN: ptr to check size_t size, // IN: size of ptr uint8 byteValue) // IN: memory must be filled with this { uint8 *p; uint8 *end; uint64 bigValue; ASSERT(ptr); if (size == 0) { return NULL; } p = (uint8 *) ptr; end = p + size; /* Compare bytes until a "nice" boundary is achieved. */ while ((uintptr_t) p % sizeof bigValue) { if (*p != byteValue) { return p; } p++; if (p == end) { return NULL; } } /* Compare using a "nice sized" chunk for a long as possible. */ memset(&bigValue, (int) byteValue, sizeof bigValue); while (p + sizeof bigValue <= end) { if (*((uint64 *) p) != bigValue) { /* That's not right... let the loop below report the exact address. */ break; } size -= sizeof bigValue; p += sizeof bigValue; } /* Handle any trailing bytes. */ while (p < end) { if (*p != byteValue) { return p; } p++; } return NULL; } /* *---------------------------------------------------------------------- * * Util_BufferIsEmpty -- * * Determine if the specified buffer of 'len' bytes starting at 'base' * is empty (i.e. full of zeroes). * * Results: * TRUE Yes * FALSE No * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE Bool Util_BufferIsEmpty(void const *base, // IN: size_t len) // IN: { return Util_ValidateBytes(base, len, '\0') == NULL; } /* *----------------------------------------------------------------------------- * * Util_Zero -- * * Zeros out bufSize bytes of buf. NULL is legal. * * Results: * None. * * Side effects: * See above. * *----------------------------------------------------------------------------- */ static INLINE void Util_Zero(void *buf, // OUT size_t bufSize) // IN { if (buf != NULL) { #if defined _WIN32 && defined USERLEVEL /* * Simple memset calls might be optimized out. See CERT advisory * MSC06-C. */ SecureZeroMemory(buf, bufSize); #else memset(buf, 0, bufSize); #if !defined _WIN32 /* * Memset calls before free might be optimized out. See PR1248269. */ __asm__ __volatile__("" : : "r"(&buf) : "memory"); #endif #endif } } /* *----------------------------------------------------------------------------- * * Util_ZeroString -- * * Zeros out a NULL-terminated string. NULL is legal. * * Results: * None. * * Side effects: * See above. * *----------------------------------------------------------------------------- */ static INLINE void Util_ZeroString(char *str) // IN/OUT/OPT { if (str != NULL) { Util_Zero(str, strlen(str)); } } #ifndef VMKBOOT /* *----------------------------------------------------------------------------- * * Util_ZeroFree -- * * Zeros out bufSize bytes of buf, and then frees it. NULL is * legal. * * Results: * None. * * Side effects: * buf is zeroed, and then free() is called on it. * *----------------------------------------------------------------------------- */ static INLINE void Util_ZeroFree(void *buf, // OUT/OPT size_t bufSize) // IN { if (buf != NULL) { // See Posix_Free. int err = errno; Util_Zero(buf, bufSize); free(buf); errno = err; } } /* *----------------------------------------------------------------------------- * * Util_ZeroFreeString -- * * Zeros out a NULL-terminated string, and then frees it. NULL is * legal. * * Results: * None. * * Side effects: * str is zeroed, and then free() is called on it. * *----------------------------------------------------------------------------- */ static INLINE void Util_ZeroFreeString(char *str) // IN/OUT/OPT { if (str != NULL) { // See Posix_Free. int err = errno; Util_ZeroString(str); free(str); errno = err; } } #endif /* VMKBOOT */ #ifdef _WIN32 /* *----------------------------------------------------------------------------- * * Util_ZeroFreeStringW -- * * Zeros out a NUL-terminated wide-character string, and then frees it. * NULL is legal. * * Results: * None. * * Side effects: * str is zeroed, and then free() is called on it. * *----------------------------------------------------------------------------- */ static INLINE void Util_ZeroFreeStringW(wchar_t *str) // IN/OUT/OPT { if (str != NULL) { // See Posix_Free. int err = errno; Util_Zero(str, wcslen(str) * sizeof *str); free(str); errno = err; } } #endif /* _WIN32 */ #if defined(__cplusplus) } // extern "C" #endif #endif /* UTIL_ZERO_H */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/uuid.h000066400000000000000000000142321470176644300236330ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * uuid.h -- * * UUID generation */ #ifndef _UUID_H_ #define _UUID_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL // for typedefs only #include "includeCheck.h" #if defined(__cplusplus) extern "C" { #endif #define UUID_SIZE 16 #define UUID_STRSIZE (2*UUID_SIZE + 1) #define UUID_MAXLEN 48 /* * ISO 11578 (now X.667 section 6.4) defines the canonical text format of a * UUID, which looks like this example: * * "f81d4fae-7dec-11d0-a765-00a0c91e6bf6" * * It is always precisely 36 characters long (excluding terminating NUL). */ #define UUID_ISO_11578_LEN 36 typedef enum { UUID_WITH_PATH = 0, UUID_RANDOM, UUID_VPX_BIOS, UUID_VPX_INSTANCE, UUID_UNKNOWN } UUIDStyle; /* Scheme control */ #define UUID_CREATE_WS6 0 /* the WS6 scheme - "native" path */ #define UUID_CREATE_WS65 1 /* the WS65 scheme - UTF-8 path */ #define UUID_CREATE_ESXi2018 2 /* UTF-8 path, no host UUID for >= 2018 ESXi */ #define UUID_CREATE_CURRENT 2 /* the current scheme - always the latest */ /* * RFC 4122-compliant UUIDs and UEFI/Microsoft GUIDs are essentially * the same thing except for byte-ordering issues. Although their * fields are named differently, the meanings are the same. The only * important difference is that RFC 4122 recommends always storing and * transmitting binary UUIDs with the multi-byte fields in network * byte order (big-endian), while binary UEFI/Microsoft GUIDs are * typically stored and transmitted with the first three fields in x86 * CPU native order (little-endian). But both UUIDs and GUIDs use the * same canonical text format representation, in which the hex digits * are in big-endian order. Details of each are below. */ /* * An RFC 4122-compliant UUID. * * See RFC 4122 section 4.1.2 (Layout and Byte Order). The RFC * recommends that multi-byte types be stored in big-endian (most * significant byte first) order. * * The UUID packed text string * 00112233-4455-6677-8899-AABBCCDDEEFF * represents * timeLow = 0x00112233 * timeMid = 0x4455 * timeHiAndVersion = 0x6677 * clockSeqHiAndReserved = 0x88 * clockSeqLow = 0x99 * node[0] = 0xAA * node[1] = 0xBB * node[2] = 0xCC * node[3] = 0xDD * node[4] = 0xEE * node[5] = 0xFF * and the structure is stored as the sequence of bytes * 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF * * Confusingly, some applications use the field names from this * definition but store timeLow, timeMid, and timeHiAndVersion in * little-endian order as UEFI/Microsoft GUIDs do; for example, the * SMBIOS standard does so. In that case, the structure is stored as * the sequence of bytes * 33 22 11 00 55 44 77 66 88 99 AA BB CC DD EE FF */ #pragma pack(push, 1) typedef struct { uint32 timeLow; uint16 timeMid; uint16 timeHiAndVersion; uint8 clockSeqHiAndReserved; uint8 clockSeqLow; uint8 node[6]; } UUIDRFC4122; #pragma pack(pop) /* * An EFI/UEFI/Microsoft-compliant GUID. * * See MdeModulePkg/Universal/DevicePathDxe/DevicePathFromText.c::StrToGuid(), * BaseTools/Source/C/Common/ParseInf.c::StringToGuid(), * http://en.wikipedia.org/wiki/GUID . All multi-byte types are stored in CPU * (a.k.a. native) byte order. * * The GUID packed text string * 00112233-4455-6677-8899-AABBCCDDEEFF * represents * data1 = 0x00112233 * data2 = 0x4455 * data3 = 0x6677 * data4[0] = 0x88 * data4[1] = 0x99 * data4[2] = 0xAA * data4[3] = 0xBB * data4[4] = 0xCC * data4[5] = 0xDD * data4[6] = 0xEE * data4[7] = 0xFF * and the structure is stored as the sequence of bytes * big-endian CPU: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF * little-endian CPU: 33 22 11 00 55 44 77 66 88 99 AA BB CC DD EE FF */ #pragma pack(push, 1) typedef struct { uint32 data1; uint16 data2; uint16 data3; uint8 data4[8]; } EFIGUID; #pragma pack(pop) Bool UUID_ConvertPackedToBin(EFIGUID *destID, const char *text); Bool UUID_ConvertPackedToUUIDRFC4122(UUIDRFC4122 *destID, const char *text); Bool UUID_ConvertToBin(uint8 dest_id[UUID_SIZE], const char *text); char *UUID_ConvertToText(const uint8 id[UUID_SIZE]); void UUID_ConvertToTextBuf(const uint8 id[UUID_SIZE], char *buffer, size_t len); char *UUID_CreateLocation(const char *configFileFullPath, int schemeControl); char *UUID_CreateRandom(void); Bool UUID_CreateRandomRFC4122V4(UUIDRFC4122 *id); Bool UUID_CreateRandomEFI(EFIGUID *id); char *UUID_CreateRandomVpxStyle(uint8 vpxdId, UUIDStyle); Bool UUID_IsUUIDGeneratedByThatVpxd(const uint8 *id, int vpxdInstanceId); char *UUID_PackText(const char *text, char *pack, size_t packLen); char *UUID_ProperHostUUID(void); char *UUID_GetHostUUID(void); UUIDStyle UUID_GetStyle(const uint8 *id); Bool UUID_Equal(const uint8 id1[UUID_SIZE], const uint8 id2[UUID_SIZE]); /* Like UUID_GetHostUUID, except gets actual host UUID */ char *UUID_GetRealHostUUID(void); #if defined(__cplusplus) } // extern "C" #endif #endif open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vix.h000066400000000000000000001326071470176644300235020ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2004-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * This is the C interface to the VIX API. * This is platform-independent. */ #ifndef _VIX_H_ #define _VIX_H_ #ifdef __cplusplus extern "C" { #endif /* *----------------------------------------------------------------------------- * * Basic Types -- * *----------------------------------------------------------------------------- */ #include "vm_basic_types.h" typedef int VixHandle; enum { VIX_INVALID_HANDLE = 0, }; /* * These are the types of handles. */ typedef int VixHandleType; enum { VIX_HANDLETYPE_NONE = 0, VIX_HANDLETYPE_HOST = 2, VIX_HANDLETYPE_VM = 3, VIX_HANDLETYPE_NETWORK = 5, VIX_HANDLETYPE_JOB = 6, VIX_HANDLETYPE_SNAPSHOT = 7, VIX_HANDLETYPE_PROPERTY_LIST = 9, VIX_HANDLETYPE_METADATA_CONTAINER = 11 }; /* * The "//{{ Begin VIX_ERROR }}" and "//{{ End VIX_ERROR }}" lines are * to bracket the error code definitions that will be copied over * to vixDiskLib.h during build time. If you modify these two lines, please * make sure you also change bora/lib/distribute/vixDiskLib.h and * bora/support/scripts/replaceVixErrors.py */ // {{ Begin VIX_ERROR }} /* * An error is a 64-bit value. If there is no error, then the value is * set to VIX_OK. If there is an error, then the least significant bits * will be set to one of the integer error codes defined below. The more * significant bits may or may not be set to various values, depending on * the errors. */ typedef uint64 VixError; #define VIX_ERROR_CODE(err) ((err) & 0xFFFF) #define VIX_SUCCEEDED(err) (VIX_OK == (err)) #define VIX_FAILED(err) (VIX_OK != (err)) /* * The error codes are returned by all public VIX routines. */ enum { VIX_OK = 0, /* General errors */ VIX_E_FAIL = 1, VIX_E_OUT_OF_MEMORY = 2, VIX_E_INVALID_ARG = 3, VIX_E_FILE_NOT_FOUND = 4, VIX_E_OBJECT_IS_BUSY = 5, VIX_E_NOT_SUPPORTED = 6, VIX_E_FILE_ERROR = 7, VIX_E_DISK_FULL = 8, VIX_E_INCORRECT_FILE_TYPE = 9, VIX_E_CANCELLED = 10, VIX_E_FILE_READ_ONLY = 11, VIX_E_FILE_ALREADY_EXISTS = 12, VIX_E_FILE_ACCESS_ERROR = 13, VIX_E_REQUIRES_LARGE_FILES = 14, VIX_E_FILE_ALREADY_LOCKED = 15, VIX_E_VMDB = 16, VIX_E_NOT_SUPPORTED_ON_REMOTE_OBJECT = 20, VIX_E_FILE_TOO_BIG = 21, VIX_E_FILE_NAME_INVALID = 22, VIX_E_ALREADY_EXISTS = 23, VIX_E_BUFFER_TOOSMALL = 24, VIX_E_OBJECT_NOT_FOUND = 25, VIX_E_HOST_NOT_CONNECTED = 26, VIX_E_INVALID_UTF8_STRING = 27, VIX_E_OPERATION_ALREADY_IN_PROGRESS = 31, VIX_E_UNFINISHED_JOB = 29, VIX_E_NEED_KEY = 30, VIX_E_LICENSE = 32, VIX_E_VM_HOST_DISCONNECTED = 34, VIX_E_AUTHENTICATION_FAIL = 35, VIX_E_HOST_CONNECTION_LOST = 36, VIX_E_DUPLICATE_NAME = 41, VIX_E_ARGUMENT_TOO_BIG = 44, /* Handle Errors */ VIX_E_INVALID_HANDLE = 1000, VIX_E_NOT_SUPPORTED_ON_HANDLE_TYPE = 1001, VIX_E_TOO_MANY_HANDLES = 1002, /* XML errors */ VIX_E_NOT_FOUND = 2000, VIX_E_TYPE_MISMATCH = 2001, VIX_E_INVALID_XML = 2002, /* VM Control Errors */ VIX_E_TIMEOUT_WAITING_FOR_TOOLS = 3000, VIX_E_UNRECOGNIZED_COMMAND = 3001, VIX_E_OP_NOT_SUPPORTED_ON_GUEST = 3003, VIX_E_PROGRAM_NOT_STARTED = 3004, VIX_E_CANNOT_START_READ_ONLY_VM = 3005, VIX_E_VM_NOT_RUNNING = 3006, VIX_E_VM_IS_RUNNING = 3007, VIX_E_CANNOT_CONNECT_TO_VM = 3008, VIX_E_POWEROP_SCRIPTS_NOT_AVAILABLE = 3009, VIX_E_NO_GUEST_OS_INSTALLED = 3010, VIX_E_VM_INSUFFICIENT_HOST_MEMORY = 3011, VIX_E_SUSPEND_ERROR = 3012, VIX_E_VM_NOT_ENOUGH_CPUS = 3013, VIX_E_HOST_USER_PERMISSIONS = 3014, VIX_E_GUEST_USER_PERMISSIONS = 3015, VIX_E_TOOLS_NOT_RUNNING = 3016, VIX_E_GUEST_OPERATIONS_PROHIBITED = 3017, VIX_E_ANON_GUEST_OPERATIONS_PROHIBITED = 3018, VIX_E_ROOT_GUEST_OPERATIONS_PROHIBITED = 3019, VIX_E_MISSING_ANON_GUEST_ACCOUNT = 3023, VIX_E_CANNOT_AUTHENTICATE_WITH_GUEST = 3024, VIX_E_UNRECOGNIZED_COMMAND_IN_GUEST = 3025, VIX_E_CONSOLE_GUEST_OPERATIONS_PROHIBITED = 3026, VIX_E_MUST_BE_CONSOLE_USER = 3027, VIX_E_VMX_MSG_DIALOG_AND_NO_UI = 3028, /* VIX_E_NOT_ALLOWED_DURING_VM_RECORDING = 3029, Removed in version 1.11 */ /* VIX_E_NOT_ALLOWED_DURING_VM_REPLAY = 3030, Removed in version 1.11 */ VIX_E_OPERATION_NOT_ALLOWED_FOR_LOGIN_TYPE = 3031, VIX_E_LOGIN_TYPE_NOT_SUPPORTED = 3032, VIX_E_EMPTY_PASSWORD_NOT_ALLOWED_IN_GUEST = 3033, VIX_E_INTERACTIVE_SESSION_NOT_PRESENT = 3034, VIX_E_INTERACTIVE_SESSION_USER_MISMATCH = 3035, /* VIX_E_UNABLE_TO_REPLAY_VM = 3039, Removed in version 1.11 */ VIX_E_CANNOT_POWER_ON_VM = 3041, VIX_E_NO_DISPLAY_SERVER = 3043, /* VIX_E_VM_NOT_RECORDING = 3044, Removed in version 1.11 */ /* VIX_E_VM_NOT_REPLAYING = 3045, Removed in version 1.11 */ VIX_E_TOO_MANY_LOGONS = 3046, VIX_E_INVALID_AUTHENTICATION_SESSION = 3047, /* VM Errors */ VIX_E_VM_NOT_FOUND = 4000, VIX_E_NOT_SUPPORTED_FOR_VM_VERSION = 4001, VIX_E_CANNOT_READ_VM_CONFIG = 4002, VIX_E_TEMPLATE_VM = 4003, VIX_E_VM_ALREADY_LOADED = 4004, VIX_E_VM_ALREADY_UP_TO_DATE = 4006, VIX_E_VM_UNSUPPORTED_GUEST = 4011, /* Property Errors */ VIX_E_UNRECOGNIZED_PROPERTY = 6000, VIX_E_INVALID_PROPERTY_VALUE = 6001, VIX_E_READ_ONLY_PROPERTY = 6002, VIX_E_MISSING_REQUIRED_PROPERTY = 6003, VIX_E_INVALID_SERIALIZED_DATA = 6004, VIX_E_PROPERTY_TYPE_MISMATCH = 6005, /* Completion Errors */ VIX_E_BAD_VM_INDEX = 8000, /* Message errors */ VIX_E_INVALID_MESSAGE_HEADER = 10000, VIX_E_INVALID_MESSAGE_BODY = 10001, /* Snapshot errors */ VIX_E_SNAPSHOT_INVAL = 13000, VIX_E_SNAPSHOT_DUMPER = 13001, VIX_E_SNAPSHOT_DISKLIB = 13002, VIX_E_SNAPSHOT_NOTFOUND = 13003, VIX_E_SNAPSHOT_EXISTS = 13004, VIX_E_SNAPSHOT_VERSION = 13005, VIX_E_SNAPSHOT_NOPERM = 13006, VIX_E_SNAPSHOT_CONFIG = 13007, VIX_E_SNAPSHOT_NOCHANGE = 13008, VIX_E_SNAPSHOT_CHECKPOINT = 13009, VIX_E_SNAPSHOT_LOCKED = 13010, VIX_E_SNAPSHOT_INCONSISTENT = 13011, VIX_E_SNAPSHOT_NAMETOOLONG = 13012, VIX_E_SNAPSHOT_VIXFILE = 13013, VIX_E_SNAPSHOT_DISKLOCKED = 13014, VIX_E_SNAPSHOT_DUPLICATEDDISK = 13015, VIX_E_SNAPSHOT_INDEPENDENTDISK = 13016, VIX_E_SNAPSHOT_NONUNIQUE_NAME = 13017, VIX_E_SNAPSHOT_MEMORY_ON_INDEPENDENT_DISK = 13018, VIX_E_SNAPSHOT_MAXSNAPSHOTS = 13019, VIX_E_SNAPSHOT_MIN_FREE_SPACE = 13020, VIX_E_SNAPSHOT_HIERARCHY_TOODEEP = 13021, // DEPRECRATED VIX_E_SNAPSHOT_RRSUSPEND = 13022, VIX_E_SNAPSHOT_NOT_REVERTABLE = 13024, /* Host Errors */ VIX_E_HOST_DISK_INVALID_VALUE = 14003, VIX_E_HOST_DISK_SECTORSIZE = 14004, VIX_E_HOST_FILE_ERROR_EOF = 14005, VIX_E_HOST_NETBLKDEV_HANDSHAKE = 14006, VIX_E_HOST_SOCKET_CREATION_ERROR = 14007, VIX_E_HOST_SERVER_NOT_FOUND = 14008, VIX_E_HOST_NETWORK_CONN_REFUSED = 14009, VIX_E_HOST_TCP_SOCKET_ERROR = 14010, VIX_E_HOST_TCP_CONN_LOST = 14011, VIX_E_HOST_NBD_HASHFILE_VOLUME = 14012, VIX_E_HOST_NBD_HASHFILE_INIT = 14013, VIX_E_HOST_SERVER_SHUTDOWN = 14014, VIX_E_HOST_SERVER_NOT_AVAILABLE = 14015, /* Disklib errors */ VIX_E_DISK_INVAL = 16000, VIX_E_DISK_NOINIT = 16001, VIX_E_DISK_NOIO = 16002, VIX_E_DISK_PARTIALCHAIN = 16003, VIX_E_DISK_NEEDSREPAIR = 16006, VIX_E_DISK_OUTOFRANGE = 16007, VIX_E_DISK_CID_MISMATCH = 16008, VIX_E_DISK_CANTSHRINK = 16009, VIX_E_DISK_PARTMISMATCH = 16010, VIX_E_DISK_UNSUPPORTEDDISKVERSION = 16011, VIX_E_DISK_OPENPARENT = 16012, VIX_E_DISK_NOTSUPPORTED = 16013, VIX_E_DISK_NEEDKEY = 16014, VIX_E_DISK_NOKEYOVERRIDE = 16015, VIX_E_DISK_NOTENCRYPTED = 16016, VIX_E_DISK_NOKEY = 16017, VIX_E_DISK_INVALIDPARTITIONTABLE = 16018, VIX_E_DISK_NOTNORMAL = 16019, VIX_E_DISK_NOTENCDESC = 16020, VIX_E_DISK_NEEDVMFS = 16022, VIX_E_DISK_RAWTOOBIG = 16024, VIX_E_DISK_TOOMANYOPENFILES = 16027, VIX_E_DISK_TOOMANYREDO = 16028, VIX_E_DISK_RAWTOOSMALL = 16029, VIX_E_DISK_INVALIDCHAIN = 16030, VIX_E_DISK_KEY_NOTFOUND = 16052, // metadata key is not found VIX_E_DISK_SUBSYSTEM_INIT_FAIL = 16053, VIX_E_DISK_INVALID_CONNECTION = 16054, VIX_E_DISK_ENCODING = 16061, VIX_E_DISK_CANTREPAIR = 16062, VIX_E_DISK_INVALIDDISK = 16063, VIX_E_DISK_NOLICENSE = 16064, VIX_E_DISK_NODEVICE = 16065, VIX_E_DISK_UNSUPPORTEDDEVICE = 16066, VIX_E_DISK_CAPACITY_MISMATCH = 16067, VIX_E_DISK_PARENT_NOTALLOWED = 16068, VIX_E_DISK_ATTACH_ROOTLINK = 16069, /* Crypto Library Errors */ VIX_E_CRYPTO_UNKNOWN_ALGORITHM = 17000, VIX_E_CRYPTO_BAD_BUFFER_SIZE = 17001, VIX_E_CRYPTO_INVALID_OPERATION = 17002, VIX_E_CRYPTO_RANDOM_DEVICE = 17003, VIX_E_CRYPTO_NEED_PASSWORD = 17004, VIX_E_CRYPTO_BAD_PASSWORD = 17005, VIX_E_CRYPTO_NOT_IN_DICTIONARY = 17006, VIX_E_CRYPTO_NO_CRYPTO = 17007, VIX_E_CRYPTO_ERROR = 17008, VIX_E_CRYPTO_BAD_FORMAT = 17009, VIX_E_CRYPTO_LOCKED = 17010, VIX_E_CRYPTO_EMPTY = 17011, VIX_E_CRYPTO_KEYSAFE_LOCATOR = 17012, /* Remoting Errors. */ VIX_E_CANNOT_CONNECT_TO_HOST = 18000, VIX_E_NOT_FOR_REMOTE_HOST = 18001, VIX_E_INVALID_HOSTNAME_SPECIFICATION = 18002, /* Screen Capture Errors. */ VIX_E_SCREEN_CAPTURE_ERROR = 19000, VIX_E_SCREEN_CAPTURE_BAD_FORMAT = 19001, VIX_E_SCREEN_CAPTURE_COMPRESSION_FAIL = 19002, VIX_E_SCREEN_CAPTURE_LARGE_DATA = 19003, /* Guest Errors */ VIX_E_GUEST_VOLUMES_NOT_FROZEN = 20000, VIX_E_NOT_A_FILE = 20001, VIX_E_NOT_A_DIRECTORY = 20002, VIX_E_NO_SUCH_PROCESS = 20003, VIX_E_FILE_NAME_TOO_LONG = 20004, VIX_E_OPERATION_DISABLED = 20005, /* Tools install errors */ VIX_E_TOOLS_INSTALL_NO_IMAGE = 21000, VIX_E_TOOLS_INSTALL_IMAGE_INACCESIBLE = 21001, VIX_E_TOOLS_INSTALL_NO_DEVICE = 21002, VIX_E_TOOLS_INSTALL_DEVICE_NOT_CONNECTED = 21003, VIX_E_TOOLS_INSTALL_CANCELLED = 21004, VIX_E_TOOLS_INSTALL_INIT_FAILED = 21005, VIX_E_TOOLS_INSTALL_AUTO_NOT_SUPPORTED = 21006, VIX_E_TOOLS_INSTALL_GUEST_NOT_READY = 21007, VIX_E_TOOLS_INSTALL_SIG_CHECK_FAILED = 21008, VIX_E_TOOLS_INSTALL_ERROR = 21009, VIX_E_TOOLS_INSTALL_ALREADY_UP_TO_DATE = 21010, VIX_E_TOOLS_INSTALL_IN_PROGRESS = 21011, VIX_E_TOOLS_INSTALL_IMAGE_COPY_FAILED = 21012, /* Wrapper Errors */ VIX_E_WRAPPER_WORKSTATION_NOT_INSTALLED = 22001, VIX_E_WRAPPER_VERSION_NOT_FOUND = 22002, VIX_E_WRAPPER_SERVICEPROVIDER_NOT_FOUND = 22003, VIX_E_WRAPPER_PLAYER_NOT_INSTALLED = 22004, VIX_E_WRAPPER_RUNTIME_NOT_INSTALLED = 22005, VIX_E_WRAPPER_MULTIPLE_SERVICEPROVIDERS = 22006, /* FuseMnt errors*/ VIX_E_MNTAPI_MOUNTPT_NOT_FOUND = 24000, VIX_E_MNTAPI_MOUNTPT_IN_USE = 24001, VIX_E_MNTAPI_DISK_NOT_FOUND = 24002, VIX_E_MNTAPI_DISK_NOT_MOUNTED = 24003, VIX_E_MNTAPI_DISK_IS_MOUNTED = 24004, VIX_E_MNTAPI_DISK_NOT_SAFE = 24005, VIX_E_MNTAPI_DISK_CANT_OPEN = 24006, VIX_E_MNTAPI_CANT_READ_PARTS = 24007, VIX_E_MNTAPI_UMOUNT_APP_NOT_FOUND = 24008, VIX_E_MNTAPI_UMOUNT = 24009, VIX_E_MNTAPI_NO_MOUNTABLE_PARTITONS = 24010, VIX_E_MNTAPI_PARTITION_RANGE = 24011, VIX_E_MNTAPI_PERM = 24012, VIX_E_MNTAPI_DICT = 24013, VIX_E_MNTAPI_DICT_LOCKED = 24014, VIX_E_MNTAPI_OPEN_HANDLES = 24015, VIX_E_MNTAPI_CANT_MAKE_VAR_DIR = 24016, VIX_E_MNTAPI_NO_ROOT = 24017, VIX_E_MNTAPI_LOOP_FAILED = 24018, VIX_E_MNTAPI_DAEMON = 24019, VIX_E_MNTAPI_INTERNAL = 24020, VIX_E_MNTAPI_SYSTEM = 24021, VIX_E_MNTAPI_NO_CONNECTION_DETAILS = 24022, /* FuseMnt errors: Do not exceed 24299 */ /* VixMntapi errors*/ VIX_E_MNTAPI_INCOMPATIBLE_VERSION = 24300, VIX_E_MNTAPI_OS_ERROR = 24301, VIX_E_MNTAPI_DRIVE_LETTER_IN_USE = 24302, VIX_E_MNTAPI_DRIVE_LETTER_ALREADY_ASSIGNED = 24303, VIX_E_MNTAPI_VOLUME_NOT_MOUNTED = 24304, VIX_E_MNTAPI_VOLUME_ALREADY_MOUNTED = 24305, VIX_E_MNTAPI_FORMAT_FAILURE = 24306, VIX_E_MNTAPI_NO_DRIVER = 24307, VIX_E_MNTAPI_ALREADY_OPENED = 24308, VIX_E_MNTAPI_ITEM_NOT_FOUND = 24309, VIX_E_MNTAPI_UNSUPPROTED_BOOT_LOADER = 24310, VIX_E_MNTAPI_UNSUPPROTED_OS = 24311, VIX_E_MNTAPI_CODECONVERSION = 24312, VIX_E_MNTAPI_REGWRITE_ERROR = 24313, VIX_E_MNTAPI_UNSUPPORTED_FT_VOLUME = 24314, VIX_E_MNTAPI_PARTITION_NOT_FOUND = 24315, VIX_E_MNTAPI_PUTFILE_ERROR = 24316, VIX_E_MNTAPI_GETFILE_ERROR = 24317, VIX_E_MNTAPI_REG_NOT_OPENED = 24318, VIX_E_MNTAPI_REGDELKEY_ERROR = 24319, VIX_E_MNTAPI_CREATE_PARTITIONTABLE_ERROR = 24320, VIX_E_MNTAPI_OPEN_FAILURE = 24321, VIX_E_MNTAPI_VOLUME_NOT_WRITABLE = 24322, /* Success on operation that completes asynchronously */ VIX_ASYNC = 25000, /* Async errors */ VIX_E_ASYNC_MIXEDMODE_UNSUPPORTED = 26000, /* Network Errors */ VIX_E_NET_HTTP_UNSUPPORTED_PROTOCOL = 30001, VIX_E_NET_HTTP_URL_MALFORMAT = 30003, VIX_E_NET_HTTP_COULDNT_RESOLVE_PROXY = 30005, VIX_E_NET_HTTP_COULDNT_RESOLVE_HOST = 30006, VIX_E_NET_HTTP_COULDNT_CONNECT = 30007, VIX_E_NET_HTTP_HTTP_RETURNED_ERROR = 30022, VIX_E_NET_HTTP_OPERATION_TIMEDOUT = 30028, VIX_E_NET_HTTP_SSL_CONNECT_ERROR = 30035, VIX_E_NET_HTTP_TOO_MANY_REDIRECTS = 30047, VIX_E_NET_HTTP_TRANSFER = 30200, VIX_E_NET_HTTP_SSL_SECURITY = 30201, VIX_E_NET_HTTP_GENERIC = 30202, }; // {{ End VIX_ERROR }} const char *Vix_GetErrorText(VixError err, const char *locale); /* *----------------------------------------------------------------------------- * * VIX Handles -- * * These are common functions that apply to handles of several types. *----------------------------------------------------------------------------- */ /* * VIX Property Type */ typedef int VixPropertyType; enum { VIX_PROPERTYTYPE_ANY = 0, VIX_PROPERTYTYPE_INTEGER = 1, VIX_PROPERTYTYPE_STRING = 2, VIX_PROPERTYTYPE_BOOL = 3, VIX_PROPERTYTYPE_HANDLE = 4, VIX_PROPERTYTYPE_INT64 = 5, VIX_PROPERTYTYPE_BLOB = 6 }; /* * VIX Property ID's */ typedef int VixPropertyID; enum { VIX_PROPERTY_NONE = 0, /* Properties used by several handle types. */ VIX_PROPERTY_META_DATA_CONTAINER = 2, /* VIX_HANDLETYPE_HOST properties */ VIX_PROPERTY_HOST_HOSTTYPE = 50, VIX_PROPERTY_HOST_API_VERSION = 51, VIX_PROPERTY_HOST_SOFTWARE_VERSION = 52, /* VIX_HANDLETYPE_VM properties */ VIX_PROPERTY_VM_NUM_VCPUS = 101, VIX_PROPERTY_VM_VMX_PATHNAME = 103, VIX_PROPERTY_VM_VMTEAM_PATHNAME = 105, VIX_PROPERTY_VM_MEMORY_SIZE = 106, VIX_PROPERTY_VM_READ_ONLY = 107, VIX_PROPERTY_VM_NAME = 108, VIX_PROPERTY_VM_GUESTOS = 109, VIX_PROPERTY_VM_IN_VMTEAM = 128, VIX_PROPERTY_VM_POWER_STATE = 129, VIX_PROPERTY_VM_TOOLS_STATE = 152, VIX_PROPERTY_VM_IS_RUNNING = 196, VIX_PROPERTY_VM_SUPPORTED_FEATURES = 197, /* VIX_PROPERTY_VM_IS_RECORDING = 236, Removed in version 1.11 */ /* VIX_PROPERTY_VM_IS_REPLAYING = 237, Removed in version 1.11 */ VIX_PROPERTY_VM_SSL_ERROR = 293, /* Result properties; these are returned by various procedures */ VIX_PROPERTY_JOB_RESULT_ERROR_CODE = 3000, VIX_PROPERTY_JOB_RESULT_VM_IN_GROUP = 3001, VIX_PROPERTY_JOB_RESULT_USER_MESSAGE = 3002, VIX_PROPERTY_JOB_RESULT_EXIT_CODE = 3004, VIX_PROPERTY_JOB_RESULT_COMMAND_OUTPUT = 3005, VIX_PROPERTY_JOB_RESULT_HANDLE = 3010, VIX_PROPERTY_JOB_RESULT_GUEST_OBJECT_EXISTS = 3011, VIX_PROPERTY_JOB_RESULT_GUEST_PROGRAM_ELAPSED_TIME = 3017, VIX_PROPERTY_JOB_RESULT_GUEST_PROGRAM_EXIT_CODE = 3018, VIX_PROPERTY_JOB_RESULT_ITEM_NAME = 3035, VIX_PROPERTY_JOB_RESULT_FOUND_ITEM_DESCRIPTION = 3036, VIX_PROPERTY_JOB_RESULT_SHARED_FOLDER_COUNT = 3046, VIX_PROPERTY_JOB_RESULT_SHARED_FOLDER_HOST = 3048, VIX_PROPERTY_JOB_RESULT_SHARED_FOLDER_FLAGS = 3049, VIX_PROPERTY_JOB_RESULT_PROCESS_ID = 3051, VIX_PROPERTY_JOB_RESULT_PROCESS_OWNER = 3052, VIX_PROPERTY_JOB_RESULT_PROCESS_COMMAND = 3053, VIX_PROPERTY_JOB_RESULT_FILE_FLAGS = 3054, VIX_PROPERTY_JOB_RESULT_PROCESS_START_TIME = 3055, VIX_PROPERTY_JOB_RESULT_VM_VARIABLE_STRING = 3056, VIX_PROPERTY_JOB_RESULT_PROCESS_BEING_DEBUGGED = 3057, VIX_PROPERTY_JOB_RESULT_SCREEN_IMAGE_SIZE = 3058, VIX_PROPERTY_JOB_RESULT_SCREEN_IMAGE_DATA = 3059, VIX_PROPERTY_JOB_RESULT_FILE_SIZE = 3061, VIX_PROPERTY_JOB_RESULT_FILE_MOD_TIME = 3062, VIX_PROPERTY_JOB_RESULT_EXTRA_ERROR_INFO = 3084, /* Event properties; these are sent in the moreEventInfo for some events. */ VIX_PROPERTY_FOUND_ITEM_LOCATION = 4010, /* VIX_HANDLETYPE_SNAPSHOT properties */ VIX_PROPERTY_SNAPSHOT_DISPLAYNAME = 4200, VIX_PROPERTY_SNAPSHOT_DESCRIPTION = 4201, VIX_PROPERTY_SNAPSHOT_POWERSTATE = 4205, /* VIX_PROPERTY_SNAPSHOT_IS_REPLAYABLE = 4207, Removed in version 1.11 */ VIX_PROPERTY_GUEST_SHAREDFOLDERS_SHARES_PATH = 4525, /* Virtual machine encryption properties */ VIX_PROPERTY_VM_ENCRYPTION_PASSWORD = 7001, }; /* * These are events that may be signalled by calling a procedure * of type VixEventProc. */ typedef int VixEventType; enum { VIX_EVENTTYPE_JOB_COMPLETED = 2, VIX_EVENTTYPE_JOB_PROGRESS = 3, VIX_EVENTTYPE_FIND_ITEM = 8, VIX_EVENTTYPE_CALLBACK_SIGNALLED = 2, // Deprecated - Use VIX_EVENTTYPE_JOB_COMPLETED instead. }; /* * These are the property flags for each file. */ enum { VIX_FILE_ATTRIBUTES_DIRECTORY = 0x0001, VIX_FILE_ATTRIBUTES_SYMLINK = 0x0002, }; /* * Procedures of this type are called when an event happens on a handle. */ typedef void VixEventProc(VixHandle handle, VixEventType eventType, VixHandle moreEventInfo, void *clientData); /* * Handle Property functions */ void Vix_ReleaseHandle(VixHandle handle); void Vix_AddRefHandle(VixHandle handle); VixHandleType Vix_GetHandleType(VixHandle handle); VixError Vix_GetProperties(VixHandle handle, VixPropertyID firstPropertyID, ...); VixError Vix_GetPropertyType(VixHandle handle, VixPropertyID propertyID, VixPropertyType *propertyType); void Vix_FreeBuffer(void *p); /* *----------------------------------------------------------------------------- * * VIX Host -- * *----------------------------------------------------------------------------- */ typedef int VixHostOptions; enum { /* * The following option was removed in version 1.11. VIX_HOSTOPTION_USE_EVENT_PUMP = 0x0008, */ VIX_HOSTOPTION_VERIFY_SSL_CERT = 0x4000, }; typedef int VixServiceProvider; enum { VIX_SERVICEPROVIDER_DEFAULT = 1, VIX_SERVICEPROVIDER_VMWARE_SERVER = 2, VIX_SERVICEPROVIDER_VMWARE_WORKSTATION = 3, VIX_SERVICEPROVIDER_VMWARE_PLAYER = 4, VIX_SERVICEPROVIDER_VMWARE_VI_SERVER = 10, VIX_SERVICEPROVIDER_VMWARE_WORKSTATION_SHARED = 11, }; /* * VIX_API_VERSION tells VixHost_Connect to use the latest API version * that is available for the product specified in the VixServiceProvider * parameter. */ enum { VIX_API_VERSION = -1 }; VixHandle VixHost_Connect(int apiVersion, VixServiceProvider hostType, const char *hostName, int hostPort, const char *userName, const char *password, VixHostOptions options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); void VixHost_Disconnect(VixHandle hostHandle); /* * VM Registration */ VixHandle VixHost_RegisterVM(VixHandle hostHandle, const char *vmxFilePath, VixEventProc *callbackProc, void *clientData); VixHandle VixHost_UnregisterVM(VixHandle hostHandle, const char *vmxFilePath, VixEventProc *callbackProc, void *clientData); /* * VM Search */ typedef int VixFindItemType; enum { VIX_FIND_RUNNING_VMS = 1, VIX_FIND_REGISTERED_VMS = 4, }; VixHandle VixHost_FindItems(VixHandle hostHandle, VixFindItemType searchType, VixHandle searchCriteria, int32 timeout, VixEventProc *callbackProc, void *clientData); /* * VixHost_OpenVM() supercedes VixVM_Open() since it allows for * the passing of option flags and extra data in the form of a * property list. * It is recommended to use VixHost_OpenVM() instead of VixVM_Open(). */ typedef int VixVMOpenOptions; enum { VIX_VMOPEN_NORMAL = 0x0, }; VixHandle VixHost_OpenVM(VixHandle hostHandle, const char *vmxFilePathName, VixVMOpenOptions options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); /* * Following functions were removed in version 1.11. * typedef int VixPumpEventsOptions; enum { VIX_PUMPEVENTOPTION_NONE = 0, }; void Vix_PumpEvents(VixHandle hostHandle, VixPumpEventsOptions options); VixHandle VixVM_OpenUrlInGuest(VixHandle vmHandle, const char *url, int windowState, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); */ /* *----------------------------------------------------------------------------- * * PropertyList -- * *----------------------------------------------------------------------------- */ #ifndef VIX_HIDE_FROM_JAVA VixError VixPropertyList_AllocPropertyList(VixHandle hostHandle, VixHandle *resultHandle, int firstPropertyID, ...); #endif /* *----------------------------------------------------------------------------- * * VIX VM -- * * This describes the persistent configuration state of a single VM. The * VM may or may not be running. * *----------------------------------------------------------------------------- */ VixHandle VixVM_Open(VixHandle hostHandle, const char *vmxFilePathName, VixEventProc *callbackProc, void *clientData); typedef int VixVMPowerOpOptions; enum { VIX_VMPOWEROP_NORMAL = 0, VIX_VMPOWEROP_FROM_GUEST = 0x0004, VIX_VMPOWEROP_SUPPRESS_SNAPSHOT_POWERON = 0x0080, VIX_VMPOWEROP_LAUNCH_GUI = 0x0200, VIX_VMPOWEROP_START_VM_PAUSED = 0x1000, }; /* * Power operations */ VixHandle VixVM_PowerOn(VixHandle vmHandle, VixVMPowerOpOptions powerOnOptions, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_PowerOff(VixHandle vmHandle, VixVMPowerOpOptions powerOffOptions, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_Reset(VixHandle vmHandle, VixVMPowerOpOptions resetOptions, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_Suspend(VixHandle vmHandle, VixVMPowerOpOptions suspendOptions, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_Pause(VixHandle vmHandle, int options, VixHandle propertyList, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_Unpause(VixHandle vmHandle, int options, VixHandle propertyList, VixEventProc *callbackProc, void *clientData); typedef int VixVMDeleteOptions; enum { VIX_VMDELETE_DISK_FILES = 0x0002, }; VixHandle VixVM_Delete(VixHandle vmHandle, VixVMDeleteOptions deleteOptions, VixEventProc *callbackProc, void *clientData); /* * This is the state of an individual VM. These values are bitwise flags. * The actual value returned for may be a bitwise OR of one more of these * flags, along with other reserved values not documented here. */ typedef int VixPowerState; enum { VIX_POWERSTATE_POWERING_OFF = 0x0001, VIX_POWERSTATE_POWERED_OFF = 0x0002, VIX_POWERSTATE_POWERING_ON = 0x0004, VIX_POWERSTATE_POWERED_ON = 0x0008, VIX_POWERSTATE_SUSPENDING = 0x0010, VIX_POWERSTATE_SUSPENDED = 0x0020, VIX_POWERSTATE_TOOLS_RUNNING = 0x0040, VIX_POWERSTATE_RESETTING = 0x0080, VIX_POWERSTATE_BLOCKED_ON_MSG = 0x0100, VIX_POWERSTATE_PAUSED = 0x0200, VIX_POWERSTATE_RESUMING = 0x0800, }; typedef int VixToolsState; enum { VIX_TOOLSSTATE_UNKNOWN = 0x0001, VIX_TOOLSSTATE_RUNNING = 0x0002, VIX_TOOLSSTATE_NOT_INSTALLED = 0x0004, }; /* * These flags describe optional functions supported by different * types of VM. */ enum { VIX_VM_SUPPORT_SHARED_FOLDERS = 0x0001, VIX_VM_SUPPORT_MULTIPLE_SNAPSHOTS = 0x0002, VIX_VM_SUPPORT_TOOLS_INSTALL = 0x0004, VIX_VM_SUPPORT_HARDWARE_UPGRADE = 0x0008, }; /* * VIX_ADMINISTRATOR_USER_NAME and VIX_CONSOLE_USER_NAME are no longer * supported. If your code includes references to these constants please * update your code to use a valid guest username and password when calling * VixVM_LoginInGuest(). */ //#define VIX_ADMINISTRATOR_USER_NAME "__VMware_Vix_Guest_User_Admin__" //#define VIX_CONSOLE_USER_NAME "__VMware_Vix_Guest_Console_User__" /* * Guest operations */ VixHandle VixVM_WaitForToolsInGuest(VixHandle vmHandle, int timeoutInSeconds, VixEventProc *callbackProc, void *clientData); /* * VixVM_LoginInGuest option flags. */ enum { VIX_LOGIN_IN_GUEST_REQUIRE_INTERACTIVE_ENVIRONMENT = 0x08, }; VixHandle VixVM_LoginInGuest(VixHandle vmHandle, const char *userName, const char *password, int options, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_LogoutFromGuest(VixHandle vmHandle, VixEventProc *callbackProc, void *clientData); /* * Guest Process functions */ typedef int VixRunProgramOptions; enum { VIX_RUNPROGRAM_RETURN_IMMEDIATELY = 0x0001, VIX_RUNPROGRAM_ACTIVATE_WINDOW = 0x0002, }; VixHandle VixVM_RunProgramInGuest(VixHandle vmHandle, const char *guestProgramName, const char *commandLineArgs, VixRunProgramOptions options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_ListProcessesInGuest(VixHandle vmHandle, int options, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_KillProcessInGuest(VixHandle vmHandle, uint64 pid, int options, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_RunScriptInGuest(VixHandle vmHandle, const char *interpreter, const char *scriptText, VixRunProgramOptions options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); /* * Guest File functions */ VixHandle VixVM_CopyFileFromHostToGuest(VixHandle vmHandle, const char *hostPathName, const char *guestPathName, int options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_CopyFileFromGuestToHost(VixHandle vmHandle, const char *guestPathName, const char *hostPathName, int options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_DeleteFileInGuest(VixHandle vmHandle, const char *guestPathName, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_FileExistsInGuest(VixHandle vmHandle, const char *guestPathName, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_RenameFileInGuest(VixHandle vmHandle, const char *oldName, const char *newName, int options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_CreateTempFileInGuest(VixHandle vmHandle, int options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_GetFileInfoInGuest(VixHandle vmHandle, const char *pathName, VixEventProc *callbackProc, void *clientData); /* * Guest Directory functions */ VixHandle VixVM_ListDirectoryInGuest(VixHandle vmHandle, const char *pathName, int options, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_CreateDirectoryInGuest(VixHandle vmHandle, const char *pathName, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_DeleteDirectoryInGuest(VixHandle vmHandle, const char *pathName, int options, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_DirectoryExistsInGuest(VixHandle vmHandle, const char *pathName, VixEventProc *callbackProc, void *clientData); /* * Guest Variable Functions */ enum { VIX_VM_GUEST_VARIABLE = 1, VIX_VM_CONFIG_RUNTIME_ONLY = 2, VIX_GUEST_ENVIRONMENT_VARIABLE = 3, }; VixHandle VixVM_ReadVariable(VixHandle vmHandle, int variableType, const char *name, int options, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_WriteVariable(VixHandle vmHandle, int variableType, const char *valueName, const char *value, int options, VixEventProc *callbackProc, void *clientData); /* * Snapshot functions that operate on a VM */ VixError VixVM_GetNumRootSnapshots(VixHandle vmHandle, int *result); VixError VixVM_GetRootSnapshot(VixHandle vmHandle, int index, VixHandle *snapshotHandle); VixError VixVM_GetCurrentSnapshot(VixHandle vmHandle, VixHandle *snapshotHandle); VixError VixVM_GetNamedSnapshot(VixHandle vmHandle, const char *name, VixHandle *snapshotHandle); typedef int VixRemoveSnapshotOptions; enum { VIX_SNAPSHOT_REMOVE_CHILDREN = 0x0001, }; VixHandle VixVM_RemoveSnapshot(VixHandle vmHandle, VixHandle snapshotHandle, VixRemoveSnapshotOptions options, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_RevertToSnapshot(VixHandle vmHandle, VixHandle snapshotHandle, VixVMPowerOpOptions options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); typedef int VixCreateSnapshotOptions; enum { VIX_SNAPSHOT_INCLUDE_MEMORY = 0x0002, }; VixHandle VixVM_CreateSnapshot(VixHandle vmHandle, const char *name, const char *description, VixCreateSnapshotOptions options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); /* * Shared Folders Functions */ /* * These are the flags describing each shared folder. */ typedef int VixMsgSharedFolderOptions; enum { VIX_SHAREDFOLDER_WRITE_ACCESS = 0x04, }; VixHandle VixVM_EnableSharedFolders(VixHandle vmHandle, Bool enabled, int options, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_GetNumSharedFolders(VixHandle vmHandle, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_GetSharedFolderState(VixHandle vmHandle, int index, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_SetSharedFolderState(VixHandle vmHandle, const char *shareName, const char *hostPathName, VixMsgSharedFolderOptions flags, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_AddSharedFolder(VixHandle vmHandle, const char *shareName, const char *hostPathName, VixMsgSharedFolderOptions flags, VixEventProc *callbackProc, void *clientData); VixHandle VixVM_RemoveSharedFolder(VixHandle vmHandle, const char *shareName, int flags, VixEventProc *callbackProc, void *clientData); /* * Screen Capture */ #ifndef VIX_HIDE_FROM_JAVA enum { VIX_CAPTURESCREENFORMAT_PNG = 0x01, VIX_CAPTURESCREENFORMAT_PNG_NOCOMPRESS = 0x02, }; VixHandle VixVM_CaptureScreenImage(VixHandle vmHandle, int captureType, VixHandle additionalProperties, VixEventProc *callbackProc, void *clientdata); #endif // VIX_HIDE_FROM_JAVA /* * VM Cloning -- */ typedef int VixCloneType; enum { VIX_CLONETYPE_FULL = 0, VIX_CLONETYPE_LINKED = 1, }; VixHandle VixVM_Clone(VixHandle vmHandle, VixHandle snapshotHandle, VixCloneType cloneType, const char *destConfigPathName, int options, VixHandle propertyListHandle, VixEventProc *callbackProc, void *clientData); /* * Misc Functions */ VixHandle VixVM_UpgradeVirtualHardware(VixHandle vmHandle, int options, VixEventProc *callbackProc, void *clientData); enum { VIX_INSTALLTOOLS_MOUNT_TOOLS_INSTALLER = 0x00, VIX_INSTALLTOOLS_AUTO_UPGRADE = 0x01, VIX_INSTALLTOOLS_RETURN_IMMEDIATELY = 0x02 }; VixHandle VixVM_InstallTools(VixHandle vmHandle, int options, const char *commandLineArgs, VixEventProc *callbackProc, void *clientData); /* *----------------------------------------------------------------------------- * * VIX Job -- * *----------------------------------------------------------------------------- */ /* * Synchronization functions * (used to detect when an asynch operation completes). */ VixError VixJob_Wait(VixHandle jobHandle, VixPropertyID firstPropertyID, ...); VixError VixJob_CheckCompletion(VixHandle jobHandle, Bool *complete); /* * Accessor functions * (used to get results of a completed asynch operation). */ VixError VixJob_GetError(VixHandle jobHandle); int VixJob_GetNumProperties(VixHandle jobHandle, int resultPropertyID); VixError VixJob_GetNthProperties(VixHandle jobHandle, int index, int propertyID, ...); /* *----------------------------------------------------------------------------- * * VIX Snapshot -- * *----------------------------------------------------------------------------- */ VixError VixSnapshot_GetNumChildren(VixHandle parentSnapshotHandle, int *numChildSnapshots); VixError VixSnapshot_GetChild(VixHandle parentSnapshotHandle, int index, VixHandle *childSnapshotHandle); VixError VixSnapshot_GetParent(VixHandle snapshotHandle, VixHandle *parentSnapshotHandle); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* _VIX_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vixCommands.h000066400000000000000000002244151470176644300251630ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2003-2021, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * vixCommands.h -- * * Defines used when Vix crosses various IPC boundaries. */ #ifndef _VIX_COMMANDS_H_ #define _VIX_COMMANDS_H_ #include "vixOpenSource.h" #if defined(__cplusplus) extern "C" { #endif /* * These describe the format of the message objects. * This will change when the client/vmx support different * structures for the message header. Hopefully, that won't * happen. */ #define VIX_COMMAND_MAGIC_WORD 0xd00d0001 #define VIX_COMMAND_MESSAGE_VERSION 5 /* * These give upper bounds for how big any VIX IPC meesage * should be. There are for confidence checks and to ignore maliciously * large messages that may be part of an DoS attack. The may need to * be revised if large messages are added to the protocol. */ #define VIX_COMMAND_MAX_SIZE (16 * 1024 * 1024) #define VIX_COMMAND_MAX_REQUEST_SIZE 65536 /* * We don't want to allow guest ops commands with input size too large. * Limit it to the max request size with enough room for the credentials. * Check bugs 824773, 926819 for more details. */ #define VIX_COMMAND_MAX_USER_INPUT_SIZE (VIX_COMMAND_MAX_REQUEST_SIZE - 5000) /* * The types of credential we can pass with any request. */ #define VIX_USER_CREDENTIAL_NONE 0 #define VIX_USER_CREDENTIAL_NAME_PASSWORD 1 #define VIX_USER_CREDENTIAL_ANONYMOUS 2 #define VIX_USER_CREDENTIAL_ROOT 3 #define VIX_USER_CREDENTIAL_NAME_PASSWORD_OBFUSCATED 4 #define VIX_USER_CREDENTIAL_CONSOLE_USER 5 #define VIX_USER_CREDENTIAL_HOST_CONFIG_SECRET 6 #define VIX_USER_CREDENTIAL_HOST_CONFIG_HASHED_SECRET 7 #define VIX_USER_CREDENTIAL_NAMED_INTERACTIVE_USER 8 #define VIX_USER_CREDENTIAL_TICKETED_SESSION 9 #define VIX_USER_CREDENTIAL_SSPI 10 #define VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN 11 #define VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN_HOST_VERIFIED 12 #define VIX_SHARED_SECRET_CONFIG_USER_NAME "__VMware_Vix_Shared_Secret_1__" /* * Base64 encoded value of string %HOST_VERIFIED_SIGNATURE% */ #define VIX_BASE64_ENCODED_HOST_VERIFIED_SIGNATURE_VALUE "JUhPU1RfVkVSSUZJRURfU0lHTkFUVVJFJQA=" /* * This is the port for the server side remote Vix component */ #define VIX_SERVER_PORT 61525 #define VIX_TOOLS_SOCKET_PORT 61526 /* * These are the flags set in the commonFlags field. */ enum VixCommonCommandOptionValues { VIX_COMMAND_REQUEST = 0x01, VIX_COMMAND_REPORT_EVENT = 0x02, VIX_COMMAND_FORWARD_TO_GUEST = 0x04, VIX_COMMAND_GUEST_RETURNS_STRING = 0x08, VIX_COMMAND_GUEST_RETURNS_INTEGER_STRING = 0x10, /* DEPRECATED VIX_COMMAND_GUEST_RETURNS_ENCODED_STRING = 0x20, */ VIX_COMMAND_GUEST_RETURNS_PROPERTY_LIST = 0x40, VIX_COMMAND_GUEST_RETURNS_BINARY = 0x80, // We cannot add more constants here. This is stored in a uint8, // so it is full. Use requestFlags or responseFlags. }; /* * These are the flags set in the request Flags field. */ enum { VIX_REQUESTMSG_ONLY_RELOAD_NETWORKS = 0x001, VIX_REQUESTMSG_RETURN_ON_INITIATING_TOOLS_UPGRADE = 0x002, VIX_REQUESTMSG_RUN_IN_ANY_VMX_STATE = 0x004, VIX_REQUESTMSG_REQUIRES_INTERACTIVE_ENVIRONMENT = 0x008, VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1 = 0x010, VIX_REQUESTMSG_REQUIRES_VMDB_NOTIFICATION = 0x020, VIX_REQUESTMSG_ESCAPE_XML_DATA = 0x040, VIX_REQUESTMSG_HAS_HASHED_SHARED_SECRET = 0x080, VIX_REQUESTMSG_VIGOR_COMMAND = 0x100, }; /* * These are the flags set in responseFlags. */ enum VixResponseFlagsValues { VIX_RESPONSE_SOFT_POWER_OP = 0x0001, VIX_RESPONSE_EXTENDED_RESULT_V1 = 0x0002, VIX_RESPONSE_TRUNCATED = 0x0004, VIX_RESPONSE_FSR = 0x0008, VIX_RESPONSE_VMDB_NOTIFICATION_POSTED = 0x0010, VIX_RESPONSE_VIGOR_COMMAND = 0x0020, }; /* * This is the header for one message, either a request or a * response, and sent either to or from the VMX. * * Every message has 3 regions: * * ------------------------------------- * | Header | Body | Credential | * ------------------------------------- * * The credential and the body may either or both be empty. * The 3 regions always appear in this order. First the header, then a body * if there is one, then a credential if there is one. * There should be no gaps between these regions. New regions are added * to the end. This means the lengths can also be used to compute * offsets to the regions. * * The length of the headers, the credential, and the body are all stored in * the common header. This should allow parsing code to receive complete * messages even if it does not understand them. * * Currently that the credential is only used for a Request. It is * currently empty for a response. * */ #pragma pack(push, 1) typedef struct VixMsgHeader { uint32 magic; uint16 messageVersion; uint32 totalMessageLength; uint32 headerLength; uint32 bodyLength; uint32 credentialLength; uint8 commonFlags; } VixMsgHeader; #pragma pack(pop) /* * These are the headers for a single request, response, or event. * In theory, either the VMX or the client may issue a request * to the other. In practice, legacy foundry clients can only * accept response messages from the VMX, not requests. Because of * this, an event message is a special kind of response message. */ #pragma pack(push, 1) typedef struct VixCommandRequestHeader { VixMsgHeader commonHeader; uint32 opCode; uint32 requestFlags; uint32 timeOut; uint64 cookie; uint32 clientHandleId; // for remote case uint32 userCredentialType; } VixCommandRequestHeader; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixCommandResponseHeader { VixMsgHeader commonHeader; uint64 requestCookie; uint32 responseFlags; uint32 duration; uint32 error; uint32 additionalError; uint32 errorDataLength; } VixCommandResponseHeader; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgEventHeader { VixCommandResponseHeader responseHeader; int32 eventType; } VixMsgEventHeader; #pragma pack(pop) /* * A trivial request that is just a generic * response header (it has no body). */ #pragma pack(push, 1) typedef struct VixMsgTrivialRequest { VixCommandRequestHeader header; } VixMsgTrivialRequest; #pragma pack(pop) /* * A trivial event that is just a generic * event header (it has no body). */ #pragma pack(push, 1) typedef struct VixMsgTrivialEvent { VixMsgEventHeader eventHeader; } VixMsgTrivialEvent; #pragma pack(pop) /* * ********************************************************** * This is a generic progress update from the VMX. * The VMX may send several of these before sending a final response * message. These only report progress, they do not mean the job * has completed. These messages are identified by the * VIX_COMMAND_REPORT_EVENT flag in the commonFlags field and * VIX_EVENTTYPE_JOB_PROGRESS as the eventType. */ #pragma pack(push, 1) typedef struct VixMsgProgressEvent { VixMsgEventHeader eventHeader; int64 workToDo; int64 workDone; } VixMsgProgressEvent; #pragma pack(pop) /* * This is an event sent from the VMX to all clients when some property changes. * It may be used for any runtime property. */ #pragma pack(push, 1) typedef struct VixMsgPropertyChangedEvent { VixMsgEventHeader eventHeader; int options; uint32 propertyListSize; } VixMsgPropertyChangedEvent; #pragma pack(pop) /* * ********************************************************** * This is a userName and password pair. */ #pragma pack(push, 1) typedef struct VixCommandNamePassword { uint32 nameLength; uint32 passwordLength; } VixCommandNamePassword; #pragma pack(pop) /* * ********************************************************** * This is a ticketed session for authentication. */ #pragma pack(push, 1) typedef struct VixCommandTicketedSession { uint32 ticketLength; } VixCommandTicketedSession; #pragma pack(pop) /* * ********************************************************** * This is a SSPI token for acquiring credentials */ #pragma pack(push, 1) typedef struct VixCommandSSPI { uint32 tokenLength; } VixCommandSSPI; #pragma pack(pop) /* * ********************************************************** * This is a SAML bearer token with optional userName to specify * an IdProvider store. */ #pragma pack(push, 1) typedef struct VixCommandSAMLToken { uint32 tokenLength; uint32 nameLength; } VixCommandSAMLToken; #pragma pack(pop) /* * ********************************************************** * Basic power op request. The response is just a generic * response header (it has no body). */ #pragma pack(push, 1) typedef struct VixMsgPowerOpRequest { VixCommandRequestHeader header; VixVMPowerOpOptions powerOpOptions; /* * Starting in Workstation 7.0, a serialized property list buffer * can be appended here. This was originally used for augmenting * poweroff to support revert to snapshot upon poweroff functionality. */ } VixMsgPowerOpRequest; #pragma pack(pop) /* * ********************************************************** * Get/Set Properties Request */ #pragma pack(push, 1) typedef struct VixMsgGetVMStateResponse { VixCommandResponseHeader header; uint32 bufferSize; // This is followed by the buffer of serialized properties } VixMsgGetVMStateResponse; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSetVMStateRequest { VixCommandRequestHeader header; uint32 bufferSize; // This is followed by the buffer of serialized properties } VixMsgSetVMStateRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgAuthDataV1 { int64 nonce; uint32 sequenceNumber; uint8 hashValue[32]; } VixMsgAuthDataV1; #pragma pack(pop) /* * ********************************************************** * Basic reload state request. The response is just a generic * response header (it has no body). */ #pragma pack(push, 1) typedef struct VixMsgReloadVMStateRequest { VixCommandRequestHeader header; // This is followed by an array of VixMsgConfigurationObjectType objects } VixMsgReloadVMStateRequest; #pragma pack(pop) /* * This is a prefix to a configuration object. The current supported * types are defined below in the VixCommonConfigObjectType enum. * Following each object type struct is the specific object. Currently, * we support: * * VIX_NETWORK_SETTING_CONFIG - VixMsgNICBandwidth */ #pragma pack(push, 1) typedef struct VixMsgConfigurationObjectType { int32 configurationType; uint32 objectSize; } VixMsgConfigurationObjectType; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgNICBandwidth { Bool validNICNum; int32 nicNum; char pvnGUID[64]; uint32 totalBandwidth; uint32 maxSendBandwidth; uint32 maxReceiveBandwidth; uint32 packetLossPattern; uint32 packetLossRate; uint32 packetLossMinBurstDuration; uint32 packetLossMaxBurstDuration; uint32 minLatency; uint32 maxLatency; uint32 options; } VixMsgNICBandwidth; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgLANSegmentConfiguration { VixMsgConfigurationObjectType configHeader; VixMsgNICBandwidth lanSegment; } VixMsgLANSegmentConfiguration; #pragma pack(pop) /* * These are options to the bandwidth commands. */ enum VixMsgPacketLossType { // packetLossPattern values VIX_PACKETLOSS_RANDOM = 1, }; /* * These are the types of configuration objects we can send * to a VIX_COMMAND_RELOAD_VM command. */ enum VixMsgConfigObjectType { VIX_LAN_SEGMENT_SETTING_CONFIG = 1, }; /* * ********************************************************** * Wait for tools request. The response is just a generic * response header (it has no body). */ #pragma pack(push, 1) typedef struct VixMsgWaitForToolsRequest { VixCommandRequestHeader header; int32 timeoutInSeconds; int32 minVersion; } VixMsgWaitForToolsRequest; #pragma pack(pop) /* * ********************************************************** * Run a program on the guest. */ #pragma pack(push, 1) typedef struct VixMsgRunProgramRequest { VixCommandRequestHeader header; int32 runProgramOptions; uint32 programNameLength; uint32 commandLineArgsLength; } VixMsgRunProgramRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgOldRunProgramResponse { VixCommandResponseHeader header; int32 exitCode; VmTimeType deltaTime; } VixMsgOldRunProgramResponse; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgRunProgramResponse { VixCommandResponseHeader header; int32 exitCode; VmTimeType deltaTime; int64 pid; uint32 stdOutLength; uint32 stdErrLength; } VixMsgRunProgramResponse; #pragma pack(pop) /* * ********************************************************** * Install VMware tools. */ #pragma pack(push, 1) typedef struct VixMsgInstallToolsRequest { VixCommandRequestHeader header; int32 installOptions; uint32 commandLineArgsLength; } VixMsgInstallToolsRequest; #pragma pack(pop) /* * ********************************************************** * Send keystrokes to the guest. */ enum VixKeyStrokeCharType { VIX_KEYSTROKE_SCANCODE = 1, VIX_KEYSTROKE_TEXT_CHAR = 2, }; enum VixKeyStrokeModifiers { VIX_KEYSTROKE_MODIFIER_KEY_DOWN = 0x01, VIX_KEYSTROKE_MODIFIER_KEY_UP = 0x02, VIX_KEYSTROKE_MODIFIER_CONTROL = 0x04, VIX_KEYSTROKE_MODIFIER_SHIFT = 0x08, VIX_KEYSTROKE_MODIFIER_ALT = 0x10, VIX_KEYSTROKE_MODIFIER_KEY_DOWN_ONLY = 0x80, VIX_KEYSTROKE_MODIFIER_KEY_UP_ONLY = 0x100, }; #pragma pack(push, 1) typedef struct VixMsgKeyStroke { int32 modifier; int32 scanCode; int32 duration; int32 delayAfterKeyUp; int32 repeat; } VixMsgKeyStroke; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSendKeyStrokesRequest { VixCommandRequestHeader header; int32 keyStrokeType; int32 options; int64 targetPid; int32 numKeyStrokes; uint32 windowNameLength; } VixMsgSendKeyStrokesRequest; #pragma pack(pop) /* * send a mouse event to the guest */ #pragma pack(push, 1) typedef struct VixMsgSendMouseEventRequest { VixCommandRequestHeader header; int16 x; int16 y; int16 buttons; int32 options; } VixMsgSendMouseEventRequest; #pragma pack(pop) /* * ********************************************************** * Read or write the registry on the guest. */ #pragma pack(push, 1) typedef struct VixMsgRegistryRequest { VixCommandRequestHeader header; uint32 registryKeyLength; int32 expectedRegistryKeyType; uint32 dataToWriteSize; } VixMsgRegistryRequest; #pragma pack(pop) /* * ********************************************************** * Copy files between the host and the guest. */ #pragma pack(push, 1) typedef struct VixCommandRenameFileRequest { VixCommandRequestHeader header; int32 copyFileOptions; uint32 oldPathNameLength; uint32 newPathNameLength; uint32 filePropertiesLength; } VixCommandRenameFileRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixCommandRenameFileRequestEx { VixCommandRequestHeader header; int32 copyFileOptions; uint32 oldPathNameLength; uint32 newPathNameLength; uint32 filePropertiesLength; Bool overwrite; } VixCommandRenameFileRequestEx; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixCommandHgfsSendPacket { VixCommandRequestHeader header; uint32 hgfsPacketSize; int32 timeout; } VixCommandHgfsSendPacket; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSetGuestFileAttributesRequest { VixCommandRequestHeader header; int32 fileOptions; int64 accessTime; int64 modificationTime; int32 ownerId; int32 groupId; int32 permissions; Bool hidden; Bool readOnly; uint32 guestPathNameLength; } VixMsgSetGuestFileAttributesRequest; #pragma pack(pop) /* * ********************************************************** * Perform a simple operation (like delete or check for existence) * on a file or registry key on the guest. */ #pragma pack(push, 1) typedef struct VixMsgSimpleFileRequest { VixCommandRequestHeader header; int32 fileOptions; uint32 guestPathNameLength; } VixMsgSimpleFileRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgListDirectoryRequest { VixCommandRequestHeader header; int32 fileOptions; uint32 guestPathNameLength; int64 offset; } VixMsgListDirectoryRequest; #pragma pack(pop) enum VixListDirectoryOptions { VIX_LIST_DIRECTORY_USE_OFFSET = 0x01 }; #pragma pack(push, 1) typedef struct VixMsgListFilesRequest { VixCommandRequestHeader header; int32 fileOptions; uint32 guestPathNameLength; uint32 patternLength; int32 index; int32 maxResults; uint64 offset; } VixMsgListFilesRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixCommandInitiateFileTransferToGuestRequest { VixCommandRequestHeader header; int32 options; uint32 guestPathNameLength; Bool overwrite; } VixCommandInitiateFileTransferToGuestRequest; #pragma pack(pop) /* * This is used to reply to several operations, like testing whether * a file or registry key exists on the client. */ #pragma pack(push, 1) typedef struct VixMsgCheckExistsResponse { VixCommandResponseHeader header; Bool exists; } VixMsgCheckExistsResponse; #pragma pack(pop) /* * ********************************************************** * Perform a create file operation (like createDir or moveFile) * on a file in the guest. This lets you pass in things like the initial file * properties. */ #pragma pack(push, 1) typedef struct VixMsgCreateFileRequest { VixCommandRequestHeader header; int32 fileOptions; uint32 guestPathNameLength; uint32 filePropertiesLength; } VixMsgCreateFileRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgCreateFileRequestEx { VixCommandRequestHeader header; int32 fileOptions; uint32 guestPathNameLength; uint32 filePropertiesLength; Bool createParentDirectories; } VixMsgCreateFileRequestEx; #pragma pack(pop) /* * ********************************************************** * Hot extend a disk in a running VM. */ #pragma pack(push, 1) typedef struct VixMsgHotExtendDiskRequest { VixCommandRequestHeader header; int32 hotDiskOptions; uint32 typeLength; int32 adapterNum; int32 targetNum; uint64 newNumSectors; } VixMsgHotExtendDiskRequest; #pragma pack(pop) /* * ********************************************************** * Hot plug CPU in a running VM. */ #pragma pack(push, 1) typedef struct VixMsgHotPlugCPURequest { VixCommandRequestHeader header; uint32 newNumCPU; } VixMsgHotPlugCPURequest; #pragma pack(pop) /* * ********************************************************** * Hot plug memory in a running VM. */ #pragma pack(push, 1) typedef struct VixMsgHotPlugMemoryRequest { VixCommandRequestHeader header; uint32 newSizeMb; } VixMsgHotPlugMemoryRequest; #pragma pack(pop) /* * ********************************************************** * Hot add device in a running VM. */ #pragma pack(push, 1) typedef struct VixMsgHotAddDeviceRequest { VixCommandRequestHeader header; int32 deviceType; uint32 devicePropsBufferSize; int32 backingType; uint32 backingPropsBufferSize; } VixMsgHotAddDeviceRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgHotAddDeviceResponse { VixCommandResponseHeader header; int32 adapterNum; int32 targetNum; } VixMsgHotAddDeviceResponse; #pragma pack(pop) /* * ********************************************************** * Hot remove device in a running VM. */ #pragma pack(push, 1) typedef struct VixMsgHotRemoveDeviceRequest { VixCommandRequestHeader header; int32 deviceType; uint32 devicePropsBufferSize; } VixMsgHotRemoveDeviceRequest; #pragma pack(pop) /* * ********************************************************** * Change monitor type of a running VM. */ #pragma pack(push, 1) typedef struct VixMsgHotChangeMonitorTypeRequest { VixCommandRequestHeader header; int32 monitorType; } VixMsgHotChangeMonitorTypeRequest; #pragma pack(pop) /* * ********************************************************** * Hot plug begin batch. */ #pragma pack(push, 1) typedef struct VixMsgHotPlugBeginBatchRequest { VixCommandRequestHeader header; int32 flags; } VixMsgHotPlugBeginBatchRequest; #pragma pack(pop) /* * ********************************************************** * Hot plug commit batch. */ #pragma pack(push, 1) typedef struct VixMsgHotPlugCommitBatchRequest { VixCommandRequestHeader header; int32 status; } VixMsgHotPlugCommitBatchRequest; #pragma pack(pop) /* * ********************************************************** * Transfer connection. Besides fields here you are supposed to * receive file descriptor OOB. */ #pragma pack(push, 1) typedef struct VixMsgTransferConnectionRequest { VixCommandRequestHeader header; Bool isPrivileged; uint32 cryptoLength; uint32 fdLength; /* uint8 cryptoData[]; */ /* uint8 fdData[]; */ } VixMsgTransferConnectionRequest; #pragma pack(pop) /* * ********************************************************** * Pass data. Besides fields here you may receive also * file descriptor. Data is just command which was pending * on original connection already transferred via * TransferConnectionRequest. */ #pragma pack(push, 1) typedef struct VixMsgTransferRequestRequest { VixCommandRequestHeader header; uint32 dataLength; uint32 fdLength; /* uint8 data[]; */ /* uint8 fdData[]; */ } VixMsgTransferRequestRequest; #pragma pack(pop) /* * ********************************************************** * Pass final data. Besides fields here you may receive also * file descriptor. Data is just what was already received * on the socket passed by TransferConnectionRequest. */ #pragma pack(push, 1) typedef struct VixMsgTransferFinalDataRequest { VixCommandRequestHeader header; uint32 dataLength; uint32 fdLength; /* uint8 data[]; */ /* uint8 fdData[]; */ } VixMsgTransferFinalDataRequest; #pragma pack(pop) /* * ********************************************************** * Create a snapshot of a running VM. */ #pragma pack(push, 1) typedef struct VixMsgCreateSnapshotRequest { VixCommandRequestHeader header; int32 options; Bool powerOff; Bool saveDeviceState; uint32 nameLength; uint32 descriptionLength; } VixMsgCreateSnapshotRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgCreateSnapshotResponse { VixCommandResponseHeader header; int32 snapshotUID; } VixMsgCreateSnapshotResponse; #pragma pack(pop) /* * Several snapshot operations for a running VM. */ #pragma pack(push, 1) typedef struct VixMsgSnapshotRequest { VixCommandRequestHeader header; int32 options; int32 snapshotId; } VixMsgSnapshotRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSnapshotUpdateEvent { VixMsgEventHeader eventHeader; int32 options; uint32 propertyListLength; /* * This is followed by a serialized property list. */ } VixMsgSnapshotUpdateEvent; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSnapshotMRURequest { VixCommandRequestHeader header; int32 snapshotId; int32 maxMRU; } VixMsgSnapshotMRURequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSetSnapshotInfoRequest { VixCommandRequestHeader header; int32 snapshotId; int32 clientFlags; int32 numTierUIDs; uint32 displayNameLength; uint32 descriptionLength; uint32 propertyListLength; uint32 tierUIDListLength; /* * Followed by: * displayName string * description string * serialized property list. */ } VixMsgSetSnapshotInfoRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSetSnapshotInfoResponse { VixCommandResponseHeader header; uint32 propertyListLength; } VixMsgSetSnapshotInfoResponse; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgRemoveBulkSnapshotRequest { VixCommandRequestHeader header; int32 options; int32 numSnapshots; /* * This is followed by numSnapshots snapshotIDs. */ } VixMsgRemoveBulkSnapshotRequest; #pragma pack(pop) /* * Stop recording or playback of a snapshot event log. */ #pragma pack(push, 1) typedef struct VixMsgVMSnapshotPauseRequest { VixCommandRequestHeader header; int32 options; } VixMsgVMSnapshotPauseRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgDebuggerEvent { VixMsgEventHeader eventHeader; int32 blobLength; /* * This is followed by the blob buffer. */ } VixMsgDebuggerEvent; #pragma pack(pop) /* * ********************************************************** * Shared folder operations. */ #pragma pack(push, 1) typedef struct VixMsgSharedFolderRequest { VixCommandRequestHeader header; int32 options; int32 index; uint32 shareNameLength; uint32 hostPathNameLength; } VixMsgSharedFolderRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSharedFolderResponse { VixCommandResponseHeader header; int32 numSharedFolders; } VixMsgSharedFolderResponse; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgGetSharedFolderInfoResponse { VixCommandResponseHeader header; uint32 shareNameLength; uint32 hostPathNameLength; int32 sharedFolderFlags; } VixMsgGetSharedFolderInfoResponse; #pragma pack(pop) /* * Add or change a shared folder request. */ #pragma pack(push, 1) typedef struct VixMsgSetSharedFolderRequest { VixCommandRequestHeader header; int32 options; uint32 shareNameLength; uint32 hostPathNameLength; } VixMsgSetSharedFolderRequest; #pragma pack(pop) /* * ********************************************************** * Capture the screen of a VM */ #pragma pack(push, 1) typedef struct VixMsgCaptureScreenRequest { VixCommandRequestHeader header; int32 format; // Identifies the requested data format. int32 maxSize; // Max data response size in bytes // (-1 is any size) int32 captureScreenOptions; } VixMsgCaptureScreenRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgCaptureScreenResponse { VixCommandResponseHeader header; int32 format; // Format of the data in the response. uint32 dataOffset; // Relative to the address of this struct. } VixMsgCaptureScreenResponse; #pragma pack(pop) /* * ********************************************************** * Run a script in the guest. */ #pragma pack(push, 1) typedef struct VixMsgRunScriptRequest { VixCommandRequestHeader header; int32 scriptOptions; uint32 interpreterNameLength; uint32 scriptLength; uint32 propertiesLength; } VixMsgRunScriptRequest; #pragma pack(pop) /* * ********************************************************** * An unsupported command. This is used to test future versions * of the API sending us commands we don't recognize. */ #pragma pack(push, 1) typedef struct VixUnsupportedCommandRequest { VixCommandRequestHeader header; char junk[2053]; } VixUnsupportedCommandRequest; #pragma pack(pop) /* * ********************************************************** * Create a session key between the client and the VMX. */ #pragma pack(push, 1) typedef struct VixCommandMakeSessionKeyRequest { VixCommandRequestHeader header; int32 keyOptions; int32 timeout; uint32 responseKeyLength; int32 responseKeyCypherType; int32 cypherType; } VixCommandMakeSessionKeyRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixCommandMakeSessionKeyResponse { VixCommandResponseHeader header; int32 keyOptions; int32 timeout; uint32 keyLength; int32 cypherType; } VixCommandMakeSessionKeyResponse; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixCommandGenerateNonceResponse { VixCommandResponseHeader header; int64 nonce; } VixCommandGenerateNonceResponse; #pragma pack(pop) enum { VIX_CYPHERTYPE_NONE = 0, VIX_CYPHERTYPE_DEFAULT = 1, }; /* * ********************************************************** * Force a guest process to quit. */ #pragma pack(push, 1) typedef struct VixCommandKillProcessRequest { VixCommandRequestHeader header; uint64 pid; uint32 options; } VixCommandKillProcessRequest; #pragma pack(pop) /* * ********************************************************** * Read and write variables like guest variables and config values. */ #pragma pack(push, 1) typedef struct VixMsgReadVariableRequest { VixCommandRequestHeader header; int32 variableType; int32 options; uint32 nameLength; } VixMsgReadVariableRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgReadVariableResponse { VixCommandResponseHeader header; int32 valueType; int32 valueProperties; uint32 valueLength; } VixMsgReadVariableResponse; #pragma pack(pop) /* * Several snapshot operations for a running VM. */ #pragma pack(push, 1) typedef struct VixMsgWriteVariableRequest { VixCommandRequestHeader header; int32 variableType; int32 options; uint32 nameLength; uint32 valueLength; } VixMsgWriteVariableRequest; #pragma pack(pop) /* * ********************************************************** * Perform a create file operation (like createDir or moveFile) * on a file in the guest. This lets you pass in things like the initial file * properties. */ #pragma pack(push, 1) typedef struct VixMsgCreateTempFileRequest { VixCommandRequestHeader header; int32 options; uint32 propertyNameLength; uint32 filePrefixLength; uint32 fileSuffixLength; } VixMsgCreateTempFileRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgCreateTempFileRequestEx { VixCommandRequestHeader header; int32 options; uint32 filePrefixLength; uint32 fileSuffixLength; uint32 directoryPathLength; uint32 propertyListLength; } VixMsgCreateTempFileRequestEx; #pragma pack(pop) #pragma pack(push, 1) typedef struct { VixCommandRequestHeader header; int32 fileOptions; uint32 guestPathNameLength; uint32 filePropertiesLength; Bool recursive; } VixMsgDeleteDirectoryRequest; #pragma pack(pop) /* * ********************************************************** * Connect/Disconnect device request. The response is just a generic * response header (it has no body). */ #pragma pack(push, 1) typedef struct VixMsgConnectDeviceRequest { VixCommandRequestHeader header; int32 options; Bool connected; uint32 nameLength; } VixMsgConnectDeviceRequest; #pragma pack(pop) /* * ********************************************************** * Get the state of a virtual device. */ #pragma pack(push, 1) typedef struct VixMsgGetDeviceStateRequest { VixCommandRequestHeader header; int32 options; uint32 nameLength; } VixMsgGetDeviceStateRequest; #pragma pack(pop) /* * This is used to reply to IsDeviceConnected operations. */ #pragma pack(push, 1) typedef struct VixMsgGetDeviceStateResponse { VixCommandResponseHeader header; Bool connected; int32 stateFlags; // Maybe capacity and percent allocated? } VixMsgGetDeviceStateResponse; #pragma pack(pop) /* * ********************************************************** * Enable/disable all shared folders on this VM. The response * is just a generic response header (it has no body). */ #pragma pack(push, 1) typedef struct VixMsgEnableSharedFoldersRequest { VixCommandRequestHeader header; Bool enabled; int32 sharedFolderOptions; } VixMsgEnableSharedFoldersRequest; #pragma pack(pop) /* * ********************************************************** * Mount volumes in the guest. */ enum VixMountOptions { VIX_MOUNT_ALL = 0x0001, VIX_MOUNT_REMOUNT_FIRST = 0x0002, }; #pragma pack(push, 1) typedef struct VixMsgMountHGFSRequest { VixCommandRequestHeader header; int32 mountOptions; int32 mountType; /* The str path list has the form "host1\0dest1\0host2\0dest2\0host3\0dest3\0\0" */ uint32 pathListLength; } VixMsgMountHGFSRequest; #pragma pack(pop) /* * Get guest networking config */ #pragma pack(push, 1) typedef struct VixMsgGetGuestNetworkingConfigRequest { VixCommandRequestHeader header; int32 options; } VixMsgGetGuestNetworkingConfigRequest; #pragma pack(pop) /* * Set guest networking config */ #pragma pack(push, 1) typedef struct VixMsgSetGuestNetworkingConfigRequest { VixCommandRequestHeader header; int32 options; uint32 bufferSize; } VixMsgSetGuestNetworkingConfigRequest; #pragma pack(pop) /* * Query VMX performance data */ #pragma pack(push, 1) typedef struct VixMsgGetPerformanceDataRequest { VixCommandRequestHeader header; // unused for now, but left for future expansion in case we // get such a large list that we want to pass the desired properties. int32 options; uint32 sizeOfPropertyList; // This is followed by the buffer of properties we wish to fetch } VixMsgGetPerformanceDataRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgGetPerformanceDataResponse { VixCommandResponseHeader header; uint32 bufferSize; // This is followed by the buffer of serialized properties } VixMsgGetPerformanceDataResponse; #pragma pack(pop) /* * Run a program in guest with (VI version with more args) */ #pragma pack(push, 1) typedef struct VixMsgStartProgramRequest { VixCommandRequestHeader header; Bool startMinimized; uint32 programPathLength; uint32 argumentsLength; uint32 workingDirLength; uint32 numEnvVars; uint32 envVarLength; // This is followed by the buffer of the args } VixMsgStartProgramRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgListProcessesExRequest { VixCommandRequestHeader header; // if we need to make multiple trips, this is the key used to identify // the result being processed uint32 key; // if we need to make multiple trips, this is the offset in the reply // from which to send the next chunk uint32 offset; uint32 numPids; // This is followed by the list of uint64s } VixMsgListProcessesExRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgReadEnvironmentVariablesRequest { VixCommandRequestHeader header; uint32 numNames; uint32 namesLength; // This is followed by the list of NUL-terminated names } VixMsgReadEnvironmentVariablesRequest; #pragma pack(pop) /* IdProvider support */ #pragma pack(push, 1) typedef struct VixMsgAddAliasRequest { VixCommandRequestHeader header; uint32 options; uint32 userNameLen; uint32 pemCertLen; Bool addMapping; int32 subjectType; // one of VixGuestAuthSubjectType uint32 subjectNameLen; uint32 aliasCommentLen; /* Followed by the NUL-terminated string arguments. */ /* char[] userName; */ /* char[] pemCert; */ /* char[] subjectName; */ /* char[] aliasComment; */ } VixMsgAddAuthAliasRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgRemoveAuthAliasRequest { VixCommandRequestHeader header; uint32 options; uint32 userNameLen; uint32 pemCertLen; // special case for RemoveAliasByCert: // if subjectType is NONE, then all aliases will be removed. int32 subjectType; // one of VixGuestAuthSubjectType uint32 subjectNameLen; /* Followed by the NUL-terminated string arguments. */ /* char[] userName; */ /* char[] pemCert; */ /* char[] subjectName; */ } VixMsgRemoveAuthAliasRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgListAuthAliasesRequest { VixCommandRequestHeader header; uint32 options; uint32 userNameLen; /* char[] userName; */ } VixMsgListAuthAliasesRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgListMappedAliasesRequest { VixCommandRequestHeader header; uint32 options; } VixMsgListMappedAliasesRequest; #pragma pack(pop) /* * Windows Registry Management Support. */ #pragma pack(push, 1) typedef struct VixMsgCreateRegKeyRequest { VixCommandRequestHeader header; uint32 options; uint32 pathLength; uint32 wowBitness; Bool isVolatile; uint32 classTypeLength; /* * Followed by NUL-terminated string arguments. * char[] path; * char[] classType; */ } VixMsgCreateRegKeyRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgListRegKeysRequest { VixCommandRequestHeader header; uint32 options; /* * If we need multiple roundtrips, this is the index * used to identify the result being processed. */ uint32 index; /* * If we need multiple roundtrips, this is the offset * in the reply from which to send the next chunk. */ uint32 offset; uint32 pathLength; uint32 wowBitness; Bool recursive; uint32 matchPatternLength; /* * Followed by NUL-terminated string arguments. * char[] path; * char[] matchPattern; */ } VixMsgListRegKeysRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgDeleteRegKeyRequest { VixCommandRequestHeader header; uint32 options; uint32 pathLength; uint32 wowBitness; Bool recursive; /* * Followed by NUL-terminated string arguments. * char[] path; */ } VixMsgDeleteRegKeyRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSetRegValueRequest { VixCommandRequestHeader header; uint32 options; uint32 pathLength; uint32 wowBitness; uint32 nameLength; uint32 dataBlobType; uint32 dataBlobLength; /* * Followed by NUL-terminated string arguments. * char[] path; * char[] name; * * Followed by a data blob of specified length * containing information of specified type. * void *dataBlob; */ } VixMsgSetRegValueRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgListRegValuesRequest { VixCommandRequestHeader header; uint32 options; /* * If we need multiple roundtrips, this is the index * used to identify the result being processed. */ uint32 index; /* * If we need multiple roundtrips, this is the offset * in the reply from which to send the next chunk. */ uint32 offset; uint32 pathLength; uint32 wowBitness; Bool expandStrings; uint32 matchPatternLength; /* * Followed by NUL-terminated string arguments. * char[] path; * char[] matchPattern; */ } VixMsgListRegValuesRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgDeleteRegValueRequest { VixCommandRequestHeader header; uint32 options; uint32 pathLength; uint32 wowBitness; uint32 nameLength; /* * Followed by NUL-terminated string arguments. * char[] path; * char[] name; */ } VixMsgDeleteRegValueRequest; #pragma pack(pop) /* * HOWTO: Adding a new Vix Command. Step 3. * * Add a new struct to pass over the control socket into the VMX. * You only need to do this if your command is manipulating a running * VM, but that is a common situation. If your command only manipulates * non-running VMs, then you can skip this. * * This particular command passes strings as both a param and a * result. This is the most general case, because it means that both * the request and response have a variable-length string on the end. * You can make a simpler request or response if it only passes integers * and so is fixed size. */ /* * ********************************************************** * Sample Command. */ #pragma pack(push, 1) typedef struct VixMsgSampleCommandRequest { VixCommandRequestHeader header; int32 intArg; uint32 strArgLength; } VixMsgSampleCommandRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgSampleCommandResponse { VixCommandResponseHeader header; int32 intResult; uint32 strResultLength; } VixMsgSampleCommandResponse; #pragma pack(pop) // End of "HOWTO: Adding a new Vix Command. Step 3." /* * ********************************************************** * Debugger related commands. */ #pragma pack(push, 1) typedef struct VixMsgAttachDebuggerRequest { VixCommandRequestHeader header; int32 options; uint32 propertyListBufferSize; } VixMsgAttachDebuggerRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgAttachDebuggerResponse { VixCommandResponseHeader header; uint32 propertyListBufferSize; } VixMsgAttachDebuggerResponse; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgIssueDebuggerCommandRequest { VixCommandRequestHeader header; int32 options; uint32 propertyListBufferSize; uint32 debuggerBlobBufferSize; } VixMsgIssueDebuggerCommandRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgIssueDebuggerCommandResponse { VixCommandResponseHeader header; uint32 propertyListBufferSize; uint32 debuggerBlobBufferSize; } VixMsgIssueDebuggerCommandResponse; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgDetachDebuggerRequest { VixCommandRequestHeader header; int32 options; uint32 propertyListBufferSize; } VixMsgDetachDebuggerRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgDetachDebuggerResponse { VixCommandResponseHeader header; uint32 propertyListBufferSize; } VixMsgDetachDebuggerResponse; #pragma pack(pop) /* * ********************************************************** * VM Pause state change event format */ #pragma pack(push, 1) typedef struct VixMsgPauseStateChangedEvent { VixMsgEventHeader eventHeader; Bool paused; } VixMsgPauseStateChangedEvent; #pragma pack(pop) /* * ********************************************************** * Wait for a user action, such as a user logging into the guest. */ /* * Vix_WaitForUserActionInGuest Request * VIX_COMMAND_WAIT_FOR_USER_ACTION_IN_GUEST */ #pragma pack(push, 1) typedef struct VixMsgWaitForUserActionRequest { VixCommandRequestHeader header; int32 userType; int32 userAction; int32 timeoutInSeconds; int32 options; uint32 userNameLength; uint32 propertyBufferSize; // This is followed by: // userName // buffer of serialized properties } VixMsgWaitForUserActionRequest; #pragma pack(pop) #pragma pack(push, 1) typedef struct VixMsgWaitForUserActionResponse { VixCommandRequestHeader header; Bool actionHappened; uint32 bufferSize; // This is followed by the buffer of serialized properties } VixMsgWaitForUserActionResponse; #pragma pack(pop) /* * ********************************************************** * List filesystems */ #pragma pack(push, 1) typedef struct VixCommandListFileSystemsRequest { VixCommandRequestHeader header; uint32 options; uint32 propertyListSize; } VixCommandListFileSystemsRequest; #pragma pack(pop) /* * ********************************************************** * Acquire Credentials. */ #pragma pack(push, 1) typedef struct VixCommandAcquireCredentialsRequest { VixCommandRequestHeader header; int64 sessionID; } VixCommandAcquireCredentialsRequest; #pragma pack(pop) /* * ********************************************************** * A simple request packet that contains an options field and a * property list. */ #pragma pack(push, 1) typedef struct VixCommandGenericRequest { VixCommandRequestHeader header; uint32 options; uint32 propertyListSize; // This is followed by the buffer of serialized properties } VixCommandGenericRequest; #pragma pack(pop) /* * The security classifications for async op types/op code. Each op code * is given a security category, and the VMX uses that category to determine * whether a client is allowed to perform the given command. */ typedef enum VixCommandSecurityCategory { /* The default for unknown commands */ VIX_COMMAND_CATEGORY_UNKNOWN, /* * A command that should be executed in the guest OS by the VIX Tools. * component. These are allowed for all connection types. */ VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED, /* * A command that only allowed by privileged connections; in the VI * world this is means that only Hostd is allowed to perform these * commands. */ VIX_COMMAND_CATEGORY_PRIVILEGED, /* * A command that may or may not be privileged. Usually, extra inspection * of the payload is required to make the determination. This should be * used sparingly, since must always be accompanied by "deep packet * inspection" code in the VMX (mainDispatch.c). */ VIX_COMMAND_CATEGORY_MIXED, } VixCommandSecurityCategory; /* * This is the list of all Vix commands * * Be really careful with these. These values are passed over the socket * between clients and the VMX process. One client may connect to newer or * older versions of the VMX, so we cannot ever change or recycle values if * if we add or remove command ids. This is why the values are explicitly * assigned, and there may be gaps in the numeric sequence as some commands * are no longer supported. */ typedef int VixAsyncOpType; enum { VIX_COMMAND_UNKNOWN = -1, VIX_COMMAND_VM_POWERON = 0, VIX_COMMAND_VM_POWEROFF = 1, VIX_COMMAND_VM_RESET = 2, VIX_COMMAND_VM_SUSPEND = 3, VIX_COMMAND_RUN_PROGRAM = 4, /* DEPRECATED VIX_COMMAND_GET_PROPERTY = 5, */ /* DEPRECATED VIX_COMMAND_SET_PROPERTY = 6, */ VIX_COMMAND_KEYSTROKES = 7, VIX_COMMAND_READ_REGISTRY = 8, VIX_COMMAND_WRITE_REGISTRY = 10, VIX_COMMAND_COPY_FILE_FROM_GUEST_TO_HOST = 12, VIX_COMMAND_COPY_FILE_FROM_HOST_TO_GUEST = 13, VIX_COMMAND_CREATE_SNAPSHOT = 14, VIX_COMMAND_REMOVE_SNAPSHOT = 15, VIX_COMMAND_REVERT_TO_SNAPSHOT = 16, VIX_COMMAND_VM_CLONE = 17, VIX_COMMAND_DELETE_GUEST_FILE = 18, VIX_COMMAND_GUEST_FILE_EXISTS = 19, VIX_COMMAND_FIND_VM = 20, VIX_COMMAND_CALL_PROCEDURE = 21, VIX_COMMAND_REGISTRY_KEY_EXISTS = 22, VIX_COMMAND_WIN32_WINDOW_MESSAGE = 23, VIX_COMMAND_CONSOLIDATE_SNAPSHOTS = 24, VIX_COMMAND_INSTALL_TOOLS = 25, VIX_COMMAND_CANCEL_INSTALL_TOOLS = 26, VIX_COMMAND_UPGRADE_VIRTUAL_HARDWARE = 27, VIX_COMMAND_SET_NIC_BANDWIDTH = 28, /* DEPRECATED VIX_COMMAND_CREATE_DISK = 29, */ /* DEPRECATED VIX_COMMAND_CREATE_FLOPPY = 30, */ VIX_COMMAND_RELOAD_VM = 31, VIX_COMMAND_DELETE_VM = 32, /* DEPRECATED VIX_COMMAND_SYNCDRIVER_FREEZE = 33, */ /* DEPRECATED VIX_COMMAND_SYNCDRIVER_THAW = 34, */ /* DEPRECATED VIX_COMMAND_HOT_ADD_DISK = 35, */ /* DEPRECATED VIX_COMMAND_HOT_REMOVE_DISK = 36, */ /* DEPRECATED VIX_COMMAND_SET_GUEST_PRINTER = 37, */ VIX_COMMAND_WAIT_FOR_TOOLS = 38, VIX_COMMAND_CREATE_RUNNING_VM_SNAPSHOT = 39, VIX_COMMAND_CONSOLIDATE_RUNNING_VM_SNAPSHOT = 40, VIX_COMMAND_GET_NUM_SHARED_FOLDERS = 41, VIX_COMMAND_GET_SHARED_FOLDER_STATE = 42, VIX_COMMAND_EDIT_SHARED_FOLDER_STATE = 43, VIX_COMMAND_REMOVE_SHARED_FOLDER = 44, VIX_COMMAND_ADD_SHARED_FOLDER = 45, VIX_COMMAND_RUN_SCRIPT_IN_GUEST = 46, VIX_COMMAND_OPEN_VM = 47, /* DEPRECATED VIX_COMMAND_GET_DISK_PROPERTIES = 48, */ /* DEPRECATED VIX_COMMAND_OPEN_URL = 49, */ VIX_COMMAND_GET_HANDLE_STATE = 50, /* DEPRECATED VIX_COMMAND_SET_HANDLE_STATE = 51, */ VIX_COMMAND_CREATE_WORKING_COPY = 55, // DELETE this when we switch remote foundry to VIM VIX_COMMAND_DISCARD_WORKING_COPY = 56, // DELETE this when we switch remote foundry to VIM VIX_COMMAND_SAVE_WORKING_COPY = 57, // DELETE this when we switch remote foundry to VIM VIX_COMMAND_CAPTURE_SCREEN = 58, /* DEPRECATED VIX_COMMAND_GET_VMDB_VALUES = 59, */ /* DEPRECATED VIX_COMMAND_SET_VMDB_VALUES = 60, */ /* DEPRECATED VIX_COMMAND_READ_XML_FILE = 61, */ VIX_COMMAND_GET_TOOLS_STATE = 62, VIX_COMMAND_CHANGE_SCREEN_RESOLUTION = 69, VIX_COMMAND_DIRECTORY_EXISTS = 70, VIX_COMMAND_DELETE_GUEST_REGISTRY_KEY = 71, VIX_COMMAND_DELETE_GUEST_DIRECTORY = 72, VIX_COMMAND_DELETE_GUEST_EMPTY_DIRECTORY = 73, VIX_COMMAND_CREATE_TEMPORARY_FILE = 74, VIX_COMMAND_LIST_PROCESSES = 75, VIX_COMMAND_MOVE_GUEST_FILE = 76, VIX_COMMAND_CREATE_DIRECTORY = 77, VIX_COMMAND_CHECK_USER_ACCOUNT = 78, VIX_COMMAND_LIST_DIRECTORY = 79, VIX_COMMAND_REGISTER_VM = 80, VIX_COMMAND_UNREGISTER_VM = 81, VIX_CREATE_SESSION_KEY_COMMAND = 83, VMXI_HGFS_SEND_PACKET_COMMAND = 84, VIX_COMMAND_KILL_PROCESS = 85, /* DEPRECATED VIX_VM_FORK_COMMAND = 86, */ VIX_COMMAND_LOGOUT_IN_GUEST = 87, VIX_COMMAND_READ_VARIABLE = 88, VIX_COMMAND_WRITE_VARIABLE = 89, VIX_COMMAND_CONNECT_DEVICE = 92, VIX_COMMAND_IS_DEVICE_CONNECTED = 93, VIX_COMMAND_GET_FILE_INFO = 94, VIX_COMMAND_SET_FILE_INFO = 95, VIX_COMMAND_MOUSE_EVENTS = 96, VIX_COMMAND_OPEN_TEAM = 97, /* DEPRECATED VIX_COMMAND_FIND_HOST_DEVICES = 98, */ VIX_COMMAND_ANSWER_MESSAGE = 99, VIX_COMMAND_ENABLE_SHARED_FOLDERS = 100, VIX_COMMAND_MOUNT_HGFS_FOLDERS = 101, VIX_COMMAND_HOT_EXTEND_DISK = 102, /* DEPRECATED VIX_COMMAND_GET_VPROBES_VERSION = 104, */ /* DEPRECATED VIX_COMMAND_GET_VPROBES = 105, */ /* DEPRECATED VIX_COMMAND_VPROBE_GET_GLOBALS = 106, */ /* DEPRECATED VIX_COMMAND_VPROBE_LOAD = 107, */ /* DEPRECATED VIX_COMMAND_VPROBE_RESET = 108, */ /* DEPRECATED VIX_COMMAND_LIST_USB_DEVICES = 109, */ VIX_COMMAND_CONNECT_HOST = 110, VIX_COMMAND_CREATE_LINKED_CLONE = 112, /* DEPRECATED VIX_COMMAND_STOP_SNAPSHOT_LOG_RECORDING = 113, */ /* DEPRECATED VIX_COMMAND_STOP_SNAPSHOT_LOG_PLAYBACK = 114, */ VIX_COMMAND_SAMPLE_COMMAND = 115, VIX_COMMAND_GET_GUEST_NETWORKING_CONFIG = 116, VIX_COMMAND_SET_GUEST_NETWORKING_CONFIG = 117, /* DEPRECATED VIX_COMMAND_FAULT_TOLERANCE_REGISTER = 118, */ /* DEPRECATED VIX_COMMAND_FAULT_TOLERANCE_UNREGISTER = 119, */ /* DEPRECATED VIX_COMMAND_FAULT_TOLERANCE_CONTROL = 120, */ /* DEPRECATED VIX_COMMAND_FAULT_TOLERANCE_QUERY_SECONDARY = 121, */ VIX_COMMAND_VM_PAUSE = 122, VIX_COMMAND_VM_UNPAUSE = 123, /* DEPRECATED VIX_COMMAND_GET_SNAPSHOT_LOG_INFO = 124, */ /* DEPRECATED VIX_COMMAND_SET_REPLAY_SPEED = 125, */ /* DEPRECATED VIX_COMMAND_ANSWER_USER_MESSAGE = 126, */ /* DEPRECATED VIX_COMMAND_SET_CLIENT_LOCALE = 127, */ VIX_COMMAND_GET_PERFORMANCE_DATA = 128, /* DEPRECATED VIX_COMMAND_REFRESH_RUNTIME_PROPERTIES = 129, */ VIX_COMMAND_GET_SNAPSHOT_SCREENSHOT = 130, /* DEPRECATED VIX_COMMAND_ADD_TIMEMARKER = 131, */ VIX_COMMAND_WAIT_FOR_USER_ACTION_IN_GUEST = 132, /* DEPRECATED VIX_COMMAND_VMDB_END_TRANSACTION = 133, */ /* DEPRECATED VIX_COMMAND_VMDB_SET = 134, */ VIX_COMMAND_CHANGE_VIRTUAL_HARDWARE = 135, VIX_COMMAND_HOT_PLUG_CPU = 136, VIX_COMMAND_HOT_PLUG_MEMORY = 137, VIX_COMMAND_HOT_ADD_DEVICE = 138, VIX_COMMAND_HOT_REMOVE_DEVICE = 139, /* DEPRECATED VIX_COMMAND_DEBUGGER_ATTACH = 140, */ /* DEPRECATED VIX_COMMAND_DEBUGGER_DETACH = 141, */ /* DEPRECATED VIX_COMMAND_DEBUGGER_SEND_COMMAND = 142, */ /* DEPRECATED VIX_COMMAND_GET_RECORD_STATE = 143, */ /* DEPRECATED VIX_COMMAND_SET_RECORD_STATE = 144, */ /* DEPRECATED VIX_COMMAND_REMOVE_RECORD_STATE = 145, */ /* DEPRECATED VIX_COMMAND_GET_REPLAY_STATE = 146, */ /* DEPRECATED VIX_COMMAND_SET_REPLAY_STATE = 147, */ /* DEPRECATED VIX_COMMAND_REMOVE_REPLAY_STATE = 148, */ /* DEPRECATED VIX_COMMAND_CANCEL_USER_PROGRESS_MESSAGE = 150, */ VIX_COMMAND_GET_VMX_DEVICE_STATE = 151, /* DEPRECATED VIX_COMMAND_GET_NUM_TIMEMARKERS = 152, */ /* DEPRECATED VIX_COMMAND_GET_TIMEMARKER = 153, */ /* DEPRECATED VIX_COMMAND_REMOVE_TIMEMARKER = 154, */ VIX_COMMAND_SET_SNAPSHOT_INFO = 155, VIX_COMMAND_SNAPSHOT_SET_MRU = 156, VIX_COMMAND_LOGOUT_HOST = 157, VIX_COMMAND_HOT_PLUG_BEGIN_BATCH = 158, VIX_COMMAND_HOT_PLUG_COMMIT_BATCH = 159, VIX_COMMAND_TRANSFER_CONNECTION = 160, VIX_COMMAND_TRANSFER_REQUEST = 161, VIX_COMMAND_TRANSFER_FINAL_DATA = 162, /* DEPRECATED VIX_COMMAND_ADD_ROLLING_SNAPSHOT_TIER = 163, */ /* DEPRECATED VIX_COMMAND_REMOVE_ROLLING_SNAPSHOT_TIER = 164, */ /* DEPRECATED VIX_COMMAND_LIST_ROLLING_SNAPSHOT_TIER = 165, */ /* DEPRECATED VIX_COMMAND_ADD_ROLLING_SNAPSHOT_TIER_VMX = 166, */ /* DEPRECATED VIX_COMMAND_REMOVE_ROLLING_SNAPSHOT_TIER_VMX = 167, */ /* DEPRECATED VIX_COMMAND_LIST_ROLLING_SNAPSHOT_TIER_VMX = 168, */ VIX_COMMAND_LIST_FILESYSTEMS = 169, VIX_COMMAND_CHANGE_DISPLAY_TOPOLOGY = 170, VIX_COMMAND_SUSPEND_AND_RESUME = 171, VIX_COMMAND_REMOVE_BULK_SNAPSHOT = 172, VIX_COMMAND_COPY_FILE_FROM_READER_TO_GUEST = 173, VIX_COMMAND_GENERATE_NONCE = 174, VIX_COMMAND_CHANGE_DISPLAY_TOPOLOGY_MODES = 175, VIX_COMMAND_QUERY_CHILDREN = 176, VIX_COMMAND_LIST_FILES = 177, VIX_COMMAND_CREATE_DIRECTORY_EX = 178, VIX_COMMAND_MOVE_GUEST_FILE_EX = 179, VIX_COMMAND_MOVE_GUEST_DIRECTORY = 180, VIX_COMMAND_CREATE_TEMPORARY_FILE_EX = 181, VIX_COMMAND_CREATE_TEMPORARY_DIRECTORY = 182, VIX_COMMAND_SET_GUEST_FILE_ATTRIBUTES = 183, VIX_COMMAND_COPY_FILE_FROM_GUEST_TO_READER = 184, VIX_COMMAND_START_PROGRAM = 185, VIX_COMMAND_LIST_PROCESSES_EX = 186, VIX_COMMAND_READ_ENV_VARIABLES = 187, VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST = 188, VIX_COMMAND_INITIATE_FILE_TRANSFER_TO_GUEST = 189, VIX_COMMAND_ACQUIRE_CREDENTIALS = 190, VIX_COMMAND_RELEASE_CREDENTIALS = 191, VIX_COMMAND_VALIDATE_CREDENTIALS = 192, VIX_COMMAND_TERMINATE_PROCESS = 193, VIX_COMMAND_DELETE_GUEST_FILE_EX = 194, VIX_COMMAND_DELETE_GUEST_DIRECTORY_EX = 195, VIX_COMMAND_HOT_CHANGE_MONITOR_TYPE = 196, VIX_COMMAND_ADD_AUTH_ALIAS = 197, VIX_COMMAND_REMOVE_AUTH_ALIAS = 198, VIX_COMMAND_LIST_AUTH_PROVIDER_ALIASES = 199, VIX_COMMAND_LIST_AUTH_MAPPED_ALIASES = 200, VIX_COMMAND_CREATE_REGISTRY_KEY = 201, VIX_COMMAND_LIST_REGISTRY_KEYS = 202, VIX_COMMAND_DELETE_REGISTRY_KEY = 203, VIX_COMMAND_SET_REGISTRY_VALUE = 204, VIX_COMMAND_LIST_REGISTRY_VALUES = 205, VIX_COMMAND_DELETE_REGISTRY_VALUE = 206, VIX_COMMAND_REMOVE_AUTH_ALIAS_BY_CERT = 207, /* * HOWTO: Adding a new Vix Command. Step 2a. * * Add a new ID for your new function prototype here. BE CAREFUL. The * OFFICIAL list of id's is in the bfg-main tree, in bora/lib/public/vixCommands.h. * When people add new command id's in different tree, they may collide and use * the same ID values. This can merge without conflicts, and cause runtime bugs. * Once a new command is added here, a command info field needs to be added * in bora/lib/foundryMsg/foundryMsg.c as well. */ VIX_COMMAND_LAST_NORMAL_COMMAND = 208, VIX_TEST_UNSUPPORTED_TOOLS_OPCODE_COMMAND = 998, VIX_TEST_UNSUPPORTED_VMX_OPCODE_COMMAND = 999, }; /* * These are the command names that are passed through the backdoor from the * VMX to the tools. */ #define VIX_BACKDOOR_COMMAND_VERSION "Vix_1_" #define VIX_BACKDOORCOMMAND_RUN_PROGRAM VIX_BACKDOOR_COMMAND_VERSION"Run_Program" #define VIX_BACKDOORCOMMAND_SYNCDRIVER_FREEZE VIX_BACKDOOR_COMMAND_VERSION"SyncDriver_Freeze" #define VIX_BACKDOORCOMMAND_SYNCDRIVER_THAW VIX_BACKDOOR_COMMAND_VERSION"SyncDriver_Thaw" #define VIX_BACKDOORCOMMAND_GET_PROPERTIES VIX_BACKDOOR_COMMAND_VERSION"Get_ToolsProperties" #define VIX_BACKDOORCOMMAND_UNRECOGNIZED_COMMAND VIX_BACKDOOR_COMMAND_VERSION"Unrecognized_Command" #define VIX_BACKDOORCOMMAND_COMMAND VIX_BACKDOOR_COMMAND_VERSION"Relayed_Command" #define VIX_BACKDOORCOMMAND_MOUNT_VOLUME_LIST VIX_BACKDOOR_COMMAND_VERSION"Mount_Volumes" /* * This is the set of features that may be supported by different * versions of the VMX or Vix Tools. */ enum VixToolsFeatures { VIX_TOOLSFEATURE_SUPPORT_GET_HANDLE_STATE = 0x0001, /* VIX_TOOLSFEATURE_SUPPORT_OPEN_URL = 0x0002, Removed in version 1.11*/ }; enum { VIX_TOOLS_READ_FILE_ACCESS = 0x01, VIX_TOOLS_WRITE_FILE_ACCESS = 0x02, }; /* * These are the command names that are passed through the backdoor from the tools * to the VMX. */ #define VIX_BACKDOORCOMMAND_RUN_PROGRAM_DONE "Run_Program_Done" #define VIX_FEATURE_UNKNOWN_VALUE "Unknown" /* * VIX_COMMAND_RUN_PROGRAM returns 2 integer values as an array. These * are the indexes * TODO: Delete this enum */ enum VixRunProgramResultValues { VIX_COMMAND_RUN_PROGRAM_ELAPSED_TIME_RESULT = 0, VIX_COMMAND_RUN_PROGRAM_EXIT_CODE_RESULT = 1, }; /* These are the values of Vix objects. */ #define VIX_VM_OBJECT_TYPE "VixVM" /* VM enumeration */ #ifdef _WIN32 #define VIX_WINDOWSREGISTRY_VMWARE_KEY "Software\\" COMPANY_NAME #define VIX_WINDOWSREGISTRY_RUNNING_VM_LIST "Running VM List" #define VIX_WINDOWSREGISTRY_VMWARE_KEY_RUNNING_VM_LIST VIX_WINDOWSREGISTRY_VMWARE_KEY "\\" VIX_WINDOWSREGISTRY_RUNNING_VM_LIST #endif /* * This is used to denote that the contents of a VIX XML-like response * string has been escaped. Old Tools did not escape the contents. * This tag is only used for existing commands that did not originally perform * escaping. Any new command must always escape any strings passed in XML. * See ListProcessesInGuest as an example. * The protocol works as follows: * 1) A client library that internally knows how to handle escaped XML opts in * by including the VIX_REQUESTMSG_ESCAPE_XML_DATA in relevent requests. * 2) Tools that understands the VIX_REQUESTMSG_ESCAPE_XML_DATA flag sees that * it is set in the request, and then escapes all string data within the * XML response. To indicate to the client that it has understood the * request, it include the VIX_XML_ESCAPED_TAG in the response (at the * begining of the response). * 3) When the client library receives the response, it searches for the * VIX_XML_ESCAPED_TAG. If it is present, it then unescapes all string * data in the response. If the tag is not present, the client library * assumes that the Tools did not understand VIX_REQUESTMSG_ESCAPE_XML_DATA * and that the string data is not escaped. * The following characters are escaped: '<', '>', and '%'. * For new commands (starting with those released in M/N for the vSphere * guest ops project), the escaping is exactly the same, but the * VIX_REQUESTMSG_ESCAPE_XML_DATA flag and the VIX_XML_ESCAPED_TAG are not * used, since both ends expect escaping. */ #define VIX_XML_ESCAPED_TAG "" #define VIX_XML_ESCAPE_CHARACTER '%' /* *----------------------------------------------------------------------------- * * VixMsg -- * * These are the formatting and parsing utilities provided by the VixMsg * library. * *----------------------------------------------------------------------------- */ #ifndef VIX_HIDE_FROM_JAVA struct VixCommandRequestHeader * VixMsg_AllocRequestMsg(size_t msgHeaderAndBodyLength, int opCode, uint64 cookie, int credentialType, const char *userNamePassword); struct VixCommandResponseHeader * VixMsg_AllocResponseMsg(const struct VixCommandRequestHeader *requestHeader, VixError error, uint32 additionalError, size_t responseBodyLength, const void *responseBody, size_t *responseMsgLength); void VixMsg_InitResponseMsg(struct VixCommandResponseHeader *responseHeader, const struct VixCommandRequestHeader *requestHeader, VixError error, uint32 additionalError, size_t totalMessageLength); VixError VixMsg_ValidateMessage(const void *vMsg, size_t msgLength); VixError VixMsg_ValidateRequestMsg(const void *vMsg, size_t msgLength); VixError VixMsg_ValidateResponseMsg(const void *vMsg, size_t msgLength); VixError VixMsg_ParseWriteVariableRequest(VixMsgWriteVariableRequest *msg, char **valueName, char **value); VixError VixMsg_ObfuscateNamePassword(const char *userName, const char *password, char **result); VixError VixMsg_DeObfuscateNamePassword(const char *packagedName, char **userNameResult, char **passwordResult); VixError VixMsg_EncodeString(const char *str, char **result); VixError VixMsg_DecodeString(const char *str, char **result); Bool VixMsg_ValidateCommandInfoTable(void); const char *VixAsyncOp_GetDebugStrForOpCode(int opCode); VixCommandSecurityCategory VixMsg_GetCommandSecurityCategory(int opCode); /* * Vix private internal properties shared between the Vix client * and the VMX. */ enum { VIX_PROPERTY_VM_POWER_OFF_TO_SNAPSHOT_UID = 5102, }; VixError VixMsg_AllocGenericRequestMsg(int opCode, uint64 cookie, int credentialType, const char *userNamePassword, int options, VixPropertyListImpl *propertyList, VixCommandGenericRequest **request); VixError VixMsg_ParseGenericRequestMsg(const VixCommandGenericRequest *request, int *options, VixPropertyListImpl *propertyList); VixError VixMsg_ParseSimpleResponseWithString(const VixCommandResponseHeader *response, const char **result); void *VixMsg_MallocClientData(size_t size); void *VixMsg_ReallocClientData(void *ptr, size_t size); char *VixMsg_StrdupClientData(const char *s, Bool *allocateFailed); /* * Parser state used by VMAutomationMsgParser* group of functions. */ typedef struct { const char *currentPtr; const char *endPtr; } VMAutomationMsgParser; /* Keep the original type name around all the old code can stay the same. */ typedef VMAutomationMsgParser VMAutomationRequestParser; #define VMAutomationRequestParserInit VMAutomationMsgParserInitRequest #define VMAutomationMsgParserInitRequest(state, msg, fixedLength) \ __VMAutomationMsgParserInitRequest(__FUNCTION__, __LINE__, state, msg, fixedLength) VixError __VMAutomationMsgParserInitRequest(const char *caller, unsigned int line, VMAutomationMsgParser *state, const struct VixCommandRequestHeader *msg, size_t fixedLength); #define VMAutomationMsgParserInitResponse(state, msg, fixedLength) \ __VMAutomationMsgParserInitResponse(__FUNCTION__, __LINE__, state, msg, fixedLength) VixError __VMAutomationMsgParserInitResponse(const char *caller, unsigned int line, VMAutomationMsgParser *state, const struct VixCommandResponseHeader *msg, size_t fixedLength); #define VMAutomationRequestParserGetRemainingData \ VMAutomationMsgParserGetRemainingData const void * VMAutomationMsgParserGetRemainingData(VMAutomationMsgParser *state, size_t *length); #define VMAutomationRequestParserGetData VMAutomationMsgParserGetData #define VMAutomationMsgParserGetData(state, length, result) \ __VMAutomationMsgParserGetData(__FUNCTION__, __LINE__, \ state, length, (const char **)result) VixError __VMAutomationMsgParserGetData(const char *caller, unsigned int line, VMAutomationMsgParser *state, size_t length, const char **result); #define VMAutomationRequestParserGetOptionalString \ VMAutomationMsgParserGetOptionalString #define VMAutomationMsgParserGetOptionalString(state, length, result) \ __VMAutomationMsgParserGetOptionalString(__FUNCTION__, __LINE__, \ state, length, result) VixError __VMAutomationMsgParserGetOptionalString(const char *caller, unsigned int line, VMAutomationMsgParser *state, size_t length, const char **result); #define VMAutomationRequestParserGetOptionalStrings \ VMAutomationMsgParserGetOptionalStrings #define VMAutomationMsgParserGetOptionalStrings(state, count, length, \ result) \ __VMAutomationMsgParserGetOptionalStrings(__FUNCTION__, __LINE__, \ state, count, length, result) VixError __VMAutomationMsgParserGetOptionalStrings (const char *caller, unsigned int line, VMAutomationMsgParser *state, uint32 count, size_t length, const char **result); #define VMAutomationRequestParserGetString VMAutomationMsgParserGetString #define VMAutomationMsgParserGetString(state, length, result) \ __VMAutomationMsgParserGetString(__FUNCTION__, __LINE__, \ state, length, result) VixError __VMAutomationMsgParserGetString(const char *caller, unsigned int line, VMAutomationMsgParser *state, size_t length, const char **result); #define VMAutomationRequestParserGetPropertyList \ VMAutomationMsgParserGetPropertyList #define VMAutomationMsgParserGetPropertyList(state, length, propList) \ __VMAutomationMsgParserGetPropertyList(__FUNCTION__, __LINE__, \ state, length, propList) VixError __VMAutomationMsgParserGetPropertyList(const char *caller, unsigned int line, VMAutomationMsgParser *state, size_t length, VixPropertyListImpl *propList); #endif // VIX_HIDE_FROM_JAVA #if defined(__cplusplus) } // extern "C" #endif #endif // _VIX_COMMANDS_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vixOpenSource.h000066400000000000000000000716241470176644300255060ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2007-2021, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * This header file is given out as part of the open source * tools. Things in this file are public, but they may not have * been tested or documented, and that may change in future releases. * The public Vix API is defined in vix.h * * These definitions are used by the implementation of the vix * client, the VMX process, and the tols. * */ #ifndef _VIXOpenSource_h_ #define _VIXOpenSource_h_ #if defined(__cplusplus) extern "C" { #endif /* * VIX_HIDE_BORA_DEPENDENCIES: * * This flag allows some mini-applications to use parts of Vix that will * someday make it into the public API, without including all of the include * directories in bora. Specifically, some VMware apps will want to use a * separate, more public, build tree, but still make use API that have not been * publicly released yet. */ /* * VIX_HIDE_FROM_JAVA * * Setting this flag minizes the functions exposed here. The java * binding is generated by processing this header, resulting in a * large number of currently unused functions. To keep the number * of functions that need to be exposed via vixWrapper, we hide all * but the needed functions to java. */ /* * If we're hiding functions from java, also hide the bora dependencies. */ #ifdef VIX_HIDE_FROM_JAVA #define VIX_HIDE_BORA_DEPENDENCIES #endif #include "vm_basic_types.h" #ifndef VIX_HIDE_BORA_DEPENDENCIES #include "cryptoError.h" #endif // VIX_HIDE_BORA_DEPENDENCIES #include "vix.h" // Vix Public API /* *----------------------------------------------------------------------------- * * Vix Errors -- * *----------------------------------------------------------------------------- */ #ifndef VIX_HIDE_BORA_DEPENDENCIES VixError Vix_TranslateSystemError(int systemError); VixError Vix_TranslateCryptoError(CryptoError cryptoError); VixError Vix_TranslateErrno(int systemError); #ifdef _WIN32 VixError Vix_TranslateCOMError(HRESULT comError); VixError Vix_TranslateGuestRegistryError(int systemError); #endif #endif // VIX_HIDE_BORA_DEPENDENCIES /* * This is an expanded view of a VixError * Every VixError is a 64-bit int, so it can fit into this struct. * * The flags, extraErrorType, and extraError are all optional. They * do not have to be set for any error. In fact, these are guaranteed * to be all 0 when the error is VIX_OK. This means that any program * that checks (VIX_OK == err) or (VIX_OK != err) will always work. * * The basic error field is a Vix error value, and it's the lsb * of the new struct. This means that a 64-bit error can be assigned * enum constant, like an integer. For example, err = VIX_E_FAIL; works. * This just leaves the flags and extraError fields as 0. */ #pragma pack(push, 1) typedef struct VixErrorFields { uint16 error; uint8 flags; uint8 extraErrorType; uint32 extraError; } VixErrorFields; #pragma pack(pop) /* * These are the flags for a Vix error. */ enum { VIX_ERRORFLAG_GUEST = 0x0001, VIX_ERRORFLAG_REMOTE = 0x0002, }; /* * These are the types of extra error in a Vix error. */ enum { VIX_ERROREXTRATYPE_NONE = 0, VIX_ERROREXTRATYPE_SNAPSHOT = 1, VIX_ERROREXTRATYPE_DISKLIB = 2, VIX_ERROREXTRATYPE_WINDOWS = 3, VIX_ERROREXTRATYPE_LINUX = 4, VIX_ERROREXTRATYPE_FILE = 5, VIX_ERROREXTRATYPE_VMDB = 6, VIX_ERROREXTRATYPE_AIO = 7, VIX_ERROREXTRATYPE_CRYPTO = 8, VIX_ERROREXTRATYPE_KEYSAFE = 9, VIX_ERROREXTRATYPE_BLOCKLIST = 10, VIX_ERROREXTRATYPE_V2I = 11, VIX_ERROREXTRATYPE_MSGPOST = 12, VIX_ERROREXTRATYPE_NFC = 13, // NfcErrorCode }; /* * These are the types of extra error in a Vix error. */ #define VIX_ERROR_BASE_ERROR(err) ((VixErrorFields *) &err)->error #define VIX_ERROR_EXTRA_ERROR(err) ((VixErrorFields *) &err)->extraError #define VIX_ERROR_EXTRA_ERROR_TYPE(err) ((VixErrorFields *) &err)->extraErrorType #define VIX_ERROR_FROM_GUEST(err) (((VixErrorFields *) &err)->flags & VIX_ERRORFLAG_GUEST) #define VIX_ERROR_FROM_REMOTE(err) (((VixErrorFields *) &err)->flags & VIX_ERRORFLAG_REMOTE) #define VIX_ERROR_SET_FROM_GUEST(err) (((VixErrorFields *) &err)->flags |= VIX_ERRORFLAG_GUEST) #define VIX_ERROR_SET_FROM_REMOTE(err) (((VixErrorFields *) &err)->flags |= VIX_ERRORFLAG_REMOTE) #define VIX_SET_GUEST_WINDOWS_ERROR(err, vixError, winError) \ do { \ err = 0; \ VIX_ERROR_BASE_ERROR(err) = vixError; \ VIX_ERROR_EXTRA_ERROR(err) = winError; \ VIX_ERROR_EXTRA_ERROR_TYPE(err) = VIX_ERROREXTRATYPE_WINDOWS; \ VIX_ERROR_SET_FROM_GUEST(err); \ } while (0) #define VIX_ERROR_SET_ADDITIONAL_ERROR(err, vixError, additionalError) \ do { \ err = additionalError; \ err = (err << 32) | vixError; \ } while (0) #define VIX_SET_ERROR(err, vixError, origErrorType, origError) \ do { \ err = 0; \ VIX_ERROR_BASE_ERROR(err) = vixError; \ VIX_ERROR_EXTRA_ERROR_TYPE(err) = origErrorType; \ VIX_ERROR_EXTRA_ERROR(err) = origError; \ } while (0) /* * This defines additional error codes. * The public error codes are defined in vix.h * These error codes are in addition to those. */ enum { VIX_E_OP_NOT_SUPPORTED_ON_NON_VMWARE_VM = 3038, VIX_E_VI_OP_NOT_SUPPORTED_ON_GUEST = 3048, VIX_E_INVALID_LOGIN_CREDENTIALS = 3050, VIX_E_GUEST_AUTHTYPE_DISABLED = 3051, /* File Errors */ VIX_E_DIRECTORY_NOT_EMPTY = 20006, VIX_E_GUEST_AUTH_MULIPLE_MAPPINGS = 20007, /* Guest Reg Errors */ VIX_E_REG_KEY_INVALID = 20008, VIX_E_REG_KEY_HAS_SUBKEYS = 20009, VIX_E_REG_VALUE_NOT_FOUND = 20010, VIX_E_REG_KEY_ALREADY_EXISTS = 20011, VIX_E_REG_KEY_PARENT_VOLATILE = 20012, /* Generic Guest Errors */ VIX_E_HGFS_MOUNT_FAIL = 20050, /* Reg Errors*/ VIX_E_REG_INCORRECT_VALUE_TYPE = 25000 /* WARNING. Do not exceed 2**16 */ }; /* *----------------------------------------------------------------------------- * * VIX Handles -- * * These are common functions that apply to handles of several types. *----------------------------------------------------------------------------- */ /* * VIX Property ID's * * These are used in the tools, but they are not (yet) part of the public * API. They may be promoted, but for now they are not tested or documented. */ enum { VIX_PROPERTY_VM_GUEST_TEMP_DIR_PROPERTY = 203, /* VMX properties. */ VIX_PROPERTY_VMX_VERSION = 4400, VIX_PROPERTY_VMX_PRODUCT_NAME = 4401, /* DEPRECTATED VIX_PROPERTY_VMX_VIX_FEATURES = 4402, */ /* GuestOS and Tools properties. */ VIX_PROPERTY_GUEST_TOOLS_VERSION = 4500, VIX_PROPERTY_GUEST_TOOLS_API_OPTIONS = 4501, VIX_PROPERTY_GUEST_OS_FAMILY = 4502, VIX_PROPERTY_GUEST_OS_VERSION = 4503, VIX_PROPERTY_GUEST_OS_PACKAGE_LIST = 4504, VIX_PROPERTY_GUEST_NAME = 4505, VIX_PROPERTY_GUEST_POWER_OFF_SCRIPT = 4506, VIX_PROPERTY_GUEST_POWER_ON_SCRIPT = 4507, VIX_PROPERTY_GUEST_RESUME_SCRIPT = 4508, VIX_PROPERTY_GUEST_SUSPEND_SCRIPT = 4509, VIX_PROPERTY_GUEST_TOOLS_PRODUCT_NAM = 4511, VIX_PROPERTY_FOREIGN_VM_TOOLS_VERSION = 4512, VIX_PROPERTY_VM_DHCP_ENABLED = 4513, VIX_PROPERTY_VM_IP_ADDRESS = 4514, VIX_PROPERTY_VM_SUBNET_MASK = 4515, VIX_PROPERTY_VM_DEFAULT_GATEWAY = 4516, VIX_PROPERTY_VM_DNS_SERVER_DHCP_ENABLED = 4517, VIX_PROPERTY_VM_DNS_SERVER = 4518, VIX_PROPERTY_GUEST_TOOLS_WORD_SIZE = 4519, VIX_PROPERTY_GUEST_OS_VERSION_SHORT = 4520, VIX_PROPERTY_GUEST_AUTH_SSPI_TOKEN = 4531, VIX_PROPERTY_GUEST_AUTH_SSPI_SESSION_ID = 4532, VIX_PROPERTY_GUEST_AUTH_SESSION_TICKET = 4533, /* VI guest operation status */ VIX_PROPERTY_GUEST_START_PROGRAM_ENABLED = 4540, VIX_PROPERTY_GUEST_LIST_PROCESSES_ENABLED = 4541, VIX_PROPERTY_GUEST_TERMINATE_PROCESS_ENABLED = 4542, VIX_PROPERTY_GUEST_READ_ENVIRONMENT_VARIABLE_ENABLED = 4543, VIX_PROPERTY_GUEST_VALIDATE_CREDENTIALS_ENABLED = 4544, VIX_PROPERTY_GUEST_ACQUIRE_CREDENTIALS_ENABLED = 4545, VIX_PROPERTY_GUEST_RELEASE_CREDENTIALS_ENABLED = 4546, VIX_PROPERTY_GUEST_MAKE_DIRECTORY_ENABLED = 4547, VIX_PROPERTY_GUEST_DELETE_FILE_ENABLED = 4548, VIX_PROPERTY_GUEST_DELETE_DIRECTORY_ENABLED = 4549, VIX_PROPERTY_GUEST_MOVE_DIRECTORY_ENABLED = 4550, VIX_PROPERTY_GUEST_MOVE_FILE_ENABLED = 4551, VIX_PROPERTY_GUEST_CREATE_TEMP_FILE_ENABLED = 4552, VIX_PROPERTY_GUEST_CREATE_TEMP_DIRECTORY_ENABLED = 4553, VIX_PROPERTY_GUEST_LIST_FILES_ENABLED = 4554, VIX_PROPERTY_GUEST_CHANGE_FILE_ATTRIBUTES_ENABLED = 4555, VIX_PROPERTY_GUEST_INITIATE_FILE_TRANSFER_FROM_GUEST_ENABLED = 4556, VIX_PROPERTY_GUEST_INITIATE_FILE_TRANSFER_TO_GUEST_ENABLED = 4557, VIX_PROPERTY_GUEST_ADD_AUTH_ALIAS_ENABLED = 4558, VIX_PROPERTY_GUEST_REMOVE_AUTH_ALIAS_ENABLED = 4559, VIX_PROPERTY_GUEST_LIST_AUTH_ALIASES_ENABLED = 4560, VIX_PROPERTY_GUEST_LIST_MAPPED_ALIASES_ENABLED = 4561, VIX_PROPERTY_GUEST_CREATE_REGISTRY_KEY_ENABLED = 4562, VIX_PROPERTY_GUEST_LIST_REGISTRY_KEYS_ENABLED = 4563, VIX_PROPERTY_GUEST_DELETE_REGISTRY_KEY_ENABLED = 4564, VIX_PROPERTY_GUEST_SET_REGISTRY_VALUE_ENABLED = 4565, VIX_PROPERTY_GUEST_LIST_REGISTRY_VALUES_ENABLED = 4566, VIX_PROPERTY_GUEST_DELETE_REGISTRY_VALUE_ENABLED = 4567, VIX_PROPERTY_GUEST_REMOVE_AUTH_ALIAS_BY_CERT_ENABLED = 4568, }; /* *----------------------------------------------------------------------------- * * PropertyList -- * *----------------------------------------------------------------------------- */ /* * VIX Property Type */ enum { //VIX_PROPERTYTYPE_ANY = 0, //VIX_PROPERTYTYPE_INTEGER = 1, //VIX_PROPERTYTYPE_STRING = 2, //VIX_PROPERTYTYPE_BOOL = 3, //VIX_PROPERTYTYPE_HANDLE = 4, //VIX_PROPERTYTYPE_INT64 = 5, //VIX_PROPERTYTYPE_BLOB = 6, VIX_PROPERTYTYPE_POINTER = 7 }; #ifndef VIX_HIDE_FROM_JAVA /* * This is a single name/value pair. */ typedef struct VixPropertyValue { int propertyID; VixPropertyType type; union { Bool boolValue; char *strValue; int intValue; int64 int64Value; VixHandle handleValue; struct { unsigned char *blobContents; int blobSize; } blobValue; void *ptrValue; } value; Bool isDirty; Bool isSensitive; struct VixPropertyValue *next; } VixPropertyValue; /* * This is the entire list. */ typedef struct VixPropertyListImpl { VixPropertyValue *properties; } VixPropertyListImpl; /* * This defines what action Deserialize should take when it encounters * a string that is not UTF-8. */ typedef enum VixPropertyListBadEncodingAction { /* * Cancel the deserialization and return an error. This is the recommended * value since it is the strictest; you don't have to think about how * any clients or library code will handle escaped values. * This should always be used when parsing property lists passing arguments * to RPCs since we should be very strict in terms of actions we take * based on arguments. */ VIX_PROPERTY_LIST_BAD_ENCODING_ERROR, /* * Escape any non-UTF-8 characters in the string, add the result to the * property list, and continue deserializing. This should only be used * when there are likely to be applications generated non-ASCII values * for the property list in question (e.g., the Tools properties sent by * pre-i18n Tools) and the properties are more informative then * actionable (something like the hostname of a guest, maybe). */ VIX_PROPERTY_LIST_BAD_ENCODING_ESCAPE, } VixPropertyListBadEncodingAction; void VixPropertyList_Initialize(VixPropertyListImpl *propList); void VixPropertyList_RemoveAllWithoutHandles(VixPropertyListImpl *propList); VixError VixPropertyList_Serialize(VixPropertyListImpl *propListImpl, Bool dirtyOnly, size_t *resultSize, char **resultBuffer); VixError VixPropertyList_Deserialize(VixPropertyListImpl *propListImpl, const char *buffer, size_t bufferSize, VixPropertyListBadEncodingAction action); VixError VixPropertyList_DeserializeNoClobber(VixPropertyListImpl *propListImpl, const char *buffer, size_t bufferSize, VixPropertyListBadEncodingAction action); VixError VixPropertyList_GetString(struct VixPropertyListImpl *propList, int propertyID, int index, char **resultValue); VixError VixPropertyList_SetStringSensitive(struct VixPropertyListImpl *propList, int propertyID, const char *value); VixError VixPropertyList_SetString(struct VixPropertyListImpl *propList, int propertyID, const char *value); VixError VixPropertyList_GetInteger(struct VixPropertyListImpl *propList, int propertyID, int index, int *resultValue); VixError VixPropertyList_SetInteger(struct VixPropertyListImpl *propList, int propertyID, int value); VixError VixPropertyList_GetBool(struct VixPropertyListImpl *propList, int propertyID, int index, Bool *resultValue); VixError VixPropertyList_SetBool(struct VixPropertyListImpl *propList, int propertyID, Bool value); VixError VixPropertyList_GetHandle(struct VixPropertyListImpl *propList, int propertyID, int index, VixHandle *resultValue); VixError VixPropertyList_SetHandle(struct VixPropertyListImpl *propList, int propertyID, VixHandle value); VixError VixPropertyList_GetInt64(struct VixPropertyListImpl *propList, int propertyID, int index, int64 *resultValue); VixError VixPropertyList_SetInt64(struct VixPropertyListImpl *propList, int propertyID, int64 value); VixError VixPropertyList_GetBlob(struct VixPropertyListImpl *propList, int propertyID, int index, int *resultSize, unsigned char **resultValue); VixError VixPropertyList_SetBlob(struct VixPropertyListImpl *propList, int propertyID, int blobSize, const unsigned char *value); VixError VixPropertyList_SetBlobSensitive(struct VixPropertyListImpl *propList, int propertyID, int blobSize, const unsigned char *value); VixError VixPropertyList_RemoveAll(VixHandle propertyListHandle); VixError VixPropertyList_Remove(VixHandle propertyListHandle, int propertyID); VixError VixPropertyList_RemoveFromImpl(VixPropertyListImpl *propList, int propertyID); VixError VixPropertyList_AppendProperties(VixHandle handle, int firstPropertyID, ...); VixError VixPropertyList_FindProperty(VixPropertyListImpl *propList, int propertyID, VixPropertyType type, int index, Bool createIfMissing, VixPropertyValue **resultEntry); Bool VixPropertyList_PropertyExists(VixPropertyListImpl *propList, int propertyID, VixPropertyType type); VixError VixPropertyListAppendProperty(VixPropertyListImpl *propList, int propertyID, VixPropertyType type, VixPropertyValue **resultEntry); int VixPropertyList_GetNumProperties(VixHandle propertyListHandle, int propertyID); VixError VixPropertyList_GetOptionalProperties(VixHandle propertyListHandle, int firstPropertyID, ...); VixError VixPropertyList_GetIndexedProperties(VixHandle propertyListHandle, Bool ignoreMissingProperties, int firstPropertyID, int firstPropertyIndex, ...); VixError VixPropertyList_GetPtr(VixPropertyListImpl *propList, int propertyID, int index, void **resultValue); VixError VixPropertyList_SetPtr(VixPropertyListImpl *propList, int propertyID, void *value); int VixPropertyList_NumItems(VixPropertyListImpl *propList); Bool VixPropertyList_Empty(VixPropertyListImpl *propList); void VixPropertyList_MarkAllSensitive(VixPropertyListImpl *propList); Bool Vix_XMLFindElementText(const char *pattern, char *str, char *endStr, char **startText, char **stopText, char **resumeSearch); Bool Vix_XMLFindStringElementText(const char *pattern, char *str, char *endStr, Bool doUnescape, char **startText, char **stopText, Bool *needToFree, char **resumeSearch); Bool Vix_XMLResultIsEscaped(const char *resultXML, const char *dataParentTag); Bool Vix_IsValidString(const char *str); #endif // VIX_HIDE_FROM_JAVA /* *----------------------------------------------------------------------------- * * VixVM -- * * This describes the persistent configuration state of a single VM. The * VM may or may not be running. * *----------------------------------------------------------------------------- */ #define VIX_FOREIGN_VM_TOOLS_VMX_VERSION_STRING "Foreign VM Tools" /* * These are the types of variable strings we can read in the VM. */ enum { //VIX_VM_GUEST_VARIABLE = 1, //VIX_VM_CONFIG_RUNTIME_ONLY = 2, //VIX_GUEST_ENVIRONMENT_VARIABLE = 3, VIX_GUEST_CONFIG = 4, VIX_VMDB_VARIABLE = 5, }; /* * Options for RunProgramInGuest(). */ enum { //VIX_RUNPROGRAM_RETURN_IMMEDIATELY = 0x0001, //VIX_RUNPROGRAM_ACTIVATE_WINDOW = 0x0002, /* DEPRECATED VIX_RUNPROGRAM_USE_INTERACTIVE_SESSION = 0x0004, */ VIX_RUNPROGRAM_RUN_AS_LOCAL_SYSTEM = 0x0008, }; /* * Options for VixVM_ListFileSystemsInGuest() */ enum { VIX_FILESYSTEMS_SHOW_ALL = 0x000, }; /* * These are the property flags for each file. This is a superset * of the values defined in the public header. */ enum { //VIX_FILE_ATTRIBUTES_DIRECTORY = 0x0001, //VIX_FILE_ATTRIBUTES_SYMLINK = 0x0002, VIX_FILE_ATTRIBUTES_HIDDEN = 0x0004, VIX_FILE_ATTRIBUTES_READONLY = 0x0008, }; /* * These are the propery flags for SetGuestFileAttributes request. */ enum { VIX_FILE_ATTRIBUTE_SET_ACCESS_DATE = 0x0001, VIX_FILE_ATTRIBUTE_SET_MODIFY_DATE = 0x0002, VIX_FILE_ATTRIBUTE_SET_READONLY = 0x0004, VIX_FILE_ATTRIBUTE_SET_HIDDEN = 0x0008, VIX_FILE_ATTRIBUTE_SET_UNIX_OWNERID = 0x0010, VIX_FILE_ATTRIBUTE_SET_UNIX_GROUPID = 0x0020, VIX_FILE_ATTRIBUTE_SET_UNIX_PERMISSIONS = 0x0040, }; /* * Subject types for Alias management. */ typedef enum VixGuestAuthSubjectType { VIX_GUEST_AUTH_SUBJECT_TYPE_NONE = 0, VIX_GUEST_AUTH_SUBJECT_TYPE_NAMED = 1, VIX_GUEST_AUTH_SUBJECT_TYPE_ANY = 2, } VixGuestAuthSubjectType; /* * Types for Windows Registry Management. */ /* * In a 64 bit Windows OS, the registry has two views: 32 bit and 64 bit. * Normally using "registry redirection", 32 bit applications automatically * access the 32 bit view, while 64 bit applications access 64 bit view. * However, applications can pass a flag to specifically access either 32 * or 64 bit registry view, irrespective of their own bitness. * * NOTE: 32 bit windows will ignore these flags if passed. * * Based on the above, and on the fact that in our case 32 bit tools run only * on 32 bit windows and 64 bit tools run only on 64 bit windows, we get the * following registry view access matrix: * Application wowNative wow32 wow64 * ----------- -------- ----- ----- * 32 bit tools 32 bit view 32 bit view 32 bit view * 64 bit tools 64 bit view 32 bit view 64 bit view * So in essence, we always access 32 bit view UNLESS its 64 bit tools and user * has specified either wowNative or wow64 as the registry access flag. */ typedef enum VixRegKeyWowBitness { VIX_REGISTRY_KEY_WOW_NATIVE = 0, VIX_REGISTRY_KEY_WOW_32 = 1, VIX_REGISTRY_KEY_WOW_64 = 2, } VixRegKeyWowBitness; typedef enum VixRegValueDataType { VIX_REGISTRY_VALUE_DWORD = 0, VIX_REGISTRY_VALUE_QWORD = 1, VIX_REGISTRY_VALUE_STRING = 2, VIX_REGISTRY_VALUE_EXPAND_STRING = 3, VIX_REGISTRY_VALUE_MULTI_STRING = 4, VIX_REGISTRY_VALUE_BINARY = 5, } VixRegValueDataType; /* *----------------------------------------------------------------------------- * * VixDebug -- * * Vix debug macros, to allow conditional printf debugging with file/line * information. * * Use as: * * VIX_DEBUG("test debug message: %s %d\n", stringArg, intArg); * * Output will go to logfile if VIX_DEBUG_PREFERENCE_NAME is non-zero * * VIX_DEBUG_LEVEL(3, "test debug message: %s %d\n", stringArg, intArg); * * Output will go to logfile if VIX_DEBUG_PREFERENCE_NAME is >= * the first argument to the macro. * *----------------------------------------------------------------------------- */ #ifndef VIX_HIDE_FROM_JAVA extern int vixDebugGlobalSpewLevel; extern int vixApiTraceGlobalSpewLevel; extern char *VixAllocDebugString(char *fmt, ...) PRINTF_DECL(1,2); extern void VixDebugInit(int debugLevel, int apiTraceLevel, Bool panicOnVixAssert); extern const char *VixDebug_GetFileBaseName(const char *path); extern void VixAssert(const char *cond, const char *file, int lineNum); extern VixError VixLogError(VixError err, const char *function, int line, const char *fileName, const char *fmt, ...) PRINTF_DECL(5, 6); /* * preference name for client and vmx */ #define VIX_DEBUG_PREFERENCE_NAME "vix.debugLevel" #define VIX_ASSERT_PREFERENCE_NAME "vix.doAssert" #define VIX_API_TRACE_PREFERENCE_NAME "vix.apiTraceLevel" /* * Assertions. Normally we'd just use ASSERT(), but we've hit many cases * where ASSERT() is desired by foundry developers, but not by foundry users. * So we have our own VIX_ASSERT(), which is configured via a preference, * vix.doAssert, off by default. */ #ifdef VMX86_DEBUG # ifdef __cplusplus # define VIX_ASSERT(cond) (UNLIKELY(!(cond)) ? VixAssert(#cond, __FILE__, __LINE__) : (void) 0) # else # define VIX_ASSERT(cond) (UNLIKELY(!(cond)) ? VixAssert(#cond, __FILE__, __LINE__) : 0) # endif #else #define VIX_ASSERT(cond) #endif #define DEFAULT_VIX_LOG_LEVEL 0 #define DEFAULT_VIX_API_TRACE_LEVEL 0 #define VIX_DEBUG_LEVEL(logLevel, ...) \ if (logLevel <= vixDebugGlobalSpewLevel) { \ char *debugString = VixAllocDebugString(__VA_ARGS__); \ \ Log("Vix: [%s:%d]: %s", \ VixDebug_GetFileBaseName(__FILE__), __LINE__, \ debugString); \ free(debugString); \ } #define VIX_DEBUG(...) \ if (0 != vixDebugGlobalSpewLevel) { \ char *debugString = VixAllocDebugString(__VA_ARGS__); \ \ Log("Vix: [%s:%d]: %s", \ VixDebug_GetFileBaseName(__FILE__), __LINE__, \ debugString); \ free(debugString); \ } #define VIX_DEBUG_ALWAYS(...) \ { \ char *debugString = VixAllocDebugString(__VA_ARGS__); \ \ Log("Vix: [%s:%d]: %s", \ VixDebug_GetFileBaseName(__FILE__), __LINE__, \ debugString); \ free(debugString); \ } #define VIX_API_TRACE_ON() (vixApiTraceGlobalSpewLevel > 0) #define VIX_API_LOG(...) \ if (VIX_API_TRACE_ON()) { \ char *debugString = VixAllocDebugString(__VA_ARGS__); \ \ Log("VixApiLog: %s %s\n", __FUNCTION__, debugString); \ free(debugString); \ } // If no MSG is given, a description of err is supplemented. #define VIX_ERROR(err) (VIX_ERROR_MSG(err, NULL)) #define VIX_ERROR_MSG(err, ...) (VixLogError(err, __FUNCTION__, __LINE__, \ VixDebug_GetFileBaseName(__FILE__), __VA_ARGS__)) #endif // VIX_HIDE_FROM_JAVA #if defined(__cplusplus) } // extern "C" #endif #endif // _VIXOpenSource_h_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vmGuestAppMonitorLib.h000066400000000000000000000131571470176644300267640ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2009-2016 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /** * @file vmGuestAppMonitorLib.h * * This is the VMware Guest Application Monitor Lib, * an API used to communicate the health of one or more applications * running in a virtual machine to VMware infrastructure. * * @defgroup VMGuestAppMonitor * * @brief VMGuestAppMonitorLib A collection of routines used in the guest * by an application monitoring agent to * indicate the liveness of a monitored set of * applications. * * @code * VMGuestAppMonitor_Enable(); * * -- Call at least every 30 seconds * VMGuestAppMonitor_MarkActive(); * * -- When finished monitoring * VMGuestAppMonitor_Disable(); * @endcode * * To signal an application failure, simply do not call * VMGuestAppMonitor_MarkActive(). * * @endcode * * @addtogroup VMGuestAppMonitor * @{ */ #ifndef _VM_GUEST_APP_MONITOR_LIB_H_ #define _VM_GUEST_APP_MONITOR_LIB_H_ #ifdef __cplusplus extern "C" { #endif /** * VMGuestAppMonitorLib error codes. */ typedef enum { VMGUESTAPPMONITORLIB_ERROR_SUCCESS = 0, /**< No error. */ VMGUESTAPPMONITORLIB_ERROR_OTHER, /**< Other error */ VMGUESTAPPMONITORLIB_ERROR_NOT_RUNNING_IN_VM, /**< Not running in a VM */ VMGUESTAPPMONITORLIB_ERROR_NOT_ENABLED, /**< Monitoring is not enabled */ VMGUESTAPPMONITORLIB_ERROR_NOT_SUPPORTED, /**< Monitoring is not supported */ } VMGuestAppMonitorLibError; /* ****************************************************************************** * VMGuestAppMonitor_Enable -- */ /** * * Enable application monitoring. After this call, the agent must * call VMGuestAppMonitor_MarkActive() at least once every 30 * seconds or the application will be viewed as having failed. * * @return VMGUESTAPPMONITORLIB_ERROR_SUCCESS if monitoring has been enabled. * ****************************************************************************** */ VMGuestAppMonitorLibError VMGuestAppMonitor_Enable(void); /* ****************************************************************************** * VMGuestAppMonitor_Disable -- */ /** * * Disable application monitoring. * * @return TRUE if monitoring has been disabled. * ****************************************************************************** */ VMGuestAppMonitorLibError VMGuestAppMonitor_Disable(void); /* ****************************************************************************** * VMGuestAppMonitor_IsEnabled -- */ /** * * Return the current state of application monitoring. * * @return 1 (TRUE) if monitoring is enabled. * ****************************************************************************** */ int VMGuestAppMonitor_IsEnabled(void); /* ****************************************************************************** * VMGuestAppMonitor_MarkActive -- */ /** * * Marks the application as active. This function needs to be called * at least once every 30 seconds while application monitoring is * enabled or HA will determine that the application has failed. * * @return VMGUESTAPPMONITORLIB_ERROR_SUCCESS if successful and * VMGUESTAPPMONITORLIB_ERROR_NOT_ENABLED if monitoring is not enabled. * ****************************************************************************** */ VMGuestAppMonitorLibError VMGuestAppMonitor_MarkActive(void); /* ****************************************************************************** * VMGuestAppMonitor_GetAppStatus -- */ /** * * Return the current status recorded for the application. * * @return the application status. The caller must free the result. * ****************************************************************************** */ char * VMGuestAppMonitor_GetAppStatus(void); /* ****************************************************************************** * VMGuestAppMonitor_PostAppState -- */ /** * * Post application state. * * @return VMGUESTAPPMONITORLIB_ERROR_SUCCESS if successful * ****************************************************************************** */ VMGuestAppMonitorLibError VMGuestAppMonitor_PostAppState(const char *state); /* ****************************************************************************** * VMGuestAppMonitor_Free -- */ /** * * Free the result of VMGuestAppMonitor_GetAppStatus. * * @param[in] str Pointer to the memory to be freed. * ****************************************************************************** */ void VMGuestAppMonitor_Free(char *str); #ifdef __cplusplus } #endif #endif /* _VM_GUEST_APP_MONITOR_LIB_H_ */ /** @} */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vmGuestLib.h000066400000000000000000000427531470176644300247570ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2003-2016,2019-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _VM_GUEST_LIB_H_ #define _VM_GUEST_LIB_H_ #include "vm_basic_types.h" #include "vmSessionId.h" #ifdef __cplusplus extern "C" { #endif /* * This is the VMware GuestLib, an API used for accessing various * performance statistics pertaining to the VMware virtual environment * from within a VMware Virtual Machine. */ #if __GNUC__ > 3 || \ (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || \ defined (__clang__) #define VMGUESTLIB_DEPRECATED __attribute__((__deprecated__)) #elif defined(_MSC_VER) && (_MSC_VER >= 1300) #define VMGUESTLIB_DEPRECATED __declspec(deprecated) #else #define VMGUESTLIB_DEPRECATED #endif /* * Error codes returned by GuestLib functions. * * XXX These should be unified with Foundry's error codes. */ typedef enum { VMGUESTLIB_ERROR_SUCCESS = 0, // No error VMGUESTLIB_ERROR_OTHER, // Other error VMGUESTLIB_ERROR_NOT_RUNNING_IN_VM, // Not running in a VM VMGUESTLIB_ERROR_NOT_ENABLED, // GuestLib not enabled on the host. VMGUESTLIB_ERROR_NOT_AVAILABLE, // This stat not available on this host. VMGUESTLIB_ERROR_NO_INFO, // UpdateInfo() has never been called. VMGUESTLIB_ERROR_MEMORY, // Not enough memory VMGUESTLIB_ERROR_BUFFER_TOO_SMALL, // Buffer too small VMGUESTLIB_ERROR_INVALID_HANDLE, // Handle is invalid VMGUESTLIB_ERROR_INVALID_ARG, // One or more arguments were invalid VMGUESTLIB_ERROR_UNSUPPORTED_VERSION // The host doesn't support this request } VMGuestLibError; char const * VMGuestLib_GetErrorText(VMGuestLibError error); // IN /* * GuestLib handle. * * This handle provides a context for accessing all GuestLib * state. Use VMGuestLib_OpenHandle to get a handle for use with other * GuestLib functions, and use VMGuestLib_CloseHandle to release a * handle previously acquired with VMGuestLib_OpenHandle. * * All of the statistics and session state are maintained per GuestLib * handle, so operating on one GuestLib handle will not affect the * state of another handle. */ struct _VMGuestLibHandle; typedef struct _VMGuestLibHandle* VMGuestLibHandle; VMGuestLibError VMGuestLib_OpenHandle(VMGuestLibHandle *handle); // OUT VMGuestLibError VMGuestLib_CloseHandle(VMGuestLibHandle handle); // IN /* * Update the info and session state for the given handle. * * Concurrency/thread safety: No locking is done internally around the * access of a handle. If a calling program uses multiple threads then * the caller must either ensure that each thread of execution is * using a separate handle, or the caller must implement locking * around calls to VMGuestLib_UpdateInfo() on a given handle to ensure * that two threads do not update the handle concurrently. * * Because the state is maintained per handle and no two handles can * be updated exactly simultaneously, the state of two handles may * differ even if they are updated one immediately after the other. * * VMGuestLib_UpdateInfo() is a fairly heavyweight function; it should * be viewed similar to a system call in terms of the computational * cost and performance hit. For this reason, a user of the API who * is concerned about performance will get best results by minimizing * the number of calls to VMGuestLib_UpdateInfo(). */ VMGuestLibError VMGuestLib_UpdateInfo(VMGuestLibHandle handle); // IN /* * Session ID * * This is used to detect changes in the "session" of a virtual * machine. "Session" in this context refers to the particular running * instance of this virtual machine on a given host. Moving a virtual * machine to another host using VMotion will cause a change in * session ID, as will suspending and resuming a virtual machine or * reverting to a snapshot. * * Any of the events above (VMotion, suspend/resume, snapshot revert) * are likely to render invalid any information previously retrieved * through this API, so the intention of the session ID is to provide * applications with a mechanism to detect those events and react * accordingly, e.g. by refreshing and resetting any state that relies * on validity of previously retrieved information. * * Use VMGuestLib_GetSessionId() to retrieve the ID for the current * session after calling VMGuestLib_UpdateInfo(). After a VMotion or * similar event, VMGuestLib_GetSessionId() will return a new value. * See code example below for an example of how to use this. * * If VMGuestLib_UpdateInfo() has never been called, * VMGUESTLIB_ERROR_NO_INFO is returned. * * The session ID should be considered opaque and cannot be compared * in any meaningful way with the session IDs from any other virtual * machine (e.g. to determine if two virtual machines are on the same * host). * * Here is simple pseudo-code (with no error checking) showing a naive * implementation of detecting stale information using the session ID. * * ----- * * VMSessionId sid = 0; * Bool done = FALSE; * * while (!done) { * VMSessionId tmp; * * VMGuestLib_UpdateInfo(); * VMGuestLib_GetSessionId(&tmp); * if (tmp != sid) { * ResetStats(); * sid = tmp; * } * } * * ----- */ VMGuestLibError VMGuestLib_GetSessionId(VMGuestLibHandle handle, // IN VMSessionId *id); // OUT /* * Specific Stat accessors. The values returned by these accessor * functions are up to date as of the last call to VMGuestLib_UpdateInfo(). * * If VMGuestLib_UpdateInfo() has never been called, * VMGUESTLIB_ERROR_NO_INFO is returned. */ /* CPU */ /* * Retrieves the minimum processing power in MHz available to the virtual * machine. Assigning a cpuReservationMhz ensures that even as other virtual * machines on a single host consume shared processing power, there is * still a certain minimum amount for this virtual machine. */ VMGuestLibError VMGuestLib_GetCpuReservationMHz(VMGuestLibHandle handle, // IN uint32 *cpuReservationMHz); // OUT /* * Retrieves the maximum processing power in MHz available to the virtual * machine. Assigning a cpuLimitMHz ensures that this virtual machine never * consumes more than a certain amount of the available processor power. By * limiting the amount of processing power consumed, a portion of this * shared resource is available to other virtual machines. */ VMGuestLibError VMGuestLib_GetCpuLimitMHz(VMGuestLibHandle handle, // IN uint32 *cpuLimitMHz); // OUT /* * Retrieves the number of CPU shares allocated to the virtual machine. */ VMGuestLibError VMGuestLib_GetCpuShares(VMGuestLibHandle handle, // IN uint32 *cpuShares); // OUT /* * Retrieves the number of milliseconds during which the virtual machine * has been using the CPU. This value is always less than or equal to * elapsedMS. This value, in conjunction with elapsedMS, can be used to * estimate efective virtual machine CPU speed. */ VMGuestLibError VMGuestLib_GetCpuUsedMs(VMGuestLibHandle handle, // IN uint64 *cpuUsedMs); // OUT /* * Host Processor speed. This can be used along with CpuUsedMs and * elapsed time to estimate approximate effective VM CPU speed * over a time interval. The following pseudocode illustrates how * to make this calculation: * * ------------------------------------ * * uint32 effectiveVMSpeed; * uint32 hostMhz; * uint64 elapsed1; * uint64 elapsed2; * uint64 used1; * uint64 used2; * * * VMGuestLib_UpdateInfo(handle); * VMGuestLib_GetHostProcessorSpeed(handle, &hostMhz); * VMGuestLib_GetElapsedMs(handle, &elapsed1); * VMGuestLib_GetUsedMs(handle, &used1); * .... * VMGuestLib_UpdateInfo(handle); * VMGuestLib_GetElapsedMs(handle, &elapsed2); * VMGuestLib_GetUsedMs(handle, &used2); * * effectiveVMSpeed = hostMhz * ((used2 - used1) / (elapsed2 - elapsed1)); * * * ------------------------------------ * * After this code executes, effectiveVMSpeed will be the approximate * average effective speed of the VM's virtual CPU over the time period * between the two calls to VMGuestLib_UpdateInfo(). * */ VMGuestLibError VMGuestLib_GetHostProcessorSpeed(VMGuestLibHandle handle, // IN uint32 *mhz); // OUT /* Memory */ /* * Retrieves the minimum amount of memory that is available to the virtual * machine. Assigning a cpuReservationMB ensures that even as other virtual * machines on a single host consume memory, there is still a certain * minimum amount for this virtual machine. */ VMGuestLibError VMGuestLib_GetMemReservationMB(VMGuestLibHandle handle, // IN uint32 *memReservationMB); // OUT /* * Retrieves the maximum amount of memory that is available to the virtual * machine. Assigning a cpuLimitMB ensures that this virtual machine never * consumes more than a certain amount of the available processor power. By * limiting the amount of processing power consumed, a portion of this * shared resource is available to other virtual machines. */ VMGuestLibError VMGuestLib_GetMemLimitMB(VMGuestLibHandle handle, // IN uint32 *memLimitMB); // OUT /* * Retrieves the number of memory shares allocated to the virtual machine. * This API returns an error if the memory shares exceeds the maximum * value of 32-bit unsigned integer (0xFFFFFFFF). Therefore, * VMGuestLib_GetMemShares64 API should be used instead of this API. */ VMGuestLibError VMGuestLib_GetMemShares(VMGuestLibHandle handle, // IN uint32 *memShares); // OUT /* * Retrieves the number of memory shares allocated to the virtual machine. */ VMGuestLibError VMGuestLib_GetMemShares64(VMGuestLibHandle handle, // IN uint64 *memShares64); // OUT /* * Retrieves the mapped memory size of this virtual machine. This * is the current total amount of guest memory that is backed by * physical memory. Note that this number may include pages of * memory shared between multiple virtual machines and thus may be * an overestimate of the amount of physical host memory "consumed" * by this virtual machine. */ VMGuestLibError VMGuestLib_GetMemMappedMB(VMGuestLibHandle handle, // IN uint32 *memMappedSizeMB); // OUT /* * Retrieves the estimated amount of memory the virtual machine is actively * using. This method returns an estimated working set size for the virtual * machine. */ VMGuestLibError VMGuestLib_GetMemActiveMB(VMGuestLibHandle handle, // IN uint32 *memActiveMB); // OUT /* * Retrieves the amount of overhead memory associated with this virtual * machine consumed on the host system. */ VMGuestLibError VMGuestLib_GetMemOverheadMB(VMGuestLibHandle handle, // IN uint32 *memOverheadMB); // OUT /* * Retrieves the amount of memory that has been reclaimed from this virtual * machine via the VMware Memory Balloon mechanism. */ VMGuestLibError VMGuestLib_GetMemBalloonedMB(VMGuestLibHandle handle, // IN uint32 *memBalloonedMB); // OUT /* * Retrieves the amount of memory associated with this virtual machine that * has been swapped by the host system. */ VMGuestLibError VMGuestLib_GetMemSwappedMB(VMGuestLibHandle handle, // IN uint32 *memSwappedMB); // OUT /* * Retrieves the amount of physical memory associated with this virtual * machine that is copy-on-write (COW) shared on the host. */ VMGuestLibError VMGuestLib_GetMemSharedMB(VMGuestLibHandle handle, // IN uint32 *memSharedMB); // OUT /* * Retrieves the estimated amount of physical memory on the host saved * from copy-on-write (COW) shared guest physical memory. */ VMGuestLibError VMGuestLib_GetMemSharedSavedMB(VMGuestLibHandle handle, // IN uint32 *memSharedSavedMB); // OUT /* * Retrieves the estimated amount of physical host memory currently * consumed for this virtual machine's physical memory. This is the * same as (mapped memory) - (sharedSaved memory). */ VMGuestLibError VMGuestLib_GetMemUsedMB(VMGuestLibHandle handle, // IN uint32 *memUsedMB); // OUT /* Elapsed Time */ /* * Retrieves the number of milliseconds that have passed in real time since * the virtual machine started running on the current host system. The * elapsed time counter is reset any time the virtual machine is powered * on, resumed, or migrated via VMotion. This value, in conjunction with * cpuUsedMS, can be used to estimate effective virtual machine CPU speed. * The cpuUsedMS value is always less than or equal to this value. */ VMGuestLibError VMGuestLib_GetElapsedMs(VMGuestLibHandle handle, // IN uint64 *elapsedMs); // OUT /* * Resource Pool Path. * * Retrieves a string representation of the path to this virtual machine in * the resource pool namespace of the host system. * * pathBuffer is a pointer to a buffer that will receive the resource * pool path string. bufferSize is a pointer to the size of the * pathBuffer in bytes. If bufferSize is not large enough to * accomodate the path and NUL terminator, then * VMGUESTLIB_ERROR_BUFFER_TOO_SMALL is returned and bufferSize * contains the amount of memory needed (in bytes). */ VMGuestLibError VMGuestLib_GetResourcePoolPath(VMGuestLibHandle handle, // IN size_t *bufferSize, // IN/OUT char *pathBuffer); // OUT #ifndef SWIGJAVA /* * CPU stolen time. The time (in ms) that the VM was runnable but not scheduled * to run. */ VMGuestLibError VMGuestLib_GetCpuStolenMs(VMGuestLibHandle handle, // IN uint64 *cpuStolenMs); // OUT /* * Memory Target Size. */ VMGuestLibError VMGuestLib_GetMemTargetSizeMB(VMGuestLibHandle handle, // IN uint64 *memTargetSizeMB); // OUT /* * Number of physical CPU cores on the host machine. */ VMGuestLibError VMGuestLib_GetHostNumCpuCores(VMGuestLibHandle handle, // IN uint32 *hostNumCpuCores); // OUT /* * Total CPU time used by host. */ VMGuestLibError VMGuestLib_GetHostCpuUsedMs(VMGuestLibHandle handle, // IN uint64 *hostCpuUsedMs); // OUT /* * Total memory swapped out on the host. */ VMGuestLibError VMGuestLib_GetHostMemSwappedMB(VMGuestLibHandle handle, // IN uint64 *hostMemSwappedMB); // OUT /* * Total COW (Copy-On-Write) memory on host. */ VMGuestLibError VMGuestLib_GetHostMemSharedMB(VMGuestLibHandle handle, // IN uint64 *hostMemSharedMB); // OUT /* * Total consumed memory on host. */ VMGuestLibError VMGuestLib_GetHostMemUsedMB(VMGuestLibHandle handle, // IN uint64 *hostMemUsedMB); // OUT /* * Total memory available to host OS kernel. */ VMGuestLibError VMGuestLib_GetHostMemPhysMB(VMGuestLibHandle handle, // IN uint64 *hostMemPhysMB); // OUT /* * Total physical memory free on host. */ VMGuestLibError VMGuestLib_GetHostMemPhysFreeMB(VMGuestLibHandle handle, // IN uint64 *hostMemPhysFreeMB); // OUT /* * Total host kernel memory overhead. * * Note: This function is deprecated in GuestSDK 11.2.0. Will be removed * in the future releases. hostMemKernOvhdMB is always set to 0. */ VMGUESTLIB_DEPRECATED VMGuestLibError VMGuestLib_GetHostMemKernOvhdMB(VMGuestLibHandle handle, // IN uint64 *hostMemKernOvhdMB); // OUT /* * Total mapped memory on host. */ VMGuestLibError VMGuestLib_GetHostMemMappedMB(VMGuestLibHandle handle, // IN uint64 *hostMemMappedMB); // OUT /* * Total unmapped memory on host. */ VMGuestLibError VMGuestLib_GetHostMemUnmappedMB(VMGuestLibHandle handle, // IN uint64 *hostMemUnmappedMB); // OUT /* * Semi-structured hypervisor stats collection, for troubleshooting. */ VMGuestLibError VMGuestLib_StatGet(const char *encoding, // IN const char *stat, // IN char **reply, // OUT size_t *replySize); // OUT void VMGuestLib_StatFree(char *reply, size_t replySize); #endif /* SWIGJAVA */ #ifdef __cplusplus } #endif #endif /* _VM_GUEST_LIB_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vmSessionId.h000066400000000000000000000021361470176644300251300ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2006-2017 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ #ifndef _VM_SESSION_ID_H_ #define _VM_SESSION_ID_H_ #include "vm_basic_types.h" #if defined(__cplusplus) extern "C" { #endif typedef uint64 VMSessionId; #if defined(__cplusplus) } // extern "C" #endif #endif /* _VM_SESSION_ID_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vm_api.h000066400000000000000000000120401470176644300241330ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2010-2016,2021 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * * vm_api.h -- * * Import/export macro definitions. */ #ifndef VM_API_H #define VM_API_H /* * API macros * * These macros can be used by libraries to export/import/hide symbols. * * The general approach is: * * 1) libfoo defines a macro, say EXPORT_FOO_API or STATIC_FOO_API, * in its Makefile/SCons file depending on the type of the library. * * 2) libfoo has the following code in a header file, e.g. foo/platform.h, * that is included by all headers that export/import/hide symbols: * * // In a file named platform.h * #include * * #ifdef STATIC_FOO_API * # define FOO_API VMW_LIB_STATIC * # define FOO_INLINE_API VMW_LIB_STATIC * #elif defined EXPORT_FOO_API * # define FOO_API VMW_LIB_DYNAMIC * # define FOO_INLINE_API VMW_LIB_DYNAMIC_INLINE * #else * # define FOO_API VMW_LIB_CLIENT * # define FOO_INLINE_API VMW_LIB_CLIENT_INLINE * #endif * * For example: * // In a file named FooTypes.h * #ifndef FOO_TYPES_H * #define FOO_TYPES_H * * #include * * class FOO_API FooObject { }; * FOO_API FooObject *GetFooObject(); * * class FOO_INLINE_API FooException { }; * FOO_INLINE_API int GetInt() { return 5; } * * #endif // FOO_TYPES_H * * DLL/DSO import/export macros. * * 3) Compiling a shared library - define EXPORT_FOO_API. * libfoo can now use FOO_API for all symbols it would like to export, * which resolves to VMW_LIB_DYNAMIC, while compiling libfoo as a dynamic * shared library. * On posix systems types that need to export RTTI information, including * exceptions, must have default visibility. However these types may not need * __declspec(dllexport) on Windows. Such classes should be marked with a * FOO_INLINE_API macro. * * 4) Linking against a shared library - no defines needed. * Whenever a client of libfoo includes its headers, these symbols will be * marked with VMW_LIB_CLIENT or VMW_LIB_CLIENT_INLINE, since EXPORT_FOO_API * and STATIC_FOO_API are not defined for the client. * * Static library macros. * * 3) Compiling a static library - define STATIC_FOO_API. * libfoo should hide all of its symbols so that they don't leak through to * another library, say libbar, which links libfoo statically. FOO_API and * FOO_INLINE_API would both resolve to VMW_LIB_STATIC while compiling libfoo * as a static library. * * 4) Linking against a static library - define STATIC_FOO_API. * Whenever a client of libfoo includes its headers, the libfoo symbols * should be hidden on posix systems, marked with VMW_LIB_STATIC. On Windows * defining STATIC_FOO_API is a must when linking against the libfoo static * library. If it's not defined then the libfoo symbols would get an * __declspec(dllimport) declaration. As a result the linker will try to * import them from the list of DLLs present in the link line instead of * linking them directly from the libfoo static library. * * NOTE: By default, symbols are hidden when compiling with MSC and exported * when compiling with GCC. Thus, it's best to compile with GCC's * -fvisibility=hidden and -fvisibility-inlines-hidden flags, so that only * symbols explicitly marked with VMW_LIB_DYNAMIC are exported. Also note that * these flags, as well as the attributes, are available in GCC 4 and later. * * @see http://gcc.gnu.org/wiki/Visibility */ #ifdef _MSC_VER # define VMW_LIB_STATIC # define VMW_LIB_CLIENT __declspec(dllimport) # define VMW_LIB_CLIENT_INLINE # define VMW_LIB_DYNAMIC __declspec(dllexport) # define VMW_LIB_DYNAMIC_INLINE #elif defined __GNUC__ # define VMW_LIB_STATIC __attribute__ ((visibility ("hidden"))) # define VMW_LIB_CLIENT __attribute__ ((visibility ("default"))) # define VMW_LIB_CLIENT_INLINE __attribute__ ((visibility ("default"))) # define VMW_LIB_DYNAMIC __attribute__ ((visibility ("default"))) # define VMW_LIB_DYNAMIC_INLINE __attribute__ ((visibility ("default"))) #else # define VMW_LIB_STATIC # define VMW_LIB_CLIENT # define VMW_LIB_CLIENT_INLINE # define VMW_LIB_DYNAMIC # define VMW_LIB_DYNAMIC_INLINE #endif /* _MSC_VER */ #endif /* VM_API_H */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vm_assert.h000066400000000000000000000402541470176644300246730ustar00rootroot00000000000000/********************************************************* * Copyright (C) 1998-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * vm_assert.h -- * * The basic assertion facility for all VMware code. * * For proper use, see bora/doc/assert */ #ifndef _VM_ASSERT_H_ #define _VM_ASSERT_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" // XXX not necessary except some places include vm_assert.h improperly #include "vm_basic_types.h" /* No stdarg.h on Linux kernels 5.15+ */ #ifndef KBUILD_MODNAME #include #endif #ifdef __cplusplus extern "C" { #endif /* * Some bits of vmcore are used in VMKernel code and cannot have * the VMKERNEL define due to other header dependencies. */ #if defined(VMKERNEL) && !defined(VMKPANIC) #define VMKPANIC 1 #endif /* * Internal macros, functions, and strings * * The monitor wants to save space at call sites, so it has specialized * functions for each situation. User level wants to save on implementation * so it uses generic functions. */ #if !defined VMM || \ defined BINARY_CHECKER || defined COREQUERY || defined DECODER || \ defined DIS16 || defined FROBOS || defined TRAPAPI_APP || \ defined VMM_LINKER || defined VMSS2CORE # if defined (VMKPANIC) # include "vmk_assert.h" # else /* !VMKPANIC */ # define _ASSERT_PANIC(name) \ Panic(_##name##Fmt "\n", __FILE__, __LINE__) # define _ASSERT_PANIC_BUG(bug, name) \ Panic(_##name##Fmt " bugNr=%d\n", __FILE__, __LINE__, bug) # define _ASSERT_PANIC_NORETURN(name) \ Panic(_##name##Fmt "\n", __FILE__, __LINE__) # define _ASSERT_PANIC_BUG_NORETURN(bug, name) \ Panic(_##name##Fmt " bugNr=%d\n", __FILE__, __LINE__, bug) # endif /* VMKPANIC */ #endif // These strings don't have newline so that a bug can be tacked on. #define _AssertAssertFmt "ASSERT %s:%d" #define _AssertVerifyFmt "VERIFY %s:%d" #define _AssertNotImplementedFmt "NOT_IMPLEMENTED %s:%d" #define _AssertNotReachedFmt "NOT_REACHED %s:%d" #define _AssertMemAllocFmt "MEM_ALLOC %s:%d" #define _AssertNotTestedFmt "NOT_TESTED %s:%d" /* * Panic and log functions */ void Log(const char *fmt, ...) PRINTF_DECL(1, 2); void Warning(const char *fmt, ...) PRINTF_DECL(1, 2); #if defined VMKPANIC void Panic_SaveRegs(void); NORETURN void Panic_NoSave(const char *fmt, ...) PRINTF_DECL(1, 2); # define Panic(fmt...) \ do { \ Panic_SaveRegs(); \ Panic_NoSave(fmt); \ } while(0) #else /* !VMKPANIC */ NORETURN void Panic(const char *fmt, ...) PRINTF_DECL(1, 2); #endif void LogThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3); void WarningThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3); #ifndef ASSERT_IFNOT /* * 'UNLIKELY' is defined with __builtin_expect, which does not warn when * passed an assignment (gcc bug 36050). To get around this, we put 'cond' * in an 'if' statement and make sure it never gets executed by putting * that inside of 'if (0)'. We use gcc's statement expression syntax to * make ASSERT an expression because some code uses it that way. * * Since statement expression syntax is a gcc extension and since it's * not clear if this is a problem with other compilers, the ASSERT * definition was not changed for them. Using a bare 'cond' with the * ternary operator may provide a solution. * * PR 271512: When compiling with gcc, catch assignments inside an ASSERT. */ # ifdef __GNUC__ # define ASSERT_IFNOT(cond, panic) \ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) {;}}} (void)0;}) # else # define ASSERT_IFNOT(cond, panic) \ (UNLIKELY(!(cond)) ? (panic) : (void)0) # endif #endif /* * Assert, panic, and log macros * * Some of these are redefined or undef below in !VMX86_DEBUG. */ #if defined VMX86_DEBUG /* * Assert is a debug-only construct. * * Assert should capture (i.e., document and validate) invariants, * including method preconditions, postconditions, loop invariants, * class invariants, data structure invariants, etc. * * ASSERT() is special cased because of interaction with Windows DDK. */ # undef ASSERT # define ASSERT(cond) ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertAssert)) # define ASSERT_BUG(bug, cond) \ ASSERT_IFNOT(cond, _ASSERT_PANIC_BUG(bug, AssertAssert)) #endif /* * Verify is present on all build types. * * Verify should protect against missing functionality (e.g., unhandled * cases), bugs and other forms of gaps, and also be used as the fail-safe * way to plug remaining security risks. Verify is not the correct primitive * to use to validate an invariant, as a condition never being true implies * that it need not be handled. */ #undef VERIFY #define VERIFY(cond) \ ASSERT_IFNOT(cond, _ASSERT_PANIC_NORETURN(AssertVerify)) #define VERIFY_BUG(bug, cond) \ ASSERT_IFNOT(cond, _ASSERT_PANIC_BUG_NORETURN(bug, AssertVerify)) /* * NOT IMPLEMENTED is useful to indicate that a codepath has not yet * been implemented, and should cause execution to forcibly quit if it is * ever reached. Some instances use NOT_IMPLEMENTED for things that will * never be implemented (as implied by ASSERT_NOT_IMPLEMENTED). * * PR1151214 asks for ASSERT_NOT_IMPLEMENTED to be replaced with VERIFY. * ASSERT_NOT_IMPLEMENTED is a conditional NOT_IMPLEMENTED. Despite the * name, ASSERT_NOT_IMPLEMENTED is present in release builds. * * NOT_IMPLEMENTED_BUG is NOT_IMPLEMENTED with the bug number included * in the panic string. */ #define ASSERT_NOT_IMPLEMENTED(cond) \ ASSERT_IFNOT(cond, NOT_IMPLEMENTED()) #if defined VMKPANIC || defined VMM # define NOT_IMPLEMENTED() _ASSERT_PANIC_NORETURN(AssertNotImplemented) #else # define NOT_IMPLEMENTED() _ASSERT_PANIC(AssertNotImplemented) #endif #if defined VMM # define NOT_IMPLEMENTED_BUG(bug) \ _ASSERT_PANIC_BUG_NORETURN(bug, AssertNotImplemented) #else # define NOT_IMPLEMENTED_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertNotImplemented) #endif /* * NOT_REACHED is meant to indicate code paths that we can never * execute. This can be very dangerous on release builds due to how * some compilers behave when you do potentially reach the point * indicated by NOT_REACHED and can lead to very difficult to debug * failures. NOT_REACHED should be used sparingly due to this. * * On debug builds, NOT_REACHED is a Panic with a fixed string. */ #if defined VMKPANIC || defined VMM # define NOT_REACHED() _ASSERT_PANIC_NORETURN(AssertNotReached) #else # define NOT_REACHED() _ASSERT_PANIC(AssertNotReached) #endif #if !defined VMKERNEL && !defined VMKBOOT && !defined VMKERNEL_MODULE /* * PR 2621164,2624036: ASSERT_MEM_ALLOC is deprecated and should not be * used. Please use VERIFY where applicable, since the latter aligns * better with the consistency model as defined by bora/doc/assert. You * could also consider the Util_Safe*alloc* functions in userland. * * Despite its name, ASSERT_MEM_ALLOC is present in both debug and release * builds. */ # define ASSERT_MEM_ALLOC(cond) \ ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertMemAlloc)) #endif /* * ASSERT_NO_INTERRUPTS & ASSERT_HAS_INTERRUPTS are shorthand to * assert whether interrupts are disabled or enabled. */ #define ASSERT_NO_INTERRUPTS() ASSERT(!INTERRUPTS_ENABLED()) #define ASSERT_HAS_INTERRUPTS() ASSERT(INTERRUPTS_ENABLED()) /* * NOT_TESTED may be used to indicate that we've reached a code path. * It simply puts an entry in the log file. * * ASSERT_NOT_TESTED does the same, conditionally. * NOT_TESTED_ONCE will only log the first time we executed it. * NOT_TESTED_1024 will only log every 1024th time we execute it. */ #ifdef VMX86_DEVEL # define NOT_TESTED() Warning(_AssertNotTestedFmt "\n", __FILE__, __LINE__) #else # define NOT_TESTED() Log(_AssertNotTestedFmt "\n", __FILE__, __LINE__) #endif #define ASSERT_NOT_TESTED(cond) (UNLIKELY(!(cond)) ? NOT_TESTED() : (void)0) #define NOT_TESTED_ONCE() DO_ONCE(NOT_TESTED()) #define NOT_TESTED_1024() \ do { \ static MONITOR_ONLY(PERVCPU) uint16 count = 0; \ if (UNLIKELY(count == 0)) { NOT_TESTED(); } \ count = (count + 1) & 1023; \ } while (0) #define LOG_ONCE(...) DO_ONCE(Log(__VA_ARGS__)) /* * Redefine macros that have a different behaviour on release * builds. This includes no behaviour (ie. removed). */ #if !defined VMX86_DEBUG // { # undef ASSERT # define ASSERT(cond) ((void)0) # define ASSERT_BUG(bug, cond) ((void)0) /* * NOT_REACHED on debug builds is a Panic; but on release * builds reaching it is __builtin_unreachable() * which is "undefined behaviour" according to * gcc. (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) * * When used correctly __builtin_unreachable() allows the compiler * to generate slightly better code and eliminates some warnings * when the compiler can't identify a "fallthrough" path that is * never reached. * * When used incorrectly, __builtin_unreachable is a dangerous * construct and we should structure code in such a way that we * need fewer instances of NOT_REACHED to silence the compiler, * and use the function attribute "noreturn" where appropriate * and potentially then using NOT_REACHED as documentation. * * We should *never* have code after NOT_REACHED in a block as * it's unclear to the reader if that path is ever possible, and * as mentioned above, gcc will do weird and wonderful things to us. * * Mainly, we want the compiler to infer the same control-flow * information as it would from Panic(). Otherwise, different * compilation options will lead to different control-flow-derived * errors, causing some make targets to fail while others succeed. * * VC++ has the __assume() built-in function which we don't trust (see * bug 43485). However, __assume() is used in the Windows ULM * implementation, because the newer compiler used for that project * generates correct code. * * With gcc, the __builtin_unreachable() extension is used when the * compiler is known to support it. */ # if defined VMKPANIC || defined VMM || defined ULM_ESX # undef NOT_REACHED # define NOT_REACHED() __builtin_unreachable() # elif defined ULM_WIN # undef NOT_REACHED # define NOT_REACHED() __assume(0) # else // keep debug definition # endif # undef LOG_UNEXPECTED # define LOG_UNEXPECTED(bug) ((void)0) # undef ASSERT_NOT_TESTED # define ASSERT_NOT_TESTED(cond) ((void)0) # undef NOT_TESTED # define NOT_TESTED() ((void)0) # undef NOT_TESTED_ONCE # define NOT_TESTED_ONCE() ((void)0) # undef NOT_TESTED_1024 # define NOT_TESTED_1024() ((void)0) #endif // !VMX86_DEBUG } /* * Compile-time assertions. * * ASSERT_ON_COMPILE does not use the common * switch (0) { case 0: case (e): ; } trick because some compilers (e.g. MSVC) * generate code for it. * * The implementation uses both enum and typedef because the typedef alone is * insufficient; gcc allows arrays to be declared with non-constant expressions * (even in typedefs, where it makes no sense). * * NOTE: if GCC ever changes so that it ignores unused types altogether, this * assert might not fire! We explicitly mark it as unused because GCC 4.8+ * uses -Wunused-local-typedefs as part of -Wall, which means the typedef will * generate a warning. */ #if defined(_Static_assert) || defined(__cplusplus) || \ !defined(__GNUC__) || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) #define ASSERT_ON_COMPILE(e) \ do { \ enum { AssertOnCompileMisused = ((e) ? 1 : -1) }; \ UNUSED_TYPE(typedef char AssertOnCompileFailed[AssertOnCompileMisused]); \ } while (0) #else #define ASSERT_ON_COMPILE(e) \ do { \ _Static_assert(e, #e); \ } while (0) #endif /* * To put an ASSERT_ON_COMPILE() outside a function, wrap it * in MY_ASSERTS(). The first parameter must be unique in * each .c file where it appears. For example, * * MY_ASSERTS(FS3_INT, * ASSERT_ON_COMPILE(sizeof(FS3_DiskLock) == 128); * ASSERT_ON_COMPILE(sizeof(FS3_DiskLockReserved) == DISK_BLOCK_SIZE); * ASSERT_ON_COMPILE(sizeof(FS3_DiskBlock) == DISK_BLOCK_SIZE); * ASSERT_ON_COMPILE(sizeof(Hardware_DMIUUID) == 16); * ) * * Caution: ASSERT() within MY_ASSERTS() is silently ignored. * The same goes for anything else not evaluated at compile time. */ #define MY_ASSERTS(name, assertions) \ static INLINE void name(void) { \ assertions \ } /* * Avoid generating extra code due to asserts which are required by * Clang static analyzer, e.g. right before a statement would fail, using * the __clang_analyzer__ macro defined only when clang SA is parsing files. */ #ifdef __clang_analyzer__ # define ANALYZER_ASSERT(cond) ASSERT(cond) #else # define ANALYZER_ASSERT(cond) ((void)0) #endif #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ifndef _VM_ASSERT_H_ */ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vm_atomic.h000066400000000000000000003236441470176644300246550ustar00rootroot00000000000000/********************************************************* * Copyright (c) 1998-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * vm_atomic.h -- * * Atomic power * * Note: Only partially tested on ARM processors: Works for View Open * Client, which shouldn't have threads, and ARMv8 processors. */ #ifndef _ATOMIC_H_ #define _ATOMIC_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #if defined _MSC_VER && !defined BORA_NO_WIN32_INTRINS #pragma warning(push) #pragma warning(disable : 4255) // disable no-prototype() to (void) warning #include #pragma warning(pop) #endif #ifdef __wasm__ #define VM_ATOMIC_USE_C11 #endif #ifdef VM_ATOMIC_USE_C11 #include #endif #include "vm_basic_types.h" #include "vm_assert.h" #if defined __cplusplus extern "C" { #endif /* * There are two concepts involved when dealing with atomic accesses: * 1. Atomicity of the access itself * 2. Ordering of the access with respect to other reads&writes (from the view * of other processors/devices). * * Two examples help to clarify #2: * a. Inc: A caller implementing a simple independent global event counter * might not care if the compiler or processor visibly reorders the * increment around other memory accesses. * b. Dec: A caller implementing a reference count absolutely *doesn't* want * the compiler or processor to visibly reordering writes after that * decrement: if that happened, the program could then end up writing * to memory that was freed by another processor. * * C11 has standardized a good model for expressing these orderings when doing * atomics. It defines three *tiers* of ordering: * 1. Sequential Consistency (every processor sees the same total order of * events) * * 2. Acquire/Release ordering (roughly, everybody can agree previous events * have completed, but they might disagree on the ordering of previous * independent events). * * The relative ordering provided by this tier is sufficient for common * locking and initialization activities, but is insufficient for unusual * synchronization schemes (e.g. IRIW aka Independent Read Independent * Write designs such Dekker's algorithm, Peterson's algorithm, etc.) * * In other words, this tier is close in behavior to Sequential Consistency * in much the same way a General-Relativity universe is close to a * Newtonian universe. * 3. Relaxed (i.e unordered/unfenced) * * In C11 standard's terminology for atomic memory ordering, * - in case (a) we want "relaxed" ordering for perf and, * - in case (b) we want "sequentially consistent" ordering (or perhaps the * only slightly weaker "release" ordering) for correctness. * * There are standardized mappings of operations to orderings for every * processor architecture. See * - https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html * - http://preshing.com/20120913/acquire-and-release-semantics/ * * In this file: * 1. all RMW (Read/Modify/Write) operations are sequentially consistent. * This includes operations like Atomic_IncN, Atomic_ReadIfEqualWriteN, * Atomic_ReadWriteN, etc. * 2. all R and W operations are relaxed. This includes operations like * Atomic_WriteN, Atomic_ReadN, Atomic_TestBitN, etc. * * The below routines of course ensure both the CPU and compiler honor the * ordering constraint. * * Notes: * 1. Since R-only and W-only operations do not provide ordering, callers * using them for synchronizing operations like double-checked * initialization or releasing spinlocks must provide extra barriers. * 2. This implementation of Atomic operations is suboptimal. On x86,simple * reads and writes have acquire/release semantics at the hardware level. * On arm64, we have separate instructions for sequentially consistent * reads and writes (the same instructions are used for acquire/release). * Neither of these are exposed for R-only or W-only callers. * * For further details on x86 and ARM memory ordering see * https://wiki.eng.vmware.com/ARM/MemoryOrdering. */ #ifdef VM_ARM_64 # include "vm_atomic_arm64_begin.h" #endif /* Basic atomic types: 8, 16, 32, 64 and 128 bits */ typedef ALIGNED(1) struct Atomic_uint8 { volatile uint8 value; } Atomic_uint8; typedef ALIGNED(2) struct Atomic_uint16 { volatile uint16 value; } Atomic_uint16; typedef ALIGNED(4) struct Atomic_uint32 { volatile uint32 value; } Atomic_uint32; typedef ALIGNED(8) struct Atomic_uint64 { volatile uint64 value; } Atomic_uint64; #ifdef VM_HAS_INT128 typedef ALIGNED(16) struct Atomic_uint128 { volatile uint128 value; } Atomic_uint128; #endif #if defined __arm__ /* * LDREX without STREX or CLREX may cause problems in environments where the * context switch may not clear the reference monitor - according ARM manual * the reference monitor should be cleared after a context switch, but some * may not like Linux kernel's non-preemptive context switch path. So use of * ARM routines in kernel code may not be safe. */ # if defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ || \ defined __ARM_ARCH_7R__|| defined __ARM_ARCH_7M__ # define VM_ARM_V7 # ifdef __KERNEL__ # warning LDREX/STREX may not be safe in linux kernel, since it \ does not issue CLREX on context switch (as of 2011-09-29). # endif # else # error Only ARMv7 extends the synchronization primitives ldrex/strex. \ For the lower ARM version, please implement the atomic functions \ by kernel APIs. # endif #endif /* Data Memory Barrier */ #ifdef VM_ARM_V7 #define dmb() __asm__ __volatile__("dmb" : : : "memory") #endif /* * Whether GCC flags output operands are supported. * If building with GCC 6+ on x86, and 10+ on arm, flags output is supported. * Some pieces are still built with GCC 4, which doesn't support flag outputs. */ #ifdef __GCC_ASM_FLAG_OUTPUTS__ #define IF_ASM_FLAG_OUTPUT(supportedValue, fallbackValue) supportedValue #else /* older gcc (or not gcc), flags output is not supported */ #define IF_ASM_FLAG_OUTPUT(supportedValue, fallbackValue) fallbackValue #endif /* Convert a volatile uint32 to Atomic_uint32. */ static INLINE Atomic_uint32 * Atomic_VolatileToAtomic32(volatile uint32 *var) // IN: { return (Atomic_uint32 *)var; } #define Atomic_VolatileToAtomic Atomic_VolatileToAtomic32 /* Convert a volatile uint64 to Atomic_uint64. */ static INLINE Atomic_uint64 * Atomic_VolatileToAtomic64(volatile uint64 *var) // IN: { return (Atomic_uint64 *)var; } /* * The Read/Modify/Write operations on x86/x64 are all written using the * "memory" constraint. This is to ensure the compiler treats the operation as * a full barrier, flushing any pending/cached state currently residing in * registers. */ /* Force the link step to fail for unimplemented functions. */ extern int AtomicUndefined(void const *); /* *----------------------------------------------------------------------------- * * Atomic_ReadIfEqualWrite128 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * The value that was compared against oldVal. * * Side effects: * None. * *----------------------------------------------------------------------------- */ #ifdef VM_HAS_INT128 static INLINE uint128 Atomic_ReadIfEqualWrite128(Atomic_uint128 *ptr, // IN/OUT uint128 oldVal, // IN uint128 newVal) // IN { #if defined __GNUC__ && defined VM_ARM_64 #define VM_HAS_ATOMIC_READIFEQUALWRITE128 // This function can be used. /* * Don't use __sync_val_compare_and_swap, as this cannot magically * use the right (LL/SC vs LSE) atomics without -moutline-atomics. */ #if __GNUC__ >= 9 if (Atomic_HaveLse()) { SMP_RW_BARRIER_RW(); __asm__ __volatile__( ".arch armv8.2-a \n\t" "casp %0, %H0, %2, %H2, %1 \n\t" : "+r" (oldVal), "+Q" (ptr->value) : "r" (newVal) ); SMP_RW_BARRIER_RW(); return oldVal; } else #endif /* __GNUC__ */ { union { uint128 raw; struct { uint64 lo; uint64 hi; }; } res, _old = { oldVal }, _new = { newVal }; uint32 failed; SMP_RW_BARRIER_RW(); __asm__ __volatile__( "1: ldxp %x0, %x1, %3 \n\t" " cmp %x0, %x4 \n\t" " ccmp %x1, %x5, #0, eq \n\t" " b.ne 2f \n\t" " stxp %w2, %x6, %x7, %3 \n\t" " cbnz %w2, 1b \n\t" "2: \n\t" : "=&r" (res.lo), "=&r" (res.hi), "=&r" (failed), "+Q" (ptr->value) : "r" (_old.lo), "r" (_old.hi), "r" (_new.lo), "r" (_new.hi) : "cc" ); SMP_RW_BARRIER_RW(); return res.raw; } #elif defined __GNUC__ && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 #define VM_HAS_ATOMIC_READIFEQUALWRITE128 // This function can be used. return __sync_val_compare_and_swap(&ptr->value, oldVal, newVal); #else return AtomicUndefined(ptr + oldVal + newVal); #endif } #endif /* *----------------------------------------------------------------------------- * * Atomic_Read8 -- * * Read the value of the specified object atomically. * * Results: * The value of the atomic variable. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_Read8(Atomic_uint8 const *var) // IN: { uint8 val; #if defined VM_ATOMIC_USE_C11 val = atomic_load((const _Atomic(uint8) *)&var->value); #elif defined __GNUC__ && defined VM_ARM_32 val = AtomicUndefined(var); #elif defined __GNUC__ && defined VM_ARM_64 val = _VMATOM_X(R, 8, &var->value); #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) __asm__ __volatile__( "movb %1, %0" : "=q" (val) : "m" (var->value) ); #elif defined _MSC_VER val = var->value; #else #error Atomic_Read8 not implemented #endif return val; } /* *----------------------------------------------------------------------------- * * Atomic_ReadWrite8 -- * * Read followed by write. * * Results: * The value of the atomic variable before the write. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_ReadWrite8(Atomic_uint8 *var, // IN/OUT: uint8 val) // IN: { #if defined VM_ATOMIC_USE_C11 return atomic_exchange((_Atomic(uint8) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_32 return AtomicUndefined(var + val); #elif defined __GNUC__ && defined VM_ARM_64 return _VMATOM_X(RW, 8, TRUE, &var->value, val); #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) __asm__ __volatile__( "xchgb %0, %1" : "=q" (val), "+m" (var->value) : "0" (val) : "memory" ); return val; #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (volatile char) == sizeof var->value); return _InterlockedExchange8((volatile char *)&var->value, val); #else #error Atomic_ReadWrite8 not implemented #endif } /* *----------------------------------------------------------------------------- * * Atomic_Write8 -- * * Write the specified value to the specified object atomically. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Write8(Atomic_uint8 *var, // IN/OUT: uint8 val) // IN: { #if defined VM_ATOMIC_USE_C11 atomic_store((_Atomic(uint8) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_32 AtomicUndefined(var + val); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(W, 8, &var->value, val); #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) __asm__ __volatile__( "movb %1, %0" : "=m" (var->value) : "qn" (val) ); #elif defined _MSC_VER var->value = val; #else #error Atomic_Write8 not implemented #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadIfEqualWrite8 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal. * * Results: * The value that was compared against oldVal. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_ReadIfEqualWrite8(Atomic_uint8 *var, // IN/OUT: uint8 oldVal, // IN: uint8 newVal) // IN: { #if defined VM_ATOMIC_USE_C11 atomic_compare_exchange_strong( (_Atomic(uint8) *)&var->value, &oldVal, newVal); return oldVal; #elif defined __GNUC__ && defined VM_ARM_32 return AtomicUndefined(var + oldVal + newVal); #elif defined __GNUC__ && defined VM_ARM_64 return _VMATOM_X(RIFEQW, 8, TRUE, &var->value, oldVal, newVal); #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) uint8 val; __asm__ __volatile__( "lock; cmpxchgb %2, %1" : "=a" (val), "+m" (var->value) : "q" (newVal), "0" (oldVal) : "cc", "memory" ); return val; #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (volatile char) == sizeof var->value); return _InterlockedCompareExchange8((volatile char *)&var->value, newVal, oldVal); #else #error Atomic_ReadIfEqualWrite8 not implemented #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadAnd8 -- * * Atomic read (returned), bitwise AND with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_ReadAnd8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { uint8 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_and((_Atomic(uint8) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 8, TRUE, &var->value, and, val); #else do { res = Atomic_Read8(var); } while (res != Atomic_ReadIfEqualWrite8(var, res, res & val)); #endif return res; } /* *----------------------------------------------------------------------------- * * Atomic_And8 -- * * Atomic read, bitwise AND with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_And8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { #if defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 8, TRUE, &var->value, and, val); #else (void)Atomic_ReadAnd8(var, val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadOr8 -- * * Atomic read (returned), bitwise OR with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_ReadOr8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { uint8 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_or((_Atomic(uint8) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 8, TRUE, &var->value, orr, val); #else do { res = Atomic_Read8(var); } while (res != Atomic_ReadIfEqualWrite8(var, res, res | val)); #endif return res; } /* *----------------------------------------------------------------------------- * * Atomic_Or8 -- * * Atomic read, bitwise OR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Or8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { #if defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 8, TRUE, &var->value, orr, val); #else (void)Atomic_ReadOr8(var, val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadXor8 -- * * Atomic read (returned), bitwise XOR with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_ReadXor8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { uint8 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_xor((_Atomic(uint8) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 8, TRUE, &var->value, eor, val); #else do { res = Atomic_Read8(var); } while (res != Atomic_ReadIfEqualWrite8(var, res, res ^ val)); #endif return res; } /* *----------------------------------------------------------------------------- * * Atomic_Xor8 -- * * Atomic read, bitwise XOR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Xor8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { #if defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 8, TRUE, &var->value, eor, val); #else (void)Atomic_ReadXor8(var, val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadAdd8 -- * * Atomic read (returned), add a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_ReadAdd8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { uint8 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_add((_Atomic(uint8) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 8, TRUE, &var->value, add, val); #else do { res = Atomic_Read8(var); } while (res != Atomic_ReadIfEqualWrite8(var, res, res + val)); #endif return res; } /* *----------------------------------------------------------------------------- * * Atomic_Add8 -- * * Atomic read, add a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Add8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { #if defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 8, TRUE, &var->value, add, val); #else (void)Atomic_ReadAdd8(var, val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Sub8 -- * * Atomic read, subtract a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Sub8(Atomic_uint8 *var, // IN/OUT uint8 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_sub((_Atomic(uint8) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 8, TRUE, &var->value, sub, val); #else Atomic_Add8(var, -val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Inc8 -- * * Atomic read, increment, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Inc8(Atomic_uint8 *var) // IN/OUT { Atomic_Add8(var, 1); } /* *----------------------------------------------------------------------------- * * Atomic_Dec8 -- * * Atomic read, decrement, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Dec8(Atomic_uint8 *var) // IN/OUT { Atomic_Sub8(var, 1); } /* *----------------------------------------------------------------------------- * * Atomic_ReadInc8 -- * * Atomic read (returned), increment, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_ReadInc8(Atomic_uint8 *var) // IN/OUT { return Atomic_ReadAdd8(var, 1); } /* *----------------------------------------------------------------------------- * * Atomic_ReadDec8 -- * * Atomic read (returned), decrement, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint8 Atomic_ReadDec8(Atomic_uint8 *var) // IN/OUT { return Atomic_ReadAdd8(var, (uint8)-1); } /* *----------------------------------------------------------------------------- * * Atomic_Read32 -- * * Read * * Results: * The value of the atomic variable. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_Read32(Atomic_uint32 const *var) // IN { uint32 value; #if defined VMM || defined VM_ARM_64 || defined VMKERNEL || defined VMKERNEL_MODULE ASSERT(((uintptr_t)var % 4) == 0); #endif #if defined VM_ATOMIC_USE_C11 value = atomic_load((_Atomic(uint32) *)&var->value); #elif defined __GNUC__ /* * Use inline assembler to force using a single load instruction to * ensure that the compiler doesn't split a transfer operation into multiple * instructions. */ #if defined VM_ARM_32 __asm__ __volatile__( "ldr %0, [%1]" : "=r" (value) : "r" (&var->value) ); #elif defined VM_ARM_64 value = _VMATOM_X(R, 32, &var->value); #else __asm__ __volatile__( "mov %1, %0" : "=r" (value) : "m" (var->value) ); #endif #elif defined _MSC_VER /* * Microsoft docs guarantee simple reads and writes to properly * aligned 32-bit variables use only a single instruction. * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx */ value = var->value; #else #error Atomic_Read32 not implemented #endif return value; } #define Atomic_Read Atomic_Read32 /* *----------------------------------------------------------------------------- * * Atomic_ReadWrite32 -- * * Read followed by write * * Results: * The value of the atomic variable before the write. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadWrite32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { #if defined VM_ATOMIC_USE_C11 return atomic_exchange((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ #ifdef VM_ARM_V7 uint32 retVal; uint32 res; dmb(); __asm__ __volatile__( "1: ldrex %[retVal], [%[var]] \n\t" "strex %[res], %[val], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [retVal] "=&r" (retVal), [res] "=&r" (res) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); return retVal; #elif defined VM_ARM_64 return _VMATOM_X(RW, 32, TRUE, &var->value, val); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "xchgl %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) : "memory" ); return val; #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); return _InterlockedExchange((long *)&var->value, (long)val); #else #error Atomic_ReadWrite32 not implemented #endif // __GNUC__ } #define Atomic_ReadWrite Atomic_ReadWrite32 /* *----------------------------------------------------------------------------- * * Atomic_Write32 -- * * Write * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Write32(Atomic_uint32 *var, // OUT uint32 val) // IN { #if defined VMM || defined VM_ARM_64 || defined VMKERNEL || defined VMKERNEL_MODULE ASSERT(((uintptr_t)var % 4) == 0); #endif #if defined VM_ATOMIC_USE_C11 atomic_store((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ #if defined VM_ARM_64 _VMATOM_X(W, 32, &var->value, val); #elif defined VM_ARM_32 /* * Best left this way due to the intricacies of exclusive load/store * operations on legacy (32-bit) ARM. * * A3.4.1 ARM DDI 0406C: * * When a processor writes using any instruction other than a * Store-Exclusive: * * - if the write is to a physical address that is not covered by its local * monitor the write does not affect the state of the local monitor * - if the write is to a physical address that is covered by its local * monitor it is IMPLEMENTATION DEFINED whether the write affects the * state of the local monitor. * * A3.4.5 ARM DDI 0406C: * * If two STREX instructions are executed without an intervening LDREX the * second STREX returns a status value of 1. This means that: * * - ARM recommends that, in a given thread of execution, every STREX has a * preceding LDREX associated with it * - it is not necessary for every LDREX to have a subsequent STREX. */ Atomic_ReadWrite32(var, val); #else /* * Use inline assembler to force using a single store instruction to * ensure that the compiler doesn't split a transfer operation into multiple * instructions. */ __asm__ __volatile__( "mov %1, %0" : "=m" (var->value) : "r" (val) ); #endif #elif defined _MSC_VER /* * Microsoft docs guarantee simple reads and writes to properly * aligned 32-bit variables use only a single instruction. * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx */ var->value = val; #else #error Atomic_Write32 not implemented #endif } #define Atomic_Write Atomic_Write32 /* *----------------------------------------------------------------------------- * * Atomic_ReadIfEqualWrite32 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * The value that was compared against oldVal. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadIfEqualWrite32(Atomic_uint32 *var, // IN/OUT uint32 oldVal, // IN uint32 newVal) // IN { #if defined VM_ATOMIC_USE_C11 atomic_compare_exchange_strong( (_Atomic(uint32) *)&var->value, &oldVal, newVal); return oldVal; #elif defined __GNUC__ #ifdef VM_ARM_V7 uint32 retVal; uint32 res; dmb(); __asm__ __volatile__( "1: ldrex %[retVal], [%[var]] \n\t" "mov %[res], #0 \n\t" "teq %[retVal], %[oldVal] \n\t" "strexeq %[res], %[newVal], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [retVal] "=&r" (retVal), [res] "=&r" (res) : [var] "r" (&var->value), [oldVal] "r" (oldVal), [newVal] "r" (newVal) : "cc" ); dmb(); return retVal; #elif defined VM_ARM_64 return _VMATOM_X(RIFEQW, 32, TRUE, &var->value, oldVal, newVal); #else /* VM_X86_ANY */ uint32 val; /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; cmpxchgl %2, %1" : "=a" (val), "+m" (var->value) : "r" (newVal), "0" (oldVal) : "cc", "memory" ); return val; #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); return _InterlockedCompareExchange((long *)&var->value, (long)newVal, (long)oldVal); #else #error Atomic_ReadIfEqualWrite32 not implemented #endif } #define Atomic_ReadIfEqualWrite Atomic_ReadIfEqualWrite32 #if defined VM_64BIT || defined VM_ARM_V7 || defined VM_ATOMIC_USE_C11 /* *----------------------------------------------------------------------------- * * Atomic_ReadIfEqualWrite64 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * The value that was compared against oldVal. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadIfEqualWrite64(Atomic_uint64 *var, // IN/OUT uint64 oldVal, // IN uint64 newVal) // IN { #if defined VM_ATOMIC_USE_C11 atomic_compare_exchange_strong( (_Atomic(uint64) *)&var->value, &oldVal, newVal); return oldVal; #elif defined __GNUC__ #ifdef VM_ARM_V7 uint64 retVal; uint32 res; dmb(); /* * Under Apple LLVM version 5.0 (clang-500.2.76) (based on LLVM 3.3svn) * There will be a warning: * "value size does not match register size specified by the constraint * and modifier [-Wasm-operand-widths]" * on the lines: * : [var] "r" (&var->value), [oldVal] "r" (oldVal), [newVal] "r" (newVal) * ^ * : [var] "r" (&var->value), [oldVal] "r" (oldVal), [newVal] "r" (newVal) * ^ * * Furthermore, using a 32-bits register to store a * 64-bits value of an variable looks risky. */ #if defined __APPLE__ && __clang__ == 1 && __clang_major__ >= 5 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wasm-operand-widths" #endif __asm__ __volatile__( "1: ldrexd %[retVal], %H[retVal], [%[var]] \n\t" "mov %[res], #0 \n\t" "teq %[retVal], %[oldVal] \n\t" "teqeq %H[retVal], %H[oldVal] \n\t" "strexdeq %[res], %[newVal], %H[newVal], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [retVal] "=&r" (retVal), [res] "=&r" (res) : [var] "r" (&var->value), [oldVal] "r" (oldVal), [newVal] "r" (newVal) : "cc" ); #if defined __APPLE__ && __clang__ == 1 && __clang_major__ >= 5 #pragma clang diagnostic pop #endif // defined __APPLE__ && __clang__ == 1 && __clang_major__ >= 5 dmb(); return retVal; #elif defined VM_ARM_64 return _VMATOM_X(RIFEQW, 64, TRUE, &var->value, oldVal, newVal); #else /* VM_X86_64 */ uint64 val; /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; cmpxchgq %2, %1" : "=a" (val), "+m" (var->value) : "r" (newVal), "0" (oldVal) : "cc", "memory" ); return val; #endif //VM_ARM_V7 #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); return _InterlockedCompareExchange64((__int64 *)&var->value, (__int64)newVal, (__int64)oldVal); #else #error Atomic_ReadIfEqualWrite64 not implemented #endif } #endif /* *----------------------------------------------------------------------------- * * Atomic_And32 -- * * Atomic read, bitwise AND with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_And32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_and((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ #ifdef VM_ARM_V7 uint32 res; uint32 tmp; dmb(); __asm__ __volatile__( "1: ldrex %[tmp], [%[var]] \n\t" "and %[tmp], %[tmp], %[val] \n\t" "strex %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined VM_ARM_64 _VMATOM_X(OP, 32, TRUE, &var->value, and, val); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; andl %1, %0" : "+m" (var->value) : "ri" (val) : "cc", "memory" ); #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); _InterlockedAnd((long *)&var->value, (long)val); #else #error Atomic_And32 not implemented #endif } #define Atomic_And Atomic_And32 /* *----------------------------------------------------------------------------- * * Atomic_Or32 -- * * Atomic read, bitwise OR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Or32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_or((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ #ifdef VM_ARM_V7 uint32 res; uint32 tmp; dmb(); __asm__ __volatile__( "1: ldrex %[tmp], [%[var]] \n\t" "orr %[tmp], %[tmp], %[val] \n\t" "strex %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined VM_ARM_64 _VMATOM_X(OP, 32, TRUE, &var->value, orr, val); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; orl %1, %0" : "+m" (var->value) : "ri" (val) : "cc", "memory" ); #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); _InterlockedOr((long *)&var->value, (long)val); #else #error Atomic_Or32 not implemented #endif } #define Atomic_Or Atomic_Or32 /* *----------------------------------------------------------------------------- * * Atomic_Xor32 -- * * Atomic read, bitwise XOR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Xor32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_xor((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ #ifdef VM_ARM_V7 uint32 res; uint32 tmp; dmb(); __asm__ __volatile__( "1: ldrex %[tmp], [%[var]] \n\t" "eor %[tmp], %[tmp], %[val] \n\t" "strex %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined VM_ARM_64 _VMATOM_X(OP, 32, TRUE, &var->value, eor, val); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; xorl %1, %0" : "+m" (var->value) : "ri" (val) : "cc", "memory" ); #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); _InterlockedXor((long *)&var->value, (long)val); #else #error Atomic_Xor32 not implemented #endif } #define Atomic_Xor Atomic_Xor32 #if defined VM_64BIT /* *----------------------------------------------------------------------------- * * Atomic_Xor64 -- * * Atomic read, bitwise XOR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Xor64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_xor((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ #if defined VM_ARM_64 _VMATOM_X(OP, 64, TRUE, &var->value, eor, val); #else /* VM_X86_64 */ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; xorq %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #endif #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); _InterlockedXor64((__int64 *)&var->value, (__int64)val); #else #error Atomic_Xor64 not implemented #endif } #endif /* *----------------------------------------------------------------------------- * * Atomic_Add32 -- * * Atomic read, add a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Add32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_add((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ #ifdef VM_ARM_V7 uint32 res; uint32 tmp; dmb(); __asm__ __volatile__( "1: ldrex %[tmp], [%[var]] \n\t" "add %[tmp], %[tmp], %[val] \n\t" "strex %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined VM_ARM_64 _VMATOM_X(OP, 32, TRUE, &var->value, add, val); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; addl %1, %0" : "+m" (var->value) : "ri" (val) : "cc", "memory" ); #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); _InterlockedExchangeAdd((long *)&var->value, (long)val); #else #error Atomic_Add32 not implemented #endif } #define Atomic_Add Atomic_Add32 /* *----------------------------------------------------------------------------- * * Atomic_Sub32 -- * * Atomic read, subtract a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Sub32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_sub((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ #ifdef VM_ARM_V7 uint32 res; uint32 tmp; dmb(); __asm__ __volatile__( "1: ldrex %[tmp], [%[var]] \n\t" "sub %[tmp], %[tmp], %[val] \n\t" "strex %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined VM_ARM_64 _VMATOM_X(OP, 32, TRUE, &var->value, sub, val); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; subl %1, %0" : "+m" (var->value) : "ri" (val) : "cc", "memory" ); #endif /* VM_X86_ANY */ #elif defined _MSC_VER /* * Microsoft warning C4146, enabled by the /sdl option for * additional security checks, objects to `-val' when val is * unsigned, even though that is always well-defined by C and has * exactly the semantics we want, namely negation modulo 2^32. * (The signed version, in contrast, has undefined behaviour at * some inputs.) * * https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4146?view=msvc-170 * https://docs.microsoft.com/en-us/cpp/build/reference/sdl-enable-additional-security-checks?view=msvc-170 */ # pragma warning(push) # pragma warning(disable: 4146) ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); _InterlockedExchangeAdd((long *)&var->value, (long)-val); # pragma warning(pop) #else #error Atomic_Sub32 not implemented #endif } #define Atomic_Sub Atomic_Sub32 /* *----------------------------------------------------------------------------- * * Atomic_Inc32 -- * * Atomic read, increment, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Inc32(Atomic_uint32 *var) // IN/OUT { #if defined VM_ATOMIC_USE_C11 Atomic_Add32(var, 1); #elif defined __GNUC__ #if defined VM_ARM_ANY Atomic_Add32(var, 1); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; incl %0" : "+m" (var->value) : : "cc", "memory" ); #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); _InterlockedIncrement((long *)&var->value); #else #error Atomic_Inc32 not implemented #endif } #define Atomic_Inc Atomic_Inc32 /* *----------------------------------------------------------------------------- * * Atomic_Dec32 -- * * Atomic read, decrement, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Dec32(Atomic_uint32 *var) // IN/OUT { #if defined VM_ATOMIC_USE_C11 Atomic_Sub32(var, 1); #elif defined __GNUC__ #if defined VM_ARM_ANY Atomic_Sub32(var, 1); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; decl %0" : "+m" (var->value) : : "cc", "memory" ); #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); _InterlockedDecrement((long *)&var->value); #else #error Atomic_Dec32 not implemented #endif } #define Atomic_Dec Atomic_Dec32 /* * Note that the technique below can be used to implement ReadX(), where X is * an arbitrary mathematical function. */ /* *----------------------------------------------------------------------------- * * Atomic_ReadOr32 -- * * Atomic read (returned), bitwise OR with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadOr32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { uint32 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_or((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 32, TRUE, &var->value, orr, val); #else do { res = Atomic_Read32(var); } while (res != Atomic_ReadIfEqualWrite32(var, res, res | val)); #endif return res; } /* *----------------------------------------------------------------------------- * * Atomic_ReadAnd32 -- * * Atomic read (returned), bitwise And with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadAnd32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { uint32 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_and((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 32, TRUE, &var->value, and, val); #else do { res = Atomic_Read32(var); } while (res != Atomic_ReadIfEqualWrite32(var, res, res & val)); #endif return res; } #if defined VM_64BIT /* *----------------------------------------------------------------------------- * * Atomic_ReadOr64 -- * * Atomic read (returned), bitwise OR with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadOr64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { uint64 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_or((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 64, TRUE, &var->value, orr, val); #else do { res = var->value; } while (res != Atomic_ReadIfEqualWrite64(var, res, res | val)); #endif return res; } /* *----------------------------------------------------------------------------- * * Atomic_ReadAnd64 -- * * Atomic read (returned), bitwise AND with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadAnd64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { uint64 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_and((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 64, TRUE, &var->value, and, val); #else do { res = var->value; } while (res != Atomic_ReadIfEqualWrite64(var, res, res & val)); #endif return res; } #endif /* defined VM_64BIT */ /* *----------------------------------------------------------------------------- * * Atomic_ReadAdd32 -- * * Atomic read (returned), add a value, write. * * If you have to implement ReadAdd32() on an architecture other than * x86 or x86-64, you might want to consider doing something similar to * Atomic_ReadOr32(). * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadAdd32(Atomic_uint32 *var, // IN/OUT uint32 val) // IN { #if defined VM_ATOMIC_USE_C11 return atomic_fetch_add((_Atomic(uint32) *)&var->value, val); #elif defined __GNUC__ #ifdef VM_ARM_V7 uint32 res; uint32 retVal; uint32 tmp; dmb(); __asm__ __volatile__( "1: ldrex %[retVal], [%[var]] \n\t" "add %[tmp], %[val], %[retVal] \n\t" "strex %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [tmp] "=&r" (tmp), [res] "=&r" (res), [retVal] "=&r" (retVal) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); return retVal; #elif defined VM_ARM_64 return _VMATOM_X(ROP, 32, TRUE, &var->value, add, val); #else /* VM_X86_ANY */ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; xaddl %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) : "cc", "memory" ); return val; #endif /* VM_X86_ANY */ #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (long) == sizeof var->value); return _InterlockedExchangeAdd((long *)&var->value, (long)val); #else #error Atomic_ReadAdd32 not implemented #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadInc32 -- * * Atomic read (returned), increment, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadInc32(Atomic_uint32 *var) // IN/OUT { return Atomic_ReadAdd32(var, 1); } /* *----------------------------------------------------------------------------- * * Atomic_ReadDec32 -- * * Atomic read (returned), decrement, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadDec32(Atomic_uint32 *var) // IN/OUT { return Atomic_ReadAdd32(var, (uint32)-1); } /* *----------------------------------------------------------------------------- * * Atomic_CMPXCHG64 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * TRUE if equal, FALSE if not equal * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_CMPXCHG64(Atomic_uint64 *var, // IN/OUT uint64 oldVal, // IN uint64 newVal) // IN { #if defined VM_ATOMIC_USE_C11 return atomic_compare_exchange_strong( (_Atomic(uint64) *)&var->value, &oldVal, newVal); #elif defined __GNUC__ #if defined VM_ARM_ANY return Atomic_ReadIfEqualWrite64(var, oldVal, newVal) == oldVal; #else /* VM_X86_ANY */ Bool equal; /* Checked against the Intel manual and GCC --walken */ #if defined __x86_64__ uint64 dummy; __asm__ __volatile__( "lock; cmpxchgq %3, %0" IF_ASM_FLAG_OUTPUT("", "\n\t" "sete %1") : "+m" (*var), IF_ASM_FLAG_OUTPUT("=@cce", "=qm") (equal), "=a" (dummy) : "r" (newVal), "2" (oldVal) : "cc", "memory" ); #else /* 32-bit version for non-ARM */ typedef struct { uint32 lowValue; uint32 highValue; } S_uint64; int dummy1, dummy2; # if defined __PIC__ /* * Rules for __asm__ statements in __PIC__ code * -------------------------------------------- * * The compiler uses %ebx for __PIC__ code, so an __asm__ statement cannot * clobber %ebx. The __asm__ statement can temporarily modify %ebx, but _for * each parameter that is used while %ebx is temporarily modified_: * * 1) The constraint cannot be "m", because the memory location the compiler * chooses could then be relative to %ebx. * * 2) The constraint cannot be a register class which contains %ebx (such as * "r" or "q"), because the register the compiler chooses could then be * %ebx. (This happens when compiling the Fusion UI with gcc 4.2.1, Apple * build 5577.) * * 3) Using register classes even for other values is problematic, as gcc * can decide e.g. %ecx == %edi == 0 (as compile-time constants) and * ends up using one register for two things. Which breaks xchg's ability * to temporarily put the PIC pointer somewhere else. PR772455 * * For that reason alone, the __asm__ statement should keep the regions * where it temporarily modifies %ebx as small as possible, and should * prefer specific register assignments. */ __asm__ __volatile__( "xchgl %%ebx, %6" "\n\t" "lock; cmpxchg8b (%3)" "\n\t" "xchgl %%ebx, %6" IF_ASM_FLAG_OUTPUT("", "\n\t" "sete %0") : IF_ASM_FLAG_OUTPUT("=@cce", "=qm") (equal), "=a" (dummy1), "=d" (dummy2) : /* * See the "Rules for __asm__ statements in __PIC__ code" above: %3 * must use a register class which does not contain %ebx. * "a"/"c"/"d" are already used, so we are left with either "S" or "D". * * Note that this assembly uses ALL GP registers (with %esp reserved for * stack, %ebp reserved for frame, %ebx reserved for PIC). */ "S" (var), "1" (((S_uint64 *)&oldVal)->lowValue), "2" (((S_uint64 *)&oldVal)->highValue), "D" (((S_uint64 *)&newVal)->lowValue), "c" (((S_uint64 *)&newVal)->highValue) : "cc", "memory" ); # else __asm__ __volatile__( "lock; cmpxchg8b %0" IF_ASM_FLAG_OUTPUT("", "\n\t" "sete %1") : "+m" (*var), IF_ASM_FLAG_OUTPUT("=@cce", "=qm") (equal), "=a" (dummy1), "=d" (dummy2) : "2" (((S_uint64 *)&oldVal)->lowValue), "3" (((S_uint64 *)&oldVal)->highValue), "b" (((S_uint64 *)&newVal)->lowValue), "c" (((S_uint64 *)&newVal)->highValue) : "cc", "memory" ); # endif #endif return equal; #endif //VM_ARM_V7 #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); return (__int64)oldVal == _InterlockedCompareExchange64((__int64 *)&var->value, (__int64)newVal, (__int64)oldVal); #else #error Atomic_CMPXCHG64 not implemented #endif // !GNUC } /* *----------------------------------------------------------------------------- * * Atomic_CMPXCHG32 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * TRUE if equal, FALSE if not equal * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_CMPXCHG32(Atomic_uint32 *var, // IN/OUT uint32 oldVal, // IN uint32 newVal) // IN { #if defined VM_ATOMIC_USE_C11 return atomic_compare_exchange_strong( (_Atomic(uint32) *)&var->value, &oldVal, newVal); #elif defined __GNUC__ #if defined VM_ARM_ANY return Atomic_ReadIfEqualWrite32(var, oldVal, newVal) == oldVal; #else /* VM_X86_ANY */ Bool equal; uint32 dummy; __asm__ __volatile__( "lock; cmpxchgl %3, %0" IF_ASM_FLAG_OUTPUT("", "\n\t" "sete %1") : "+m" (*var), IF_ASM_FLAG_OUTPUT("=@cce", "=qm") (equal), "=a" (dummy) : "r" (newVal), "2" (oldVal) : "cc", "memory" ); return equal; #endif /* VM_X86_ANY */ #else // defined __GNUC__ return Atomic_ReadIfEqualWrite32(var, oldVal, newVal) == oldVal; #endif // !defined __GNUC__ } /* *----------------------------------------------------------------------------- * * Atomic_Read64 -- * * Read and return. * * Results: * The value of the atomic variable. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_Read64(Atomic_uint64 const *var) // IN { #if defined VM_ATOMIC_USE_C11 return atomic_load((const _Atomic(uint64) *)&var->value); #else #if defined __GNUC__ uint64 value; #endif #if defined VMM || defined VM_ARM_64 || defined VMKERNEL || defined VMKERNEL_MODULE ASSERT((uintptr_t)var % 8 == 0); #endif #if defined __GNUC__ && defined __x86_64__ /* * Use asm to ensure we emit a single load. */ __asm__ __volatile__( "movq %1, %0" : "=r" (value) : "m" (var->value) ); #elif defined __GNUC__ && defined __i386__ /* * Since cmpxchg8b will replace the contents of EDX:EAX with the * value in memory if there is no match, we need only execute the * instruction once in order to atomically read 64 bits from * memory. The only constraint is that ECX:EBX must have the same * value as EDX:EAX so that if the comparison succeeds. We * intentionally don't tell gcc that we are using ebx and ecx as we * don't modify them and do not care what value they store. */ __asm__ __volatile__( "mov %%ebx, %%eax" "\n\t" "mov %%ecx, %%edx" "\n\t" "lock; cmpxchg8b %1" : "=&A" (value) : "m" (*var) : "cc" ); #elif defined _MSC_VER && defined VM_64BIT /* * Microsoft docs guarantee "Simple reads and writes to properly * aligned 64-bit variables are atomic on 64-bit Windows." * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx * * XXX Unconditionally verify that value is properly aligned. Bug 61315. */ return var->value; #elif defined _MSC_VER && defined VM_ARM_32 /* MSVC + 32-bit ARM has add64 but no cmpxchg64 */ ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); return _InterlockedAdd64((__int64 *)&var->value, 0); #elif defined _MSC_VER && defined __i386__ /* MSVC + 32-bit x86 has cmpxchg64 but no add64 */ ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); return _InterlockedCompareExchange64((__int64 *)&var->value, (__int64)255, // Unlikely value to (__int64)255); // not dirty cache #elif defined __GNUC__ && defined VM_ARM_V7 __asm__ __volatile__( "ldrexd %[value], %H[value], [%[var]] \n\t" : [value] "=&r" (value) : [var] "r" (&var->value) ); #elif defined VM_ARM_64 value = _VMATOM_X(R, 64, &var->value); #endif #if defined __GNUC__ return value; #endif #endif // !defined VM_ATOMIC_USE_C11 } /* *---------------------------------------------------------------------- * * Atomic_ReadUnaligned64 -- * * Atomically read a 64 bit integer, possibly misaligned. * This function can be *very* expensive, costing over 50 kcycles * on Nehalem. * * Note that "var" needs to be writable, even though it will not * be modified. * * Results: * The value of the atomic variable. * * Side effects: * None * *---------------------------------------------------------------------- */ #if defined VM_64BIT static INLINE uint64 Atomic_ReadUnaligned64(Atomic_uint64 const *var) // IN: { return Atomic_ReadIfEqualWrite64((Atomic_uint64*)var, 0, 0); } #endif /* *---------------------------------------------------------------------- * * Atomic_ReadAdd64 -- * * Atomically adds a 64-bit integer to another * * Results: * Returns the old value just prior to the addition * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadAdd64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { #if defined VM_ATOMIC_USE_C11 return atomic_fetch_add((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 return _VMATOM_X(ROP, 64, TRUE, &var->value, add, val); #elif defined __x86_64__ #if defined __GNUC__ __asm__ __volatile__( "lock; xaddq %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) : "cc", "memory" ); return val; #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); return _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val); #else #error Atomic_ReadAdd64 not implemented #endif #else uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal + val; } while (!Atomic_CMPXCHG64(var, oldVal, newVal)); return oldVal; #endif } /* *---------------------------------------------------------------------- * * Atomic_ReadSub64 -- * * Atomically subtracts a 64-bit integer from another. * * Results: * Returns the old value just prior to the subtraction * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadSub64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { #if defined VM_ATOMIC_USE_C11 return atomic_fetch_sub((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 return _VMATOM_X(ROP, 64, TRUE, &var->value, sub, val); #else # ifdef _MSC_VER /* * Microsoft warning C4146, enabled by the /sdl option for * additional security checks, objects to `-val' when val is * unsigned, even though that is always well-defined by C and has * exactly the semantics we want, namely negation modulo 2^64. * (The signed version, in contrast, has undefined behaviour at * some inputs.) * * https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4146?view=msvc-170 * https://docs.microsoft.com/en-us/cpp/build/reference/sdl-enable-additional-security-checks?view=msvc-170 */ # pragma warning(push) # pragma warning(disable: 4146) # endif return Atomic_ReadAdd64(var, -val); # ifdef _MSC_VER # pragma warning(pop) # endif #endif } /* *---------------------------------------------------------------------- * * Atomic_ReadInc64 -- * * Atomically increments a 64-bit integer * * Results: * Returns the old value just prior to incrementing * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadInc64(Atomic_uint64 *var) // IN/OUT { return Atomic_ReadAdd64(var, 1); } /* *---------------------------------------------------------------------- * * Atomic_ReadDec64 -- * * Atomically decrements a 64-bit integer * * Results: * Returns the old value just prior to decrementing * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadDec64(Atomic_uint64 *var) // IN/OUT { return Atomic_ReadAdd64(var, (uint64)CONST64(-1)); } /* *----------------------------------------------------------------------------- * * Atomic_Add64 -- * * Atomic read, add a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Add64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_add((_Atomic(uint64) *)&var->value, val); #elif !defined VM_64BIT Atomic_ReadAdd64(var, val); /* Return value is unused. */ #elif defined __GNUC__ #if defined VM_ARM_64 _VMATOM_X(OP, 64, TRUE, &var->value, add, val); #else /* defined VM_X86_64 */ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; addq %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #endif #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val); #else #error Atomic_Add64 not implemented #endif } /* *----------------------------------------------------------------------------- * * Atomic_Sub64 -- * * Atomic read, subtract a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Sub64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_sub((_Atomic(uint64) *)&var->value, val); #elif !defined VM_64BIT Atomic_ReadSub64(var, val); /* Return value is unused. */ #elif defined __GNUC__ #if defined VM_ARM_64 _VMATOM_X(OP, 64, TRUE, &var->value, sub, val); #else /* VM_X86_64 */ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; subq %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #endif #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)-val); #else #error Atomic_Sub64 not implemented #endif } /* *----------------------------------------------------------------------------- * * Atomic_Inc64 -- * * Atomic read, increment, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Inc64(Atomic_uint64 *var) // IN/OUT { #if defined VM_ARM_64 || defined VM_ATOMIC_USE_C11 Atomic_Add64(var, 1); #elif !defined __x86_64__ Atomic_ReadInc64(var); /* Return value is unused. */ #elif defined __GNUC__ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; incq %0" : "+m" (var->value) : : "cc", "memory" ); #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); _InterlockedIncrement64((__int64 *)&var->value); #else #error Atomic_Inc64 not implemented #endif } /* *----------------------------------------------------------------------------- * * Atomic_Dec64 -- * * Atomic read, decrement, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Dec64(Atomic_uint64 *var) // IN/OUT { #if defined VM_ARM_64 || defined VM_ATOMIC_USE_C11 Atomic_Sub64(var, 1); #elif !defined __x86_64__ Atomic_ReadDec64(var); /* Return value is unused. */ #elif defined __GNUC__ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; decq %0" : "+m" (var->value) : : "cc", "memory" ); #elif defined _MSC_VER ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); _InterlockedDecrement64((__int64 *)&var->value); #else #error Atomic_Dec64 not implemented #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadWrite64 -- * * Read followed by write * * Results: * The value of the atomic variable before the write. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadWrite64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { #if defined VM_ATOMIC_USE_C11 return atomic_exchange((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ && defined __x86_64__ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "xchgq %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) : "memory" ); return val; #elif defined __GNUC__ && defined VM_ARM_64 return _VMATOM_X(RW, 64, TRUE, &var->value, val); #elif defined _MSC_VER && defined VM_64BIT ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); return _InterlockedExchange64((__int64 *)&var->value, (__int64)val); #else uint64 oldVal; do { oldVal = var->value; } while (!Atomic_CMPXCHG64(var, oldVal, val)); return oldVal; #endif } /* *----------------------------------------------------------------------------- * * Atomic_Write64 -- * * Write * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Write64(Atomic_uint64 *var, // OUT uint64 val) // IN { #if defined VMM || defined VM_ARM_64 || defined VMKERNEL || defined VMKERNEL_MODULE ASSERT((uintptr_t)var % 8 == 0); #endif #if defined VM_ATOMIC_USE_C11 atomic_store((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ && defined __x86_64__ /* * There is no move instruction for 64-bit immediate to memory, so unless * the immediate value fits in 32-bit (i.e. can be sign-extended), GCC * breaks the assignment into two movl instructions. The code below forces * GCC to load the immediate value into a register first. */ __asm__ __volatile__( "movq %1, %0" : "=m" (var->value) : "r" (val) ); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(W, 64, &var->value, val); #elif defined _MSC_VER && defined VM_64BIT /* * Microsoft docs guarantee "Simple reads and writes to properly aligned * 64-bit variables are atomic on 64-bit Windows." * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx * * XXX Unconditionally verify that value is properly aligned. Bug 61315. */ var->value = val; #else (void)Atomic_ReadWrite64(var, val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Or64 -- * * Atomic read, bitwise OR with a 64-bit value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Or64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_or((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ && defined __x86_64__ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; orq %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 64, TRUE, &var->value, orr, val); #elif defined _MSC_VER && defined VM_64BIT ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); _InterlockedOr64((__int64 *)&var->value, (__int64)val); #else uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal | val; } while (!Atomic_CMPXCHG64(var, oldVal, newVal)); #endif } /* *----------------------------------------------------------------------------- * * Atomic_And64 -- * * Atomic read, bitwise AND with a 64-bit value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_And64(Atomic_uint64 *var, // IN/OUT uint64 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_and((_Atomic(uint64) *)&var->value, val); #elif defined __GNUC__ && defined __x86_64__ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; andq %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 64, TRUE, &var->value, and, val); #elif defined _MSC_VER && defined VM_64BIT ASSERT_ON_COMPILE(sizeof (__int64) == sizeof var->value); _InterlockedAnd64((__int64 *)&var->value, (__int64)val); #else uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal & val; } while (!Atomic_CMPXCHG64(var, oldVal, newVal)); #endif } /* *----------------------------------------------------------------------------- * * Atomic_SetBit64 -- * * Atomically set the bit 'bit' in var. Bit must be between 0 and 63. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_SetBit64(Atomic_uint64 *var, // IN/OUT unsigned bit) // IN { #if defined __x86_64__ && defined __GNUC__ ASSERT(bit <= 63); __asm__ __volatile__( "lock; btsq %1, %0" : "+m" (var->value) : "ri" ((uint64)bit) : "cc", "memory" ); #else uint64 oldVal; uint64 newVal; ASSERT(bit <= 63); do { oldVal = var->value; newVal = oldVal | (CONST64U(1) << bit); } while (!Atomic_CMPXCHG64(var, oldVal, newVal)); #endif } /* *----------------------------------------------------------------------------- * * Atomic_ClearBit64 -- * * Atomically clear the bit 'bit' in var. Bit must be between 0 and 63. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_ClearBit64(Atomic_uint64 *var, // IN/OUT unsigned bit) // IN { #if defined __x86_64__ && defined __GNUC__ ASSERT(bit <= 63); __asm__ __volatile__( "lock; btrq %1, %0" : "+m" (var->value) : "ri" ((uint64)bit) : "cc", "memory" ); #else uint64 oldVal; uint64 newVal; ASSERT(bit <= 63); do { oldVal = var->value; newVal = oldVal & ~(CONST64U(1) << bit); } while (!Atomic_CMPXCHG64(var, oldVal, newVal)); #endif } /* *----------------------------------------------------------------------------- * * Atomic_TestBit64 -- * * Read the bit 'bit' in var. Bit must be between 0 and 63. * * Results: * TRUE if the tested bit was set; else FALSE. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_TestBit64(Atomic_uint64 *var, // IN unsigned bit) // IN { Bool out; ASSERT(bit <= 63); #if defined __x86_64__ && defined __GNUC__ __asm__ __volatile__( "btq %2, %1" IF_ASM_FLAG_OUTPUT("", "\n\t" "setc %0") : IF_ASM_FLAG_OUTPUT("=@ccc", "=rm") (out) : "m" (var->value), "rJ" ((uint64)bit) : "cc" ); #else out = (var->value & (CONST64U(1) << bit)) != 0; #endif return out; } /* *----------------------------------------------------------------------------- * * Atomic_TestSetBit64 -- * * Atomically test and set the bit 'bit' in var. * Bit must be between 0 and 63. * * Results: * TRUE if the tested bit was set; else FALSE. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_TestSetBit64(Atomic_uint64 *var, // IN/OUT unsigned bit) // IN { #if defined __x86_64__ && defined __GNUC__ Bool out; ASSERT(bit <= 63); __asm__ __volatile__( "lock; btsq %2, %1" IF_ASM_FLAG_OUTPUT("", "\n\t" "setc %0") : IF_ASM_FLAG_OUTPUT("=@ccc", "=rm") (out), "+m" (var->value) : "rJ" ((uint64)bit) : "cc", "memory" ); return out; #else uint64 oldVal; uint64 mask; ASSERT(bit <= 63); mask = CONST64U(1) << bit; do { oldVal = var->value; } while (!Atomic_CMPXCHG64(var, oldVal, oldVal | mask)); return (oldVal & mask) != 0; #endif } /* *----------------------------------------------------------------------------- * * Atomic_Read16 -- * * Read and return. * * Results: * The value of the atomic variable. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint16 Atomic_Read16(Atomic_uint16 const *var) // IN { uint16 value; #if defined VMM || defined VM_ARM_64 || defined VMKERNEL || \ defined VMKERNEL_MODULE ASSERT((uintptr_t)var % 2 == 0); #endif #if defined VM_ATOMIC_USE_C11 value = atomic_load((_Atomic(uint16) *)&var->value); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "movw %1, %0" : "=r" (value) : "m" (var->value) ); #elif defined __GNUC__ && defined VM_ARM_V7 NOT_TESTED(); __asm__ __volatile__( "ldrh %0, [%1]" : "=r" (value) : "r" (&var->value) ); #elif defined __GNUC__ && defined VM_ARM_64 value = _VMATOM_X(R, 16, &var->value); #else value = (uint16)AtomicUndefined(var); #endif return value; } /* *----------------------------------------------------------------------------- * * Atomic_ReadWrite16 -- * * Read followed by write * * Results: * The value of the atomic variable before the write. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint16 Atomic_ReadWrite16(Atomic_uint16 *var, // IN/OUT: uint16 val) // IN: { #if defined VM_ATOMIC_USE_C11 return atomic_exchange((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "xchgw %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) : "memory" ); return val; #elif defined __GNUC__ && defined VM_ARM_V7 uint16 retVal; uint16 res; NOT_TESTED(); dmb(); __asm__ __volatile__( "1: ldrexh %[retVal], [%[var]] \n\t" "strexh %[res], %[val], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [retVal] "=&r" (retVal), [res] "=&r" (res) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); return retVal; #elif defined __GNUC__ && defined VM_ARM_64 return _VMATOM_X(RW, 16, TRUE, &var->value, val); #else return (uint16)AtomicUndefined(var + val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Write16 -- * * Write * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Write16(Atomic_uint16 *var, // OUT: uint16 val) // IN: { #if defined VMM || defined VM_ARM_64 || defined VMKERNEL || \ defined VMKERNEL_MODULE ASSERT((uintptr_t)var % 2 == 0); #endif #if defined VM_ATOMIC_USE_C11 atomic_store((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "movw %1, %0" : "=m" (var->value) : "r" (val) ); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(W, 16, &var->value, val); #elif defined VM_ARM_32 /* * Best left this way due to the intricacies of exclusive load/store * operations on legacy (32-bit) ARM. */ Atomic_ReadWrite16(var, val); #else AtomicUndefined(var + val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadIfEqualWrite16 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * The value that was compared against oldVal. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint16 Atomic_ReadIfEqualWrite16(Atomic_uint16 *var, // IN/OUT uint16 oldVal, // IN uint16 newVal) // IN { #if defined VM_ATOMIC_USE_C11 atomic_compare_exchange_strong( (_Atomic(uint16) *)&var->value, &oldVal, newVal); return oldVal; #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) uint16 val; __asm__ __volatile__( "lock; cmpxchgw %2, %1" : "=a" (val), "+m" (var->value) : "r" (newVal), "0" (oldVal) : "cc", "memory" ); return val; #elif defined __GNUC__ && defined VM_ARM_V7 uint16 retVal; uint16 res; NOT_TESTED(); dmb(); __asm__ __volatile__( "1: ldrexh %[retVal], [%[var]] \n\t" "mov %[res], #0 \n\t" "teq %[retVal], %[oldVal] \n\t" "strexheq %[res], %[newVal], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [retVal] "=&r" (retVal), [res] "=&r" (res) : [var] "r" (&var->value), [oldVal] "r" (oldVal), [newVal] "r" (newVal) : "cc" ); dmb(); return retVal; #elif defined __GNUC__ && defined VM_ARM_64 return _VMATOM_X(RIFEQW, 16, TRUE, &var->value, oldVal, newVal); #else return (uint16)AtomicUndefined(var + oldVal + newVal); #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadAnd16 -- * * Atomic read (returned), bitwise AND with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint16 Atomic_ReadAnd16(Atomic_uint16 *var, // IN/OUT uint16 val) // IN { uint16 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_and((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 16, TRUE, &var->value, and, val); #else do { res = Atomic_Read16(var); } while (res != Atomic_ReadIfEqualWrite16(var, res, res & val)); #endif return res; } /* *----------------------------------------------------------------------------- * * Atomic_And16 -- * * Atomic read, bitwise AND with a 16-bit value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_And16(Atomic_uint16 *var, // IN/OUT uint16 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_and((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "lock; andw %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #elif defined __GNUC__ && defined VM_ARM_V7 uint16 res; uint16 tmp; NOT_TESTED(); dmb(); __asm__ __volatile__( "1: ldrexh %[tmp], [%[var]] \n\t" "and %[tmp], %[tmp], %[val] \n\t" "strexh %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 16, TRUE, &var->value, and, val); #else AtomicUndefined(var + val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Or16 -- * * Atomic read, bitwise OR with a 16-bit value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Or16(Atomic_uint16 *var, // IN/OUT uint16 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_or((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "lock; orw %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #elif defined __GNUC__ && defined VM_ARM_V7 uint16 res; uint16 tmp; NOT_TESTED(); dmb(); __asm__ __volatile__( "1: ldrexh %[tmp], [%[var]] \n\t" "orr %[tmp], %[tmp], %[val] \n\t" "strexh %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 16, TRUE, &var->value, orr, val); #else AtomicUndefined(var + val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Xor16 -- * * Atomic read, bitwise XOR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Xor16(Atomic_uint16 *var, // IN/OUT uint16 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_xor((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "lock; xorw %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #elif defined __GNUC__ && defined VM_ARM_V7 uint16 res; uint16 tmp; NOT_TESTED(); dmb(); __asm__ __volatile__( "1: ldrexh %[tmp], [%[var]] \n\t" "eor %[tmp], %[tmp], %[val] \n\t" "strexh %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 16, TRUE, &var->value, eor, val); #else AtomicUndefined(var + val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Add16 -- * * Atomic read, add a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Add16(Atomic_uint16 *var, // IN/OUT uint16 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_add((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "lock; addw %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #elif defined __GNUC__ && defined VM_ARM_V7 uint16 res; uint16 tmp; NOT_TESTED(); dmb(); __asm__ __volatile__( "1: ldrexh %[tmp], [%[var]] \n\t" "add %[tmp], %[tmp], %[val] \n\t" "strexh %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 16, TRUE, &var->value, add, val); #else AtomicUndefined(var + val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Sub16 -- * * Atomic read, subtract a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Sub16(Atomic_uint16 *var, // IN/OUT uint16 val) // IN { #if defined VM_ATOMIC_USE_C11 atomic_fetch_sub((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "lock; subw %1, %0" : "+m" (var->value) : "re" (val) : "cc", "memory" ); #elif defined __GNUC__ && defined VM_ARM_V7 uint16 res; uint16 tmp; NOT_TESTED(); dmb(); __asm__ __volatile__( "1: ldrexh %[tmp], [%[var]] \n\t" "sub %[tmp], %[tmp], %[val] \n\t" "strexh %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [res] "=&r" (res), [tmp] "=&r" (tmp) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); #elif defined __GNUC__ && defined VM_ARM_64 _VMATOM_X(OP, 16, TRUE, &var->value, sub, val); #else AtomicUndefined(var + val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Inc16 -- * * Atomic read, increment, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Inc16(Atomic_uint16 *var) // IN/OUT { #if defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "lock; incw %0" : "+m" (var->value) : : "cc", "memory" ); #else Atomic_Add16(var, 1); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Dec16 -- * * Atomic read, decrement, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Dec16(Atomic_uint16 *var) // IN/OUT { #if defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "lock; decw %0" : "+m" (var->value) : : "cc", "memory" ); #else Atomic_Sub16(var, 1); #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadOr16 -- * * Atomic read (returned), bitwise OR with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint16 Atomic_ReadOr16(Atomic_uint16 *var, // IN/OUT uint16 val) // IN { uint16 res; #if defined VM_ATOMIC_USE_C11 res = atomic_fetch_or((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && defined VM_ARM_64 res = _VMATOM_X(ROP, 16, TRUE, &var->value, orr, val); #else do { res = var->value; } while (res != Atomic_ReadIfEqualWrite16(var, res, res | val)); #endif return res; } /* *---------------------------------------------------------------------- * * Atomic_ReadAdd16 -- * * Atomically adds a 16-bit integer to another * * Results: * Returns the old value just prior to the addition * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint16 Atomic_ReadAdd16(Atomic_uint16 *var, // IN/OUT uint16 val) // IN: { #if defined VM_ATOMIC_USE_C11 return atomic_fetch_add((_Atomic(uint16) *)&var->value, val); #elif defined __GNUC__ && (defined __x86_64__ || defined __i386__) __asm__ __volatile__( "lock; xaddw %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) : "cc", "memory" ); return val; #elif defined __GNUC__ && defined VM_ARM_V7 uint16 res; uint16 retVal; uint16 tmp; NOT_TESTED(); dmb(); __asm__ __volatile__( "1: ldrexh %[retVal], [%[var]] \n\t" "add %[tmp], %[val], %[retVal] \n\t" "strexh %[res], %[tmp], [%[var]] \n\t" "teq %[res], #0 \n\t" "bne 1b" : [tmp] "=&r" (tmp), [res] "=&r" (res), [retVal] "=&r" (retVal) : [var] "r" (&var->value), [val] "r" (val) : "cc" ); dmb(); return retVal; #elif defined __GNUC__ && defined VM_ARM_64 return _VMATOM_X(ROP, 16, TRUE, &var->value, add, val); #else return (uint16)AtomicUndefined(var + val); #endif } /* *---------------------------------------------------------------------- * * Atomic_ReadInc16 -- * * Atomically increments a 16-bit integer * * Results: * Returns the old value just prior to incrementing * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint16 Atomic_ReadInc16(Atomic_uint16 *var) // IN/OUT { return Atomic_ReadAdd16(var, 1); } /* *---------------------------------------------------------------------- * * Atomic_ReadDec16 -- * * Atomically decrements a 16-bit integer * * Results: * Returns the old value just prior to decrementing * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint16 Atomic_ReadDec16(Atomic_uint16 *var) // IN/OUT { return Atomic_ReadAdd16(var, (uint16)-1); } /* * Template code for the Atomic_ type and its operators. * * The cast argument is an intermediate type cast to make some * compilers stop complaining about casting uint32 <-> void *, * even though we only do it in the 32-bit case so they are always * the same size. So for val of type uint32, instead of * (void *)val, we have (void *)(uintptr_t)val. * The specific problem case is the Windows ddk compiler * (as used by the SVGA driver). -- edward * * NOTE: See the comment in vm_assert.h for why we need UNUSED_TYPE in * AtomicAssertOnCompile(), and why we need to be very careful doing so. */ #define MAKE_ATOMIC_TYPE(name, size, in, out, cast) \ typedef Atomic_uint ## size Atomic_ ## name; \ \ \ static INLINE void \ AtomicAssertOnCompile ## name(void) \ { \ enum { AssertOnCompileMisused = 8 * sizeof (in) == size \ && 8 * sizeof (out) == size \ && 8 * sizeof (cast) == size \ ? 1 : -1 }; \ UNUSED_TYPE(typedef char AssertOnCompileFailed[AssertOnCompileMisused]);\ } \ \ \ static INLINE out \ Atomic_Read ## name(Atomic_ ## name const *var) \ { \ return (out)(cast)Atomic_Read ## size(var); \ } \ \ \ static INLINE void \ Atomic_Write ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Write ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE out \ Atomic_ReadWrite ## name(Atomic_ ## name *var, \ in val) \ { \ return (out)(cast)Atomic_ReadWrite ## size(var, \ (uint ## size)(cast)val); \ } \ \ \ static INLINE out \ Atomic_ReadIfEqualWrite ## name(Atomic_ ## name *var, \ in oldVal, \ in newVal) \ { \ return (out)(cast)Atomic_ReadIfEqualWrite ## size(var, \ (uint ## size)(cast)oldVal, (uint ## size)(cast)newVal); \ } \ \ \ static INLINE void \ Atomic_And ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_And ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Or ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Or ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Xor ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Xor ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Add ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Add ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Sub ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Sub ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Inc ## name(Atomic_ ## name *var) \ { \ Atomic_Inc ## size(var); \ } \ \ \ static INLINE void \ Atomic_Dec ## name(Atomic_ ## name *var) \ { \ Atomic_Dec ## size(var); \ } \ \ \ static INLINE out \ Atomic_ReadOr ## name(Atomic_ ## name *var, \ in val) \ { \ return (out)(cast)Atomic_ReadOr ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE out \ Atomic_ReadAdd ## name(Atomic_ ## name *var, \ in val) \ { \ return (out)(cast)Atomic_ReadAdd ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE out \ Atomic_ReadInc ## name(Atomic_ ## name *var) \ { \ return (out)(cast)Atomic_ReadInc ## size(var); \ } \ \ \ static INLINE out \ Atomic_ReadDec ## name(Atomic_ ## name *var) \ { \ return (out)(cast)Atomic_ReadDec ## size(var); \ } /* * Since we use a macro to generate these definitions, it is hard to look for * them. So DO NOT REMOVE THIS COMMENT and keep it up-to-date. --hpreg * * Atomic_Ptr * Atomic_ReadPtr -- * Atomic_WritePtr -- * Atomic_ReadWritePtr -- * Atomic_ReadIfEqualWritePtr -- * Atomic_AndPtr -- * Atomic_OrPtr -- * Atomic_XorPtr -- * Atomic_AddPtr -- * Atomic_SubPtr -- * Atomic_IncPtr -- * Atomic_DecPtr -- * Atomic_ReadOrPtr -- * Atomic_ReadAddPtr -- * Atomic_ReadIncPtr -- * Atomic_ReadDecPtr -- * * Atomic_Int * Atomic_ReadInt -- * Atomic_WriteInt -- * Atomic_ReadWriteInt -- * Atomic_ReadIfEqualWriteInt -- * Atomic_AndInt -- * Atomic_OrInt -- * Atomic_XorInt -- * Atomic_AddInt -- * Atomic_SubInt -- * Atomic_IncInt -- * Atomic_DecInt -- * Atomic_ReadOrInt -- * Atomic_ReadAddInt -- * Atomic_ReadIncInt -- * Atomic_ReadDecInt -- * * Atomic_Bool * Atomic_ReadBool -- * Atomic_WriteBool -- * Atomic_ReadWriteBool -- * Atomic_ReadIfEqualWriteBool -- * Atomic_AndBool -- * Atomic_OrBool -- * Atomic_XorBool -- * Atomic_AddBool -- * Atomic_SubBool -- * Atomic_IncBool -- * Atomic_DecBool -- * Atomic_ReadOrBool -- * Atomic_ReadAddBool -- * Atomic_ReadIncBool -- * Atomic_ReadDecBool -- */ #if defined VM_64BIT MAKE_ATOMIC_TYPE(Ptr, 64, void const *, void *, uintptr_t) #else MAKE_ATOMIC_TYPE(Ptr, 32, void const *, void *, uintptr_t) #endif MAKE_ATOMIC_TYPE(Int, 32, int, int, int) MAKE_ATOMIC_TYPE(Bool, 8, Bool, Bool, Bool) /* * Define arbitrary sized bit vector to be used by * Atomic_TestSetBitVector and Atomic_TestClearBitVector. */ #define ATOMIC_BITVECTOR(varName, capacity) \ Atomic_uint8 varName[CEILING(capacity, 8)] /* *----------------------------------------------------------------------------- * * Atomic_SetBitVector -- * * Atomically set the bit 'index' in bit vector var. * * The index input value specifies which bit to modify and is 0-based. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_SetBitVector(Atomic_uint8 *var, // IN/OUT unsigned index) // IN { Atomic_Or8(var + index / 8, 1 << index % 8); } /* *----------------------------------------------------------------------------- * * Atomic_TestSetBitVector -- * * Atomically test and set the bit 'index' in bit vector var. * * The index input value specifies which bit to modify and is 0-based. * * Results: * Returns the value of the bit before modification. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_TestSetBitVector(Atomic_uint8 *var, // IN/OUT unsigned index) // IN { #if defined __x86_64__ && defined __GNUC__ Bool bit; __asm__ __volatile__( "lock; bts %2, %1" IF_ASM_FLAG_OUTPUT("", "\n\t" "setc %0") : IF_ASM_FLAG_OUTPUT("=@ccc", "=qQm") (bit), "+m" (var->value) : "rI" (index) : "cc", "memory" ); return bit; #else uint8 bit = 1 << index % 8; return (Atomic_ReadOr8(var + index / 8, bit) & bit) != 0; #endif } /* *----------------------------------------------------------------------------- * * Atomic_ClearBitVector -- * * Atomically clear the bit 'index' in bit vector var. * * The index input value specifies which bit to modify and is 0-based. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_ClearBitVector(Atomic_uint8 *var, // IN/OUT unsigned index) // IN { Atomic_And8(var + index / 8, ~(1 << index % 8)); } /* *----------------------------------------------------------------------------- * * Atomic_TestClearBitVector -- * * Atomically test and clear the bit 'index' in bit vector var. * * The index input value specifies which bit to modify and is 0-based. * * Results: * Returns the value of the bit before modification. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_TestClearBitVector(Atomic_uint8 *var, // IN/OUT unsigned index) // IN { #if defined __x86_64__ && defined __GNUC__ Bool bit; __asm__ __volatile__( "lock; btr %2, %1" IF_ASM_FLAG_OUTPUT("", "\n\t" "setc %0") : IF_ASM_FLAG_OUTPUT("=@ccc", "=qQm") (bit), "+m" (var->value) : "rI" (index) : "cc", "memory" ); return bit; #else uint8 bit = 1 << index % 8; return (Atomic_ReadAnd8(var + index / 8, ~bit) & bit) != 0; #endif } /* *----------------------------------------------------------------------------- * * Atomic_TestBitVector -- * * Test the bit 'index' (zero-based) in bit vector var. *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_TestBitVector(const Atomic_uint8 *var, // IN unsigned index) // IN { uint8 bit = 1 << index % 8; return (Atomic_Read8(var + index / 8) & bit) != 0; } #ifdef VM_ARM_64 # include "vm_atomic_arm64_end.h" #endif #if defined __cplusplus } // extern "C" #endif #endif // ifndef _ATOMIC_H_ open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vm_atomic_arm64_begin.h000066400000000000000000000533151470176644300270250ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2017-2018,2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * vm_atomic_arm64_begin.h -- * * Define private macros used to implement ARM64 atomic operations. */ #if !( defined _ATOMIC_H_ \ || defined _VM_UNINTERRUPTIBLE_H_ \ || defined _WAIT_UNTIL_LIKELY_H_) # error "Only files which implement an atomic API can include this file!" #endif #include "vm_basic_asm_arm64.h" /* * Atomic_LsePresent should be set to 1 for CPUs that have the LSE extenstion * and where the atomic instructions are known to have a performance benefit. * Seemingly, on some low-end chips (CA55) there may not be a benefit. * * Not every operation can be performed using a single-instruction atomic - * LSE doesn't cover all kinds of logical/arithmetic operations. For example, * there's an ldeor instruction, but not an ldorr. For cases, where there is no * combined instruction that atomically performs the load/store and the ALU * operation, we fall back to CAS or to LL/SC. On some uarches - e.g. Neoverse * N1 - CAS shows better behavior during heavy contention than LL/SC. LL/SC, * though, remains the safest option. Atomic_PreferCasForOps controls this. */ /* * The silliness with _VMATOM_HAVE_LSE_DEFINED is necessary because this * could be included multiple times (via vm_atomic and vm_atomic_relaxed). */ #ifndef _VMATOM_HAVE_LSE_DEFINED typedef struct { Bool LsePresent; #ifndef VMKERNEL Bool ProbedForLse; #endif Bool PreferCasForOps; } Atomic_ConfigParams; #if defined(VMX86_SERVER) || defined(VMKBOOT) /* * When building UW code for ESXi, Atomic_Config a weak symbol. * When building for kernel mode, Atomic_Config is exported by * bora/vmkernel/lib/arm64/atomic.c */ #ifndef VMKERNEL #pragma weak Atomic_Config Atomic_ConfigParams Atomic_Config; #else extern Atomic_ConfigParams Atomic_Config; #endif static INLINE Bool Atomic_HaveLse(void) { #ifndef VMKERNEL /* * Can't just include sys/auxv.h, unfortunately. */ extern uint64 getauxval(uint64 type); #define _VMATOM_AT_ESXI_HWCAP 2000 #define _VMATOM_AT_ESXI_HWCAP_HAVE_LSE (1 << 0) #define _VMATOM_AT_ESXI_HWCAP_PREFER_CAS_FOR_OPS (1 << 1) if (!Atomic_Config.ProbedForLse) { uint64 cap = getauxval(_VMATOM_AT_ESXI_HWCAP); Atomic_Config.LsePresent = (cap &_VMATOM_AT_ESXI_HWCAP_HAVE_LSE) != 0; Atomic_Config.PreferCasForOps = Atomic_Config.LsePresent && (cap & _VMATOM_AT_ESXI_HWCAP_PREFER_CAS_FOR_OPS) != 0; SMP_W_BARRIER_W(); Atomic_Config.ProbedForLse = TRUE; } #undef _VMATOM_AT_ESXI_HWCAP #undef _VMATOM_AT_ESXI_HWCAP_HAVE_LSE #undef _VMATOM_AT_ESXI_HWCAP_PREFER_CAS_FOR_OPS #endif return Atomic_Config.LsePresent; } static INLINE Bool Atomic_PreferCasForOps(void) { return Atomic_Config.PreferCasForOps; } #else /* !VMX86_SERVER && !VMKBOOT */ /* * Not building for ESXi? Assume no LSE. */ #define Atomic_PreferCasForOps() FALSE #define Atomic_HaveLse() FALSE #endif #define _VMATOM_HAVE_LSE_DEFINED #endif /* _VMATOM_HAVE_LSE_DEFINED */ #define _VMATOM_LSE_HAVE(x) _VMATOM_LSE_HAVE_##x #define _VMATOM_LSE_HAVE_add 1 #define _VMATOM_LSE_HAVE_sub 0 #define _VMATOM_LSE_HAVE_eor 1 #define _VMATOM_LSE_HAVE_orr 0 #define _VMATOM_LSE_HAVE_and 0 #define _VMATOM_PREFER_LSE(op) ((_VMATOM_LSE_HAVE(op) && Atomic_HaveLse()) || Atomic_PreferCasForOps()) /* bit size, instruction suffix, register prefix, extend suffix */ #define _VMATOM_SIZE_8 8, b, w, b #define _VMATOM_SIZE_16 16, h, w, h #define _VMATOM_SIZE_32 32, , w, w #define _VMATOM_SIZE_64 64, , x, x /* * Expand 'size' (a _VMATOM_SIZE_*) into its 4 components, then expand * 'snippet' (a _VMATOM_SNIPPET_*) */ #define _VMATOM_X2(snippet, size, ...) snippet(size, __VA_ARGS__) /* Prepend a prefix to 'shortSnippet' and 'shortSize'. */ #define _VMATOM_X(shortSnippet, shortSize, ...) \ _VMATOM_X2(_VMATOM_SNIPPET_##shortSnippet, _VMATOM_SIZE_##shortSize, \ __VA_ARGS__) /* Read relaxed (returned). */ #define _VMATOM_SNIPPET_R_NF(bs, is, rp, es, atm) ({ \ uint##bs _val; \ \ /* ldr is atomic if and only if 'atm' is aligned on #bs bits. */ \ __asm__ __volatile__( \ "ldr"#is" %"#rp"0, %1 \n\t"\ : "=r" (_val) \ : "m" (*atm) \ ); \ \ _val; \ }) #define _VMATOM_SNIPPET_R _VMATOM_SNIPPET_R_NF /* Read acquire/seq_cst (returned). */ #define _VMATOM_SNIPPET_R_SC(bs, is, rp, es, atm) ({ \ uint##bs _val; \ \ /* ldar is atomic if and only if 'atm' is aligned on #bs bits. */ \ __asm__ __volatile__( \ "ldar"#is" %"#rp"0, %1 \n\t"\ : "=r" (_val) \ : "Q" (*atm) \ ); \ \ _val; \ }) /* Write relaxed. */ #define _VMATOM_SNIPPET_W_NF(bs, is, rp, es, atm, val) ({ \ /* \ * str is atomic if and only if 'atm' is aligned on #bs bits. \ * \ * Clearing the exclusive monitor is not required. The local monitor is \ * cleared on any exception return, and the global monitor (as per B2.10.2,\ * ARM DDI 0487A.k) is cleared by a successful write. \ */ \ __asm__ __volatile__( \ "str"#is" %"#rp"1, %0 \n\t"\ : "=m" (*atm) \ : "r" (val) \ ); \ }) #define _VMATOM_SNIPPET_W _VMATOM_SNIPPET_W_NF /* Write release/seq_cst. */ #define _VMATOM_SNIPPET_W_SC(bs, is, rp, es, atm, val) ({ \ /* \ * stlr is atomic if and only if 'atm' is aligned on #bs bits. \ * \ * Clearing the exclusive monitor is not required. The local monitor is \ * cleared on any exception return, and the global monitor (as per B2.10.2,\ * ARM DDI 0487A.k) is cleared by a successful write. \ */ \ __asm__ __volatile__( \ "stlr"#is" %"#rp"1, %0 \n\t"\ : "=Q" (*atm) \ : "r" (val) \ ); \ }) /* * Since on x86, some atomic operations are using LOCK semantics, assumptions * have been made about the ordering these operations imply on surrounding * code. As a result, on arm64 we have to provide these same guarantees. * We do this by making use of DMB barriers both before and after the atomic * ldrx/strx sequences. */ #define _VMATOM_FENCE(fenced) \ if (fenced) { \ SMP_RW_BARRIER_RW(); \ } /* Read (not returned), op with modval, write. */ #define _VMATOM_SNIPPET_OP(bs, is, rp, es, fenced, atm, op, modval) ({ \ uint##bs _newval; \ \ _VMATOM_FENCE(fenced); \ if (_VMATOM_PREFER_LSE(op)) { \ if (_VMATOM_LSE_HAVE(op)) { \ __asm__ __volatile__( \ ".arch armv8.2-a \n\t"\ "st" #op #is" %"#rp"1, %0 \n\t"\ : "+Q" (*atm) \ : "r" (modval) \ ); \ } else { \ uint##bs _oldval; \ uint##bs _clobberedval; \ __asm__ __volatile__( \ ".arch armv8.2-a \n\t"\ " ldr"#is" %"#rp"1, %3 \n\t"\ "1: mov %"#rp"0, %"#rp"1 \n\t"\ " "#op" %"#rp"2, %"#rp"0, %"#rp"4 \n\t"\ " cas"#is" %"#rp"1, %"#rp"2, %3 \n\t"\ " cmp %"#rp"0, %"#rp"1, uxt"#es" \n\t"\ " b.ne 1b \n\t"\ : "=&r" (_oldval), \ "=&r" (_clobberedval), \ "=&r" (_newval), \ "+Q" (*atm) \ : "r" (modval) \ : "cc" \ ); \ } \ } else { \ uint32 _failed; \ __asm__ __volatile__( \ "1: ldxr"#is" %"#rp"0, %2 \n\t"\ " "#op" %"#rp"0, %"#rp"0, %"#rp"3 \n\t"\ " stxr"#is" %w1 , %"#rp"0, %2 \n\t"\ " cbnz %w1 , 1b \n\t"\ : "=&r" (_newval), \ "=&r" (_failed), \ "+Q" (*atm) \ : "r" (modval) \ ); \ } \ _VMATOM_FENCE(fenced); \ }) /* Read (returned), op with modval, write. */ #define _VMATOM_SNIPPET_ROP(bs, is, rp, es, fenced, atm, op, modval) ({ \ uint##bs _newval; \ uint##bs _oldval; \ \ _VMATOM_FENCE(fenced); \ if (_VMATOM_PREFER_LSE(op)) { \ if (_VMATOM_LSE_HAVE(op)) { \ __asm__ __volatile__( \ ".arch armv8.2-a \n\t"\ "ld" #op #is" %"#rp"2, %"#rp"0, %1 \n\t"\ : "=r" (_oldval), \ "+Q" (*atm) \ : "r" (modval) \ ); \ } else { \ uint##bs _clobberedval; \ __asm__ __volatile__( \ ".arch armv8.2-a \n\t"\ " ldr"#is" %"#rp"1, %3 \n\t"\ "1: mov %"#rp"0, %"#rp"1 \n\t"\ " "#op" %"#rp"2, %"#rp"0, %"#rp"4 \n\t"\ " cas"#is" %"#rp"1, %"#rp"2, %3 \n\t"\ " cmp %"#rp"0, %"#rp"1, uxt"#es" \n\t"\ " b.ne 1b \n\t"\ : "=&r" (_oldval), \ "=&r" (_clobberedval), \ "=&r" (_newval), \ "+Q" (*atm) \ : "r" (modval) \ : "cc" \ ); \ } \ } else { \ uint32 _failed; \ __asm__ __volatile__( \ "1: ldxr"#is" %"#rp"0, %3 \n\t"\ " "#op" %"#rp"1, %"#rp"0, %"#rp"4 \n\t"\ " stxr"#is" %w2 , %"#rp"1, %3 \n\t"\ " cbnz %w2 , 1b \n\t"\ : "=&r" (_oldval), \ "=&r" (_newval), \ "=&r" (_failed), \ "+Q" (*atm) \ : "r" (modval) \ ); \ } \ _VMATOM_FENCE(fenced); \ \ _oldval; \ }) /* Read (returned), write. */ #define _VMATOM_SNIPPET_RW(bs, is, rp, es, fenced, atm, val) ({ \ uint##bs _oldval; \ \ _VMATOM_FENCE(fenced); \ if (Atomic_HaveLse()) { \ __asm__ __volatile__( \ ".arch armv8.2-a \n\t"\ "swp"#is" %"#rp"2, %"#rp"0, %1 \n\t"\ : "=r" (_oldval), \ "+Q" (*atm) \ : "r" (val) \ ); \ } else { \ uint32 _failed; \ __asm__ __volatile__( \ "1: ldxr"#is" %"#rp"0, %2 \n\t"\ " stxr"#is" %w1 , %"#rp"3, %2 \n\t"\ " cbnz %w1 , 1b \n\t"\ : "=&r" (_oldval), \ "=&r" (_failed), \ "+Q" (*atm) \ : "r" (val) \ ); \ } \ _VMATOM_FENCE(fenced); \ \ _oldval; \ }) /* Read (returned), if equal to old then write new. */ #define _VMATOM_SNIPPET_RIFEQW(bs, is, rp, es, fenced, atm, old, new) ({ \ uint##bs _oldval; \ \ _VMATOM_FENCE(fenced); \ if (Atomic_HaveLse()) { \ __asm__ __volatile__( \ ".arch armv8.2-a \n\t"\ "cas"#is" %"#rp"0, %"#rp"2, %1 \n\t"\ : "=r" (_oldval), \ "+Q" (*atm) \ : "r" (new), "0" (old) \ ); \ } else { \ uint32 _failed; \ __asm__ __volatile__( \ "1: ldxr"#is" %"#rp"0, %2 \n\t"\ " cmp %"#rp"0, %"#rp"3, uxt"#es" \n\t"\ " b.ne 2f \n\t"\ " stxr"#is" %w1 , %"#rp"4, %2 \n\t"\ " cbnz %w1 , 1b \n\t"\ "2: \n\t"\ : "=&r" (_oldval), \ "=&r" (_failed), \ "+Q" (*atm) \ : "r" (old), \ "r" (new) \ : "cc" \ ); \ } \ _VMATOM_FENCE(fenced); \ \ _oldval; \ }) open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vm_atomic_arm64_end.h000066400000000000000000000034311470176644300265010ustar00rootroot00000000000000/********************************************************* * Copyright (C) 2017,2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /* * vm_atomic_arm64_end.h -- * * Undefine private macros used to implement ARM64 atomic operations. */ #if !defined _VMATOM_X # error "vm_atomic_arm64_begin.h must be included before this file!" #endif /* Undefine all the private macros we previously defined. */ #undef _VMATOM_LSE_HAVE #undef _VMATOM_LSE_HAVE_add #undef _VMATOM_LSE_HAVE_sub #undef _VMATOM_LSE_HAVE_eor #undef _VMATOM_LSE_HAVE_orr #undef _VMATOM_LSE_HAVE_and #undef _VMATOM_SIZE_8 #undef _VMATOM_SIZE_16 #undef _VMATOM_SIZE_32 #undef _VMATOM_SIZE_64 #undef _VMATOM_X2 #undef _VMATOM_X #undef _VMATOM_SNIPPET_R_NF #undef _VMATOM_SNIPPET_R #undef _VMATOM_SNIPPET_R_SC #undef _VMATOM_SNIPPET_W_NF #undef _VMATOM_SNIPPET_W #undef _VMATOM_SNIPPET_W_SC #undef _VMATOM_FENCE #undef _VMATOM_SNIPPET_OP #undef _VMATOM_SNIPPET_ROP #undef _VMATOM_SNIPPET_RW #undef _VMATOM_SNIPPET_RIFEQW #undef _VMATOM_PREFER_LSE #undef _VMATOM_AT_HWCAP_LSE #undef _VMATOM_AT_HWCAP open-vm-tools-stable-12.5.0/open-vm-tools/lib/include/vm_basic_asm.h000066400000000000000000001026711470176644300253150ustar00rootroot00000000000000/********************************************************* * Copyright (c) 2003-2024 Broadcom. All rights reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ /********************************************************* * The contents of this file are subject to the terms of the Common * Development and Distribution License (the "License") version 1.0 * and no later version. You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://www.opensource.org/licenses/cddl1.php * * See the License for the specific language governing permissions * and limitations under the License. * *********************************************************/ /* * vm_basic_asm.h -- * * Basic asm macros. */ #ifndef _VM_BASIC_ASM_H_ #define _VM_BASIC_ASM_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #if defined _MSC_VER && !defined BORA_NO_WIN32_INTRINS #pragma warning(push) #pragma warning(disable : 4255) // disable no-prototype() to (void) warning #include #pragma warning(pop) #endif #include "vm_basic_types.h" #if defined VM_X86_64 #include "vm_basic_asm_x86_common.h" #include "vm_basic_asm_x86_64.h" #elif defined VM_X86_32 #include "vm_basic_asm_x86_common.h" #include "vm_basic_asm_x86.h" #elif defined VM_ARM_32 #include "vm_basic_asm_arm32.h" #define MUL64_NO_ASM 1 #include "mul64.h" #elif defined VM_ARM_64 #include "vm_basic_asm_arm64.h" #ifdef VMKERNEL #include "vmk_arm_mode.h" #endif #else #define MUL64_NO_ASM 1 #include "mul64.h" #endif #if defined _M_ARM64EC || defined _M_ARM64 #include "vm_assert.h" #define MUL64_NO_ASM 1 #include "mul64.h" #endif #if defined __cplusplus extern "C" { #endif /* * Locate most and least significant bit set functions. Use our own name * space to avoid namespace collisions. The new names follow a pattern, *