~ubuntu-branches/ubuntu/hardy/ntfs-3g/hardy

« back to all changes in this revision

Viewing changes to libntfs-3g/attrib.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Cécile (Le_Vert)
  • Date: 2006-11-24 00:33:43 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20061124003343-9ag45l8hiuz69nkd
Tags: upstream-0.0.0+20061031
Import upstream version 0.0.0+20061031

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/**
2
 
 * attrib.c - Attribute handling code. Part of the Linux-NTFS project.
 
2
 * attrib.c - Attribute handling code. Originated from the Linux-NTFS project.
3
3
 *
4
4
 * Copyright (c) 2000-2005 Anton Altaparmakov
5
5
 * Copyright (c) 2002-2005 Richard Russon
17
17
 * GNU General Public License for more details.
18
18
 *
19
19
 * You should have received a copy of the GNU General Public License
20
 
 * along with this program (in the main directory of the Linux-NTFS
 
20
 * along with this program (in the main directory of the NTFS-3G
21
21
 * distribution in the file COPYING); if not, write to the Free Software
22
22
 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
23
 */
77
77
        errno = 0;
78
78
        if (a->non_resident)
79
79
                return sle64_to_cpu(a->data_size);
80
 
        else
81
 
                return (s64)le32_to_cpu(a->value_length);
82
 
        errno = EINVAL;
83
 
        return 0;
 
80
        
 
81
        return (s64)le32_to_cpu(a->value_length);
84
82
}
85
83
 
86
84
/**
245
243
                                errno = EIO;
246
244
                        }
247
245
#undef ESTR
 
246
                        free(rl);
248
247
                        return 0;
249
248
                }
250
249
                total += r;
896
895
        return -1;
897
896
}
898
897
 
 
898
static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs, 
 
899
                               runlist_element **rl, VCN *update_from)
 
900
{
 
901
        s64 to_write;
 
902
        ntfs_volume *vol = na->ni->vol;
 
903
        int eo, ret = -1;
 
904
        runlist *rlc;
 
905
        LCN lcn_seek_from = -1;
 
906
        VCN cur_vcn, from_vcn;
 
907
 
 
908
        to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs);
 
909
        
 
910
        /* Instantiate the hole. */
 
911
        cur_vcn = (*rl)->vcn;
 
912
        from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits);
 
913
        ntfs_log_trace("Instantiate the hole with vcn 0x%llx.\n", cur_vcn);
 
914
        /*
 
915
         * Map whole runlist to be able update mapping pairs
 
916
         * later.
 
917
         */
 
918
        if (ntfs_attr_map_whole_runlist(na))
 
919
                goto err_out;
 
920
        /*
 
921
         * Restore @*rl, it probably get lost during runlist
 
922
         * mapping.
 
923
         */
 
924
        *rl = ntfs_attr_find_vcn(na, cur_vcn);
 
925
        if (!*rl) {
 
926
                ntfs_log_error("Failed to find run after mapping runlist. "
 
927
                               "Please report to %s.\n", NTFS_DEV_LIST);
 
928
                errno = EIO;
 
929
                goto err_out;
 
930
        }
 
931
        /*
 
932
         * Search backwards to find the best lcn to start
 
933
         * seek from.
 
934
         */
 
935
        rlc = *rl;
 
936
        while (rlc->vcn) {
 
937
                rlc--;
 
938
                if (rlc->lcn >= 0) {
 
939
                        lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn);
 
940
                        break;
 
941
                }
 
942
        }
 
943
        if (lcn_seek_from == -1) {
 
944
                /* Backwards search failed, search forwards. */
 
945
                rlc = *rl;
 
946
                while (rlc->length) {
 
947
                        rlc++;
 
948
                        if (rlc->lcn >= 0) {
 
949
                                lcn_seek_from = rlc->lcn - (rlc->vcn - from_vcn);
 
950
                                break;
 
951
                        }
 
952
                }
 
953
        }
 
954
        /* Allocate clusters to instantiate the hole. */
 
955
        rlc = ntfs_cluster_alloc(vol, from_vcn,
 
956
                                ((*ofs + to_write - 1) >> vol->cluster_size_bits)
 
957
                                 + 1 + (*rl)->vcn - from_vcn, 
 
958
                                 lcn_seek_from, DATA_ZONE);
 
959
        if (!rlc) {
 
960
                ntfs_log_perror("Hole filling cluster allocation failed");
 
961
                goto err_out;
 
962
        }
 
963
        /* Merge runlists. */
 
964
        *rl = ntfs_runlists_merge(na->rl, rlc);
 
965
        if (!*rl) {
 
966
                eo = errno;
 
967
                ntfs_log_perror("Failed to merge runlists");
 
968
                if (ntfs_cluster_free_from_rl(vol, rlc)) {
 
969
                        ntfs_log_perror("Failed to free hot clusters. "
 
970
                                        "Please run chkdsk /f");
 
971
                }
 
972
                errno = eo;
 
973
                goto err_out;
 
974
        }
 
975
        na->rl = *rl;
 
976
        if (*update_from == -1)
 
977
                *update_from = from_vcn;
 
978
        *rl = ntfs_attr_find_vcn(na, cur_vcn);
 
979
        if (!*rl) {
 
980
                /*
 
981
                 * It's definitely a BUG, if we failed to find @cur_vcn, because
 
982
                 * we missed it during instantiating of the hole.
 
983
                 */
 
984
                ntfs_log_error("Failed to find run after hole instantiation. "
 
985
                               "Please report to %s.\n", NTFS_DEV_LIST);
 
986
                errno = EIO;
 
987
                goto err_out;
 
988
        }
 
989
        /* If leaved part of the hole go to the next run. */
 
990
        if ((*rl)->lcn < 0)
 
991
                (*rl)++;
 
992
        /* Now LCN shoudn't be less than 0. */
 
993
        if ((*rl)->lcn < 0) {
 
994
                ntfs_log_error("BUG! LCN is lesser than 0. "
 
995
                               "Please report to the %s.\n", NTFS_DEV_LIST);
 
996
                errno = EIO;
 
997
                goto err_out;
 
998
        }
 
999
        if (*ofs) {
 
1000
                /*
 
1001
                 * Need to clear region between start of
 
1002
                 * @cur_vcn cluster and @*ofs.
 
1003
                 */
 
1004
                char *buf;
 
1005
 
 
1006
                buf = ntfs_malloc(*ofs);
 
1007
                if (!buf)
 
1008
                        goto err_out;
 
1009
                
 
1010
                memset(buf, 0, *ofs);
 
1011
                if (ntfs_rl_pwrite(vol, na->rl, cur_vcn << vol->cluster_size_bits, 
 
1012
                                   *ofs, buf) < 0) {
 
1013
                        ntfs_log_perror("Failed to zero area");
 
1014
                        free(buf);
 
1015
                        goto err_out;
 
1016
                }
 
1017
                free(buf);
 
1018
        }
 
1019
        if ((*rl)->vcn < cur_vcn) {
 
1020
                /*
 
1021
                 * Clusters that replaced hole are merged with
 
1022
                 * previous run, so we need to update offset.
 
1023
                 */
 
1024
                *ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits;
 
1025
        }
 
1026
        if ((*rl)->vcn > cur_vcn) {
 
1027
                /*
 
1028
                 * We left part of the hole, so we need to update offset
 
1029
                 */
 
1030
                *ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits;
 
1031
        }
 
1032
        
 
1033
        ret = 0;
 
1034
err_out:
 
1035
        return ret;
 
1036
}
 
1037
 
899
1038
/**
900
1039
 * ntfs_attr_pwrite - positioned write to an ntfs attribute
901
1040
 * @na:         ntfs attribute to write to
917
1056
 */
918
1057
s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
919
1058
{
920
 
        s64 written, to_write, ofs, total, old_initialized_size, old_data_size;
 
1059
        s64 written, to_write, ofs, old_initialized_size, old_data_size;
 
1060
        s64 total = 0;
921
1061
        VCN update_from = -1;
922
1062
        ntfs_volume *vol;
923
1063
        ntfs_attr_search_ctx *ctx = NULL;
926
1066
        struct {
927
1067
                unsigned int undo_initialized_size      : 1;
928
1068
                unsigned int undo_data_size             : 1;
929
 
                unsigned int update_mapping_pairs       : 1;
930
 
        } need_to = { 0, 0, 0 };
 
1069
        } need_to = { 0, 0 };
931
1070
 
932
1071
        ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count "
933
1072
                        "0x%llx.\n", na->ni->mft_no, na->type, (long long)pos,
934
1073
                        (long long)count);
935
1074
        if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
936
1075
                errno = EINVAL;
937
 
                return -1;
 
1076
                goto errno_set;
938
1077
        }
939
1078
        vol = na->ni->vol;
940
1079
        /*
943
1082
         */
944
1083
        if (NAttrEncrypted(na) && NAttrNonResident(na)) {
945
1084
                errno = EACCES;
946
 
                return -1;
 
1085
                goto errno_set;
947
1086
        }
948
1087
        /* If this is a compressed attribute it needs special treatment. */
949
1088
        if (NAttrCompressed(na)) {
951
1090
                // return ntfs_attr_pwrite_compressed(ntfs_attr *na,
952
1091
                //              const s64 pos, s64 count, void *b);
953
1092
                errno = EOPNOTSUPP;
954
 
                return -1;
 
1093
                goto errno_set;
955
1094
        }
956
1095
        /* Update access and change times if needed. */
957
1096
        if (na->type == AT_DATA || na->type == AT_INDEX_ROOT ||
958
1097
                        na->type == AT_INDEX_ALLOCATION)
959
1098
                ntfs_inode_update_time(na->ni);
960
1099
        if (!count)
961
 
                return 0;
 
1100
                goto out;
962
1101
        /* If the write reaches beyond the end, extend the attribute. */
963
1102
        old_data_size = na->data_size;
964
1103
        if (pos + count > na->data_size) {
965
1104
                if (ntfs_attr_truncate(na, pos + count)) {
966
1105
                        ntfs_log_perror("Failed to enlarge attribute");
967
 
                        return -1;
 
1106
                        goto errno_set;
968
1107
                }
969
1108
                need_to.undo_data_size = 1;
970
1109
        }
999
1138
                        goto err_out;
1000
1139
                }
1001
1140
                ntfs_attr_put_search_ctx(ctx);
1002
 
                return count;
 
1141
                total = count;
 
1142
                goto out;
1003
1143
        }
1004
 
        total = 0;
 
1144
        
1005
1145
        /* Handle writes beyond initialized_size. */
1006
1146
        if (pos + count > na->initialized_size) {
1007
1147
                if (ntfs_attr_map_whole_runlist(na))
1096
1236
                        goto rl_err_out;
1097
1237
                }
1098
1238
                if (rl->lcn < (LCN)0) {
1099
 
                        LCN lcn_seek_from = -1;
1100
 
                        runlist *rlc;
1101
 
                        VCN cur_vcn, from_vcn;
1102
1239
 
1103
1240
                        if (rl->lcn != (LCN)LCN_HOLE) {
1104
1241
                                errno = EIO;
1105
1242
                                goto rl_err_out;
1106
1243
                        }
1107
1244
                        
1108
 
                        to_write = min(count, (rl->length <<
1109
 
                                        vol->cluster_size_bits) - ofs);
1110
 
                        
1111
 
                        /* Instantiate the hole. */
1112
 
                        cur_vcn = rl->vcn;
1113
 
                        from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits);
1114
 
                        ntfs_log_trace("Instantiate the hole with vcn 0x%llx.\n",
1115
 
                                        cur_vcn);
1116
 
                        /*
1117
 
                         * Map whole runlist to be able update mapping pairs
1118
 
                         * later.
1119
 
                         */
1120
 
                        if (ntfs_attr_map_whole_runlist(na))
1121
 
                                goto err_out;
1122
 
                        /*
1123
 
                         * Restore @rl, it probably get lost during runlist
1124
 
                         * mapping.
1125
 
                         */
1126
 
                        rl = ntfs_attr_find_vcn(na, cur_vcn);
1127
 
                        if (!rl) {
1128
 
                                ntfs_log_error("BUG! Failed to find run after "
1129
 
                                                "mapping whole runlist. Please "
1130
 
                                                "report to the %s.\n",
1131
 
                                                NTFS_DEV_LIST);
1132
 
                                errno = EIO;
1133
 
                                goto err_out;
1134
 
                        }
1135
 
                        /*
1136
 
                         * Search backwards to find the best lcn to start
1137
 
                         * seek from.
1138
 
                         */
1139
 
                        rlc = rl;
1140
 
                        while (rlc->vcn) {
1141
 
                                rlc--;
1142
 
                                if (rlc->lcn >= 0) {
1143
 
                                        lcn_seek_from = rlc->lcn +
1144
 
                                                        (from_vcn - rlc->vcn);
1145
 
                                        break;
1146
 
                                }
1147
 
                        }
1148
 
                        if (lcn_seek_from == -1) {
1149
 
                                /* Backwards search failed, search forwards. */
1150
 
                                rlc = rl;
1151
 
                                while (rlc->length) {
1152
 
                                        rlc++;
1153
 
                                        if (rlc->lcn >= 0) {
1154
 
                                                lcn_seek_from = rlc->lcn -
1155
 
                                                        (rlc->vcn - from_vcn);
1156
 
                                                break;
1157
 
                                        }
1158
 
                                }
1159
 
                        }
1160
 
                        /* Allocate clusters to instantiate the hole. */
1161
 
                        rlc = ntfs_cluster_alloc(vol, from_vcn,
1162
 
                                                ((ofs + to_write - 1) >>
1163
 
                                                vol->cluster_size_bits) + 1 +
1164
 
                                                rl->vcn - from_vcn,
1165
 
                                                lcn_seek_from, DATA_ZONE);
1166
 
                        if (!rlc) {
1167
 
                                ntfs_log_perror("Failed to allocate clusters "
1168
 
                                                "for hole instantiating");
1169
 
                                goto err_out;
1170
 
                        }
1171
 
                        /* Merge runlists. */
1172
 
                        rl = ntfs_runlists_merge(na->rl, rlc);
1173
 
                        if (!rl) {
1174
 
                                eo = errno;
1175
 
                                ntfs_log_perror("Failed to merge runlists");
1176
 
                                if (ntfs_cluster_free_from_rl(vol, rlc)) {
1177
 
                                        ntfs_log_perror("Failed to free hot "
1178
 
                                                        "clusters. Please run "
1179
 
                                                        "chkdsk /f");
1180
 
                                }
1181
 
                                errno = eo;
1182
 
                                goto err_out;
1183
 
                        }
1184
 
                        na->rl = rl;
1185
 
                        need_to.update_mapping_pairs = 1;
1186
 
                        if (update_from == -1)
1187
 
                                update_from = from_vcn;
1188
 
                        rl = ntfs_attr_find_vcn(na, cur_vcn);
1189
 
                        if (!rl) {
1190
 
                                /*
1191
 
                                 * It's definitely a BUG, if we failed to find
1192
 
                                 * @cur_vcn, because we missed it during
1193
 
                                 * instantiating of the hole.
1194
 
                                 */
1195
 
                                ntfs_log_error("BUG! Failed to find run after "
1196
 
                                                "instantiating. Please report "
1197
 
                                                "to the %s.\n", NTFS_DEV_LIST);
1198
 
                                errno = EIO;
1199
 
                                goto err_out;
1200
 
                        }
1201
 
                        /* If leaved part of the hole go to the next run. */
1202
 
                        if (rl->lcn < 0)
1203
 
                                rl++;
1204
 
                        /* Now LCN shoudn't be less than 0. */
1205
 
                        if (rl->lcn < 0) {
1206
 
                                ntfs_log_error("BUG! LCN is lesser than 0. "
1207
 
                                                "Please report to the %s.\n",
1208
 
                                                NTFS_DEV_LIST);
1209
 
                                errno = EIO;
1210
 
                                goto err_out;
1211
 
                        }
1212
 
                        if (ofs) {
1213
 
                                /*
1214
 
                                 * Need to clear region between start of
1215
 
                                 * @cur_vcn cluster and @ofs.
1216
 
                                 */
1217
 
                                char *buf;
1218
 
 
1219
 
                                buf = ntfs_malloc(ofs);
1220
 
                                if (!buf)
1221
 
                                        goto err_out;
1222
 
                                
1223
 
                                memset(buf, 0, ofs);
1224
 
                                if (ntfs_rl_pwrite(vol, na->rl, cur_vcn <<
1225
 
                                                        vol->cluster_size_bits,
1226
 
                                                        ofs, buf) < 0) {
1227
 
                                        ntfs_log_perror("Failed to zero area");
1228
 
                                        free(buf);
1229
 
                                        goto err_out;
1230
 
                                }
1231
 
                                free(buf);
1232
 
                        }
1233
 
                        if (rl->vcn < cur_vcn) {
1234
 
                                /*
1235
 
                                 * Clusters that replaced hole are merged with
1236
 
                                 * previous run, so we need to update offset.
1237
 
                                 */
1238
 
                                ofs += (cur_vcn - rl->vcn) <<
1239
 
                                        vol->cluster_size_bits;
1240
 
                        }
1241
 
                        if (rl->vcn > cur_vcn) {
1242
 
                                /*
1243
 
                                 * We left part of the hole, so update we need
1244
 
                                 * to update offset
1245
 
                                 */
1246
 
                                ofs -= (rl->vcn - cur_vcn) <<
1247
 
                                        vol->cluster_size_bits;
1248
 
                        }
 
1245
                        if (ntfs_attr_fill_hole(na, count, &ofs, &rl, &update_from))
 
1246
                                goto err_out;
1249
1247
                }
1250
1248
                /* It is a real lcn, write it to the volume. */
1251
 
                to_write = min(count, (rl->length << vol->cluster_size_bits) -
1252
 
                                ofs);
 
1249
                to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs);
1253
1250
retry:
1254
 
                ntfs_log_trace("Writing 0x%llx bytes to vcn 0x%llx, lcn 0x%llx,"
1255
 
                                " ofs 0x%llx.\n", to_write, rl->vcn, rl->lcn,
1256
 
                                ofs);
 
1251
                ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs "
 
1252
                               "%lld.\n", to_write, rl->vcn, rl->lcn, ofs);
1257
1253
                if (!NVolReadOnly(vol))
1258
1254
                        written = ntfs_pwrite(vol->dev, (rl->lcn <<
1259
1255
                                        vol->cluster_size_bits) + ofs,
1278
1274
        if (ctx)
1279
1275
                ntfs_attr_put_search_ctx(ctx);
1280
1276
        /* Update mapping pairs if needed. */
1281
 
        if (need_to.update_mapping_pairs)
 
1277
        if (update_from != -1)
1282
1278
                ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/);
1283
 
        /* Finally, return the number of bytes written. */
 
1279
out:    
1284
1280
        return total;
1285
1281
rl_err_out:
1286
1282
        eo = errno;
1336
1332
        if (ctx)
1337
1333
                ntfs_attr_put_search_ctx(ctx);
1338
1334
        /* Update mapping pairs if needed. */
1339
 
        if (need_to.update_mapping_pairs)
 
1335
        if (update_from != -1)
1340
1336
                ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/);
1341
1337
        /* Restore original data_size if needed. */
1342
1338
        if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size))
1343
1339
                ntfs_log_perror("Failed to restore data_size");
1344
1340
        errno = eo;
1345
 
        return -1;
 
1341
errno_set:
 
1342
        total = -1;
 
1343
        goto out;
1346
1344
}
1347
1345
 
1348
1346
/**
4027
4025
        MFT_RECORD *m;
4028
4026
        ATTR_RECORD *a;
4029
4027
        VCN stop_vcn;
4030
 
        int err, mp_size, cur_max_mp_size, exp_max_mp_size;
 
4028
        int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1;
4031
4029
        BOOL finished_build;
4032
4030
 
4033
4031
retry:
4364
4362
                }
4365
4363
                ntfs_log_trace("Deallocate done.\n");
4366
4364
                ntfs_attr_put_search_ctx(ctx);
4367
 
                return 0;
 
4365
                goto ok;
4368
4366
        }
4369
4367
        ntfs_attr_put_search_ctx(ctx);
4370
4368
        ctx = NULL;
4432
4430
                if (!err)
4433
4431
                        break;
4434
4432
        }
4435
 
        return 0;
 
4433
ok:
 
4434
        ret = 0;
 
4435
out:
 
4436
        return ret;
4436
4437
put_err_out:
4437
4438
        if (ctx)
4438
4439
                ntfs_attr_put_search_ctx(ctx);
4439
4440
        errno = err;
4440
 
        return -1;
 
4441
        goto out;
4441
4442
}
4442
4443
#undef NTFS_VCN_DELETE_MARK
4443
4444