Merge branch 'js/mingw-rename-fix'
authorJunio C Hamano <gitster@pobox.com>
Fri, 28 Nov 2008 03:25:06 +0000 (19:25 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 28 Nov 2008 03:25:06 +0000 (19:25 -0800)
* js/mingw-rename-fix:
compat/mingw.c: Teach mingw_rename() to replace read-only files

1  2 
compat/mingw.c
diff --combined compat/mingw.c
index b534a8a4725617a3711c1ac4e2cc1883814b4684,45733f9e04eb87409a896898cb5a92b37e87a920..3dbe6a77ffa4675b19e7183fd49e11212cb2cda0
@@@ -1,5 -1,4 +1,5 @@@
  #include "../git-compat-util.h"
 +#include "win32.h"
  #include "../strbuf.h"
  
  unsigned int _CRT_fmode = _O_BINARY;
@@@ -32,6 -31,12 +32,6 @@@ static inline time_t filetime_to_time_t
        return (time_t)winTime;
  }
  
 -static inline size_t size_to_blocks(size_t s)
 -{
 -      return (s+511)/512;
 -}
 -
 -extern int _getdrive( void );
  /* We keep the do_lstat code in a separate function to avoid recursion.
   * When a path ends with a slash, the stat will fail with ENOENT. In
   * this case, we strip the trailing slashes and stat again.
@@@ -40,19 -45,46 +40,19 @@@ static int do_lstat(const char *file_na
  {
        WIN32_FILE_ATTRIBUTE_DATA fdata;
  
 -      if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {
 -              int fMode = S_IREAD;
 -              if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 -                      fMode |= S_IFDIR;
 -              else
 -                      fMode |= S_IFREG;
 -              if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
 -                      fMode |= S_IWRITE;
 -
 +      if (!(errno = get_file_attr(file_name, &fdata))) {
                buf->st_ino = 0;
                buf->st_gid = 0;
                buf->st_uid = 0;
 -              buf->st_mode = fMode;
 +              buf->st_nlink = 1;
 +              buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
                buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
 -              buf->st_blocks = size_to_blocks(buf->st_size);
 -              buf->st_dev = _getdrive() - 1;
 +              buf->st_dev = buf->st_rdev = 0; /* not used by Git */
                buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
                buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
                buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 -              errno = 0;
                return 0;
        }
 -
 -      switch (GetLastError()) {
 -      case ERROR_ACCESS_DENIED:
 -      case ERROR_SHARING_VIOLATION:
 -      case ERROR_LOCK_VIOLATION:
 -      case ERROR_SHARING_BUFFER_EXCEEDED:
 -              errno = EACCES;
 -              break;
 -      case ERROR_BUFFER_OVERFLOW:
 -              errno = ENAMETOOLONG;
 -              break;
 -      case ERROR_NOT_ENOUGH_MEMORY:
 -              errno = ENOMEM;
 -              break;
 -      default:
 -              errno = ENOENT;
 -              break;
 -      }
        return -1;
  }
  
@@@ -62,7 -94,7 +62,7 @@@
   * complete. Note that Git stat()s are redirected to mingw_lstat()
   * too, since Windows doesn't really handle symlinks that well.
   */
 -int mingw_lstat(const char *file_name, struct mingw_stat *buf)
 +int mingw_lstat(const char *file_name, struct stat *buf)
  {
        int namelen;
        static char alt_name[PATH_MAX];
  }
  
  #undef fstat
 -#undef stat
 -int mingw_fstat(int fd, struct mingw_stat *buf)
 +int mingw_fstat(int fd, struct stat *buf)
  {
        HANDLE fh = (HANDLE)_get_osfhandle(fd);
        BY_HANDLE_FILE_INFORMATION fdata;
                return -1;
        }
        /* direct non-file handles to MS's fstat() */
 -      if (GetFileType(fh) != FILE_TYPE_DISK) {
 -              struct stat st;
 -              if (fstat(fd, &st))
 -                      return -1;
 -              buf->st_ino = st.st_ino;
 -              buf->st_gid = st.st_gid;
 -              buf->st_uid = st.st_uid;
 -              buf->st_mode = st.st_mode;
 -              buf->st_size = st.st_size;
 -              buf->st_blocks = size_to_blocks(buf->st_size);
 -              buf->st_dev = st.st_dev;
 -              buf->st_atime = st.st_atime;
 -              buf->st_mtime = st.st_mtime;
 -              buf->st_ctime = st.st_ctime;
 -              return 0;
 -      }
 +      if (GetFileType(fh) != FILE_TYPE_DISK)
 +              return fstat(fd, buf);
  
        if (GetFileInformationByHandle(fh, &fdata)) {
 -              int fMode = S_IREAD;
 -              if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 -                      fMode |= S_IFDIR;
 -              else
 -                      fMode |= S_IFREG;
 -              if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
 -                      fMode |= S_IWRITE;
 -
                buf->st_ino = 0;
                buf->st_gid = 0;
                buf->st_uid = 0;
 -              buf->st_mode = fMode;
 +              buf->st_nlink = 1;
 +              buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
                buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
 -              buf->st_blocks = size_to_blocks(buf->st_size);
 -              buf->st_dev = _getdrive() - 1;
 +              buf->st_dev = buf->st_rdev = 0; /* not used by Git */
                buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
                buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
                buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
@@@ -228,13 -283,8 +228,13 @@@ int poll(struct pollfd *ufds, unsigned 
  {
        int i, pending;
  
 -      if (timeout != -1)
 +      if (timeout >= 0) {
 +              if (nfds == 0) {
 +                      Sleep(timeout);
 +                      return 0;
 +              }
                return errno = EINVAL, error("poll timeout not supported");
 +      }
  
        /* When there is only one fd to wait for, then we pretend that
         * input is available and let the actual wait happen when the
@@@ -536,16 -586,12 +536,16 @@@ static pid_t mingw_spawnve(const char *
                 * would normally create a console window. But
                 * since we'll be redirecting std streams, we do
                 * not need the console.
 +               * It is necessary to use DETACHED_PROCESS
 +               * instead of CREATE_NO_WINDOW to make ssh
 +               * recognize that it has no console.
                 */
 -              flags = CREATE_NO_WINDOW;
 +              flags = DETACHED_PROCESS;
        } else {
                /* There is already a console. If we specified
 -               * CREATE_NO_WINDOW here, too, Windows would
 +               * DETACHED_PROCESS here, too, Windows would
                 * disassociate the child from the console.
 +               * The same is true for CREATE_NO_WINDOW.
                 * Go figure!
                 */
                flags = 0;
@@@ -819,6 -865,8 +819,8 @@@ int mingw_connect(int sockfd, struct so
  #undef rename
  int mingw_rename(const char *pold, const char *pnew)
  {
+       DWORD attrs;
        /*
         * Try native rename() first to get errno right.
         * It is based on MoveFile(), which cannot overwrite existing files.
        if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
                return 0;
        /* TODO: translate more errors */
-       if (GetLastError() == ERROR_ACCESS_DENIED) {
-               DWORD attrs = GetFileAttributes(pnew);
-               if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
+       if (GetLastError() == ERROR_ACCESS_DENIED &&
+           (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
+               if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
                        errno = EISDIR;
                        return -1;
                }
+               if ((attrs & FILE_ATTRIBUTE_READONLY) &&
+                   SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+                       if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
+                               return 0;
+                       /* revert file attributes on failure */
+                       SetFileAttributes(pnew, attrs);
+               }
        }
        errno = EACCES;
        return -1;