⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 5 页
字号:
  {
#ifdef WIN32
      
      if (! FlushFileBuffers (filehand))
        return svn_error_wrap_apr
          (apr_get_os_error (), "Can't flush file to disk.");
      
#else
      int rv;

      do {
        rv = fsync (filehand);
      } while (rv == -1 && APR_STATUS_IS_EINTR (apr_get_os_error ()));

      /* If the file is in a memory filesystem, fsync() may return
         EINVAL.  Presumably the user knows the risks, and we can just
         ignore the error. */
      if (rv == -1 && APR_STATUS_IS_EINVAL (apr_get_os_error ()))
        return SVN_NO_ERROR;

      if (rv == -1)
        return svn_error_wrap_apr
          (apr_get_os_error (), "Can't flush file to disk.");

#endif
  }
  return SVN_NO_ERROR;
}
    


/* TODO write test for these two functions, then refactor. */

svn_error_t *
svn_stringbuf_from_file (svn_stringbuf_t **result,
                         const char *filename,
                         apr_pool_t *pool)
{
  apr_file_t *f = NULL;

  if (filename[0] == '-' && filename[1] == '\0')
    return svn_error_create
        (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
         "Reading from stdin is currently broken, so disabled");

  SVN_ERR (svn_io_file_open (&f, filename, APR_READ, APR_OS_DEFAULT, pool));

  SVN_ERR (svn_stringbuf_from_aprfile (result, f, pool));

  SVN_ERR (svn_io_file_close (f, pool));

  return SVN_NO_ERROR;
}


/* Get the name of FILE, or NULL if FILE is an unnamed stream. */
static svn_error_t *
file_name_get (const char **fname_utf8, apr_file_t *file, apr_pool_t *pool)
{
  apr_status_t apr_err;
  const char *fname;

  apr_err = apr_file_name_get (&fname, file);
  if (apr_err)
    return svn_error_wrap_apr (apr_err, "Can't get file name");

  if (fname)
    SVN_ERR (svn_path_cstring_to_utf8 (fname_utf8, fname, pool));
  else
    *fname_utf8 = NULL;

  return SVN_NO_ERROR;
}


svn_error_t *
svn_stringbuf_from_aprfile (svn_stringbuf_t **result,
                            apr_file_t *file,
                            apr_pool_t *pool)
{
  apr_size_t len;
  svn_error_t *err;
  svn_stringbuf_t *res = svn_stringbuf_create("", pool);
  char buf[BUFSIZ];

  /* XXX: We should check the incoming data for being of type binary. */

  /* apr_file_read will not return data and eof in the same call. So this loop
   * is safe from missing read data.  */
  len = sizeof(buf);
  err = svn_io_file_read (file, buf, &len, pool);
  while (! err)
    {
      svn_stringbuf_appendbytes(res, buf, len);
      len = sizeof(buf);
      err = svn_io_file_read (file, buf, &len, pool);
    }

  /* Having read all the data we *expect* EOF */
  if (err && !APR_STATUS_IS_EOF(err->apr_err))
    return err;
  svn_error_clear (err);

  /* Null terminate the stringbuf. */
  res->data[res->len] = 0;

  *result = res;
  return SVN_NO_ERROR;
}



/* Deletion. */

svn_error_t *
svn_io_remove_file (const char *path, apr_pool_t *pool)
{
  apr_status_t apr_err;
  const char *path_apr;

#ifdef WIN32
  /* Set the file writable but only on Windows, because Windows
     will not allow us to remove files that are read-only. */
  SVN_ERR (svn_io_set_file_read_write (path, TRUE, pool));
#endif /* WIN32 */

  SVN_ERR (svn_path_cstring_from_utf8 (&path_apr, path, pool));

  apr_err = apr_file_remove (path_apr, pool);
  WIN32_RETRY_LOOP (apr_err, apr_file_remove (path_apr, pool));

  if (apr_err)
    return svn_error_wrap_apr (apr_err, "Can't remove file '%s'", path);

  return SVN_NO_ERROR;
}


/*
 Mac OS X has a bug where if you're readding the contents of a
 directory via readdir in a loop, and you remove one of the entries in
 the directory and the directory has 338 or more files in it you will
 skip over some of the entries in the directory.  Needless to say,
 this causes problems if you are using this kind of loop inside a
 function that is recursively deleting a directory, because when you
 get around to removing the directory it will still have something in
 it.

 This works around the problem by inserting a rewinddir after we
 remove each item in the directory, which makes the problem go away.

 See http://subversion.tigris.org/issues/show_bug.cgi?id=1896 for more
 discussion.
*/
#if defined(__APPLE__) && defined(__MACH__)
#define MACOSX_REWINDDIR_HACK(dir, path)                                   \
  do                                                                       \
    {                                                                      \
      apr_status_t apr_err  = apr_dir_rewind (dir);                        \
      if (apr_err)                                                         \
        return svn_error_wrap_apr (apr_err, "Can't rewind directory '%s'", \
                                   path);                                  \
    }                                                                      \
  while (0)
#else
#define MACOSX_REWINDDIR_HACK(dir, path) do {} while (0)
#endif


/* Neither windows nor unix allows us to delete a non-empty
   directory.  

   This is a function to perform the equivalent of 'rm -rf'. */
svn_error_t *
svn_io_remove_dir (const char *path, apr_pool_t *pool)
{
  apr_status_t status;
  apr_dir_t *this_dir;
  apr_finfo_t this_entry;
  apr_pool_t *subpool;
  apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;
  const char *path_apr;

  /* APR doesn't like "" directories */
  if (path[0] == '\0')
    path = ".";

  /* Convert path to native here and call apr_dir_open directly,
     instead of just using svn_io_dir_open, because we're going to
     need path_apr later anyway when we remove the dir itself. */

  SVN_ERR (svn_path_cstring_from_utf8 (&path_apr, path, pool));

  status = apr_dir_open (&this_dir, path_apr, pool);
  if (status)
    return svn_error_wrap_apr (status, "Can't open directory '%s'", path);

  subpool = svn_pool_create (pool);
  for (status = apr_dir_read (&this_entry, flags, this_dir);
       status == APR_SUCCESS;
       status = apr_dir_read (&this_entry, flags, this_dir))
    {
      svn_pool_clear (subpool);
      if ((this_entry.filetype == APR_DIR)
          && ((this_entry.name[0] == '.')
              && ((this_entry.name[1] == '\0')
                  || ((this_entry.name[1] == '.')
                      && (this_entry.name[2] == '\0')))))
        {
          continue;
        }
      else  /* something other than "." or "..", so proceed */
        {
          const char *fullpath, *entry_utf8;

          SVN_ERR (svn_path_cstring_to_utf8 (&entry_utf8, this_entry.name,
                                             subpool));
          
          fullpath = svn_path_join (path, entry_utf8, subpool);

          if (this_entry.filetype == APR_DIR)
            {
              SVN_ERR (svn_io_remove_dir (fullpath, subpool));

              MACOSX_REWINDDIR_HACK (this_dir, path);
            }
          else if (this_entry.filetype == APR_REG)
            {
              /* ### Do we really need the check for APR_REG here? Shouldn't
                 we remove symlinks, pipes and whatnot, too?  --xbc */
              svn_error_t *err = svn_io_remove_file (fullpath, subpool);
              if (err)
                return svn_error_createf (err->apr_err, err,
                                          "Can't remove '%s'", fullpath);

              MACOSX_REWINDDIR_HACK (this_dir, path);
            }
        }
    }

  apr_pool_destroy (subpool);

  if (!APR_STATUS_IS_ENOENT (status))
    return svn_error_wrap_apr (status, "Can't read directory '%s'", path);

  status = apr_dir_close (this_dir);
  if (status)
    return svn_error_wrap_apr (status, "Error closing directory '%s'", path);

  status = apr_dir_remove (path_apr, pool);
  WIN32_RETRY_LOOP (status, apr_dir_remove (path_apr, pool));
  if (status)
    return svn_error_wrap_apr (status, "Can't remove '%s'", path);

  return APR_SUCCESS;
}



svn_error_t *
svn_io_get_dirents (apr_hash_t **dirents,
                    const char *path,
                    apr_pool_t *pool)
{
  apr_status_t status; 
  apr_dir_t *this_dir;
  apr_finfo_t this_entry;
  apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;

  /* These exist so we can use their addresses as hash values! */
  static const svn_node_kind_t static_svn_node_file = svn_node_file;
  static const svn_node_kind_t static_svn_node_dir = svn_node_dir;

  *dirents = apr_hash_make (pool);
  
  SVN_ERR (svn_io_dir_open (&this_dir, path, pool));

  for (status = apr_dir_read (&this_entry, flags, this_dir);
       status == APR_SUCCESS;
       status = apr_dir_read (&this_entry, flags, this_dir))
    {
      if ((this_entry.name[0] == '.')
          && ((this_entry.name[1] == '\0')
              || ((this_entry.name[1] == '.')
                  && (this_entry.name[2] == '\0'))))
        {
          continue;
        }
      else
        {
          const char *name;

          SVN_ERR (svn_path_cstring_to_utf8 (&name, this_entry.name, pool));
          
          if (this_entry.filetype == APR_REG)
            apr_hash_set (*dirents, name, APR_HASH_KEY_STRING,
                          &static_svn_node_file);
          else if (this_entry.filetype == APR_DIR)
            apr_hash_set (*dirents, name, APR_HASH_KEY_STRING,
                          &static_svn_node_dir);
          else
            /* ### symlinks, etc. will fall into this category for now.
               someday subversion will recognize them. :)  */
            apr_hash_set (*dirents, name, APR_HASH_KEY_STRING,
                          &static_svn_node_file);
        }
    }

  if (! (APR_STATUS_IS_ENOENT (status)))
    return svn_error_wrap_apr (status, "Can't read directory '%s'", path);

  status = apr_dir_close (this_dir);
  if (status)
    return svn_error_wrap_apr (status, "Error closing directory '%s'", path);
  
  return SVN_NO_ERROR;
}


svn_error_t *
svn_io_run_cmd (const char *path,
                const char *cmd,
                const char *const *args,
                int *exitcode,
                apr_exit_why_e *exitwhy,
                svn_boolean_t inherit,
                apr_file_t *infile,
                apr_file_t *outfile,
                apr_file_t *errfile,
                apr_pool_t *pool)
{
  apr_status_t apr_err;
  apr_proc_t cmd_proc;
  apr_procattr_t *cmdproc_attr;
  apr_exit_why_e exitwhy_val;
  int exitcode_val, num_args;
  const char **args_native;
  const char *cmd_apr;

  /* Create the process attributes. */
  apr_err = apr_procattr_create (&cmdproc_attr, pool); 
  if (apr_err)
    return svn_error_wrap_apr
      (apr_err, "Can't create process '%s' attributes", cmd);

  /* Make sure we invoke cmd directly, not through a shell. */
  apr_err = apr_procattr_cmdtype_set (cmdproc_attr,
                                      inherit?APR_PROGRAM_PATH:APR_PROGRAM);
  if (apr_err)
    return svn_error_wrap_apr (apr_err, "Can't set process '%s' cmdtype", cmd);

  /* Set the process's working directory. */
  if (path)
    {
      const char *path_apr;

      SVN_ERR (svn_path_cstring_from_utf8 (&path_apr, path, pool));
      apr_err = apr_procattr_dir_set (cmdproc_attr, path_apr);
      if (apr_err)
        return svn_error_wrap_apr
          (apr_err, "Can't set process '%s' directory", cmd);
    }

  /* Use requested inputs and outputs.

     ### Unfortunately each of these apr functions creates a pipe and then
     overwrites the pipe file descriptor with the descriptor we pass
     in. The pipes can then never be closed. This is an APR bug. */
  if (infile)
    {
      apr_err = apr_procattr_child_in_set (cmdproc_attr, infile, NULL);
      if (apr_err)
        return svn_error_wrap_apr
          (apr_err, "Can't set process '%s' child input", cmd);
    }
  if (outfile)
    {
      apr_err = apr_procattr_child_out_set (cmdproc_attr, outfile, NULL);
      if (apr_err)
        return svn_error_wrap_apr
          (apr_err, "Can't set process '%s' child outfile", cmd);
    }
  if (errfile)
    {
      apr_err = apr_procattr_child_err_set (cmdproc_attr, errfile, NULL);
      if (apr_err)
        return svn_error_wrap_apr
          (apr_err, "Can't set process '%s' child errfile", cmd);
    }

  /* Convert cmd and args from UTF-8 */
  SVN_ERR (svn_path_cstring_from_utf8 (&cmd_apr, cmd, pool));
  for (num_args = 0; args[num_args]; num_args++)
    ;
  args_native = apr_palloc (pool, (num_args + 1) * sizeof(char *));
  args_native[num_args] = NULL;
  while (num_args--)
    {
      /* ### Well, it turns out that on APR on Windows expects all
             program args to be in UTF-8. Callers of svn_io_run_cmd
             should be aware of that. */
      SVN_ERR (svn_path_cstring_from_utf8 (&args_native[num_args],
                                           args[num_args],
                                           pool));
    }


  /* Start the cmd command. */ 
  apr_err = apr_proc_create (&cmd_proc, cmd_apr, args_native, NULL,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -