patch-2.4.10 linux/fs/ntfs/attr.c
Next file: linux/fs/ntfs/attr.h
Previous file: linux/fs/ntfs/Makefile
Back to the patch index
Back to the overall index
- Lines: 523
- Date:
Sat Sep 8 12:24:40 2001
- Orig file:
v2.4.9/linux/fs/ntfs/attr.c
- Orig date:
Mon Aug 27 12:41:46 2001
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/attr.c linux/fs/ntfs/attr.c
@@ -13,6 +13,7 @@
#include "attr.h"
#include <linux/errno.h>
+#include <linux/ntfs_fs.h>
#include "macros.h"
#include "support.h"
#include "util.h"
@@ -148,7 +149,10 @@
"attribute non-resident. Bug!\n");
return -EINVAL;
}
- m = memcmp(value, a->d.data, min(int, value_len, a->size));
+ m = value_len;
+ if (m > a->size)
+ m = a->size;
+ m = memcmp(value, a->d.data, m);
if (m > 0)
continue;
if (m < 0) {
@@ -234,7 +238,7 @@
}
if (attr->d.r.runlist) {
ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
- * sizeof(ntfs_runlist));
+ * sizeof(ntfs_runlist));
ntfs_vfree(attr->d.r.runlist);
}
attr->d.r.runlist = new;
@@ -243,82 +247,97 @@
ntfs_memmove(attr->d.r.runlist + cnum + 1,
attr->d.r.runlist + cnum,
(attr->d.r.len - cnum) * sizeof(ntfs_runlist));
- attr->d.r.runlist[cnum].cluster = cluster;
+ attr->d.r.runlist[cnum].lcn = cluster;
attr->d.r.runlist[cnum].len = len;
attr->d.r.len++;
return 0;
}
-/* Extends an attribute. Another run will be added if necessary, but we try to
- * extend the last run in the runlist first.
- * FIXME: what if there isn't enough contiguous space, we don't create
- * multiple runs?
+/**
+ * ntfs_extend_attr - extend allocated size of an attribute
+ * @ino: ntfs inode containing the attribute to extend
+ * @attr: attribute which to extend
+ * @len: desired new length for @attr (_not_ the amount to extend by)
+ *
+ * Extends an attribute. Allocate clusters on the volume which @ino belongs to.
+ * Extends the run list accordingly, preferably by extending the last run of
+ * the existing run list, first.
*
- * *len: the desired new length of the attr (_not_ the amount to extend by)
+ * Only modifies attr->allocated, i.e. doesn't touch attr->size, nor
+ * attr->initialized.
*/
-int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 *len, int flags)
+int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, const __s64 len)
{
- int error = 0;
- ntfs_runlist *rl;
- int rlen;
- ntfs_cluster_t cluster;
- int clen;
+ int rlen, rl2_len, err = 0;
+ ntfs_cluster_t cluster, clen;
+ ntfs_runlist *rl, *rl2;
- if (attr->compressed || ino->record_count > 1)
+ if ((attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)) ||
+ ino->record_count > 1)
return -EOPNOTSUPP;
+ /*
+ * FIXME: Don't make non-resident if the attribute type is not right.
+ * For example cannot make index attribute non-resident! (AIA)
+ */
if (attr->resident) {
- error = ntfs_make_attr_nonresident(ino, attr);
- if (error)
- return error;
+ err = ntfs_make_attr_nonresident(ino, attr);
+ if (err)
+ return err;
}
- if (*len <= attr->allocated)
- return 0; /* Truely stupid things do sometimes happen. */
+ if (len <= attr->allocated)
+ return 0; /* Truly stupid things do sometimes happen. */
rl = attr->d.r.runlist;
- rlen = attr->d.r.len - 1;
- if (rlen >= 0)
- cluster = rl[rlen].cluster + rl[rlen].len;
+ rlen = attr->d.r.len;
+ if (rlen > 0)
+ cluster = rl[rlen - 1].lcn + rl[rlen - 1].len;
else
/* No preference for allocation space. */
- cluster = 0;
- /* Calculate the extra space we need, and round up to multiple of
- * cluster size to get number of new clusters needed */
- clen = ((*len - attr->allocated) + ino->vol->cluster_size - 1) >>
- ino->vol->cluster_size_bits;
- if (clen == 0)
+ cluster = (ntfs_cluster_t)-1;
+ /*
+ * Calculate the extra space we need, and round up to multiple of
+ * cluster size to get number of new clusters needed.
+ */
+ clen = (len - attr->allocated + ino->vol->cluster_size - 1) >>
+ ino->vol->cluster_size_bits;
+ if (!clen)
return 0;
- /* FIXME: try to allocate smaller pieces */
- error = ntfs_allocate_clusters(ino->vol, &cluster, &clen,
- flags | ALLOC_REQUIRE_SIZE);
- if (error)
- return error;
+ err = ntfs_allocate_clusters(ino->vol, &cluster, &clen, &rl2,
+ &rl2_len, DATA_ZONE);
+ if (err)
+ return err;
attr->allocated += (__s64)clen << ino->vol->cluster_size_bits;
- *len = attr->allocated;
- /* Contiguous chunk. */
- if (rlen >= 0 && cluster == rl[rlen].cluster + rl[rlen].len) {
- rl[rlen].len += clen;
- return 0;
+ if (rlen > 0) {
+ err = splice_runlists(&rl, &rlen, rl2, rl2_len);
+ ntfs_vfree(rl2);
+ if (err)
+ return err;
+ } else {
+ if (rl)
+ ntfs_vfree(rl);
+ rl = rl2;
+ rlen = rl2_len;
}
- /*
- * FIXME: if ntfs_insert_run fails we need to deallocate the cluster
- * to revert to state before we were called...
- */
- ntfs_insert_run(attr, rlen + 1, cluster, clen);
+ attr->d.r.runlist = rl;
+ attr->d.r.len = rlen;
return 0;
}
int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
{
- void *data = attr->d.data;
- __s64 len = attr->size;
int error;
- __s64 alen;
ntfs_io io;
+ void *data = attr->d.data;
+ __s64 len = attr->size;
+
attr->d.r.len = 0;
- attr->d.r.runlist = 0;
+ attr->d.r.runlist = NULL;
attr->resident = 0;
+ /*
+ * ->allocated is updated by ntfs_extend_attr(), while ->initialized
+ * and ->size are updated by ntfs_readwrite_attr(). (AIA)
+ */
attr->allocated = attr->initialized = 0;
- alen = len;
- error = ntfs_extend_attr(ino, attr, &alen, ALLOC_REQUIRE_SIZE);
+ error = ntfs_extend_attr(ino, attr, len);
if (error)
return error; /* FIXME: On error, restore old values. */
io.fn_put = ntfs_put;
@@ -344,21 +363,22 @@
return error;
}
-/* Resize the attribute to a newsize. */
+/*
+ * Resize the attribute to a newsize. attr->allocated and attr->size are
+ * updated, but attr->initialized is not changed unless it becomes bigger than
+ * attr->size, in which case it is set to attr->size.
+ */
int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize)
{
int error = 0;
__s64 oldsize = attr->size;
int clustersizebits = ino->vol->cluster_size_bits;
int i, count, newcount;
- ntfs_runlist *rl;
- __s64 newlen;
+ ntfs_runlist *rl, *rlt;
if (newsize == oldsize)
return 0;
- /* FIXME: Modifying compressed attributes not supported yet. */
- if (attr->compressed)
- /* FIXME: Extending is easy: just insert sparse runs. */
+ if (attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED))
return -EOPNOTSUPP;
if (attr->resident) {
void *v;
@@ -370,16 +390,18 @@
}
v = attr->d.data;
if (newsize) {
+ __s64 minsize = newsize;
attr->d.data = ntfs_malloc(newsize);
if (!attr->d.data) {
ntfs_free(v);
return -ENOMEM;
}
- if (newsize > oldsize)
+ if (newsize > oldsize) {
+ minsize = oldsize;
ntfs_bzero((char*)attr->d.data + oldsize,
newsize - oldsize);
- ntfs_memcpy((char*)attr->d.data, v,
- min(s64, newsize, oldsize));
+ }
+ ntfs_memcpy((char*)attr->d.data, v, minsize);
} else
attr->d.data = 0;
ntfs_free(v);
@@ -389,59 +411,79 @@
/* Non-resident attribute. */
rl = attr->d.r.runlist;
if (newsize < oldsize) {
+ int rl_size;
+ /*
+ * FIXME: We might be going awfully wrong for newsize = 0,
+ * possibly even leaking memory really badly. But considering
+ * in that case there is more breakage due to -EOPNOTSUPP stuff
+ * further down the code path, who cares for the moment... (AIA)
+ */
for (i = 0, count = 0; i < attr->d.r.len; i++) {
if ((__s64)(count + rl[i].len) << clustersizebits >
- newsize)
+ newsize) {
+ i++;
break;
+ }
count += (int)rl[i].len;
}
- newlen = i + 1;
- /* Free unused clusters in current run, unless sparse. */
newcount = count;
- if (rl[i].cluster != (ntfs_cluster_t)-1) {
- int rounded = newsize - ((__s64)count <<
- clustersizebits);
+ /* Free unused clusters in current run, unless sparse. */
+ if (rl[--i].lcn != (ntfs_cluster_t)-1) {
+ ntfs_cluster_t rounded = newsize - ((__s64)count <<
+ clustersizebits);
rounded = (rounded + ino->vol->cluster_size - 1) >>
- clustersizebits;
- error = ntfs_deallocate_clusters(ino->vol,
- rl[i].cluster + rounded,
- (int)rl[i].len - rounded);
+ clustersizebits;
+ error = ntfs_deallocate_cluster_run(ino->vol,
+ rl[i].lcn + rounded,
+ rl[i].len - rounded);
if (error)
return error; /* FIXME: Incomplete operation. */
rl[i].len = rounded;
newcount = count + rounded;
}
/* Free all other runs. */
- for (i++; i < attr->d.r.len; i++)
- if (rl[i].cluster != (ntfs_cluster_t)-1) {
- error = ntfs_deallocate_clusters(ino->vol,
- rl[i].cluster,
- (int)rl[i].len);
- if (error)
- return error; /* FIXME: Incomplete
- * operation */
+ i++;
+ error = ntfs_deallocate_clusters(ino->vol, rl + i,
+ attr->d.r.len - i);
+ if (error)
+ return error; /* FIXME: Incomplete operation. */
+ /*
+ * Free space for extra runs in memory if enough memory left
+ * to do so. FIXME: Only do it if it would free memory. (AIA)
+ */
+ rl_size = ((i + 1) * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
+ PAGE_MASK;
+ if (rl_size < ((attr->d.r.len * sizeof(ntfs_runlist) +
+ PAGE_SIZE - 1) & PAGE_MASK)) {
+ rlt = ntfs_vmalloc(rl_size);
+ if (rlt) {
+ ntfs_memcpy(rlt, rl, i * sizeof(ntfs_runlist));
+ ntfs_vfree(rl);
+ attr->d.r.runlist = rl = rlt;
}
- /* FIXME: Free space for extra runs in memory? */
- attr->d.r.len = newlen;
+ }
+ rl[i].lcn = (ntfs_cluster_t)-1;
+ rl[i].len = (ntfs_cluster_t)0;
+ attr->d.r.len = i;
} else {
- newlen = newsize;
- error = ntfs_extend_attr(ino, attr, &newlen,
- ALLOC_REQUIRE_SIZE);
+ error = ntfs_extend_attr(ino, attr, newsize);
if (error)
return error; /* FIXME: Incomplete operation. */
- newcount = newlen >> clustersizebits;
+ newcount = (newsize + ino->vol->cluster_size - 1) >>
+ clustersizebits;
}
/* Fill in new sizes. */
attr->allocated = (__s64)newcount << clustersizebits;
attr->size = newsize;
- /* attr->initialized does not change. */
+ if (attr->initialized > newsize)
+ attr->initialized = newsize;
if (!newsize)
error = ntfs_make_attr_resident(ino, attr);
return error;
}
int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
- int dsize, ntfs_attribute **rattr)
+ int dsize, ntfs_attribute **rattr)
{
void *name;
int namelen;
@@ -463,7 +505,7 @@
namelen = 0;
}
error = ntfs_new_attr(ino, anum, name, namelen, data, dsize, &i,
- &found);
+ &found);
if (error || found) {
ntfs_free(name);
return error ? error : -EEXIST;
@@ -481,7 +523,8 @@
"+ 0x28) (%i)\n", attr->attrno,
NTFS_GETU16(ino->attr + 0x28));
attr->resident = 1;
- attr->compressed = attr->cengine = 0;
+ attr->flags = 0;
+ attr->cengine = 0;
attr->size = attr->allocated = attr->initialized = dsize;
/* FIXME: INDEXED information should come from $AttrDef
@@ -498,7 +541,8 @@
return 0;
}
-/* Non-resident attributes are stored in runs (intervals of clusters).
+/*
+ * Non-resident attributes are stored in runs (intervals of clusters).
*
* This function stores in the inode readable information about a non-resident
* attribute.
@@ -520,7 +564,7 @@
* base mft record contains the last extent instead of the first one
* and the first extent is stored, like any intermediate extents in
* extension mft records. This would be difficult to allow the way the
- * run list is stored in memory. Thus we fix else where by causing the
+ * runlist is stored in memory. Thus we fix elsewhere by causing the
* attribute list attribute to be processed immediately when found. The
* extents will then be processed starting with the first one. */
for (cnum = 0, vcn = 0; cnum < attr->d.r.len; cnum++)
@@ -534,7 +578,7 @@
ntfs_error("Problem with runlist in extended record\n");
return -1;
}
- /* Tried to insert an already inserted run list. */
+ /* Tried to insert an already inserted runlist. */
return 0;
}
if (!endvcn) {
@@ -630,7 +674,7 @@
}
attr = ino->attrs + i;
attr->resident = NTFS_GETU8(attrdata + 8) == 0;
- attr->compressed = NTFS_GETU16(attrdata + 0xC);
+ attr->flags = *(__u16*)(attrdata + 0xC);
attr->attrno = NTFS_GETU16(attrdata + 0xE);
if (attr->resident) {
@@ -640,13 +684,13 @@
if (!attr->d.data)
return -ENOMEM;
ntfs_memcpy(attr->d.data, data, attr->size);
- attr->indexed = NTFS_GETU16(attrdata + 0x16);
+ attr->indexed = NTFS_GETU8(attrdata + 0x16);
} else {
attr->allocated = NTFS_GETS64(attrdata + 0x28);
attr->size = NTFS_GETS64(attrdata + 0x30);
attr->initialized = NTFS_GETS64(attrdata + 0x38);
attr->cengine = NTFS_GETU16(attrdata + 0x22);
- if (attr->compressed)
+ if (attr->flags & ATTR_IS_COMPRESSED)
attr->compsize = NTFS_GETS64(attrdata + 0x40);
ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: "
"attr->allocated = 0x%Lx, attr->size = 0x%Lx, "
@@ -664,11 +708,14 @@
int ntfs_read_zero(ntfs_io *dest, int size)
{
+ int i;
char *sparse = ntfs_calloc(512);
if (!sparse)
return -ENOMEM;
+ i = 512;
while (size) {
- int i = min(int, size, 512);
+ if (i > size)
+ i = size;
dest->fn_put(dest, sparse, i);
size -= i;
}
@@ -683,7 +730,7 @@
int error = 0;
int clustersizebits;
int s_vcn, rnum, vcn, got, l1;
- __s64 copied, len, chunk, offs1, l;
+ __s64 copied, len, chunk, offs1, l, chunk2;
ntfs_cluster_t cluster, cl1;
char *comp = 0, *comp1;
char *decomp = 0;
@@ -713,19 +760,22 @@
io.do_read = 1;
io.fn_put = ntfs_put;
io.fn_get = 0;
- cluster = rl->cluster;
+ cluster = rl->lcn;
len = rl->len;
copied = 0;
while (l) {
chunk = 0;
if (cluster == (ntfs_cluster_t)-1) {
/* Sparse cluster. */
- __s64 l1;
+ __s64 ll;
+
if ((len - (s_vcn - vcn)) & 15)
ntfs_error("Unexpected sparse chunk size.");
- l1 = chunk = min(s64, ((__s64)(vcn + len) << clustersizebits)
- - offset, l);
- error = ntfs_read_zero(dest, l1);
+ ll = ((__s64)(vcn + len) << clustersizebits) - offset;
+ if (ll > l)
+ ll = l;
+ chunk = ll;
+ error = ntfs_read_zero(dest, ll);
if (error)
goto out;
} else if (dest->do_read) {
@@ -741,18 +791,25 @@
cl1 = cluster + s_vcn - vcn;
comp1 = comp;
do {
+ int delta;
+
io.param = comp1;
- l1 = min(int, len - max(int, s_vcn - vcn, 0), 16 - got);
+ delta = s_vcn - vcn;
+ if (delta < 0)
+ delta = 0;
+ l1 = len - delta;
+ if (l1 > 16 - got)
+ l1 = 16 - got;
io.size = (__s64)l1 << clustersizebits;
error = ntfs_getput_clusters(ino->vol, cl1, 0,
&io);
if (error)
goto out;
- if (l1 + max(int, s_vcn - vcn, 0) == len) {
+ if (l1 + delta == len) {
rnum++;
rl++;
vcn += len;
- cluster = cl1 = rl->cluster;
+ cluster = cl1 = rl->lcn;
len = rl->len;
}
got += l1;
@@ -779,8 +836,11 @@
comp1 = decomp;
}
offs1 = offset - ((__s64)s_vcn << clustersizebits);
- chunk = min(s64, (16 << clustersizebits) - offs1, chunk);
- chunk = min(s64, l, chunk);
+ chunk2 = (16 << clustersizebits) - offs1;
+ if (chunk2 > l)
+ chunk2 = l;
+ if (chunk > chunk2)
+ chunk = chunk2;
dest->fn_put(dest, comp1 + offs1, chunk);
}
l -= chunk;
@@ -791,11 +851,11 @@
rnum++;
rl++;
vcn += len;
- cluster = rl->cluster;
+ cluster = rl->lcn;
len = rl->len;
}
}
- out:
+out:
if (comp)
ntfs_free(comp);
if (decomp)
@@ -805,7 +865,7 @@
}
int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
- ntfs_io *dest)
+ ntfs_io *dest)
{
return -EOPNOTSUPP;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)