5 * Truncate handling routines for the OSTA-UDF(tm) filesystem.
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
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.
18 * (C) 1999-2001 Ben Fennema
19 * (C) 1999 Stelias Computing Inc
23 * 02/24/99 blf Created.
30 #include <linux/udf_fs.h>
35 static void extent_trunc(struct inode * inode, lb_addr bloc, int extoffset,
36 lb_addr eloc, int8_t etype, uint32_t elen, struct buffer_head *bh, uint32_t nelen)
38 lb_addr neloc = { 0, 0 };
39 int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
40 int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
44 if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
46 udf_free_blocks(inode->i_sb, inode, eloc, 0, last_block);
47 etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
51 nelen = (etype << 30) | nelen;
56 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
57 if (last_block - first_block > 0)
59 if (etype == (EXT_RECORDED_ALLOCATED >> 30))
60 mark_inode_dirty(inode);
62 if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
63 udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block);
68 void udf_truncate_extents(struct inode * inode)
70 lb_addr bloc, eloc, neloc = { 0, 0 };
71 uint32_t extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
73 int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits;
74 struct buffer_head *bh = NULL;
77 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
78 adsize = sizeof(short_ad);
79 else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
80 adsize = sizeof(long_ad);
84 etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
85 offset += (inode->i_size & (inode->i_sb->s_blocksize - 1));
89 extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset);
95 lenalloc = extoffset - adsize;
97 if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
98 lenalloc -= udf_file_entry_alloc_offset(inode);
100 lenalloc -= sizeof(struct allocExtDesc);
102 while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1)
104 if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
106 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
110 if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
111 memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
113 memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
114 udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
118 if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
120 UDF_I_LENALLOC(inode) = lenalloc;
121 mark_inode_dirty(inode);
125 struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
126 aed->lengthAllocDescs = cpu_to_le32(lenalloc);
127 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
128 udf_update_tag(bh->b_data, lenalloc +
129 sizeof(struct allocExtDesc));
131 udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
132 mark_buffer_dirty_inode(bh, inode);
136 udf_release_data(bh);
141 lelen = (elen + inode->i_sb->s_blocksize - 1) >>
142 inode->i_sb->s_blocksize_bits;
148 extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
155 if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
156 memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
158 memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
159 udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
163 if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
165 UDF_I_LENALLOC(inode) = lenalloc;
166 mark_inode_dirty(inode);
170 struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
171 aed->lengthAllocDescs = cpu_to_le32(lenalloc);
172 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
173 udf_update_tag(bh->b_data, lenalloc +
174 sizeof(struct allocExtDesc));
176 udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
177 mark_buffer_dirty_inode(bh, inode);
181 else if (inode->i_size)
186 * OK, there is not extent covering inode->i_size and
187 * no extent above inode->i_size => truncate is
188 * extending the file by 'offset'.
190 if ((!bh && extoffset == udf_file_entry_alloc_offset(inode)) ||
191 (bh && extoffset == sizeof(struct allocExtDesc))) {
192 /* File has no extents at all! */
193 memset(&eloc, 0x00, sizeof(lb_addr));
194 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
195 udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
199 etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
200 if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
203 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
204 udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
206 else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
208 lb_addr neloc = { 0, 0 };
210 nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
211 ((elen + offset + inode->i_sb->s_blocksize - 1) &
212 ~(inode->i_sb->s_blocksize - 1));
213 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
214 udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
218 if (elen & (inode->i_sb->s_blocksize - 1))
221 elen = EXT_RECORDED_ALLOCATED |
222 ((elen + inode->i_sb->s_blocksize - 1) &
223 ~(inode->i_sb->s_blocksize - 1));
224 udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
226 memset(&eloc, 0x00, sizeof(lb_addr));
227 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
228 udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
233 UDF_I_LENEXTENTS(inode) = inode->i_size;
235 udf_release_data(bh);