Re: Git changes permissions on directories when deleting files.
Yes... though I'm just letting Gentoo compile it for me and I'm not doing anything serious enough to justify downloading/installing GIT by hand and next to the one that's already there. So I just worked from the tarball that Gentoo uses and added stuff. Any other day and I'd be all over that git usage ;)
I did run into more permissions being messed up, so I grepped for
rmdir and replaced /all/ instances of it in git's C code. I haven't
had anymore trouble so far. Here's the newer patch:
diff -crB git-1.7.3.4/dir.c git-1.7.3.4-new/dir.c
*** git-1.7.3.4/dir.c Wed Mar 2 13:00:54 2011
--- git-1.7.3.4-new/dir.c Thu Mar 10 11:09:32 2011
***************
*** 994,999 ****
--- 994,1022 ----
return ret;
}
+ int rmdir_on_broken_cifs(const char *path)
+ {
+ struct stat sb;
+ if (stat(path, &sb) < 0) {
+ /* Oh well, hopefully if we can't stat it
+ * it is already gone or we don't have
+ * permissions to screw it up anyway. */
+ return rmdir(path);
+ }
+ if (rmdir(path) == 0) {
+ /* it worked, nothing to restore */
+ return 0;
+ }
+ /* maybe remove this conditional if you can trigger
+ * the problem with other types of errors */
+ if (errno != ENOTEMPTY)
+ return -1;
+ if (chmod(path, sb.st_mode) < 0)
+ warning("we probably just screwed up the permissions of %s",
+ path);
+ return -1;
+ }
+
int remove_dir_recursively(struct strbuf *path, int flag)
{
DIR *dir;
***************
*** 1037,1043 **** strbuf_setlen(path, original_len);
if (!ret)
! ret = rmdir(path->buf);
return ret;
}
--- 1060,1066 ----
strbuf_setlen(path, original_len);
if (!ret)
! ret = rmdir_on_broken_cifs(path->buf);
return ret;
}
***************
*** 1066,1072 ****
slash = dirs + (slash - name);
do {
*slash = '\0';
! } while (rmdir(dirs) == 0 && (slash = strrchr(dirs, '/')));
free(dirs);
}
return 0;
--- 1090,1096 ----
slash = dirs + (slash - name);
do {
*slash = '\0';
! } while (rmdir_on_broken_cifs(dirs) == 0 && (slash = strrchr(dirs, '/')));
free(dirs);
}
return 0;
Only in git-1.7.3.4: dir.c~
diff -crB git-1.7.3.4/dir.h git-1.7.3.4-new/dir.h
*** git-1.7.3.4/dir.h Wed Dec 15 21:52:11 2010
--- git-1.7.3.4-new/dir.h Thu Mar 10 11:09:13 2011
***************
*** 101,104 ****
--- 101,106 ----
/* tries to remove the path with empty directories along it, ignores ENOENT */
extern int remove_path(const char *path);+ extern int rmdir_on_broken_cifs(const char *path);
+
#endif
diff -crB git-1.7.3.4/entry.c git-1.7.3.4-new/entry.c
*** git-1.7.3.4/entry.c Wed Dec 15 21:52:11 2010
--- git-1.7.3.4-new/entry.c Thu Mar 10 11:12:25 2011
***************
*** 68,74 ****
die_errno("cannot unlink '%s'", pathbuf);
}
closedir(dir);
! if (rmdir(path))
die_errno("cannot rmdir '%s'", path);
}--- 68,74 ----
die_errno("cannot unlink '%s'", pathbuf);
}
closedir(dir);
! if (rmdir_on_broken_cifs(path))
die_errno("cannot rmdir '%s'", path);
}diff -crB git-1.7.3.4/pack-refs.c git-1.7.3.4-new/pack-refs.c
*** git-1.7.3.4/pack-refs.c Wed Dec 15 21:52:11 2010
--- git-1.7.3.4-new/pack-refs.c Thu Mar 10 12:34:53 2011
***************
*** 2,7 ****
--- 2,8 ----
#include "refs.h"
#include "tag.h"
#include "pack-refs.h"
+ #include "dir.h"
struct ref_to_prune {
struct ref_to_prune *next;
***************
*** 86,92 ****
if (q == p)
break;
*q = '\0';
! if (rmdir(git_path("%s", name)))
break;
}
}
--- 87,93 ----
if (q == p)
break;
*q = '\0';
! if (rmdir_on_broken_cifs(git_path("%s", name)))
break;
}
}
diff -crB git-1.7.3.4/symlinks.c git-1.7.3.4-new/symlinks.c
*** git-1.7.3.4/symlinks.c Wed Dec 15 21:52:11 2010
--- git-1.7.3.4-new/symlinks.c Thu Mar 10 11:24:08 2011
***************
*** 1,4 ****
--- 1,5 ----
#include "cache.h"
+ #include "dir.h" /*
* Returns the length (on a path component basis) of the longest
***************
*** 255,261 ****
{
while (removal.len > new_len) {
removal.path[removal.len] = '\0';
! if (rmdir(removal.path))
break;
do {
removal.len--;
--- 256,262 ----
{
while (removal.len > new_len) {
removal.path[removal.len] = '\0';
! if (rmdir_on_broken_cifs(removal.path))
break;
do {
removal.len--;
diff -crB git-1.7.3.4/wrapper.c git-1.7.3.4-new/wrapper.c
*** git-1.7.3.4/wrapper.c Wed Dec 15 21:52:11 2010
--- git-1.7.3.4-new/wrapper.c Thu Mar 10 11:12:36 2011
***************
*** 2,7 ****
--- 2,8 ----
* Various trivial helper wrappers around standard functions
*/
#include "cache.h"
+ #include "dir.h" static void try_to_free_builtin(size_t size)
{
***************
*** 346,352 **** int rmdir_or_warn(const char *file)
{
! return warn_if_unremovable("rmdir", file, rmdir(file));
} int remove_or_warn(unsigned int mode, const char *file)
--- 347,353 ----
int rmdir_or_warn(const char *file)
{
! return warn_if_unremovable("rmdir", file, rmdir_on_broken_cifs(file));
} int remove_or_warn(unsigned int mode, const char *file)