Convert tabs to spaces in design doc templates
[pintos-anon] / src / examples / pwd.c
1 /* pwd.c
2    
3    Prints the absolute name of the present working directory. */
4
5 #include <syscall.h>
6 #include <stdbool.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 static bool getcwd (char *cwd, size_t cwd_size);
11
12 int
13 main (void) 
14 {
15   char cwd[128];
16   if (getcwd (cwd, sizeof cwd)) 
17     {
18       printf ("%s\n", cwd);
19       return EXIT_SUCCESS;
20     }
21   else 
22     {
23       printf ("error\n");
24       return EXIT_FAILURE; 
25     }
26 }
27 \f
28 /* Stores the inode number for FILE_NAME in *INUM.
29    Returns true if successful, false if the file could not be
30    opened. */
31 static bool
32 get_inumber (const char *file_name, int *inum) 
33 {
34   int fd = open (file_name);
35   if (fd >= 0) 
36     {
37       *inum = inumber (fd);
38       close (fd);
39       return true;
40     }
41   else
42     return false;
43 }
44
45 /* Prepends PREFIX to the characters stored in the final *DST_LEN
46    bytes of the DST_SIZE-byte buffer that starts at DST.
47    Returns true if successful, false if adding that many
48    characters, plus a null terminator, would overflow the buffer.
49    (No null terminator is actually added or depended upon, but
50    its space is accounted for.) */
51 static bool
52 prepend (const char *prefix,
53          char *dst, size_t *dst_len, size_t dst_size) 
54 {
55   size_t prefix_len = strlen (prefix);
56   if (prefix_len + *dst_len + 1 <= dst_size) 
57     {
58       *dst_len += prefix_len;
59       memcpy ((dst + dst_size) - *dst_len, prefix, prefix_len);
60       return true;
61     }
62   else
63     return false;
64 }
65
66 /* Stores the current working directory, as a null-terminated
67    string, in the CWD_SIZE bytes in CWD.
68    Returns true if successful, false on error.  Errors include
69    system errors, directory trees deeper than MAX_LEVEL levels,
70    and insufficient space in CWD. */
71 static bool
72 getcwd (char *cwd, size_t cwd_size) 
73 {
74   size_t cwd_len = 0;   
75   
76 #define MAX_LEVEL 20
77   char name[MAX_LEVEL * 3 + 1 + READDIR_MAX_LEN + 1];
78   char *namep;
79
80   int child_inum;
81
82   /* Make sure there's enough space for at least "/". */
83   if (cwd_size < 2)
84     return false;
85
86   /* Get inumber for current directory. */
87   if (!get_inumber (".", &child_inum))
88     return false;
89
90   namep = name;
91   for (;;)
92     {
93       int parent_inum, parent_fd;
94
95       /* Compose "../../../..", etc., in NAME. */
96       if ((namep - name) > MAX_LEVEL * 3)
97         return false;
98       *namep++ = '.';
99       *namep++ = '.';
100       *namep = '\0';
101
102       /* Open directory. */
103       parent_fd = open (name);
104       if (parent_fd < 0)
105         return false;
106       *namep++ = '/';
107
108       /* If parent and child have the same inumber,
109          then we've arrived at the root. */
110       parent_inum = inumber (parent_fd);
111       if (parent_inum == child_inum)
112         break;
113
114       /* Find name of file in parent directory with the child's
115          inumber. */
116       for (;;)
117         {
118           int test_inum;
119           if (!readdir (parent_fd, namep) || !get_inumber (name, &test_inum)) 
120             {
121               close (parent_fd);
122               return false; 
123             }
124           if (test_inum == child_inum)
125             break;
126         }
127       close (parent_fd);
128
129       /* Prepend "/name" to CWD. */
130       if (!prepend (namep - 1, cwd, &cwd_len, cwd_size))
131         return false;
132
133       /* Move up. */
134       child_inum = parent_inum;
135     }
136
137   /* Finalize CWD. */
138   if (cwd_len > 0) 
139     {
140       /* Move the string to the beginning of CWD,
141          and null-terminate it. */
142       memmove (cwd, (cwd + cwd_size) - cwd_len, cwd_len);
143       cwd[cwd_len] = '\0';
144     }
145   else 
146     {
147       /* Special case for the root. */
148       strlcpy (cwd, "/", cwd_size); 
149     }
150   
151   return true;
152 }