~ubuntu-branches/ubuntu/utopic/parted/utopic-proposed

« back to all changes in this revision

Viewing changes to libparted/fs/r/hfs/file_plus.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2014-07-21 10:23:16 UTC
  • mfrom: (7.2.32 sid)
  • Revision ID: package-import@ubuntu.com-20140721102316-jsyv3yzmbo8vlde5
Tags: 3.1-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    libparted - a library for manipulating disk partitions
 
3
    Copyright (C) 2004-2005, 2007, 2009-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
#ifndef DISCOVER_ONLY
 
20
 
 
21
#include <config.h>
 
22
 
 
23
#include <parted/parted.h>
 
24
#include <parted/endian.h>
 
25
#include <parted/debug.h>
 
26
#include <stdint.h>
 
27
 
 
28
#if ENABLE_NLS
 
29
#  include <libintl.h>
 
30
#  define _(String) dgettext (PACKAGE, String)
 
31
#else
 
32
#  define _(String) (String)
 
33
#endif /* ENABLE_NLS */
 
34
 
 
35
#include "hfs.h"
 
36
#include "advfs_plus.h"
 
37
 
 
38
#include "file_plus.h"
 
39
 
 
40
/* Open the data fork of a file with its first eight extents and its CNID */
 
41
/* CNID and ext_desc must be in disc order, sect_nb in CPU order */
 
42
/* return null on failure */
 
43
HfsPPrivateFile*
 
44
hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
 
45
                   HfsPExtDataRec ext_desc, PedSector sect_nb)
 
46
{
 
47
        HfsPPrivateFile* file;
 
48
 
 
49
        file = (HfsPPrivateFile*) ped_malloc (sizeof (HfsPPrivateFile));
 
50
        if (!file) return NULL;
 
51
 
 
52
        file->fs = fs;
 
53
        file->sect_nb = sect_nb;
 
54
        file->CNID = CNID;
 
55
        memcpy(file->first, ext_desc, sizeof (HfsPExtDataRec));
 
56
        file->start_cache = 0;
 
57
 
 
58
        return file;
 
59
}
 
60
 
 
61
/* Close an HFS+ file */
 
62
void
 
63
hfsplus_file_close (HfsPPrivateFile* file)
 
64
{
 
65
        free (file);
 
66
}
 
67
 
 
68
/* warning : only works on data forks */
 
69
static int
 
70
hfsplus_get_extent_containing (HfsPPrivateFile* file, unsigned int block,
 
71
                               HfsPExtDataRec cache, uint32_t* ptr_start_cache)
 
72
{
 
73
        uint8_t                 record[sizeof (HfsPExtentKey)
 
74
                                       + sizeof (HfsPExtDataRec)];
 
75
        HfsPExtentKey           search;
 
76
        HfsPExtentKey*          ret_key = (HfsPExtentKey*) record;
 
77
        HfsPExtDescriptor*      ret_cache = (HfsPExtDescriptor*)
 
78
                                              (record + sizeof (HfsPExtentKey));
 
79
        HfsPPrivateFSData*      priv_data = (HfsPPrivateFSData*)
 
80
                                                file->fs->type_specific;
 
81
 
 
82
        search.key_length = PED_CPU_TO_BE16 (sizeof (HfsPExtentKey) - 2);
 
83
        search.type = HFS_DATA_FORK;
 
84
        search.pad = 0;
 
85
        search.file_ID = file->CNID;
 
86
        search.start = PED_CPU_TO_BE32 (block);
 
87
 
 
88
        if (!hfsplus_btree_search (priv_data->extents_file,
 
89
                                   (HfsPPrivateGenericKey*) &search,
 
90
                                   record, sizeof (record), NULL))
 
91
                return 0;
 
92
 
 
93
        if (ret_key->file_ID != search.file_ID || ret_key->type != search.type)
 
94
                return 0;
 
95
 
 
96
        memcpy (cache, ret_cache, sizeof(HfsPExtDataRec));
 
97
        *ptr_start_cache = PED_BE32_TO_CPU (ret_key->start);
 
98
 
 
99
        return 1;
 
100
}
 
101
 
 
102
/* find a sub extent contained in the desired area */
 
103
/* and with the same starting point */
 
104
/* return 0 in sector_count on error, or the physical area */
 
105
/* on the volume corresponding to the logical area in the file */
 
106
static HfsPPrivateExtent
 
107
hfsplus_file_find_extent (HfsPPrivateFile* file, PedSector sector,
 
108
                          unsigned int nb)
 
109
{
 
110
        HfsPPrivateExtent ret = {0,0};
 
111
        HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
 
112
                                        file->fs->type_specific;
 
113
        unsigned int    sect_by_block = PED_BE32_TO_CPU (
 
114
                                            priv_data->vh->block_size)
 
115
                                        / PED_SECTOR_SIZE_DEFAULT;
 
116
        unsigned int    i, s, vol_block, size;
 
117
        PedSector       sect_size;
 
118
        unsigned int    block  = sector / sect_by_block;
 
119
        unsigned int    offset = sector % sect_by_block;
 
120
 
 
121
        /* in the 8 first extent */
 
122
        for (s = 0, i = 0; i < HFSP_EXT_NB; i++) {
 
123
                if ((block >= s) && (block < s + PED_BE32_TO_CPU (
 
124
                                                file->first[i].block_count))) {
 
125
                        vol_block = (block - s)
 
126
                                    + PED_BE32_TO_CPU (file->first[i]
 
127
                                                       .start_block);
 
128
                        size = PED_BE32_TO_CPU (file->first[i].block_count)
 
129
                                + s - block;
 
130
                        goto plus_sector_found;
 
131
                }
 
132
                s += PED_BE32_TO_CPU (file->first[i].block_count);
 
133
        }
 
134
 
 
135
        /* in the 8 cached extent */
 
136
        if (file->start_cache && block >= file->start_cache)
 
137
        for (s = file->start_cache, i = 0; i < HFSP_EXT_NB; i++) {
 
138
                if ((block >= s) && (block < s + PED_BE32_TO_CPU (
 
139
                                                file->cache[i].block_count))) {
 
140
                        vol_block = (block - s)
 
141
                                    + PED_BE32_TO_CPU (file->cache[i]
 
142
                                                       .start_block);
 
143
                        size = PED_BE32_TO_CPU (file->cache[i].block_count)
 
144
                                + s - block;
 
145
                        goto plus_sector_found;
 
146
                }
 
147
                s += PED_BE32_TO_CPU (file->cache[i].block_count);
 
148
        }
 
149
 
 
150
        /* update cache */
 
151
        if (!hfsplus_get_extent_containing (file, block, file->cache,
 
152
                                            &(file->start_cache))) {
 
153
                ped_exception_throw (
 
154
                        PED_EXCEPTION_WARNING,
 
155
                        PED_EXCEPTION_CANCEL,
 
156
                        _("Could not update the extent cache for HFS+ file "
 
157
                          "with CNID %X."),
 
158
                        PED_BE32_TO_CPU(file->CNID));
 
159
                return ret; /* ret == {0,0} */
 
160
        }
 
161
 
 
162
        /* ret == {0,0} */
 
163
        PED_ASSERT(file->start_cache && block >= file->start_cache);
 
164
 
 
165
        for (s = file->start_cache, i = 0; i < HFSP_EXT_NB; i++) {
 
166
                if ((block >= s) && (block < s + PED_BE32_TO_CPU (
 
167
                                                file->cache[i].block_count))) {
 
168
                        vol_block = (block - s)
 
169
                                    + PED_BE32_TO_CPU (file->cache[i]
 
170
                                                       .start_block);
 
171
                        size = PED_BE32_TO_CPU (file->cache[i].block_count)
 
172
                                + s - block;
 
173
                        goto plus_sector_found;
 
174
                }
 
175
                s += PED_BE32_TO_CPU (file->cache[i].block_count);
 
176
        }
 
177
 
 
178
        return ret;
 
179
 
 
180
plus_sector_found:
 
181
        sect_size = (PedSector) size * sect_by_block - offset;
 
182
        ret.start_sector = vol_block * sect_by_block + offset;
 
183
        ret.sector_count = (sect_size < nb) ? sect_size : nb;
 
184
        return ret;
 
185
}
 
186
 
 
187
int
 
188
hfsplus_file_read(HfsPPrivateFile* file, void *buf, PedSector sector,
 
189
                  unsigned int nb)
 
190
{
 
191
        HfsPPrivateExtent phy_area;
 
192
        HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
 
193
                                        file->fs->type_specific;
 
194
        char *b = buf;
 
195
 
 
196
        if (sector+nb < sector /* detect overflow */
 
197
            || sector+nb > file->sect_nb) /* out of file */ {
 
198
                ped_exception_throw (
 
199
                        PED_EXCEPTION_ERROR,
 
200
                        PED_EXCEPTION_CANCEL,
 
201
                        _("Trying to read HFS+ file with CNID %X behind EOF."),
 
202
                        PED_BE32_TO_CPU(file->CNID));
 
203
                return 0;
 
204
        }
 
205
 
 
206
        while (nb) {
 
207
                phy_area = hfsplus_file_find_extent(file, sector, nb);
 
208
                if (phy_area.sector_count == 0) {
 
209
                        ped_exception_throw (
 
210
                                PED_EXCEPTION_ERROR,
 
211
                                PED_EXCEPTION_CANCEL,
 
212
                                _("Could not find sector %lli of HFS+ file "
 
213
                                  "with CNID %X."),
 
214
                                sector, PED_BE32_TO_CPU(file->CNID));
 
215
                        return 0;
 
216
                }
 
217
                if (!ped_geometry_read(priv_data->plus_geom, b,
 
218
                                       phy_area.start_sector,
 
219
                                       phy_area.sector_count))
 
220
                        return 0;
 
221
 
 
222
                nb -= phy_area.sector_count; /* < nb anyway ... */
 
223
                sector += phy_area.sector_count;
 
224
                b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
 
225
        }
 
226
 
 
227
        return 1;
 
228
}
 
229
 
 
230
int
 
231
hfsplus_file_write(HfsPPrivateFile* file, void *buf, PedSector sector,
 
232
                  unsigned int nb)
 
233
{
 
234
        HfsPPrivateExtent phy_area;
 
235
        HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
 
236
                                        file->fs->type_specific;
 
237
        char *b = buf;
 
238
 
 
239
        if (sector+nb < sector /* detect overflow */
 
240
            || sector+nb > file->sect_nb) /* out of file */ {
 
241
                ped_exception_throw (
 
242
                        PED_EXCEPTION_ERROR,
 
243
                        PED_EXCEPTION_CANCEL,
 
244
                        _("Trying to write HFS+ file with CNID %X behind EOF."),
 
245
                        PED_BE32_TO_CPU(file->CNID));
 
246
                return 0;
 
247
        }
 
248
 
 
249
        while (nb) {
 
250
                phy_area = hfsplus_file_find_extent(file, sector, nb);
 
251
                if (phy_area.sector_count == 0) {
 
252
                        ped_exception_throw (
 
253
                                PED_EXCEPTION_ERROR,
 
254
                                PED_EXCEPTION_CANCEL,
 
255
                                _("Could not find sector %lli of HFS+ file "
 
256
                                  "with CNID %X."),
 
257
                                sector, PED_BE32_TO_CPU(file->CNID));
 
258
                        return 0;
 
259
                }
 
260
                if (!ped_geometry_write(priv_data->plus_geom, b,
 
261
                                       phy_area.start_sector,
 
262
                                       phy_area.sector_count))
 
263
                        return 0;
 
264
 
 
265
                nb -= phy_area.sector_count; /* < nb anyway ... */
 
266
                sector += phy_area.sector_count;
 
267
                b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
 
268
        }
 
269
 
 
270
        return 1;
 
271
}
 
272
 
 
273
#endif /* !DISCOVER_ONLY */