Beispiel #1
0
bool gfapi_device::d_truncate(DCR *dcr)
{
   struct stat st;

   if (m_gfd) {
      if (glfs_ftruncate(m_gfd, 0) != 0) {
         berrno be;

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

      /*
       * Check for a successful glfs_truncate() and issue work-around when truncation doesn't work.
       *
       * 1. close file
       * 2. delete file
       * 3. open new file with same mode
       * 4. change ownership to original
       */
      if (glfs_fstat(m_gfd, &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) {             /* glfs_truncate() didn't work */
         glfs_close(m_gfd);
         glfs_unlink(m_glfs, getVolCatName());

         set_mode(CREATE_READ_WRITE);

         /*
          * Recreate the file -- of course, empty
          */
         m_gfd = glfs_creat(m_glfs, getVolCatName(), oflags, st.st_mode);
         if (!m_gfd) {
            berrno be;

            dev_errno = errno;
            Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), getVolCatName(), be.bstrerror());
            Emsg0(M_FATAL, 0, errmsg);

            return false;
         }

         /*
          * Reset proper owner
          */
         glfs_chown(m_glfs, getVolCatName(), st.st_uid, st.st_gid);
      }
   }

   return true;
}
boffset_t object_store_device::d_lseek(DCR *dcr, boffset_t offset, int whence)
{
   switch (whence) {
   case SEEK_SET:
      m_offset = offset;
      break;
   case SEEK_CUR:
      m_offset += offset;
      break;
   case SEEK_END: {
      size_t filesize;

      filesize = object_store_get_file_size(m_ctx, getVolCatName());
      if (filesize >= 0) {
         m_offset = filesize + offset;
      } else {
         return -1;
      }
      break;
   }
   default:
      return -1;
   }

   return m_offset;
}
Beispiel #3
0
bool DCR::dir_get_volume_info(enum get_vol_info_rw writing)
{
   Dmsg0(100, "Fake dir_get_volume_info\n");
   setVolCatName(VolumeName);
   Dmsg1(500, "Vol=%s\n", getVolCatName());
   return 1;
}
Beispiel #4
0
/*
 * Open the device with the operating system and
 * initialize buffer pointers.
 *
 * Returns: true on success
 *          false on error
 *
 * Note, for a tape, the VolName is the name we give to the
 * volume (not really used here), but for a file, the
 * VolName represents the name of the file to be created/opened.
 * In the case of a file, the full name is the device name
 * (archive_name) with the VolName concatenated.
 */
bool DEVICE::open(DCR *dcr, int omode)
{
   char preserve[ST_BYTES];

   clear_all_bits(ST_MAX, preserve);
   if (is_open()) {
      if (open_mode == omode) {
         return true;
      } else {
         d_close(m_fd);
         clear_opened();
         Dmsg0(100, "Close fd for mode change.\n");

         if (bit_is_set(ST_LABEL, state))
            set_bit(ST_LABEL, preserve);
         if (bit_is_set(ST_APPENDREADY, state))
            set_bit(ST_APPENDREADY, preserve);
         if (bit_is_set(ST_READREADY, state))
            set_bit(ST_READREADY, preserve);
      }
   }

   if (dcr) {
      dcr->setVolCatName(dcr->VolumeName);
      VolCatInfo = dcr->VolCatInfo;    /* structure assign */
   }

   Dmsg4(100, "open dev: type=%d dev_name=%s vol=%s mode=%s\n", dev_type,
         print_name(), getVolCatName(), mode_to_str(omode));

   clear_bit(ST_LABEL, state);
   clear_bit(ST_APPENDREADY, state);
   clear_bit(ST_READREADY, state);
   clear_bit(ST_EOT, state);
   clear_bit(ST_WEOT, state);
   clear_bit(ST_EOF, state);

   label_type = B_BAREOS_LABEL;

   /*
    * We are about to open the device so let any plugin know we are.
    */
   if (dcr && generate_plugin_event(dcr->jcr, bsdEventDeviceOpen, dcr) != bRC_OK) {
      Dmsg0(100, "open_dev: bsdEventDeviceOpen failed\n");
      return false;
   }

   Dmsg1(100, "call open_device mode=%s\n", mode_to_str(omode));
   open_device(dcr, omode);

   /*
    * Reset any important state info
    */
   clone_bits(ST_MAX, preserve, state);

   Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, m_fd);

   return m_fd >= 0;
}
Beispiel #5
0
/**
 * Get Volume info for a specific volume from the Director's Database
 *
 * Returns: true  on success   (Director guarantees that Pool and MediaType
 *                              are correct and VolStatus==Append or
 *                              VolStatus==Recycle)
 *          false on failure
 *
 * Volume information returned in dcr->VolCatInfo
 */
bool SD_DCR::dir_get_volume_info(enum get_vol_info_rw writing)
{
   bool ok;
   BSOCK *dir = jcr->dir_bsock;

   P(vol_info_mutex);
   setVolCatName(VolumeName);
   bash_spaces(getVolCatName());
   dir->fsend(Get_Vol_Info, jcr->Job, getVolCatName(),
              (writing == GET_VOL_INFO_FOR_WRITE) ? 1 : 0);
   Dmsg1(dbglvl, ">dird %s", dir->msg);
   unbash_spaces(getVolCatName());
   ok = do_get_volume_info(this);
   V(vol_info_mutex);

   return ok;
}
Beispiel #6
0
/*
 * 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);
}
Beispiel #7
0
/*
 * Walk through all attached jcrs indicating the File has changed
 */
void
DEVICE::notify_newfile_in_attached_dcrs()
{
   Dmsg1(140, "Notify dcrs of file change. Volume=%s\n", getVolCatName());
   Lock_dcrs();
   DCR *mdcr;
   foreach_dlist(mdcr, attached_dcrs) {
      if (mdcr->jcr->JobId == 0) {
         continue;                 /* ignore console */
      }
      Dmsg1(140, "Notify JobI=%d\n", mdcr->jcr->JobId);
      mdcr->NewFile = true;
   }
   Unlock_dcrs();
}
/*
 * Write data to a volume using libdroplet.
 */
ssize_t object_store_device::d_write(int fd, const void *buffer, size_t count)
{
   if (m_vfd) {
      dpl_status_t status;

      status = dpl_pwrite(m_vfd, (char *)buffer, count, m_offset);
      switch (status) {
      case DPL_SUCCESS:
         m_offset += count;
         return count;
      default:
         Mmsg2(errmsg, _("Failed to write %s using dpl_write(): ERR=%s.\n"),
               getVolCatName(), dpl_status_str(status));
         return droplet_errno_to_system_errno(status);
      }
   } else {
      errno = EBADF;
      return -1;
   }
}
Beispiel #9
0
/*
 * Walk through all attached jcrs indicating the volume has changed
 *   Note: If you have the new VolumeName, it is passed here,
 *     otherwise pass a NULL.
 */
void
DEVICE::notify_newvol_in_attached_dcrs(const char *newVolumeName)
{
   Dmsg2(140, "Notify dcrs of vol change. oldVolume=%s NewVolume=%s\n",
      getVolCatName(), newVolumeName?"*None*":newVolumeName);
   Lock_dcrs();
   DCR *mdcr;
   foreach_dlist(mdcr, attached_dcrs) {
      if (mdcr->jcr->JobId == 0) {
         continue;                 /* ignore console */
      }
      mdcr->NewVol = true;
      mdcr->NewFile = true;
      if (newVolumeName && mdcr->VolumeName != newVolumeName) {
         bstrncpy(mdcr->VolumeName, newVolumeName, sizeof(mdcr->VolumeName));
         Dmsg2(140, "Set NewVol=%s in JobId=%d\n", mdcr->VolumeName, mdcr->jcr->JobId);
      }
   }
   Unlock_dcrs();
}
Beispiel #10
0
/*
 * Read data from a volume using libdroplet.
 */
ssize_t object_store_device::d_read(int fd, void *buffer, size_t count)
{
   if (m_vfd) {
      unsigned int buflen;
      dpl_status_t status;

      buflen = count;
      status = dpl_pread(m_vfd, count, m_offset, (char **)&buffer, &buflen);

      switch (status) {
      case DPL_SUCCESS:
         m_offset += buflen;
         return buflen;
      default:
         Mmsg2(errmsg, _("Failed to read %s using dpl_read(): ERR=%s.\n"),
               getVolCatName(), dpl_status_str(status));
         return droplet_errno_to_system_errno(status);
      }
   } else {
      errno = EBADF;
      return -1;
   }
}
Beispiel #11
0
/*
 * Open the device with the operating system and
 * initialize buffer pointers.
 *
 * Returns:  true on success
 *           false on error
 *
 * Note, for a tape, the VolName is the name we give to the
 *    volume (not really used here), but for a file, the
 *    VolName represents the name of the file to be created/opened.
 *    In the case of a file, the full name is the device name
 *    (archive_name) with the VolName concatenated.
 */
bool DEVICE::open(DCR *dcr, int omode)
{
   int preserve = 0;
   if (is_open()) {
      if (openmode == omode) {
         return true;
      } else {
         Dmsg1(200, "Close fd=%d for mode change in open().\n", m_fd);
         d_close(m_fd);
         clear_opened();
         preserve = state & (ST_LABEL|ST_APPEND|ST_READ);
      }
   }
   if (dcr) {
      dcr->setVolCatName(dcr->VolumeName);
      VolCatInfo = dcr->VolCatInfo;    /* structure assign */
   }

   state &= ~(ST_NOSPACE|ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
   label_type = B_BACULA_LABEL;

   if (is_tape() || is_fifo()) {
      open_tape_device(dcr, omode);
   } else if (is_ftp()) {
      open_device(dcr, omode);
   } else {
      Dmsg1(100, "call open_file_device mode=%s\n", mode_to_str(omode));
      open_file_device(dcr, omode);
   }
   state |= preserve;                 /* reset any important state info */
   Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, m_fd);

   Dmsg7(100, "open dev: fd=%d dev=%p dcr=%p vol=%s type=%d dev_name=%s mode=%s\n",
         m_fd, getVolCatName(), this, dcr, dev_type, print_name(), mode_to_str(omode));
   return m_fd >= 0;
}
Beispiel #12
0
bool object_store_device::d_truncate(DCR *dcr)
{
   /*
    * libdroplet doesn't have a truncate function so unlink the volume and create a new empty one.
    */
   if (m_vfd) {
      dpl_status_t status;
      dpl_vfile_flag_t dpl_flags;
      dpl_option_t dpl_options;

      status = dpl_close(m_vfd);
      switch (status) {
      case DPL_SUCCESS:
         m_vfd = NULL;
         break;
      default:
         Mmsg2(errmsg, _("Failed to close %s using dpl_close(): ERR=%s.\n"),
               getVolCatName(), dpl_status_str(status));
         return false;
      }

      status = dpl_unlink(m_ctx, getVolCatName());
      switch (status) {
      case DPL_SUCCESS:
         break;
      default:
         Mmsg2(errmsg, _("Failed to unlink %s using dpl_unlink(): ERR=%s.\n"),
               getVolCatName(), dpl_status_str(status));
         return false;
      }

      /*
       * Create some options for libdroplet.
       *
       * DPL_OPTION_NOALLOC - we provide the buffer to copy the data into
       *                      no need to let the library allocate memory we
       *                      need to free after copying the data.
       */
      memset(&dpl_options, 0, sizeof(dpl_options));
      dpl_options.mask |= DPL_OPTION_NOALLOC;

      dpl_flags = DPL_VFILE_FLAG_CREAT | DPL_VFILE_FLAG_RDWR;
      status = dpl_open(m_ctx, /* context */
                        getVolCatName(), /* locator */
                        dpl_flags, /* flags */
                        &dpl_options, /* options */
                        NULL, /* condition */
                        NULL, /* metadata */
                        NULL, /* sysmd */
                        NULL, /* query_params */
                        NULL, /* stream_status */
                        &m_vfd);

      switch (status) {
      case DPL_SUCCESS:
         break;
      default:
         Mmsg2(errmsg, _("Failed to open %s using dpl_open(): ERR=%s.\n"),
               getVolCatName(), dpl_status_str(status));
         return false;
      }
   }

   return true;
}
Beispiel #13
0
/*
 * Open a volume using libdroplet.
 */
int object_store_device::d_open(const char *pathname, int flags, int mode)
{
   dpl_status_t status;
   dpl_vfile_flag_t dpl_flags;
   dpl_option_t dpl_options;

#if 1
   Mmsg1(errmsg, _("Object Storage devices are not yet supported, please disable %s\n"), dev_name);
   return -1;
#endif

   /*
    * Initialize the droplet library when its not done previously.
    */
   P(mutex);
   if (droplet_reference_count == 0) {
      status = dpl_init();
      if (status != DPL_SUCCESS) {
         V(mutex);
         return -1;
      }

      dpl_set_log_func(object_store_logfunc);
      droplet_reference_count++;
   }
   V(mutex);

   if (!m_object_configstring) {
      int len;
      char *bp, *next_option;
      bool done;

      if (!dev_options) {
         Mmsg0(errmsg, _("No device options configured\n"));
         Emsg0(M_FATAL, 0, errmsg);
         return -1;
      }

      m_object_configstring = bstrdup(dev_options);

      bp = m_object_configstring;
      while (bp) {
         next_option = strchr(bp, ',');
         if (next_option) {
            *next_option++ = '\0';
         }

         done = false;
         for (int i = 0; !done && device_options[i].name; i++) {
            /*
             * Try to find a matching device option.
             */
            if (bstrncasecmp(bp, device_options[i].name, device_options[i].compare_size)) {
               switch (device_options[i].type) {
               case argument_profile:
                  m_profile = bp + device_options[i].compare_size;
                  done = true;
                  break;
               case argument_bucket:
                  m_object_bucketname = bp + device_options[i].compare_size;
                  done = true;
                  break;
               default:
                  break;
               }
            }
         }

         if (!done) {
            Mmsg1(errmsg, _("Unable to parse device option: %s\n"), bp);
            Emsg0(M_FATAL, 0, errmsg);
            goto bail_out;
         }

         bp = next_option;
      }

      if (!m_profile) {
         Mmsg0(errmsg, _("No droplet profile configured\n"));
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }

      /*
       * Strip any .profile prefix from the libdroplet profile name.
       */
      len = strlen(m_profile);
      if (len > 8 && bstrcasecmp(m_profile + (len - 8), ".profile")) {
         m_profile[len - 8] = '\0';
      }
   }

   /*
    * See if we need to setup a new context for this device.
    */
   if (!m_ctx) {
      char *bp;

      /*
       * See if this is a path.
       */
      bp = strrchr(m_object_configstring, '/');
      if (!bp) {
         /*
          * Only a profile name.
          */
         m_ctx = dpl_ctx_new(NULL, m_object_configstring);
      } else {
         if (bp == m_object_configstring) {
            /*
             * Profile in root of filesystem
             */
            m_ctx = dpl_ctx_new("/", bp + 1);
         } else {
            /*
             * Profile somewhere else.
             */
            *bp++ = '\0';
            m_ctx = dpl_ctx_new(m_object_configstring, bp);
         }
      }

      /*
       * If we failed to allocate a new context fail the open.
       */
      if (!m_ctx) {
         Mmsg1(errmsg, _("Failed to create a new context using config %s\n"), dev_options);
         return -1;
      }

      /*
       * Login if that is needed for this backend.
       */
      status = dpl_login(m_ctx);
      switch (status) {
      case DPL_SUCCESS:
         break;
      case DPL_ENOTSUPP:
         /*
          * Backend doesn't support login which is fine.
          */
         break;
      default:
         Mmsg2(errmsg, _("Failed to login for voume %s using dpl_login(): ERR=%s.\n"),
               getVolCatName(), dpl_status_str(status));
         return -1;
      }

      /*
       * If a bucketname was defined set it in the context.
       */
      if (m_object_bucketname) {
         m_ctx->cur_bucket = m_object_bucketname;
      }
   }

   /*
    * See if we don't have a file open already.
    */
   if (m_vfd) {
      dpl_close(m_vfd);
      m_vfd = NULL;
   }

   /*
    * Create some options for libdroplet.
    *
    * DPL_OPTION_NOALLOC - we provide the buffer to copy the data into
    *                      no need to let the library allocate memory we
    *                      need to free after copying the data.
    */
   memset(&dpl_options, 0, sizeof(dpl_options));
   dpl_options.mask |= DPL_OPTION_NOALLOC;

   if (flags & O_CREAT) {
      dpl_flags = DPL_VFILE_FLAG_CREAT | DPL_VFILE_FLAG_RDWR;
      status = dpl_open(m_ctx, /* context */
                        getVolCatName(), /* locator */
                        dpl_flags, /* flags */
                        &dpl_options, /* options */
                        NULL, /* condition */
                        NULL, /* metadata */
                        NULL, /* sysmd */
                        NULL, /* query_params */
                        NULL, /* stream_status */
                        &m_vfd);
   } else {
      dpl_flags = DPL_VFILE_FLAG_RDWR;
      status = dpl_open(m_ctx, /* context */
                        getVolCatName(), /* locator */
                        dpl_flags, /* flags */
                        &dpl_options, /* options */
                        NULL, /* condition */
                        NULL, /* metadata */
                        NULL, /* sysmd */
                        NULL, /* query_params */
                        NULL, /* stream_status */
                        &m_vfd);
   }

   switch (status) {
   case DPL_SUCCESS:
      m_offset = 0;
      return 0;
   default:
      Mmsg2(errmsg, _("Failed to open %s using dpl_open(): ERR=%s.\n"),
            getVolCatName(), dpl_status_str(status));
      m_vfd = NULL;
      return droplet_errno_to_system_errno(status);
   }

bail_out:
   return -1;
}
Beispiel #14
0
/*
 * Open a volume using gfapi.
 */
int gfapi_device::d_open(const char *pathname, int flags, int mode)
{
   int status;
   POOL_MEM virtual_filename(PM_FNAME);

   /*
    * Parse the gluster URI.
    */
   if (!m_gfapi_volume) {
      m_gfapi_volume = bstrdup(dev_name);
      if (!parse_gfapi_devicename(m_gfapi_volume,
                                  &m_transport,
                                  &m_servername,
                                  &m_volumename,
                                  &m_basedir,
                                  &m_serverport)) {
         Mmsg1(errmsg, _("Unable to parse device URI %s.\n"), dev_name);
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }
   }

   /*
    * See if we need to setup a Gluster context.
    */
   if (!m_glfs) {
      m_glfs = glfs_new(m_volumename);
      if (!m_glfs) {
         Mmsg1(errmsg, _("Unable to create new Gluster context for volumename %s.\n"), m_volumename);
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }

      status = glfs_set_volfile_server(m_glfs, (m_transport) ? m_transport : "tcp", m_servername, m_serverport);
      if (status < 0) {
         Mmsg3(errmsg, _("Unable to initialize Gluster management server for transport %s, servername %s, serverport %d\n"),
               (m_transport) ? m_transport : "tcp", m_servername, m_serverport);
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }

      status = glfs_init(m_glfs);
      if (status < 0) {
         Mmsg1(errmsg, _("Unable to initialize Gluster for volumename %s.\n"), m_volumename);
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }
   }

   /*
    * See if we don't have a file open already.
    */
   if (m_gfd) {
      glfs_close(m_gfd);
      m_gfd = NULL;
   }

   /*
    * See if we store in an explicit directory.
    */
   if (m_basedir) {
      struct stat st;

      /*
       * Make sure the dir exists if one is defined.
       */
      Mmsg(virtual_filename, "/%s", m_basedir);
      if (glfs_stat(m_glfs, virtual_filename.c_str(), &st) != 0) {
         switch (errno) {
         case ENOENT:
            if (!gfapi_makedir(m_glfs, virtual_filename.c_str())) {
               Mmsg1(errmsg, _("Specified glusterfs direcory %s cannot be created.\n"), virtual_filename.c_str());
               Emsg0(M_FATAL, 0, errmsg);
               goto bail_out;
            }
            break;
         default:
            goto bail_out;
         }
      } else {
         if (!S_ISDIR(st.st_mode)) {
            Mmsg1(errmsg, _("Specified glusterfs direcory %s is not a directory.\n"), virtual_filename.c_str());
            Emsg0(M_FATAL, 0, errmsg);
            goto bail_out;
         }
      }

      Mmsg(virtual_filename, "/%s/%s", m_basedir, getVolCatName());
   } else {
      Mmsg(virtual_filename, "%s", getVolCatName());
   }

   /*
    * See if the O_CREAT flag is set as glfs_open doesn't support that flag and you have to call glfs_creat then.
    */
   if (flags & O_CREAT) {
      m_gfd = glfs_creat(m_glfs, virtual_filename.c_str(), flags, mode);
   } else {
      m_gfd = glfs_open(m_glfs, virtual_filename.c_str(), flags);
   }

   if (!m_gfd) {
      goto bail_out;
   }

   return 0;

bail_out:
   /*
    * Cleanup the Gluster context.
    */
   if (m_glfs) {
      glfs_fini(m_glfs);
      m_glfs = NULL;
   }

   return -1;
}