OSDN Git Service

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