2
libparted - a library for manipulating disk partitions
3
Copyright (C) 2004-2005, 2007, 2009-2012 Free Software Foundation, Inc.
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.
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.
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/>.
23
#include <parted/parted.h>
24
#include <parted/endian.h>
25
#include <parted/debug.h>
30
# define _(String) dgettext (PACKAGE, String)
32
# define _(String) (String)
33
#endif /* ENABLE_NLS */
36
#include "advfs_plus.h"
38
#include "file_plus.h"
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 */
44
hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
45
HfsPExtDataRec ext_desc, PedSector sect_nb)
47
HfsPPrivateFile* file;
49
file = (HfsPPrivateFile*) ped_malloc (sizeof (HfsPPrivateFile));
50
if (!file) return NULL;
53
file->sect_nb = sect_nb;
55
memcpy(file->first, ext_desc, sizeof (HfsPExtDataRec));
56
file->start_cache = 0;
61
/* Close an HFS+ file */
63
hfsplus_file_close (HfsPPrivateFile* file)
68
/* warning : only works on data forks */
70
hfsplus_get_extent_containing (HfsPPrivateFile* file, unsigned int block,
71
HfsPExtDataRec cache, uint32_t* ptr_start_cache)
73
uint8_t record[sizeof (HfsPExtentKey)
74
+ sizeof (HfsPExtDataRec)];
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;
82
search.key_length = PED_CPU_TO_BE16 (sizeof (HfsPExtentKey) - 2);
83
search.type = HFS_DATA_FORK;
85
search.file_ID = file->CNID;
86
search.start = PED_CPU_TO_BE32 (block);
88
if (!hfsplus_btree_search (priv_data->extents_file,
89
(HfsPPrivateGenericKey*) &search,
90
record, sizeof (record), NULL))
93
if (ret_key->file_ID != search.file_ID || ret_key->type != search.type)
96
memcpy (cache, ret_cache, sizeof(HfsPExtDataRec));
97
*ptr_start_cache = PED_BE32_TO_CPU (ret_key->start);
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,
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;
118
unsigned int block = sector / sect_by_block;
119
unsigned int offset = sector % sect_by_block;
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]
128
size = PED_BE32_TO_CPU (file->first[i].block_count)
130
goto plus_sector_found;
132
s += PED_BE32_TO_CPU (file->first[i].block_count);
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]
143
size = PED_BE32_TO_CPU (file->cache[i].block_count)
145
goto plus_sector_found;
147
s += PED_BE32_TO_CPU (file->cache[i].block_count);
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 "
158
PED_BE32_TO_CPU(file->CNID));
159
return ret; /* ret == {0,0} */
163
PED_ASSERT(file->start_cache && block >= file->start_cache);
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]
171
size = PED_BE32_TO_CPU (file->cache[i].block_count)
173
goto plus_sector_found;
175
s += PED_BE32_TO_CPU (file->cache[i].block_count);
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;
188
hfsplus_file_read(HfsPPrivateFile* file, void *buf, PedSector sector,
191
HfsPPrivateExtent phy_area;
192
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
193
file->fs->type_specific;
196
if (sector+nb < sector /* detect overflow */
197
|| sector+nb > file->sect_nb) /* out of file */ {
198
ped_exception_throw (
200
PED_EXCEPTION_CANCEL,
201
_("Trying to read HFS+ file with CNID %X behind EOF."),
202
PED_BE32_TO_CPU(file->CNID));
207
phy_area = hfsplus_file_find_extent(file, sector, nb);
208
if (phy_area.sector_count == 0) {
209
ped_exception_throw (
211
PED_EXCEPTION_CANCEL,
212
_("Could not find sector %lli of HFS+ file "
214
sector, PED_BE32_TO_CPU(file->CNID));
217
if (!ped_geometry_read(priv_data->plus_geom, b,
218
phy_area.start_sector,
219
phy_area.sector_count))
222
nb -= phy_area.sector_count; /* < nb anyway ... */
223
sector += phy_area.sector_count;
224
b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
231
hfsplus_file_write(HfsPPrivateFile* file, void *buf, PedSector sector,
234
HfsPPrivateExtent phy_area;
235
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
236
file->fs->type_specific;
239
if (sector+nb < sector /* detect overflow */
240
|| sector+nb > file->sect_nb) /* out of file */ {
241
ped_exception_throw (
243
PED_EXCEPTION_CANCEL,
244
_("Trying to write HFS+ file with CNID %X behind EOF."),
245
PED_BE32_TO_CPU(file->CNID));
250
phy_area = hfsplus_file_find_extent(file, sector, nb);
251
if (phy_area.sector_count == 0) {
252
ped_exception_throw (
254
PED_EXCEPTION_CANCEL,
255
_("Could not find sector %lli of HFS+ file "
257
sector, PED_BE32_TO_CPU(file->CNID));
260
if (!ped_geometry_write(priv_data->plus_geom, b,
261
phy_area.start_sector,
262
phy_area.sector_count))
265
nb -= phy_area.sector_count; /* < nb anyway ... */
266
sector += phy_area.sector_count;
267
b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
273
#endif /* !DISCOVER_ONLY */