Add missing file from my previous commit.
[platform/upstream/binutils.git] / bfd / vms-lib.c
1 /* BFD back-end for VMS archive files.
2
3    Copyright 2010 Free Software Foundation, Inc.
4    Written by Tristan Gingold <gingold@adacore.com>, AdaCore.
5
6    This file is part of BFD, the Binary File Descriptor library.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21    MA 02110-1301, USA.  */
22
23 #include "sysdep.h"
24 #include "bfd.h"
25 #include "libbfd.h"
26 #include "safe-ctype.h"
27 #include "bfdver.h"
28 #include "vms.h"
29 #include "vms/lbr.h"
30 #include "vms/dcx.h"
31
32 /* The standard VMS disk block size.  */
33 #ifndef VMS_BLOCK_SIZE
34 #define VMS_BLOCK_SIZE 512
35 #endif
36
37 /* Maximum key length (which is also the maximum symbol length in archive).  */
38 #define MAX_KEYLEN 129
39
40 /* DCX Submaps.  */
41
42 struct dcxsbm_desc
43 {
44   unsigned char min_char;
45   unsigned char max_char;
46   unsigned char *flags;
47   unsigned char *nodes;
48   unsigned short *next;
49 };
50
51 /* Kind of library.  Used to filter in archive_p.  */
52
53 enum vms_lib_kind
54   {
55     vms_lib_vax,
56     vms_lib_alpha,
57     vms_lib_ia64,
58     vms_lib_txt
59   };
60
61 /* Back-end private data.  */
62
63 struct lib_tdata
64 {
65   /* Major version.  */
66   unsigned char ver;
67
68   /* Type of the archive.  */
69   unsigned char type;
70
71   /* Kind of archive.  Summary of its type.  */
72   enum vms_lib_kind kind;
73
74   /* Total size of the mhd (element header).  */
75   unsigned int mhd_size;
76
77   /* Vector of modules (archive elements), already sorted.  */
78   unsigned int nbr_modules;
79   struct carsym *modules;
80   bfd **cache;
81
82   /* Vector of symbols (archive map), already sorted.  */
83   unsigned int nbr_syms;
84   struct carsym *syms;
85
86   /* DCX (decompression) data.  */
87   unsigned int nbr_dcxsbm;
88   struct dcxsbm_desc *dcxsbm;
89 };
90
91 #define bfd_libdata(bfd) ((struct lib_tdata *)((bfd)->tdata.any))
92
93 /* End-Of-Text pattern.  This is a special record to mark the end of file.  */
94
95 static const unsigned char eotdesc[] = { 0x03, 0x00, 0x77, 0x00, 0x77, 0x00 };
96
97 /* Read index block VBN and put the entry in **IDX (which is updated).
98    If the entry is indirect, recurse.  */
99
100 static bfd_boolean
101 vms_traverse_index (bfd *abfd, unsigned int vbn, struct carsym **idx)
102 {
103   struct vms_indexdef indexdef;
104   unsigned int used;
105   file_ptr off;
106   unsigned int i;
107
108   /* Read the index block.  */
109   off = (vbn - 1) * VMS_BLOCK_SIZE;
110   if (bfd_seek (abfd, off, SEEK_SET) != 0
111       || bfd_bread (&indexdef, sizeof (indexdef), abfd) != sizeof (indexdef))
112     return FALSE;
113
114   /* Traverse it.  */
115   used = bfd_getl16 (indexdef.used);
116   for (i = 0; i < used;)
117     {
118       unsigned int idx_vbn;
119       unsigned int idx_off;
120       unsigned int keylen;
121       unsigned char *keyname;
122       unsigned char *ridx = (unsigned char *)&indexdef.keys[i];
123       unsigned int len;
124
125       idx_vbn = bfd_getl32 (ridx);
126       idx_off = bfd_getl16 (ridx + 4);
127
128       /* Illegal value.  */
129       if (idx_vbn == 0)
130         return FALSE;
131
132       /* Extract key length.  */
133       if (bfd_libdata (abfd)->ver == 3)
134         {
135           keylen = ridx[6];
136           len = 7;
137         }
138       else if (bfd_libdata (abfd)->ver == 4)
139         {
140           keylen = bfd_getl16 (ridx + 6);
141           len = 9;
142         }
143       else
144         return FALSE;
145
146       keyname = ridx + len;
147       i += len + keylen;
148
149       if (idx_off == RFADEF__C_INDEX)
150         {
151           /* Indirect entry.  Recurse.  */
152           if (!vms_traverse_index (abfd, idx_vbn, idx))
153             return FALSE;
154         }
155       else
156         {
157           /* Add a new entry.  */
158           char *name;
159
160           name = bfd_alloc (abfd, keylen + 1);
161           if (name == NULL)
162             return FALSE;
163           memcpy (name, keyname, keylen);
164           name[keylen] = 0;
165           (*idx)->file_offset = (idx_vbn - 1) * VMS_BLOCK_SIZE + idx_off;
166           (*idx)->name = name;
167           (*idx)++;
168         }
169     }
170
171   return TRUE;
172 }
173
174 /* Read index #IDX, which must have NBREL entries.  */
175
176 static struct carsym *
177 vms_lib_read_index (bfd *abfd, int idx, unsigned int nbrel)
178 {
179   struct carsym *res;
180   struct carsym *el;
181   struct vms_idd idd;
182   unsigned int flags;
183   unsigned int vbn;
184
185   /* Read index desription.  */
186   if (bfd_seek (abfd, LHD_IDXDESC + idx * IDD_LENGTH, SEEK_SET) != 0
187       || bfd_bread (&idd, sizeof (idd), abfd) != sizeof (idd))
188     return NULL;
189
190   /* Sanity checks.  */
191   flags = bfd_getl16 (idd.flags);
192   if (!(flags & IDD__FLAGS_ASCII)
193       || !(flags & IDD__FLAGS_VARLENIDX))
194     return NULL;
195
196   res = bfd_alloc (abfd, nbrel * sizeof (struct carsym));
197   if (res == NULL)
198     return NULL;
199
200   el = res;
201
202   /* Note: if the index is empty, there is no block to traverse.  */
203   vbn = bfd_getl32 (idd.vbn);
204   if (vbn != 0 && !vms_traverse_index (abfd, vbn, &el))
205     {
206       bfd_release (abfd, res);
207       return NULL;
208     }
209
210   if ((unsigned int)(el - res) != nbrel)
211     {
212       /* Inconsistency between the number of modules declared and the number
213          of modules found in the index.  */
214       bfd_release (abfd, res);
215       return NULL;
216     }
217   return res;
218 }
219
220 /* Standard function.  */
221
222 static const bfd_target *
223 _bfd_vms_lib_archive_p (bfd *abfd, enum vms_lib_kind kind)
224 {
225   struct vms_lhd lhd;
226   unsigned int sanity;
227   struct lib_tdata *tdata_hold;
228   struct lib_tdata *tdata;
229   unsigned int dcxvbn;
230
231   /* Read header.  */
232   if (bfd_bread (&lhd, sizeof (lhd), abfd) != sizeof (lhd))
233     {
234       if (bfd_get_error () != bfd_error_system_call)
235         bfd_set_error (bfd_error_wrong_format);
236       return NULL;
237     }
238
239   /* Check sanity (= magic) number.  */
240   sanity = bfd_getl32 (lhd.sanity);
241   if (!(sanity == LHD_SANEID3
242         || sanity == LHD_SANEID4
243         || sanity == LHD_SANEID_DCX))
244     {
245       bfd_set_error (bfd_error_wrong_format);
246       return NULL;
247     }
248
249   /* Check archive kind.  */
250   switch (kind)
251     {
252     case vms_lib_alpha:
253       if ((lhd.type != LBR__C_TYP_EOBJ && lhd.type != LBR__C_TYP_ESHSTB)
254           || bfd_getl32 (lhd.majorid) != 3
255           || lhd.nindex != 2)
256         {
257           bfd_set_error (bfd_error_wrong_format);
258           return NULL;
259         }
260       break;
261     case vms_lib_txt:
262       if ((lhd.type != LBR__C_TYP_TXT
263            && lhd.type != LBR__C_TYP_MLB
264            && lhd.type != LBR__C_TYP_HLP)
265           || bfd_getl32 (lhd.majorid) != 3
266           || lhd.nindex != 1)
267         {
268           bfd_set_error (bfd_error_wrong_format);
269           return NULL;
270         }
271       break;
272     default:
273       abort ();
274     }
275
276   /* Allocate and initialize private data.  */
277   tdata_hold = bfd_libdata (abfd);
278   tdata = (struct lib_tdata *) bfd_zalloc (abfd, sizeof (struct lib_tdata));
279   if (tdata == NULL)
280     return NULL;
281   abfd->tdata.any = (void *)tdata;
282   tdata->ver = bfd_getl32 (lhd.majorid);
283   tdata->mhd_size = MHD__C_USRDAT + lhd.mhdusz;
284   tdata->type = lhd.type;
285   tdata->kind = kind;
286
287   /* Read indexes.  */
288   tdata->nbr_modules = bfd_getl32 (lhd.modcnt);
289   tdata->nbr_syms = bfd_getl32 (lhd.idxcnt) - tdata->nbr_modules;
290   tdata->modules = vms_lib_read_index (abfd, 0, tdata->nbr_modules);
291   if (tdata->modules == NULL)
292     goto err;
293   if (lhd.nindex == 2)
294     {
295       tdata->syms = vms_lib_read_index (abfd, 1, tdata->nbr_syms);
296       if (tdata->syms == NULL)
297         goto err;
298     }
299   tdata->cache = bfd_zalloc (abfd, sizeof (bfd *) * tdata->nbr_modules);
300   if (tdata->cache == NULL)
301     goto err;
302
303   /* Read DCX submaps.  */
304   dcxvbn = bfd_getl32 (lhd.dcxmapvbn);
305   if (dcxvbn != 0)
306     {
307       unsigned char buf_reclen[4];
308       unsigned int reclen;
309       unsigned char *buf;
310       struct vms_dcxmap *map;
311       unsigned int sbm_off;
312       unsigned int i;
313
314       if (bfd_seek (abfd, (dcxvbn - 1) * VMS_BLOCK_SIZE, SEEK_SET) != 0
315           || bfd_bread (buf_reclen, sizeof (buf_reclen), abfd)
316           != sizeof (buf_reclen))
317         goto err;
318       reclen = bfd_getl32 (buf_reclen);
319       buf = bfd_malloc (reclen);
320       if (buf == NULL)
321         goto err;
322       if (bfd_bread (buf, reclen, abfd) != reclen)
323         {
324           free (buf);
325           goto err;
326         }
327       map = (struct vms_dcxmap *)buf;
328       tdata->nbr_dcxsbm = bfd_getl16 (map->nsubs);
329       sbm_off = bfd_getl16 (map->sub0);
330       tdata->dcxsbm = (struct dcxsbm_desc *)bfd_alloc
331         (abfd, tdata->nbr_dcxsbm * sizeof (struct dcxsbm_desc));
332       for (i = 0; i < tdata->nbr_dcxsbm; i++)
333         {
334           struct vms_dcxsbm *sbm = (struct vms_dcxsbm *) (buf + sbm_off);
335           struct dcxsbm_desc *sbmdesc = &tdata->dcxsbm[i];
336           unsigned int sbm_len;
337           unsigned int sbm_sz;
338           unsigned char *data = (unsigned char *)sbm;
339           unsigned char *buf1;
340           unsigned int l, j;
341
342           sbm_sz = bfd_getl16 (sbm->size);
343           sbm_off += sbm_sz;
344           BFD_ASSERT (sbm_off <= reclen);
345
346           sbmdesc->min_char = sbm->min_char;
347           BFD_ASSERT (sbmdesc->min_char == 0);
348           sbmdesc->max_char = sbm->max_char;
349           sbm_len = sbmdesc->max_char - sbmdesc->min_char + 1;
350           l = (2 * sbm_len + 7) / 8;
351           BFD_ASSERT (sbm_sz >= sizeof (struct vms_dcxsbm) + l + 3 * sbm_len);
352           sbmdesc->flags = (unsigned char *)bfd_alloc (abfd, l);
353           memcpy (sbmdesc->flags, data + bfd_getl16 (sbm->flags), l);
354           sbmdesc->nodes = (unsigned char *)bfd_alloc (abfd, 2 * sbm_len);
355           memcpy (sbmdesc->nodes, data + bfd_getl16 (sbm->nodes), 2 * sbm_len);
356           sbmdesc->next = (unsigned short *)bfd_alloc
357             (abfd, sbm_len * sizeof (unsigned short));
358           buf1 = data + bfd_getl16 (sbm->next);
359           for (j = 0; j < sbm_len; j++)
360             sbmdesc->next[j] = bfd_getl16 (buf1 + j * 2);
361         }
362       free (buf);
363     }
364   else
365     {
366       tdata->nbr_dcxsbm = 0;
367     }
368
369   /* The map is always present.  Also mark shared image library.  */
370   abfd->has_armap = TRUE;
371   if (tdata->type == LBR__C_TYP_ESHSTB)
372     abfd->is_thin_archive = TRUE;
373
374   return abfd->xvec;
375
376  err:
377   bfd_release (abfd, tdata);
378   abfd->tdata.any = (void *)tdata_hold;;
379   return NULL;
380 }
381
382 /* Standard function for alpha libraries.  */
383
384 const bfd_target *
385 _bfd_vms_lib_alpha_archive_p (bfd *abfd)
386 {
387   return _bfd_vms_lib_archive_p (abfd, vms_lib_alpha);
388 }
389
390 /* Standard function for text libraries.  */
391
392 static const bfd_target *
393 _bfd_vms_lib_txt_archive_p (bfd *abfd)
394 {
395   return _bfd_vms_lib_archive_p (abfd, vms_lib_txt);
396 }
397
398 /* Standard bfd function.  */
399
400 bfd_boolean
401 _bfd_vms_lib_mkarchive (bfd *abfd)
402 {
403   struct lib_tdata *tdata;
404
405   tdata = (struct lib_tdata *) bfd_zalloc (abfd, sizeof (struct lib_tdata));
406   if (tdata == NULL)
407     return FALSE;
408
409   abfd->tdata.any = (void *)tdata;
410   tdata->ver = 3;
411   tdata->mhd_size = sizeof (struct vms_mhd);
412   tdata->type = LBR__C_TYP_EOBJ;
413
414   tdata->nbr_modules = 0;
415   tdata->nbr_syms = 0;
416   tdata->modules = NULL;
417   tdata->syms = NULL;
418   tdata->cache = NULL;
419
420   return TRUE;
421 }
422
423 /* Find NAME in the symbol index.  Return the index.  */
424
425 symindex
426 _bfd_vms_lib_find_symbol (bfd *abfd, const char *name)
427 {
428   struct lib_tdata *tdata = bfd_libdata (abfd);
429   int lo, hi;
430
431   /* Open-coded binary search for speed.  */
432   lo = 0;
433   hi = tdata->nbr_syms - 1;
434
435   while (lo <= hi)
436     {
437       int mid = lo + (hi - lo) / 2;
438       int diff;
439
440       diff = (char)(name[0] - tdata->syms[mid].name[0]);
441       if (diff == 0)
442         diff = strcmp (name, tdata->syms[mid].name);
443       if (diff == 0)
444         return tdata->syms[mid].file_offset;
445       else if (diff < 0)
446         hi = mid - 1;
447       else
448         lo = mid + 1;
449     }
450   return 0;
451 }
452
453 /* IO vector for archive member.  Need that because members are not linearly
454    stored in archives.  */
455
456 struct vms_lib_iovec
457 {
458   /* Current offset.  */
459   ufile_ptr where;
460
461   /* Length of the module, when known.  */
462   ufile_ptr file_len;
463
464   /* Current position in the record from bfd_bread point of view (ie, after
465      decompression).  0 means that no data byte have been read, -2 and -1
466      are reserved for the length word.  */
467   int rec_pos;
468 #define REC_POS_NL   -4
469 #define REC_POS_PAD  -3
470 #define REC_POS_LEN0 -2
471 #define REC_POS_LEN1 -1
472
473   /* Record length.  */
474   unsigned short rec_len;
475   /* Number of bytes to read in the current record.  */
476   unsigned short rec_rem;
477   /* Offset of the next block.  */
478   file_ptr next_block;
479   /* Current *data* offset in the data block.  */
480   unsigned short blk_off;
481
482   /* Offset of the first block.  Extracted from the index.  */
483   file_ptr first_block;
484
485   /* Initial next_block.  Extracted when the MHD is read.  */
486   file_ptr init_next_block;
487   /* Initial blk_off, once the MHD is read.  */
488   unsigned short init_blk_off;
489
490   /* Used to store any 3 byte record, which could be the EOF pattern.  */
491   unsigned char pattern[4];
492
493   /* DCX.  */
494   struct dcxsbm_desc *dcxsbms;
495   /* Current submap.  */
496   struct dcxsbm_desc *dcx_sbm;
497   /* Current offset in the submap.  */
498   unsigned int dcx_offset;
499   int dcx_pos;
500
501   /* Compressed buffer.  */
502   unsigned char *dcx_buf;
503   /* Size of the buffer.  Used to resize.  */
504   unsigned int dcx_max;
505   /* Number of valid bytes in the buffer.  */
506   unsigned int dcx_rlen;
507 };
508
509 /* Return the current position.  */
510
511 static file_ptr
512 vms_lib_btell (struct bfd *abfd)
513 {
514   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
515   return vec->where;
516 }
517
518 /* Read the header of the next data block if all bytes of the current block
519    have been read.  */
520
521 static bfd_boolean
522 vms_lib_read_block (struct bfd *abfd)
523 {
524   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
525
526   if (vec->blk_off == DATA__LENGTH)
527     {
528       unsigned char hdr[DATA__DATA];
529
530       /* Read next block.  */
531       if (bfd_seek (abfd->my_archive, vec->next_block, SEEK_SET) != 0)
532         return FALSE;
533       if (bfd_bread (hdr, sizeof (hdr), abfd->my_archive) != sizeof (hdr))
534         return FALSE;
535       vec->next_block = (bfd_getl32 (hdr + 2) - 1) * VMS_BLOCK_SIZE;
536       vec->blk_off = sizeof (hdr);
537     }
538   return TRUE;
539 }
540
541 /* Read NBYTES from ABFD into BUF if not NULL.  If BUF is NULL, bytes are
542    not stored.  Read linearly from the library, but handle blocks.  This
543    function does not handle records nor EOF.  */
544
545 static file_ptr
546 vms_lib_bread_raw (struct bfd *abfd, void *buf, file_ptr nbytes)
547 {
548   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
549   file_ptr res;
550
551   res = 0;
552   while (nbytes > 0)
553     {
554       unsigned int l;
555
556       /* Be sure the current data block is read.  */
557       if (!vms_lib_read_block (abfd))
558         return -1;
559
560       l = DATA__LENGTH - vec->blk_off;
561       if (l > nbytes)
562         l = nbytes;
563       if (l == 0)
564         return 0;
565       if (buf != NULL)
566         {
567           if (bfd_bread (buf, l, abfd->my_archive) != l)
568             return -1;
569         }
570       else
571         {
572           if (bfd_seek (abfd->my_archive, l, SEEK_CUR) != 0)
573             return -1;
574         }
575
576       if (buf != NULL)
577         buf += l;
578       vec->blk_off += l;
579       nbytes -= l;
580       res += l;
581     }
582   return res;
583 }
584
585 /* Decompress NBYTES from VEC.  Store the bytes into BUF if not NULL.  */
586
587 static file_ptr
588 vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
589 {
590   struct dcxsbm_desc *sbm;
591   unsigned int i;
592   unsigned int offset;
593   unsigned int j;
594   file_ptr res = 0;
595
596   /* The loop below expect to deliver at least one byte.  */
597   if (nbytes == 0)
598     return 0;
599
600   /* Get the current state.  */
601   sbm = vec->dcx_sbm;
602   offset = vec->dcx_offset;
603   j = vec->dcx_pos & 7;
604
605   for (i = vec->dcx_pos >> 3; i < vec->dcx_rlen; i++)
606     {
607       unsigned char b = vec->dcx_buf[i];
608
609       for (; j < 8; j++)
610         {
611           if (b & (1 << j))
612             offset++;
613           if (!(sbm->flags[offset >> 3] & (1 << (offset & 7))))
614             {
615               unsigned int n_offset = sbm->nodes[offset];
616               if (n_offset == 0)
617                 {
618                   /* End of buffer.  Stay where we are.  */
619                   vec->dcx_pos = (i << 3) + j;
620                   if (b & (1 << j))
621                     offset--;
622                   vec->dcx_offset = offset;
623                   vec->dcx_sbm = sbm;
624                   return res;
625                 }
626               offset = 2 * n_offset;
627             }
628           else
629             {
630               unsigned char v = sbm->nodes[offset];
631
632               sbm = vec->dcxsbms + sbm->next[v];
633               offset = 0;
634               res++;
635
636               if (buf)
637                 {
638                   *buf++ = v;
639                   nbytes--;
640
641                   if (nbytes == 0)
642                     {
643                       vec->dcx_pos = (i << 3) + j + 1;
644                       vec->dcx_offset = offset;
645                       vec->dcx_sbm = sbm;
646
647                       return res;
648                     }
649                 }
650             }
651         }
652       j = 0;
653     }
654   return -1;
655 }
656
657 /* Standard IOVEC function.  */
658
659 static file_ptr
660 vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
661 {
662   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
663   file_ptr res;
664   file_ptr chunk;
665
666   /* Do not read past the end.  */
667   if (vec->where >= vec->file_len)
668     return 0;
669
670   res = 0;
671   while (nbytes > 0)
672     {
673       if (vec->rec_rem == 0)
674         {
675           unsigned char blen[2];
676
677           /* Read record length.  */
678           if (vms_lib_bread_raw (abfd, &blen, sizeof (blen)) != sizeof (blen))
679             return -1;
680           vec->rec_len = bfd_getl16 (blen);
681           if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
682             {
683               /* Discard record size and align byte.  */
684               vec->rec_pos = 0;
685               vec->rec_rem = vec->rec_len;
686             }
687           else
688             {
689               /* Prepend record size.  */
690               vec->rec_pos = REC_POS_LEN0;
691               vec->rec_rem = (vec->rec_len + 1) & ~1;   /* With align byte.  */
692             }
693           if (vec->rec_len == 3)
694             {
695               /* Possibly end of file.  Check the pattern.  */
696               if (vms_lib_bread_raw (abfd, vec->pattern, 4) != 4)
697                 return -1;
698               if (!memcmp (vec->pattern, eotdesc + 2, 3))
699                 {
700                   /* This is really an EOF.  */
701                   vec->where += res;
702                   vec->file_len = vec->where;
703                   return res;
704                 }
705             }
706
707           if (vec->dcxsbms != NULL)
708             {
709               /* This is a compressed member.  */
710               unsigned int len;
711               file_ptr elen;
712
713               /* Be sure there is enough room for the expansion.  */
714               len = (vec->rec_len + 1) & ~1;
715               if (len > vec->dcx_max)
716                 {
717                   while (len > vec->dcx_max)
718                     vec->dcx_max *= 2;
719                   vec->dcx_buf = bfd_alloc (abfd, vec->dcx_max);
720                   if (vec->dcx_buf == NULL)
721                     return -1;
722                 }
723
724               /* Read the compressed record.  */
725               vec->dcx_rlen = len;
726               if (vec->rec_len == 3)
727                 {
728                   /* Already read.  */
729                   memcpy (vec->dcx_buf, vec->pattern, 3);
730                 }
731               else
732                 {
733                   elen = vms_lib_bread_raw (abfd, vec->dcx_buf, len);
734                   if (elen != len)
735                     return -1;
736                 }
737
738               /* Dummy expansion to get the expanded length.  */
739               vec->dcx_offset = 0;
740               vec->dcx_sbm = vec->dcxsbms;
741               vec->dcx_pos = 0;
742               elen = vms_lib_dcx (vec, NULL, 0x10000);
743               if (elen < 0)
744                 return -1;
745               vec->rec_len = elen;
746               vec->rec_rem = elen;
747
748               /* Reset the state.  */
749               vec->dcx_offset = 0;
750               vec->dcx_sbm = vec->dcxsbms;
751               vec->dcx_pos = 0;
752             }
753         }
754       if (vec->rec_pos < 0)
755         {
756           unsigned char c;
757           switch (vec->rec_pos)
758             {
759             case REC_POS_LEN0:
760               c = vec->rec_len & 0xff;
761               vec->rec_pos = REC_POS_LEN1;
762               break;
763             case REC_POS_LEN1:
764               c = (vec->rec_len >> 8) & 0xff;
765               vec->rec_pos = 0;
766               break;
767             case REC_POS_PAD:
768               c = 0;
769               vec->rec_rem = 0;
770               break;
771             case REC_POS_NL:
772               c = '\n';
773               vec->rec_rem = 0;
774               break;
775             default:
776               abort ();
777             }
778           if (buf != NULL)
779             {
780               *(unsigned char *)buf = c;
781               buf++;
782             }
783           nbytes--;
784           res++;
785           continue;
786         }
787
788       if (nbytes > vec->rec_rem)
789         chunk = vec->rec_rem;
790       else
791         chunk = nbytes;
792
793       if (vec->dcxsbms != NULL)
794         {
795           /* Optimize the stat() case: no need to decompress again as we
796              know the length.  */
797           if (!(buf == NULL && chunk == vec->rec_rem))
798             chunk = vms_lib_dcx (vec, buf, chunk);
799         }
800       else
801         {
802           if (vec->rec_len == 3)
803             {
804               if (buf != NULL)
805                 memcpy (buf, vec->pattern + vec->rec_pos, chunk);
806             }
807           else
808             chunk = vms_lib_bread_raw (abfd, buf, chunk);
809         }
810       if (chunk < 0)
811         return -1;
812       res += chunk;
813       if (buf != NULL)
814         buf += chunk;
815       nbytes -= chunk;
816       vec->rec_pos += chunk;
817       vec->rec_rem -= chunk;
818
819       if (vec->rec_rem == 0)
820         {
821           if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
822             {
823               if ((vec->rec_len & 1) == 1
824                   && vec->rec_len != 3
825                   && vec->dcxsbms == NULL)
826                 {
827                   /* Eat the pad byte.  */
828                   unsigned char pad;
829                   if (vms_lib_bread_raw (abfd, &pad, 1) != 1)
830                     return -1;
831                 }
832               vec->rec_pos = REC_POS_NL;
833               vec->rec_rem = 1;
834             }
835           else
836             {
837               if ((vec->rec_len & 1) == 1 && vec->dcxsbms != NULL)
838                 {
839                   vec->rec_pos = REC_POS_PAD;
840                   vec->rec_rem = 1;
841                 }
842             }
843         }
844     }
845   vec->where += res;
846   return res;
847 }
848
849 /* Standard function, but we currently only handle the rewind case.  */
850
851 static int
852 vms_lib_bseek (struct bfd *abfd, file_ptr offset, int whence)
853 {
854   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
855
856   if (whence == SEEK_SET && offset == 0)
857     {
858       vec->where = 0;
859       vec->rec_rem = 0;
860       vec->dcx_pos = -1;
861       vec->blk_off = vec->init_blk_off;
862       vec->next_block = vec->init_next_block;
863
864       if (bfd_seek (abfd->my_archive, vec->first_block, SEEK_SET) != 0)
865         return -1;
866     }
867   else
868     abort ();
869   return 0;
870 }
871
872 static file_ptr
873 vms_lib_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
874               const void *where ATTRIBUTE_UNUSED,
875               file_ptr nbytes ATTRIBUTE_UNUSED)
876 {
877   return -1;
878 }
879
880 static int
881 vms_lib_bclose (struct bfd *abfd)
882 {
883   abfd->iostream = NULL;
884   return 0;
885 }
886
887 static int
888 vms_lib_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
889 {
890   return 0;
891 }
892
893 static int
894 vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
895                struct stat *sb ATTRIBUTE_UNUSED)
896 {
897   /* Not supported.  */
898   return 0;
899 }
900
901 static void *
902 vms_lib_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
903               void *addr ATTRIBUTE_UNUSED,
904               bfd_size_type len ATTRIBUTE_UNUSED,
905               int prot ATTRIBUTE_UNUSED,
906               int flags ATTRIBUTE_UNUSED,
907               file_ptr offset ATTRIBUTE_UNUSED)
908 {
909   return (void *) -1;
910 }
911
912 static const struct bfd_iovec vms_lib_iovec = {
913   &vms_lib_bread, &vms_lib_bwrite, &vms_lib_btell, &vms_lib_bseek,
914   &vms_lib_bclose, &vms_lib_bflush, &vms_lib_bstat, &vms_lib_bmmap
915 };
916
917 /* Open a library module.  FILEPOS is the position of the module header.  */
918
919 static bfd_boolean
920 vms_lib_bopen (bfd *el, file_ptr filepos)
921 {
922   struct vms_lib_iovec *vec;
923   char buf[256];
924   struct vms_mhd *mhd;
925   struct lib_tdata *tdata = bfd_libdata (el->my_archive);
926   unsigned int len;
927
928   /* Allocate and initialized the iovec.  */
929   vec = bfd_zalloc (el, sizeof (*vec));
930   if (vec == NULL)
931     return FALSE;
932
933   el->iostream = vec;
934   el->iovec = &vms_lib_iovec;
935
936   /* File length is not known.  */
937   vec->file_len = -1;
938
939   /* Read the first data block.  */
940   vec->next_block = filepos & ~(VMS_BLOCK_SIZE - 1);
941   vec->blk_off = DATA__LENGTH;
942   if (!vms_lib_read_block (el))
943     return FALSE;
944
945   /* Prepare to read the first record.  */
946   vec->blk_off = filepos & (VMS_BLOCK_SIZE - 1);
947   vec->rec_rem = 0;
948   if (bfd_seek (el->my_archive, filepos, SEEK_SET) != 0)
949     return FALSE;
950
951   /* Read Record length + MHD + align byte.  */
952   len = tdata->mhd_size;
953   if (vms_lib_bread_raw (el, buf, 2) != 2)
954     return -1;
955   if (bfd_getl16 (buf) != len)
956     return -1;
957   len = (len + 1) & ~1;
958   BFD_ASSERT (len <= sizeof (buf));
959   if (vms_lib_bread_raw (el, buf, len) != len)
960     return -1;
961
962   /* Get info from mhd.  */
963   mhd = (struct vms_mhd *)buf;
964   if (len >= sizeof (struct vms_mhd))
965     el->selective_search = (mhd->objstat & MHD__M_SELSRC) ? 1 : 0;
966   el->mtime = vms_rawtime_to_time_t (mhd->datim);
967   el->mtime_set = TRUE;
968
969   /* Reinit the iovec so that seek() will point to the first record after
970      the mhd.  */
971   vec->where = 0;
972   vec->init_blk_off = vec->blk_off;
973   vec->init_next_block = vec->next_block;
974   vec->first_block = bfd_tell (el->my_archive);
975   vec->dcxsbms = bfd_libdata (el->my_archive)->dcxsbm;
976
977   if (vec->dcxsbms != NULL)
978     {
979       /* Handle DCX.  */
980       vec->dcx_max = 10 * 1024;
981       vec->dcx_buf = bfd_alloc (el, vec->dcx_max);
982       vec->dcx_pos = -1;
983       if (vec->dcx_buf == NULL)
984         return -1;
985     }
986   return TRUE;
987 }
988
989 /* Standard function: get member at IDX.  */
990
991 bfd *
992 _bfd_vms_lib_get_elt_at_index (bfd *abfd, symindex idx)
993 {
994   struct lib_tdata *tdata = bfd_libdata (abfd);
995   bfd *res;
996   unsigned int i;
997
998   /* Linear-scan.  */
999   for (i = 0; i < tdata->nbr_modules; i++)
1000     {
1001       if (tdata->modules[i].file_offset == (file_ptr)idx)
1002         break;
1003     }
1004
1005   /* Invalid index.  */
1006   if (i >= tdata->nbr_modules)
1007     return NULL;
1008
1009   /* Already loaded.  */
1010   if (tdata->cache[i])
1011     return tdata->cache[i];
1012
1013   /* Build it.  */
1014   res = _bfd_create_empty_archive_element_shell (abfd);
1015   if (!vms_lib_bopen (res, idx))
1016     return NULL;
1017   res->filename = tdata->modules[i].name;
1018
1019   tdata->cache[i] = res;
1020
1021   return res;
1022 }
1023
1024 /* Elements of an imagelib are stubs.  You can get the real image with this
1025    function.  */
1026
1027 bfd *
1028 _bfd_vms_lib_get_imagelib_file (bfd *el)
1029 {
1030   bfd *archive = el->my_archive;
1031   const char *modname = el->filename;
1032   int modlen = strlen (modname);
1033   char *filename;
1034   int j;
1035   bfd *res;
1036
1037   /* Convert module name to lower case and append '.exe'.  */
1038   filename = bfd_alloc (el, modlen + 5);
1039   if (filename == NULL)
1040     return NULL;
1041   for (j = 0; j < modlen; j++)
1042     if (ISALPHA (modname[j]))
1043       filename[j] = TOLOWER (modname[j]);
1044     else
1045       filename[j] = modname[j];
1046   memcpy (filename + modlen, ".exe", 5);
1047
1048   filename = _bfd_append_relative_path (archive, filename);
1049   if (filename == NULL)
1050     return NULL;
1051   res = bfd_openr (filename, NULL);
1052
1053   if (res == NULL)
1054     {
1055       (*_bfd_error_handler)(_("could not open shared image '%s' from '%s'"),
1056                             filename, archive->filename);
1057       bfd_release (archive, filename);
1058       return NULL;
1059     }
1060
1061   /* FIXME: put it in a cache ?  */
1062   return res;
1063 }
1064
1065 /* Standard function.  */
1066
1067 bfd *
1068 _bfd_vms_lib_openr_next_archived_file (bfd *archive,
1069                                        bfd *last_file)
1070 {
1071   unsigned int idx;
1072   bfd *res;
1073
1074   if (!last_file)
1075     idx = 0;
1076   else
1077     idx = last_file->proxy_origin + 1;
1078
1079   if (idx >= bfd_libdata (archive)->nbr_modules)
1080     {
1081       bfd_set_error (bfd_error_no_more_archived_files);
1082       return NULL;
1083     }
1084
1085   res = _bfd_vms_lib_get_elt_at_index
1086     (archive, bfd_libdata (archive)->modules[idx].file_offset);
1087   if (res == NULL)
1088     return res;
1089   res->proxy_origin = idx;
1090   return res;
1091 }
1092
1093 /* Standard function.  Just compute the length.  */
1094
1095 int
1096 _bfd_vms_lib_generic_stat_arch_elt (bfd *abfd, struct stat *st)
1097 {
1098   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1099
1100   if (abfd->my_archive == NULL)
1101     {
1102       bfd_set_error (bfd_error_invalid_operation);
1103       return -1;
1104     }
1105
1106   if (vec->file_len == (ufile_ptr)-1)
1107     {
1108       if (vms_lib_bseek (abfd, 0, SEEK_SET) != 0)
1109         return -1;
1110
1111       /* Compute length.  */
1112       while (vms_lib_bread (abfd, NULL, 1 << 20) > 0)
1113         ;
1114     }
1115
1116   st->st_size = vec->file_len;
1117   if (abfd->mtime_set)
1118     st->st_mtime = abfd->mtime;
1119   else
1120     st->st_mtime = 0;
1121   st->st_uid = 0;
1122   st->st_gid = 0;
1123   st->st_mode = 0644;
1124
1125   return 0;
1126 }
1127
1128 /* Internal representation of an index entry.  */
1129
1130 struct vms_index
1131 {
1132   /* Corresponding archive member.  */
1133   bfd *abfd;
1134
1135   /* Number of reference to this entry.  */
1136   unsigned int ref;
1137
1138   /* Length of the key.  */
1139   unsigned short namlen;
1140
1141   /* Key.  */
1142   const char *name;
1143 };
1144
1145 /* Used to sort index entries.  */
1146
1147 static int
1148 vms_index_cmp (const void *lv, const void *rv)
1149 {
1150   const struct vms_index *l = lv;
1151   const struct vms_index *r = rv;
1152
1153   return strcmp (l->name, r->name);
1154 }
1155
1156 /* Maximum number of index blocks level.  */
1157
1158 #define MAX_LEVEL 10
1159
1160 /* Get the size of an index entry.  */
1161
1162 static unsigned int
1163 get_idxlen (struct vms_index *idx)
1164 {
1165   return 7 + idx->namlen;
1166 }
1167
1168 /* Write the index.  VBN is the first vbn to be used, and will contain
1169    on return the last vbn.
1170    Return TRUE on success.  */
1171
1172 static bfd_boolean
1173 vms_write_index (bfd *abfd,
1174                  struct vms_index *idx, unsigned int nbr, unsigned int *vbn,
1175                  unsigned int *topvbn)
1176 {
1177   unsigned int i;
1178   int j;
1179   int level;
1180   struct vms_indexdef *rblk[MAX_LEVEL];
1181   struct idxblk
1182   {
1183     unsigned int vbn;
1184     unsigned short len;
1185     unsigned short lastlen;
1186   } blk[MAX_LEVEL];
1187
1188   if (nbr == 0)
1189     {
1190       if (topvbn != NULL)
1191         *topvbn = 0;
1192       return TRUE;
1193     }
1194
1195   if (abfd == NULL)
1196     {
1197       /* Sort the index the first time this function is called.  */
1198       qsort (idx, nbr, sizeof (struct vms_index), vms_index_cmp);
1199     }
1200
1201   /* Allocate first index block.  */
1202   level = 1;
1203   if (abfd != NULL)
1204     rblk[0] = bfd_malloc (sizeof (struct vms_indexdef));
1205   blk[0].vbn = (*vbn)++;
1206   blk[0].len = 0;
1207   blk[0].lastlen = 0;
1208
1209   for (i = 0; i < nbr; i++, idx++)
1210     {
1211       unsigned int idxlen = get_idxlen (idx);
1212       struct vms_idxdef *en;
1213       int flush = 0;
1214
1215       /* Check if a block might overflow.  In this case we will flush this
1216          block and all the blocks below it.  */
1217       for (j = 0; j < level; j++)
1218         if (blk[j].len + blk[j].lastlen + idxlen > INDEXDEF__BLKSIZ)
1219           flush = j + 1;
1220
1221       for (j = 0; j < level; j++)
1222         {
1223           if (j < flush)
1224             {
1225               /* There is not enough room to write the new entry in this
1226                  block or in a parent block.  */
1227
1228               if (j + 1 == level)
1229                 {
1230                   BFD_ASSERT (level < MAX_LEVEL);
1231
1232                   /* Need to create a parent.  */
1233                   if (abfd != NULL)
1234                     {
1235                       rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
1236                       bfd_putl32 (*vbn, rblk[j]->parent);
1237                     }
1238                   blk[level].vbn = (*vbn)++;
1239                   blk[level].len = 0;
1240                   blk[level].lastlen = 0;
1241
1242                   level++;
1243                 }
1244
1245               /* Update parent block: write the new entry.  */
1246               if (abfd != NULL)
1247                 {
1248                   en = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1249                   memcpy (rblk[j + 1]->keys + blk[j + 1].len, en,
1250                           blk[j].lastlen);
1251                   en = (struct vms_idxdef *)
1252                     (rblk[j + 1]->keys + blk[j + 1].len);
1253                   bfd_putl32 (blk[j].vbn, en->vbn);
1254                   bfd_putl16 (RFADEF__C_INDEX, en->offset);
1255                 }
1256
1257               if (j + 1 == flush)
1258                 {
1259                   /* And allocate it.  Do it only on the block that won't be
1260                      flushed (so that the parent of the parent can be
1261                      updated too).  */
1262                   blk[j + 1].len += blk[j].lastlen;
1263                   blk[j + 1].lastlen = 0;
1264                 }
1265
1266               /* Write this block on the disk.  */
1267               if (abfd != NULL)
1268                 {
1269                   bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1270                   if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1271                                 SEEK_SET) != 0)
1272                     return FALSE;
1273                   if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1274                       != sizeof (struct vms_indexdef))
1275                     return FALSE;
1276                 }
1277
1278               /* Reset this block.  */
1279               blk[j].len = 0;
1280               blk[j].lastlen = 0;
1281               blk[j].vbn = (*vbn)++;
1282             }
1283
1284           /* Append it to the block.  */
1285           if (j == 0)
1286             {
1287               blk[j].len += blk[j].lastlen;
1288
1289               if (abfd != NULL)
1290                 {
1291                   en = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1292                   bfd_putl32 ((idx->abfd->proxy_origin / VMS_BLOCK_SIZE) + 1,
1293                               en->vbn);
1294                   bfd_putl16
1295                     ((idx->abfd->proxy_origin % VMS_BLOCK_SIZE) + DATA__DATA,
1296                      en->offset);
1297                   en->keylen = idx->namlen;
1298                   memcpy (en->keyname, idx->name, idx->namlen);
1299                 }
1300             }
1301
1302           blk[j].lastlen = idxlen;
1303         }
1304     }
1305
1306   if (topvbn != NULL)
1307     *topvbn = blk[level - 1].vbn;
1308
1309   if (abfd == NULL)
1310     return TRUE;
1311
1312   /* Flush.  */
1313   for (j = 0; j < level; j++)
1314     {
1315       if (j > 0)
1316         {
1317           /* Update parent block: write the new entry.  */
1318           struct vms_idxdef *en;
1319           struct vms_idxdef *par;
1320
1321           en = (struct vms_idxdef *)(rblk[j - 1]->keys + blk[j - 1].len);
1322           par = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1323           memcpy (par, en, blk[j - 1].lastlen);
1324           bfd_putl32 (blk[j - 1].vbn, par->vbn);
1325           bfd_putl16 (RFADEF__C_INDEX, par->offset);
1326         }
1327
1328       /* Write this block on the disk.  */
1329       bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1330       if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1331                     SEEK_SET) != 0)
1332         return FALSE;
1333       if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1334           != sizeof (struct vms_indexdef))
1335         return FALSE;
1336
1337       free (rblk[j]);
1338     }
1339
1340   return TRUE;
1341 }
1342
1343 /* Append data to the data block DATA.  Force write if PAD is true.  */
1344
1345 static bfd_boolean
1346 vms_write_data_block (bfd *arch, struct vms_datadef *data, file_ptr *off,
1347                       const unsigned char *buf, unsigned int len, int pad)
1348 {
1349   while (len > 0 || pad)
1350     {
1351       unsigned int doff = *off & (VMS_BLOCK_SIZE - 1);
1352       unsigned int remlen = (DATA__LENGTH - DATA__DATA) - doff;
1353       unsigned int l;
1354
1355       l = (len > remlen) ? remlen : len;
1356       memcpy (data->data + doff, buf, l);
1357       buf += l;
1358       len -= l;
1359       doff += l;
1360       *off += l;
1361
1362       if (doff == (DATA__LENGTH - DATA__DATA) || (len == 0 && pad))
1363         {
1364           data->recs = 0;
1365           data->fill_1 = 0;
1366           bfd_putl32 ((*off / VMS_BLOCK_SIZE) + 2, data->link);
1367
1368           if (bfd_bwrite (data, sizeof (*data), arch) != sizeof (*data))
1369             return FALSE;
1370
1371           *off += DATA__LENGTH - doff;
1372
1373           if (len == 0)
1374             break;
1375         }
1376     }
1377   return TRUE;
1378 }
1379
1380 /* Build the symbols index.  */
1381
1382 static bfd_boolean
1383 _bfd_vms_lib_build_map (unsigned int nbr_modules,
1384                         struct vms_index *modules,
1385                         unsigned int *res_cnt,
1386                         struct vms_index **res)
1387 {
1388   unsigned int i;
1389   asymbol **syms = NULL;
1390   long syms_max = 0;
1391   struct vms_index *map = NULL;
1392   unsigned int map_max = 1024;          /* Fine initial default.  */
1393   unsigned int map_count = 0;
1394
1395   map = (struct vms_index *) bfd_malloc (map_max * sizeof (struct vms_index));
1396   if (map == NULL)
1397     goto error_return;
1398
1399   /* Gather symbols.  */
1400   for (i = 0; i < nbr_modules; i++)
1401     {
1402       long storage;
1403       long symcount;
1404       long src_count;
1405       bfd *current = modules[i].abfd;
1406
1407       if ((bfd_get_file_flags (current) & HAS_SYMS) == 0)
1408         continue;
1409
1410       storage = bfd_get_symtab_upper_bound (current);
1411       if (storage < 0)
1412         goto error_return;
1413
1414       if (storage != 0)
1415         {
1416           if (storage > syms_max)
1417             {
1418               if (syms_max > 0)
1419                 free (syms);
1420               syms_max = storage;
1421               syms = (asymbol **) bfd_malloc (syms_max);
1422               if (syms == NULL)
1423                 goto error_return;
1424             }
1425           symcount = bfd_canonicalize_symtab (current, syms);
1426           if (symcount < 0)
1427             goto error_return;
1428
1429           /* Now map over all the symbols, picking out the ones we
1430              want.  */
1431           for (src_count = 0; src_count < symcount; src_count++)
1432             {
1433               flagword flags = (syms[src_count])->flags;
1434               asection *sec = syms[src_count]->section;
1435
1436               if ((flags & BSF_GLOBAL
1437                    || flags & BSF_WEAK
1438                    || flags & BSF_INDIRECT
1439                    || bfd_is_com_section (sec))
1440                   && ! bfd_is_und_section (sec))
1441                 {
1442                   struct vms_index *new_map;
1443
1444                   /* This symbol will go into the archive header.  */
1445                   if (map_count == map_max)
1446                     {
1447                       map_max *= 2;
1448                       new_map = (struct vms_index *)
1449                         bfd_realloc (map, map_max * sizeof (struct vms_index));
1450                       if (new_map == NULL)
1451                         goto error_return;
1452                       map = new_map;
1453                     }
1454
1455                   map[map_count].abfd = current;
1456                   /* FIXME: check length.  */
1457                   map[map_count].namlen = strlen (syms[src_count]->name);
1458                   map[map_count].name = syms[src_count]->name;
1459                   map_count++;
1460                   modules[i].ref++;
1461                 }
1462             }
1463         }
1464     }
1465
1466   *res_cnt = map_count;
1467   *res = map;
1468   return TRUE;
1469
1470  error_return:
1471   if (syms_max > 0)
1472     free (syms);
1473   if (map != NULL)
1474     free (map);
1475   return FALSE;
1476 }
1477
1478 /* Do the hard work: write an archive on the disk.  */
1479
1480 bfd_boolean
1481 _bfd_vms_lib_write_archive_contents (bfd *arch)
1482 {
1483   bfd *current;
1484   unsigned int nbr_modules;
1485   struct vms_index *modules;
1486   unsigned int nbr_symbols;
1487   struct vms_index *symbols;
1488   struct lib_tdata *tdata = bfd_libdata (arch);
1489   unsigned int i;
1490   file_ptr off;
1491   unsigned int nbr_mod_iblk;
1492   unsigned int nbr_sym_iblk;
1493   unsigned int vbn;
1494   unsigned int mod_idx_vbn;
1495   unsigned int sym_idx_vbn;
1496
1497   /* Count the number of modules (and do a first sanity check).  */
1498   nbr_modules = 0;
1499   for (current = arch->archive_head;
1500        current != NULL;
1501        current = current->archive_next)
1502     {
1503       /* This check is checking the bfds for the objects we're reading
1504          from (which are usually either an object file or archive on
1505          disk), not the archive entries we're writing to.  We don't
1506          actually create bfds for the archive members, we just copy
1507          them byte-wise when we write out the archive.  */
1508       if (bfd_write_p (current) || !bfd_check_format (current, bfd_object))
1509         {
1510           bfd_set_error (bfd_error_invalid_operation);
1511           goto input_err;
1512         }
1513
1514       nbr_modules++;
1515     }
1516
1517   /* Build the modules list.  */
1518   BFD_ASSERT (tdata->modules == NULL);
1519   modules = bfd_alloc (arch, nbr_modules * sizeof (struct vms_index));
1520   if (modules == NULL)
1521     return FALSE;
1522
1523   for (current = arch->archive_head, i = 0;
1524        current != NULL;
1525        current = current->archive_next, i++)
1526     {
1527       int nl;
1528
1529       modules[i].abfd = current;
1530       modules[i].name = vms_get_module_name (current->filename, FALSE);
1531       modules[i].ref = 1;
1532
1533       /* FIXME: silently truncate long names ?  */
1534       nl = strlen (modules[i].name);
1535       modules[i].namlen = (nl > MAX_KEYLEN ? MAX_KEYLEN : nl);
1536     }
1537
1538   /* Create the module index.  */
1539   vbn = 0;
1540   if (!vms_write_index (NULL, modules, nbr_modules, &vbn, NULL))
1541     return FALSE;
1542   nbr_mod_iblk = vbn;
1543
1544   /* Create symbol index.  */
1545   if (!_bfd_vms_lib_build_map (nbr_modules, modules, &nbr_symbols, &symbols))
1546     return FALSE;
1547
1548   vbn = 0;
1549   if (!vms_write_index (NULL, symbols, nbr_symbols, &vbn, NULL))
1550     return FALSE;
1551   nbr_sym_iblk = vbn;
1552
1553   /* Write modules and remember their position.  */
1554   off = (1 + nbr_mod_iblk + nbr_sym_iblk) * VMS_BLOCK_SIZE;
1555
1556   if (bfd_seek (arch, off, SEEK_SET) != 0)
1557     return FALSE;
1558
1559   for (i = 0; i < nbr_modules; i++)
1560     {
1561       struct vms_datadef data;
1562       unsigned char blk[VMS_BLOCK_SIZE];
1563       struct vms_mhd *mhd;
1564       unsigned int sz;
1565
1566       current = modules[i].abfd;
1567       current->proxy_origin = off;
1568
1569       bfd_putl16 (sizeof (struct vms_mhd), blk);
1570       mhd = (struct vms_mhd *)(blk + 2);
1571       memset (mhd, 0, sizeof (struct vms_mhd));
1572       mhd->lbrflag = 0;
1573       mhd->id = MHD__C_MHDID;
1574       mhd->objidlng = 4;
1575       memcpy (mhd->objid, "V1.0", 4);
1576       bfd_putl32 (modules[i].ref, mhd->refcnt);
1577       /* FIXME: datim.  */
1578
1579       sz = (2 + sizeof (struct vms_mhd) + 1) & ~1;
1580       if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1581         goto input_err;
1582
1583       if (bfd_seek (current, 0, SEEK_SET) != 0)
1584         goto input_err;
1585
1586       while (1)
1587         {
1588           sz = bfd_bread (blk, sizeof (blk), current);
1589           if (sz == 0)
1590             break;
1591           if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1592             goto input_err;
1593         }
1594       if (vms_write_data_block (arch, &data, &off,
1595                                 eotdesc, sizeof (eotdesc), 1) < 0)
1596         goto input_err;
1597     }
1598
1599   /* Write the indexes.  */
1600   vbn = 2;
1601   if (vms_write_index (arch, modules, nbr_modules, &vbn, &mod_idx_vbn) != TRUE)
1602     return FALSE;
1603   if (vms_write_index (arch, symbols, nbr_symbols, &vbn, &sym_idx_vbn) != TRUE)
1604     return FALSE;
1605
1606   /* Write libary header.  */
1607   {
1608     unsigned char blk[VMS_BLOCK_SIZE];
1609     struct vms_lhd *lhd = (struct vms_lhd *)blk;
1610     struct vms_idd *idd = (struct vms_idd *)(blk + sizeof (*lhd));
1611
1612     memset (blk, 0, sizeof (blk));
1613
1614     lhd->type = LBR__C_TYP_EOBJ;
1615     lhd->nindex = 2;
1616     bfd_putl32 (LHD_SANEID3, lhd->sanity);
1617     bfd_putl16 (3, lhd->majorid);
1618     bfd_putl16 (0, lhd->minorid);
1619     snprintf ((char *)lhd->lbrver + 1, sizeof (lhd->lbrver) - 1,
1620               "GNU ar %u.%u.%u",
1621               (unsigned)(BFD_VERSION / 100000000UL),
1622               (unsigned)(BFD_VERSION / 1000000UL) % 100,
1623               (unsigned)(BFD_VERSION / 10000UL) % 100);
1624     lhd->lbrver[sizeof (lhd->lbrver) - 1] = 0;
1625     lhd->lbrver[0] = strlen ((char *)lhd->lbrver + 1);
1626
1627     /* FIXME.  */
1628     bfd_putl64 (0, lhd->credat);
1629     bfd_putl64 (0, lhd->updtim);
1630
1631     lhd->mhdusz = sizeof (struct vms_mhd) - MHD__C_USRDAT;
1632
1633     bfd_putl32 (nbr_modules + nbr_symbols, lhd->idxcnt);
1634     bfd_putl32 (nbr_modules, lhd->modcnt);
1635     bfd_putl32 (nbr_modules, lhd->modhdrs);
1636
1637     bfd_putl32 (vbn - 1, lhd->hipreal);
1638     bfd_putl32 (vbn - 1, lhd->hiprusd);
1639
1640     /* First index (modules name).  */
1641     bfd_putl16 (IDD__FLAGS_ASCII | IDD__FLAGS_VARLENIDX, idd->flags);
1642     bfd_putl16 (MAX_KEYLEN, idd->keylen);
1643     bfd_putl16 (mod_idx_vbn, idd->vbn);
1644     idd++;
1645
1646     /* Second index (symbols name).  */
1647     bfd_putl16 (IDD__FLAGS_ASCII | IDD__FLAGS_VARLENIDX, idd->flags);
1648     bfd_putl16 (MAX_KEYLEN, idd->keylen);
1649     bfd_putl16 (sym_idx_vbn, idd->vbn);
1650     idd++;
1651
1652     if (bfd_seek (arch, 0, SEEK_SET) != 0)
1653       return FALSE;
1654     if (bfd_bwrite (blk, sizeof (blk), arch) != sizeof (blk))
1655       return FALSE;
1656   }
1657
1658   return TRUE;
1659
1660  input_err:
1661   bfd_set_error (bfd_error_on_input, current, bfd_get_error ());
1662   return FALSE;
1663 }
1664
1665 /* Add a target for text library.  This costs almost nothing and is useful to
1666    read VMS library on the host.  */
1667
1668 const bfd_target vms_lib_txt_vec =
1669 {
1670   "vms-libtxt",                 /* Name.  */
1671   bfd_target_unknown_flavour,
1672   BFD_ENDIAN_UNKNOWN,           /* byteorder */
1673   BFD_ENDIAN_UNKNOWN,           /* header_byteorder */
1674   0,                            /* Object flags.  */
1675   0,                            /* Sect flags.  */
1676   0,                            /* symbol_leading_char.  */
1677   ' ',                          /* ar_pad_char.  */
1678   15,                           /* ar_max_namelen.  */
1679   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1680   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1681   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
1682   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1683   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1684   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
1685
1686   {_bfd_dummy_target, _bfd_dummy_target,        /* bfd_check_format.  */
1687    _bfd_vms_lib_txt_archive_p, _bfd_dummy_target},
1688   {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_set_format.  */
1689   {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_write_contents.  */
1690
1691   BFD_JUMP_TABLE_GENERIC (_bfd_generic),
1692   BFD_JUMP_TABLE_COPY (_bfd_generic),
1693   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1694   BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib),
1695   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
1696   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1697   BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
1698   BFD_JUMP_TABLE_LINK (_bfd_nolink),
1699   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1700
1701   NULL,
1702
1703   (PTR) 0
1704 };