Example #1
0
// ScanFile scans a single file for viruses using the ClamAV databases. It returns the virus name
// (if found), the number of bytes read from the file, in CountPrecision units, and a status code.
// If the file is clean the error code will be Success (Clean) and virus name will be empty. If a
// virus is found the error code will be the corresponding string for Virus (currently "Virus(es)
// detected").
func (e *Engine) ScanFile(path string, opts uint) (string, uint, error) {
	var name *C.char
	var scanned C.ulong
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	err := ErrorCode(C.cl_scanfile(cpath, &name, &scanned, (*C.struct_cl_engine)(e), C.uint(opts)))
	if err == Success {
		return "", 0, nil
	}
	if err == Virus {
		if opts&ScanAllmatches > 0 {
			return C.GoString(C.fixup_clam_virus(&name)), uint(scanned), fmt.Errorf(StrError(err))
		} else {
			return C.GoString(name), uint(scanned), fmt.Errorf(StrError(err))
		}
	}
	return "", 0, fmt.Errorf(StrError(err))
}
Example #2
0
// ScanFileCb scans a single file for viruses using the ClamAV databases and using callbacks from
// ClamAV to read/resolve file data. The callbacks can be used to scan files in memory, to scan multiple
// files inside archives, etc. The function returns the virus name
// (if found), the number of bytes read from the file in CountPrecision units, and a status code.
// If the file is clean the error code will be Success (Clean) and virus name will be empty. If a
// virus is found the error code will be the corresponding string for Virus (currently "Virus(es)
// detected").
// The context argument will be sent back to the callbacks, so effort must be made to retain it
// throughout the execution of the scan from garbage collection
func (e *Engine) ScanFileCb(path string, opts uint, context interface{}) (string, uint, error) {
	var name *C.char
	var scanned C.ulong
	// pass a C-allocated pointer to the path to avoid crashing with garbage collector
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))

	// find where to store the context in our callback map. we do _not_ pass the context to
	// C directly because aggressive garbage collection will move it around
	callbacks.Lock()
	// find the next available empty spot. uintptr overflow should be ok -- we don't expect
	// to have Max(uintptr) files scanned at the same time
	for _, ok := callbacks.cb[callbacks.nextId]; ok; callbacks.nextId++ {
	}
	cbidx := callbacks.nextId
	callbacks.cb[cbidx] = context
	callbacks.nextId++
	callbacks.Unlock()

	// cleanup
	defer func() {
		callbacks.Lock()
		delete(callbacks.cb, cbidx)
		callbacks.Unlock()
	}()

	err := ErrorCode(C.cl_scanfile_callback(cpath, &name, &scanned, (*C.struct_cl_engine)(e), C.uint(opts), unsafe.Pointer(cbidx)))
	if err == Success {
		return "", 0, nil
	}
	if err == Virus {
		if opts&ScanAllmatches > 0 {
			return C.GoString(C.fixup_clam_virus(&name)), uint(scanned), fmt.Errorf(StrError(err))
		} else {
			return C.GoString(name), uint(scanned), fmt.Errorf(StrError(err))
		}
	}
	return "", 0, fmt.Errorf(StrError(err))
}