2 libparted - a library for manipulating disk partitions
3 Copyright (C) 2004-2005, 2007, 2009-2011 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, return ret);
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 */