示例#1
0
文件: impl.cpp 项目: iychoi/syndicate
// stat a file--build a manifest request, and set its mode
// return 0 on success 
// return -ESTALE if the inode is not local 
// return -ENOENT if we don't have it
// return -ENOMEM on OOM
// return -errno on error 
static int UG_impl_stat( struct SG_gateway* gateway, struct SG_request_data* reqdat, struct SG_request_data* entity_info, mode_t* mode, void* cls ) {
  
   int rc = 0;
   struct UG_state* ug = (struct UG_state*)SG_gateway_cls( gateway );
   struct md_entry ent_info;

   rc = UG_stat_raw( ug, reqdat->fs_path, &ent_info );
   if( rc != 0 ) {
      
      SG_error("UG_stat_raw('%s') rc = %d\n", reqdat->fs_path, rc );
      return rc;
   }
   
   if( ent_info.coordinator != SG_gateway_id( gateway ) ) {
     
      // not ours 
      SG_error("Not the coordinator of '%s' (it is now %" PRIu64 ")\n", reqdat->fs_path, ent_info.coordinator );
      md_entry_free( &ent_info );
      return -ESTALE;
   }
  
   if( mode != NULL ) {
      *mode = ent_info.mode;
   }

   if( entity_info != NULL ) {
      
      rc = SG_request_data_init_manifest( gateway, reqdat->fs_path, ent_info.file_id, ent_info.version, ent_info.manifest_mtime_sec, ent_info.manifest_mtime_nsec, entity_info );
      if( rc != 0 ) {

         // OOM 
         md_entry_free( &ent_info );
         return -ENOMEM;
      }

      if( ent_info.type != MD_ENTRY_FILE ) {

         // not a file 
         md_entry_free( &ent_info );
         return -ENOENT;
      }
   }
   md_entry_free( &ent_info );

   return 0;
}
示例#2
0
void meta_data_destroy(meta_data_t *md) /* {{{ */
{
  if (md == NULL)
    return;

  md_entry_free(md->head);
  pthread_mutex_destroy(&md->lock);
  free(md);
} /* }}} void meta_data_destroy */
示例#3
0
static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
{
  meta_entry_t *this;
  meta_entry_t *prev;

  if ((md == NULL) || (e == NULL))
    return (-EINVAL);

  pthread_mutex_lock (&md->lock);

  prev = NULL;
  this = md->head;
  while (this != NULL)
  {
    if (strcasecmp (e->key, this->key) == 0)
      break;

    prev = this;
    this = this->next;
  }

  if (this == NULL)
  {
    /* This key does not exist yet. */
    if (md->head == NULL)
      md->head = e;
    else
    {
      assert (prev != NULL);
      prev->next = e;
    }

    e->next = NULL;
  }
  else /* (this != NULL) */
  {
    if (prev == NULL)
      md->head = e;
    else
      prev->next = e;

    e->next = this->next;
  }

  pthread_mutex_unlock (&md->lock);

  if (this != NULL)
  {
    this->next = NULL;
    md_entry_free (this);
  }

  return (0);
} /* }}} int md_entry_insert */
示例#4
0
/* XXX: The lock on md must be held while calling this function! */
static int md_entry_insert_clone(meta_data_t *md, meta_entry_t *orig) /* {{{ */
{
  meta_entry_t *e;
  meta_entry_t *this;
  meta_entry_t *prev;

  /* WARNINGS :
   *  - we do not check that md and e != NULL here. You should have done it
   * before.
   *  - we do not use the lock. You should have set it before.
   */

  e = md_entry_clone_contents(orig);

  prev = NULL;
  this = md->head;
  while (this != NULL) {
    if (strcasecmp(e->key, this->key) == 0)
      break;

    prev = this;
    this = this->next;
  }

  if (this == NULL) {
    /* This key does not exist yet. */
    if (md->head == NULL)
      md->head = e;
    else {
      assert(prev != NULL);
      prev->next = e;
    }

    e->next = NULL;
  } else /* (this != NULL) */
  {
    if (prev == NULL)
      md->head = e;
    else
      prev->next = e;

    e->next = this->next;
  }

  if (this != NULL) {
    this->next = NULL;
    md_entry_free(this);
  }

  return (0);
} /* }}} int md_entry_insert_clone */
示例#5
0
// utime
int fs_entry_utime( struct fs_core* core, char const* path, struct utimbuf* tb, uint64_t user, uint64_t volume ) {
   int err = 0;
   uint64_t parent_id = 0;
   char* parent_name = NULL;
   
   struct fs_entry* fent = fs_entry_resolve_path_and_parent_info( core, path, user, volume, true, &err, &parent_id, &parent_name );
   if( !fent || err ) {
      if( !err )
         err = -ENOMEM;

      return err;
   }

   // check permissions
   if( tb == NULL && !IS_WRITEABLE( fent->mode, fent->owner, fent->volume, user, volume ) ) {
      fs_entry_unlock( fent );
      return -EACCES;
   }
   if( tb != NULL && fent->owner != user ) {
      fs_entry_unlock( fent );
      return -EACCES;
   }

   if( tb != NULL ) {
      fent->mtime_sec = tb->modtime;
      fent->atime = tb->actime;
   }
   else {
      struct timespec ts;
      clock_gettime( CLOCK_REALTIME, &ts );

      fent->mtime_sec = ts.tv_sec;
      fent->mtime_nsec = ts.tv_nsec;
      fent->atime = fent->mtime_sec;
   }

   fent->atime = currentTimeSeconds();

   // post update
   struct md_entry up;
   fs_entry_to_md_entry( core, &up, fent, parent_id, parent_name );

   int rc = ms_client_update( core->ms, &fent->write_nonce, &up );
   if( rc != 0 ) {
      errorf("ms_client_update(%s) rc = %d\n", path, rc );
   }

   md_entry_free( &up );
   fs_entry_unlock( fent );
   return rc;
}
示例#6
0
// do the create remotely on the MS
// child must be write-locked
int fs_entry_do_MS_create( struct fs_core* core, char const* path, struct fs_entry* child, uint64_t parent_id, char const* parent_name ) {

    // create this file in the MS
    struct md_entry data;
    int rc = 0;

    fs_entry_to_md_entry( core, &data, child, parent_id, parent_name );

    // create synchronously, obtaining the child's file ID and write_nonce
    rc = ms_client_create( core->ms, &child->file_id, &child->write_nonce, &data );

    md_entry_free( &data );

    return rc;
}
示例#7
0
static void md_entry_free(meta_entry_t *e) /* {{{ */
{
  if (e == NULL)
    return;

  free(e->key);

  if (e->type == MD_TYPE_STRING)
    free(e->value.mv_string);

  if (e->next != NULL)
    md_entry_free(e->next);

  free(e);
} /* }}} void md_entry_free */
示例#8
0
/*
 * Add functions
 */
int meta_data_add_string(meta_data_t *md, /* {{{ */
                         const char *key, const char *value) {
  meta_entry_t *e;

  if ((md == NULL) || (key == NULL) || (value == NULL))
    return (-EINVAL);

  e = md_entry_alloc(key);
  if (e == NULL)
    return (-ENOMEM);

  e->value.mv_string = md_strdup(value);
  if (e->value.mv_string == NULL) {
    ERROR("meta_data_add_string: md_strdup failed.");
    md_entry_free(e);
    return (-ENOMEM);
  }
  e->type = MD_TYPE_STRING;

  return (md_entry_insert(md, e));
} /* }}} int meta_data_add_string */
示例#9
0
int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
{
  meta_entry_t *this;
  meta_entry_t *prev;

  if ((md == NULL) || (key == NULL))
    return (-EINVAL);

  pthread_mutex_lock (&md->lock);

  prev = NULL;
  this = md->head;
  while (this != NULL)
  {
    if (strcasecmp (key, this->key) == 0)
      break;

    prev = this;
    this = this->next;
  }

  if (this == NULL)
  {
    pthread_mutex_unlock (&md->lock);
    return (-ENOENT);
  }

  if (prev == NULL)
    md->head = this->next;
  else
    prev->next = this->next;

  pthread_mutex_unlock (&md->lock);

  this->next = NULL;
  md_entry_free (this);

  return (0);
} /* }}} int meta_data_delete */
示例#10
0
// chmod
int fs_entry_chmod( struct fs_core* core, char const* path, uint64_t user, uint64_t volume, mode_t mode ) {
   int err = 0;
   uint64_t parent_id = 0;
   char* parent_name = NULL;
   
   struct fs_entry* fent = fs_entry_resolve_path_and_parent_info( core, path, user, volume, true, &err, &parent_id, &parent_name );
   if( !fent || err ) {
      if( !err )
         err = -ENOMEM;

      return err;
   }

   // can't chmod unless we own the file
   if( fent->owner != user ) {
      fs_entry_unlock( fent );
      free( parent_name );
      return -EPERM;
   }

   fent->mode = mode;
   
   // post update
   struct md_entry up;
   fs_entry_to_md_entry( core, &up, fent, parent_id, parent_name );

   int rc = ms_client_update( core->ms, &fent->write_nonce, &up );
   if( rc != 0 ) {
      errorf("ms_client_update(%s) rc = %d\n", path, rc );
   }

   md_entry_free( &up );
   fs_entry_unlock( fent );
   free( parent_name );

   return rc;
}
示例#11
0
// remove a directory, if it is empty
int fs_entry_rmdir( struct fs_core* core, char const* path, uint64_t user, uint64_t volume ) {

   if( core->gateway == GATEWAY_ANON ) {
      errorf("%s", "Removing directories is forbidden for anonymous gateways\n");
      return -EPERM;
   }
   
   // get some info about this directory first
   int rc = 0;
   
   char* fpath = strdup( path );
   md_sanitize_path( fpath );
   
   // revalidate this path
   rc = fs_entry_revalidate_path( core, volume, fpath );
   if( rc != 0 && rc != -ENOENT ) {
      // consistency cannot be guaranteed
      errorf("fs_entry_revalidate_path(%s) rc = %d\n", fpath, rc );
      free( fpath );
      return rc;
   }
   
   free( fpath );

   int err = 0;
   struct fs_entry* dent = fs_entry_resolve_path( core, path, user, volume, false, &err );
   if( !dent || err ) {
      return err;
   }

   if( dent->ftype != FTYPE_DIR ) {
      fs_entry_unlock( dent );
      return -ENOTDIR;
   }

   char* path_dirname = md_dirname( path, NULL );

   struct fs_entry* parent = fs_entry_resolve_path( core, path_dirname, user, volume, true, &err );

   free( path_dirname );

   if( !parent || err ) {
      fs_entry_unlock( dent );

      return err;
   }

   // IS THE PARENT EMPTY?
   if( fs_entry_set_count( dent->children ) > 2 ) {
      // nope
      fs_entry_unlock( dent );
      fs_entry_unlock( parent );

      return -ENOTEMPTY;
   }


   struct md_entry ent;
   fs_entry_to_md_entry( core, &ent, dent, parent->file_id, parent->name );

   // tell the MS that this directory should go away
   rc = ms_client_delete( core->ms, &ent );
   md_entry_free( &ent );

   if( rc != 0 ) {
      errorf( "ms_client_delete(%s) rc = %d\n", path, rc );
      rc = -EREMOTEIO;

      fs_entry_unlock( dent );
      fs_entry_unlock( parent );
   }
   else {

      fs_entry_unlock( dent );

      // detach from the filesystem 
      rc = fs_entry_detach_lowlevel( core, parent, dent );
      if( rc != 0 ) {
         errorf("fs_entry_detach_lowlevel(%s) rc = %d\n", path, rc );
      }
      
      fs_entry_unlock( parent );
   }
   
   return rc;
}
示例#12
0
// unlink a file from the filesystem
// pass -1 if the version is not known, or pass the known version to be unlinked
// return -EUCLEAN if we failed to garbage-collect, but needed to (i.e. a manifest was missing)
// return -EREMOTEIO for failure to revalidate metadata 
// return -ESTALE if the given information is out of date
int fs_entry_versioned_unlink( struct fs_core* core, char const* path, uint64_t file_id, uint64_t coordinator_id, int64_t known_version, uint64_t owner, uint64_t volume, uint64_t gateway_id, 
                               bool check_file_id_and_coordinator_id ) {
   
   // can't modify state if anonymous
   if( core->gateway == SG_GATEWAY_ANON ) {
      SG_error("%s", "Writing is forbidden for anonymous gateways\n");
      return -EPERM;
   }
   
   // get some info about this file first
   int rc = 0;
   int err = 0;
   bool no_manifest = false;
   
   // consistency check
   err = fs_entry_revalidate_path( core, path );
   if( err != 0 ) {
      SG_error("fs_entry_revalidate_path(%s) rc = %d\n", path, err );
      
      if( err == -ENOENT )
         return -ENOENT;
      
      return -EREMOTEIO;
   }
   
   // look up the parent
   char* path_dirname = md_dirname( path, NULL );
   char* path_basename = md_basename( path, NULL );
   
   struct fs_entry* parent = fs_entry_resolve_path( core, path_dirname, owner, volume, true, &err );

   free( path_dirname );

   if( !parent || err ) {

      free( path_basename );
      return err;
   }
   
   if( parent->ftype != FTYPE_DIR ) {
      fs_entry_unlock( parent );
      free( path_basename );
      return err;
   }
   
   // get the child
   struct fs_entry* fent = fs_entry_set_find_name( parent->children, path_basename );
   
   free( path_basename );
   
   if( fent == NULL ) {
      fs_entry_unlock( fent );
      fs_entry_unlock( parent );
      return -ENOENT;
   }
   
   fs_entry_wlock( fent );
   
   bool local = FS_ENTRY_LOCAL( core, fent );
   int64_t version = fent->version;
   
   if( check_file_id_and_coordinator_id ) {
      if( fent->file_id != file_id ) {
         SG_error("Remote unlink to file %s ID %" PRIX64 ", expected %" PRIX64 "\n", path, file_id, fent->file_id );
         fs_entry_unlock( fent );
         fs_entry_unlock( parent );
         return -ESTALE;
      }
      
      if( fent->coordinator != coordinator_id ) {
         SG_error("Remote unlink to file %s coordinator %" PRIu64 ", expected %" PRIu64 "\n", path, coordinator_id, fent->coordinator );
         fs_entry_unlock( fent );
         fs_entry_unlock( parent );
         return -ESTALE;
      }
   }
   
   if( known_version > 0 && fent->version > 0 && fent->version != known_version ) {
      SG_error("Remote unlink to file %s version %" PRId64 ", expected %" PRId64 "\n", path, known_version, fent->version );
      fs_entry_unlock( fent );
      fs_entry_unlock( parent );
      return -ESTALE;
   }
   
   // make sure the manifest is fresh, so we delete every block
   // only need to worry about this if file has > 0 size
   if( fent->size > 0 ) {
      
      // try to get it
      err = fs_entry_revalidate_manifest( core, path, fent );
            
      if( err != 0 ) {
         SG_error( "fs_entry_revalidate_manifest(%s) rc = %d\n", path, err );
         
         if( err == -ENOENT ) {
            // continue without a manifest 
            no_manifest = true;
            SG_error("WARN: no manifest found for %s %" PRIX64 ".  Assuming data is already vacuumed.\n", path, fent->file_id );
         }
         else {
            // some other problem
            fs_entry_unlock( fent );
            fs_entry_unlock( parent );
            return err;
         }
      }
   }
   
   // tell the driver we're deleting 
   int driver_rc = driver_delete_file( core, core->closure, path, fent );
   if( driver_rc != 0 ) {
      SG_error("driver_delete_file(%s %" PRIX64 ") rc = %d\n", path, fent->file_id, driver_rc );
      
      fs_entry_unlock( fent );
      fs_entry_unlock( parent );
      return driver_rc;
   }
   
   rc = 0;
   
   if( !local ) {
      // this is someone else's file; tell them to unlink
      Serialization::WriteMsg* detach_request = new Serialization::WriteMsg();

      fs_entry_init_write_message( detach_request, core, Serialization::WriteMsg::DETACH );
      
      fs_entry_prepare_detach_message( detach_request, path, fent, version );

      Serialization::WriteMsg* detach_ack = new Serialization::WriteMsg();
      
      // send the write message, or become the coordinator
      rc = fs_entry_send_write_or_coordinate( core, path, fent, detach_request, detach_ack );
      
      if( rc < 0 ) {
         SG_error( "fs_entry_send_write_or_coordinate(%s) rc = %d\n", path, rc );
      }
      else if( rc == 0 ) {
         // successfully sent
         if( detach_ack->type() != Serialization::WriteMsg::ACCEPTED ) {
            if( detach_ack->type() == Serialization::WriteMsg::ERROR ) {
               // could not detach on the remote end
               SG_error( "remote unlink error = %d (%s)\n", detach_ack->errorcode(), detach_ack->errortxt().c_str() );
               rc = detach_ack->errorcode();
            }
            else {
               // unknown message
               SG_error( "remote unlink invalid message %d\n", detach_ack->type() );
               rc = -EIO;
            }
         }
      }
      else {
         // we're now the coordinator.          
         local = true;
      }

      delete detach_ack;
      delete detach_request;
   }

   if( local ) {
      // we're responsible for this file
      // mark the file as deleted, so it won't show up again in any listing 
      fent->deletion_in_progress = true;
      
      // safe to unlock parent--it won't be empty (in a rmdir-able sense) until fent is fully garbage-collected, but fent won't be listed either
      fs_entry_unlock( parent );
      
      // garbage-collect, then unlink on the MS.  Loop this until we succeed in unlinking on the MS (which can only happen 
      // once all of fent's data has been garbage-collected).
      while( true ) {
         
         if( !no_manifest ) {
            // if we got the latest manifest, garbage-collect all writes on the file 
            rc = fs_entry_vacuumer_file( core, path, fent );
            
            if( rc != 0 ) {
               SG_error("fs_entry_vacuumer_vacuum_file( %s %" PRIX64 " ) rc = %d\n", path, fent->file_id, rc );
               
               // failed to garbage-collect...need to un-delete fent
               fent->deletion_in_progress = false;
               fs_entry_unlock( fent );
               
               return -EREMOTEIO;
            }
         }
         
         // tell the metadata server we just unlinked
         // preserve the entry information so we can issue a deletion
         struct md_entry ent;
         fs_entry_to_md_entry( core, &ent, fent, parent->file_id, parent->name );

         rc = ms_client_delete( core->ms, &ent );
         md_entry_free( &ent );
            
         if( rc != 0 ) {
            SG_error( "ms_client_delete(%s) rc = %d\n", path, rc );
            
            if( rc == -EAGAIN ) {
               if( !no_manifest ) {
                  // try vacuuming again--some write got added in between our garbage-collection and our unlink request
                  rc = 0;
                  continue;
               }
               else {
                  // there are un-garbage-collected writes, but we have no manifest, so we can't vacuum in order to proceed with the delete.
                  SG_error("MEMORY LEAK DETECTED: No manifest for %" PRIX64 " available; unable to vacuum!\n", fent->file_id );
                  
                  // failed to garbage-collect...need to un-delete fent
                  fent->deletion_in_progress = false;
                  fs_entry_unlock( fent );
                  
                  return -EUCLEAN;
               }
            }
            else {
               
               // something more serious 
               rc = -EREMOTEIO;
               
               fent->deletion_in_progress = false;
               fs_entry_unlock( fent );
               return rc;
            }
         }
         else {
            // success!
            break;
         }
      }
      
      // re-lock the parent--it's guaranteed to exist, since it's not empty 
      fs_entry_wlock( parent );
      
      // unlock fent--we're done with it 
      fs_entry_unlock( fent );
      
      // detatch fent from parent
      rc = fs_entry_detach_lowlevel( core, parent, fent );
      if( rc != 0 ) {
         SG_error("fs_entry_detach_lowlevel(%" PRIX64 ") rc = %d\n", fent->file_id, rc );
         fs_entry_unlock( parent );
         
         return rc;
      }
      
      fs_entry_unlock( parent );
   }
   
   return rc;
}
示例#13
0
// make a node (regular files only at this time)
int fs_entry_mknod( struct fs_core* core, char const* path, mode_t mode, dev_t dev, uint64_t user, uint64_t vol ) {
    // only regular files at this time...
    if( ! ( S_ISREG( mode ) || S_ISFIFO( mode ) ) ) {
        return -ENOTSUP;
    }

    // revalidate this path
    int rc = fs_entry_revalidate_path( core, path );
    if( rc != 0 && rc != -ENOENT ) {
        // consistency cannot be guaranteed
        SG_error("fs_entry_revalidate_path(%s) rc = %d\n", path, rc );
        return rc;
    }

    int err = 0;

    // get the parent directory and lock it
    char* path_dirname = md_dirname( path, NULL );
    struct fs_entry* parent = fs_entry_resolve_path( core, path_dirname, user, vol, true, &err );
    free( path_dirname );

    if( !IS_DIR_READABLE( parent->mode, parent->owner, parent->volume, user, vol ) ) {
        // not searchable
        fs_entry_unlock( parent );
        return -EACCES;
    }

    if( !IS_WRITEABLE( parent->mode, parent->owner, parent->volume, user, vol ) ) {
        // not writeable
        fs_entry_unlock( parent );
        return -EACCES;
    }

    uint64_t parent_id = parent->file_id;
    char* parent_name = strdup( parent->name );

    char* path_basename = md_basename( path, NULL );

    // make sure it doesn't exist already (or isn't in the process of being deleted, since we might have to re-create it if deleting it fails)
    if( fs_entry_set_find_name( parent->children, path_basename ) != NULL ) {
        free( path_basename );
        fs_entry_unlock( parent );
        free( parent_name );
        return -EEXIST;
    }

    struct fs_entry* child = (struct fs_entry*)calloc( sizeof(struct fs_entry), 1 );

    struct timespec ts;
    clock_gettime( CLOCK_REALTIME, &ts );
    int mmode = 0;
    if (S_ISFIFO(mode)) {
        mmode = ( mode & 0777 ) | S_IFIFO;
        err = fs_entry_init_fifo( core, child, path_basename, 0, fs_entry_next_file_version(), user, core->gateway, vol, mmode, 0, ts.tv_sec, ts.tv_nsec, 0, 0 );
    }
    if (S_ISREG(mode)) {
        mmode = ( mode & 0777 );
        err = fs_entry_init_file( core, child, path_basename, 0, fs_entry_next_file_version(), user, core->gateway, vol, mmode, 0, ts.tv_sec, ts.tv_nsec, 0, 0 );
    }

    if( err == 0 ) {

        // mark it as created in this session
        child->created_in_session = true;

        // we're creating, so this manifest is initialized (to zero blocks)
        child->manifest->initialize_empty( child->version );

        fs_entry_wlock( child );

        // call the driver
        err = driver_create_file( core, core->closure, path, child );

        if( err != 0 ) {
            // undo
            SG_error("driver_create_file(%s) rc = %d\n", path, err );

            child->open_count = 0;

            fs_entry_unlock( child );
            fs_entry_destroy( child, false );
            free( child );
        }

        else {

            // attach the file
            fs_entry_attach_lowlevel( core, parent, child );

            struct md_entry data;
            fs_entry_to_md_entry( core, &data, child, parent_id, parent_name );

            // create the child on the MS, obtaining its file ID and write nonce
            err = ms_client_create( core->ms, &child->file_id, &child->write_nonce, &data );

            md_entry_free( &data );

            if( err != 0 ) {
                SG_error( "ms_client_create(%s) rc = %d\n", path, err );
                err = -EREMOTEIO;

                child->open_count = 0;
                fs_entry_unlock( child );
                fs_entry_detach_lowlevel( core, parent, child );
                free( child );
            }
            else {
                fs_entry_unlock( child );
            }
        }
    }

    fs_entry_unlock( parent );

    free( parent_name );
    free( path_basename );

    return err;
}
// finish up getting directory metadata, and free up the download handle
// return 0 on success, and set *batch_id to this download's batch
//   *ret_num_children to the number of children downloaded, and *max_gen to be the largest generation number seen.
// return -ENOMEM on OOM 
static int ms_client_get_dir_metadata_end( struct ms_client* client, uint64_t parent_id, struct md_download_context* dlctx, ms_client_dir_listing* dir_listing, int64_t* batch_id, size_t* ret_num_children, int64_t* max_gen ) {
   
   int rc = 0;
   int listing_error = 0;
   struct md_entry* children = NULL;
   size_t num_children = 0;
   size_t num_unique_children = 0;
   CURL* curl = NULL;
   
   int64_t biggest_generation = 0;
   
   struct ms_client_get_dir_download_state* dlstate = (struct ms_client_get_dir_download_state*)md_download_context_get_cls( dlctx );
   md_download_context_set_cls( dlctx, NULL );

   // download status?
   rc = ms_client_download_parse_errors( dlctx );
   
   if( rc != 0 ) {
      
      if( rc != -EAGAIN) {
         // fatal 
         SG_error("ms_client_download_parse_errors( %p ) rc = %d\n", dlctx, rc );
      }
      
      md_download_context_unref_free( dlctx, &curl );
      if( curl != NULL ) {
          curl_easy_cleanup( curl );
      }

      ms_client_get_dir_download_state_free( dlstate );
      dlstate = NULL;
      
      return rc;
   }
   
   // collect the data 
   rc = ms_client_listing_read_entries( client, dlctx, &children, &num_children, &listing_error );
   
   // done with the download
   md_download_context_unref_free( dlctx, &curl );
   if( curl != NULL ) {
      curl_easy_cleanup( curl );
   }

   ms_client_get_dir_download_state_free( dlstate );
   dlstate = NULL;
   
   // did we get valid data?
   if( rc != 0 ) {
      
      SG_error("ms_client_listing_read_entries(%p) rc = %d\n", dlctx, rc );
      return rc;
   }
   
   if( listing_error != MS_LISTING_NEW ) {
      
      // somehow we didn't get data.  shouldn't happen in listdir
      SG_error("BUG: failed to get listing data for %" PRIX64 ", listing_error = %d\n", parent_id, listing_error );
      return -ENODATA;
   }
   
   // merge children in 
   for( unsigned int i = 0; i < num_children; i++ ) {
      
      uint64_t file_id = children[i].file_id;
      
      SG_debug("%p: %" PRIX64 "\n", dlctx, file_id );
      
      if( dir_listing->count( file_id ) > 0 ) {
         
         SG_warn("Duplicate child %" PRIX64 "\n", file_id );
         md_entry_free( &children[i] );
         continue;
      }
      
      try {
         
         (*dir_listing)[ file_id ] = children[i];
      }
      catch( bad_alloc& ba ) {
         rc = -ENOMEM;
         break;
      }
      
      // generation?
      if( children[i].generation > biggest_generation ) {
         
         biggest_generation = children[i].generation;
      }

      num_unique_children ++;
   }
   
   // NOTE: shallow free--we've copied the children into dir_listing
   SG_safe_free( children );
   
   *ret_num_children = num_unique_children;
   *max_gen = biggest_generation;
   
   return 0;
}
示例#15
0
// entry point 
int main( int argc, char** argv ) {
   
   int rc = 0;
   struct UG_state* ug = NULL;
   struct SG_gateway* gateway = NULL;
   int path_optind = 0;
   struct tool_opts opts;
   struct md_entry ent_data;
   char* path = NULL;
   uint64_t new_coord = 0;
   
   memset( &opts, 0, sizeof(tool_opts) );
   
   rc = parse_args( argc, argv, &opts );
   if( rc != 0 ) {
      
      usage( argv[0], "file [file...]" );
      md_common_usage();
      exit(1);
   }
   
   // setup...
   ug = UG_init( argc, argv, opts.anonymous );
   if( ug == NULL ) {
      
      SG_error("%s", "UG_init failed\n" );
      exit(1);
   }
   
   gateway = UG_state_gateway( ug );
   
   // get the list of files to coordinate 
   path_optind = SG_gateway_first_arg_optind( gateway );
   if( path_optind == argc ) {
      
      usage( argv[0], "file [file...]" );
      md_common_usage();
      UG_shutdown( ug );
      exit(1);
   }
   
   for( int i = path_optind; i < argc; i++ ) {

      path = argv[i];

      // make sure this is a file...
      rc = UG_stat_raw( ug, path, &ent_data );
      if( rc != 0 ) {
         SG_error("UG_stat_raw('%s') rc = %d\n", path, rc );
         rc = 1;
         goto UG_coord_shutdown;
      }

      if( ent_data.type != MD_ENTRY_FILE ) {
         fprintf(stderr, "Not a file: %s\n", path );
         rc = 1;
         goto UG_coord_shutdown;
      }

      // if we're not the coordinator, become it 
      if( ent_data.coordinator != SG_gateway_id( gateway ) ) {

         SG_debug("Become the coordinator of '%s'\n", path );
         rc = UG_chcoord( ug, path, &new_coord );
         if( rc != 0 ) {
            fprintf(stderr, "chcoord '%s': %s\n", path, strerror(-rc) );
            rc = 1;
            goto UG_coord_shutdown;
         }
      }

      md_entry_free( &ent_data );
   }

   // proceed to handle requests
   SG_debug("%s", "Proceed to handle requests\n");

   rc = UG_main( ug );
   if( rc != 0 ) {
      fprintf(stderr, "UG_main: %s\n", strerror(-rc) );
      rc = 1;
   }

UG_coord_shutdown:
   UG_shutdown( ug );
   exit(rc);
}