summaryrefslogtreecommitdiff
Diffstat
-rwxr-xr-xAUTHORS23
-rwxr-xr-xAndroid.mk89
-rwxr-xr-xAndroid.mk.bak89
-rwxr-xr-xCOPYING340
-rwxr-xr-xCOPYING.LIB482
-rwxr-xr-xCREDITS41
-rwxr-xr-xChangeLog7
-rwxr-xr-xINSTALL237
-rwxr-xr-xMakefile715
-rwxr-xr-xMakefile.am66
-rwxr-xr-xMakefile.in722
-rwxr-xr-xNEWS5
-rwxr-xr-xREADME68
-rwxr-xr-xaclocal.m47723
-rwxr-xr-xautogen.sh22
-rwxr-xr-xcompile142
-rwxr-xr-xconfig.guess1536
-rwxr-xr-xconfig.h361
-rwxr-xr-xconfig.h.in350
-rwxr-xr-xconfig.log3290
-rwxr-xr-xconfig.status1220
-rwxr-xr-xconfig.sub1658
-rwxr-xr-xconfigure25302
-rwxr-xr-xconfigure.ac441
-rwxr-xr-xdepcomp589
-rwxr-xr-xinclude/Makefile.am4
-rwxr-xr-xinclude/Makefile.in503
-rwxr-xr-xinclude/fuse-lite/Makefile.am10
-rwxr-xr-xinclude/fuse-lite/Makefile.in400
-rwxr-xr-xinclude/fuse-lite/fuse.h654
-rwxr-xr-xinclude/fuse-lite/fuse_common.h193
-rwxr-xr-xinclude/fuse-lite/fuse_kernel.h422
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel.h1375
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel_compat.h16
-rwxr-xr-xinclude/fuse-lite/fuse_opt.h261
-rwxr-xr-xinclude/ntfs-3g/Makefile.am45
-rwxr-xr-xinclude/ntfs-3g/Makefile.in471
-rwxr-xr-xinclude/ntfs-3g/acls.h199
-rwxr-xr-xinclude/ntfs-3g/attrib.h358
-rwxr-xr-xinclude/ntfs-3g/attrlist.h51
-rwxr-xr-xinclude/ntfs-3g/bitmap.h96
-rwxr-xr-xinclude/ntfs-3g/bootsect.h42
-rwxr-xr-xinclude/ntfs-3g/cache.h115
-rwxr-xr-xinclude/ntfs-3g/collate.h34
-rwxr-xr-xinclude/ntfs-3g/compat.h69
-rwxr-xr-xinclude/ntfs-3g/compress.h39
-rwxr-xr-xinclude/ntfs-3g/debug.h47
-rwxr-xr-xinclude/ntfs-3g/device.h128
-rwxr-xr-xinclude/ntfs-3g/device_io.h77
-rwxr-xr-xinclude/ntfs-3g/dir.h128
-rwxr-xr-xinclude/ntfs-3g/efs.h30
-rwxr-xr-xinclude/ntfs-3g/endians.h203
-rwxr-xr-xinclude/ntfs-3g/index.h167
-rwxr-xr-xinclude/ntfs-3g/inode.h225
-rwxr-xr-xinclude/ntfs-3g/layout.h2661
-rwxr-xr-xinclude/ntfs-3g/lcnalloc.h50
-rwxr-xr-xinclude/ntfs-3g/logfile.h394
-rwxr-xr-xinclude/ntfs-3g/logging.h118
-rwxr-xr-xinclude/ntfs-3g/mft.h132
-rwxr-xr-xinclude/ntfs-3g/misc.h30
-rwxr-xr-xinclude/ntfs-3g/mst.h34
-rwxr-xr-xinclude/ntfs-3g/ntfstime.h131
-rwxr-xr-xinclude/ntfs-3g/object_id.h35
-rwxr-xr-xinclude/ntfs-3g/param.h63
-rwxr-xr-xinclude/ntfs-3g/reparse.h39
-rwxr-xr-xinclude/ntfs-3g/runlist.h89
-rwxr-xr-xinclude/ntfs-3g/security.h353
-rwxr-xr-xinclude/ntfs-3g/support.h85
-rwxr-xr-xinclude/ntfs-3g/types.h124
-rwxr-xr-xinclude/ntfs-3g/unistr.h116
-rwxr-xr-xinclude/ntfs-3g/volume.h277
-rwxr-xr-xinstall-sh519
-rwxr-xr-xlibfuse-lite/Makefile.am28
-rwxr-xr-xlibfuse-lite/Makefile.in572
-rwxr-xr-xlibfuse-lite/fuse.c2789
-rwxr-xr-xlibfuse-lite/fuse_i.h25
-rwxr-xr-xlibfuse-lite/fuse_kern_chan.c96
-rwxr-xr-xlibfuse-lite/fuse_loop.c40
-rwxr-xr-xlibfuse-lite/fuse_lowlevel.c1395
-rwxr-xr-xlibfuse-lite/fuse_misc.h106
-rwxr-xr-xlibfuse-lite/fuse_opt.c368
-rwxr-xr-xlibfuse-lite/fuse_session.c183
-rwxr-xr-xlibfuse-lite/fuse_signals.c73
-rwxr-xr-xlibfuse-lite/fusermount.c772
-rwxr-xr-xlibfuse-lite/helper.c40
-rwxr-xr-xlibfuse-lite/mount.c256
-rwxr-xr-xlibfuse-lite/mount_util.c219
-rwxr-xr-xlibfuse-lite/mount_util.h22
-rwxr-xr-xlibntfs-3g/Makefile.am79
-rwxr-xr-xlibntfs-3g/Makefile.in841
-rwxr-xr-xlibntfs-3g/acls.c4296
-rwxr-xr-xlibntfs-3g/attrib.c5913
-rwxr-xr-xlibntfs-3g/attrlist.c314
-rwxr-xr-xlibntfs-3g/bitmap.c300
-rwxr-xr-xlibntfs-3g/bootsect.c285
-rwxr-xr-xlibntfs-3g/cache.c609
-rwxr-xr-xlibntfs-3g/collate.c271
-rwxr-xr-xlibntfs-3g/compat.c250
-rwxr-xr-xlibntfs-3g/compress.c1431
-rwxr-xr-xlibntfs-3g/debug.c79
-rwxr-xr-xlibntfs-3g/device.c730
-rwxr-xr-xlibntfs-3g/dir.c2582
-rwxr-xr-xlibntfs-3g/efs.c346
-rwxr-xr-xlibntfs-3g/index.c2063
-rwxr-xr-xlibntfs-3g/inode.c1566
-rwxr-xr-xlibntfs-3g/lcnalloc.c735
-rwxr-xr-xlibntfs-3g/libntfs-3g.pc.in10
-rwxr-xr-xlibntfs-3g/libntfs-3g.script.so.in2
-rwxr-xr-xlibntfs-3g/logfile.c737
-rwxr-xr-xlibntfs-3g/logging.c613
-rwxr-xr-xlibntfs-3g/mft.c1909
-rwxr-xr-xlibntfs-3g/misc.c61
-rwxr-xr-xlibntfs-3g/mst.c231
-rwxr-xr-xlibntfs-3g/object_id.c637
-rwxr-xr-xlibntfs-3g/reparse.c1222
-rwxr-xr-xlibntfs-3g/runlist.c2166
-rwxr-xr-xlibntfs-3g/security.c5167
-rwxr-xr-xlibntfs-3g/unistr.c1321
-rwxr-xr-xlibntfs-3g/unix_io.c386
-rwxr-xr-xlibntfs-3g/volume.c1663
-rwxr-xr-xlibntfs-3g/win32_io.c1477
-rwxr-xr-xlibtool7621
-rwxr-xr-xltmain.sh6956
-rwxr-xr-xm4/.keep0
-rwxr-xr-xmissing367
-rwxr-xr-xprog.IAB1071
-rwxr-xr-xprog.IAD5
-rwxr-xr-xprog.IMB466
-rwxr-xr-xprog.IMD2
-rwxr-xr-xprog.PFI2
-rwxr-xr-xprog.PO1
-rwxr-xr-xprog.PR14
-rwxr-xr-xprog.PRI219
-rwxr-xr-xprog.PS979
-rwxr-xr-xprog.SearchResults3
-rwxr-xr-xprog.WK39
-rwxr-xr-xsrc/lowntfs-3g.c4492
-rwxr-xr-xsrc/ntfs-3g.8.in349
-rwxr-xr-xsrc/ntfs-3g.c4461
-rwxr-xr-xsrc/ntfs-3g.probe.8.in81
-rwxr-xr-xsrc/ntfs-3g.probe.c163
-rwxr-xr-xsrc/ntfs-3g.secaudit.8.in171
-rwxr-xr-xsrc/ntfs-3g.usermap.8.in96
-rwxr-xr-xsrc/secaudit.c7176
-rwxr-xr-xsrc/secaudit.h731
-rwxr-xr-xsrc/test.c88
-rwxr-xr-xsrc/usermap.c1356
-rwxr-xr-xstamp-h11
148 files changed, 141286 insertions, 0 deletions
diff --git a/libntfs-3g/lcnalloc.c b/libntfs-3g/lcnalloc.c
new file mode 100755
index 0000000..9eb907c
--- a/dev/null
+++ b/libntfs-3g/lcnalloc.c
@@ -0,0 +1,735 @@
+/**
+ * lcnalloc.c - Cluster (de)allocation code. Originated from the Linux-NTFS project.
+ *
+ * Copyright (c) 2002-2004 Anton Altaparmakov
+ * Copyright (c) 2004 Yura Pakhuchiy
+ * Copyright (c) 2004-2008 Szabolcs Szakacsits
+ * Copyright (c) 2008-2009 Jean-Pierre Andre
+ *
+ * This program/include file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (in the main directory of the NTFS-3G
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "types.h"
+#include "attrib.h"
+#include "bitmap.h"
+#include "debug.h"
+#include "runlist.h"
+#include "volume.h"
+#include "lcnalloc.h"
+#include "logging.h"
+#include "misc.h"
+
+/*
+ * Plenty possibilities for big optimizations all over in the cluster
+ * allocation, however at the moment the dominant bottleneck (~ 90%) is
+ * the update of the mapping pairs which converges to the cubic Faulhaber's
+ * formula as the function of the number of extents (fragments, runs).
+ */
+#define NTFS_LCNALLOC_BSIZE 4096
+#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
+
+enum {
+ ZONE_MFT = 1,
+ ZONE_DATA1 = 2,
+ ZONE_DATA2 = 4
+} ;
+
+static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc)
+{
+ ntfs_log_trace("pos: %lld tc: %lld\n", (long long)*pos, (long long)tc);
+
+ if (tc >= end)
+ *pos = start;
+ else if (tc >= start)
+ *pos = tc;
+}
+
+static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc)
+{
+ ntfs_log_trace("tc = %lld, zone = %d\n", (long long)tc, zone);
+
+ if (zone == ZONE_MFT)
+ ntfs_cluster_set_zone_pos(vol->mft_lcn, vol->mft_zone_end,
+ &vol->mft_zone_pos, tc);
+ else if (zone == ZONE_DATA1)
+ ntfs_cluster_set_zone_pos(vol->mft_zone_end, vol->nr_clusters,
+ &vol->data1_zone_pos, tc);
+ else /* zone == ZONE_DATA2 */
+ ntfs_cluster_set_zone_pos(0, vol->mft_zone_start,
+ &vol->data2_zone_pos, tc);
+}
+
+/*
+ * Unmark full zones when a cluster has been freed in a full zone
+ *
+ * Next allocation will reuse the freed cluster
+ */
+
+static void update_full_status(ntfs_volume *vol, LCN lcn)
+{
+ if (lcn >= vol->mft_zone_end) {
+ if (vol->full_zones & ZONE_DATA1) {
+ ntfs_cluster_update_zone_pos(vol, ZONE_DATA1, lcn);
+ vol->full_zones &= ~ZONE_DATA1;
+ }
+ } else
+ if (lcn < vol->mft_zone_start) {
+ if (vol->full_zones & ZONE_DATA2) {
+ ntfs_cluster_update_zone_pos(vol, ZONE_DATA2, lcn);
+ vol->full_zones &= ~ZONE_DATA2;
+ }
+ } else {
+ if (vol->full_zones & ZONE_MFT) {
+ ntfs_cluster_update_zone_pos(vol, ZONE_MFT, lcn);
+ vol->full_zones &= ~ZONE_MFT;
+ }
+ }
+}
+
+static s64 max_empty_bit_range(unsigned char *buf, int size)
+{
+ int i, j, run = 0;
+ int max_range = 0;
+ s64 start_pos = -1;
+
+ ntfs_log_trace("Entering\n");
+
+ i = 0;
+ while (i < size) {
+ switch (*buf) {
+ case 0 :
+ do {
+ buf++;
+ run += 8;
+ i++;
+ } while ((i < size) && !*buf);
+ break;
+ case 255 :
+ if (run > max_range) {
+ max_range = run;
+ start_pos = (s64)i * 8 - run;
+ }
+ run = 0;
+ do {
+ buf++;
+ i++;
+ } while ((i < size) && (*buf == 255));
+ break;
+ default :
+ for (j = 0; j < 8; j++) {
+
+ int bit = *buf & (1 << j);
+
+ if (bit) {
+ if (run > max_range) {
+ max_range = run;
+ start_pos = (s64)i * 8 + (j - run);
+ }
+ run = 0;
+ } else
+ run++;
+ }
+ i++;
+ buf++;
+
+ }
+ }
+
+ if (run > max_range)
+ start_pos = (s64)i * 8 - run;
+
+ return start_pos;
+}
+
+static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
+ u8 *writeback)
+{
+ s64 written;
+
+ ntfs_log_trace("Entering\n");
+
+ if (!*writeback)
+ return 0;
+
+ *writeback = 0;
+
+ written = ntfs_attr_pwrite(vol->lcnbmp_na, pos, size, b);
+ if (written != size) {
+ if (!written)
+ errno = EIO;
+ ntfs_log_perror("Bitmap write error (%lld, %lld)",
+ (long long)pos, (long long)size);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * ntfs_cluster_alloc - allocate clusters on an ntfs volume
+ * @vol: mounted ntfs volume on which to allocate the clusters
+ * @start_vcn: vcn to use for the first allocated cluster
+ * @count: number of clusters to allocate
+ * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none)
+ * @zone: zone from which to allocate the clusters
+ *
+ * Allocate @count clusters preferably starting at cluster @start_lcn or at the
+ * current allocator position if @start_lcn is -1, on the mounted ntfs volume
+ * @vol. @zone is either DATA_ZONE for allocation of normal clusters and
+ * MFT_ZONE for allocation of clusters for the master file table, i.e. the
+ * $MFT/$DATA attribute.
+ *
+ * On success return a runlist describing the allocated cluster(s).
+ *
+ * On error return NULL with errno set to the error code.
+ *
+ * Notes on the allocation algorithm
+ * =================================
+ *
+ * There are two data zones. First is the area between the end of the mft zone
+ * and the end of the volume, and second is the area between the start of the
+ * volume and the start of the mft zone. On unmodified/standard NTFS 1.x
+ * volumes, the second data zone doesn't exist due to the mft zone being
+ * expanded to cover the start of the volume in order to reserve space for the
+ * mft bitmap attribute.
+ *
+ * The complexity stems from the need of implementing the mft vs data zoned
+ * approach and from the fact that we have access to the lcn bitmap via up to
+ * NTFS_LCNALLOC_BSIZE bytes at a time, so we need to cope with crossing over
+ * boundaries of two buffers. Further, the fact that the allocator allows for
+ * caller supplied hints as to the location of where allocation should begin
+ * and the fact that the allocator keeps track of where in the data zones the
+ * next natural allocation should occur, contribute to the complexity of the
+ * function. But it should all be worthwhile, because this allocator:
+ * 1) implements MFT zone reservation
+ * 2) causes reduction in fragmentation.
+ * The code is not optimized for speed.
+ */
+runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
+ LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone)
+{
+ LCN zone_start, zone_end; /* current search range */
+ LCN last_read_pos, lcn;
+ LCN bmp_pos; /* current bit position inside the bitmap */
+ LCN prev_lcn = 0, prev_run_len = 0;
+ s64 clusters, br;
+ runlist *rl = NULL, *trl;
+ u8 *buf, *byte, bit, writeback;
+ u8 pass = 1; /* 1: inside zone; 2: start of zone */
+ u8 search_zone; /* 4: data2 (start) 1: mft (middle) 2: data1 (end) */
+ u8 done_zones = 0;
+ u8 has_guess, used_zone_pos;
+ int err = 0, rlpos, rlsize, buf_size;
+
+ ntfs_log_enter("Entering with count = 0x%llx, start_lcn = 0x%llx, "
+ "zone = %s_ZONE.\n", (long long)count, (long long)
+ start_lcn, zone == MFT_ZONE ? "MFT" : "DATA");
+
+ if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
+ (s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
+ errno = EINVAL;
+ ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld",
+ __FUNCTION__, (long long)start_vcn,
+ (long long)count, (long long)start_lcn);
+ goto out;
+ }
+
+ /* Return empty runlist if @count == 0 */
+ if (!count) {
+ rl = ntfs_malloc(0x1000);
+ if (rl) {
+ rl[0].vcn = start_vcn;
+ rl[0].lcn = LCN_RL_NOT_MAPPED;
+ rl[0].length = 0;
+ }
+ goto out;
+ }
+
+ buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE);
+ if (!buf)
+ goto out;
+ /*
+ * If no @start_lcn was requested, use the current zone
+ * position otherwise use the requested @start_lcn.
+ */
+ has_guess = 1;
+ zone_start = start_lcn;
+
+ if (zone_start < 0) {
+ if (zone == DATA_ZONE)
+ zone_start = vol->data1_zone_pos;
+ else
+ zone_start = vol->mft_zone_pos;
+ has_guess = 0;
+ }
+
+ used_zone_pos = has_guess ? 0 : 1;
+
+ if (!zone_start || zone_start == vol->mft_zone_start ||
+ zone_start == vol->mft_zone_end)
+ pass = 2;
+
+ if (zone_start < vol->mft_zone_start) {
+ zone_end = vol->mft_zone_start;
+ search_zone = ZONE_DATA2;
+ } else if (zone_start < vol->mft_zone_end) {
+ zone_end = vol->mft_zone_end;
+ search_zone = ZONE_MFT;
+ } else {
+ zone_end = vol->nr_clusters;
+ search_zone = ZONE_DATA1;
+ }
+
+ bmp_pos = zone_start;
+
+ /* Loop until all clusters are allocated. */
+ clusters = count;
+ rlpos = rlsize = 0;
+ while (1) {
+ /* check whether we have exhausted the current zone */
+ if (search_zone & vol->full_zones)
+ goto zone_pass_done;
+ last_read_pos = bmp_pos >> 3;
+ br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos,
+ NTFS_LCNALLOC_BSIZE, buf);
+ if (br <= 0) {
+ if (!br)
+ goto zone_pass_done;
+ err = errno;
+ ntfs_log_perror("Reading $BITMAP failed");
+ goto err_ret;
+ }
+ /*
+ * We might have read less than NTFS_LCNALLOC_BSIZE bytes
+ * if we are close to the end of the attribute.
+ */
+ buf_size = (int)br << 3;
+ lcn = bmp_pos & 7;
+ bmp_pos &= ~7;
+ writeback = 0;
+
+ while (lcn < buf_size) {
+ byte = buf + (lcn >> 3);
+ bit = 1 << (lcn & 7);
+ if (has_guess) {
+ if (*byte & bit) {
+ has_guess = 0;
+ break;
+ }
+ } else {
+ lcn = max_empty_bit_range(buf, br);
+ if (lcn < 0)
+ break;
+ has_guess = 1;
+ continue;
+ }
+
+ /* First free bit is at lcn + bmp_pos. */
+
+ /* Reallocate memory if necessary. */
+ if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
+ rlsize += 4096;
+ trl = realloc(rl, rlsize);
+ if (!trl) {
+ err = ENOMEM;
+ ntfs_log_perror("realloc() failed");
+ goto wb_err_ret;
+ }
+ rl = trl;
+ }
+
+ /* Allocate the bitmap bit. */
+ *byte |= bit;
+ writeback = 1;
+ if (vol->free_clusters <= 0)
+ ntfs_log_error("Non-positive free clusters "
+ "(%lld)!\n",
+ (long long)vol->free_clusters);
+ else
+ vol->free_clusters--;
+
+ /*
+ * Coalesce with previous run if adjacent LCNs.
+ * Otherwise, append a new run.
+ */
+ if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
+ ntfs_log_debug("Cluster coalesce: prev_lcn: "
+ "%lld lcn: %lld bmp_pos: %lld "
+ "prev_run_len: %lld\n",
+ (long long)prev_lcn,
+ (long long)lcn, (long long)bmp_pos,
+ (long long)prev_run_len);
+ rl[rlpos - 1].length = ++prev_run_len;
+ } else {
+ if (rlpos)
+ rl[rlpos].vcn = rl[rlpos - 1].vcn +
+ prev_run_len;
+ else {
+ rl[rlpos].vcn = start_vcn;
+ ntfs_log_debug("Start_vcn: %lld\n",
+ (long long)start_vcn);
+ }
+
+ rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
+ rl[rlpos].length = prev_run_len = 1;
+ rlpos++;
+ }
+
+ ntfs_log_debug("RUN: %-16lld %-16lld %-16lld\n",
+ (long long)rl[rlpos - 1].vcn,
+ (long long)rl[rlpos - 1].lcn,
+ (long long)rl[rlpos - 1].length);
+ /* Done? */
+ if (!--clusters) {
+ if (used_zone_pos)
+ ntfs_cluster_update_zone_pos(vol,
+ search_zone, lcn + bmp_pos + 1 +
+ NTFS_LCNALLOC_SKIP);
+ goto done_ret;
+ }
+
+ lcn++;
+ }
+
+ if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
+ err = errno;
+ goto err_ret;
+ }
+
+ if (!used_zone_pos) {
+
+ used_zone_pos = 1;
+
+ if (search_zone == ZONE_MFT)
+ zone_start = vol->mft_zone_pos;
+ else if (search_zone == ZONE_DATA1)
+ zone_start = vol->data1_zone_pos;
+ else
+ zone_start = vol->data2_zone_pos;
+
+ if (!zone_start || zone_start == vol->mft_zone_start ||
+ zone_start == vol->mft_zone_end)
+ pass = 2;
+ bmp_pos = zone_start;
+ } else
+ bmp_pos += buf_size;
+
+ if (bmp_pos < zone_end)
+ continue;
+
+zone_pass_done:
+ ntfs_log_trace("Finished current zone pass(%i).\n", pass);
+ if (pass == 1) {
+ pass = 2;
+ zone_end = zone_start;
+
+ if (search_zone == ZONE_MFT)
+ zone_start = vol->mft_zone_start;
+ else if (search_zone == ZONE_DATA1)
+ zone_start = vol->mft_zone_end;
+ else
+ zone_start = 0;
+
+ /* Sanity check. */
+ if (zone_end < zone_start)
+ zone_end = zone_start;
+
+ bmp_pos = zone_start;
+
+ continue;
+ }
+ /* pass == 2 */
+done_zones_check:
+ done_zones |= search_zone;
+ vol->full_zones |= search_zone;
+ if (done_zones < (ZONE_MFT + ZONE_DATA1 + ZONE_DATA2)) {
+ ntfs_log_trace("Switching zone.\n");
+ pass = 1;
+ if (rlpos) {
+ LCN tc = rl[rlpos - 1].lcn +
+ rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
+
+ if (used_zone_pos)
+ ntfs_cluster_update_zone_pos(vol,
+ search_zone, tc);
+ }
+
+ switch (search_zone) {
+ case ZONE_MFT:
+ ntfs_log_trace("Zone switch: mft -> data1\n");
+switch_to_data1_zone: search_zone = ZONE_DATA1;
+ zone_start = vol->data1_zone_pos;
+ zone_end = vol->nr_clusters;
+ if (zone_start == vol->mft_zone_end)
+ pass = 2;
+ break;
+ case ZONE_DATA1:
+ ntfs_log_trace("Zone switch: data1 -> data2\n");
+ search_zone = ZONE_DATA2;
+ zone_start = vol->data2_zone_pos;
+ zone_end = vol->mft_zone_start;
+ if (!zone_start)
+ pass = 2;
+ break;
+ case ZONE_DATA2:
+ if (!(done_zones & ZONE_DATA1)) {
+ ntfs_log_trace("data2 -> data1\n");
+ goto switch_to_data1_zone;
+ }
+ ntfs_log_trace("Zone switch: data2 -> mft\n");
+ search_zone = ZONE_MFT;
+ zone_start = vol->mft_zone_pos;
+ zone_end = vol->mft_zone_end;
+ if (zone_start == vol->mft_zone_start)
+ pass = 2;
+ break;
+ }
+
+ bmp_pos = zone_start;
+
+ if (zone_start == zone_end) {
+ ntfs_log_trace("Empty zone, skipped.\n");
+ goto done_zones_check;
+ }
+
+ continue;
+ }
+
+ ntfs_log_trace("All zones are finished, no space on device.\n");
+ err = ENOSPC;
+ goto err_ret;
+ }
+done_ret:
+ ntfs_log_debug("At done_ret.\n");
+ /* Add runlist terminator element. */
+ rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
+ rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
+ rl[rlpos].length = 0;
+ if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
+ err = errno;
+ goto err_ret;
+ }
+done_err_ret:
+ free(buf);
+ if (err) {
+ errno = err;
+ ntfs_log_perror("Failed to allocate clusters");
+ rl = NULL;
+ }
+out:
+ ntfs_log_leave("\n");
+ return rl;
+
+wb_err_ret:
+ ntfs_log_trace("At wb_err_ret.\n");
+ if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback))
+ err = errno;
+err_ret:
+ ntfs_log_trace("At err_ret.\n");
+ if (rl) {
+ /* Add runlist terminator element. */
+ rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
+ rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
+ rl[rlpos].length = 0;
+ ntfs_debug_runlist_dump(rl);
+ ntfs_cluster_free_from_rl(vol, rl);
+ free(rl);
+ rl = NULL;
+ }
+ goto done_err_ret;
+}
+
+/**
+ * ntfs_cluster_free_from_rl - free clusters from runlist
+ * @vol: mounted ntfs volume on which to free the clusters
+ * @rl: runlist from which deallocate clusters
+ *
+ * On success return 0 and on error return -1 with errno set to the error code.
+ */
+int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
+{
+ s64 nr_freed = 0;
+ int ret = -1;
+
+ ntfs_log_trace("Entering.\n");
+
+ for (; rl->length; rl++) {
+
+ ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
+ (long long)rl->lcn, (long long)rl->length);
+
+ if (rl->lcn >= 0) {
+ update_full_status(vol,rl->lcn);
+ if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
+ rl->length)) {
+ ntfs_log_perror("Cluster deallocation failed "
+ "(%lld, %lld)",
+ (long long)rl->lcn,
+ (long long)rl->length);
+ goto out;
+ }
+ nr_freed += rl->length ;
+ }
+ }
+
+ ret = 0;
+out:
+ vol->free_clusters += nr_freed;
+ if (vol->free_clusters > vol->nr_clusters)
+ ntfs_log_error("Too many free clusters (%lld > %lld)!",
+ (long long)vol->free_clusters,
+ (long long)vol->nr_clusters);
+ return ret;
+}
+
+/**
+ * ntfs_cluster_free - free clusters on an ntfs volume
+ * @vol: mounted ntfs volume on which to free the clusters
+ * @na: attribute whose runlist describes the clusters to free
+ * @start_vcn: vcn in @rl at which to start freeing clusters
+ * @count: number of clusters to free or -1 for all clusters
+ *
+ * Free @count clusters starting at the cluster @start_vcn in the runlist
+ * described by the attribute @na from the mounted ntfs volume @vol.
+ *
+ * If @count is -1, all clusters from @start_vcn to the end of the runlist
+ * are deallocated.
+ *
+ * On success return the number of deallocated clusters (not counting sparse
+ * clusters) and on error return -1 with errno set to the error code.
+ */
+int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
+{
+ runlist *rl;
+ s64 delta, to_free, nr_freed = 0;
+ int ret = -1;
+
+ if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
+ (count < 0 && count != -1)) {
+ ntfs_log_trace("Invalid arguments!\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
+ "vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no,
+ na->type, (long long)count, (long long)start_vcn);
+
+ rl = ntfs_attr_find_vcn(na, start_vcn);
+ if (!rl) {
+ if (errno == ENOENT)
+ ret = 0;
+ goto leave;
+ }
+
+ if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
+ errno = EIO;
+ ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__,
+ (long long)rl->lcn);
+ goto leave;
+ }
+
+ /* Find the starting cluster inside the run that needs freeing. */
+ delta = start_vcn - rl->vcn;
+
+ /* The number of clusters in this run that need freeing. */
+ to_free = rl->length - delta;
+ if (count >= 0 && to_free > count)
+ to_free = count;
+
+ if (rl->lcn != LCN_HOLE) {
+ /* Do the actual freeing of the clusters in this run. */
+ update_full_status(vol,rl->lcn + delta);
+ if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
+ to_free))
+ goto leave;
+ nr_freed = to_free;
+ }
+
+ /* Go to the next run and adjust the number of clusters left to free. */
+ ++rl;
+ if (count >= 0)
+ count -= to_free;
+
+ /*
+ * Loop over the remaining runs, using @count as a capping value, and
+ * free them.
+ */
+ for (; rl->length && count != 0; ++rl) {
+ // FIXME: Need to try ntfs_attr_map_runlist() for attribute
+ // list support! (AIA)
+ if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
+ // FIXME: Eeek! We need rollback! (AIA)
+ errno = EIO;
+ ntfs_log_perror("%s: Invalid lcn (%lli)",
+ __FUNCTION__, (long long)rl->lcn);
+ goto out;
+ }
+
+ /* The number of clusters in this run that need freeing. */
+ to_free = rl->length;
+ if (count >= 0 && to_free > count)
+ to_free = count;
+
+ if (rl->lcn != LCN_HOLE) {
+ update_full_status(vol,rl->lcn);
+ if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
+ to_free)) {
+ // FIXME: Eeek! We need rollback! (AIA)
+ ntfs_log_perror("%s: Clearing bitmap run failed",
+ __FUNCTION__);
+ goto out;
+ }
+ nr_freed += to_free;
+ }
+
+ if (count >= 0)
+ count -= to_free;
+ }
+
+ if (count != -1 && count != 0) {
+ // FIXME: Eeek! BUG()
+ errno = EIO;
+ ntfs_log_perror("%s: count still not zero (%lld)", __FUNCTION__,
+ (long long)count);
+ goto out;
+ }
+
+ ret = nr_freed;
+out:
+ vol->free_clusters += nr_freed ;
+ if (vol->free_clusters > vol->nr_clusters)
+ ntfs_log_error("Too many free clusters (%lld > %lld)!",
+ (long long)vol->free_clusters,
+ (long long)vol->nr_clusters);
+leave:
+ ntfs_log_leave("\n");
+ return ret;
+}