3 Copyright (C) 1998-2000, 2005, 2007-2010 Free Software Foundation,
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 static char tmp_buffer [4096];
35 fat_traverse_entries_per_buffer (FatTraverseInfo* trav_info)
37 return trav_info->buffer_size / sizeof (FatDirEntry);
40 /* returns 1 if there are no more directory entries in the directory being
41 * traversed, 0 otherwise.
44 is_last_buffer (FatTraverseInfo* trav_info) {
45 FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
47 if (trav_info->is_legacy_root_dir)
50 return fat_table_is_eof (fs_info->fat, trav_info->next_buffer);
54 write_root_dir (FatTraverseInfo* trav_info)
56 FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
58 if (!ped_geometry_write (trav_info->fs->geom, trav_info->dir_entries,
59 fs_info->root_dir_offset,
60 fs_info->root_dir_sector_count))
62 if (!ped_geometry_sync (trav_info->fs->geom))
69 write_dir_cluster (FatTraverseInfo* trav_info)
71 if (!fat_write_sync_cluster (trav_info->fs,
72 (void*) trav_info->dir_entries,
73 trav_info->this_buffer))
80 write_dir_buffer (FatTraverseInfo* trav_info)
82 if (trav_info->is_legacy_root_dir)
83 return write_root_dir (trav_info);
85 return write_dir_cluster (trav_info);
89 read_next_dir_buffer (FatTraverseInfo* trav_info)
91 FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
93 PED_ASSERT (!trav_info->is_legacy_root_dir, return 0);
95 trav_info->this_buffer = trav_info->next_buffer;
97 if (trav_info->this_buffer < 2
98 || trav_info->this_buffer >= fs_info->cluster_count + 2) {
101 PED_EXCEPTION_CANCEL,
102 "Cluster %ld in directory %s is outside file system!",
103 (long) trav_info->this_buffer,
104 trav_info->dir_name);
108 trav_info->next_buffer
109 = fat_table_get (fs_info->fat, trav_info->this_buffer);
111 return fat_read_cluster (trav_info->fs, (void *) trav_info->dir_entries,
112 trav_info->this_buffer);
115 /* FIXME: put into fat_dir_entry_* operations */
117 fat_traverse_mark_dirty (FatTraverseInfo* trav_info)
119 trav_info->dirty = 1;
123 fat_traverse_begin (PedFileSystem* fs, FatCluster start_cluster,
124 const char* dir_name)
126 FatSpecific* fs_info = FAT_SPECIFIC (fs);
127 FatTraverseInfo* trav_info;
129 trav_info = (FatTraverseInfo*) ped_malloc (sizeof (FatTraverseInfo));
133 trav_info->dir_name = strdup (dir_name);
134 if (!trav_info->dir_name)
135 goto error_free_trav_info;
138 trav_info->is_legacy_root_dir
139 = (fs_info->fat_type == FAT_TYPE_FAT16) && (start_cluster == 0);
140 trav_info->dirty = 0;
142 trav_info->current_entry = -1;
144 if (trav_info->is_legacy_root_dir) {
145 trav_info->buffer_size = 512 * fs_info->root_dir_sector_count;
147 trav_info->next_buffer = start_cluster;
148 trav_info->buffer_size = fs_info->cluster_size;
151 trav_info->dir_entries
152 = (FatDirEntry*) ped_malloc (trav_info->buffer_size);
153 if (!trav_info->dir_entries)
154 goto error_free_dir_name;
156 if (trav_info->is_legacy_root_dir) {
157 if (!ped_geometry_read (fs->geom, trav_info->dir_entries,
158 fs_info->root_dir_offset,
159 fs_info->root_dir_sector_count))
160 goto error_free_dir_entries;
162 if (!read_next_dir_buffer (trav_info))
163 goto error_free_dir_entries;
168 error_free_dir_entries:
169 free (trav_info->dir_entries);
171 free (trav_info->dir_name);
172 error_free_trav_info:
179 fat_traverse_complete (FatTraverseInfo* trav_info)
181 if (trav_info->dirty) {
182 if (!write_dir_buffer (trav_info))
185 free (trav_info->dir_entries);
186 free (trav_info->dir_name);
192 fat_traverse_directory (FatTraverseInfo *trav_info, FatDirEntry* parent)
194 strcpy (tmp_buffer, trav_info->dir_name);
195 fat_dir_entry_get_name (parent,
196 tmp_buffer + strlen (trav_info->dir_name));
197 strcat (tmp_buffer, "\\");
199 return fat_traverse_begin (trav_info->fs,
200 fat_dir_entry_get_first_cluster (parent, trav_info->fs),
205 fat_traverse_next_dir_entry (FatTraverseInfo *trav_info)
210 trav_info->current_entry++;
211 if (trav_info->current_entry
212 >= fat_traverse_entries_per_buffer (trav_info)) {
213 if (trav_info->dirty) {
214 if (!write_dir_buffer (trav_info))
218 trav_info->current_entry = 0;
219 if (is_last_buffer (trav_info)) {
223 if (!read_next_dir_buffer (trav_info))
226 return trav_info->dir_entries + trav_info->current_entry;
230 fat_dir_entry_get_first_cluster (FatDirEntry* dir_entry, PedFileSystem *fs)
232 FatSpecific* fs_info = FAT_SPECIFIC (fs);
234 switch (fs_info->fat_type) {
237 return PED_LE16_TO_CPU (dir_entry->first_cluster);
240 return PED_LE16_TO_CPU (dir_entry->first_cluster_high)
242 + PED_LE16_TO_CPU (dir_entry->first_cluster);
249 fat_dir_entry_set_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs,
252 FatSpecific* fs_info = FAT_SPECIFIC (fs);
254 switch (fs_info->fat_type) {
256 PED_ASSERT (0, (void) 0);
260 dir_entry->first_cluster = PED_CPU_TO_LE16 (cluster);
264 dir_entry->first_cluster
265 = PED_CPU_TO_LE16 (cluster & 0xffff);
266 dir_entry->first_cluster_high
267 = PED_CPU_TO_LE16 (cluster / 0x10000);
273 fat_dir_entry_get_length (FatDirEntry* dir_entry)
275 return PED_LE32_TO_CPU (dir_entry->length);
279 fat_dir_entry_is_null_term (const FatDirEntry* dir_entry)
281 FatDirEntry null_entry;
283 memset (&null_entry, 0, sizeof (null_entry));
284 return memcmp (&null_entry, dir_entry, sizeof (null_entry)) == 0;
288 fat_dir_entry_is_active (FatDirEntry* dir_entry)
290 if ((unsigned char) dir_entry->name[0] == DELETED_FLAG) return 0;
291 if ((unsigned char) dir_entry->name[0] == 0) return 0;
292 if ((unsigned char) dir_entry->name[0] == 0xF6) return 0;
297 fat_dir_entry_is_file (FatDirEntry* dir_entry) {
298 if (dir_entry->attributes == VFAT_ATTR) return 0;
299 if (dir_entry->attributes & VOLUME_LABEL_ATTR) return 0;
300 if (!fat_dir_entry_is_active (dir_entry)) return 0;
301 if ((dir_entry->attributes & DIRECTORY_ATTR) == DIRECTORY_ATTR) return 0;
306 fat_dir_entry_is_system_file (FatDirEntry* dir_entry)
308 if (!fat_dir_entry_is_file (dir_entry)) return 0;
309 return (dir_entry->attributes & SYSTEM_ATTR)
310 || (dir_entry->attributes & HIDDEN_ATTR);
314 fat_dir_entry_is_directory (FatDirEntry* dir_entry)
316 if (dir_entry->attributes == VFAT_ATTR) return 0;
317 if (dir_entry->attributes & VOLUME_LABEL_ATTR) return 0;
318 if (!fat_dir_entry_is_active (dir_entry)) return 0;
319 return (dir_entry->attributes & DIRECTORY_ATTR) == DIRECTORY_ATTR;
323 fat_dir_entry_has_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs)
325 FatSpecific* fs_info = FAT_SPECIFIC (fs);
326 FatCluster first_cluster;
328 if (!fat_dir_entry_is_file (dir_entry)
329 && !fat_dir_entry_is_directory (dir_entry))
332 first_cluster = fat_dir_entry_get_first_cluster (dir_entry, fs);
333 if (first_cluster == 0
334 || fat_table_is_eof (fs_info->fat, first_cluster))
341 decrypts silly DOS names to FILENAME.EXT
344 fat_dir_entry_get_name (const FatDirEntry *dir_entry, char *result) {
349 src = dir_entry->name;
351 for (i=0; i < sizeof dir_entry->name; i++) {
352 if (src[i] == ' ' || src[i] == 0) break;
356 ext = (const char *) dir_entry->extension;
357 if (ext[0] != ' ' && ext[0] != 0) {
359 for (i=0; i < sizeof dir_entry->extension; i++) {
360 if (ext[i] == ' ' || ext[i] == 0) break;
368 #endif /* !DISCOVER_ONLY */