~youscribe/parted/3.1

« back to all changes in this revision

Viewing changes to libparted/filesys.c

  • Committer: Guilhem Lettron
  • Date: 2012-10-22 14:37:59 UTC
  • Revision ID: guilhem+ubuntu@lettron.fr-20121022143759-m403kecgz13sknvp
3.1 from tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    libparted - a library for manipulating disk partitions
 
3
    Copyright (C) 1999-2001, 2007-2012 Free Software Foundation, Inc.
 
4
 
 
5
    This program is free software; you can redistribute it and/or modify
 
6
    it under the terms of the GNU General Public License as published by
 
7
    the Free Software Foundation; either version 3 of the License, or
 
8
    (at your option) any later version.
 
9
 
 
10
    This program is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
    GNU General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU General Public License
 
16
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
*/
 
18
 
 
19
/** \file filesys.c */
 
20
 
 
21
/**
 
22
 * \addtogroup PedFileSystem
 
23
 *
 
24
 * \note File systems exist on a PedGeometry - NOT a PedPartition.
 
25
 *
 
26
 * @{
 
27
 */
 
28
 
 
29
#include <config.h>
 
30
 
 
31
#include <parted/parted.h>
 
32
#include <parted/debug.h>
 
33
 
 
34
#if ENABLE_NLS
 
35
#  include <libintl.h>
 
36
#  define _(String) dgettext (PACKAGE, String)
 
37
#else
 
38
#  define _(String) (String)
 
39
#endif /* ENABLE_NLS */
 
40
 
 
41
#define BUFFER_SIZE     4096            /* in sectors */
 
42
 
 
43
static PedFileSystemType*       fs_types = NULL;
 
44
static PedFileSystemAlias*      fs_aliases = NULL;
 
45
 
 
46
void
 
47
ped_file_system_type_register (PedFileSystemType* fs_type)
 
48
{
 
49
        PED_ASSERT (fs_type != NULL);
 
50
        PED_ASSERT (fs_type->ops != NULL);
 
51
        PED_ASSERT (fs_type->name != NULL);
 
52
 
 
53
        fs_type->next = fs_types;
 
54
        fs_types = fs_type;
 
55
}
 
56
 
 
57
void
 
58
ped_file_system_type_unregister (PedFileSystemType* fs_type)
 
59
{
 
60
        PedFileSystemType*      walk;
 
61
        PedFileSystemType*      last = NULL;
 
62
 
 
63
        PED_ASSERT (fs_types != NULL);
 
64
        PED_ASSERT (fs_type != NULL);
 
65
 
 
66
        for (walk = fs_types; walk && walk != fs_type;
 
67
                last = walk, walk = walk->next);
 
68
 
 
69
        PED_ASSERT (walk != NULL);
 
70
        if (last)
 
71
                ((struct _PedFileSystemType*) last)->next = fs_type->next;
 
72
        else
 
73
                fs_types = fs_type->next;
 
74
}
 
75
 
 
76
void
 
77
ped_file_system_alias_register (PedFileSystemType* fs_type, const char* alias,
 
78
                                int deprecated)
 
79
{
 
80
        PedFileSystemAlias*     fs_alias;
 
81
 
 
82
        PED_ASSERT (fs_type != NULL);
 
83
        PED_ASSERT (alias != NULL);
 
84
 
 
85
        fs_alias = ped_malloc (sizeof *fs_alias);
 
86
        if (!fs_alias)
 
87
                return;
 
88
 
 
89
        fs_alias->next = fs_aliases;
 
90
        fs_alias->fs_type = fs_type;
 
91
        fs_alias->alias = alias;
 
92
        fs_alias->deprecated = deprecated;
 
93
        fs_aliases = fs_alias;
 
94
}
 
95
 
 
96
void
 
97
ped_file_system_alias_unregister (PedFileSystemType* fs_type,
 
98
                                  const char* alias)
 
99
{
 
100
        PedFileSystemAlias*     walk;
 
101
        PedFileSystemAlias*     last = NULL;
 
102
 
 
103
        PED_ASSERT (fs_aliases != NULL);
 
104
        PED_ASSERT (fs_type != NULL);
 
105
        PED_ASSERT (alias != NULL);
 
106
 
 
107
        for (walk = fs_aliases; walk; last = walk, walk = walk->next) {
 
108
                if (walk->fs_type == fs_type && !strcmp (walk->alias, alias))
 
109
                        break;
 
110
        }
 
111
 
 
112
        PED_ASSERT (walk != NULL);
 
113
        if (last)
 
114
                last->next = walk->next;
 
115
        else
 
116
                fs_aliases = walk->next;
 
117
        free (walk);
 
118
}
 
119
 
 
120
/**
 
121
 * Get a PedFileSystemType by its @p name.
 
122
 *
 
123
 * @return @c NULL if none found.
 
124
 */
 
125
PedFileSystemType*
 
126
ped_file_system_type_get (const char* name)
 
127
{
 
128
        PedFileSystemType*      walk;
 
129
        PedFileSystemAlias*     alias_walk;
 
130
 
 
131
        PED_ASSERT (name != NULL);
 
132
 
 
133
        for (walk = fs_types; walk != NULL; walk = walk->next) {
 
134
                if (!strcasecmp (walk->name, name))
 
135
                        break;
 
136
        }
 
137
        if (walk != NULL)
 
138
                return walk;
 
139
 
 
140
        for (alias_walk = fs_aliases; alias_walk != NULL;
 
141
             alias_walk = alias_walk->next) {
 
142
                if (!strcasecmp (alias_walk->alias, name))
 
143
                        break;
 
144
        }
 
145
        if (alias_walk != NULL) {
 
146
                if (alias_walk->deprecated)
 
147
                        PED_DEBUG (0, "File system alias %s is deprecated",
 
148
                                   name);
 
149
                return alias_walk->fs_type;
 
150
        }
 
151
 
 
152
        return NULL;
 
153
}
 
154
 
 
155
/**
 
156
 * Get the next PedFileSystemType after @p fs_type.
 
157
 *
 
158
 * @return @c NULL if @p fs_type is the last item in the list.
 
159
 */
 
160
PedFileSystemType*
 
161
ped_file_system_type_get_next (const PedFileSystemType* fs_type)
 
162
{
 
163
        if (fs_type)
 
164
                return fs_type->next;
 
165
        else
 
166
                return fs_types;
 
167
}
 
168
 
 
169
/**
 
170
 * Get the next PedFileSystemAlias after @p fs_alias.
 
171
 *
 
172
 * @return @c NULL if @p fs_alias is the last item in the list.
 
173
 */
 
174
PedFileSystemAlias*
 
175
ped_file_system_alias_get_next (const PedFileSystemAlias* fs_alias)
 
176
{
 
177
        if (fs_alias)
 
178
                return fs_alias->next;
 
179
        else
 
180
                return fs_aliases;
 
181
}
 
182
 
 
183
/**
 
184
 * Attempt to find a file system and return the region it occupies.
 
185
 *
 
186
 * @param fs_type The file system type to probe for.
 
187
 * @param geom The region to be searched.
 
188
 *
 
189
 * @return @p NULL if @p fs_type file system wasn't detected
 
190
 */
 
191
PedGeometry*
 
192
ped_file_system_probe_specific (
 
193
                const PedFileSystemType* fs_type, PedGeometry* geom)
 
194
{
 
195
        PedGeometry*    result;
 
196
 
 
197
        PED_ASSERT (fs_type != NULL);
 
198
        PED_ASSERT (fs_type->ops->probe != NULL);
 
199
        PED_ASSERT (geom != NULL);
 
200
 
 
201
        /* Fail all fs-specific probe-related tests when sector size
 
202
           is not the default.  */
 
203
        if (geom->dev->sector_size != PED_SECTOR_SIZE_DEFAULT)
 
204
                return 0;
 
205
 
 
206
        if (!ped_device_open (geom->dev))
 
207
                return 0;
 
208
        result = fs_type->ops->probe (geom);
 
209
        ped_device_close (geom->dev);
 
210
        return result;
 
211
}
 
212
 
 
213
static int
 
214
_geometry_error (const PedGeometry* a, const PedGeometry* b)
 
215
{
 
216
        PedSector       start_delta = a->start - b->start;
 
217
        PedSector       end_delta = a->end - b->end;
 
218
 
 
219
        return abs (start_delta) + abs (end_delta);
 
220
}
 
221
 
 
222
static PedFileSystemType*
 
223
_best_match (const PedGeometry* geom, PedFileSystemType* detected [],
 
224
             const int detected_error [], int detected_count)
 
225
{
 
226
        int             best_match = 0;
 
227
        int             i;
 
228
        PedSector       min_error;
 
229
 
 
230
        min_error = PED_MAX (4096, geom->length / 100);
 
231
 
 
232
        for (i = 1; i < detected_count; i++) {
 
233
                if (detected_error [i] < detected_error [best_match])
 
234
                        best_match = i;
 
235
        }
 
236
 
 
237
        /* make sure the best match is significantly better than all the
 
238
         * other matches
 
239
         */
 
240
        for (i = 0; i < detected_count; i++) {
 
241
                if (i == best_match)
 
242
                        continue;
 
243
 
 
244
                if (abs (detected_error [best_match] - detected_error [i])
 
245
                                < min_error)
 
246
                        return NULL;
 
247
        }
 
248
 
 
249
        return detected [best_match];
 
250
}
 
251
 
 
252
 
 
253
/**
 
254
 * Attempt to detect a file system in region \p geom.
 
255
 * This function tries to be clever at dealing with ambiguous
 
256
 * situations, such as when one file system was not completely erased before a
 
257
 * new file system was created on top of it.
 
258
 *
 
259
 * \return a new PedFileSystem on success, \c NULL on failure
 
260
 */
 
261
PedFileSystemType*
 
262
ped_file_system_probe (PedGeometry* geom)
 
263
{
 
264
        PedFileSystemType*      detected[32];
 
265
        int                     detected_error[32];
 
266
        int                     detected_count = 0;
 
267
        PedFileSystemType*      walk = NULL;
 
268
 
 
269
        PED_ASSERT (geom != NULL);
 
270
 
 
271
        if (!ped_device_open (geom->dev))
 
272
                return NULL;
 
273
 
 
274
        ped_exception_fetch_all ();
 
275
        while ( (walk = ped_file_system_type_get_next (walk)) ) {
 
276
                PedGeometry*    probed;
 
277
 
 
278
                probed = ped_file_system_probe_specific (walk, geom);
 
279
                if (probed) {
 
280
                        detected [detected_count] = walk;
 
281
                        detected_error [detected_count]
 
282
                                = _geometry_error (geom, probed);
 
283
                        detected_count++;
 
284
                        ped_geometry_destroy (probed);
 
285
                } else {
 
286
                        ped_exception_catch ();
 
287
                }
 
288
        }
 
289
        ped_exception_leave_all ();
 
290
 
 
291
        ped_device_close (geom->dev);
 
292
 
 
293
        if (!detected_count)
 
294
                return NULL;
 
295
        walk = _best_match (geom, detected, detected_error, detected_count);
 
296
        if (walk)
 
297
                return walk;
 
298
        return NULL;
 
299
}