@@ -18,7 +18,17 @@ module PlaceOS::Core
1818 def compiled ?(file_name : String , commit : String , branch : String , uri : String ) : Bool
1919 Log .debug { {message: " Checking whether driver is compiled or not?" , driver: file_name, commit: commit, branch: branch, repo: uri} }
2020 path = Path [binary_path, executable_name(file_name, commit)]
21- return true if File .exists?(path)
21+
22+ if File .exists?(path)
23+ # Validate that the local file is a valid executable by running it with -h
24+ if validate_binary(path)
25+ return true
26+ else
27+ Log .warn { {message: " Local binary exists but is corrupted, removing and re-downloading" , driver_file: file_name, path: path.to_s} }
28+ File .delete(path) rescue nil
29+ end
30+ end
31+
2232 resp = BuildApi .compiled?(file_name, commit, branch, uri)
2333 return false unless resp.success?
2434 ret = fetch_binary(LinkData .from_json(resp.body)) rescue nil
@@ -90,6 +100,16 @@ module PlaceOS::Core
90100 {driver_source, commit, Core ::ARCH }.join(" _" ).downcase
91101 end
92102
103+ private def validate_binary (path : Path ) : Bool
104+ # Try to execute the binary with -h flag to validate it's a working executable
105+ result = Process .run(path.to_s, [" -h" ], output: Process ::Redirect ::Close , error: Process ::Redirect ::Close )
106+ # If the process runs without crashing, consider it valid
107+ result.exit_code == 0
108+ rescue ex : Exception
109+ Log .error(exception: ex) { {message: " Driver binary validation failed" , path: path.to_s} }
110+ false
111+ end
112+
93113 def reload_driver (driver_id : String )
94114 if driver = Model ::Driver .find?(driver_id)
95115 repo = driver.repository!
@@ -120,16 +140,27 @@ module PlaceOS::Core
120140 ConnectProxy ::HTTPClient .new(url.host.not_nil!, 9000 ).get(uri.to_s)
121141 end
122142 if resp.success?
123- unless link.size == resp.headers.fetch(" Content-Length" , " 0" ).to_i
124- Log .error { {message: " Expected content length #{ link.size } , but received #{ resp.headers.fetch(" Content-Length" , " 0" ) } " , driver_file: driver_file} }
143+ # Check Content-Length header first if available
144+ content_length = resp.headers.fetch(" Content-Length" , " 0" ).to_i64
145+ if content_length > 0 && link.size != content_length
146+ Log .error { {message: " Expected content length #{ link.size } , but received #{ content_length } " , driver_file: driver_file} }
125147 raise Error .new(" Response size doesn't match with build service returned result" )
126148 end
127149
128150 body_io = IO ::Digest .new(resp.body_io? || IO ::Memory .new(resp.body), Digest ::MD5 .new)
151+ bytes_written = 0 _i64
129152 File .open(filename, " wb+" ) do |f |
130- IO .copy(body_io, f)
153+ bytes_written = IO .copy(body_io, f)
131154 f.chmod(0o755 )
132155 end
156+
157+ # Verify actual downloaded size matches expected size
158+ unless link.size == bytes_written
159+ Log .error { {message: " Expected download size #{ link.size } , but actually downloaded #{ bytes_written } bytes" , driver_file: driver_file} }
160+ File .delete(filename) if File .exists?(filename)
161+ raise Error .new(" Downloaded size doesn't match expected size from build service" )
162+ end
163+
133164 filename.to_s
134165 else
135166 raise Error .new(" Unable to fetch driver. Error : #{ resp.body } " )
0 commit comments