MacOS renameatx_np, 원자 스왑 파일 이름 바꾸기에 해당하는 *BSD가 있습니까?

MacOS renameatx_np, 원자 스왑 파일 이름 바꾸기에 해당하는 *BSD가 있습니까?

나는 다음과 같은 *BSD 호환 C 함수를 만들려고 합니다.아래의 것:

int
fs_ext__swap (const char *from, const char *to) {
  int res = renameatx_np(AT_FDCWD, from, AT_FDCWD, to, RENAME_SWAP);

  return res == -1 ? uv_translate_sys_error(errno) : res;
}

'renameatx_np' is invalid in C99 [-Wimplicit-function-declaration]현재 제가 아는 한, 빌드 오류( )가 발생하고 있습니다 .renameatx_np기능MacOS에 고유합니다. *BSD에 상응하는 것이 있습니까(저는 OpenBSD 7.3 atm을 사용하고 있습니다)?

RENAME_SWAP플래그를 제거하고 기능을 다음으로 변경하면 어떤 위험이 발생합니까?renameat(편집: 이것을 시도했는데 빌드 및 컴파일이 잘 되었지만 업스트림 테스트 중에 ENOENT 오류가 발생했습니다.)?

내 계획은 다음과 같습니다링카트그리고풀리다renameatx_np의 기능을 시뮬레이션하는 함수입니다.

이 문제를 어떻게 처리할 수 있나요?

답변1

제목 질문에 대한 짧은 대답은 다음과 같습니다.아니요,내가 아는 한.

그러나 fs_ext__swap 함수를 구현하는 데 사용할 수 있는 네이티브 함수가 충분합니다. 그게 다야내가 해냈어:

#include <fcntl.h>
#include <stdint.h>
#include <uv.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <libgen.h>

#include "../include/fs-ext.h"
#include "platform.h"

void random_string_len10(char *str){
  // Creates a 10 char long random alpha-numeric string (with in the input char array). Note the input array *str must have length of 11 to allow for 10 chars and a '\0' termination.
  const char charset[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  size_t charset_length = strlen(charset);
  size_t str_length = 10;

  for (size_t i = 0; i < str_length; ++i){
    str[i] = charset[arc4random_uniform(charset_length -1)];
  }
  str[str_length] = '\0';
}

int append_file_to_path_string(char *path, char *filename, char *result)
{
  // function to append a filename to directory name. Directory name must have a slash at the end.
  size_t path_length = strlen(path);
  size_t filename_length = strlen(filename);
  size_t result_size = path_length + filename_length + 1; // +1 for null terminator

  if (result_size > PATH_MAX ) {
      fprintf(stderr, "Cannot append file name to to path; result size is too large!\n");
      return EXIT_FAILURE;
  }

  strncpy(result, path, path_length);
  strncpy(result + path_length, filename, filename_length);
  result[result_size - 1] = '\0'; // Ensure null termination

  return EXIT_SUCCESS;
}

void append_slash(char *str) {
  // appends a slash to an input string
    size_t len = strlen(str);
    if (len > 0 && str[len -1] != '/' && len < PATH_MAX-1) {
        str[len] = '/';
        str[len+1] = '\0';
    }
}

int
swap_directories (const char *from, const char *to) {
  // *****************
  // Prep temporary directory with same underlying path as from
  char temp_dir[PATH_MAX];
  snprintf(temp_dir,sizeof(temp_dir), "%s.swap_temp", from);

  // *****************
  // Perform series of rename operations to swap to and from directories. 

  // 1. Rename fromdir to tempdir
  if( renameat( AT_FDCWD, from, AT_FDCWD, temp_dir) == -1) {
    printf("Renameat from - temp failed.\n");
    return uv_translate_sys_error(errno);  
  }  else {
    printf("Renameat from - to  worked!\n");
  }
  // 2. Rename todir to fromdir
  if( renameat( AT_FDCWD, to, AT_FDCWD, from) == -1) {
    printf("Renameat to - from failed.\n");
    return uv_translate_sys_error(errno);  
  }  else {
    printf("Renameat to - from  worked!\n");
  } 
  // 3. Rename temp_dir(now original fromdir) to todir
  if( renameat( AT_FDCWD, temp_dir, AT_FDCWD, to) == -1) {
    printf("Renameat temp - to failed.\n");
    if( renameat( AT_FDCWD, from, AT_FDCWD, to) == -1) {  printf("Rollback failed.\n");}
    return uv_translate_sys_error(errno);  
  }  else {
    printf("Renameat temp - to  worked!\n");
  }

  return 0;
}

int
swap_files (const char *from, const char *to) {

  // *****************
  // Prep temporary files with random names. Must share path of input files to avoid cross file system error.

  char temp_nameA[11];
  char temp_nameB[11];

  random_string_len10(temp_nameA);
  random_string_len10(temp_nameB);

  char *to_path = dirname(strdup(to));    
  size_t pathlen = strlen(to_path);

  if ( pathlen + 1 < PATH_MAX){
      append_slash(to_path);    
  } else {
    return -1;
  }

  char temp_fileA[PATH_MAX];
  char temp_fileB[PATH_MAX];

  append_file_to_path_string(to_path,temp_nameA,temp_fileA);
  append_file_to_path_string(to_path,temp_nameB,temp_fileB); 

  // *****************
  // Perform series of linking and unlinking operations to swap to and from file. "TO-file" and "FROM-file" in the comments denote the original underlying file objects.

  // 1. LINK (from,tempA) tempA and from can access FROM-file
  if( linkat( AT_FDCWD, from, AT_FDCWD, temp_fileA,0)== -1) {
    printf("link(from tempA) failed.\n");
    return uv_translate_sys_error(errno); 

  }
  else {
    printf("link(from tempA) worked!\n");
  }
  // 2. LINK (to,tempB) tempB and to can access TO-file
  if( linkat( AT_FDCWD, to, AT_FDCWD, temp_fileB,0)== -1) {
    printf("link(to tempB) failed.\n");
    return uv_translate_sys_error(errno);  
  } else {
    printf("link(to tempB) worked!\n");
  }
   // 3. UNLINK (from) only tempA can access FROM-file
  if( unlinkat( AT_FDCWD, from,0)== -1) {
    printf("unlink(from) failed.\n");
    return uv_translate_sys_error(errno); 
  } else {
    printf("unlink(from) worked!\n");
  }

  // 4. UNLINK (to) only tempB can access TO-file
  if( unlinkat( AT_FDCWD, to,0)== -1) {
    printf("unlink(to) failed.\n");
    return uv_translate_sys_error(errno); 
  }  else {
    printf("unlink(to) worked!\n");
  }

  // 5. LINK (tempA,to) tempA and to can access FROM-file
  if( linkat( AT_FDCWD, temp_fileA, AT_FDCWD, to,0)== -1) {
    printf("link(tempB to) failed.\n");
    return uv_translate_sys_error(errno);  
  }  else {
    printf("link(to tempB) worked!\n");
  }

  // 6. LINK (tempB,from) tempB and from can access TO-file
  if( linkat( AT_FDCWD, temp_fileB, AT_FDCWD, from,0)== -1) {
    printf("link(tempB from) failed.\n");
    return uv_translate_sys_error(errno);  
  } else {
    printf("link(tempB,from) worked!\n");
  }

  // 7. UNLINK (tempA) only to can access FROM-file
  if( unlinkat( AT_FDCWD, temp_fileA,0)== -1) {
    printf("unlink(tempA) failed.\n");
    return uv_translate_sys_error(errno); 
  } else {
    printf("unlink(tempA) worked!\n");
  }

  // 8. UNLINK (tempB) only from can access TO-file
  if( unlinkat( AT_FDCWD, temp_fileB,0)== -1) {
    printf("unlink(tempB) failed.\n");
    return uv_translate_sys_error(errno); 
  } else {
    printf("unlink(tempB) worked!\n");
  }

  return 0;
}

int
fs_ext__swap (const char *from, const char *to) {
  // use sys/stat.h to determine if from and to are files or directories
  struct stat st_from, st_to;

  int from_is_dir = stat(from, &st_from) == 0 && S_ISDIR(st_from.st_mode);
  int to_is_dir = stat(to, &st_to) == 0 && S_ISDIR(st_to.st_mode);

  // Call swap_files or swap_directories dependendent whether inputs are files or directories:
  switch (from_is_dir * 2 + to_is_dir) {
    case 0: // Both are files
      if( swap_files(from,to)!=0){ return uv_translate_sys_error(errno);} // swap files
      return 0;
    case 1: // from is file to is dir: file dir-swap seems to work with case 3 code, so no return statements included.
    case 2: // from is dir to is file
    case 3: // Both are dirs
      if (swap_directories(from,to)!=0){  return uv_translate_sys_error(errno);}
      return 0; 
    default: // something else:  ERR
      return -1;
    }
}

관련 정보