~youscribe/parted/3.1

« back to all changes in this revision

Viewing changes to libparted/fs/r/hfs/file.c

  • Committer: Guilhem Lettron
  • Date: 2012-10-22 14:37:59 UTC
  • Revision ID: guilhem+ubuntu@lettron.fr-20121022143759-m403kecgz13sknvp
3.1 from tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    libparted - a library for manipulating disk partitions
 
3
    Copyright (C) 2004-2005, 2007, 2009-2012 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);
 
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 */