コード例 #1
0
ファイル: dvd.c プロジェクト: anarexia/bacula
void dvd_remove_empty_part(DCR *dcr) 
{
   DEVICE *dev = dcr->dev;

   /* Remove the last part file if it is empty */
   if (dev->is_dvd() && dev->num_dvd_parts > 0) {
      struct stat statp;
      uint32_t part_save = dev->part;
      POOL_MEM archive_name(PM_FNAME);
      int status;

      dev->part = dev->num_dvd_parts;
      make_spooled_dvd_filename(dev, archive_name);
      /* Check that the part file is empty */
      status = stat(archive_name.c_str(), &statp);
      if (status == 0 && statp.st_size == 0) {
         Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n", 
                part_save, dev->num_dvd_parts, dev->getVolCatName());
         Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
         unlink(archive_name.c_str());
         if (part_save == dev->part) {
            dev->set_part_spooled(false);  /* no spooled part left */
         }
      } else if (status < 0) {                         
         if (part_save == dev->part) {
            dev->set_part_spooled(false);  /* spool doesn't exit */
         }
      }       
      dev->part = part_save;               /* restore part number */
   }
}
コード例 #2
0
ファイル: dev.c プロジェクト: dl5rcw/bareos
/*
 * Open a device.
 */
void DEVICE::open_device(DCR *dcr, int omode)
{
   POOL_MEM archive_name(PM_FNAME);

   get_autochanger_loaded_slot(dcr);

   /*
    * Handle opening of File Archive (not a tape)
    */
   pm_strcpy(archive_name, dev_name);

   /*
    * If this is a virtual autochanger (i.e. changer_res != NULL) we simply use
    * the device name, assuming it has been appropriately setup by the "autochanger".
    */
   if (!device->changer_res || device->changer_command[0] == 0) {
      if (VolCatInfo.VolCatName[0] == 0) {
         Mmsg(errmsg, _("Could not open file device %s. No Volume name given.\n"),
            print_name());
         clear_opened();
         return;
      }

      if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
         pm_strcat(archive_name, "/");
      }
      pm_strcat(archive_name, getVolCatName());
   }

   mount(dcr, 1);                     /* do mount if required */

   open_mode = omode;
   set_mode(omode);

   /*
    * If creating file, give 0640 permissions
    */
   Dmsg3(100, "open disk: mode=%s open(%s, 0x%x, 0640)\n", mode_to_str(omode),
         archive_name.c_str(), oflags);

   if ((m_fd = d_open(archive_name.c_str(), oflags, 0640)) < 0) {
      berrno be;
      dev_errno = errno;
      Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(),
            be.bstrerror());
      Dmsg1(100, "open failed: %s", errmsg);
   }

   if (m_fd >= 0) {
      dev_errno = 0;
      file = 0;
      file_addr = 0;
   }

   Dmsg1(100, "open dev: disk fd=%d opened\n", m_fd);
}
コード例 #3
0
ファイル: dev.c プロジェクト: prelegalwonder/bacula
/*
 * Edit codes into (Un)MountCommand, Write(First)PartCommand
 *  %% = %
 *  %a = archive device name
 *  %e = erase (set if cannot mount and first part)
 *  %n = part number
 *  %m = mount point
 *  %v = last part name
 *
 *  omsg = edited output message
 *  imsg = input string containing edit codes (%x)
 *
 */
void DEVICE::edit_mount_codes(POOL_MEM &omsg, const char *imsg)
{
   const char *p;
   const char *str;
   char add[20];

   POOL_MEM archive_name(PM_FNAME);

   omsg.c_str()[0] = 0;
   Dmsg1(800, "edit_mount_codes: %s\n", imsg);
   for (p=imsg; *p; p++) {
      if (*p == '%') {
         switch (*++p) {
         case '%':
            str = "%";
            break;
         case 'a':
            str = dev_name;
            break;
         case 'e':
            if (num_dvd_parts == 0) {
               if (truncating || blank_dvd) {
                  str = "2";
               } else {
                  str = "1";
               }
            } else {
               str = "0";
            }
            break;
         case 'n':
            bsnprintf(add, sizeof(add), "%d", part);
            str = add;
            break;
         case 'm':
            str = device->mount_point;
            break;
         default:
            add[0] = '%';
            add[1] = *p;
            add[2] = 0;
            str = add;
            break;
         }
      } else {
         add[0] = *p;
         add[1] = 0;
         str = add;
      }
      Dmsg1(1900, "add_str %s\n", str);
      pm_strcat(omsg, (char *)str);
      Dmsg1(1800, "omsg=%s\n", omsg.c_str());
   }
}
コード例 #4
0
ファイル: dev.c プロジェクト: dl5rcw/bareos
/*
 * Edit codes into (Un)MountCommand
 *  %% = %
 *  %a = archive device name
 *  %m = mount point
 *
 *  omsg = edited output message
 *  imsg = input string containing edit codes (%x)
 *
 */
void DEVICE::edit_mount_codes(POOL_MEM &omsg, const char *imsg)
{
   const char *p;
   const char *str;
   char add[20];

   POOL_MEM archive_name(PM_FNAME);

   omsg.c_str()[0] = 0;
   Dmsg1(800, "edit_mount_codes: %s\n", imsg);
   for (p=imsg; *p; p++) {
      if (*p == '%') {
         switch (*++p) {
         case '%':
            str = "%";
            break;
         case 'a':
            str = dev_name;
            break;
         case 'm':
            str = device->mount_point;
            break;
         default:
            add[0] = '%';
            add[1] = *p;
            add[2] = 0;
            str = add;
            break;
         }
      } else {
         add[0] = *p;
         add[1] = 0;
         str = add;
      }
      Dmsg1(1900, "add_str %s\n", str);
      pm_strcat(omsg, (char *)str);
      Dmsg1(1800, "omsg=%s\n", omsg.c_str());
   }
}
コード例 #5
0
ファイル: dvd.c プロジェクト: anarexia/bacula
bool truncate_dvd(DCR *dcr) 
{
   DEVICE* dev = dcr->dev;

   dev->clear_freespace_ok();             /* need to update freespace */
   dev->close_part(dcr);

   if (!dev->unmount(1)) {
      Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
      return false;
   }

   /* If necessary, delete its spool file. */
   if (dev->is_part_spooled()) {
      POOL_MEM archive_name(PM_FNAME);
      /* Delete spool file */
      make_spooled_dvd_filename(dev, archive_name);
      unlink(archive_name.c_str());
      dev->set_part_spooled(false);
   }

   /* Set num_dvd_parts to zero (on disk) */
   dev->part = 0;
   dev->num_dvd_parts = 0;
   dcr->VolCatInfo.VolCatParts = 0;
   dev->VolCatInfo.VolCatParts = 0;
   
   Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
   
   dev->truncating = true;
   /* This creates a zero length spool file and sets part=1 */
   if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
      Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
      dev->truncating = false;
      return false;
   }

   dev->close_part(dcr);
   
   Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
   
   /* 
    * Now actually truncate the DVD which is done by writing
    *  a zero length part to the DVD/
    */
   if (!dvd_write_part(dcr)) {
      Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
      dev->truncating = false;
      return false;
   }
   dev->truncating = false;
   
   /* Set num_dvd_parts to zero (on disk) */
   dev->part = 0;
   dev->num_dvd_parts = 0;
   dcr->VolCatInfo.VolCatParts = 0;
   dev->VolCatInfo.VolCatParts = 0;
   /* Clear the size of the volume */
   dev->VolCatInfo.VolCatBytes = 0;
   dcr->VolCatInfo.VolCatBytes = 0;

   /* Update catalog */
   if (!dir_update_volume_info(dcr, false, true)) {
      return false;
   }
   
   return true;
}
コード例 #6
0
ファイル: dvd.c プロジェクト: anarexia/bacula
/*
 * Open the next part file.
 *  - Close the fd
 *  - Increment part number 
 *  - Reopen the device
 */
int dvd_open_next_part(DCR *dcr)
{
   DEVICE *dev = dcr->dev;

   Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
      dev->part, dev->num_dvd_parts, dev->print_name(),
         dev->getVolCatName(), dev->openmode, dev->file_addr);
   if (!dev->is_dvd()) {
      Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name()); 
      return -1;
   }
   
   /* When appending, do not open a new part if the current is empty */
   if (dev->can_append() && (dev->part > dev->num_dvd_parts) && 
       (dev->part_size == 0)) {
      Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
      return dev->fd();
   }

   dev->close_part(dcr);               /* close current part */
   
   /*
    * If we have a spooled part open, write it to the
    *  DVD before opening the next part.
    */
   if (dev->is_part_spooled()) {
      Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
         dev->part, dev->num_dvd_parts);
      if (!dvd_write_part(dcr)) {
         Dmsg0(29, "Error in dvd_write part.\n");
         return -1;
      }
   }
     
   dev->part_start += dev->part_size;
   dev->part++;
   Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);

   /* Are we working on a part past what is written in the DVD? */
   if (dev->num_dvd_parts < dev->part) {
      POOL_MEM archive_name(PM_FNAME);
      struct stat buf;
      /* 
       * First check what is on DVD.  If our part is there, we
       *   are in trouble, so bail out.
       * NB: This is however not a problem if we are writing the first part.
       * It simply means that we are over writing an existing volume...
       */
      if (dev->num_dvd_parts > 0) {
         make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
         Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
         if (stat(archive_name.c_str(), &buf) == 0) {
            /* bad news bail out */
            dev->set_part_spooled(false);
            Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
               archive_name.c_str());
            return -1;
         }
      }

#ifdef neeeded
      Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
      make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
      
      /* Check if the next part exists in spool directory . */
      Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
      if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
         Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
         /* Then try to unlink it */
         if (unlink(archive_name.c_str()) < 0) {
            berrno be;
            dev->set_part_spooled(false);
            dev->dev_errno = errno;
            Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
                   archive_name.c_str(), be.bstrerror());
            return -1;
         }
      }
#endif
   }

   Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(), 
         dev->openmode);

   /* Open next part.  Note, this sets part_size for part opened. */
   if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
      return -1;
   } 
   dev->set_labeled();                   /* all next parts are "labeled" */
   
   return dev->fd();
}
コード例 #7
0
ファイル: dvd.c プロジェクト: anarexia/bacula
/*
 * Note!!!! Part numbers now begin at 1. The part number is
 *  suppressed from the first part, which is just the Volume
 *  name. Each subsequent part is the Volumename.partnumber.
 *
 * Write a part (Vol, Vol.2, ...) from the spool to the DVD   
 * This routine does not update the part number, so normally, you
 *  should call open_next_part()
 *
 * It is also called from truncate_dvd to "blank" the medium, as
 *  well as from block.c when the DVD is full to write the last part.
 */
bool dvd_write_part(DCR *dcr)
{
   DEVICE *dev = dcr->dev;
   POOL_MEM archive_name(PM_FNAME);
   
   /*
    * Don't write empty part files.
    * This is only useful when growisofs does not support write beyond
    * the 4GB boundary.
    * Example :
    *   - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
    *   - Write 0.2 GB on the volume, Bacula thinks it could still
    *     append data, it creates a new empty part.
    *   - dvd-freespace reports 0 GB free, as the 4GB boundary has
    *     been crossed
    *   - Bacula thinks he must finish to write to the device, so it
    *     tries to write the last part (0-byte), but dvd-writepart fails...
    *
    * There is one exception: when recycling a volume, we write a blank part
    * file, so, then, we need to accept to write it.
    */
   if (dev->part_size == 0 && !dev->truncating) {
      Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
      /* Delete spool file */
      make_spooled_dvd_filename(dev, archive_name);
      unlink(archive_name.c_str());
      dev->set_part_spooled(false);
      Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
      Dsm_check(400);
      return true;
   }
   
   POOL_MEM ocmd(PM_FNAME);
   POOL_MEM results(PM_MESSAGE);
   char* icmd;
   int status;
   int timeout;
   char ed1[50];
   
   dev->clear_freespace_ok();             /* need to update freespace */

   Dsm_check(400);
   Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
   icmd = dev->device->write_part_command;
   
   dev->edit_mount_codes(ocmd, icmd);
      
   /*
    * original line follows
    * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
    * I modified this for a longer timeout; pre-formatting, blanking and
    * writing can take quite a while
    */

   /* Explanation of the timeout value, when writing the first part,
    *  by Arno Lehmann :
    * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
    * Overhead: 900 seconds (starting, initializing, finalizing,probably 
    *   reloading 15 minutes)
    * Sum: 15780.
    * A reasonable last-exit timeout would be 16000 seconds. Quite long - 
    * almost 4.5 hours, but hopefully, that timeout will only ever be needed 
    * in case of a serious emergency.
    */

   if (dev->part == 1) {
      timeout = 16000;
   } else {
      timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
   }

   Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
   status = run_program_full_output(ocmd.c_str(), timeout, results.addr());
   Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());

   dev->blank_dvd = false;
   if (status != 0) {
      Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
         dev->part, results.c_str());
      Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
            results.c_str());
      Dmsg1(100, "%s\n", dev->errmsg);
      dev->dev_errno = EIO;
      if (!dev->truncating) {
         dcr->mark_volume_in_error();
      }
      Dsm_check(400);
      return false;
   }
   Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
   Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
            dev->part, dev->part_size, results.c_str());
    
   dev->num_dvd_parts++;            /* there is now one more part on DVD */
   dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
   dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
   Dmsg1(100, "Update num_parts=%d\n", dev->num_dvd_parts);

   /* Delete spool file */
   make_spooled_dvd_filename(dev, archive_name);
   unlink(archive_name.c_str());
   dev->set_part_spooled(false);
   Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
   Dsm_check(400);
   
   /* growisofs umounted the device, so remount it (it will update the free space) */
   dev->clear_mounted();
   dev->mount(1);
   Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
      edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
   Dsm_check(400);
   return true;
}
コード例 #8
0
bool win32_file_device::d_truncate(DCR *dcr)
{
   struct stat st;

   if (ftruncate(m_fd, 0) != 0) {
      berrno be;

      Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"), print_name(), be.bstrerror());
      return false;
   }

   /*
    * Check for a successful ftruncate() and issue a work-around for devices
    * (mostly cheap NAS) that don't support truncation.
    * Workaround supplied by Martin Schmid as a solution to bug #1011.
    * 1. close file
    * 2. delete file
    * 3. open new file with same mode
    * 4. change ownership to original
    */
   if (fstat(m_fd, &st) != 0) {
      berrno be;

      Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"), print_name(), be.bstrerror());
      return false;
   }

   if (st.st_size != 0) {             /* ftruncate() didn't work */
      POOL_MEM archive_name(PM_FNAME);

      pm_strcpy(archive_name, dev_name);
      if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
         pm_strcat(archive_name, "/");
      }
      pm_strcat(archive_name, dcr->VolumeName);

      Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"),
            print_name(), archive_name.c_str());

      /*
       * Close file and blow it away
       */
      ::close(m_fd);
      ::unlink(archive_name.c_str());

      /*
       * Recreate the file -- of course, empty
       */
      oflags = O_CREAT | O_RDWR | O_BINARY;
      if ((m_fd = ::open(archive_name.c_str(), oflags, st.st_mode)) < 0) {
         berrno be;

         dev_errno = errno;
         Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(), be.bstrerror());
         Dmsg1(100, "reopen failed: %s", errmsg);
         Emsg0(M_FATAL, 0, errmsg);
         return false;
      }

      /*
       * Reset proper owner
       */
      chown(archive_name.c_str(), st.st_uid, st.st_gid);
   }

   return true;
}
コード例 #9
0
ファイル: rw.c プロジェクト: ah42/CUDALucas
static void note_archive_failure(FILE *fp, int error) {
	static char cnt = 0;
	
	if (++cnt > 3)
		return; /* already warned in all possible output files, but warn again after it overflows */
	if (fp != NULL && !ferror(fp)) {
		fprintf(fp, "%s: previous line may not have been appended to %s correctly\n", program_name, archive_name());
		fprintf(fp, "\terrno %d: %s\n", error, strerror(error));
	}
}
コード例 #10
0
ファイル: rw.c プロジェクト: ah42/CUDALucas
FILE *open_archive() {
  return(fopen(archive_name(), "a"));
}
コード例 #11
0
ファイル: file_dev.c プロジェクト: rkorzeniewski/bacula
/*
 * Truncate a volume.  If this is aligned disk, we
 *  truncate both volumes.
 */
bool DEVICE::truncate(DCR *dcr) /* We need the DCR for DVD-writing */
{
   struct stat st;
   DEVICE *dev = this;

   Dmsg1(100, "truncate %s\n", print_name());
   switch (dev_type) {
   case B_VTL_DEV:
   case B_VTAPE_DEV:
   case B_TAPE_DEV:
      /* maybe we should rewind and write and eof ???? */
      return true;                    /* we don't really truncate tapes */
   case B_FILE_DEV:
      Dmsg1(100, "Truncate fd=%d\n", dev->m_fd);
      if (ftruncate(dev->m_fd, 0) != 0) {
         berrno be;
         Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"),
               print_name(), be.bstrerror());
         return false;
      }

      /*
       * Check for a successful ftruncate() and issue a work-around for devices
       * (mostly cheap NAS) that don't support truncation.
       * Workaround supplied by Martin Schmid as a solution to bug #1011.
       * 1. close file
       * 2. delete file
       * 3. open new file with same mode
       * 4. change ownership to original
       */

      if (fstat(dev->m_fd, &st) != 0) {
         berrno be;
         Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"),
               print_name(), be.bstrerror());
         return false;
      }

      if (st.st_size != 0) {             /* ftruncate() didn't work */
         POOL_MEM archive_name(PM_FNAME);

         pm_strcpy(archive_name, dev_name);
         if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
            pm_strcat(archive_name, "/");
         }
         pm_strcat(archive_name, dcr->VolumeName);

         Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"),
               print_name(), archive_name.c_str());

         /* Close file and blow it away */
         ::close(dev->m_fd);
         ::unlink(archive_name.c_str());

         /* Recreate the file -- of course, empty */
         dev->set_mode(CREATE_READ_WRITE);
         if ((dev->m_fd = ::open(archive_name.c_str(), mode, st.st_mode)) < 0) {
            berrno be;
            dev_errno = errno;
            Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(),
                  be.bstrerror());
            Dmsg1(40, "reopen failed: %s", errmsg);
            Emsg0(M_FATAL, 0, errmsg);
            return false;
         }

         /* Reset proper owner */
         chown(archive_name.c_str(), st.st_uid, st.st_gid);
      }
      return true;
   }
   return false;
}
コード例 #12
0
ファイル: machoread.c プロジェクト: jon-turney/binutils-gdb
static void
macho_symfile_read_all_oso (std::vector<oso_el> *oso_vector_ptr,
			    struct objfile *main_objfile,
			    symfile_add_flags symfile_flags)
{
  int ix;
  oso_el *oso;

  /* Sort oso by name so that files from libraries are gathered.  */
  std::sort (oso_vector_ptr->begin (), oso_vector_ptr->end (),
	     oso_el_compare_name);

  for (ix = 0; ix < oso_vector_ptr->size (); ++ix)
    {
      int pfx_len;

      oso = &(*oso_vector_ptr)[ix];

      /* Check if this is a library name.  */
      pfx_len = get_archive_prefix_len (oso->name);
      if (pfx_len > 0)
	{
          int last_ix;
          oso_el *oso2;
          int ix2;

	  std::string archive_name (oso->name, pfx_len);

          /* Compute number of oso for this archive.  */
          for (last_ix = ix; last_ix < oso_vector_ptr->size (); last_ix++)
            {
	      oso2 = &(*oso_vector_ptr)[last_ix];
              if (strncmp (oso2->name, archive_name.c_str (), pfx_len) != 0)
                break;
            }

	  /* Open the archive and check the format.  */
	  gdb_bfd_ref_ptr archive_bfd (gdb_bfd_open (archive_name.c_str (),
						     gnutarget, -1));
	  if (archive_bfd == NULL)
	    {
	      warning (_("Could not open OSO archive file \"%s\""),
		       archive_name.c_str ());
              ix = last_ix;
	      continue;
	    }
	  if (!bfd_check_format (archive_bfd.get (), bfd_archive))
	    {
	      warning (_("OSO archive file \"%s\" not an archive."),
		       archive_name.c_str ());
              ix = last_ix;
	      continue;
	    }

	  gdb_bfd_ref_ptr member_bfd
	    (gdb_bfd_openr_next_archived_file (archive_bfd.get (), NULL));

	  if (member_bfd == NULL)
	    {
	      warning (_("Could not read archive members out of "
			 "OSO archive \"%s\""), archive_name.c_str ());
              ix = last_ix;
	      continue;
	    }

          /* Load all oso in this library.  */
	  while (member_bfd != NULL)
	    {
	      const char *member_name = member_bfd->filename;
              int member_len = strlen (member_name);

              /* If this member is referenced, add it as a symfile.  */
              for (ix2 = ix; ix2 < last_ix; ix2++)
                {
                  oso2 = &(*oso_vector_ptr)[ix2];

                  if (oso2->name
                      && strlen (oso2->name) == pfx_len + member_len + 2
                      && !memcmp (member_name, oso2->name + pfx_len + 1,
                                  member_len))
                    {
                      macho_add_oso_symfile (oso2, member_bfd,
					     bfd_get_filename (member_bfd),
                                             main_objfile, symfile_flags);
                      oso2->name = NULL;
                      break;
                    }
                }

	      member_bfd = gdb_bfd_openr_next_archived_file (archive_bfd.get (),
							     member_bfd.get ());
	    }
          for (ix2 = ix; ix2 < last_ix; ix2++)
            {
              oso_el *oso2 = &(*oso_vector_ptr)[ix2];

              if (oso2->name != NULL)
                warning (_("Could not find specified archive member "
                           "for OSO name \"%s\""), oso->name);
            }
          ix = last_ix;
	}
      else
	{
	  gdb_bfd_ref_ptr abfd (gdb_bfd_open (oso->name, gnutarget, -1));
	  if (abfd == NULL)
            warning (_("`%s': can't open to read symbols: %s."), oso->name,
                     bfd_errmsg (bfd_get_error ()));
          else
            macho_add_oso_symfile (oso, abfd, oso->name, main_objfile,
				   symfile_flags);

          ix++;
        }
    }
}