diff --git a/include/ntfs-3g/param.h b/include/ntfs-3g/param.h index 97cec6cf..f21bd653 100644 --- a/include/ntfs-3g/param.h +++ b/include/ntfs-3g/param.h @@ -43,6 +43,8 @@ enum { * Parameters for compression */ + /* default option for compression */ +#define DEFAULT_COMPRESSION FALSE /* (log2 of) number of clusters in a compression block for new files */ #define STANDARD_COMPRESSION_UNIT 4 /* maximum cluster size for allowing compression for new files */ diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index 3998e974..79193c53 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -110,6 +110,7 @@ typedef enum { NV_ShowSysFiles, /* 1: Show NTFS metafiles. */ NV_ShowHidFiles, /* 1: Show files marked hidden. */ NV_HideDotFiles, /* 1: Set hidden flag on dot files */ + NV_Compression, /* 1: allow compression */ } ntfs_volume_state_bits; #define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state) @@ -140,6 +141,10 @@ typedef enum { #define NVolSetHideDotFiles(nv) set_nvol_flag(nv, HideDotFiles) #define NVolClearHideDotFiles(nv) clear_nvol_flag(nv, HideDotFiles) +#define NVolCompression(nv) test_nvol_flag(nv, Compression) +#define NVolSetCompression(nv) set_nvol_flag(nv, Compression) +#define NVolClearCompression(nv) clear_nvol_flag(nv, Compression) + /* * NTFS version 1.1 and 1.2 are used by Windows NT4. * NTFS version 2.x is used by Windows 2000 Beta diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index 3a78c0b9..275a1dbc 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -464,11 +464,12 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, * change when stream is wiped out. * * Also prevent compression on NTFS version < 3.0 - * or if cluster size > 4K + * or cluster size > 4K or compression is disabled */ a->flags &= ~ATTR_COMPRESSION_MASK; if ((ni->flags & FILE_ATTR_COMPRESSED) && (ni->vol->major_ver >= 3) + && NVolCompression(ni->vol) && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE)) a->flags |= ATTR_IS_COMPRESSED; } @@ -4010,6 +4011,7 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, add_attr_record: if ((ni->flags & FILE_ATTR_COMPRESSED) && (ni->vol->major_ver >= 3) + && NVolCompression(ni->vol) && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) && ((type == AT_DATA) || ((type == AT_INDEX_ROOT) && (name == NTFS_INDEX_I30)))) @@ -4981,6 +4983,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) if (!na->data_size && (na->type == AT_DATA) && (na->ni->vol->major_ver >= 3) + && NVolCompression(na->ni->vol) && (na->ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) && (na->ni->flags & FILE_ATTR_COMPRESSED)) { a->flags |= ATTR_IS_COMPRESSED; diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index e5a5534c..2372f3f8 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -1469,9 +1469,11 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid, /* * Set compression flag according to parent directory * unless NTFS version < 3.0 or cluster size > 4K + * or compression has been disabled */ if ((dir_ni->flags & FILE_ATTR_COMPRESSED) && (dir_ni->vol->major_ver >= 3) + && NVolCompression(dir_ni->vol) && (dir_ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) && (S_ISREG(type) || S_ISDIR(type))) ni->flags |= FILE_ATTR_COMPRESSED; diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index f89eac92..e015a355 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -213,6 +213,7 @@ typedef struct { BOOL hide_dot_files; BOOL ignore_case; BOOL windows_names; + BOOL compression; BOOL silent; BOOL recover; BOOL hiberfile; @@ -3647,6 +3648,8 @@ static int ntfs_open(const char *device) ntfs_log_perror("Failed to mount '%s'", device); goto err_out; } + if (ctx->compression) + NVolSetCompression(ctx->vol); #ifdef HAVE_SETXATTR /* archivers must see hidden files */ if (ctx->efs_raw) @@ -3748,6 +3751,7 @@ static char *parse_mount_options(const char *orig_opts) #ifdef HAVE_SETXATTR /* extended attributes interface required */ ctx->efs_raw = FALSE; #endif /* HAVE_SETXATTR */ + ctx->compression = DEFAULT_COMPRESSION; options = strdup(orig_opts ? orig_opts : ""); if (!options) { ntfs_log_perror("%s: strdup failed", EXEC_NAME); @@ -3838,6 +3842,14 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "windows_names")) goto err_exit; ctx->windows_names = TRUE; + } else if (!strcmp(opt, "compression")) { + if (bogus_option_value(val, "compression")) + goto err_exit; + ctx->compression = TRUE; + } else if (!strcmp(opt, "nocompression")) { + if (bogus_option_value(val, "nocompression")) + goto err_exit; + ctx->compression = FALSE; } else if (!strcmp(opt, "silent")) { if (bogus_option_value(val, "silent")) goto err_exit; diff --git a/src/ntfs-3g.8.in b/src/ntfs-3g.8.in index 69d1a9a0..ee342b9a 100644 --- a/src/ntfs-3g.8.in +++ b/src/ntfs-3g.8.in @@ -256,6 +256,19 @@ write operation so that encrypted files can be saved and restored without being decrypted. The \fBuser.ntfs.efsinfo\fP extended attribute has also to be saved and restored for the file to be decrypted. .TP +.B compression +This option enables creating new transparently compressed files in +directories marked for compression. A directory is marked for compression by +setting the bit 11 (value 0x00000800) in its Windows attribute. In such a +directory, new files are created compressed and new subdirectories are +themselves marked for compression. The option and the flag have no effect +on existing files. +.TP +.B nocompression +This option disables creating new transparently compressed files in directories +marked for compression. Existing compressed files can still be read and +updated. Currently this is the default option. +.TP .B debug Makes ntfs-3g to not detach from terminal and print a lot of debug output from libntfs-3g and FUSE. diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 970b0456..5a529a7f 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -173,6 +173,7 @@ typedef struct { BOOL hide_hid_files; BOOL hide_dot_files; BOOL windows_names; + BOOL compression; BOOL silent; BOOL recover; BOOL hiberfile; @@ -3600,6 +3601,8 @@ static int ntfs_open(const char *device) ntfs_log_perror("Failed to mount '%s'", device); goto err_out; } + if (ctx->compression) + NVolSetCompression(ctx->vol); #ifdef HAVE_SETXATTR /* archivers must see hidden files */ if (ctx->efs_raw) @@ -3698,6 +3701,7 @@ static char *parse_mount_options(const char *orig_opts) #ifdef HAVE_SETXATTR /* extended attributes interface required */ ctx->efs_raw = FALSE; #endif /* HAVE_SETXATTR */ + ctx->compression = DEFAULT_COMPRESSION; options = strdup(orig_opts ? orig_opts : ""); if (!options) { ntfs_log_perror("%s: strdup failed", EXEC_NAME); @@ -3784,6 +3788,14 @@ static char *parse_mount_options(const char *orig_opts) if (bogus_option_value(val, "windows_names")) goto err_exit; ctx->windows_names = TRUE; + } else if (!strcmp(opt, "compression")) { + if (bogus_option_value(val, "compression")) + goto err_exit; + ctx->compression = TRUE; + } else if (!strcmp(opt, "nocompression")) { + if (bogus_option_value(val, "nocompression")) + goto err_exit; + ctx->compression = FALSE; } else if (!strcmp(opt, "silent")) { if (bogus_option_value(val, "silent")) goto err_exit;