OSDN Git Service

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