Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/user/testbin/dirseek/dirseek.c
734 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*
31
* dirseek.c
32
*
33
* Tests seeking on directories (both legally and illegally).
34
*
35
* Makes a test subdirectory in the current directory.
36
*
37
* Intended for the file system assignment. Should run (on SFS)
38
* when that assignment is complete.
39
*
40
* Note: checks a few things that are not _strictly_ guaranteed
41
* by the official semantics of getdirentry() but that are more
42
* or less necessary in a sane implementation, like that the
43
* current seek position returned after seeking is the same
44
* position that was requested. If you believe your
45
* implementation is legal and the the test is rejecting it
46
* gratuitously, please contact the course staff.
47
*/
48
49
#include <sys/types.h>
50
#include <sys/stat.h>
51
#include <unistd.h>
52
#include <string.h>
53
#include <stdio.h>
54
#include <stdlib.h>
55
#include <err.h>
56
57
#define TESTDIR "seektestdir"
58
59
static struct {
60
const char *name;
61
int make_it;
62
off_t pos;
63
} testfiles[] = {
64
{ ".", 0, -1 },
65
{ "..", 0, -1 },
66
{ "ridcully", 1, -1 },
67
{ "weatherwax", 1, -1 },
68
{ "ogg", 1, -1 },
69
{ "vorbis", 1, -1 },
70
{ "verence", 1, -1 },
71
{ "magrat", 1, -1 },
72
{ "agnes", 1, -1 },
73
{ "rincewind", 1, -1 },
74
{ "angua", 1, -1 },
75
{ "cherry", 1, -1 },
76
{ "dorfl", 1, -1 },
77
{ "nobby", 1, -1 },
78
{ "carrot", 1, -1 },
79
{ "vimes", 1, -1 },
80
{ "detritus", 1, -1 },
81
{ "twoflower", 1, -1 },
82
{ "teatime", 1, -1 },
83
{ "qu", 1, -1 },
84
{ NULL, 0, 0 }
85
};
86
87
/************************************************************/
88
/* Test code */
89
/************************************************************/
90
91
static int dirfd;
92
93
static
94
int
95
findentry(const char *name)
96
{
97
int i;
98
99
for (i=0; testfiles[i].name; i++) {
100
if (!strcmp(testfiles[i].name, name)) {
101
return i;
102
}
103
}
104
return -1;
105
}
106
107
static
108
void
109
openit(void)
110
{
111
dirfd = open(".", O_RDONLY);
112
if (dirfd < 0) {
113
err(1, ".: open");
114
}
115
}
116
117
static
118
void
119
closeit(void)
120
{
121
if (close(dirfd)<0) {
122
err(1, ".: close");
123
}
124
dirfd = -1;
125
}
126
127
static
128
void
129
readit(void)
130
{
131
char buf[4096];
132
off_t pos;
133
int len;
134
int n, i, ix;
135
136
for (i=0; testfiles[i].name; i++) {
137
testfiles[i].pos = -1;
138
}
139
140
pos = lseek(dirfd, 0, SEEK_CUR);
141
if (pos < 0) {
142
err(1, ".: lseek(0, SEEK_CUR)");
143
}
144
n = 0;
145
146
while ((len = getdirentry(dirfd, buf, sizeof(buf)-1)) > 0) {
147
148
if ((unsigned)len >= sizeof(buf)-1) {
149
errx(1, ".: entry %d: getdirentry returned "
150
"invalid length %d", n, len);
151
}
152
buf[len] = 0;
153
ix = findentry(buf);
154
if (ix < 0) {
155
errx(1, ".: entry %d: getdirentry returned "
156
"unexpected name %s", n, buf);
157
}
158
159
if (testfiles[ix].pos >= 0) {
160
errx(1, ".: entry %d: getdirentry returned "
161
"%s a second time", n, buf);
162
}
163
164
testfiles[ix].pos = pos;
165
166
pos = lseek(dirfd, 0, SEEK_CUR);
167
if (pos < 0) {
168
err(1, ".: lseek(0, SEEK_CUR)");
169
}
170
n++;
171
}
172
if (len<0) {
173
err(1, ".: entry %d: getdirentry", n);
174
}
175
176
for (i=0; testfiles[i].name; i++) {
177
if (testfiles[i].pos < 0) {
178
errx(1, ".: getdirentry failed to return %s",
179
testfiles[i].name);
180
}
181
}
182
if (i!=n) {
183
/*
184
* If all of the other checks have passed, this should not
185
* be able to fail. But... just in case I forgot something
186
* or there's a bug...
187
*/
188
189
errx(1, ".: getdirentry returned %d names, not %d (huh...?)",
190
n, i);
191
}
192
}
193
194
static
195
void
196
firstread(void)
197
{
198
off_t pos;
199
200
pos = lseek(dirfd, 0, SEEK_CUR);
201
if (pos < 0) {
202
err(1, ".: lseek(0, SEEK_CUR)");
203
}
204
if (pos != 0) {
205
errx(1, ".: File position after open not 0");
206
}
207
208
printf("Scanning directory...\n");
209
210
readit();
211
}
212
213
static
214
void
215
doreadat0(void)
216
{
217
off_t pos;
218
219
printf("Rewinding directory and reading it again...\n");
220
221
pos = lseek(dirfd, 0, SEEK_SET);
222
if (pos < 0) {
223
err(1, ".: lseek(0, SEEK_SET)");
224
}
225
if (pos != 0) {
226
errx(1, ".: lseek(0, SEEK_SET) returned %ld", (long) pos);
227
}
228
229
readit();
230
}
231
232
static
233
void
234
readone(const char *shouldbe)
235
{
236
char buf[4096];
237
int len;
238
239
len = getdirentry(dirfd, buf, sizeof(buf)-1);
240
if (len < 0) {
241
err(1, ".: getdirentry");
242
}
243
if ((unsigned)len >= sizeof(buf)-1) {
244
errx(1, ".: getdirentry returned invalid length %d", len);
245
}
246
buf[len] = 0;
247
248
if (strcmp(buf, shouldbe)) {
249
errx(1, ".: getdirentry returned %s (expected %s)",
250
buf, shouldbe);
251
}
252
}
253
254
static
255
void
256
doreadone(int which)
257
{
258
off_t pos;
259
pos = lseek(dirfd, testfiles[which].pos, SEEK_SET);
260
if (pos<0) {
261
err(1, ".: lseek(%ld, SEEK_SET)", (long) testfiles[which].pos);
262
}
263
if (pos != testfiles[which].pos) {
264
errx(1, ".: lseek(%ld, SEEK_SET) returned %ld",
265
(long) testfiles[which].pos, (long) pos);
266
}
267
268
readone(testfiles[which].name);
269
}
270
271
static
272
void
273
readallonebyone(void)
274
{
275
int i;
276
277
printf("Trying to read each entry again...\n");
278
for (i=0; testfiles[i].name; i++) {
279
doreadone(i);
280
}
281
}
282
283
static
284
void
285
readallrandomly(void)
286
{
287
int n, i, x;
288
289
printf("Trying to read a bunch of entries randomly...\n");
290
291
for (i=0; testfiles[i].name; i++);
292
n = i;
293
294
srandom(39584);
295
for (i=0; i<512; i++) {
296
x = (int)(random()%n);
297
doreadone(x);
298
}
299
}
300
301
static
302
void
303
readateof(void)
304
{
305
char buf[4096];
306
int len;
307
308
len = getdirentry(dirfd, buf, sizeof(buf)-1);
309
if (len < 0) {
310
err(1, ".: at EOF: getdirentry");
311
}
312
if (len==0) {
313
return;
314
}
315
if ((unsigned)len >= sizeof(buf)-1) {
316
errx(1, ".: at EOF: getdirentry returned "
317
"invalid length %d", len);
318
}
319
buf[len] = 0;
320
errx(1, ".: at EOF: got unexpected name %s", buf);
321
}
322
323
static
324
void
325
doreadateof(void)
326
{
327
off_t pos;
328
int i;
329
330
printf("Trying to read after going to EOF...\n");
331
332
pos = lseek(dirfd, 0, SEEK_END);
333
if (pos<0) {
334
err(1, ".: lseek(0, SEEK_END)");
335
}
336
337
for (i=0; testfiles[i].name; i++) {
338
if (pos <= testfiles[i].pos) {
339
errx(1, ".: EOF position %ld below position %ld of %s",
340
pos, testfiles[i].pos, testfiles[i].name);
341
}
342
}
343
344
readateof();
345
}
346
347
static
348
void
349
inval_read(void)
350
{
351
char buf[4096];
352
int len;
353
354
len = getdirentry(dirfd, buf, sizeof(buf)-1);
355
356
/* Any result is ok, as long as the system doesn't crash */
357
(void)len;
358
}
359
360
static
361
void
362
dobadreads(void)
363
{
364
off_t pos, pos2, eof;
365
int valid, i, k=0;
366
367
printf("Trying some possibly invalid reads...\n");
368
369
eof = lseek(dirfd, 0, SEEK_END);
370
if (eof < 0) {
371
err(1, ".: lseek(0, SEEK_END)");
372
}
373
374
for (pos=0; pos < eof; pos++) {
375
valid = 0;
376
for (i=0; testfiles[i].name; i++) {
377
if (pos==testfiles[i].pos) {
378
valid = 1;
379
}
380
}
381
if (valid) {
382
/* don't try offsets that are known to be valid */
383
continue;
384
}
385
386
pos2 = lseek(dirfd, pos, SEEK_SET);
387
if (pos2 < 0) {
388
/* this is ok */
389
}
390
else {
391
inval_read();
392
k++;
393
}
394
}
395
396
if (k>0) {
397
printf("Survived %d invalid reads...\n", k);
398
}
399
else {
400
printf("Couldn't find any invalid offsets to try...\n");
401
}
402
403
printf("Trying to read beyond EOF...\n");
404
pos2 = lseek(dirfd, eof + 1000, SEEK_SET);
405
if (pos2 < 0) {
406
/* this is ok */
407
}
408
else {
409
inval_read();
410
}
411
}
412
413
static
414
void
415
dotest(void)
416
{
417
printf("Opening directory...\n");
418
openit();
419
420
printf("Running tests...\n");
421
422
/* read the whole directory */
423
firstread();
424
425
/* make sure eof behaves right */
426
readateof();
427
428
/* read all the filenames again by seeking */
429
readallonebyone();
430
431
/* try reading at eof */
432
doreadateof();
433
434
/* read a bunch of the filenames over and over again */
435
readallrandomly();
436
437
/* rewind and read the whole thing again, to make sure that works */
438
doreadat0();
439
440
/* do invalid reads */
441
dobadreads();
442
443
/* rewind again to make sure the invalid attempts didn't break it */
444
doreadat0();
445
446
printf("Closing directory...\n");
447
closeit();
448
}
449
450
/************************************************************/
451
/* Setup code */
452
/************************************************************/
453
454
static
455
void
456
mkfile(const char *name)
457
{
458
int fd, i, r;
459
static const char message[] = "The turtle moves!\n";
460
char buf[32*sizeof(message)+1];
461
462
buf[0]=0;
463
for (i=0; i<32; i++) {
464
strcat(buf, message);
465
}
466
467
/* Use O_EXCL, because we know the file shouldn't already be there */
468
fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0664);
469
if (fd<0) {
470
err(1, "%s: create", name);
471
}
472
473
r = write(fd, buf, strlen(buf));
474
if (r<0) {
475
err(1, "%s: write", name);
476
}
477
if ((unsigned)r != strlen(buf)) {
478
errx(1, "%s: short write (%d bytes)", name, r);
479
}
480
481
if (close(fd)<0) {
482
err(1, "%s: close", name);
483
}
484
}
485
486
static
487
void
488
setup(void)
489
{
490
int i;
491
492
printf("Making directory %s...\n", TESTDIR);
493
494
/* Create a directory */
495
if (mkdir(TESTDIR, 0775)<0) {
496
err(1, "%s: mkdir", TESTDIR);
497
}
498
499
/* Switch to it */
500
if (chdir(TESTDIR)<0) {
501
err(1, "%s: chdir", TESTDIR);
502
}
503
504
printf("Making some files...\n");
505
506
/* Populate it */
507
for (i=0; testfiles[i].name; i++) {
508
if (testfiles[i].make_it) {
509
mkfile(testfiles[i].name);
510
}
511
testfiles[i].pos = -1;
512
}
513
}
514
515
static
516
void
517
cleanup(void)
518
{
519
int i;
520
521
printf("Cleaning up...\n");
522
523
/* Remove the files */
524
for (i=0; testfiles[i].name; i++) {
525
if (testfiles[i].make_it) {
526
if (remove(testfiles[i].name)<0) {
527
err(1, "%s: remove", testfiles[i].name);
528
}
529
}
530
}
531
532
/* Leave the dir */
533
if (chdir("..")<0) {
534
err(1, "..: chdir");
535
}
536
537
/* Remove the dir */
538
if (rmdir(TESTDIR)<0) {
539
err(1, "%s: rmdir", TESTDIR);
540
}
541
}
542
543
544
int
545
main()
546
{
547
setup();
548
549
/* Do the whole thing twice */
550
dotest();
551
dotest();
552
553
cleanup();
554
return 0;
555
}
556
557