updated replacement dir code for BSD
authortridge <>
Sun, 24 Jul 2005 18:44:46 +0000 (18:44 +0000)
committertridge <>
Sun, 24 Jul 2005 18:44:46 +0000 (18:44 +0000)
repdir/Makefile
repdir/bsd_telldir.c [new file with mode: 0644]
repdir/os2_delete.c
repdir/repdir.c

index 171e92ca6da1583545091105bcdfde8903015522..9971a561c373a35e14cb9666f6018e2a5ffca918 100644 (file)
@@ -1,9 +1,13 @@
 CC=gcc
 CFLAGS=-Wall -g
 
+all: os2_delete bsd_telldir
 
 os2_delete: os2_delete.o repdir.o
        $(CC) -o os2_delete os2_delete.o repdir.o
 
+bsd_telldir: bsd_telldir.o repdir.o
+       $(CC) -o bsd_telldir bsd_telldir.o repdir.o
+
 clean:
-       rm -f *.o os2_delete *~
+       rm -f *.o os2_delete bsd_telldir *~
diff --git a/repdir/bsd_telldir.c b/repdir/bsd_telldir.c
new file mode 100644 (file)
index 0000000..58cc65d
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+  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;
+}
index c2c9e6d5f9790720f9fee4118e8416c31cfaa600..b176ce2b33ee4ddeb6c4516c9419bce2237d4f20 100644 (file)
@@ -3,7 +3,6 @@
   tridge@samba.org July 2005
 */
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
@@ -13,7 +12,6 @@
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
-#include "repdir.h"
 
 #define NUM_FILES 700
 #define READDIR_SIZE 100
index ebef0ef8140b3fd6e77448dc07b50b7e3b543b6b..b536ed658703fe57cca62dbbb25a73d291dfc2b6 100644 (file)
@@ -1,6 +1,24 @@
+/* 
+   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>
@@ -39,7 +61,7 @@ struct dir_buf {
        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));
@@ -55,11 +77,12 @@ struct dir_buf *rep_opendir(const char *dname)
        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) {
@@ -75,8 +98,9 @@ struct dirent *rep_readdir(struct dir_buf *d)
        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;
@@ -90,18 +114,25 @@ off_t rep_telldir(struct dir_buf *d)
        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;
@@ -110,3 +141,11 @@ int rep_closedir(struct dir_buf *d)
        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