示例#1
0
/*
 * Retrieve metadata in a given root for a given file. It does not resolve
 * paths yet, but gets the preferred versions.
 */
metadata_t *parse_metadata_for_file(char *root, char *filename)
{
  char *metafile, *dflfile, *metapath, *dflpath;
  metadata_t *metadata;

  /* Build the path for the metadata file */
  metafile = helper_get_file_name(filename, "metadata");
  metapath = helper_build_composite("SS", "/", root, metafile);
  free(metafile);

  /* Read the partial metadata */
  metadata = parse_metadata_file(metapath);
  if (!metadata)
    {
      /* No metadata, we don't know about this file yet */
      free(metapath);
      return NULL;
    }

  /* Build the path for the default version file */
  dflfile = helper_get_file_name(filename, "dfl-meta");
  dflpath = helper_build_composite("SS", "/", root, dflfile);
  free(dflfile);

  /* Parse the default version file */
  parse_default_file(dflpath, &metadata->md_dfl_vid, &metadata->md_dfl_svid);

  free(metapath);
  free(dflpath);
  return metadata;
}
示例#2
0
文件: ea.c 项目: butesa/fuse-copyfs
int ea_getxattr_rcs(const char *path, const char *name, char *value, size_t size)
{
  metadata_t *metadata;
  version_t *version;
  
  rcs_ignore_deleted = 1;
  metadata = rcs_translate_to_metadata(path, rcs_version_path);
  rcs_ignore_deleted = 0;
  if (!metadata)
    return -ENOENT;

  if (!strcmp(name, "rcs.purge"))
    {
      /* This one is write-only */
      return -EPERM;
    }
  else if (!strcmp(name, "rcs.locked_version"))
    {
      char buffer[64];
      int vid, svid;
      
      if (metadata->md_deleted)
      {
        strcpy(buffer, "0.0");
      }
      else
      {
        if (metadata->md_dfl_vid == -1)
          {
            vid = metadata->md_versions->v_vid;
            svid = metadata->md_versions->v_svid;
          }
        else
          {
            vid = metadata->md_dfl_vid;
            svid = metadata->md_dfl_svid;
          }
  
        /* Get the version number */
        snprintf(buffer, 64, "%i.%i", vid, svid);
      }

      /* Handle the EA protocol */
      if (size == 0)
        return strlen(buffer);
      if (strlen(buffer) > size)
        return -ERANGE;
      strcpy(value, buffer);
      return strlen(buffer);
    }
  else if (!strcmp(name, "rcs.metadata_dump"))
    {
      char **array, *result;
      unsigned int count;
      int res;

      /*
       * We need to pass the version metadata to userspace, but we also need
       * to pass the file type and modification type from the stat syscall,
       * since the userspace program may be running as a non-root, and thus
       * can't see the version store.
       */

      for (count = 0, version = metadata->md_versions; version;
        version = version->v_next)
        count++;
      array = safe_malloc(sizeof(char *) * (count + 1));
      memset(array, 0, sizeof(char *) * (count + 1));

      /* Traverse the version list and build the individual strings */
      for (count = 0, version = metadata->md_versions; version;
        version = version->v_next)
        {
          struct stat st_data;
      
          /* stat() the real file, but just ignore failures (bad version ?) */
          if (lstat(version->v_rfile, &st_data) < 0)
            {
              st_data.st_mode = S_IFREG;
              st_data.st_mtime = -1;
            }
          else
            st_data.st_mode &= ~07777;
      
          if (asprintf(&array[count], "%d:%d:%d:%d:%d:%lld:%ld",
            version->v_vid, version->v_svid,
            version->v_mode | st_data.st_mode, version->v_uid,
            version->v_gid, (long long)st_data.st_size, st_data.st_mtime) < 0)
            {
              unsigned int i;
      
              /* Free everything if it failed */
              for (i = 0; i < count; i++)
                free(array[i]);
              free(array);
              return -ENOMEM;
            }
      
          count++;
        }

      /* Build the final string */
      result = helper_build_composite("A", "|", array);
      helper_free_array(array);

      /* Handle the EA protocol */

      if (size == 0)
        res = strlen(result);
      else if (strlen(result) > size)
        res = -ERANGE;
      else
        {
          strcpy(value, result);
          res = strlen(result);
        }
      free(result);
      return res;
    }
  else if (!strcmp(name, "rcs.list_dir"))
    {
      struct dirent *entry;
      int res;
      DIR *dir;
      char *result;
      size_t result_size;
      string_list_t *file_list;
      string_list_t **file_list_ptr;
    
      file_list = NULL;
      file_list_ptr = &file_list;

      rcs_ignore_deleted = 1;
      version = rcs_find_version(metadata, LATEST, LATEST);
      rcs_ignore_deleted = 0;
      
      dir = opendir(version->v_rfile);
      if (!dir)
        {
          return -errno;
        }      
    
      /* Find the metadata files */
      while ((entry = readdir(dir)))
        {
          /*
           * We want the metadata files (because a versioned file is
           * behind them)
           */
          if (!strcmp(entry->d_name, METADATA_PREFIX))
            {
              /* This is the root's metadata, ignore it */
              continue;
            }
          else if (!strncmp(entry->d_name, METADATA_PREFIX,
                strlen(METADATA_PREFIX)))
            {
              char *file;
              metadata_t *file_metadata;
              int len;
      
              if (strcmp(path, "/"))
                file = helper_build_composite("SS", "/", path,
                  entry->d_name + strlen(METADATA_PREFIX));
              else
                file = helper_build_composite("-S", "/", entry->d_name +
                  strlen(METADATA_PREFIX));
              rcs_ignore_deleted = 1;
              file_metadata = rcs_translate_to_metadata(file, rcs_version_path);
              rcs_ignore_deleted = 0;
              free(file);
              if (!file_metadata)
                {
                  closedir(dir);
                  return -ENOENT;
                }
              
              *file_list_ptr = safe_malloc(sizeof(string_list_t));
              memset(*file_list_ptr, 0, sizeof(string_list_t));
              
              if (file_metadata->md_deleted)
                len = asprintf(&(*file_list_ptr)->sl_data, "0:0:0:0:0:0:0:%s",
                  entry->d_name + strlen(METADATA_PREFIX));
              else
                {
                  version_t *file_version;
                  struct stat st_data;
                  
                  file_version = rcs_find_version(file_metadata, LATEST, LATEST);
                  if (!file_version)
                    {
                      helper_free_string_list(file_list);
                      closedir(dir);
                      return -ENOENT;
                    }
                    
                  /* stat() the real file, but just ignore failures (bad version ?) */
                  if (lstat(file_version->v_rfile, &st_data) < 0)
                    {
                      st_data.st_mode = S_IFREG;
                      st_data.st_mtime = -1;
                    }
                  else
                    st_data.st_mode &= ~07777;
          
                  len = asprintf(&(*file_list_ptr)->sl_data, "%d:%d:%d:%d:%d:%lld:%ld:%s",
                    file_version->v_vid, file_version->v_svid,
                    file_version->v_mode | st_data.st_mode, file_version->v_uid,
                    file_version->v_gid, (long long)st_data.st_size, st_data.st_mtime,
                    entry->d_name + strlen(METADATA_PREFIX));
                }
              if (len < 0)
                {
                  /* Free everything if it failed */
                  helper_free_string_list(file_list);
                  closedir(dir);
                  return -ENOMEM;
                }
              
              file_list_ptr = &(*file_list_ptr)->sl_next;
            }
        }
    
      closedir(dir);

      /* Build the final string */
      result_size = helper_compose_string_list(&result, file_list, '\0');
      helper_free_string_list(file_list);

      /* Handle the EA protocol */

      if (size == 0)
        res = result_size;
      else if (result_size > size)
        res = -ERANGE;
      else
        {
          memcpy(value, result, result_size);
          res = result_size;
        }
      free(result);
      return res;
    }
  else
    {
      /* unknown rcs.*-attribute */
      return -EPERM;
    }
}
示例#3
0
static int callback_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t fill)
{
  struct dirent *entry;
  char *rpath;
  int res;
  DIR *dir;

  rpath = rcs_translate_path(path, rcs_version_path);
  dir = opendir(rpath);
  if (!dir)
    {
      free(rpath);
      return -errno;
    }

  /* Find the metadata files */
  do
    {
      entry = readdir(dir);
      if (entry)
	{
	  /*
	   * We want the metadata files (because a versionned file is
	   * behind them, the '.' and '..' directories, so that the listing
	   * looks reasonable.
	   */
	  if (!strcmp(entry->d_name, METADATA_PREFIX))
	    {
	      /* This is the root's metadata, ignore it */
	      continue;
	    }
	  else if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
	    {
	      res = fill(h, entry->d_name, 0);
	      if (res != 0)
		break;
	    }
	  else if (!strncmp(entry->d_name, METADATA_PREFIX,
			    strlen(METADATA_PREFIX)))
	    {
	      metadata_t *metadata;
	      char *file;

	      /* Check if the file is not currently in deleted state */
	      if (strcmp(path, "/"))
		file = helper_build_composite("SS", "/", path,
					      entry->d_name +
					      strlen(METADATA_PREFIX));
	      else
		file = helper_build_composite("-S", "/", entry->d_name +
					      strlen(METADATA_PREFIX));
	      metadata = rcs_translate_to_metadata(file, rcs_version_path);
	      free(file);
	      if (metadata && !metadata->md_deleted)
		{
		  res = fill(h, entry->d_name + strlen(METADATA_PREFIX), 0);
		  if (res != 0)
		    break;
		}
	    }
	}
    }
  while (entry);

  closedir(dir);
  free(rpath);
  return 0;
}
示例#4
0
static int callback_rmdir(const char *path)
{
  metadata_t *dir_metadata;
  version_t *version;
  struct stat st_rfile;
  char *metafile;
  DIR *dir;
  struct dirent *entry;
  char *rpath;

  dir_metadata = rcs_translate_to_metadata(path, rcs_version_path);
  if (!dir_metadata || dir_metadata->md_deleted)
    return -ENOENT;
  version = rcs_find_version(dir_metadata, LATEST, LATEST);
  if (lstat(version->v_rfile, &st_rfile) == -1)
    return -errno;
  if (!S_ISDIR(st_rfile.st_mode))
    return -ENOTDIR;

  rpath = rcs_translate_path(path, rcs_version_path);
  dir = opendir(rpath);
  if (!dir) {
    free(rpath);
    return -errno;
  }

  /* Check if there is any file in the directory */
  do {
    entry = readdir(dir);
    if (entry) {
      /*
       * We want the metadata files (because a versionned file is
       * behind them, the '.' and '..' directories, so that the listing
       * looks reasonable.
       */
      if (!strcmp(entry->d_name, METADATA_PREFIX)) {
	/* This is the root's metadata, ignore it */
	continue;
      } else if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
	continue ;
      } else if (!strncmp(entry->d_name, METADATA_PREFIX,
			    strlen(METADATA_PREFIX))) {
	metadata_t *metadata;
	char *file;

	/* Check if the file is not currently in deleted state */
	if (strcmp(path, "/"))
	  file = helper_build_composite("SS", "/", path,
					entry->d_name +
					strlen(METADATA_PREFIX));
	else
	  file = helper_build_composite("-S", "/", entry->d_name +
					strlen(METADATA_PREFIX));
	metadata = rcs_translate_to_metadata(file, rcs_version_path);
	free(file);
	if (metadata && !metadata->md_deleted) {
	  /* we found a file */
	  closedir(dir);
	  free(rpath);
	  return -ENOTEMPTY;
	}
      }
    }
  }
  while (entry);

  closedir(dir);
  free(rpath);

  dir_metadata->md_deleted = 1;
  metafile = helper_build_meta_name(dir_metadata->md_vfile, METADATA_PREFIX);
  if (write_metadata_file(metafile, dir_metadata) == -1) {
    free(metafile);
    return -errno;
  }
  free(metafile);
  return 0;
}