1 /* ncdc - NCurses Direct Connect client
2 
3   Copyright (c) 2011-2019 Yoran Heling
4 
5   Permission is hereby granted, free of charge, to any person obtaining
6   a copy of this software and associated documentation files (the
7   "Software"), to deal in the Software without restriction, including
8   without limitation the rights to use, copy, modify, merge, publish,
9   distribute, sublicense, and/or sell copies of the Software, and to
10   permit persons to whom the Software is furnished to do so, subject to
11   the following conditions:
12 
13   The above copyright notice and this permission notice shall be included
14   in all copies or substantial portions of the Software.
15 
16   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 
24 */
25 
26 
27 #include "ncdc.h"
28 #include "dlfile.h"
29 
30 
31 /* Terminology
32  *
33  *   chunk: Smallest "addressable" byte range within a file, see DLFILE_CHUNKSIZE
34  *   block: Smallest "verifiable" byte range within a file (i.e. what a TTH
35  *          leaf represents, see DL_MINBLOCKSIZE). Always a multiple of the
36  *          chunk size.
37  *  thread: A range of chunks that haven't been downloaded yet.
38  * segment: A range of chunks that is requested for downloading in a single
39  *          CGET/$ADCGET. Not necessarily aligned to or a multiple of the block
40  *          size. Segments are allocated at the start of a thread.
41  */
42 
43 
44 #if INTERFACE
45 
46 /* Size of a chunk within the downloaded file. This determines the granularity
47  * of the file data that is remembered across restarts, the size of the chunk
48  * bitmap and the minimum download request.
49  * Must be a power of two and less than or equal to DL_MINBLOCKSIZE */
50 #define DLFILE_CHUNKSIZE (128*1024)
51 
52 
53 /* For file lists (dl->islist), only len and chunk are used. The other fields
54  * aren't used because no length of TTH info is known before downloading. */
55 struct dlfile_thread_t {
56   dl_t *dl;
57   tth_ctx_t hash_tth;
58   guint32 allocated; /* Number of remaining chunks allocated to this thread (including current) */
59   guint32 avail;     /* Number of undownloaded chunks in and after this thread (including current & allocated) */
60   guint32 chunk;     /* Current chunk number */
61   guint32 len;       /* Number of bytes downloaded into this chunk */
62   gboolean busy;     /* Whether this thread is being used */
63   /* Fields for deferred error reporting */
64   guint64 uid;
65   char *err_msg, *uerr_msg;
66   char err, uerr;
67 };
68 
69 #endif
70 
71 
dlfile_chunks(guint64 size)72 static guint32 dlfile_chunks(guint64 size) {
73   return (size+DLFILE_CHUNKSIZE-1)/DLFILE_CHUNKSIZE;
74 }
75 
76 
dlfile_hasfreeblock(dlfile_thread_t * t)77 static gboolean dlfile_hasfreeblock(dlfile_thread_t *t) {
78   guint32 chunksinblock = t->dl->hash_block / DLFILE_CHUNKSIZE;
79   return t->avail - t->allocated > chunksinblock
80     || (t->chunk + t->avail == dlfile_chunks(t->dl->size) && t->chunk + t->allocated <= (((dlfile_chunks(t->dl->size)-1)/chunksinblock)*chunksinblock));
81 }
82 
83 
84 /* Highly verbose debugging function. Prints out a list of threads for a particular dl item. */
dlfile_threaddump(dl_t * dl,int n)85 static void dlfile_threaddump(dl_t *dl, int n) {
86 #if 0
87   GSList *l;
88   for(l=dl->threads; l; l=l->next) {
89     dlfile_thread_t *ti = l->data;
90     g_debug("THREAD DUMP#%p.%d: busy = %d, chunk = %u, allocated = %u, avail = %u", dl, n, ti->busy, ti->chunk, ti->allocated, ti->avail);
91   }
92 #endif
93 }
94 
95 
dlfile_fatal_load_error(dl_t * dl,const char * op,const char * err)96 static void dlfile_fatal_load_error(dl_t *dl, const char *op, const char *err) {
97   g_error("Unable to %s incoming file `%s', (%s; incoming file for `%s').\n"
98     "Delete the incoming file or otherwise repair it before restarting ncdc.",
99     op, dl->inc, err ? err : g_strerror(errno), dl->dest);
100 }
101 
102 
103 /* Must be called while the lock is held when dl->active_threads may be >0 */
dlfile_save_bitmap(dl_t * dl,int fd)104 static gboolean dlfile_save_bitmap(dl_t *dl, int fd) {
105   guint8 *buf = dl->bitmap;
106   off_t off = dl->size;
107   size_t left = bita_size(dlfile_chunks(dl->size));
108   while(left > 0) {
109     int r = pwrite(fd, buf, left, off);
110     if(r < 0)
111       return FALSE;
112     left -= r;
113     off += r;
114     buf += r;
115   }
116   return TRUE;
117 }
118 
119 
dlfile_save_bitmap_timeout(gpointer dat)120 static gboolean dlfile_save_bitmap_timeout(gpointer dat) {
121   dl_t *dl = dat;
122   g_static_mutex_lock(&dl->lock);
123   dl->bitmap_src = 0;
124   if(dl->incfd > 0 && !dlfile_save_bitmap(dl, dl->incfd)) {
125     g_warning("Error writing bitmap for `%s': %s.", dl->dest, g_strerror(errno));
126     dl_queue_seterr(dl, DLE_IO_INC, g_strerror(errno));
127   }
128   if(dl->incfd > 0 && !dl->active_threads) {
129     close(dl->incfd);
130     dl->incfd = 0;
131   }
132   g_static_mutex_unlock(&dl->lock);
133   return FALSE;
134 }
135 
136 
137 /* Must be called while dl->lock is held. */
dlfile_save_bitmap_defer(dl_t * dl)138 static void dlfile_save_bitmap_defer(dl_t *dl) {
139   if(!dl->bitmap_src)
140     dl->bitmap_src = g_timeout_add_seconds(5, dlfile_save_bitmap_timeout, dl);
141 }
142 
143 
dlfile_load_canconvert(dl_t * dl)144 static void dlfile_load_canconvert(dl_t *dl) {
145   static gboolean canconvert = FALSE;
146   if(canconvert)
147     return;
148   printf(
149     "I found a partially downloaded file without a bitmap. This probably\n"
150     "means that you are upgrading from ncdc 1.17 or earlier, which did not\n"
151     "yet support segmented downloading.\n\n"
152     "To convert your partially downloaded files to the new format and to\n"
153     "continue with starting up ncdc, press enter. To abort, hit Ctrl+C.\n\n"
154     "Note: After this conversion, you should NOT downgrade ncdc. If you\n"
155     " wish to do that, backup or delete your inc/ directory first.\n\n"
156     "Note#2: If you get this message when you haven't upgraded ncdc, then\n"
157     " your partially downloaded file is likely corrupt, and continuing\n"
158     " this conversion will not help. In that case, the best you can do is\n"
159     " delete the corrupted file and restart ncdc.\n\n"
160     "The file that triggered this warning is:\n"
161     "  %s\n"
162     "Which is the incoming file for:\n"
163     "  %s\n"
164     "(But there are possibly more affected files)\n",
165     dl->inc, dl->dest);
166   getchar();
167   canconvert = TRUE;
168 }
169 
170 
dlfile_load_nonbitmap(dl_t * dl,int fd,guint8 * bitmap)171 static void dlfile_load_nonbitmap(dl_t *dl, int fd, guint8 *bitmap) {
172   struct stat st;
173   if(fstat(fd, &st) < 0)
174     dlfile_fatal_load_error(dl, "stat", NULL);
175   if((guint64)st.st_size >= dl->size)
176     dlfile_fatal_load_error(dl, "load", "File too large");
177 
178   dlfile_load_canconvert(dl);
179 
180   guint64 left = st.st_size;
181   guint32 chunk = 0;
182   while(left > DLFILE_CHUNKSIZE) {
183     bita_set(bitmap, chunk);
184     chunk++;
185     left -= DLFILE_CHUNKSIZE;
186   }
187 }
188 
189 
dlfile_load_bitmap(dl_t * dl,int fd)190 static gboolean dlfile_load_bitmap(dl_t *dl, int fd) {
191   gboolean needsave = FALSE;
192   guint32 chunks = dlfile_chunks(dl->size);
193   guint8 *bitmap = bita_new(chunks);
194   guint8 *dest = bitmap;
195 
196   off_t off = dl->size;
197   size_t left = bita_size(chunks);
198   while(left > 0) {
199     int r = pread(fd, dest, left, off);
200     if(r < 0)
201       dlfile_fatal_load_error(dl, "read bitmap from", NULL);
202     if(!r) {
203       dlfile_load_nonbitmap(dl, fd, bitmap);
204       needsave = TRUE;
205       break;
206     }
207     left -= r;
208     off += r;
209     dest += r;
210   }
211 
212   bita_free(dl->bitmap);
213   dl->bitmap = bitmap;
214   return needsave;
215 }
216 
217 
dlfile_load_block(dl_t * dl,int fd,guint32 chunk,guint32 chunksinblock,guint32 * reset)218 static dlfile_thread_t *dlfile_load_block(dl_t *dl, int fd, guint32 chunk, guint32 chunksinblock, guint32 *reset) {
219   dlfile_thread_t *t = g_slice_new0(dlfile_thread_t);
220   t->dl = dl;
221   t->chunk = chunk;
222   t->avail = chunksinblock;
223   tth_init(&t->hash_tth);
224 
225   char *bufp = malloc(DLFILE_CHUNKSIZE);
226 
227   *reset = chunksinblock;
228   while(bita_get(dl->bitmap, t->chunk)) {
229     char *buf = bufp;
230     off_t off = (guint64)t->chunk * DLFILE_CHUNKSIZE;
231     size_t left = DLFILE_CHUNKSIZE;
232     while(left > 0) {
233       int r = pread(fd, buf, left, off);
234       if(r <= 0)
235         dlfile_fatal_load_error(dl, "read from", NULL);
236       off -= r;
237       left -= r;
238       buf += r;
239     }
240     tth_update(&t->hash_tth, bufp, DLFILE_CHUNKSIZE);
241     t->chunk++;
242     t->avail--;
243     dl->have += DLFILE_CHUNKSIZE;
244     (*reset)--;
245   }
246 
247   free(bufp);
248   dl->threads = g_slist_prepend(dl->threads, t);
249   return t;
250 }
251 
252 
253 /* Go over the bitmap and create a thread for each range of undownloaded
254  * chunks. Threads are created in a TTHL-block-aligned fashion to ensure that
255  * the downloading progress can continue from the threads while keeping the
256  * integrity checks. */
dlfile_load_threads(dl_t * dl,int fd)257 static gboolean dlfile_load_threads(dl_t *dl, int fd) {
258   guint32 chunknum = dlfile_chunks(dl->size);
259   guint32 chunksperblock = dl->hash_block / DLFILE_CHUNKSIZE;
260   gboolean needsave = FALSE;
261   dlfile_thread_t *t = NULL;
262 
263   guint32 i,j;
264   for(i=0; i<chunknum; i+=chunksperblock) {
265     guint32 reset = 0;
266     guint32 chunksinblock = MIN(chunksperblock, dlfile_chunks(dl->size) - i);
267 
268     for(j=i; j<i+chunksinblock; j++)
269       if(!bita_get(dl->bitmap, j))
270         break;
271     gboolean hasfullblock = j == i+chunksinblock;
272 
273     if(t && !bita_get(dl->bitmap, i)) {
274       t->avail += chunksinblock;
275       reset = chunksinblock;
276     } else if(hasfullblock) {
277       t = NULL;
278       dl->have += dl->hash_block;
279     } else
280       t = dlfile_load_block(dl, fd, i, chunksinblock, &reset);
281 
282     for(j=i+(chunksinblock-reset); j<i+chunksinblock; j++)
283       if(bita_get(dl->bitmap, j)) {
284         bita_reset(dl->bitmap, j);
285         needsave = TRUE;
286       }
287   }
288   return needsave;
289 }
290 
291 
dlfile_load(dl_t * dl)292 void dlfile_load(dl_t *dl) {
293   /* If moving to the destination failed in a previous run, assume that the
294    * incoming file is complete and all that's left to do is resume the
295    * finalization (which the user has to initiate by clearing the error). This
296    * needs to be handled as a special case because the incoming file will not
297    * contain the bitmap anymore at this point, and the loading process below
298    * will fail. */
299   if(dl->prio == DLP_ERR && dl->error == DLE_IO_DEST) {
300     g_message("Download for `%s' in IO_DEST error state, assuming `%s' contains the finished download.", dl->dest, dl->inc);
301     dl->have = dl->size;
302     return;
303   }
304 
305   dl->have = 0;
306   int fd = open(dl->inc, O_RDWR);
307   if(fd < 0) {
308     if(errno != ENOENT)
309       dlfile_fatal_load_error(dl, "open", NULL);
310     return;
311   }
312 
313   /* If the above didn't fail, then we should already have TTHL data.
314    * Otherwise, close and delete whatever we have. */
315   if(!dl->hastthl) {
316     g_warning("No TTHL data for `%s', deleting partially downloaded data.", dl->dest);
317     close(fd);
318     unlink(dl->inc);
319     return;
320   }
321 
322   gboolean needsave = dlfile_load_bitmap(dl, fd);
323   if(dlfile_load_threads(dl, fd))
324     needsave = TRUE;
325 
326   if(needsave && !dlfile_save_bitmap(dl, fd))
327     dlfile_fatal_load_error(dl, "save bitmap to", NULL);
328 
329   dlfile_threaddump(dl, 0);
330   close(fd);
331 }
332 
333 
334 /* Called from dl.c when a dl item is being deleted, either from
335  * dlfile_finished() or when the item is removed from the UI. */
dlfile_rm(dl_t * dl)336 void dlfile_rm(dl_t *dl) {
337   g_return_if_fail(!dl->active_threads);
338 
339   if(dl->bitmap_src)
340     g_source_remove(dl->bitmap_src);
341 
342   if(dl->incfd > 0)
343     g_warn_if_fail(close(dl->incfd) == 0);
344 
345   if(dl->inc)
346     unlink(dl->inc);
347 
348   GSList *l;
349   for(l=dl->threads; l; l=l->next)
350     g_slice_free(dlfile_thread_t, l->data);
351   g_slist_free(dl->threads);
352   g_free(dl->bitmap);
353 }
354 
355 
356 /* Create the inc file and initialize the necessary structs to prepare for
357  * handling downloaded data. */
dlfile_open(dl_t * dl)358 static gboolean dlfile_open(dl_t *dl) {
359   if(dl->incfd <= 0)
360     dl->incfd = open(dl->inc, O_WRONLY|O_CREAT, 0666);
361   if(dl->incfd < 0) {
362     g_warning("Error opening %s: %s", dl->inc, g_strerror(errno));
363     dl_queue_seterr(dl, DLE_IO_INC, g_strerror(errno));
364     return FALSE;
365   }
366 
367   /* Everything else has already been initialized if we have a thread or bitmap */
368   if(dl->threads || dl->bitmap)
369     return TRUE;
370 
371   if(!dl->islist) {
372     dl->bitmap = bita_new(dlfile_chunks(dl->size));
373     if(!dlfile_save_bitmap(dl, dl->incfd)) {
374       g_warning("Error writing bitmap for `%s': %s.", dl->dest, g_strerror(errno));
375       dl_queue_seterr(dl, DLE_IO_INC, g_strerror(errno));
376       free(dl->bitmap);
377       dl->bitmap = NULL;
378       return FALSE;
379     }
380   }
381 
382   dlfile_thread_t *t = g_slice_new0(dlfile_thread_t);
383   t->dl = dl;
384   t->chunk = 0;
385   t->allocated = 0;
386   if(!dl->islist)
387     t->avail = dlfile_chunks(dl->size);
388   tth_init(&t->hash_tth);
389   dl->threads = g_slist_prepend(dl->threads, t);
390   return TRUE;
391 }
392 
393 
394 /* XXX: This function may block in the main thread for a while. Perhaps do it in a threadpool? */
dlfile_finished(dl_t * dl)395 void dlfile_finished(dl_t *dl) {
396   if(dl->incfd <= 0 && !dlfile_open(dl))
397     return;
398 
399   /* Regular files: Remove bitmap from the file
400    * File lists: Ensure that the file size is correct after we've downloaded a
401    *   longer file list before that got interrupted. */
402   if(ftruncate(dl->incfd, dl->size) < 0) {
403     g_warning("Error truncating the incoming file for `%s': %s.", dl->dest, g_strerror(errno));
404     dl_queue_seterr(dl, DLE_IO_INC, g_strerror(errno));
405     return;
406   }
407   int r = close(dl->incfd);
408   dl->incfd = 0;
409   if(r < 0) {
410     g_warning("Error closing the incoming file for `%s': %s.", dl->dest, g_strerror(errno));
411     dl_queue_seterr(dl, DLE_IO_INC, g_strerror(errno));
412     return;
413   }
414 
415   char *fdest = g_filename_from_utf8(dl->dest, -1, NULL, NULL, NULL);
416   if(!fdest)
417     fdest = g_strdup(dl->dest);
418 
419   /* Create destination directory, if it does not exist yet. */
420   char *parent = g_path_get_dirname(fdest);
421   r = g_mkdir_with_parents(parent, 0777);
422   g_free(parent);
423   if(r < 0) {
424     g_warning("Error creating directory for `%s': %s.", dl->dest, g_strerror(errno));
425     dl_queue_seterr(dl, DLE_IO_DEST, g_strerror(errno));
426     g_free(fdest);
427     return;
428   }
429 
430   /* Prevent overwiting other files by appending a prefix to the destination if
431    * it already exists. It is assumed that fn + any dupe-prevention-extension
432    * does not exceed NAME_MAX. (Not that checking against NAME_MAX is really
433    * reliable - some filesystems have an even more strict limit) */
434   int num = 1;
435   char *dest = g_strdup(fdest);
436   while(!dl->islist && g_file_test(dest, G_FILE_TEST_EXISTS)) {
437     g_free(dest);
438     dest = g_strdup_printf("%s.%d", fdest, num++);
439   }
440   g_free(fdest);
441 
442   GError *err = NULL;
443   file_move(dl->inc, dest, dl->islist, &err);
444   g_free(dest);
445   if(err) {
446     g_warning("Error moving file to destination `%s': %s.", dl->dest, err->message);
447     dl_queue_seterr(dl, DLE_IO_DEST, err->message);
448     g_error_free(err);
449     return;
450   }
451 
452   dl_finished(dl);
453 }
454 
455 
456 /* The 'speed' argument should be a pessimistic estimate of the peers' speed,
457  * in bytes/s. I think this is best obtained from a 30 second average.
458  * Returns the thread pointer. */
dlfile_getchunk(dl_t * dl,guint64 uid,guint64 speed)459 dlfile_thread_t *dlfile_getchunk(dl_t *dl, guint64 uid, guint64 speed) {
460   dlfile_thread_t *t = NULL;
461   if(!dlfile_open(dl))
462     return NULL;
463 
464   /* File lists should always be downloaded in a single GET request because
465    * their contents may be modified between subsequent requests. */
466   if(dl->islist) {
467     t = dl->threads->data;
468     t->chunk = 0;
469     t->len = 0;
470     t->uid = uid;
471     t->busy = TRUE;
472     dl->hassize = FALSE;
473     dl->have = 0;
474     dl->allbusy = TRUE;
475     dl->active_threads++;
476     return t;
477   }
478 
479   /* Walk through the threads and look for:
480    *      t = Thread with largest avail and with allocated = 0
481    *   tsec = Thread with an unallocated block and largest avail-allocated
482    */
483   dlfile_thread_t *tsec = NULL;
484   GSList *l;
485 
486   g_static_mutex_lock(&dl->lock);
487   dlfile_threaddump(dl, 1);
488   for(l=dl->threads; l; l=l->next) {
489     dlfile_thread_t *ti = l->data;
490     if(ti->avail && (!tsec || ti->avail-ti->allocated > tsec->avail-tsec->allocated) && dlfile_hasfreeblock(ti))
491       tsec = ti;
492     if(!ti->busy && (!t || ti->avail > t->avail))
493       t = ti;
494   }
495 
496   if(!t) {
497     guint32 chunksinblock = dl->hash_block/DLFILE_CHUNKSIZE;
498     guint32 chunk = ((tsec->chunk + tsec->allocated + (tsec->avail - tsec->allocated)/2) / chunksinblock) * chunksinblock;
499     if(chunk < tsec->chunk + tsec->allocated) /* Only possible for the last block in the file */
500       chunk += chunksinblock;
501     t = g_slice_new0(dlfile_thread_t);
502     t->dl = dl;
503     t->chunk = chunk;
504     t->avail = tsec->avail - (chunk - tsec->chunk);
505     g_return_val_if_fail(t->avail > 0, NULL);
506     tth_init(&t->hash_tth);
507 
508     tsec->avail -= t->avail;
509     dl->threads = g_slist_prepend(dl->threads, t);
510   }
511 
512   /* Number of chunks to request as one segment. The size of a segment is
513    * chosen to approximate a download time of ~5 min. */
514   guint32 minsegment = var_get_int64(0, VAR_download_segment);
515   if(minsegment) {
516     guint32 chunks = MIN(G_MAXUINT32, 1 + ((speed * 300) / DLFILE_CHUNKSIZE));
517     chunks = MAX(chunks, (minsegment+DLFILE_CHUNKSIZE-1) / DLFILE_CHUNKSIZE);
518     t->allocated = MIN(t->avail, chunks);
519   } else
520     t->allocated = t->avail;
521   t->busy = TRUE;
522   t->uid = uid;
523   dl->active_threads++;
524 
525   /* Go through the list again to update dl->allbusy */
526   for(l=dl->threads; l; l=l->next) {
527     dlfile_thread_t *ti = l->data;
528     if(ti->avail && (!ti->busy || dlfile_hasfreeblock(ti)))
529       break;
530   }
531   dl->allbusy = !l;
532 
533   dlfile_threaddump(dl, 2);
534   g_static_mutex_unlock(&dl->lock);
535   g_debug("Allocating: allbusy = %d, chunk = %u, allocated = %u, avail = %u, chunksinblock = %u, chunksinfile = %u",
536       dl->allbusy, t->chunk, t->allocated, t->avail, (guint32)dl->hash_block/DLFILE_CHUNKSIZE, dlfile_chunks(dl->size));
537   return t;
538 }
539 
540 
dlfile_recv_check(dlfile_thread_t * t,char * leaf)541 static gboolean dlfile_recv_check(dlfile_thread_t *t, char *leaf) {
542   guint32 num = (t->chunk-1)/(t->dl->hash_block / DLFILE_CHUNKSIZE);
543   if(t->dl->size < t->dl->hash_block ? memcmp(leaf, t->dl->hash, 24) == 0 : db_dl_checkhash(t->dl->hash, num, leaf))
544     return TRUE;
545 
546   g_static_mutex_lock(&t->dl->lock);
547 
548   /* Hash failure, remove the failed block from the bitmap and dl->have, and
549    * reset this thread so that the block can be re-downloaded. */
550   guint32 startchunk = num * (t->dl->hash_block / DLFILE_CHUNKSIZE);
551   // Or: chunksinblock = MIN(t->dl->hash_block / DLFILE_CHUNKSIZE, dlfile_chunks(t->dl->size) - startchunk);
552   guint32 chunksinblock = t->chunk - startchunk;
553   t->chunk = startchunk;
554   t->avail += chunksinblock;
555   t->allocated += chunksinblock;
556   t->dl->have -= MIN(t->dl->hash_block, t->dl->size - (guint64)startchunk * DLFILE_CHUNKSIZE);
557 
558   guint32 i;
559   for(i=startchunk; i<startchunk+chunksinblock; i++)
560     bita_set(t->dl->bitmap, i);
561   dlfile_save_bitmap_defer(t->dl);
562 
563   g_static_mutex_unlock(&t->dl->lock);
564 
565   t->uerr = DLE_HASH;
566   t->uerr_msg = g_strdup_printf("Hash for block %u (chunk %u-%u) does not match.", num, startchunk, startchunk+chunksinblock);
567   return FALSE;
568 }
569 
570 
dlfile_recv_write(dlfile_thread_t * t,const char * buf,int len)571 static gboolean dlfile_recv_write(dlfile_thread_t *t, const char *buf, int len) {
572   off_t off = ((guint64)t->chunk * DLFILE_CHUNKSIZE) + t->len;
573   off_t offi = off;
574   size_t rem = len;
575   const char *bufi = buf;
576   while(rem > 0) {
577     ssize_t r = pwrite(t->dl->incfd, bufi, rem, offi);
578     if(r <= 0) {
579       t->err = DLE_IO_INC;
580       t->err_msg = g_strdup(g_strerror(errno));
581       return FALSE;
582     }
583     offi += r;
584     rem -= r;
585     bufi += r;
586   }
587   fadv_oneshot(t->dl->incfd, off, len, VAR_FFC_DOWNLOAD);
588   return TRUE;
589 }
590 
591 
592 /* Called when new data has been received from a downloading thread.  The data
593  * is written to the file, the TTH calculation is updated and checked with the
594  * DB, and the bitmap is updated.
595  * This function may be called from another OS thread.
596  * Returns TRUE to indicate success, FALSE on failure. */
dlfile_recv(void * vt,const char * buf,int len)597 gboolean dlfile_recv(void *vt, const char *buf, int len) {
598   dlfile_thread_t *t = vt;
599   if(!dlfile_recv_write(t, buf, len))
600     return FALSE;
601 
602   while(len > 0) {
603     guint32 inchunk = MIN((guint32)len, DLFILE_CHUNKSIZE - t->len);
604     t->len += inchunk;
605     gboolean islast = ((guint64)t->chunk * DLFILE_CHUNKSIZE) + t->len == t->dl->size;
606 
607     if(!t->dl->islist)
608       tth_update(&t->hash_tth, buf, inchunk);
609     buf += inchunk;
610     len -= inchunk;
611 
612     g_static_mutex_lock(&t->dl->lock);
613     t->dl->have += inchunk;
614 
615     if(!islast && t->len < DLFILE_CHUNKSIZE) {
616       g_static_mutex_unlock(&t->dl->lock);
617       continue;
618     }
619 
620     if(!t->dl->islist) {
621       bita_set(t->dl->bitmap, t->chunk);
622       dlfile_save_bitmap_defer(t->dl);
623     }
624     t->chunk++;
625     t->allocated--;
626     t->avail--;
627     t->len = 0;
628     g_static_mutex_unlock(&t->dl->lock);
629 
630     if(!t->dl->islist && (islast || t->chunk % (t->dl->hash_block / DLFILE_CHUNKSIZE) == 0)) {
631       char leaf[24];
632       tth_final(&t->hash_tth, leaf);
633       tth_init(&t->hash_tth);
634       if(!dlfile_recv_check(t, leaf))
635         return FALSE;
636     }
637   }
638   return TRUE;
639 }
640 
641 
dlfile_recv_done(dlfile_thread_t * t)642 void dlfile_recv_done(dlfile_thread_t *t) {
643   dl_t *dl = t->dl;
644   dl->active_threads--;
645   t->busy = FALSE;
646 
647   gboolean freet = FALSE;
648   if(dl->islist ? dl->hassize && dl->have == dl->size : !t->avail) {
649     g_return_if_fail(!(t->err || t->uerr)); /* A failed thread can't be complete */
650     dl->threads = g_slist_remove(dl->threads, t);
651     freet = TRUE;
652   } else {
653     t->allocated = 0;
654     dl->allbusy = FALSE;
655   }
656   dlfile_threaddump(dl, 3);
657 
658   /* File has been removed from the queue but the dl struct is still in memory
659    * because this thread hadn't finished yet. Free it now. Note that the actual
660    * call to dl_queue_rm() is deferred, because we can't access *t after
661    * calling it. */
662   gboolean doclose = !dl->bitmap_src && !dl->active_threads;
663   gboolean dorm = FALSE;
664   if(!dl->active_threads && !g_hash_table_lookup(dl_queue, dl->hash)) {
665     dorm = TRUE;
666     doclose = FALSE;
667   } else if(t->err)
668     dl_queue_seterr(t->dl, t->err, t->err_msg);
669   else if(t->uerr)
670     dl_queue_setuerr(t->uid, t->dl->hash, t->uerr, t->uerr_msg);
671   else if(!dl->threads) {
672     dlfile_finished(dl);
673     doclose = FALSE;
674   }
675 
676   if(doclose) {
677     close(dl->incfd);
678     dl->incfd = 0;
679   }
680 
681   g_free(t->err_msg);
682   g_free(t->uerr_msg);
683   t->err = t->uerr = 0;
684   t->err_msg = t->uerr_msg = NULL;
685   if(freet)
686     g_slice_free(dlfile_thread_t, t);
687 
688   if(dorm)
689     dl_queue_rm(dl);
690 }
691