d05fab70818cc83c3c290ba0b236fd4f0de97cd6
[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       /* Do not read past the data block, do not read more than requested.  */
561       l = DATA__LENGTH - vec->blk_off;
562       if (l > nbytes)
563         l = nbytes;
564       if (l == 0)
565         return 0;
566       if (buf != NULL)
567         {
568           /* Really read into BUF.  */
569           if (bfd_bread (buf, l, abfd->my_archive) != l)
570             return -1;
571         }
572       else
573         {
574           /* Make as if we are reading.  */
575           if (bfd_seek (abfd->my_archive, l, SEEK_CUR) != 0)
576             return -1;
577         }
578
579       if (buf != NULL)
580         buf += l;
581       vec->blk_off += l;
582       nbytes -= l;
583       res += l;
584     }
585   return res;
586 }
587
588 /* Decompress NBYTES from VEC.  Store the bytes into BUF if not NULL.  */
589
590 static file_ptr
591 vms_lib_dcx (struct vms_lib_iovec *vec, unsigned char *buf, file_ptr nbytes)
592 {
593   struct dcxsbm_desc *sbm;
594   unsigned int i;
595   unsigned int offset;
596   unsigned int j;
597   file_ptr res = 0;
598
599   /* The loop below expect to deliver at least one byte.  */
600   if (nbytes == 0)
601     return 0;
602
603   /* Get the current state.  */
604   sbm = vec->dcx_sbm;
605   offset = vec->dcx_offset;
606   j = vec->dcx_pos & 7;
607
608   for (i = vec->dcx_pos >> 3; i < vec->dcx_rlen; i++)
609     {
610       unsigned char b = vec->dcx_buf[i];
611
612       for (; j < 8; j++)
613         {
614           if (b & (1 << j))
615             offset++;
616           if (!(sbm->flags[offset >> 3] & (1 << (offset & 7))))
617             {
618               unsigned int n_offset = sbm->nodes[offset];
619               if (n_offset == 0)
620                 {
621                   /* End of buffer.  Stay where we are.  */
622                   vec->dcx_pos = (i << 3) + j;
623                   if (b & (1 << j))
624                     offset--;
625                   vec->dcx_offset = offset;
626                   vec->dcx_sbm = sbm;
627                   return res;
628                 }
629               offset = 2 * n_offset;
630             }
631           else
632             {
633               unsigned char v = sbm->nodes[offset];
634
635               sbm = vec->dcxsbms + sbm->next[v];
636               offset = 0;
637               res++;
638
639               if (buf)
640                 {
641                   *buf++ = v;
642                   nbytes--;
643
644                   if (nbytes == 0)
645                     {
646                       vec->dcx_pos = (i << 3) + j + 1;
647                       vec->dcx_offset = offset;
648                       vec->dcx_sbm = sbm;
649
650                       return res;
651                     }
652                 }
653             }
654         }
655       j = 0;
656     }
657   return -1;
658 }
659
660 /* Standard IOVEC function.  */
661
662 static file_ptr
663 vms_lib_bread (struct bfd *abfd, void *buf, file_ptr nbytes)
664 {
665   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
666   file_ptr res;
667   file_ptr chunk;
668
669   /* Do not read past the end.  */
670   if (vec->where >= vec->file_len)
671     return 0;
672
673   res = 0;
674   while (nbytes > 0)
675     {
676       if (vec->rec_rem == 0)
677         {
678           unsigned char blen[2];
679
680           /* Read record length.  */
681           if (vms_lib_bread_raw (abfd, &blen, sizeof (blen)) != sizeof (blen))
682             return -1;
683           vec->rec_len = bfd_getl16 (blen);
684           if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
685             {
686               /* Discard record size and align byte.  */
687               vec->rec_pos = 0;
688               vec->rec_rem = vec->rec_len;
689             }
690           else
691             {
692               /* Prepend record size.  */
693               vec->rec_pos = REC_POS_LEN0;
694               vec->rec_rem = (vec->rec_len + 1) & ~1;   /* With align byte.  */
695             }
696           if (vec->rec_len == 3)
697             {
698               /* Possibly end of file.  Check the pattern.  */
699               if (vms_lib_bread_raw (abfd, vec->pattern, 4) != 4)
700                 return -1;
701               if (!memcmp (vec->pattern, eotdesc + 2, 3))
702                 {
703                   /* This is really an EOF.  */
704                   vec->where += res;
705                   vec->file_len = vec->where;
706                   return res;
707                 }
708             }
709
710           if (vec->dcxsbms != NULL)
711             {
712               /* This is a compressed member.  */
713               unsigned int len;
714               file_ptr elen;
715
716               /* Be sure there is enough room for the expansion.  */
717               len = (vec->rec_len + 1) & ~1;
718               if (len > vec->dcx_max)
719                 {
720                   while (len > vec->dcx_max)
721                     vec->dcx_max *= 2;
722                   vec->dcx_buf = bfd_alloc (abfd, vec->dcx_max);
723                   if (vec->dcx_buf == NULL)
724                     return -1;
725                 }
726
727               /* Read the compressed record.  */
728               vec->dcx_rlen = len;
729               if (vec->rec_len == 3)
730                 {
731                   /* Already read.  */
732                   memcpy (vec->dcx_buf, vec->pattern, 3);
733                 }
734               else
735                 {
736                   elen = vms_lib_bread_raw (abfd, vec->dcx_buf, len);
737                   if (elen != len)
738                     return -1;
739                 }
740
741               /* Dummy expansion to get the expanded length.  */
742               vec->dcx_offset = 0;
743               vec->dcx_sbm = vec->dcxsbms;
744               vec->dcx_pos = 0;
745               elen = vms_lib_dcx (vec, NULL, 0x10000);
746               if (elen < 0)
747                 return -1;
748               vec->rec_len = elen;
749               vec->rec_rem = elen;
750
751               /* Reset the state.  */
752               vec->dcx_offset = 0;
753               vec->dcx_sbm = vec->dcxsbms;
754               vec->dcx_pos = 0;
755             }
756         }
757       if (vec->rec_pos < 0)
758         {
759           unsigned char c;
760           switch (vec->rec_pos)
761             {
762             case REC_POS_LEN0:
763               c = vec->rec_len & 0xff;
764               vec->rec_pos = REC_POS_LEN1;
765               break;
766             case REC_POS_LEN1:
767               c = (vec->rec_len >> 8) & 0xff;
768               vec->rec_pos = 0;
769               break;
770             case REC_POS_PAD:
771               c = 0;
772               vec->rec_rem = 0;
773               break;
774             case REC_POS_NL:
775               c = '\n';
776               vec->rec_rem = 0;
777               break;
778             default:
779               abort ();
780             }
781           if (buf != NULL)
782             {
783               *(unsigned char *)buf = c;
784               buf++;
785             }
786           nbytes--;
787           res++;
788           continue;
789         }
790
791       if (nbytes > vec->rec_rem)
792         chunk = vec->rec_rem;
793       else
794         chunk = nbytes;
795
796       if (vec->dcxsbms != NULL)
797         {
798           /* Optimize the stat() case: no need to decompress again as we
799              know the length.  */
800           if (!(buf == NULL && chunk == vec->rec_rem))
801             chunk = vms_lib_dcx (vec, buf, chunk);
802         }
803       else
804         {
805           if (vec->rec_len == 3)
806             {
807               if (buf != NULL)
808                 memcpy (buf, vec->pattern + vec->rec_pos, chunk);
809             }
810           else
811             chunk = vms_lib_bread_raw (abfd, buf, chunk);
812         }
813       if (chunk < 0)
814         return -1;
815       res += chunk;
816       if (buf != NULL)
817         buf += chunk;
818       nbytes -= chunk;
819       vec->rec_pos += chunk;
820       vec->rec_rem -= chunk;
821
822       if (vec->rec_rem == 0)
823         {
824           /* End of record reached.  */
825           if (bfd_libdata (abfd->my_archive)->kind == vms_lib_txt)
826             {
827               if ((vec->rec_len & 1) == 1
828                   && vec->rec_len != 3
829                   && vec->dcxsbms == NULL)
830                 {
831                   /* Eat the pad byte.  */
832                   unsigned char pad;
833                   if (vms_lib_bread_raw (abfd, &pad, 1) != 1)
834                     return -1;
835                 }
836               vec->rec_pos = REC_POS_NL;
837               vec->rec_rem = 1;
838             }
839           else
840             {
841               if ((vec->rec_len & 1) == 1 && vec->dcxsbms != NULL)
842                 {
843                   vec->rec_pos = REC_POS_PAD;
844                   vec->rec_rem = 1;
845                 }
846             }
847         }
848     }
849   vec->where += res;
850   return res;
851 }
852
853 /* Standard function, but we currently only handle the rewind case.  */
854
855 static int
856 vms_lib_bseek (struct bfd *abfd, file_ptr offset, int whence)
857 {
858   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
859
860   if (whence == SEEK_SET && offset == 0)
861     {
862       vec->where = 0;
863       vec->rec_rem = 0;
864       vec->dcx_pos = -1;
865       vec->blk_off = vec->init_blk_off;
866       vec->next_block = vec->init_next_block;
867
868       if (bfd_seek (abfd->my_archive, vec->first_block, SEEK_SET) != 0)
869         return -1;
870     }
871   else
872     abort ();
873   return 0;
874 }
875
876 static file_ptr
877 vms_lib_bwrite (struct bfd *abfd ATTRIBUTE_UNUSED,
878               const void *where ATTRIBUTE_UNUSED,
879               file_ptr nbytes ATTRIBUTE_UNUSED)
880 {
881   return -1;
882 }
883
884 static int
885 vms_lib_bclose (struct bfd *abfd)
886 {
887   abfd->iostream = NULL;
888   return 0;
889 }
890
891 static int
892 vms_lib_bflush (struct bfd *abfd ATTRIBUTE_UNUSED)
893 {
894   return 0;
895 }
896
897 static int
898 vms_lib_bstat (struct bfd *abfd ATTRIBUTE_UNUSED,
899                struct stat *sb ATTRIBUTE_UNUSED)
900 {
901   /* Not supported.  */
902   return 0;
903 }
904
905 static void *
906 vms_lib_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
907               void *addr ATTRIBUTE_UNUSED,
908               bfd_size_type len ATTRIBUTE_UNUSED,
909               int prot ATTRIBUTE_UNUSED,
910               int flags ATTRIBUTE_UNUSED,
911               file_ptr offset ATTRIBUTE_UNUSED)
912 {
913   return (void *) -1;
914 }
915
916 static const struct bfd_iovec vms_lib_iovec = {
917   &vms_lib_bread, &vms_lib_bwrite, &vms_lib_btell, &vms_lib_bseek,
918   &vms_lib_bclose, &vms_lib_bflush, &vms_lib_bstat, &vms_lib_bmmap
919 };
920
921 /* Open a library module.  FILEPOS is the position of the module header.  */
922
923 static bfd_boolean
924 vms_lib_bopen (bfd *el, file_ptr filepos)
925 {
926   struct vms_lib_iovec *vec;
927   char buf[256];
928   struct vms_mhd *mhd;
929   struct lib_tdata *tdata = bfd_libdata (el->my_archive);
930   unsigned int len;
931
932   /* Allocate and initialized the iovec.  */
933   vec = bfd_zalloc (el, sizeof (*vec));
934   if (vec == NULL)
935     return FALSE;
936
937   el->iostream = vec;
938   el->iovec = &vms_lib_iovec;
939
940   /* File length is not known.  */
941   vec->file_len = -1;
942
943   /* Read the first data block.  */
944   vec->next_block = filepos & ~(VMS_BLOCK_SIZE - 1);
945   vec->blk_off = DATA__LENGTH;
946   if (!vms_lib_read_block (el))
947     return FALSE;
948
949   /* Prepare to read the first record.  */
950   vec->blk_off = filepos & (VMS_BLOCK_SIZE - 1);
951   vec->rec_rem = 0;
952   if (bfd_seek (el->my_archive, filepos, SEEK_SET) != 0)
953     return FALSE;
954
955   /* Read Record length + MHD + align byte.  */
956   len = tdata->mhd_size;
957   if (vms_lib_bread_raw (el, buf, 2) != 2)
958     return -1;
959   if (bfd_getl16 (buf) != len)
960     return -1;
961   len = (len + 1) & ~1;
962   BFD_ASSERT (len <= sizeof (buf));
963   if (vms_lib_bread_raw (el, buf, len) != len)
964     return -1;
965
966   /* Get info from mhd.  */
967   mhd = (struct vms_mhd *)buf;
968   if (len >= sizeof (struct vms_mhd))
969     el->selective_search = (mhd->objstat & MHD__M_SELSRC) ? 1 : 0;
970   el->mtime = vms_rawtime_to_time_t (mhd->datim);
971   el->mtime_set = TRUE;
972
973   /* Reinit the iovec so that seek() will point to the first record after
974      the mhd.  */
975   vec->where = 0;
976   vec->init_blk_off = vec->blk_off;
977   vec->init_next_block = vec->next_block;
978   vec->first_block = bfd_tell (el->my_archive);
979   vec->dcxsbms = bfd_libdata (el->my_archive)->dcxsbm;
980
981   if (vec->dcxsbms != NULL)
982     {
983       /* Handle DCX.  */
984       vec->dcx_max = 10 * 1024;
985       vec->dcx_buf = bfd_alloc (el, vec->dcx_max);
986       vec->dcx_pos = -1;
987       if (vec->dcx_buf == NULL)
988         return -1;
989     }
990   return TRUE;
991 }
992
993 /* Standard function: get member at IDX.  */
994
995 bfd *
996 _bfd_vms_lib_get_elt_at_index (bfd *abfd, symindex idx)
997 {
998   struct lib_tdata *tdata = bfd_libdata (abfd);
999   bfd *res;
1000   unsigned int i;
1001
1002   /* Linear-scan.  */
1003   for (i = 0; i < tdata->nbr_modules; i++)
1004     {
1005       if (tdata->modules[i].file_offset == (file_ptr)idx)
1006         break;
1007     }
1008
1009   /* Invalid index.  */
1010   if (i >= tdata->nbr_modules)
1011     return NULL;
1012
1013   /* Already loaded.  */
1014   if (tdata->cache[i])
1015     return tdata->cache[i];
1016
1017   /* Build it.  */
1018   res = _bfd_create_empty_archive_element_shell (abfd);
1019   if (!vms_lib_bopen (res, idx))
1020     return NULL;
1021   res->filename = tdata->modules[i].name;
1022
1023   tdata->cache[i] = res;
1024
1025   return res;
1026 }
1027
1028 /* Elements of an imagelib are stubs.  You can get the real image with this
1029    function.  */
1030
1031 bfd *
1032 _bfd_vms_lib_get_imagelib_file (bfd *el)
1033 {
1034   bfd *archive = el->my_archive;
1035   const char *modname = el->filename;
1036   int modlen = strlen (modname);
1037   char *filename;
1038   int j;
1039   bfd *res;
1040
1041   /* Convert module name to lower case and append '.exe'.  */
1042   filename = bfd_alloc (el, modlen + 5);
1043   if (filename == NULL)
1044     return NULL;
1045   for (j = 0; j < modlen; j++)
1046     if (ISALPHA (modname[j]))
1047       filename[j] = TOLOWER (modname[j]);
1048     else
1049       filename[j] = modname[j];
1050   memcpy (filename + modlen, ".exe", 5);
1051
1052   filename = _bfd_append_relative_path (archive, filename);
1053   if (filename == NULL)
1054     return NULL;
1055   res = bfd_openr (filename, NULL);
1056
1057   if (res == NULL)
1058     {
1059       (*_bfd_error_handler)(_("could not open shared image '%s' from '%s'"),
1060                             filename, archive->filename);
1061       bfd_release (archive, filename);
1062       return NULL;
1063     }
1064
1065   /* FIXME: put it in a cache ?  */
1066   return res;
1067 }
1068
1069 /* Standard function.  */
1070
1071 bfd *
1072 _bfd_vms_lib_openr_next_archived_file (bfd *archive,
1073                                        bfd *last_file)
1074 {
1075   unsigned int idx;
1076   bfd *res;
1077
1078   if (!last_file)
1079     idx = 0;
1080   else
1081     idx = last_file->proxy_origin + 1;
1082
1083   if (idx >= bfd_libdata (archive)->nbr_modules)
1084     {
1085       bfd_set_error (bfd_error_no_more_archived_files);
1086       return NULL;
1087     }
1088
1089   res = _bfd_vms_lib_get_elt_at_index
1090     (archive, bfd_libdata (archive)->modules[idx].file_offset);
1091   if (res == NULL)
1092     return res;
1093   res->proxy_origin = idx;
1094   return res;
1095 }
1096
1097 /* Standard function.  Just compute the length.  */
1098
1099 int
1100 _bfd_vms_lib_generic_stat_arch_elt (bfd *abfd, struct stat *st)
1101 {
1102   struct vms_lib_iovec *vec = (struct vms_lib_iovec *) abfd->iostream;
1103
1104   if (abfd->my_archive == NULL)
1105     {
1106       bfd_set_error (bfd_error_invalid_operation);
1107       return -1;
1108     }
1109
1110   if (vec->file_len == (ufile_ptr)-1)
1111     {
1112       if (vms_lib_bseek (abfd, 0, SEEK_SET) != 0)
1113         return -1;
1114
1115       /* Compute length.  */
1116       while (vms_lib_bread (abfd, NULL, 1 << 20) > 0)
1117         ;
1118     }
1119
1120   st->st_size = vec->file_len;
1121   if (abfd->mtime_set)
1122     st->st_mtime = abfd->mtime;
1123   else
1124     st->st_mtime = 0;
1125   st->st_uid = 0;
1126   st->st_gid = 0;
1127   st->st_mode = 0644;
1128
1129   return 0;
1130 }
1131
1132 /* Internal representation of an index entry.  */
1133
1134 struct vms_index
1135 {
1136   /* Corresponding archive member.  */
1137   bfd *abfd;
1138
1139   /* Number of reference to this entry.  */
1140   unsigned int ref;
1141
1142   /* Length of the key.  */
1143   unsigned short namlen;
1144
1145   /* Key.  */
1146   const char *name;
1147 };
1148
1149 /* Used to sort index entries.  */
1150
1151 static int
1152 vms_index_cmp (const void *lv, const void *rv)
1153 {
1154   const struct vms_index *l = lv;
1155   const struct vms_index *r = rv;
1156
1157   return strcmp (l->name, r->name);
1158 }
1159
1160 /* Maximum number of index blocks level.  */
1161
1162 #define MAX_LEVEL 10
1163
1164 /* Get the size of an index entry.  */
1165
1166 static unsigned int
1167 get_idxlen (struct vms_index *idx)
1168 {
1169   return 7 + idx->namlen;
1170 }
1171
1172 /* Write the index.  VBN is the first vbn to be used, and will contain
1173    on return the last vbn.
1174    Return TRUE on success.  */
1175
1176 static bfd_boolean
1177 vms_write_index (bfd *abfd,
1178                  struct vms_index *idx, unsigned int nbr, unsigned int *vbn,
1179                  unsigned int *topvbn)
1180 {
1181   unsigned int i;
1182   int j;
1183   int level;
1184   struct vms_indexdef *rblk[MAX_LEVEL];
1185   struct idxblk
1186   {
1187     unsigned int vbn;
1188     unsigned short len;
1189     unsigned short lastlen;
1190   } blk[MAX_LEVEL];
1191
1192   if (nbr == 0)
1193     {
1194       if (topvbn != NULL)
1195         *topvbn = 0;
1196       return TRUE;
1197     }
1198
1199   if (abfd == NULL)
1200     {
1201       /* Sort the index the first time this function is called.  */
1202       qsort (idx, nbr, sizeof (struct vms_index), vms_index_cmp);
1203     }
1204
1205   /* Allocate first index block.  */
1206   level = 1;
1207   if (abfd != NULL)
1208     rblk[0] = bfd_malloc (sizeof (struct vms_indexdef));
1209   blk[0].vbn = (*vbn)++;
1210   blk[0].len = 0;
1211   blk[0].lastlen = 0;
1212
1213   for (i = 0; i < nbr; i++, idx++)
1214     {
1215       unsigned int idxlen = get_idxlen (idx);
1216       struct vms_idxdef *en;
1217       int flush = 0;
1218
1219       /* Check if a block might overflow.  In this case we will flush this
1220          block and all the blocks below it.  */
1221       for (j = 0; j < level; j++)
1222         if (blk[j].len + blk[j].lastlen + idxlen > INDEXDEF__BLKSIZ)
1223           flush = j + 1;
1224
1225       for (j = 0; j < level; j++)
1226         {
1227           if (j < flush)
1228             {
1229               /* There is not enough room to write the new entry in this
1230                  block or in a parent block.  */
1231
1232               if (j + 1 == level)
1233                 {
1234                   BFD_ASSERT (level < MAX_LEVEL);
1235
1236                   /* Need to create a parent.  */
1237                   if (abfd != NULL)
1238                     {
1239                       rblk[level] = bfd_malloc (sizeof (struct vms_indexdef));
1240                       bfd_putl32 (*vbn, rblk[j]->parent);
1241                     }
1242                   blk[level].vbn = (*vbn)++;
1243                   blk[level].len = 0;
1244                   blk[level].lastlen = 0;
1245
1246                   level++;
1247                 }
1248
1249               /* Update parent block: write the new entry.  */
1250               if (abfd != NULL)
1251                 {
1252                   en = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1253                   memcpy (rblk[j + 1]->keys + blk[j + 1].len, en,
1254                           blk[j].lastlen);
1255                   en = (struct vms_idxdef *)
1256                     (rblk[j + 1]->keys + blk[j + 1].len);
1257                   bfd_putl32 (blk[j].vbn, en->vbn);
1258                   bfd_putl16 (RFADEF__C_INDEX, en->offset);
1259                 }
1260
1261               if (j + 1 == flush)
1262                 {
1263                   /* And allocate it.  Do it only on the block that won't be
1264                      flushed (so that the parent of the parent can be
1265                      updated too).  */
1266                   blk[j + 1].len += blk[j].lastlen;
1267                   blk[j + 1].lastlen = 0;
1268                 }
1269
1270               /* Write this block on the disk.  */
1271               if (abfd != NULL)
1272                 {
1273                   bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1274                   if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1275                                 SEEK_SET) != 0)
1276                     return FALSE;
1277                   if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1278                       != sizeof (struct vms_indexdef))
1279                     return FALSE;
1280                 }
1281
1282               /* Reset this block.  */
1283               blk[j].len = 0;
1284               blk[j].lastlen = 0;
1285               blk[j].vbn = (*vbn)++;
1286             }
1287
1288           /* Append it to the block.  */
1289           if (j == 0)
1290             {
1291               blk[j].len += blk[j].lastlen;
1292
1293               if (abfd != NULL)
1294                 {
1295                   en = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1296                   bfd_putl32 ((idx->abfd->proxy_origin / VMS_BLOCK_SIZE) + 1,
1297                               en->vbn);
1298                   bfd_putl16
1299                     ((idx->abfd->proxy_origin % VMS_BLOCK_SIZE) + DATA__DATA,
1300                      en->offset);
1301                   en->keylen = idx->namlen;
1302                   memcpy (en->keyname, idx->name, idx->namlen);
1303                 }
1304             }
1305
1306           blk[j].lastlen = idxlen;
1307         }
1308     }
1309
1310   if (topvbn != NULL)
1311     *topvbn = blk[level - 1].vbn;
1312
1313   if (abfd == NULL)
1314     return TRUE;
1315
1316   /* Flush.  */
1317   for (j = 0; j < level; j++)
1318     {
1319       if (j > 0)
1320         {
1321           /* Update parent block: write the new entry.  */
1322           struct vms_idxdef *en;
1323           struct vms_idxdef *par;
1324
1325           en = (struct vms_idxdef *)(rblk[j - 1]->keys + blk[j - 1].len);
1326           par = (struct vms_idxdef *)(rblk[j]->keys + blk[j].len);
1327           memcpy (par, en, blk[j - 1].lastlen);
1328           bfd_putl32 (blk[j - 1].vbn, par->vbn);
1329           bfd_putl16 (RFADEF__C_INDEX, par->offset);
1330         }
1331
1332       /* Write this block on the disk.  */
1333       bfd_putl16 (blk[j].len + blk[j].lastlen, rblk[j]->used);
1334       if (bfd_seek (abfd, (blk[j].vbn - 1) * VMS_BLOCK_SIZE,
1335                     SEEK_SET) != 0)
1336         return FALSE;
1337       if (bfd_bwrite (rblk[j], sizeof (struct vms_indexdef), abfd)
1338           != sizeof (struct vms_indexdef))
1339         return FALSE;
1340
1341       free (rblk[j]);
1342     }
1343
1344   return TRUE;
1345 }
1346
1347 /* Append data to the data block DATA.  Force write if PAD is true.  */
1348
1349 static bfd_boolean
1350 vms_write_data_block (bfd *arch, struct vms_datadef *data, file_ptr *off,
1351                       const unsigned char *buf, unsigned int len, int pad)
1352 {
1353   while (len > 0 || pad)
1354     {
1355       unsigned int doff = *off & (VMS_BLOCK_SIZE - 1);
1356       unsigned int remlen = (DATA__LENGTH - DATA__DATA) - doff;
1357       unsigned int l;
1358
1359       l = (len > remlen) ? remlen : len;
1360       memcpy (data->data + doff, buf, l);
1361       buf += l;
1362       len -= l;
1363       doff += l;
1364       *off += l;
1365
1366       if (doff == (DATA__LENGTH - DATA__DATA) || (len == 0 && pad))
1367         {
1368           data->recs = 0;
1369           data->fill_1 = 0;
1370           bfd_putl32 ((*off / VMS_BLOCK_SIZE) + 2, data->link);
1371
1372           if (bfd_bwrite (data, sizeof (*data), arch) != sizeof (*data))
1373             return FALSE;
1374
1375           *off += DATA__LENGTH - doff;
1376
1377           if (len == 0)
1378             break;
1379         }
1380     }
1381   return TRUE;
1382 }
1383
1384 /* Build the symbols index.  */
1385
1386 static bfd_boolean
1387 _bfd_vms_lib_build_map (unsigned int nbr_modules,
1388                         struct vms_index *modules,
1389                         unsigned int *res_cnt,
1390                         struct vms_index **res)
1391 {
1392   unsigned int i;
1393   asymbol **syms = NULL;
1394   long syms_max = 0;
1395   struct vms_index *map = NULL;
1396   unsigned int map_max = 1024;          /* Fine initial default.  */
1397   unsigned int map_count = 0;
1398
1399   map = (struct vms_index *) bfd_malloc (map_max * sizeof (struct vms_index));
1400   if (map == NULL)
1401     goto error_return;
1402
1403   /* Gather symbols.  */
1404   for (i = 0; i < nbr_modules; i++)
1405     {
1406       long storage;
1407       long symcount;
1408       long src_count;
1409       bfd *current = modules[i].abfd;
1410
1411       if ((bfd_get_file_flags (current) & HAS_SYMS) == 0)
1412         continue;
1413
1414       storage = bfd_get_symtab_upper_bound (current);
1415       if (storage < 0)
1416         goto error_return;
1417
1418       if (storage != 0)
1419         {
1420           if (storage > syms_max)
1421             {
1422               if (syms_max > 0)
1423                 free (syms);
1424               syms_max = storage;
1425               syms = (asymbol **) bfd_malloc (syms_max);
1426               if (syms == NULL)
1427                 goto error_return;
1428             }
1429           symcount = bfd_canonicalize_symtab (current, syms);
1430           if (symcount < 0)
1431             goto error_return;
1432
1433           /* Now map over all the symbols, picking out the ones we
1434              want.  */
1435           for (src_count = 0; src_count < symcount; src_count++)
1436             {
1437               flagword flags = (syms[src_count])->flags;
1438               asection *sec = syms[src_count]->section;
1439
1440               if ((flags & BSF_GLOBAL
1441                    || flags & BSF_WEAK
1442                    || flags & BSF_INDIRECT
1443                    || bfd_is_com_section (sec))
1444                   && ! bfd_is_und_section (sec))
1445                 {
1446                   struct vms_index *new_map;
1447
1448                   /* This symbol will go into the archive header.  */
1449                   if (map_count == map_max)
1450                     {
1451                       map_max *= 2;
1452                       new_map = (struct vms_index *)
1453                         bfd_realloc (map, map_max * sizeof (struct vms_index));
1454                       if (new_map == NULL)
1455                         goto error_return;
1456                       map = new_map;
1457                     }
1458
1459                   map[map_count].abfd = current;
1460                   /* FIXME: check length.  */
1461                   map[map_count].namlen = strlen (syms[src_count]->name);
1462                   map[map_count].name = syms[src_count]->name;
1463                   map_count++;
1464                   modules[i].ref++;
1465                 }
1466             }
1467         }
1468     }
1469
1470   *res_cnt = map_count;
1471   *res = map;
1472   return TRUE;
1473
1474  error_return:
1475   if (syms_max > 0)
1476     free (syms);
1477   if (map != NULL)
1478     free (map);
1479   return FALSE;
1480 }
1481
1482 /* Do the hard work: write an archive on the disk.  */
1483
1484 bfd_boolean
1485 _bfd_vms_lib_write_archive_contents (bfd *arch)
1486 {
1487   bfd *current;
1488   unsigned int nbr_modules;
1489   struct vms_index *modules;
1490   unsigned int nbr_symbols;
1491   struct vms_index *symbols;
1492   struct lib_tdata *tdata = bfd_libdata (arch);
1493   unsigned int i;
1494   file_ptr off;
1495   unsigned int nbr_mod_iblk;
1496   unsigned int nbr_sym_iblk;
1497   unsigned int vbn;
1498   unsigned int mod_idx_vbn;
1499   unsigned int sym_idx_vbn;
1500
1501   /* Count the number of modules (and do a first sanity check).  */
1502   nbr_modules = 0;
1503   for (current = arch->archive_head;
1504        current != NULL;
1505        current = current->archive_next)
1506     {
1507       /* This check is checking the bfds for the objects we're reading
1508          from (which are usually either an object file or archive on
1509          disk), not the archive entries we're writing to.  We don't
1510          actually create bfds for the archive members, we just copy
1511          them byte-wise when we write out the archive.  */
1512       if (bfd_write_p (current) || !bfd_check_format (current, bfd_object))
1513         {
1514           bfd_set_error (bfd_error_invalid_operation);
1515           goto input_err;
1516         }
1517
1518       nbr_modules++;
1519     }
1520
1521   /* Build the modules list.  */
1522   BFD_ASSERT (tdata->modules == NULL);
1523   modules = bfd_alloc (arch, nbr_modules * sizeof (struct vms_index));
1524   if (modules == NULL)
1525     return FALSE;
1526
1527   for (current = arch->archive_head, i = 0;
1528        current != NULL;
1529        current = current->archive_next, i++)
1530     {
1531       int nl;
1532
1533       modules[i].abfd = current;
1534       modules[i].name = vms_get_module_name (current->filename, FALSE);
1535       modules[i].ref = 1;
1536
1537       /* FIXME: silently truncate long names ?  */
1538       nl = strlen (modules[i].name);
1539       modules[i].namlen = (nl > MAX_KEYLEN ? MAX_KEYLEN : nl);
1540     }
1541
1542   /* Create the module index.  */
1543   vbn = 0;
1544   if (!vms_write_index (NULL, modules, nbr_modules, &vbn, NULL))
1545     return FALSE;
1546   nbr_mod_iblk = vbn;
1547
1548   /* Create symbol index.  */
1549   if (!_bfd_vms_lib_build_map (nbr_modules, modules, &nbr_symbols, &symbols))
1550     return FALSE;
1551
1552   vbn = 0;
1553   if (!vms_write_index (NULL, symbols, nbr_symbols, &vbn, NULL))
1554     return FALSE;
1555   nbr_sym_iblk = vbn;
1556
1557   /* Write modules and remember their position.  */
1558   off = (1 + nbr_mod_iblk + nbr_sym_iblk) * VMS_BLOCK_SIZE;
1559
1560   if (bfd_seek (arch, off, SEEK_SET) != 0)
1561     return FALSE;
1562
1563   for (i = 0; i < nbr_modules; i++)
1564     {
1565       struct vms_datadef data;
1566       unsigned char blk[VMS_BLOCK_SIZE];
1567       struct vms_mhd *mhd;
1568       unsigned int sz;
1569
1570       current = modules[i].abfd;
1571       current->proxy_origin = off;
1572
1573       bfd_putl16 (sizeof (struct vms_mhd), blk);
1574       mhd = (struct vms_mhd *)(blk + 2);
1575       memset (mhd, 0, sizeof (struct vms_mhd));
1576       mhd->lbrflag = 0;
1577       mhd->id = MHD__C_MHDID;
1578       mhd->objidlng = 4;
1579       memcpy (mhd->objid, "V1.0", 4);
1580       bfd_putl32 (modules[i].ref, mhd->refcnt);
1581       /* FIXME: datim.  */
1582
1583       sz = (2 + sizeof (struct vms_mhd) + 1) & ~1;
1584       if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1585         goto input_err;
1586
1587       if (bfd_seek (current, 0, SEEK_SET) != 0)
1588         goto input_err;
1589
1590       while (1)
1591         {
1592           sz = bfd_bread (blk, sizeof (blk), current);
1593           if (sz == 0)
1594             break;
1595           if (vms_write_data_block (arch, &data, &off, blk, sz, 0) < 0)
1596             goto input_err;
1597         }
1598       if (vms_write_data_block (arch, &data, &off,
1599                                 eotdesc, sizeof (eotdesc), 1) < 0)
1600         goto input_err;
1601     }
1602
1603   /* Write the indexes.  */
1604   vbn = 2;
1605   if (vms_write_index (arch, modules, nbr_modules, &vbn, &mod_idx_vbn) != TRUE)
1606     return FALSE;
1607   if (vms_write_index (arch, symbols, nbr_symbols, &vbn, &sym_idx_vbn) != TRUE)
1608     return FALSE;
1609
1610   /* Write libary header.  */
1611   {
1612     unsigned char blk[VMS_BLOCK_SIZE];
1613     struct vms_lhd *lhd = (struct vms_lhd *)blk;
1614     struct vms_idd *idd = (struct vms_idd *)(blk + sizeof (*lhd));
1615     unsigned int idd_flags;
1616
1617     memset (blk, 0, sizeof (blk));
1618
1619     lhd->type = LBR__C_TYP_EOBJ;
1620     lhd->nindex = 2;
1621     bfd_putl32 (LHD_SANEID3, lhd->sanity);
1622     bfd_putl16 (3, lhd->majorid);
1623     bfd_putl16 (0, lhd->minorid);
1624     snprintf ((char *)lhd->lbrver + 1, sizeof (lhd->lbrver) - 1,
1625               "GNU ar %u.%u.%u",
1626               (unsigned)(BFD_VERSION / 100000000UL),
1627               (unsigned)(BFD_VERSION / 1000000UL) % 100,
1628               (unsigned)(BFD_VERSION / 10000UL) % 100);
1629     lhd->lbrver[sizeof (lhd->lbrver) - 1] = 0;
1630     lhd->lbrver[0] = strlen ((char *)lhd->lbrver + 1);
1631
1632     /* FIXME.  */
1633     bfd_putl64 (0, lhd->credat);
1634     bfd_putl64 (0, lhd->updtim);
1635
1636     lhd->mhdusz = sizeof (struct vms_mhd) - MHD__C_USRDAT;
1637
1638     bfd_putl32 (nbr_modules + nbr_symbols, lhd->idxcnt);
1639     bfd_putl32 (nbr_modules, lhd->modcnt);
1640     bfd_putl32 (nbr_modules, lhd->modhdrs);
1641
1642     bfd_putl32 (vbn - 1, lhd->hipreal);
1643     bfd_putl32 (vbn - 1, lhd->hiprusd);
1644
1645     /* First index (modules name).  */
1646     idd_flags = IDD__FLAGS_ASCII | IDD__FLAGS_VARLENIDX
1647       | IDD__FLAGS_NOCASECMP | IDD__FLAGS_NOCASENTR;
1648     bfd_putl16 (idd_flags, idd->flags);
1649     bfd_putl16 (MAX_KEYLEN, idd->keylen);
1650     bfd_putl16 (mod_idx_vbn, idd->vbn);
1651     idd++;
1652
1653     /* Second index (symbols name).  */
1654     bfd_putl16 (idd_flags, idd->flags);
1655     bfd_putl16 (MAX_KEYLEN, idd->keylen);
1656     bfd_putl16 (sym_idx_vbn, idd->vbn);
1657     idd++;
1658
1659     if (bfd_seek (arch, 0, SEEK_SET) != 0)
1660       return FALSE;
1661     if (bfd_bwrite (blk, sizeof (blk), arch) != sizeof (blk))
1662       return FALSE;
1663   }
1664
1665   return TRUE;
1666
1667  input_err:
1668   bfd_set_error (bfd_error_on_input, current, bfd_get_error ());
1669   return FALSE;
1670 }
1671
1672 /* Add a target for text library.  This costs almost nothing and is useful to
1673    read VMS library on the host.  */
1674
1675 const bfd_target vms_lib_txt_vec =
1676 {
1677   "vms-libtxt",                 /* Name.  */
1678   bfd_target_unknown_flavour,
1679   BFD_ENDIAN_UNKNOWN,           /* byteorder */
1680   BFD_ENDIAN_UNKNOWN,           /* header_byteorder */
1681   0,                            /* Object flags.  */
1682   0,                            /* Sect flags.  */
1683   0,                            /* symbol_leading_char.  */
1684   ' ',                          /* ar_pad_char.  */
1685   15,                           /* ar_max_namelen.  */
1686   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1687   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1688   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
1689   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
1690   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
1691   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
1692
1693   {_bfd_dummy_target, _bfd_dummy_target,        /* bfd_check_format.  */
1694    _bfd_vms_lib_txt_archive_p, _bfd_dummy_target},
1695   {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_set_format.  */
1696   {bfd_false, bfd_false, bfd_false, bfd_false}, /* bfd_write_contents.  */
1697
1698   BFD_JUMP_TABLE_GENERIC (_bfd_generic),
1699   BFD_JUMP_TABLE_COPY (_bfd_generic),
1700   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1701   BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib),
1702   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
1703   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1704   BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
1705   BFD_JUMP_TABLE_LINK (_bfd_nolink),
1706   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1707
1708   NULL,
1709
1710   (PTR) 0
1711 };