~youscribe/parted/3.1

« back to all changes in this revision

Viewing changes to libparted/fs/r/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
/* libparted - a library for manipulating disk partitions
 
2
    Copyright (C) 1999-2001, 2007-2012 Free Software Foundation, Inc.
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 3 of the License, or
 
7
    (at your option) any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU General Public License
 
15
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
*/
 
17
 
 
18
/** \file filesys.c */
 
19
 
 
20
/**
 
21
 * \addtogroup PedFileSystem
 
22
 *
 
23
 * \note File systems exist on a PedGeometry - NOT a PedPartition.
 
24
 *
 
25
 * @{
 
26
 */
 
27
 
 
28
#include <config.h>
 
29
 
 
30
#include <parted/parted.h>
 
31
#include <parted/debug.h>
 
32
#include "pt-tools.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 STREQ(a, b) (strcmp (a, b) == 0)
 
42
 
 
43
#ifndef MIN
 
44
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
 
45
#endif
 
46
 
 
47
typedef PedFileSystem * (*open_fn_t) (PedGeometry *);
 
48
extern PedFileSystem *hfsplus_open (PedGeometry *);
 
49
extern PedFileSystem *hfs_open (PedGeometry *);
 
50
extern PedFileSystem *fat_open (PedGeometry *);
 
51
 
 
52
typedef int (*close_fn_t) (PedFileSystem *);
 
53
extern int hfsplus_close (PedFileSystem *);
 
54
extern int hfs_close (PedFileSystem *);
 
55
extern int fat_close (PedFileSystem *);
 
56
 
 
57
typedef int (*resize_fn_t) (PedFileSystem *fs, PedGeometry *geom,
 
58
                            PedTimer *timer);
 
59
extern int hfsplus_resize (PedFileSystem *fs, PedGeometry *geom,
 
60
                           PedTimer *timer);
 
61
extern int hfs_resize (PedFileSystem *fs, PedGeometry *geom,
 
62
                       PedTimer *timer);
 
63
extern int fat_resize (PedFileSystem *fs, PedGeometry *geom,
 
64
                       PedTimer *timer);
 
65
 
 
66
typedef PedConstraint * (*resize_constraint_fn_t) (PedFileSystem const *fs);
 
67
extern PedConstraint *hfsplus_get_resize_constraint (PedFileSystem const *fs);
 
68
extern PedConstraint *hfs_get_resize_constraint (PedFileSystem const *fs);
 
69
extern PedConstraint *fat_get_resize_constraint (PedFileSystem const *fs);
 
70
 
 
71
static bool
 
72
is_hfs_plus (char const *fs_type_name)
 
73
{
 
74
  return STREQ (fs_type_name, "hfsx") || STREQ (fs_type_name, "hfs+");
 
75
}
 
76
 
 
77
static open_fn_t
 
78
open_fn (char const *fs_type_name)
 
79
{
 
80
  if (is_hfs_plus (fs_type_name))
 
81
    return hfsplus_open;
 
82
  if (STREQ (fs_type_name, "hfs"))
 
83
    return hfs_open;
 
84
  if (strncmp (fs_type_name, "fat", 3) == 0)
 
85
    return fat_open;
 
86
  return NULL;
 
87
}
 
88
 
 
89
static close_fn_t
 
90
close_fn (char const *fs_type_name)
 
91
{
 
92
  if (is_hfs_plus (fs_type_name))
 
93
    return hfsplus_close;
 
94
  if (STREQ (fs_type_name, "hfs"))
 
95
    return hfs_close;
 
96
  if (strncmp (fs_type_name, "fat", 3) == 0)
 
97
    return fat_close;
 
98
  return NULL;
 
99
}
 
100
 
 
101
static resize_fn_t
 
102
resize_fn (char const *fs_type_name)
 
103
{
 
104
  if (is_hfs_plus (fs_type_name))
 
105
    return hfsplus_resize;
 
106
  if (STREQ (fs_type_name, "hfs"))
 
107
    return hfs_resize;
 
108
  if (strncmp (fs_type_name, "fat", 3) == 0)
 
109
    return fat_resize;
 
110
  return NULL;
 
111
}
 
112
 
 
113
static resize_constraint_fn_t
 
114
resize_constraint_fn (char const *fs_type_name)
 
115
{
 
116
  if (is_hfs_plus (fs_type_name))
 
117
    return hfsplus_get_resize_constraint;
 
118
  if (STREQ (fs_type_name, "hfs"))
 
119
    return hfs_get_resize_constraint;
 
120
  if (strncmp (fs_type_name, "fat", 3) == 0)
 
121
    return fat_get_resize_constraint;
 
122
  return NULL;
 
123
}
 
124
 
 
125
/**
 
126
 * This function opens the file system stored on \p geom, if it
 
127
 * can find one.
 
128
 * It is often called in the following manner:
 
129
 * \code
 
130
 *     fs = ped_file_system_open (&part.geom)
 
131
 * \endcode
 
132
 *
 
133
 * \throws PED_EXCEPTION_ERROR if file system could not be detected
 
134
 * \throws PED_EXCEPTION_ERROR if the file system is bigger than its volume
 
135
 * \throws PED_EXCEPTION_NO_FEATURE if opening of a file system stored on
 
136
 *     \p geom is not implemented
 
137
 *
 
138
 * \return a PedFileSystem on success, \c NULL on failure.
 
139
 */
 
140
PedFileSystem *
 
141
ped_file_system_open (PedGeometry* geom)
 
142
{
 
143
       PED_ASSERT (geom != NULL);
 
144
 
 
145
       if (!ped_device_open (geom->dev))
 
146
               goto error;
 
147
 
 
148
       PedFileSystemType *type = ped_file_system_probe (geom);
 
149
       if (!type) {
 
150
               ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 
151
                                    _("Could not detect file system."));
 
152
               goto error_close_dev;
 
153
       }
 
154
 
 
155
       open_fn_t open_f = open_fn (type->name);
 
156
       if (open_f == NULL) {
 
157
           ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 
158
                                _("resizing %s file systems is not supported"),
 
159
                                type->name);
 
160
           goto error_close_dev;
 
161
       }
 
162
 
 
163
       PedGeometry *probed_geom = ped_file_system_probe_specific (type, geom);
 
164
       if (!probed_geom)
 
165
               goto error_close_dev;
 
166
       if (!ped_geometry_test_inside (geom, probed_geom)) {
 
167
               if (ped_exception_throw (
 
168
                       PED_EXCEPTION_ERROR,
 
169
                       PED_EXCEPTION_IGNORE_CANCEL,
 
170
                       _("The file system is bigger than its volume!"))
 
171
                               != PED_EXCEPTION_IGNORE)
 
172
                       goto error_destroy_probed_geom;
 
173
       }
 
174
 
 
175
       PedFileSystem *fs = (*open_f) (probed_geom);
 
176
       if (!fs)
 
177
               goto error_destroy_probed_geom;
 
178
       ped_geometry_destroy (probed_geom);
 
179
       fs->type = type;
 
180
       return fs;
 
181
 
 
182
error_destroy_probed_geom:
 
183
       ped_geometry_destroy (probed_geom);
 
184
error_close_dev:
 
185
       ped_device_close (geom->dev);
 
186
error:
 
187
       return NULL;
 
188
}
 
189
 
 
190
/**
 
191
 * Close file system \p fs.
 
192
 *
 
193
 * \return \c 1 on success, \c 0 on failure
 
194
 */
 
195
int
 
196
ped_file_system_close (PedFileSystem* fs)
 
197
{
 
198
       PED_ASSERT (fs != NULL);
 
199
       PedDevice *dev = fs->geom->dev;
 
200
 
 
201
       if (!(close_fn (fs->type->name) (fs)))
 
202
               goto error_close_dev;
 
203
       ped_device_close (dev);
 
204
       return 1;
 
205
 
 
206
error_close_dev:
 
207
       ped_device_close (dev);
 
208
       return 0;
 
209
}
 
210
 
 
211
/**
 
212
 * This function erases all file system signatures that indicate that a
 
213
 * file system occupies a given region described by \p geom.
 
214
 * After this operation ped_file_system_probe() won't detect any file system.
 
215
 *
 
216
 * \note ped_file_system_create() calls this before creating a new file system.
 
217
 *
 
218
 * \return \c 1 on success, \c 0 on failure
 
219
 */
 
220
static int
 
221
ped_file_system_clobber (PedGeometry* geom)
 
222
{
 
223
  PED_ASSERT (geom != NULL);
 
224
 
 
225
  if (!ped_device_open (geom->dev))
 
226
    return 0;
 
227
 
 
228
  /* Clear the first three and the last two sectors, albeit fewer
 
229
     when GEOM is too small.  */
 
230
  PedSector len = MIN (geom->length, geom->dev->length);
 
231
 
 
232
  int ok = (len <= 5
 
233
            ? ptt_geom_clear_sectors (geom, 0, len)
 
234
            : (ptt_geom_clear_sectors (geom, 0, 3)
 
235
               && ptt_geom_clear_sectors (geom, geom->dev->length - 2, 2)));
 
236
 
 
237
  ped_device_close (geom->dev);
 
238
  return !!ok;
 
239
}
 
240
 
 
241
/* This function erases all signatures that indicate the presence of
 
242
 * a file system in a particular region, without erasing any data
 
243
 * contained inside the "exclude" region.
 
244
 */
 
245
static int
 
246
ped_file_system_clobber_exclude (PedGeometry* geom,
 
247
                                 const PedGeometry* exclude)
 
248
{
 
249
        PedGeometry*    clobber_geom;
 
250
        int             status;
 
251
 
 
252
        if (ped_geometry_test_sector_inside (exclude, geom->start))
 
253
                return 1;
 
254
 
 
255
        clobber_geom = ped_geometry_duplicate (geom);
 
256
        if (ped_geometry_test_overlap (clobber_geom, exclude))
 
257
                ped_geometry_set_end (clobber_geom, exclude->start - 1);
 
258
 
 
259
        status = ped_file_system_clobber (clobber_geom);
 
260
        ped_geometry_destroy (clobber_geom);
 
261
        return status;
 
262
}
 
263
 
 
264
/**
 
265
 * Resize \p fs to new geometry \p geom.
 
266
 *
 
267
 * \p geom should satisfy the ped_file_system_get_resize_constraint().
 
268
 * (This isn't asserted, so it's not a bug not to... just it's likely
 
269
 * to fail ;)  If \p timer is non-NULL, it is used as the progress meter.
 
270
 *
 
271
 * \throws PED_EXCEPTION_NO_FEATURE if resizing of file system \p fs
 
272
 *     is not implemented yet
 
273
 *
 
274
 * \return \c 0 on failure
 
275
 */
 
276
int
 
277
ped_file_system_resize (PedFileSystem *fs, PedGeometry *geom, PedTimer *timer)
 
278
{
 
279
       PED_ASSERT (fs != NULL);
 
280
       PED_ASSERT (geom != NULL);
 
281
 
 
282
       resize_fn_t resize_f = resize_fn (fs->type->name);
 
283
       if (resize_f == NULL) {
 
284
           ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 
285
                                _("resizing %s file systems is not supported"),
 
286
                                fs->type->name);
 
287
           return 0;
 
288
       }
 
289
 
 
290
       if (!ped_file_system_clobber_exclude (geom, fs->geom))
 
291
               return 0;
 
292
 
 
293
       return resize_f (fs, geom, timer);
 
294
}
 
295
 
 
296
/**
 
297
 * Return a constraint that represents all of the possible ways the
 
298
 * file system \p fs can be resized with ped_file_system_resize().
 
299
 * This takes into account the amount of used space on
 
300
 * the filesystem \p fs and the capabilities of the resize algorithm.
 
301
 * Hints:
 
302
 * -# if constraint->start_align->grain_size == 0, or
 
303
 *    constraint->start_geom->length == 1, then the start cannot be moved
 
304
 * -# constraint->min_size is the minimum size you can resize the partition
 
305
 *    to.  You might want to tell the user this ;-).
 
306
 *
 
307
 * \return a PedConstraint on success, \c NULL on failure
 
308
 */
 
309
PedConstraint *
 
310
ped_file_system_get_resize_constraint (const PedFileSystem *fs)
 
311
{
 
312
        PED_ASSERT (fs != NULL);
 
313
 
 
314
        resize_constraint_fn_t resize_constraint_f =
 
315
          resize_constraint_fn (fs->type->name);
 
316
        if (resize_constraint_f == NULL)
 
317
          return NULL;
 
318
 
 
319
        return resize_constraint_f (fs);
 
320
}