~ubuntu-branches/ubuntu/trusty/rhash/trusty

« back to all changes in this revision

Viewing changes to find_file.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexey S Kravchenko
  • Date: 2011-06-15 01:03:34 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20110615010334-ochayini7ut2djvs
Tags: 1.2.6-1
* New upstream release version 1.2.6
 - ABI changed - now librhash0.0 is librhash0
 - OpenSSL support for faster hash calculation if libssl is installed
   (fully optional) for both rhash and librhash0

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
 
35
35
typedef struct dir_entry
36
36
{
37
 
  struct dir_entry *next;
38
 
  char* filename;
39
 
  /*unsigned short level; nesting level */
40
 
  unsigned type; /* dir,link, e.t.c. */
41
 
  /*bool operator < (struct dir_entry &right) { return (name < right.name); }*/
 
37
        struct dir_entry *next;
 
38
        char* filename;
 
39
        /*unsigned short level; nesting level */
 
40
        unsigned type; /* dir,link, e.t.c. */
 
41
        /*bool operator < (struct dir_entry &right) { return (name < right.name); }*/
42
42
} dir_entry;
43
43
 
44
44
/**
51
51
 */
52
52
static dir_entry* dir_entry_new(dir_entry *next, char* filename, unsigned type) 
53
53
{
54
 
  dir_entry* e = (dir_entry*)malloc(sizeof(dir_entry));
55
 
  if(!e) return NULL;
56
 
  if(filename) {
57
 
    e->filename = rsh_strdup(filename);
58
 
    if(!e->filename) { 
59
 
      free(e); 
60
 
      return NULL;
61
 
    }
62
 
  } else {
63
 
    e->filename = NULL;
64
 
  }
65
 
  e->next = next;
66
 
  e->type = type;
67
 
  return e;
 
54
        dir_entry* e = (dir_entry*)malloc(sizeof(dir_entry));
 
55
        if(!e) return NULL;
 
56
        if(filename) {
 
57
                e->filename = rsh_strdup(filename);
 
58
                if(!e->filename) { 
 
59
                        free(e); 
 
60
                        return NULL;
 
61
                }
 
62
        } else {
 
63
                e->filename = NULL;
 
64
        }
 
65
        e->next = next;
 
66
        e->type = type;
 
67
        return e;
68
68
}
69
69
 
70
70
/**
77
77
 */
78
78
static dir_entry* dir_entry_insert(dir_entry **at, char* filename, unsigned type)
79
79
{
80
 
  dir_entry* e = dir_entry_new(*at, filename, type);
81
 
  if(e) *at = e;
82
 
  return e;
 
80
        dir_entry* e = dir_entry_new(*at, filename, type);
 
81
        if(e) *at = e;
 
82
        return e;
83
83
}
84
84
 
85
85
/**
89
89
 */
90
90
static void dir_entry_free(dir_entry* e)
91
91
{
92
 
  free(e->filename);
93
 
  free(e);
 
92
        free(e->filename);
 
93
        free(e);
94
94
}
95
95
 
96
96
/**
98
98
 */
99
99
typedef struct dir_iterator
100
100
{
101
 
  int left;
102
 
  char* prev_dir;
 
101
        int left;
 
102
        char* prev_dir;
103
103
} dir_iterator;
104
104
#define MAX_DIRS_DEPTH 64
105
105
 
115
115
  int (*call_back)(const char* filepath, int type, void* data), 
116
116
  int options, int max_depth, void* call_back_data)
117
117
{
118
 
  dir_entry *dirs_stack = NULL; /* root of the dir_list */
119
 
  dir_iterator* it;
120
 
  int level = 1;
121
 
  dir_entry* entry;
122
 
  struct rsh_stat_struct st;
123
 
  
124
 
  if(max_depth < 0 || max_depth >= MAX_DIRS_DEPTH) {
125
 
    max_depth = MAX_DIRS_DEPTH;
126
 
  }
127
 
  /* skip the directory if max_depth == 0 */
128
 
  if(max_depth == 0) {
129
 
    return 0;
130
 
  }
131
 
  
132
 
  /* check that start_dir is a drectory */
133
 
  if(rsh_stat(start_dir, &st) < 0) { 
134
 
    return -1; /* errno is already set by stat */
135
 
  }
136
 
  if( !S_ISDIR(st.st_mode) ) {
137
 
    errno = ENOTDIR;
138
 
    return -1;
139
 
  }
140
 
  
141
 
/*#ifdef _WIN32
142
 
  const char* cur_dirpath;
143
 
  if( options&FIND_CHDIR ) {
144
 
    cur_dirpath = getcwd(NULL, 2);
145
 
  }
146
 
#else
147
 
  int root_fd;
148
 
  if( options&FIND_CHDIR ) {
149
 
    root_fd = open(".");
150
 
  }
151
 
#endif*/
152
 
 
153
 
  /* check if we should descend into the root directory */
154
 
  if( !(options&FIND_WALK_DEPTH_FIRST)
155
 
    && !call_back(start_dir, FIND_IFDIR | FIND_IFFIRST, call_back_data)) {
156
 
      return 0;
157
 
  }
158
 
 
159
 
  it = (dir_iterator*)malloc(MAX_DIRS_DEPTH*sizeof(dir_iterator));
160
 
  if(!it) return 0;
161
 
  
162
 
  /* push root directory into dirs_stack */
163
 
  it[0].left = 1;
164
 
  it[0].prev_dir = rsh_strdup(start_dir);
165
 
  it[1].prev_dir = NULL;
166
 
  if(!it[0].prev_dir) {
167
 
    errno = ENOMEM;
168
 
    return -1;
169
 
  }
170
 
  entry = dir_entry_insert(&dirs_stack, NULL, 0);
171
 
  if(!entry) {
172
 
    free(it[0].prev_dir);
173
 
    free(it);
174
 
    errno = ENOMEM;
175
 
    return -1;
176
 
  }
177
 
  
178
 
  for(;;) {
179
 
    dir_entry *dir, **insert_at;
180
 
    char* dir_path;
181
 
    DIR *dp;
182
 
    struct dirent *de;
183
 
    int type;
184
 
    /* walk back */
185
 
    while((--level) >= 0 && it[level].left <= 0) free(it[level+1].prev_dir);
186
 
    if(level < 0) break;
187
 
    assert(dirs_stack != NULL);
188
 
    /* on the first cycle: level == 0, stack[0] == 0; */
189
 
 
190
 
    dir = dirs_stack; /* take last dir from the list */
191
 
    dirs_stack = dirs_stack->next; /* remove last dir from the list */
192
 
    it[level].left--;
193
 
 
194
 
    dir_path = (!dir->filename ? rsh_strdup(it[level].prev_dir) :
195
 
      make_path(it[level].prev_dir, dir->filename) );
196
 
    dir_entry_free(dir);
197
 
    if(!dir_path) continue;
198
 
    
199
 
    level++;
200
 
    it[level].left = 0;
201
 
    it[level].prev_dir = dir_path;
202
 
 
203
 
    if( options&FIND_WALK_DEPTH_FIRST ) {
204
 
      /* check if we should skip the directory */    
205
 
      if( !call_back(dir_path, FIND_IFDIR, call_back_data) )
206
 
        continue;
207
 
    }
208
 
    
209
 
    /* read dir */
210
 
    dp = opendir(dir_path);
211
 
    if(dp == NULL) continue;
212
 
    type = FIND_IFFIRST;
213
 
    insert_at = &dirs_stack;
214
 
  
215
 
    while((de = readdir(dp)) != NULL) {
216
 
      int res;
217
 
      char* path;
218
 
      /* skip "." and ".." dirs */
219
 
      if(de->d_name[0] == '.' && (de->d_name[1] == 0 ||
220
 
        (de->d_name[1] == '.' && de->d_name[2] == 0 )))
221
 
          continue;
222
 
 
223
 
      if( !(path = make_path(dir_path, de->d_name)) ) continue;
 
118
        dir_entry *dirs_stack = NULL; /* root of the dir_list */
 
119
        dir_iterator* it;
 
120
        int level = 1;
 
121
        dir_entry* entry;
 
122
        struct rsh_stat_struct st;
 
123
 
 
124
        if(max_depth < 0 || max_depth >= MAX_DIRS_DEPTH) {
 
125
                max_depth = MAX_DIRS_DEPTH;
 
126
        }
 
127
        /* skip the directory if max_depth == 0 */
 
128
        if(max_depth == 0) {
 
129
                return 0;
 
130
        }
 
131
 
 
132
        /* check that start_dir is a drectory */
 
133
        if(rsh_stat(start_dir, &st) < 0) { 
 
134
                return -1; /* errno is already set by stat */
 
135
        }
 
136
        if( !S_ISDIR(st.st_mode) ) {
 
137
                errno = ENOTDIR;
 
138
                return -1;
 
139
        }
 
140
 
 
141
        /* check if we should descend into the root directory */
 
142
        if( !(options&FIND_WALK_DEPTH_FIRST)
 
143
                && !call_back(start_dir, FIND_IFDIR | FIND_IFFIRST, call_back_data)) {
 
144
                        return 0;
 
145
        }
 
146
 
 
147
        it = (dir_iterator*)malloc(MAX_DIRS_DEPTH*sizeof(dir_iterator));
 
148
        if(!it) return 0;
 
149
 
 
150
        /* push root directory into dirs_stack */
 
151
        it[0].left = 1;
 
152
        it[0].prev_dir = rsh_strdup(start_dir);
 
153
        it[1].prev_dir = NULL;
 
154
        if(!it[0].prev_dir) {
 
155
                errno = ENOMEM;
 
156
                return -1;
 
157
        }
 
158
        entry = dir_entry_insert(&dirs_stack, NULL, 0);
 
159
        if(!entry) {
 
160
                free(it[0].prev_dir);
 
161
                free(it);
 
162
                errno = ENOMEM;
 
163
                return -1;
 
164
        }
 
165
 
 
166
        for(;;) {
 
167
                dir_entry *dir, **insert_at;
 
168
                char* dir_path;
 
169
                DIR *dp;
 
170
                struct dirent *de;
 
171
                int type;
 
172
                /* walk back */
 
173
                while((--level) >= 0 && it[level].left <= 0) free(it[level+1].prev_dir);
 
174
                if(level < 0) break;
 
175
                assert(dirs_stack != NULL);
 
176
                /* on the first cycle: level == 0, stack[0] == 0; */
 
177
 
 
178
                dir = dirs_stack; /* take last dir from the list */
 
179
                dirs_stack = dirs_stack->next; /* remove last dir from the list */
 
180
                it[level].left--;
 
181
 
 
182
                dir_path = (!dir->filename ? rsh_strdup(it[level].prev_dir) :
 
183
                        make_path(it[level].prev_dir, dir->filename) );
 
184
                dir_entry_free(dir);
 
185
                if(!dir_path) continue;
 
186
 
 
187
                level++;
 
188
                it[level].left = 0;
 
189
                it[level].prev_dir = dir_path;
 
190
 
 
191
                if( options&FIND_WALK_DEPTH_FIRST ) {
 
192
                        /* check if we should skip the directory */    
 
193
                        if( !call_back(dir_path, FIND_IFDIR, call_back_data) )
 
194
                                continue;
 
195
                }
 
196
 
 
197
                /* read dir */
 
198
                dp = opendir(dir_path);
 
199
                if(dp == NULL) continue;
 
200
                type = FIND_IFFIRST;
 
201
                insert_at = &dirs_stack;
 
202
 
 
203
                while((de = readdir(dp)) != NULL) {
 
204
                        int res;
 
205
                        char* path;
 
206
                        /* skip "." and ".." dirs */
 
207
                        if(de->d_name[0] == '.' && (de->d_name[1] == 0 ||
 
208
                                (de->d_name[1] == '.' && de->d_name[2] == 0 )))
 
209
                                continue;
 
210
 
 
211
                        if( !(path = make_path(dir_path, de->d_name)) ) continue;
224
212
 
225
213
#ifndef USE_LSTAT_FOR_SYMLINKS
226
 
      if(rsh_stat(path, &st) < 0) {
227
 
        free(path);
228
 
        continue;
229
 
      }
 
214
                        if(rsh_stat(path, &st) < 0) {
 
215
                                free(path);
 
216
                                continue;
 
217
                        }
230
218
#else
231
 
      res = (options & FIND_FOLLOW_LINKS ? rsh_stat(path, &st) : lstat(path, &st));
232
 
      /*if((st.st_mode&S_IFMT) == S_IFLNK) type |= FIND_IFLNK;*/
233
 
      if(res < 0 || (!(options & FIND_FOLLOW_LINKS) && S_ISLNK(st.st_mode)) ) {
234
 
        free(path);
235
 
        continue;
236
 
      }
 
219
                        res = (options & FIND_FOLLOW_LINKS ? rsh_stat(path, &st) : lstat(path, &st));
 
220
                        /*if((st.st_mode&S_IFMT) == S_IFLNK) type |= FIND_IFLNK;*/
 
221
                        if(res < 0 || (!(options & FIND_FOLLOW_LINKS) && S_ISLNK(st.st_mode)) ) {
 
222
                                free(path);
 
223
                                continue;
 
224
                        }
237
225
#endif
238
226
 
239
227
/* check bits (the check fails for gcc -ansi) */
241
229
#  error wrong bits for S_IFMT and S_IFDIR
242
230
#endif*/
243
231
 
244
 
      /*type |= (S_ISDIR(st.st_mode) ? FIND_IFDIR : 0);*/
245
 
      type |= ((st.st_mode >> 12) & 0x0f);
246
 
      
247
 
      if((type & FIND_IFDIR) && (options & FIND_WALK_DEPTH_FIRST)) res = 1;
248
 
      else {
249
 
        /* handle file by callback function */
250
 
        res = call_back(path, type, call_back_data);
251
 
      }
252
 
      free(path);
253
 
 
254
 
      /* if file is a directory and we need to walk it */
255
 
      if((type & FIND_IFDIR) && res && level < max_depth) {
256
 
        /* don't go deeper if max_depth reached */
257
 
 
258
 
        /* add directory to dirs_stack */
259
 
        if( dir_entry_insert(insert_at, de->d_name, type) ) {
260
 
          /* if really added */
261
 
          insert_at = &((*insert_at)->next);
262
 
          it[level].left++;
263
 
        }
264
 
      }
265
 
      type = 0; /* clear FIND_IFFIRST flag */
266
 
    }
267
 
    closedir(dp);
268
 
 
269
 
    if(it[level].left > 0) level++;
270
 
  }
271
 
  assert(dirs_stack == NULL);
272
 
 
273
 
  free(it);
274
 
  return 0;
 
232
                        /*type |= (S_ISDIR(st.st_mode) ? FIND_IFDIR : 0);*/
 
233
                        type |= ((st.st_mode >> 12) & 0x0f);
 
234
 
 
235
                        if((type & FIND_IFDIR) && (options & FIND_WALK_DEPTH_FIRST)) res = 1;
 
236
                        else {
 
237
                                /* handle file by callback function */
 
238
                                res = call_back(path, type, call_back_data);
 
239
                        }
 
240
                        free(path);
 
241
 
 
242
                        /* if file is a directory and we need to walk it */
 
243
                        if((type & FIND_IFDIR) && res && level < max_depth) {
 
244
                                /* don't go deeper if max_depth reached */
 
245
 
 
246
                                /* add directory to dirs_stack */
 
247
                                if( dir_entry_insert(insert_at, de->d_name, type) ) {
 
248
                                        /* if really added */
 
249
                                        insert_at = &((*insert_at)->next);
 
250
                                        it[level].left++;
 
251
                                }
 
252
                        }
 
253
                        type = 0; /* clear FIND_IFFIRST flag */
 
254
                }
 
255
                closedir(dp);
 
256
 
 
257
                if(it[level].left > 0) level++;
 
258
        }
 
259
        assert(dirs_stack == NULL);
 
260
 
 
261
        free(it);
 
262
        return 0;
275
263
}