1 /*
2  * partition.c
3  *
4  * PURPOSE
5  *      Partition handling routines for the OSTA-UDF(tm) filesystem.
6  *
7  * CONTACTS
8  *      E-mail regarding any portion of the Linux UDF file system should be
9  *      directed to the development team mailing list (run by majordomo):
10  *              linux_udf@hpesjro.fc.hp.com
11  *
12  * COPYRIGHT
13  *      This file is distributed under the terms of the GNU General Public
14  *      License (GPL). Copies of the GPL can be obtained from:
15  *              ftp://prep.ai.mit.edu/pub/gnu/GPL
16  *      Each contributing author retains all rights to their own work.
17  *
18  *  (C) 1998-2001 Ben Fennema
19  *
20  * HISTORY
21  *
22  * 12/06/98 blf  Created file.
23  *
24  */
25 
26 #include "udfdecl.h"
27 #include "udf_sb.h"
28 #include "udf_i.h"
29 
30 #include <linux/fs.h>
31 #include <linux/string.h>
32 #include <linux/udf_fs.h>
33 #include <linux/slab.h>
34 
udf_get_pblock(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)35 inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
36 {
37 	if (partition >= UDF_SB_NUMPARTS(sb))
38 	{
39 		udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
40 			block, partition, offset);
41 		return 0xFFFFFFFF;
42 	}
43 	if (UDF_SB_PARTFUNC(sb, partition))
44 		return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
45 	else
46 		return UDF_SB_PARTROOT(sb, partition) + block + offset;
47 }
48 
udf_get_pblock_virt15(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)49 uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
50 {
51 	struct buffer_head *bh = NULL;
52 	uint32_t newblock;
53 	uint32_t index;
54 	uint32_t loc;
55 
56 	index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
57 
58 	if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
59 	{
60 		udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
61 			block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
62 		return 0xFFFFFFFF;
63 	}
64 
65 	if (block >= index)
66 	{
67 		block -= index;
68 		newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
69 		index = block % (sb->s_blocksize / sizeof(uint32_t));
70 	}
71 	else
72 	{
73 		newblock = 0;
74 		index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
75 	}
76 
77 	loc = udf_block_map(UDF_SB_VAT(sb), newblock);
78 
79 	if (!(bh = sb_bread(sb, loc)))
80 	{
81 		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
82 			sb, block, partition, loc, index);
83 		return 0xFFFFFFFF;
84 	}
85 
86 	loc = le32_to_cpu(((uint32_t *)bh->b_data)[index]);
87 
88 	udf_release_data(bh);
89 
90 	if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
91 	{
92 		udf_debug("recursive call to udf_get_pblock!\n");
93 		return 0xFFFFFFFF;
94 	}
95 
96 	return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
97 }
98 
udf_get_pblock_virt20(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)99 inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
100 {
101 	return udf_get_pblock_virt15(sb, block, partition, offset);
102 }
103 
udf_get_pblock_spar15(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)104 uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
105 {
106 	int i;
107 	struct sparingTable *st = NULL;
108 	uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
109 
110 	for (i=0; i<4; i++)
111 	{
112 		if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
113 		{
114 			st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
115 			break;
116 		}
117 	}
118 
119 	if (st)
120 	{
121 		for (i=0; i<st->reallocationTableLen; i++)
122 		{
123 			if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
124 				break;
125 			else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
126 			{
127 				return le32_to_cpu(st->mapEntry[i].mappedLocation) +
128 					((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
129 			}
130 			else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
131 				break;
132 		}
133 	}
134 	return UDF_SB_PARTROOT(sb,partition) + block + offset;
135 }
136 
udf_relocate_blocks(struct super_block * sb,long old_block,long * new_block)137 int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
138 {
139 	struct udf_sparing_data *sdata;
140 	struct sparingTable *st = NULL;
141 	struct sparingEntry mapEntry;
142 	uint32_t packet;
143 	int i, j, k, l;
144 
145 	for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
146 	{
147 		if (old_block > UDF_SB_PARTROOT(sb,i) &&
148 		    old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
149 		{
150 			sdata = &UDF_SB_TYPESPAR(sb,i);
151 			packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
152 
153 			for (j=0; j<4; j++)
154 			{
155 				if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
156 				{
157 					st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
158 					break;
159 				}
160 			}
161 
162 			if (!st)
163 				return 1;
164 
165 			for (k=0; k<st->reallocationTableLen; k++)
166 			{
167 				if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
168 				{
169 					for (; j<4; j++)
170 					{
171 						if (sdata->s_spar_map[j])
172 						{
173 							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
174 							st->mapEntry[k].origLocation = cpu_to_le32(packet);
175 							udf_update_tag((char *)st, sizeof(struct sparingTable) + st->reallocationTableLen * sizeof(struct sparingEntry));
176 							mark_buffer_dirty(sdata->s_spar_map[j]);
177 						}
178 					}
179 					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
180 						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
181 					return 0;
182 				}
183 				else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
184 				{
185 					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
186 						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
187 					return 0;
188 				}
189 				else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
190 					break;
191 			}
192 			for (l=k; l<st->reallocationTableLen; l++)
193 			{
194 				if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
195 				{
196 					for (; j<4; j++)
197 					{
198 						if (sdata->s_spar_map[j])
199 						{
200 							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
201 							mapEntry = st->mapEntry[l];
202 							mapEntry.origLocation = cpu_to_le32(packet);
203 							memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry));
204 							st->mapEntry[k] = mapEntry;
205 							udf_update_tag((char *)st, sizeof(struct sparingTable) + st->reallocationTableLen * sizeof(struct sparingEntry));
206 							mark_buffer_dirty(sdata->s_spar_map[j]);
207 						}
208 					}
209 					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
210 						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
211 					return 0;
212 				}
213 			}
214 			return 1;
215 		}
216 	}
217 	if (i == UDF_SB_NUMPARTS(sb))
218 	{
219 		/* outside of partitions */
220 		/* for now, fail =) */
221 		return 1;
222 	}
223 
224 	return 0;
225 }
226