Anyone with a Mac, please try this test program.
- save it as bug.c
- make bug
- cp -r $svn_trunk/build data
- while :; do rm -rf work; ./bug; done
Let us know what happens. On one particular Mac we have, we get
the random 0 byte files:
work/gen_base.py 0 != 39113, unlink_error=2
work/get-py-info.py 0 != 4255, unlink_error=2
work/vc6-build.bat.in 0 != 5630, unlink_error=2
work/gen_make.py 0 != 20457, unlink_error=2
work/svn_config.vcproj.ezt 0 != 2515, unlink_error=2
work/swig.m4 0 != 9023, unlink_error=2
work/serf.dsp.ezt 0 != 2912, unlink_error=2
...
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Demonstrate the bug:
Copy path to a tmp file in work_dir, rename the tmp file to
basename(path), and unlink the tmpfile. rename works so the tmp does
not exist, yet the target size is correct before the unlink call and
incorrect (0) after. The unlink always raises ENOENT.
*/
static void
work(char *path, char *accpath, struct stat *st, char *work_dir)
{
char *buf, *target, *tmp;
FILE *out;
int in;
ssize_t bytes;
struct stat target_st;
int unlink_error;
target = tmp = NULL;
/* Setup target and tmp file names. */
asprintf(&target, "%s/%s", work_dir, basename(path));
asprintf(&tmp, "%s/%s", work_dir, "tmp");
/* Open tmp for writing. */
if ((out = fopen(tmp, "w")) == NULL) {
fprintf(stderr, "fopen(%s, w): ", tmp);
perror("");
exit(errno);
}
/* Open path for reading. */
if ((in = open(accpath, O_RDONLY)) == -1) {
fprintf(stderr, "open(%s, O_RDONLY): ", path);
perror("");
exit(errno);
}
/* Allocate a buffer. */
buf = malloc(st->st_size);
if (buf == NULL) {
perror("malloc");
exit(errno);
}
/* And suck it all in. */
if ((bytes = read(in, buf, st->st_size)) != st->st_size) {
if (bytes == -1) {
fprintf(stderr, "read(%s, %lld): ", path, (long long)st->st_size);
perror("");
exit(errno);
}
fprintf(stderr, "can't read all %lld of %s\n",
(long long)st->st_size, path);
exit(-1);
}
/* Write it all out to the tmp file. */
if ((bytes = fwrite(buf, 1, st->st_size, out)) != st->st_size) {
if (bytes == -1) {
fprintf(stderr, "fwrite(%lld, %s): ",
(long long)st->st_size, tmp);
perror("");
exit(errno);
}
fprintf(stderr, "can't write all %lld of %s\n",
(long long)st->st_size, tmp);
exit(-1);
}
if (fclose(out) == EOF) {
fprintf(stderr, "fclose(%s): ", tmp);
perror("");
exit(errno);
}
/* Rename it into place; this always works. */
if (rename(tmp, target) == -1) {
fprintf(stderr, "rename(%s, %s): ", tmp, target);
perror("");
}
/* Ensure target has the correct size; it always does. */
if (stat(target, &target_st) == -1) {
fprintf(stderr, "stat(%s) before unlink: ", tmp);
perror("");
} else {
if (target_st.st_size != st->st_size) {
fprintf(stderr, "%s %lld != %lld before unlink\n", target,
(long long)target_st.st_size, (long long)st->st_size);
}
}
/* Now unlink the tmp file; it *NEVER EXISTS* at this point. */
if (unlink(tmp) == -1) {
unlink_error = errno;
if (errno != ENOENT) {
fprintf(stderr, "unlink(%s): ", tmp);
perror("");
exit(errno);
}
}
/* Check target size again; random files in our data set have become
size 0 now, in many but not all runs. */
if (stat(target, &target_st) == -1) {
fprintf(stderr, "stat(%s): ", tmp);
perror("");
} else {
if (target_st.st_size != st->st_size) {
fprintf(stderr, "%s %lld != %lld, unlink_error=%d\n", target,
(long long)target_st.st_size, (long long)st->st_size,
unlink_error);
}
}
free(target);
free(tmp);
free(buf);
}
/* Iterate over all files in the data directory, pass them to work. */
int
main(void)
{
char *paths[] = { "data", NULL };
FTS *ftp;
FTSENT *fte;
if (mkdir("work", 0755) == -1) {
perror("mkdir(work)");
exit(errno);
}
ftp = fts_open(paths, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL);
if (ftp == NULL) {
perror("fts_open(data)");
exit(errno);
}
while (errno = 0, (fte = fts_read(ftp)) != NULL) {
if (fte->fts_info == FTS_ERR) {
fprintf(stderr, "%s: %s\n",
fte->fts_path, strerror(fte->fts_errno));
continue;
}
if (fte->fts_info != FTS_F) {
continue;
}
work(fte->fts_path, fte->fts_accpath, fte->fts_statp, "work");
}
if (errno != 0) {
perror("fts_read(data)");
exit(errno);
}
if (fts_close(ftp) == -1) {
perror("fts_close(data)");
exit(errno);
}
return 0;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Tue Nov 13 22:13:13 2007