Mercurial > hg > toybox
comparison lib/dirtree.c @ 593:fb582378a36a
Implement DIRTREE_SYMFOLLOW and ls -cSHL.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sat, 09 Jun 2012 22:25:49 -0500 |
parents | 7013fd450ff4 |
children | a6a541b7fc34 |
comparison
equal
deleted
inserted
replaced
592:be4b2d3796eb | 593:fb582378a36a |
---|---|
8 | 8 |
9 // Create a dirtree node from a path, with stat and symlink info. | 9 // Create a dirtree node from a path, with stat and symlink info. |
10 // (This doesn't open directory filehandles yet so as not to exhaust the | 10 // (This doesn't open directory filehandles yet so as not to exhaust the |
11 // filehandle space on large trees. handle_callback() does that instead.) | 11 // filehandle space on large trees. handle_callback() does that instead.) |
12 | 12 |
13 struct dirtree *dirtree_add_node(int dirfd, char *name) | 13 struct dirtree *dirtree_add_node(int dirfd, char *name, int symfollow) |
14 { | 14 { |
15 struct dirtree *dt = NULL; | 15 struct dirtree *dt = NULL; |
16 struct stat st; | 16 struct stat st; |
17 char buf[4096]; | 17 char buf[4096]; |
18 int len = 0, linklen = 0; | 18 int len = 0, linklen = 0; |
19 | 19 |
20 if (name) { | 20 if (name) { |
21 if (fstatat(dirfd, name, &st, AT_SYMLINK_NOFOLLOW)) goto error; | 21 if (fstatat(dirfd, name, &st, symfollow ? 0 : AT_SYMLINK_NOFOLLOW)) |
22 goto error; | |
22 if (S_ISLNK(st.st_mode)) { | 23 if (S_ISLNK(st.st_mode)) { |
23 if (0>(linklen = readlinkat(dirfd, name, buf, 4095))) goto error; | 24 if (0>(linklen = readlinkat(dirfd, name, buf, 4095))) goto error; |
24 buf[linklen++]=0; | 25 buf[linklen++]=0; |
25 } | 26 } |
26 len = strlen(name); | 27 len = strlen(name); |
118 | 119 |
119 flags = callback(new); | 120 flags = callback(new); |
120 | 121 |
121 if (dir) { | 122 if (dir) { |
122 if (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)) { | 123 if (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)) { |
123 dirtree_recurse(new, callback); | 124 dirtree_recurse(new, callback, flags & DIRTREE_SYMFOLLOW); |
124 if (flags & DIRTREE_COMEAGAIN) flags = callback(new); | 125 if (flags & DIRTREE_COMEAGAIN) flags = callback(new); |
125 } else close(new->data); | 126 } else close(new->data); |
126 } | 127 } |
127 | 128 |
128 // If this had children, it was callback's job to free them already. | 129 // If this had children, it was callback's job to free them already. |
136 | 137 |
137 // Recursively read/process children of directory node (with dirfd in data), | 138 // Recursively read/process children of directory node (with dirfd in data), |
138 // filtering through callback(). | 139 // filtering through callback(). |
139 | 140 |
140 void dirtree_recurse(struct dirtree *node, | 141 void dirtree_recurse(struct dirtree *node, |
141 int (*callback)(struct dirtree *node)) | 142 int (*callback)(struct dirtree *node), int symfollow) |
142 { | 143 { |
143 struct dirtree *new, **ddt = &(node->child); | 144 struct dirtree *new, **ddt = &(node->child); |
144 struct dirent *entry; | 145 struct dirent *entry; |
145 DIR *dir; | 146 DIR *dir; |
146 | 147 |
156 // according to the fddir() man page, the filehandle in the DIR * can still | 157 // according to the fddir() man page, the filehandle in the DIR * can still |
157 // be externally used by things that don't lseek() it. | 158 // be externally used by things that don't lseek() it. |
158 | 159 |
159 // The extra parentheses are to shut the stupid compiler up. | 160 // The extra parentheses are to shut the stupid compiler up. |
160 while ((entry = readdir(dir))) { | 161 while ((entry = readdir(dir))) { |
161 if (!(new = dirtree_add_node(node->data, entry->d_name))) continue; | 162 if (!(new = dirtree_add_node(node->data, entry->d_name, symfollow))) |
163 continue; | |
162 new->parent = node; | 164 new->parent = node; |
163 new = handle_callback(new, callback); | 165 new = handle_callback(new, callback); |
164 if (new == DIRTREE_ABORTVAL) break; | 166 if (new == DIRTREE_ABORTVAL) break; |
165 if (new) { | 167 if (new) { |
166 *ddt = new; | 168 *ddt = new; |
177 // If callback == NULL allocate a tree of struct dirtree nodes and return | 179 // If callback == NULL allocate a tree of struct dirtree nodes and return |
178 // pointer to root node. | 180 // pointer to root node. |
179 | 181 |
180 struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node)) | 182 struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node)) |
181 { | 183 { |
182 struct dirtree *root = dirtree_add_node(AT_FDCWD, path); | 184 struct dirtree *root = dirtree_add_node(AT_FDCWD, path, 0); |
183 | 185 |
184 return root ? handle_callback(root, callback) : DIRTREE_ABORTVAL; | 186 return root ? handle_callback(root, callback) : DIRTREE_ABORTVAL; |
185 } | 187 } |