[functional tests] first steps in parsing the binary format.
This commit is contained in:
		
							
								
								
									
										151
									
								
								functional-tests/check-superblock.scm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								functional-tests/check-superblock.scm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| (import | ||||
|   (fmt fmt) | ||||
|   (matchable)) | ||||
|  | ||||
| ;;;;--------------------------------------------------- | ||||
| ;;;; Constants | ||||
| ;;;;--------------------------------------------------- | ||||
|  | ||||
| ;; FIXME: duplicate with main.scm | ||||
| (define (current-metadata) | ||||
|   "./metadata.bin") | ||||
|  | ||||
| (define metadata-block-size 4096) | ||||
| (define superblock-magic 27022010) | ||||
| (define superblock-salt 160774) | ||||
| (define uuid-size 16) | ||||
| (define space-map-root-size 128) | ||||
|  | ||||
| ;;;;--------------------------------------------------- | ||||
| ;;;; Metadata IO | ||||
| ;;;;--------------------------------------------------- | ||||
|  | ||||
| (define (open-metadata path) | ||||
|   (open-file-input-port path (file-options) (buffer-mode none))) | ||||
|  | ||||
| (define-syntax with-metadata | ||||
|   (syntax-rules () | ||||
|     ((_ (port path) body ...) (let ((port (open-metadata path))) | ||||
|                                 (dynamic-wind | ||||
|                                   (lambda () #f) | ||||
|                                   (lambda () body ...) | ||||
|                                   (lambda () (close-port port))))))) | ||||
|  | ||||
| ;; FIXME: return our own condition? | ||||
| (define (io-error msg) | ||||
|   (raise (condition | ||||
|            (make-error) | ||||
|            (make-message-condition msg)))) | ||||
|  | ||||
| ;;; Returns a 4k bytevector | ||||
| (define (read-block port b) | ||||
|   (set-port-position! port (* b metadata-block-size)) | ||||
|   (let ((data (get-bytevector-n port metadata-block-size))) | ||||
|    (unless (and (not (eof-object? data)) | ||||
|                 (= metadata-block-size (bytevector-length data))) | ||||
|      (io-error (fmt #f (dsp "unable to read metadata block: ") (num b)))) | ||||
|    data)) | ||||
|  | ||||
| ;;;;--------------------------------------------------- | ||||
| ;;;; CRC32 | ||||
| ;;;;--------------------------------------------------- | ||||
|  | ||||
| ;; FIXME: move to own library | ||||
| (load-shared-object "libz.so") | ||||
| (define crc32 | ||||
|   (foreign-procedure "crc32" (unsigned-long u8* unsigned-int) unsigned-long)) | ||||
|  | ||||
| (define crc32-combine | ||||
|   (foreign-procedure "crc32_combine" (unsigned-long unsigned-long unsigned-long) unsigned-long)) | ||||
|  | ||||
| ;; FIXME: stop copying the bytevector.  I'm not sure how to pass an offset into | ||||
| ;; the bv. | ||||
| (define (crc32-region salt bv start end) | ||||
|   (assert (< start end)) | ||||
|   (let ((len (- end start))) | ||||
|    (let ((copy (make-bytevector len))) | ||||
|     (bytevector-copy! bv start copy 0 len) | ||||
|     (let ((crc (crc32 salt copy 0))) | ||||
|      (crc32 crc copy len))))) | ||||
|  | ||||
| ;;;;--------------------------------------------------- | ||||
| ;;;; Decoding | ||||
| ;;;;--------------------------------------------------- | ||||
|  | ||||
| (define-syntax unpack-type | ||||
|   (syntax-rules (le32 le64 bytes) | ||||
|     ((_ bv offset le32) | ||||
|      (bytevector-u32-ref bv offset (endianness little))) | ||||
|  | ||||
|     ((_ bv offset le64) | ||||
|      (bytevector-u64-ref bv offset (endianness little))) | ||||
|  | ||||
|     ((_ bv offset (bytes count)) | ||||
|      (let ((copy (make-bytevector count))) | ||||
|       (bytevector-copy! bv offset copy 0 count) | ||||
|       copy)))) | ||||
|  | ||||
| (define (size-type t) | ||||
|   (syntax->datum | ||||
|     (syntax-case t (le32 le64 bytes) | ||||
|                  (le32 #'4) | ||||
|                  (le64 #'8) | ||||
|                  ((bytes count) #'count)))) | ||||
|  | ||||
| (define-syntax binary-format | ||||
|   (lambda (x) | ||||
|     (syntax-case x () | ||||
|                  ((_ (name pack-name unpack-name) (field type) ...) | ||||
|                   (with-syntax ((((t o) ...) | ||||
|                                  (let f ((acc 0) (types #'(type ...))) | ||||
|                                   (if (null? types) | ||||
|                                       '() | ||||
|                                       (cons (list (car types) acc) | ||||
|                                             (f (+ acc (size-type (car types))) (cdr types))))))) | ||||
|                                #'(begin | ||||
|                                    (define-record-type name (fields field ...)) | ||||
|  | ||||
|                                    (define (unpack-name bv offset) | ||||
|                                      ((record-constructor (record-type-descriptor name)) | ||||
|                                       (unpack-type bv (+ offset o) t) ...)))))))) | ||||
|  | ||||
| (binary-format (superblock pack-superblock unpack-superblock) | ||||
|   (csum le32) | ||||
|   (flags le32) | ||||
|   (block-nr le64) | ||||
|   (uuid (bytes 16)) | ||||
|   (magic le64) | ||||
|   (version le32) | ||||
|   (time le32) | ||||
|   (trans-id le64) | ||||
|   (metadata-snap le64) | ||||
|   (data-space-map-root (bytes 128)) | ||||
|   (metadata-space-map-root (bytes 128)) | ||||
|   (data-mapping-root le64) | ||||
|   (device-details-root le64) | ||||
|   (data-block-size le32) | ||||
|   (metadata-block-size le32) | ||||
|   (metadata-nr-blocks le64) | ||||
|   (compat-flags le32) | ||||
|   (compat-ro-flags le32) | ||||
|   (incompat-flags le32)) | ||||
|  | ||||
| ;;;;--------------------------------------------------- | ||||
| ;;;; Top level | ||||
| ;;;;--------------------------------------------------- | ||||
|  | ||||
| (define (check-magic sb) | ||||
|   ((let ((m (bytevector-u32-ref sb 32 (endianness little)))) | ||||
|     (fmt #t (dsp "on disk magic: ") (num m) nl) | ||||
|     ))) | ||||
|  | ||||
| (define (read-superblock) | ||||
|   (with-metadata (md (current-metadata)) | ||||
|                  (unpack-superblock (read-block md 0) 0))) | ||||
|  | ||||
| (define (check-superblock) | ||||
|   (with-metadata (md (current-metadata)) | ||||
|                  (let ((superblock (read-block md 0))) | ||||
|                   (fmt #t (dsp "checksum on disk: ") (dsp (bytevector-u32-ref superblock 0 (endianness little))) nl) | ||||
|                   (fmt #t (dsp "calculated checksum: ") (dsp (crc32-region superblock-salt superblock 4 4092)) nl) | ||||
|                   (check-magic superblock)))) | ||||
		Reference in New Issue
	
	Block a user