~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to uspace/lib/ext2/libext2_directory.c

  • Committer: Jakub Jermar
  • Date: 2011-06-02 21:26:44 UTC
  • mfrom: (720.2.82 ext2-merge)
  • Revision ID: jakub@jermar.eu-20110602212644-t5p3o4bux1n8ybvd
Merge from http://ho.st.dcs.fmph.uniba.sk/~mato/bzr/helenos-ext2.

Changes made against the ext2 branch parent:
- removed .bzrignore
- removed all traces of pipefs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011 Martin Sucha
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * - Redistributions of source code must retain the above copyright
 
10
 *   notice, this list of conditions and the following disclaimer.
 
11
 * - Redistributions in binary form must reproduce the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer in the
 
13
 *   documentation and/or other materials provided with the distribution.
 
14
 * - The name of the author may not be used to endorse or promote products
 
15
 *   derived from this software without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 */
 
28
 
 
29
/** @addtogroup libext2
 
30
 * @{
 
31
 */
 
32
/**
 
33
 * @file
 
34
 */
 
35
 
 
36
#include "libext2.h"
 
37
#include "libext2_directory.h"
 
38
#include <byteorder.h>
 
39
#include <errno.h>
 
40
#include <assert.h>
 
41
 
 
42
/**
 
43
 * Get inode number for the directory entry
 
44
 * 
 
45
 * @param de pointer to linked list directory entry
 
46
 */
 
47
uint32_t ext2_directory_entry_ll_get_inode(ext2_directory_entry_ll_t *de)
 
48
{
 
49
        return uint32_t_le2host(de->inode);
 
50
}
 
51
 
 
52
/**
 
53
 * Get length of the directory entry
 
54
 * 
 
55
 * @param de pointer to linked list directory entry
 
56
 */
 
57
uint16_t ext2_directory_entry_ll_get_entry_length(
 
58
    ext2_directory_entry_ll_t *de)
 
59
{
 
60
        return uint16_t_le2host(de->entry_length);
 
61
}
 
62
 
 
63
/**
 
64
 * Get length of the name stored in the directory entry
 
65
 * 
 
66
 * @param de pointer to linked list directory entry
 
67
 */
 
68
uint16_t ext2_directory_entry_ll_get_name_length(
 
69
    ext2_superblock_t *sb, ext2_directory_entry_ll_t *de)
 
70
{
 
71
        if (ext2_superblock_get_rev_major(sb) == 0 &&
 
72
            ext2_superblock_get_rev_minor(sb) < 5) {
 
73
                return ((uint16_t)de->name_length_high) << 8 | 
 
74
                    ((uint16_t)de->name_length);
 
75
        }
 
76
        return de->name_length;
 
77
}
 
78
 
 
79
/**
 
80
 * Initialize a directory iterator
 
81
 * 
 
82
 * @param it pointer to iterator to initialize
 
83
 * @param fs pointer to filesystem structure
 
84
 * @param inode pointer to inode reference structure
 
85
 * @return EOK on success or negative error code on failure
 
86
 */
 
87
int ext2_directory_iterator_init(ext2_directory_iterator_t *it,
 
88
    ext2_filesystem_t *fs, ext2_inode_ref_t *inode_ref)
 
89
{
 
90
        int rc;
 
91
        uint32_t block_id;
 
92
        it->inode_ref = inode_ref;
 
93
        it->fs = fs;
 
94
        
 
95
        /* Get the first data block, so we can get the first entry */
 
96
        rc = ext2_filesystem_get_inode_data_block_index(fs, inode_ref->inode, 0, 
 
97
            &block_id);
 
98
        if (rc != EOK) {
 
99
                return rc;
 
100
        }
 
101
        
 
102
        rc = block_get(&it->current_block, fs->device, block_id, 0);
 
103
        if (rc != EOK) {
 
104
                return rc;
 
105
        }
 
106
        
 
107
        it->current = it->current_block->data;
 
108
        it->current_offset = 0;
 
109
        
 
110
        return EOK;
 
111
}
 
112
 
 
113
/**
 
114
 * Advance the directory iterator to the next entry
 
115
 * 
 
116
 * @param it pointer to iterator to initialize
 
117
 * @return EOK on success or negative error code on failure
 
118
 */
 
119
int ext2_directory_iterator_next(ext2_directory_iterator_t *it)
 
120
{
 
121
        int rc;
 
122
        uint16_t skip;
 
123
        uint64_t size;
 
124
        aoff64_t current_block_idx;
 
125
        aoff64_t next_block_idx;
 
126
        uint32_t next_block_phys_idx;
 
127
        uint32_t block_size;
 
128
        uint32_t offset_in_block;
 
129
        
 
130
        assert(it->current != NULL);
 
131
        
 
132
        skip = ext2_directory_entry_ll_get_entry_length(it->current);
 
133
        size = ext2_inode_get_size(it->fs->superblock, it->inode_ref->inode);
 
134
        
 
135
        /* Are we at the end? */
 
136
        if (it->current_offset + skip >= size) {
 
137
                rc = block_put(it->current_block);
 
138
                it->current_block = NULL;
 
139
                it->current = NULL;
 
140
                if (rc != EOK) {
 
141
                        return rc;
 
142
                }
 
143
                
 
144
                it->current_offset += skip;
 
145
                return EOK;
 
146
        }
 
147
        
 
148
        block_size = ext2_superblock_get_block_size(it->fs->superblock);
 
149
        current_block_idx = it->current_offset / block_size;
 
150
        next_block_idx = (it->current_offset + skip) / block_size;
 
151
        
 
152
        /* If we are moving accross block boundary,
 
153
         * we need to get another block
 
154
         */
 
155
        if (current_block_idx != next_block_idx) {
 
156
                rc = block_put(it->current_block);
 
157
                it->current_block = NULL;
 
158
                it->current = NULL;
 
159
                if (rc != EOK) {
 
160
                        return rc;
 
161
                }
 
162
                
 
163
                rc = ext2_filesystem_get_inode_data_block_index(it->fs,
 
164
                    it->inode_ref->inode, next_block_idx, &next_block_phys_idx);
 
165
                if (rc != EOK) {
 
166
                        return rc;
 
167
                }
 
168
                
 
169
                rc = block_get(&it->current_block, it->fs->device, next_block_phys_idx,
 
170
                    BLOCK_FLAGS_NONE);
 
171
                if (rc != EOK) {
 
172
                        it->current_block = NULL;
 
173
                        return rc;
 
174
                }
 
175
        }
 
176
        
 
177
        offset_in_block = (it->current_offset + skip) % block_size;
 
178
        
 
179
        /* Ensure proper alignment */
 
180
        if ((offset_in_block % 4) != 0) {
 
181
                it->current = NULL;
 
182
                return EIO;
 
183
        }
 
184
        
 
185
        /* Ensure that the core of the entry does not overflow the block */
 
186
        if (offset_in_block > block_size - 8) {
 
187
                it->current = NULL;
 
188
                return EIO;
 
189
        }
 
190
                
 
191
        it->current = it->current_block->data + offset_in_block;
 
192
        it->current_offset += skip;
 
193
        
 
194
        /* Ensure that the whole entry does not overflow the block */
 
195
        skip = ext2_directory_entry_ll_get_entry_length(it->current);
 
196
        if (offset_in_block + skip > block_size) {
 
197
                it->current = NULL;
 
198
                return EIO;
 
199
        }
 
200
        
 
201
        /* Ensure the name length is not too large */
 
202
        if (ext2_directory_entry_ll_get_name_length(it->fs->superblock, 
 
203
            it->current) > skip-8) {
 
204
                it->current = NULL;
 
205
                return EIO;
 
206
        }
 
207
        
 
208
        return EOK;
 
209
}
 
210
 
 
211
/**
 
212
 * Release all resources asociated with the directory iterator
 
213
 * 
 
214
 * @param it pointer to iterator to initialize
 
215
 * @return EOK on success or negative error code on failure
 
216
 */
 
217
int ext2_directory_iterator_fini(ext2_directory_iterator_t *it)
 
218
{
 
219
        int rc;
 
220
        
 
221
        it->fs = NULL;
 
222
        it->inode_ref = NULL;
 
223
        it->current = NULL;
 
224
        
 
225
        if (it->current_block) {
 
226
                rc = block_put(it->current_block);
 
227
                if (rc != EOK) {
 
228
                        return rc;
 
229
                }
 
230
        }
 
231
        
 
232
        return EOK;
 
233
}
 
234
 
 
235
/** @}
 
236
 */