Commit 5a431163 authored by Julien Lepiller's avatar Julien Lepiller

torrent: Add file procedures.

* torrent/files.scm: New file.
* doc/guile-torrent.texi(Reading and Writing Downloaded Files): New chapter.
parent 5e4d6c22
......@@ -34,6 +34,7 @@ implementation of the bittorrent protocol.
* Managing .torrent files::
* Connecting to Trackers::
* Sending and Receiving Messages::
* Reading and Writing Downloaded Files::
@end menu
@node Encoding and decoding data
......@@ -520,4 +521,41 @@ this client. @var{infohash} is the infohash of the torrent that should be
recovered from that peer and @var{bitfield} is the bitfield representation of
the pieces we have and don't have yet.
@end deffn
@node Reading and Writing Downloaded Files
@chapter Reading and Writing Downloaded Files
The @code{(torrent files)} module is responsible for handling downloaded files.
It contains procedures to read, write and check pieces to one or more files.
@deffn {Scehem Procedure} check-piece @var{piece-data} @var{sha1}
Returns whether @var{piece-data} contains the data whose hash is @var{sha1}.
@end deffn
@deffn {Scheme Procedure} create-empty-file @var{filename} @var{size}
Creates @file{filename} and fill it with @var{size} null bytes.
@end deffn
@deffn {Scheme Procedure} get-block @var{file} @var{position} @var{size}
Read @var{size} bytes in @var{filename} from position @var{position} (in
bytes from the beginning of the file).
@end deffn
@deffn {Scheme Procedure} get-representation @var{piece-size} @var{pieces} @
@var{filename}
Returns a list of booleans representing the state of the file: @var{#t} for a
complete block, @code{#f} for a missing block.
@end deffn
@deffn {Scheme Procedure} get-representation-multiple @var{piece-size} @
@var{pieces} @var{files}
Returns a list of booleans representing the state of the files: @var{#t} for a
complete block, @code{#f} for a missing block.
@end deffn
@deffn {Scheme Procedure} put-block @var{filename} @var{block-data} @
@var{position}
Write @var{block-data}, a bytevector, into @var{filename} starting at position
@var{position} (in bytes from the beginning of the file).
@end deffn
@bye
;;;; Copyright (C) 2018 Julien Lepiller <julien@lepiller.eu>
;;;;
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; This library is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;;; Lesser General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;;;;
(define-module (torrent file)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
#:use-module (ice-9 match)
#:use-module (ice-9 rdelim)
#:use-module (ice-9 binary-ports)
#:use-module (rnrs base)
#:use-module (rnrs bytevectors)
#:use-module (torrent metainfo)
#:use-module (torrent protocol)
#:use-module (torrent utils sha-1)
#:export (check-piece
create-empty-file
get-block
get-representation
get-representation-multiple
put-block))
(define (create-empty-file filename size)
"Creates @file{filename} and fill it with @var{size} null bytes."
(if (file-exists? filename)
(throw 'file-exists)
(let ((file (open-file filename "wb")))
(put-bytevector file (make-bytevector size 0)))))
(define (put-block filename block-data position)
"Write @var{block-data}, a bytevector, into @var{filename} starting at position
@var{position} (in bytes from the beginning of the file)."
(let ((file (open-file filename "wb")))
(seek file position SEEK_SET)
(put-bytevector file block-data)))
(define (get-block file position size)
"Read @var{size} bytes in @var{filename} from position @var{position} (in
bytes from the beginning of the file)."
(seek file position SEEK_SET)
(get-bytevector-n file size))
(define (check-piece piece-data sha1)
"Checks that @var{piece-data} contains data whose hash is actually sha1."
(bytevector=? sha1 (sha-1->bytevector (sha-1 piece-data))))
(define (get-representation-aux piece-size pieces files)
(let loop ((pieces pieces) (file files) (bv (make-bytevector 0 0))
(head '()) (position 0))
(if (null? pieces)
head
(let* ((file (car files))
(len (- piece-size (bytevector-length bv)))
(bv2 (get-block file position len))
(bv3 (make-bytevector (+ (bytevector-length bv) (bytevector-length bv2)) 0)))
(format #t "~a~%" (length pieces))
(bytevector-copy! bv 0 bv3 0 (bytevector-length bv))
(bytevector-copy! bv2 0 bv3 (bytevector-length bv) (bytevector-length bv2))
(if (eq? (bytevector-length bv3) piece-size)
(loop
(cdr pieces)
files
(make-bytevector 0 0)
(append head (list (check-piece bv3 (car pieces))))
(+ position len))
(if (null? (cdr files))
(loop '() files bv3 head 0)
(loop
pieces
(cdr files)
bv
head
0)))))))
(define (get-representation piece-size pieces filename)
"Returns a list of booleans representing the state of the file: #t for a
complete block, #f for a missing block."
(get-representation-aux piece-size pieces (list (open-file filename "rb"))))
(define (get-representation-multiple piece-size pieces files)
"Returns a list of booleans representing the state of the files: #t for a
complete block, #f for a missing block."
(let ((files (map
(lambda (file)
(open-file (torrent-file-path file) "rb"))
files)))
(get-representation-aux piece-size pieces files)))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment