Branch: Tag:

2018-04-24

2018-04-24 14:32:10 by Henrik Grubbström (Grubba) <grubba@grubba.org>

Stdio [NT]: Clean up mv().

mv() now uses fd_rename() and is thus UTF8/UTF16 aware.

1528:    INT32 i;    struct pike_string *str1;    struct pike_string *str2; - #ifdef __NT__ -  int orig_errno = errno; -  int err; -  PIKE_STAT_T st; - #endif +        VALID_FILE_IO("mv","write");   
1560:    return;    }    - #ifndef __NT__ -  i=rename(str1->str, str2->str); - #else +  i = fd_rename(str1->str, str2->str);    -  /* Emulate the behavior of unix rename(2) when the destination exists. */ -  -  if (movefileex) { -  if (MoveFileEx (str1->str, str2->str, 0)) { -  i = 0; -  goto no_nt_rename_kludge; -  } -  if ((i = GetLastError()) != ERROR_ALREADY_EXISTS) -  goto no_nt_rename_kludge; -  } -  else { -  /* Fall back to rename() for W98 and earlier. Unlike MoveFileEx, -  * it can't move directories between directories. */ -  if (!rename (str1->str, str2->str)) { -  i = 0; -  goto no_nt_rename_kludge; -  } -  if ((i = errno) != EEXIST) -  goto no_nt_rename_kludge; -  } -  - #ifdef HAVE_LSTAT -  if (fd_lstat (str2->str, &st)) goto no_nt_rename_kludge; - #else -  if (fd_stat (str2->str, &st)) goto no_nt_rename_kludge; - #endif -  -  if ((st.st_mode & S_IFMT) != S_IFDIR && movefileex) { -  /* MoveFileEx can overwrite a file but not a dir. */ -  if (!(st.st_mode & _S_IWRITE)) -  /* Like in f_rm, we got to handle the case that NT looks on the -  * permissions on the file itself before removing it. */ -  if (chmod (str2->str, st.st_mode | _S_IWRITE)) -  goto no_nt_rename_kludge; -  if (movefileex (str1->str, str2->str, MOVEFILE_REPLACE_EXISTING)) -  i = 0; /* Success. */ -  else -  chmod (str2->str, st.st_mode); -  } -  -  else { -  char *s = malloc (str2->len + 2), *p; -  if (!s) { -  i = movefileex ? ERROR_NOT_ENOUGH_MEMORY : ENOMEM; -  goto no_nt_rename_kludge; -  } -  memcpy (s, str2->str, str2->len); -  p = s + str2->len; -  p[2] = 0; -  -  if ((st.st_mode & S_IFMT) == S_IFDIR) { -  /* Check first that the target is empty if it's a directory, so -  * that we won't even bother trying with the stunt below. */ -  WIN32_FIND_DATA *dir = malloc (sizeof (WIN32_FIND_DATA)); -  HANDLE h; -  if (!dir) { -  i = movefileex ? ERROR_NOT_ENOUGH_MEMORY : ENOMEM; -  goto nt_rename_kludge_end; -  } -  p[0] = '/', p[1] = '*'; -  h = FindFirstFile (s, dir); -  if (h != INVALID_HANDLE_VALUE) { -  do { -  if (dir->cFileName[0] != '.' || -  (dir->cFileName[1] && -  (dir->cFileName[1] != '.' || dir->cFileName[2]))) { -  /* Target dir not empty. */ -  FindClose (h); -  free (dir); -  goto nt_rename_kludge_end; -  } -  } while (FindNextFile (h, dir)); -  FindClose (h); -  } -  free (dir); -  } -  -  /* Move away the target temporarily to do the move, then cleanup -  * or undo depending on how it went. */ -  for (p[0] = 'A'; p[0] != 'Z'; p[0]++) -  for (p[1] = 'A'; p[1] != 'Z'; p[1]++) { -  if (movefileex) { -  if (!movefileex (str2->str, s, 0)) { -  if (GetLastError() == ERROR_ALREADY_EXISTS) continue; -  else goto nt_rename_kludge_end; -  } -  } -  else { -  if (rename (str2->str, s)) { -  if (errno == EEXIST) continue; -  else goto nt_rename_kludge_end; -  } -  } -  if (movefileex ? -  movefileex (str1->str, str2->str, MOVEFILE_REPLACE_EXISTING) : -  !rename (str1->str, str2->str)) { -  if (!(st.st_mode & _S_IWRITE)) -  if (chmod (s, st.st_mode | _S_IWRITE)) -  goto nt_rename_kludge_fail; -  if ((st.st_mode & S_IFMT) == S_IFDIR) { -  while ((err = rmdir (s)) && (errno == EINTR)) -  ; -  } else { -  while ((err = unlink (s)) && (errno == EINTR)) -  ; -  } -  if (!err) { /* Success. */ -  i = 0; -  goto nt_rename_kludge_end; -  } -  -  nt_rename_kludge_fail: -  /* Couldn't remove the old target, perhaps the directory -  * grew files. */ -  if (!(st.st_mode & _S_IWRITE)) -  chmod (s, st.st_mode); -  if (movefileex ? -  !movefileex (str2->str, str1->str, MOVEFILE_REPLACE_EXISTING) : -  rename (str2->str, str1->str)) { -  /* Old target left behind but the rename is still -  * successful, so we claim success anyway in lack of -  * better error reporting capabilities. */ -  i = 0; -  goto nt_rename_kludge_end; -  } -  } -  -  rename (s, str2->str); -  goto nt_rename_kludge_end; -  } -  -  nt_rename_kludge_end: -  free (s); -  } -  - no_nt_rename_kludge: -  if (i) { -  if (movefileex) -  switch (i) { -  /* Try to translate NT errors to errno codes that NT's rename() -  * would return. */ -  case ERROR_INVALID_NAME: -  errno = EINVAL; -  break; -  case ERROR_NOT_ENOUGH_MEMORY: -  errno = ENOMEM; -  break; -  case ERROR_FILE_NOT_FOUND: -  case ERROR_PATH_NOT_FOUND: -  errno = ENOENT; -  break; -  case ERROR_ALREADY_EXISTS: -  errno = EEXIST; -  break; -  default: -  errno = EACCES; -  } -  } -  else errno = orig_errno; - #endif /* __NT__ */ -  +     pop_n_elems(args);    push_int(!i);   }