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 }