xref: /onnv-gate/usr/src/lib/libparted/common/libparted/fs/hfs/file.c (revision 9663:ace9a2ac3683)
1 /*
2     libparted - a library for manipulating disk partitions
3     Copyright (C) 2004, 2005, 2007 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.h"
37 
38 #include "file.h"
39 
40 /* Open the data fork of a file with its first three extents and its CNID */
41 HfsPrivateFile*
hfs_file_open(PedFileSystem * fs,uint32_t CNID,HfsExtDataRec ext_desc,PedSector sect_nb)42 hfs_file_open (PedFileSystem *fs, uint32_t CNID,
43 	       HfsExtDataRec ext_desc, PedSector sect_nb)
44 {
45 	HfsPrivateFile* file;
46 
47 	file = (HfsPrivateFile*) ped_malloc (sizeof (HfsPrivateFile));
48 	if (!file) return NULL;
49 
50 	file->fs = fs;
51 	file->sect_nb = sect_nb;
52 	file->CNID = CNID;
53 	memcpy(file->first, ext_desc, sizeof (HfsExtDataRec));
54 	file->start_cache = 0;
55 
56 	return file;
57 }
58 
59 /* Close an HFS file */
60 void
hfs_file_close(HfsPrivateFile * file)61 hfs_file_close (HfsPrivateFile* file)
62 {
63 	ped_free (file);
64 }
65 
66 /* warning : only works on data forks */
67 static int
hfs_get_extent_containing(HfsPrivateFile * file,unsigned int block,HfsExtDataRec cache,uint16_t * ptr_start_cache)68 hfs_get_extent_containing (HfsPrivateFile* file, unsigned int block,
69 			   HfsExtDataRec cache, uint16_t* ptr_start_cache)
70 {
71 	uint8_t			record[sizeof (HfsExtentKey)
72 				       + sizeof (HfsExtDataRec)];
73 	HfsExtentKey		search;
74 	HfsExtentKey*		ret_key = (HfsExtentKey*) record;
75 	HfsExtDescriptor*	ret_cache = (HfsExtDescriptor*)
76 					      (record + sizeof (HfsExtentKey));
77 	HfsPrivateFSData* 	priv_data = (HfsPrivateFSData*)
78 					      file->fs->type_specific;
79 
80 	search.key_length = sizeof (HfsExtentKey) - 1;
81 	search.type = HFS_DATA_FORK;
82 	search.file_ID = file->CNID;
83 	search.start = PED_CPU_TO_BE16 (block);
84 
85 	if (!hfs_btree_search (priv_data->extent_file,
86 			       (HfsPrivateGenericKey*) &search,
87 			       record, sizeof (record), NULL))
88 		return 0;
89 
90 	if (ret_key->file_ID != search.file_ID || ret_key->type != search.type)
91 		return 0;
92 
93 	memcpy (cache, ret_cache, sizeof(HfsExtDataRec));
94 	*ptr_start_cache = PED_BE16_TO_CPU (ret_key->start);
95 
96 	return 1;
97 }
98 
99 /* find and return the nth sector of a file */
100 /* return 0 on error */
101 static PedSector
hfs_file_find_sector(HfsPrivateFile * file,PedSector sector)102 hfs_file_find_sector (HfsPrivateFile* file, PedSector sector)
103 {
104 	HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
105 				      file->fs->type_specific;
106 	unsigned int 	sect_by_block = PED_BE32_TO_CPU (
107 					    priv_data->mdb->block_size)
108 					/ PED_SECTOR_SIZE_DEFAULT;
109 	unsigned int 	i, s, vol_block;
110 	unsigned int 	block  = sector / sect_by_block;
111 	unsigned int	offset = sector % sect_by_block;
112 
113 	/* in the three first extent */
114 	for (s = 0, i = 0; i < HFS_EXT_NB; i++) {
115 			if ((block >= s) && ( block < s + PED_BE16_TO_CPU (
116 						file->first[i].block_count))) {
117 			vol_block = (block - s) + PED_BE16_TO_CPU (
118 						    file->first[i].start_block);
119 			goto sector_found;
120 		}
121 		s += PED_BE16_TO_CPU (file->first[i].block_count);
122 	}
123 
124 	/* in the three cached extent */
125 	if (file->start_cache && block >= file->start_cache)
126 	for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++) {
127 		if ((block >= s) && (block < s + PED_BE16_TO_CPU (
128 						file->cache[i].block_count))) {
129 			vol_block = (block - s) + PED_BE16_TO_CPU (
130 						    file->cache[i].start_block);
131 			goto sector_found;
132 		}
133 		s += PED_BE16_TO_CPU (file->cache[i].block_count);
134 	}
135 
136 	/* update cache */
137 	if (!hfs_get_extent_containing (file, block, file->cache,
138 					&(file->start_cache))) {
139 		ped_exception_throw (
140 			PED_EXCEPTION_WARNING,
141 			PED_EXCEPTION_CANCEL,
142 			_("Could not update the extent cache for HFS file with "
143 			  "CNID %X."),
144 			PED_BE32_TO_CPU(file->CNID));
145 		return 0;
146 	}
147 
148 	/* in the three cached extent */
149 	PED_ASSERT(file->start_cache && block >= file->start_cache, return 0);
150 	for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++) {
151 		if ((block >= s) && (block < s + PED_BE16_TO_CPU (
152 						file->cache[i].block_count))) {
153 			vol_block = (block - s) + PED_BE16_TO_CPU (
154 						    file->cache[i].start_block);
155 			goto sector_found;
156 		}
157 		s += PED_BE16_TO_CPU (file->cache[i].block_count);
158 	}
159 
160 	return 0;
161 
162     sector_found:
163 	return (PedSector) PED_BE16_TO_CPU (priv_data->mdb->start_block)
164 		+ (PedSector) vol_block * sect_by_block
165 		+ offset;
166 }
167 
168 /* Read the nth sector of a file */
169 /* return 0 on error */
170 int
hfs_file_read_sector(HfsPrivateFile * file,void * buf,PedSector sector)171 hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector)
172 {
173 	PedSector	abs_sector;
174 
175 	if (sector >= file->sect_nb) {
176 		ped_exception_throw (
177 			PED_EXCEPTION_ERROR,
178 			PED_EXCEPTION_CANCEL,
179 			_("Trying to read HFS file with CNID %X behind EOF."),
180 			PED_BE32_TO_CPU(file->CNID));
181 		return 0;
182 	}
183 
184 	abs_sector = hfs_file_find_sector (file, sector);
185 	if (!abs_sector) {
186 		ped_exception_throw (
187 			PED_EXCEPTION_ERROR,
188 			PED_EXCEPTION_CANCEL,
189 			_("Could not find sector %lli of HFS file with "
190 			  "CNID %X."),
191 			sector, PED_BE32_TO_CPU(file->CNID));
192 		return 0;
193 	}
194 
195 	return ped_geometry_read (file->fs->geom, buf, abs_sector, 1);
196 }
197 
198 /* Write the nth sector of a file */
199 /* return 0 on error */
200 int
hfs_file_write_sector(HfsPrivateFile * file,void * buf,PedSector sector)201 hfs_file_write_sector (HfsPrivateFile* file, void *buf, PedSector sector)
202 {
203 	PedSector	abs_sector;
204 
205 	if (sector >= file->sect_nb) {
206 		ped_exception_throw (
207 			PED_EXCEPTION_ERROR,
208 			PED_EXCEPTION_CANCEL,
209 			_("Trying to write HFS file with CNID %X behind EOF."),
210 			  PED_BE32_TO_CPU(file->CNID));
211 		return 0;
212 	}
213 
214 	abs_sector = hfs_file_find_sector (file, sector);
215 	if (!abs_sector) {
216 		ped_exception_throw (
217 			PED_EXCEPTION_ERROR,
218 			PED_EXCEPTION_CANCEL,
219 			_("Could not find sector %lli of HFS file with "
220 			  "CNID %X."),
221 			sector, PED_BE32_TO_CPU(file->CNID));
222 		return 0;
223 	}
224 
225 	return ped_geometry_write (file->fs->geom, buf, abs_sector, 1);
226 }
227 
228 #endif /* !DISCOVER_ONLY */
229