MOON
Server: Apache
System: Linux s5.yayogua.com.py 6.12.0-124.55.3.el10_1.x86_64 #1 SMP PREEMPT_DYNAMIC Thu May 7 16:54:02 EDT 2026 x86_64
User: w3com (1005)
PHP: 8.2.32
Disabled: NONE
Upload Files
File: /home/w3com/public_html/home/000~ROOT~000/bin/cloudinit_cc_write_files.rb
#!/usr/bin/env ruby

# -------------------------------------------------------------------------- #
# Copyright 2002-2024, OpenNebula Project, OpenNebula Systems                #
#                                                                            #
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
# not use this file except in compliance with the License. You may obtain    #
# a copy of the License at                                                   #
#                                                                            #
# http://www.apache.org/licenses/LICENSE-2.0                                 #
#                                                                            #
# Unless required by applicable law or agreed to in writing, software        #
# distributed under the License is distributed on an "AS IS" BASIS,          #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
# See the License for the specific language governing permissions and        #
# limitations under the License.                                             #
#--------------------------------------------------------------------------- #

require 'etc'
require 'base64'
require 'zlib'
require 'fileutils'
require 'stringio'
require 'open-uri'

module CloudInit

    DEFAULT_PERMS = '0644'
    DEFAULT_GROUP = `id -gn root`.strip
    DEFAULT_OWNER = "root:#{DEFAULT_GROUP}"
    TEXT_PLAIN_ENC = 'text/plain'
    DEFAULT_DEFER = false
    DEFAULT_APPEND = false

    ##
    # WriteFile class implements the write_file cloud-config directive.
    ##
    class WriteFile

        attr_accessor :path, :content, :source, :owner, :permissions, :encoding, :append, :defer

        def initialize(path:, content: '', source: [], owner: DEFAULT_OWNER,
                       permissions: DEFAULT_PERMS, encoding: TEXT_PLAIN_ENC,
                       append: DEFAULT_APPEND, defer: DEFAULT_DEFER)
            @path = path
            @content = content
            @source = source
            @owner = owner
            @permissions = permissions
            @encoding = encoding
            @append = append
            @defer = defer
        end

        def exec
            begin
                CloudInit::Logger.info(
                    "[writeFile] writing file [#{@permissions} #{@owner} #{@path}]"
                )

                uid, gid = uid_and_guid_by_owner
                FileUtils.mkdir_p(File.dirname(@path))
                File.open(File.absolute_path(@path), @append ? 'ab' : 'wb') do |file|
                    file.write(read_url_or_decode)
                    file.chmod(decode_perms)
                    file.chown(uid, gid)
                end
            rescue Errno::EACCES
                CloudInit::Logger.error(
                    "[writeFile] Insufficient permissions [#{@permissions} #{@owner} #{@path}]"
                )
            rescue Errno::ENOENT
                CloudInit::Logger.error(
                    "[writeFile] Parent directory missing [#{@permissions} #{@owner} #{@path}]"
                )
            rescue StandardError => e
                CloudInit::Logger.error(
                    "[writeFile] Unexpected error: #{e.message}\n#{e.backtrace.join("\n")}"
                )
            end
        end

        def self.from_map(data_map)
            unless data_map.is_a?(Hash)
                raise 'WriteFile.from_map must be called with a Hash as an argument'
            end

            WriteFile.new(**data_map)
        end

        def read_url_or_decode
            url = @source.is_a?(Hash) ? @source[:uri] : nil
            use_url = !url.nil?

            return '' if @content.nil? && !use_url

            result = nil
            if use_url
                begin
                    headers = @source[:headers]&.transform_keys(&:to_s) || {}
                    result = URI.parse(url).open(headers).read
                rescue StandardError => e
                    CloudInit::Logger.error(
                        "Failed to retrieve contents from source '#{url}'; \n
                         falling back to content: #{e.message}"
                    )
                    use_url = false
                end
            end

            if @content && !use_url
                extractions = canonicalize_extraction
                result = extract_contents(extractions)
            end

            result
        end

        def decode_perms
            if @permissions.is_a?(String) && @permissions.match?(/\A0[0-7]{1,3}\z/)
                @permissions.to_i(8)
            else
                CloudInit::Logger.warn(
                    'Undecodable permissions, returning default'
                )
                DEFAULT_PERMS.to_i(8)
            end
        end

        def uid_and_guid_by_owner
            user, group = @owner.split(':')

            begin
                return Etc.getpwnam(user).uid, Etc.getgrnam(group).gid
            rescue ArgumentError
                CloudInit::Logger.error(
                    "[writeFile] Owner does not exist [#{@permissions} #{@owner} #{@path}]"
                )
                user, group = DEFAULT_OWNER.split(':')
                return Etc.getpwnam(user).uid, Etc.getgrnam(group).gid
            end
        end

        def canonicalize_extraction
            encoding_type = @encoding.downcase.strip

            case encoding_type
            when 'gz', 'gzip'
                ['application/x-gzip']
            when 'gz+base64', 'gzip+base64', 'gz+b64', 'gzip+b64'
                ['application/base64', 'application/x-gzip']
            when 'b64', 'base64'
                ['application/base64']
            when TEXT_PLAIN_ENC
                [TEXT_PLAIN_ENC]
            else
                CloudInit::Logger.warn(
                    "Unknown encoding type #{encoding_type}, assuming #{TEXT_PLAIN_ENC}"
                )
                [TEXT_PLAIN_ENC]
            end
        end

        def extract_contents(extraction_types)
            result = @content
            extraction_types.each do |t|
                case t
                when 'application/x-gzip'
                    result = Zlib::GzipReader.new(StringIO.new(result)).read
                when 'application/base64'
                    result = Base64.decode64(result)
                when TEXT_PLAIN_ENC
                    # No transformation needed
                end
            end
            result
        end

    end

end