--- /dev/null
+/*
+ test readdir/unlink pattern that OS/2 uses
+ tridge@samba.org July 2005
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#define NUM_FILES 29
+
+#define TESTDIR "test.dir"
+
+#define FAILED() (fprintf(stderr, "Failed at %s:%d - %s\n", __FUNCTION__, __LINE__, strerror(errno)), exit(1), 1)
+
+static void cleanup(void)
+{
+ /* I'm a lazy bastard */
+ system("rm -rf " TESTDIR);
+ mkdir(TESTDIR, 0700) == 0 || FAILED();
+}
+
+static void create_files()
+{
+ int i;
+ for (i=0;i<NUM_FILES;i++) {
+ char fname[40];
+ snprintf(fname, sizeof(fname), TESTDIR "/test%u.txt", i);
+ close(open(fname, O_CREAT|O_RDWR, 0600)) == 0 || FAILED();
+ }
+}
+
+int main(void)
+{
+ int total_deleted = 0;
+ DIR *d;
+ struct dirent *de;
+
+ cleanup();
+ create_files();
+
+ d = opendir(TESTDIR);
+
+ chdir(TESTDIR) == 0 || FAILED();
+
+ /* skip past . and .. */
+ de = readdir(d);
+ strcmp(de->d_name, ".") == 0 || FAILED();
+ de = readdir(d);
+ strcmp(de->d_name, "..") == 0 || FAILED();
+
+ while ((de = readdir(d))) {
+ off_t ofs = telldir(d);
+ unlink(de->d_name) == 0 || FAILED();
+
+ /* move one more position on */
+ readdir(d);
+
+ /* seek to just after the first readdir() */
+ seekdir(d, ofs);
+ total_deleted++;
+ }
+ closedir(d);
+
+ printf("Deleted %d files of %d\n", total_deleted, NUM_FILES);
+
+ chdir("..") == 0 || FAILED();
+
+ rmdir(TESTDIR) == 0 || FAILED();
+
+ return 0;
+}
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
/*
a replacement for opendir/readdir/telldir/seekdir/closedir for BSD systems
- tridge@samba.org, July 2005
This is needed because the existing directory handling in FreeBSD
and OpenBSD (and possibly NetBSD) doesn't correctly handle unlink()
Note! This replacement code is not portable. It relies on getdents()
always leaving the file descriptor at a seek offset that is a
multiple of DIR_BUF_SIZE. If the code detects that this doesn't
- happen then it will abort().
+ happen then it will abort(). It also does not handle directories
+ with offsets larger than can be stored in a long,
+
+ This code is available under other free software licenses as
+ well. Contact the author.
*/
#include <stdlib.h>
char buf[DIR_BUF_SIZE];
};
-struct dir_buf *rep_opendir(const char *dname)
+DIR *opendir(const char *dname)
{
struct dir_buf *d;
d = malloc(sizeof(*d));
d->ofs = 0;
d->seekpos = 0;
d->nbytes = 0;
- return d;
+ return (DIR *)d;
}
-struct dirent *rep_readdir(struct dir_buf *d)
+struct dirent *readdir(DIR *dir)
{
+ struct dir_buf *d = (struct dir_buf *)dir;
struct dirent *de;
if (d->ofs >= d->nbytes) {
return de;
}
-off_t rep_telldir(struct dir_buf *d)
+long telldir(DIR *dir)
{
+ struct dir_buf *d = (struct dir_buf *)dir;
if (d->ofs >= d->nbytes) {
d->seekpos = lseek(d->fd, 0, SEEK_CUR);
d->ofs = 0;
return d->seekpos + d->ofs;
}
-void rep_seekdir(struct dir_buf *d, off_t ofs)
+void seekdir(DIR *dir, long ofs)
{
+ struct dir_buf *d = (struct dir_buf *)dir;
d->seekpos = lseek(d->fd, ofs & ~(DIR_BUF_SIZE-1), SEEK_SET);
d->nbytes = getdents(d->fd, d->buf, DIR_BUF_SIZE);
d->ofs = 0;
while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) {
- if (rep_readdir(d) == NULL) break;
+ if (readdir(dir) == NULL) break;
}
}
-int rep_closedir(struct dir_buf *d)
+void rewinddir(DIR *dir)
+{
+ seekdir(dir, 0);
+}
+
+int closedir(DIR *dir)
{
+ struct dir_buf *d = (struct dir_buf *)dir;
int r = close(d->fd);
if (r != 0) {
return r;
return 0;
}
+#ifndef dirfd
+/* darn, this is a macro on some systems. */
+int dirfd(DIR *dir)
+{
+ struct dir_buf *d = (struct dir_buf *)dir;
+ return d->fd;
+}
+#endif