]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - fres/contract/fres_container.c
8fa60b9dbf76750fb6d95623b5098126853fb160
[frescor/frsh.git] / fres / contract / fres_container.c
1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                 */
4 /*                                                                        */
5 /*   Universidad de Cantabria,              SPAIN                         */
6 /*   University of York,                    UK                            */
7 /*   Scuola Superiore Sant'Anna,            ITALY                         */
8 /*   Kaiserslautern University,             GERMANY                       */
9 /*   Univ. Politécnica  Valencia,           SPAIN                        */
10 /*   Czech Technical University in Prague,  CZECH REPUBLIC                */
11 /*   ENEA                                   SWEDEN                        */
12 /*   Thales Communication S.A.              FRANCE                        */
13 /*   Visual Tools S.A.                      SPAIN                         */
14 /*   Rapita Systems Ltd                     UK                            */
15 /*   Evidence                               ITALY                         */
16 /*                                                                        */
17 /*   See http://www.frescor.org for a link to partners' websites          */
18 /*                                                                        */
19 /*          FRESCOR project (FP6/2005/IST/5-034026) is funded             */
20 /*       in part by the European Union Sixth Framework Programme          */
21 /*       The European Union is not liable of any use that may be          */
22 /*       made of this code.                                               */
23 /*                                                                        */
24 /*                                                                        */
25 /*  This file is part of FRSH (FRescor ScHeduler)                         */
26 /*                                                                        */
27 /* FRSH is free software; you can redistribute it and/or modify it        */
28 /* under terms of the GNU General Public License as published by the      */
29 /* Free Software Foundation; either version 2, or (at your option) any    */
30 /* later version.  FRSH is distributed in the hope that it will be        */
31 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
32 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
33 /* General Public License for more details. You should have received a    */
34 /* copy of the GNU General Public License along with FRSH; see file       */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
36 /* Cambridge, MA 02139, USA.                                              */
37 /*                                                                        */
38 /* As a special exception, including FRSH header files in a file,         */
39 /* instantiating FRSH generics or templates, or linking other files       */
40 /* with FRSH objects to produce an executable application, does not       */
41 /* by itself cause the resulting executable application to be covered     */
42 /* by the GNU General Public License. This exception does not             */
43 /* however invalidate any other reasons why the executable file might be  */
44 /* covered by the GNU Public License.                                     */
45 /**************************************************************************/
46
47 /**
48  * @file   fres_contract_container.c
49  * @author Michal Sojka <sojkam1@fel.cvut.cz>
50  * 
51  * @brief  Functions for manipulating with forb-based contracts.
52  * 
53  * 
54  */
55 #include <fres_container.h>
56 #include "fres_container_internal.h"
57 #include <stdbool.h>
58 #include <ul_log.h>
59 #include <string.h>
60 #include <forb/cdr.h>
61 #include <stdio.h>
62
63 UL_LOG_CUST(ulogd_fres_container);
64 ul_log_domain_t ulogd_fres_container = {UL_LOGL_ERR, "fres_container"};
65
66 static void *
67 fres_block_duplicate_spare_capacity(enum fres_block_type type, const void *block_data);
68
69 #define desc_default(type)                                              \
70         struct fres_block_desc desc_default_##type = {                  \
71                 .name        = #type,                                   \
72                 .size        = sizeof(fres_block_##type),               \
73                 .serialize   = (fres_block_serialize_fnc_t*)fres_block_##type##_serialize, \
74                 .deserialize = (fres_block_deserialize_fnc_t*)fres_block_##type##_deserialize, \
75                 .duplicate   = fres_block_duplicate_default,            \
76                 .to_string   = fres_block_##type##_to_string            \
77         }
78
79 static size_t indent_str(char *dest, size_t size, char *src, unsigned indent_by)
80 {
81         char *p = src;
82         size_t written = 0;
83         while (*p && size > 1) {
84                 if (p == src || *(p-1) == '\n') { /* indent */
85                         int i;
86                         for (i=0; i<indent_by; i++) {
87                                 *dest++ = ' ';
88                                 written++;
89                                 size--;
90                         }
91                 }
92                 *dest++ = *p++;
93                 written++;
94                 size--;
95         }
96         *dest = 0;
97         return written;
98 }
99
100 int fres_block_label_to_string(char *dest, size_t size, enum fres_block_type type,
101                                const void *block_data)
102 {
103         const fres_block_label *b = block_data;
104         return snprintf(dest, size, "%s\n", b->label); /* FIXME: do not print more that 32 characters */
105 }
106
107 int fres_block_resource_to_string(char *dest, size_t size, enum fres_block_type type,
108                                const void *block_data)
109 {
110         const fres_block_resource *b = block_data;
111         return snprintf(dest, size, "%d.%d\n", b->resource_type, b->resource_id);
112 }
113
114 int fres_block_basic_to_string(char *dest, size_t size, enum fres_block_type type,
115                                const void *block_data)
116 {
117         const fres_block_basic *b = block_data;
118         return snprintf(dest, size,
119                         "budget: %ld.%09ld s\n"
120                         "period: %ld.%09ld s\n"
121                         "workload: %d\n"
122                         "type: %d\n",
123                         (long)b->budget.tv_sec, (long)b->budget.tv_nsec,
124                         (long)b->period.tv_sec, (long)b->period.tv_nsec,
125                         b->workload,
126                         b->contract_type
127                 );
128         return 0;
129 }
130
131 int fres_block_timing_reqs_to_string(char *dest, size_t size, enum fres_block_type type,
132                                const void *block_data)
133 {
134         const fres_block_timing_reqs *b = block_data;
135         return snprintf(dest, size,
136                         "D=T: %s\n"
137                         "deadline: %ld.%09ld s\n",
138                         b->d_equals_t ? "true" : "false",
139                         (long)b->deadline.tv_sec, (long)b->deadline.tv_nsec
140                 );
141 }
142
143 int fres_block_spare_capacity_to_string(char *dest, size_t size, enum fres_block_type type,
144                                         const void *block_data)
145 {
146         int i, ret;
147         char *orig_dest = dest;
148         const fres_block_spare_capacity *s = block_data;
149         ret = snprintf(dest, size,
150                        "granularity: %s\n"
151                        "importance: %d\n"
152                        "weight:     %d\n"
153                        "stability time: %g\n",
154                        s->granularity == FRSH_GR_CONTINUOUS ? "continuous" :
155                        s->granularity == FRSH_GR_DISCRETE ? "discrete" : "?",
156                        s->importance, s->weight, fosa_rel_time_to_double(s->stability_time));
157         dest += ret;
158         size -= ret;
159         for (i=0; i < s->variants._length; i++) {
160                 char tmp[1000];
161                 ret = snprintf(dest, size, "Variant %d:\n", i);
162                 dest += ret;
163                 size -= ret;
164                 ret = fres_container_to_string(tmp, sizeof(tmp),
165                                                forb_sequence_elem(s->variants, i));
166                 ret = indent_str(dest, size, tmp, 2);
167                 dest += ret;
168                 size -= ret;
169         }
170         return dest - orig_dest;
171 }
172
173 int fres_block_csects_to_string(char *dest, size_t size, enum fres_block_type type,
174                                 const void *block_data)
175 {
176         return snprintf(dest, size, "Coming Soon...\n");
177 }
178
179 int fres_block_power_management_to_string(char *dest, size_t size, enum fres_block_type type,
180                                           const void *block_data)
181 {
182         return snprintf(dest, size, "Coming Soon...\n");
183 }
184
185 static const desc_default(label);
186 static const desc_default(resource);
187 static const desc_default(basic);
188 static const desc_default(timing_reqs);
189 static const desc_default(csects);
190 static const desc_default(power_management);
191
192 static const struct fres_block_desc desc_spare_capacity = {
193         .name        = "spare_capacity",
194         .size        = sizeof(fres_block_spare_capacity),
195         .serialize   = (fres_block_serialize_fnc_t*)fres_block_spare_capacity_serialize, \
196         .deserialize = (fres_block_deserialize_fnc_t*)fres_block_spare_capacity_deserialize, \
197         .duplicate   = fres_block_duplicate_spare_capacity,
198         .to_string   = fres_block_spare_capacity_to_string
199 };
200
201 /**
202  * Information about various block types
203  * 
204  */
205 static const struct fres_block_desc *block_registry[FRES_NUM_BLOCKS] = {
206         [FRES_BLOCK_LABEL] = &desc_default_label,
207         [FRES_BLOCK_RESOURCE] = &desc_default_resource,
208         [FRES_BLOCK_BASIC] = &desc_default_basic,
209         [FRES_BLOCK_TIMING_REQS] = &desc_default_timing_reqs,
210         [FRES_BLOCK_CSECTS] = &desc_default_csects,
211         [FRES_BLOCK_SPARE_CAPACITY] = &desc_spare_capacity,
212         [FRES_BLOCK_POWER_MANAGEMENT] = &desc_default_power_management,
213 };
214
215 /** 
216  * Default procedure for duplicating contract blocks.
217  *
218  * It mallocs memory for the duplicate and copy memory of the original
219  * block to the allocated memory.
220  * 
221  * @param type 
222  * @param block_data 
223  * 
224  * @return Pointer to the duplicated block or NULL in case of error.
225  */
226 void *
227 fres_block_duplicate_default(enum fres_block_type type, const void *block_data)
228 {
229         void *ret = NULL;
230         size_t size;
231         if (!FRES_BLOCK_TYPE_VALID(type) || !block_registry[type]) {
232                 goto err;
233         }
234         size = block_registry[type]->size;
235         
236         ret = malloc(size);
237         if (!ret) goto err;
238
239         memcpy(ret, block_data, size);
240 err:
241         return ret;
242 }
243
244 static void *
245 fres_block_duplicate_spare_capacity(enum fres_block_type type, const void *block_data)
246 {
247         const fres_block_spare_capacity *sc1 = block_data;
248         fres_block_spare_capacity       *sc2;
249         
250         sc2 = fres_block_duplicate_default(type, block_data);
251         if (sc2) {
252                 unsigned i, len = sc1->variants._length;
253                 sc2->variants._buffer =
254                         CORBA_sequence_fres_container_ptr_allocbuf(len);
255                 sc2->variants._maximum = len;
256                 sc2->variants._length = len;
257                 for (i=0; i<len; i++) {
258                         sc2->variants._buffer[i] =
259                                 fres_container_duplicate(sc1->variants._buffer[i]);
260                 }
261         }
262         return sc2;
263 }
264
265 /** 
266  * Regsiteres a custom block type.
267  * 
268  * @param fres_block_type Type identifier
269  * @param desc Description of the type
270  * 
271  * @return Zero on success, -1 on error.
272  */
273 int
274 fres_block_register(enum fres_block_type type, const struct fres_block_desc *desc)
275 {
276         if (FRES_BLOCK_TYPE_VALID(type) &&
277             block_registry[type] == NULL) {
278                 block_registry[type] = desc;
279                 return 0;
280         }
281         return -1;
282 }
283
284 /**
285  * Allocates new contract container.
286  * 
287  * @return Pointer to the container of NULL in case of error (errno is
288  * set appropriately).
289  */
290 struct fres_container *
291 fres_container_new(void)
292 {
293         struct fres_container *c;
294
295         c = malloc(sizeof(*c));
296         if (c) {
297                 memset(c, 0, sizeof(*c));
298         }
299         return c;
300 }
301
302 /** 
303  * Deallocates all memory occupied by a container.
304  * 
305  * @param container 
306  */
307 void
308 fres_container_destroy(struct fres_container *container)
309 {
310         enum fres_block_type i;
311         if (!container) return;
312         for (i=0; i<FRES_NUM_BLOCKS; i++) {
313                 fres_container_del_block(container, i);
314         }
315
316         free(container);
317 }
318
319 /** 
320  * Duplicates a contract block of a given type. Calls duplication
321  * method registered with the block.
322  * 
323  * @param dest Where to store the copy
324  * @param source What to copy
325  * 
326  * @return Zero on success, non-zero error code on error.
327  */
328 int
329 fres_block_duplicate(struct fres_block *dest,
330                      const struct fres_block *source,
331                      enum fres_block_type type)
332 {
333         dest->state = FRES_BLOCK_EMPTY;
334         switch (source->state) {
335                 case FRES_BLOCK_EMPTY:
336                         /* nothing to do */
337                         break;
338                 case FRES_BLOCK_DATA: {
339                         void *dup;
340                         dup = block_registry[type]->duplicate(
341                                 type, source->u.data);
342                         if (!dup) {
343                                 return FRES_ERR_BLOCK_DUP;
344                         }
345                         dest->u.data = dup;
346                         dest->state = FRES_BLOCK_DATA;
347                         break;
348                 }
349                 case FRES_BLOCK_STREAM:
350                         dest->state = FRES_BLOCK_STREAM;
351                         dest->u.stream = source->u.stream;
352                         dest->u.stream.data = malloc(source->u.stream.length);
353                         if (!dest->u.stream.data) {
354                                 return errno;
355                         }
356                         memcpy(dest->u.stream.data, source->u.stream.data,
357                                source->u.stream.length);
358                         break;
359         }
360         return 0;
361 }
362                      
363
364
365 /** 
366  * Duplicates a container
367  * 
368  * @param source 
369  * 
370  * @return Pointer to the duplicated container or NULL in case of
371  * error.
372  */
373 struct fres_container *
374 fres_container_duplicate(const struct fres_container *source)
375 {
376         struct fres_container *dest;
377         enum fres_block_type type;
378         int ret;
379         if (!source) return NULL;
380         
381         dest = fres_container_new();
382         if (!dest) return NULL;
383
384         for (type=0; type<FRES_NUM_BLOCKS; type++) {
385                 ret = fres_block_duplicate(&dest->blocks[type], &source->blocks[type], type);
386                 if (ret) goto free_dest_err;
387         }
388         return dest;
389 free_dest_err:
390         fres_container_destroy(dest);
391         return NULL;
392 }
393
394 /** 
395  * Adds a block of the specific type to the contract container.
396  * 
397  * @param container Container to which add the block.
398  * @param type Type of the block.
399  * 
400  * @param block Pointer to the block which should be a malloced
401  * area. In in most cases it will points to a structure defined in
402  * IDL.
403  * 
404  * @return Zero on success, -1 on error and errno is set appropriately.
405  */
406 int
407 fres_container_add_block(struct fres_container *container,
408                          enum fres_block_type type,
409                          void *block)
410 {
411         if (!FRES_BLOCK_TYPE_VALID(type) ||
412             container->blocks[type].state != FRES_BLOCK_EMPTY)
413         {
414                 errno = EINVAL;
415                 return -1;
416         }
417         if  (!block_registry[type]) {
418                 errno = FRES_ERR_BLOCK_NOT_REGISTERED;
419                 return -1;
420         }
421
422         container->blocks[type].u.data = block;
423         container->blocks[type].state = FRES_BLOCK_DATA;
424         return 0;
425 }
426
427 /** 
428  * Deletes a block from container and frees it from memory.
429  * 
430  * @param container 
431  * @param type 
432  */
433 void
434 fres_container_del_block(struct fres_container *container,
435                          enum fres_block_type type)
436 {
437         if (FRES_BLOCK_TYPE_VALID(type)) {
438                 switch (container->blocks[type].state) {
439                         case FRES_BLOCK_EMPTY:
440                                 /* nothing to do */
441                                 break;
442                         case FRES_BLOCK_DATA:
443                                 free(container->blocks[type].u.data);
444                                 container->blocks[type].state = FRES_BLOCK_EMPTY;
445                                 break;
446                         case FRES_BLOCK_STREAM:
447                                 forb_free(container->blocks[type].u.stream.data);
448                                 container->blocks[type].state = FRES_BLOCK_EMPTY;
449                                 break;
450                 }
451         }
452 }
453
454 /** 
455  * Returns pointer to a block of a particular type.
456  * 
457  * @param container 
458  * @param type Type of the block to be returned.
459  * 
460  * @return Pointer to the block or NULL if the block is not present or
461  * deserialized. The memory area pointed by this pointer is owned by
462  * the contract. If the user needs to store the block, it must be
463  * duplicated.
464  */
465 void *
466 fres_container_get_block(const struct fres_container *container,
467                          enum fres_block_type type)
468 {
469         if (container &&
470             FRES_BLOCK_TYPE_VALID(type) &&
471             container->blocks[type].state == FRES_BLOCK_DATA) {
472                 return container->blocks[type].u.data;
473         } else {
474                 return NULL;
475         }
476 }
477
478 static CORBA_boolean
479 serialize_block(FORB_CDR_Codec *codec, enum fres_block_type type, const struct fres_block *b)
480 {
481         CORBA_boolean ret;
482         CORBA_short type_short = type;
483         CORBA_unsigned_short flags;
484         CORBA_long length;
485         unsigned int wptr_of_length, wptr_tmp, wptr_of_block_beg;
486
487         switch (b->state) {
488                 case FRES_BLOCK_STREAM:
489                         /* Endianing of stream is the same as when it
490                          * was received */
491                         flags = b->u.stream.flags;
492                         length = b->u.stream.length;
493                         break;
494                 case FRES_BLOCK_DATA:
495                         /* Endianing of stream is the same as of the
496                          * rest of data */
497                         flags = 0;
498                         flags |= (codec->data_endian == LittleEndian) ?
499                                 FRES_BLOCK_LITTLE_ENDIAN : 0;
500                         length = 0; /* Length will be determined later */
501                         break;
502                 default:
503                         break;
504         }
505         
506         if (!(ret = CORBA_short_serialize(codec, &type_short))) goto err;
507         if (!(ret = CORBA_short_serialize(codec, &flags))) goto err;
508         wptr_of_length = codec->wptr;
509         if (!(ret = CORBA_long_serialize(codec, &length))) goto err;
510         if (!(ret = FORB_CDR_put_align(codec, 8))) goto err; /* All blocks are 8 byte aligned */
511         wptr_of_block_beg = codec->wptr;
512
513         switch (b->state) {
514                 case FRES_BLOCK_DATA:
515                         if (block_registry[type] &&
516                             block_registry[type]->serialize) {
517                                 ret = block_registry[type]->serialize(codec, b->u.data);
518                         } else {
519                                 ret = CORBA_FALSE;
520                         }
521                         /* Update the length field */
522                         length = codec->wptr - wptr_of_block_beg;
523                         wptr_tmp = codec->wptr;
524                         codec->wptr = wptr_of_length;
525                         CORBA_long_serialize(codec, &length);
526                         codec->wptr = wptr_tmp;
527                         break;
528                 case FRES_BLOCK_STREAM:
529                         ret = FORB_CDR_buffer_puts(codec, b->u.stream.data,
530                                                    b->u.stream.length);
531                         break;
532                 default:
533                         ret = CORBA_FALSE;
534                         break;
535         }
536 err:
537         return ret;
538 }
539
540
541 CORBA_boolean
542 fres_container_ptr_serialize(FORB_CDR_Codec *codec, const fres_container_ptr *container_ptr)
543 {
544         //CORBA_long l;
545         CORBA_long count;
546         struct fres_container *container = *container_ptr;
547         CORBA_boolean ret;
548         enum fres_block_type type;
549         if (!container) goto err;
550
551         count=0;
552         for (type=0; type<FRES_NUM_BLOCKS; type++) {
553                 if (container->blocks[type].state != FRES_BLOCK_EMPTY)
554                         count++;
555         }
556
557         if (!CORBA_long_serialize(codec, &count)) goto err;
558         
559         for (type=0; type<FRES_NUM_BLOCKS; type++) {
560                 struct fres_block *b = &container->blocks[type];
561                 if (b->state != FRES_BLOCK_EMPTY) {
562                         ret = serialize_block(codec, type, b);
563                         if (!ret) goto err;
564                 }
565         }
566         return CORBA_TRUE;
567 err:
568         return CORBA_FALSE;
569 }
570
571 CORBA_boolean
572 fres_container_ptr_deserialize(FORB_CDR_Codec *codec,
573                                fres_container_ptr *container)
574 {
575         CORBA_boolean ret;
576         struct fres_container *c;
577         CORBA_long count;
578         enum fres_block_type type;
579         CORBA_short type_short;
580         CORBA_short flags;
581         CORBA_long length;
582         int i;
583
584         c = fres_container_new();
585         if (!c) goto err;
586
587         if (!CORBA_long_deserialize(codec, &count)) goto err;
588
589         for (i=0; i<count; i++) {
590                 if (!CORBA_short_deserialize(codec, &type_short)) goto free_err;
591                 if (!CORBA_short_deserialize(codec, &flags)) goto free_err;
592                 if (!CORBA_long_deserialize(codec, &length)) goto free_err;
593                 FORB_CDR_get_align(codec, 8); /* All blocks are 8 byte aligned */
594
595                 type = type_short;
596                 if (!FRES_BLOCK_TYPE_VALID(type)) goto free_err;
597                 if (block_registry[type] &&
598                     block_registry[type]->deserialize) {
599                         FORB_CDR_Endianness endian;
600                         void *block;
601                         block = malloc(block_registry[type]->size);
602                         if (!block) goto free_err;
603                         /* A block can have different endian from the rest of the message */
604                         endian = codec->data_endian;
605                         codec->data_endian = (flags & FRES_BLOCK_LITTLE_ENDIAN) ?
606                                 LittleEndian : BigEndian;
607                         ret = block_registry[type]->deserialize(codec, block);
608                         codec->data_endian = endian;
609                         if (!ret) goto free_err;
610                         fres_container_add_block(c, type, block);
611                 } else {
612                         /* Unknown block - store it as stream */
613                         struct fres_block_stream *bs = &c->blocks[type].u.stream;
614                         c->blocks[type].state = FRES_BLOCK_STREAM;
615                         bs->data = malloc(length);
616                         if (!bs->data) goto free_err;
617                         bs->flags = flags;
618                         bs->length = length;
619                         FORB_CDR_buffer_gets(codec, bs->data, length);
620                 }
621         }
622
623         
624         *container = c;
625         return CORBA_TRUE;
626 free_err:
627         fres_container_destroy(c);
628 err:
629         return CORBA_FALSE;
630 }
631
632 int
633 fres_container_to_string(char *dest, size_t size, const struct fres_container *c)
634 {
635         int ret, written = 0;
636         enum fres_block_type type;
637         
638         for (type=0; type<FRES_NUM_BLOCKS; type++) {
639                 const struct fres_block *b = &c->blocks[type];
640                 switch (b->state) {
641                         case FRES_BLOCK_EMPTY:
642                                 /* nothing to do */
643                                 break;
644                         case FRES_BLOCK_DATA:
645                                 ret = snprintf(dest, size, "block %s (%d)\n",
646                                                block_registry[type]->name, type);
647                                 if (ret < 0) goto err;
648                                 if (ret < size) {
649                                         written += ret;
650                                         size -= ret;
651                                         dest += ret;
652                                 }
653                                 if (block_registry[type]->to_string) {
654                                         char tmp[1000];
655                                         block_registry[type]->to_string(tmp, sizeof(tmp), type, b->u.data);
656                                         ret = indent_str(dest, size, tmp, 2);
657                                         written += ret;
658                                         size -= ret;
659                                         dest += ret;
660                                 }
661                                 break;
662                         case FRES_BLOCK_STREAM:
663                                 ret = snprintf(dest, size, "unknown block (%d)\n",
664                                                type);
665                                 if (ret < 0) goto err;
666                                 if (ret < size) {
667                                         written += ret;
668                                         size -= ret;
669                                         dest += ret;
670                                 }
671                                 break;
672                 }
673         }
674         ret = written;
675         *dest = 0;
676 err:
677         return ret;
678 }
679
680
681 /** 
682  * Returns the number of non-empty blocks in a container.
683  * 
684  * @param c Container
685  * 
686  * @return Number of non-empty blocks in container @a c.
687  */
688 int
689 fres_container_get_num_blocks(const struct fres_container *c)
690 {
691         int num = 0;
692         enum fres_block_type type;
693         
694         for (type=0; type<FRES_NUM_BLOCKS; type++) {
695                 if (c->blocks[type].state != FRES_BLOCK_EMPTY) {
696                         num++;
697                 }
698         }
699         return num;
700 }
701
702 /** 
703  * Merges two block containers. Blocks present @a src and missing in
704  * @a dest are duplicated in @a dest.
705  * 
706  * @param dest Destination of merge operation
707  * @param src Source of merge operation
708  * 
709  * @return Zero on success, non-zero error core on error.
710  */
711 int fres_container_merge(struct fres_container *dest,
712                          const struct fres_container *src)
713 {
714         enum fres_block_type type;
715         int ret;
716         
717         for (type=0; type<FRES_NUM_BLOCKS; type++) {
718                 const struct fres_block *sb = &src->blocks[type];
719                 struct fres_block *db = &dest->blocks[type];
720                 
721                 if (sb->state != FRES_BLOCK_EMPTY &&
722                     db->state == FRES_BLOCK_EMPTY) {
723                         ret = fres_block_duplicate(db, sb, type);
724                         if (ret) {
725                                 return ret;
726                         }
727                 }
728         }
729         return 0;
730 }