OSDN Git Service

Use free, not ped_free.
[android-x86/external-parted.git] / libparted / fs / hfs / file.c
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*
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
61 hfs_file_close (HfsPrivateFile* file)
62 {
63         free (file);
64 }
65
66 /* warning : only works on data forks */
67 static int
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
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
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
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 */