File: /usr/src/linux/fs/udf/truncate.c

1     /*
2      * truncate.c
3      *
4      * PURPOSE
5      *	Truncate 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) 1999-2000 Ben Fennema
19      *  (C) 1999 Stelias Computing Inc
20      *
21      * HISTORY
22      *
23      *  02/24/99 blf  Created.
24      *
25      */
26     
27     #include "udfdecl.h"
28     #include <linux/fs.h>
29     #include <linux/mm.h>
30     #include <linux/udf_fs.h>
31     
32     #include "udf_i.h"
33     #include "udf_sb.h"
34     
35     static void extent_trunc(struct inode * inode, lb_addr bloc, int extoffset,
36     	lb_addr eloc, Uint8 etype, Uint32 elen, struct buffer_head *bh, Uint32 nelen)
37     {
38     	lb_addr neloc = { 0, 0 };
39     	int blocks = inode->i_sb->s_blocksize / 512;
40     	int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
41     	int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
42     
43     	if (nelen)
44     	{
45     		neloc = eloc;
46     		nelen = (etype << 30) | nelen;
47     	}
48     
49     	if (elen != nelen)
50     	{
51     		udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
52     		if (last_block - first_block > 0)
53     		{
54     			if (etype == EXTENT_RECORDED_ALLOCATED)
55     			{
56     				inode->i_blocks -= (blocks * (last_block - first_block));
57     				mark_inode_dirty(inode);
58     			}
59     			if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED)
60     				udf_free_blocks(inode, eloc, first_block, last_block - first_block);
61     		}
62     	}
63     }
64     
65     void udf_truncate_extents(struct inode * inode)
66     {
67     	lb_addr bloc, eloc, neloc = { 0, 0 };
68     	Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
69     	int etype;
70     	int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits;
71     	struct buffer_head *bh = NULL;
72     	int adsize;
73     
74     	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
75     		adsize = sizeof(short_ad);
76     	else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
77     		adsize = sizeof(long_ad);
78     	else
79     		adsize = 0;
80     
81     	etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
82     	offset += (inode->i_size & (inode->i_sb->s_blocksize - 1));
83     	if (etype != -1)
84     	{
85     		extoffset -= adsize;
86     		extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset);
87     		extoffset += adsize;
88     
89     		if (offset)
90     			lenalloc = extoffset;
91     		else
92     			lenalloc = extoffset - adsize;
93     
94     		if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
95     			lenalloc -= udf_file_entry_alloc_offset(inode);
96     		else
97     			lenalloc -= sizeof(struct AllocExtDesc);
98     
99     		while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1)
100     		{
101     			if (etype == EXTENT_NEXT_EXTENT_ALLOCDECS)
102     			{
103     				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
104     				extoffset = 0;
105     				if (lelen)
106     				{
107     					if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
108     						memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
109     					else
110     						memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc));
111     					udf_free_blocks(inode, bloc, 0, lelen);
112     				}
113     				else
114     				{
115     					if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
116     					{
117     						UDF_I_LENALLOC(inode) = lenalloc;
118     						mark_inode_dirty(inode);
119     					}
120     					else
121     					{
122     						struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data);
123     						aed->lengthAllocDescs = cpu_to_le32(lenalloc);
124     						if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
125     							udf_update_tag(bh->b_data, lenalloc +
126     								sizeof(struct AllocExtDesc));
127     						else
128     							udf_update_tag(bh->b_data, sizeof(struct AllocExtDesc));
129     						mark_buffer_dirty_inode(bh, inode);
130     					}
131     				}
132     
133     				udf_release_data(bh);
134     				bh = NULL;
135     
136     				bloc = eloc;
137     				if (elen)
138     					lelen = (elen + inode->i_sb->s_blocksize - 1) >>
139     						inode->i_sb->s_blocksize_bits;
140     				else
141     					lelen = 1;
142     			}
143     			else
144     			{
145     				extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
146     				extoffset += adsize;
147     			}
148     		}
149     
150     		if (lelen)
151     		{
152     			if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
153     				memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
154     			else
155     				memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc));
156     			udf_free_blocks(inode, bloc, 0, lelen);
157     		}
158     		else
159     		{
160     			if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
161     			{
162     				UDF_I_LENALLOC(inode) = lenalloc;
163     				mark_inode_dirty(inode);
164     			}
165     			else
166     			{
167     				struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data);
168     				aed->lengthAllocDescs = cpu_to_le32(lenalloc);
169     				if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
170     					udf_update_tag(bh->b_data, lenalloc +
171     						sizeof(struct AllocExtDesc));
172     				else
173     					udf_update_tag(bh->b_data, sizeof(struct AllocExtDesc));
174     				mark_buffer_dirty_inode(bh, inode);
175     			}
176     		}
177     	}
178     	else if (inode->i_size)
179     	{
180     		if (offset)
181     		{
182     			extoffset -= adsize;
183     			etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
184     			if (etype == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
185     			{
186     				extoffset -= adsize;
187     				elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) | (elen + offset);
188     				udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
189     			}
190     			else if (etype == EXTENT_NOT_RECORDED_ALLOCATED)
191     			{
192     				lb_addr neloc = { 0, 0 };
193     				extoffset -= adsize;
194     				nelen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
195     					((elen + offset + inode->i_sb->s_blocksize - 1) &
196     					~(inode->i_sb->s_blocksize - 1));
197     				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
198     				udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
199     			}
200     			else
201     			{
202     				if (elen & (inode->i_sb->s_blocksize - 1))
203     				{
204     					extoffset -= adsize;
205     					elen = (EXTENT_RECORDED_ALLOCATED << 30) |
206     						((elen + inode->i_sb->s_blocksize - 1) &
207     						~(inode->i_sb->s_blocksize - 1));
208     					udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
209     				}
210     				memset(&eloc, 0x00, sizeof(lb_addr));
211     				elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) | offset;
212     				udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
213     			}
214     		}
215     	}
216     	UDF_I_LENEXTENTS(inode) = inode->i_size;
217     
218     	udf_release_data(bh);
219     }
220