summaryrefslogtreecommitdiff
path: root/user/find.c
blob: e185e9d1f8b6789a772a56eb8d6a4003eaab3f79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include "kernel/types.h"

#include "kernel/fcntl.h"
#include "kernel/fs.h"
#include "kernel/stat.h"
#include "user/user.h"

char*
fmtname(char* path)
{
  char* p;

  // Find first character after last slash.
  for (p = path + strlen(path); p >= path && *p != '/'; p--)
    ;
  p++;
  return p;
}

void
find(char* root_path, char* filename)
{
  static char buf[512];
  char* p;
  int fd;
  struct dirent de;
  struct stat st;

  if ((fd = open(root_path, O_RDONLY)) < 0) {
    fprintf(2, "find: cannot open %s\n", root_path);
    return;
  }
  if (fstat(fd, &st) < 0) {
    fprintf(2, "find: cannot stat %s\n", root_path);
    close(fd);
    return;
  }

  switch (st.type) {
    case T_FILE:
      if (!strcmp(fmtname(root_path), filename)) {
        printf("%s\n", root_path);
      }
      break;
    case T_DIR:
      if (strlen(root_path) + 1 + DIRSIZ + 1 > sizeof(buf)) {
        printf("find: path too long\n");
        break;
      }

      strcpy(buf, root_path);

      p = buf + strlen(buf);
      *p++ = '/';
      while (read(fd, &de, sizeof(de)) == sizeof(de)) {
        if (de.inum == 0)
          continue;
        memmove(p, de.name, DIRSIZ);
        p[DIRSIZ] = '\0';

        // printf("i'm finding %s!\n", fmtname(buf));

        if (!strcmp(fmtname(buf), ".") || !strcmp(fmtname(buf), "..")) {
          continue;
        }

        find(buf, filename);
      }
  }
  close(fd);
}

int
main(int argc, char* argv[])
{
  if (argc < 3) {
    fprintf(2, "usage: find [root_path] filename...\n");
    exit(1);
  }

  for (int i = 2; i < argc; i++) {
    find(argv[1], argv[i]);
  }
}