module VirtualBox # Represents a shared folder in VirtualBox. In VirtualBox, shared folders are a # method for basically "symlinking" a folder on the guest system to a folder which # exists on the host system. This allows for sharing of files across the virtual # machine. # # **Note:** Whenever modifying shared folders on a VM, the changes won't take # effect until a _cold reboot_ occurs. This means actually closing the virtual # machine _completely_, then restarting it. You can't just hit "Start > Restart" # or do a `sudo reboot`. It doesn't work that way! # # # Getting Shared Folders # # All shared folders are attached to a {VM} object, by definition. Therefore, to # get a list of the shared folders, first {VM.find find} the VM you need, then # use the `shared_folders` relationship to access an array of the shared folders. # With this array, you can create, modify, update, and delete the shared folders # for that virtual machine. # # # Creating a Shared Folder # # **This whole section will assume you already looked up a {VM} and assigned it to # a local variable named `vm`.** # # With a VM found, creating a shared folder is just a few lines of code: # # folder = VirtualBox::SharedFolder.new # folder.name = "desktop-images" # folder.hostpath = File.expand_path("~/Desktop/images") # vm.shared_folders << folder # folder.save # Or you can call vm.save, which works too! # # # Modifying an Existing Shared Folder # # **This whole section will assume you already looked up a {VM} and assigned it to # a local variable named `vm`.** # # Nothing tricky here: You treat existing shared folder objects just as if they # were new ones. Assign a new name and/or a new path, then save. # # folder = vm.shared_folders.first # folder.name = "rufus" # folder.save # Or vm.save # # **Note**: The VirtualBox-saavy will know that VirtualBox doesn't actually # expose a way to edit shared folders. Under the hood, the virtualbox ruby # library is actually deleting the old shared folder, then creating a new # one with the new details. This shouldn't affect the way anything works for # the VM itself. # # # Deleting a Shared Folder # # **This whole section will assume you already looked up a {VM} and assigned it to # a local variable named `vm`.** # # folder = vm.shared_folder.first # folder.destroy # # Poof! It'll be gone. This is usually the place where I warn you about this # being non-reversable, but since no _data_ was actually destroyed, this is # not too risky. You could always just recreate the shared folder with the # same name and path and it'll be like nothing happened. # # # Attributes and Relationships # # Properties of the model are exposed using standard ruby instance # methods which are generated on the fly. Because of this, they are not listed # below as available instance methods. # # These attributes can be accessed and modified via standard ruby-style # `instance.attribute` and `instance.attribute=` methods. The attributes are # listed below. # # Relationships are also accessed like attributes but can't be set. Instead, # they are typically references to other objects such as an {AttachedDevice} which # in turn have their own attributes which can be modified. # # ## Attributes # # This is copied directly from the class header, but lists all available # attributes. If you don't understand what this means, read {Attributable}. # # attribute :parent, :readonly => :readonly # attribute :name # attribute :hostpath # class SharedFolder < AbstractModel attribute :parent, :readonly => true, :property => false attribute :parent_collection, :readonly => true, :property => false attribute :name attribute :host_path attribute :writable, :default => true, :boolean => true attribute :accessible, :readonly => true, :boolean => true class << self # Populates the shared folder relationship for anything which is related to it. # # **This method typically won't be used except internally.** # # @return [Array] def populate_relationship(caller, imachine) relation = Proxies::Collection.new(caller) imachine.shared_folders.each do |ishared| relation << new(ishared) end relation end # Saves the relationship. This simply calls {#save} on every # member of the relationship. # # **This method typically won't be used except internally.** def save_relationship(caller, items) items.dup.each do |item| item.save end end end # @overload initialize(data={}) # Creates a new SharedFolder which is a new record. This # should be attached to a VM and saved. # @param [Hash] data (optional) A hash which contains initial attribute # values for the SharedFolder. # @overload initialize(interface) # Creates an SharedFolder for a relationship. **This should # never be called except internally.** # @param [Object] caller The parent # @param [Hash] data A hash of data which must be used # to extract the relationship data. def initialize(data=nil) super() if data initialize_attributes(data) end end # Initializes the attributes of an existing shared folder. def initialize_attributes(ishared) # Load the interface attributes load_interface_attributes(ishared) # Clear dirtiness, since this should only be called initially and # therefore shouldn't affect dirtiness clear_dirty! # But this is an existing record existing_record! end # Validates a shared folder. def validate super validates_presence_of :parent validates_presence_of :name validates_presence_of :host_path end # Saves or creates a shared folder. def save return true if !new_record? && !changed? raise Exceptions::ValidationFailedException.new(errors) if !valid? if !new_record? # If its not a new record, any changes will require a new shared # folder to be created, so we first destroy it then recreate it. destroy(false) end create end # Creates a new shared folder. This method should not be called directly. # Instead, {save} should always be called, which will do the right thing. def create return unless new_record? parent_machine.with_open_session do |session| machine = session.machine machine.create_shared_folder(name, host_path, writable) end existing_record! clear_dirty! end # Relationship callback when added to a collection. This is automatically # called by any relationship collection when this object is added. def added_to_relationship(proxy) was_clean = parent.nil? && !changed? write_attribute(:parent, proxy.parent) write_attribute(:parent_collection, proxy) # This keeps existing records not dirty when added to collection clear_dirty! if !new_record? && was_clean end # Destroys the shared folder. This doesn't actually delete the folder # from the host system. Instead, it simply removes the mapping to the # virtual machine, meaning it will no longer be possible to mount it # from within the virtual machine. def destroy(update_collection=true) parent.with_open_session do |session| machine = session.machine machine.remove_shared_folder(name) end # Remove it from it's parent collection parent_collection.delete(self, true) if parent_collection && update_collection # Mark as a new record so if it is saved again, it will create it new_record! end end end