don't set page size by default
[tridge/junkcode.git] / readdir.c
1 /*
2   a replacement for opendir/readdir/telldir/seekdir/closedir
3   
4 */
5
6 #define __USE_GNU
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <dirent.h>
16
17 #define DIR_BUF_BITS 9
18 #define DIR_BUF_SIZE (1<<DIR_BUF_BITS)
19
20 #define O_DIRECTORY 0200000
21
22 struct dir_buf {
23         int fd;
24         int nbytes, ofs;
25         off_t seekpos;
26         char buf[DIR_BUF_SIZE];
27 };
28
29 _syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count)
30
31 struct dir_buf *rep_opendir(const char *dname)
32 {
33         struct dir_buf *d;
34         d = malloc(sizeof(*d));
35         d->fd = open(dname, O_DIRECTORY | O_RDONLY);
36         if (d->fd == -1) {
37                 return NULL;
38         }
39         d->ofs = 0;
40         d->seekpos = 0;
41         d->nbytes = 0;
42         return d;
43 }
44
45 struct dirent *rep_readdir(struct dir_buf *d)
46 {
47         struct dirent *de;
48
49         if (d->ofs >= d->nbytes) {
50                 d->seekpos = lseek(d->fd, 0, SEEK_CUR);
51                 d->nbytes = getdents(d->fd, (struct dirent *)d->buf, DIR_BUF_SIZE);
52                 d->ofs = 0;
53         }
54         if (d->ofs >= d->nbytes) {
55                 return NULL;
56         }
57         de = (struct dirent *)&d->buf[d->ofs];
58         d->ofs += de->d_reclen;
59         if (d->ofs >= d->nbytes) {
60                 d->seekpos = lseek(d->fd, 0, SEEK_CUR);
61                 d->nbytes = getdents(d->fd, (struct dirent *)d->buf, DIR_BUF_SIZE);
62                 d->ofs = 0;
63         }
64         return de;
65 }
66
67 off_t rep_telldir(struct dir_buf *d)
68 {
69         if (d->ofs >= d->nbytes) {
70                 d->seekpos = lseek(d->fd, 0, SEEK_CUR);
71                 d->ofs = 0;
72                 d->nbytes = 0;
73         }
74         return (d->seekpos << DIR_BUF_BITS) + d->ofs;
75 }
76
77 void rep_seekdir(struct dir_buf *d, off_t ofs)
78 {
79         d->seekpos = lseek(d->fd, ofs >> DIR_BUF_BITS, SEEK_SET);
80         d->nbytes = getdents(d->fd, (struct dirent *)d->buf, DIR_BUF_SIZE);
81         d->ofs = 0;
82         while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) {
83                 if (rep_readdir(d) == NULL) break;
84         }
85 }
86
87 int rep_closedir(struct dir_buf *d)
88 {
89         int r = close(d->fd);
90         if (r != 0) {
91                 return r;
92         }
93         free(d);
94         return 0;
95 }
96
97
98
99
100 /*
101   test readdir/unlink pattern that OS/2 uses
102   tridge@samba.org July 2005
103 */
104
105 #define NUM_FILES 29
106
107 #define TESTDIR "test.dir"
108
109 #define FAILED() (fprintf(stderr, "Failed at %s:%d - %s\n", __FUNCTION__, __LINE__, strerror(errno)), exit(1), 1)
110
111 static void cleanup(void)
112 {
113         /* I'm a lazy bastard */
114         system("rm -rf " TESTDIR);
115         mkdir(TESTDIR, 0700) == 0 || FAILED();
116 }
117
118 static void create_files()
119 {
120         int i;
121         for (i=0;i<NUM_FILES;i++) {
122                 char fname[40];
123                 snprintf(fname, sizeof(fname), TESTDIR "/test%04u.txt", i);
124                 close(open(fname, O_CREAT|O_RDWR, 0600)) == 0 || FAILED();
125         }
126 }
127
128 int main(void)
129 {
130         int total_deleted = 0;
131         struct dir_buf *d;
132         struct dirent *de;
133
134         cleanup();
135         create_files();
136         
137         d = rep_opendir(TESTDIR);
138
139         chdir(TESTDIR) == 0 || FAILED();
140
141         /* skip past . and .. */
142         de = rep_readdir(d);
143         strcmp(de->d_name, ".") == 0 || FAILED();
144         de = rep_readdir(d);
145         strcmp(de->d_name, "..") == 0 || FAILED();
146
147         while ((de = rep_readdir(d))) {
148                 off_t ofs = rep_telldir(d);
149                 printf("Deleting %s at %d\n", de->d_name, (int)ofs);
150                 unlink(de->d_name) == 0 || FAILED();
151
152                 /* move one more position on */
153                 rep_readdir(d);
154
155                 /* seek to just after the first readdir() */
156                 rep_seekdir(d, ofs);
157                 total_deleted++;
158         }
159         rep_closedir(d);
160
161         printf("Deleted %d files of %d\n", total_deleted, NUM_FILES);
162
163         chdir("..") == 0 || FAILED();
164
165         rmdir(TESTDIR) == 0 || FAILED();
166
167         return 0;
168 }