From c85703bdcc44833a214aba1f091301c789156d24 Mon Sep 17 00:00:00 2001 From: Yijie Shen Date: Wed, 1 May 2024 14:22:50 -0700 Subject: [PATCH] feat: rename with overwrite option fix to match java signature --- c_src/libhdfs/hdfs.c | 77 ++++++++++++++++++++++++++++++++++++++++++++ c_src/libhdfs/hdfs.h | 10 ++++++ src/hdfs.rs | 8 +++-- 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/c_src/libhdfs/hdfs.c b/c_src/libhdfs/hdfs.c index 7f36775..34ae654 100644 --- a/c_src/libhdfs/hdfs.c +++ b/c_src/libhdfs/hdfs.c @@ -42,6 +42,7 @@ #define JAVA_NET_URI "java/net/URI" #define JAVA_STRING "java/lang/String" #define READ_OPTION "org/apache/hadoop/fs/ReadOption" +#define RENAME_OPTION "org/apache/hadoop/fs/Options$Rename" #define JAVA_VOID "V" @@ -2025,6 +2026,82 @@ int hdfsRename(hdfsFS fs, const char *oldPath, const char *newPath) return ret; } +int hdfsRenameOverwrite(hdfsFS fs, const char *oldPath, const char *newPath) +{ + // JAVA EQUIVALENT: + // Path old = new Path(oldPath); + // Path new = new Path(newPath); + // fs.rename(old, new, overwrite = true); + + jobject jFS = (jobject)fs; + jthrowable jthr; + jobject jOldPath = NULL, jNewPath = NULL; + int ret = -1; + jvalue jVal; + jobject enumInst = NULL, enumSetObj = NULL; + + //Get the JNIEnv* corresponding to current thread + JNIEnv* env = getJNIEnv(); + if (env == NULL) { + errno = EINTERNAL; + return -1; + } + + jthr = fetchEnumInstance(env, RENAME_OPTION, + "OVERWRITE", &enumInst); + if (jthr) { + errno = printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "hdfsRename: fetchEnumInstance(" RENAME_OPTION ", OVERWRITE)"); + goto done; + } + jthr = invokeMethod(env, &jVal, STATIC, NULL, + "java/util/EnumSet", "of", + "(Ljava/lang/Enum;)Ljava/util/EnumSet;", enumInst); + if (jthr) { + goto done; + } + enumSetObj = jVal.l; + + jclass enumSetClass = (*env)->FindClass(env, "java/util/EnumSet"); + jmethodID toArrayTypedMethodID = (*env)->GetMethodID(env, enumSetClass, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;"); + jclass renameOptionClass = (*env)->FindClass(env, "org/apache/hadoop/fs/Options$Rename"); + jobjectArray typedArray = (*env)->NewObjectArray(env, 1, renameOptionClass, NULL); + jobjectArray enumArray = (jobjectArray)(*env)->CallObjectMethod(env, enumSetObj, toArrayTypedMethodID, typedArray); + + jthr = constructNewObjectOfPath(env, oldPath, &jOldPath); + if (jthr) { + errno = printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "hdfsRename: constructNewObjectOfPath(%s)", oldPath); + goto done; + } + jthr = constructNewObjectOfPath(env, newPath, &jNewPath); + if (jthr) { + errno = printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "hdfsRename: constructNewObjectOfPath(%s)", newPath); + goto done; + } + + // Rename the file + // TODO: use rename2 here? (See HDFS-3592) + jthr = invokeMethod(env, &jVal, INSTANCE, jFS, HADOOP_FS, "rename", + "(Lorg/apache/hadoop/fs/Path;Lorg/apache/hadoop/fs/Path;[Lorg/apache/hadoop/fs/Options$Rename;)V", + jOldPath, jNewPath, enumArray); + if (jthr) { + errno = printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "hdfsRename(oldPath=%s, newPath=%s): FileSystem#rename", + oldPath, newPath); + goto done; + } + ret = 0; + +done: + destroyLocalReference(env, jOldPath); + destroyLocalReference(env, jNewPath); + destroyLocalReference(env, enumInst); + destroyLocalReference(env, enumSetObj); + return ret; +} + char* hdfsGetWorkingDirectory(hdfsFS fs, char* buffer, size_t bufferSize) diff --git a/c_src/libhdfs/hdfs.h b/c_src/libhdfs/hdfs.h index 267ca59..88f99bf 100644 --- a/c_src/libhdfs/hdfs.h +++ b/c_src/libhdfs/hdfs.h @@ -712,6 +712,16 @@ extern "C" { LIBHDFS_EXTERNAL int hdfsRename(hdfsFS fs, const char* oldPath, const char* newPath); + /** + * hdfsRename - Rename file and overwrite if exists. + * @param fs The configured filesystem handle. + * @param oldPath The path of the source file. + * @param newPath The path of the destination file. + * @return Returns 0 on success, -1 on error. + */ + LIBHDFS_EXTERNAL + int hdfsRenameOverwrite(hdfsFS fs, const char* oldPath, const char* newPath); + /** * hdfsGetWorkingDirectory - Get the current working directory for diff --git a/src/hdfs.rs b/src/hdfs.rs index 73c5269..d5b6a67 100644 --- a/src/hdfs.rs +++ b/src/hdfs.rs @@ -440,11 +440,15 @@ impl HdfsFs { } /// Rename file. - pub fn rename(&self, old_path: &str, new_path: &str) -> Result { + pub fn rename(&self, old_path: &str, new_path: &str, overwrite: bool) -> Result { if unsafe { let cstr_old_path = CString::new(old_path).unwrap(); let cstr_new_path = CString::new(new_path).unwrap(); - hdfsRename(self.raw, cstr_old_path.as_ptr(), cstr_new_path.as_ptr()) + if overwrite { + hdfsRenameOverwrite(self.raw, cstr_old_path.as_ptr(), cstr_new_path.as_ptr()) + } else { + hdfsRename(self.raw, cstr_old_path.as_ptr(), cstr_new_path.as_ptr()) + } } == 0 { Ok(true)