リビジョン | 9e02a1a31fdaf75b83b6e3eeb2c4c822220610dc (tree) |
---|---|
日時 | 2017-01-16 15:29:08 |
作者 | relan <relan@user...> |
コミッター | relan |
Generic I/O for directories: switch find_slot().
@@ -869,57 +869,87 @@ int exfat_rmdir(struct exfat* ef, struct exfat_node* node) | ||
869 | 869 | return delete(ef, node); |
870 | 870 | } |
871 | 871 | |
872 | -static int grow_directory(struct exfat* ef, struct exfat_node* dir, | |
873 | - uint64_t asize, uint32_t difference) | |
872 | +static int check_slot(struct exfat* ef, struct exfat_node* dir, off_t offset, | |
873 | + int n) | |
874 | 874 | { |
875 | - return exfat_truncate(ef, dir, | |
876 | - DIV_ROUND_UP(asize + difference, CLUSTER_SIZE(*ef->sb)) | |
877 | - * CLUSTER_SIZE(*ef->sb), true); | |
875 | + struct exfat_entry entries[n]; | |
876 | + int rc; | |
877 | + size_t i; | |
878 | + | |
879 | + /* Root directory contains entries, that don't have any nodes associated | |
880 | + with them (clusters bitmap, upper case table, label). We need to be | |
881 | + careful not to overwrite them. */ | |
882 | + if (dir != ef->root) | |
883 | + return 0; | |
884 | + | |
885 | + rc = read_entries(ef, dir, entries, n, offset); | |
886 | + if (rc != 0) | |
887 | + return rc; | |
888 | + for (i = 0; i < n; i++) | |
889 | + if (entries[i].type & EXFAT_ENTRY_VALID) | |
890 | + return -EINVAL; | |
891 | + return 0; | |
878 | 892 | } |
879 | 893 | |
880 | 894 | static int find_slot(struct exfat* ef, struct exfat_node* dir, |
881 | - cluster_t* cluster, off_t* offset, int subentries) | |
895 | + off_t* offset, int n) | |
882 | 896 | { |
883 | - struct iterator it; | |
884 | - int rc; | |
885 | - const struct exfat_entry* entry; | |
897 | + bitmap_t* dmap; | |
898 | + struct exfat_node* p; | |
899 | + size_t i; | |
886 | 900 | int contiguous = 0; |
887 | 901 | |
888 | - rc = opendir(ef, dir, &it); | |
889 | - if (rc != 0) | |
890 | - return rc; | |
891 | - for (;;) | |
902 | + if (!dir->is_cached) | |
903 | + exfat_bug("directory is not cached"); | |
904 | + | |
905 | + /* build a bitmap of valid entries in the directory */ | |
906 | + dmap = calloc(BMAP_SIZE(dir->size / sizeof(struct exfat_entry)), | |
907 | + sizeof(bitmap_t)); | |
908 | + if (dmap == NULL) | |
892 | 909 | { |
893 | - if (contiguous == 0) | |
910 | + exfat_error("failed to allocate directory bitmap (%"PRIu64")", | |
911 | + dir->size / sizeof(struct exfat_entry)); | |
912 | + return -ENOMEM; | |
913 | + } | |
914 | + for (p = dir->child; p != NULL; p = p->next) | |
915 | + for (i = 0; i < 1 + p->continuations; i++) | |
916 | + BMAP_SET(dmap, p->entry_offset / sizeof(struct exfat_entry) + i); | |
917 | + | |
918 | + /* find a slot in the directory entries bitmap */ | |
919 | + for (i = 0; i < dir->size / sizeof(struct exfat_entry); i++) | |
920 | + { | |
921 | + if (BMAP_GET(dmap, i) == 0) | |
894 | 922 | { |
895 | - *cluster = it.cluster; | |
896 | - *offset = it.offset; | |
923 | + if (contiguous++ == 0) | |
924 | + *offset = (off_t) i * sizeof(struct exfat_entry); | |
925 | + if (contiguous == n) | |
926 | + /* suitable slot is found, check that it's not occupied */ | |
927 | + switch (check_slot(ef, dir, *offset, n)) | |
928 | + { | |
929 | + case 0: | |
930 | + free(dmap); | |
931 | + return 0; | |
932 | + case -EIO: | |
933 | + free(dmap); | |
934 | + return -EIO; | |
935 | + case -EINVAL: | |
936 | + /* slot is occupied, continue searching */ | |
937 | + contiguous = 0; | |
938 | + break; | |
939 | + } | |
897 | 940 | } |
898 | - entry = get_entry_ptr(ef, &it); | |
899 | - if (entry->type & EXFAT_ENTRY_VALID) | |
900 | - contiguous = 0; | |
901 | 941 | else |
902 | - contiguous++; | |
903 | - if (contiguous == subentries) | |
904 | - break; /* suitable slot is found */ | |
905 | - if (it.offset + sizeof(struct exfat_entry) >= dir->size) | |
906 | - { | |
907 | - rc = grow_directory(ef, dir, dir->size, | |
908 | - (subentries - contiguous) * sizeof(struct exfat_entry)); | |
909 | - if (rc != 0) | |
910 | - { | |
911 | - closedir(&it); | |
912 | - return rc; | |
913 | - } | |
914 | - } | |
915 | - if (!fetch_next_entry(ef, dir, &it)) | |
916 | - { | |
917 | - closedir(&it); | |
918 | - return -EIO; | |
919 | - } | |
942 | + contiguous = 0; | |
920 | 943 | } |
921 | - closedir(&it); | |
922 | - return 0; | |
944 | + free(dmap); | |
945 | + | |
946 | + /* no suitable slots found, extend the directory */ | |
947 | + if (contiguous == 0) | |
948 | + *offset = dir->size; | |
949 | + return exfat_truncate(ef, dir, | |
950 | + ROUND_UP(dir->size + sizeof(struct exfat_entry[n - contiguous]), | |
951 | + CLUSTER_SIZE(*ef->sb)), | |
952 | + true); | |
923 | 953 | } |
924 | 954 | |
925 | 955 | static int commit_entry(struct exfat* ef, struct exfat_node* dir, |
@@ -1000,7 +1030,7 @@ static int create(struct exfat* ef, const char* path, uint16_t attrib) | ||
1000 | 1030 | return -EEXIST; |
1001 | 1031 | } |
1002 | 1032 | |
1003 | - rc = find_slot(ef, dir, &cluster, &offset, | |
1033 | + rc = find_slot(ef, dir, &offset, | |
1004 | 1034 | 2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX)); |
1005 | 1035 | if (rc != 0) |
1006 | 1036 | { |
@@ -1182,7 +1212,7 @@ int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path) | ||
1182 | 1212 | exfat_put_node(ef, existing); |
1183 | 1213 | } |
1184 | 1214 | |
1185 | - rc = find_slot(ef, dir, &cluster, &offset, | |
1215 | + rc = find_slot(ef, dir, &offset, | |
1186 | 1216 | 2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX)); |
1187 | 1217 | if (rc != 0) |
1188 | 1218 | { |
@@ -1248,7 +1278,6 @@ int exfat_set_label(struct exfat* ef, const char* label) | ||
1248 | 1278 | { |
1249 | 1279 | le16_t label_utf16[EXFAT_ENAME_MAX + 1]; |
1250 | 1280 | int rc; |
1251 | - cluster_t cluster; | |
1252 | 1281 | off_t offset; |
1253 | 1282 | struct exfat_entry_label entry; |
1254 | 1283 |
@@ -1259,7 +1288,7 @@ int exfat_set_label(struct exfat* ef, const char* label) | ||
1259 | 1288 | |
1260 | 1289 | rc = find_label(ef, &offset); |
1261 | 1290 | if (rc == -ENOENT) |
1262 | - rc = find_slot(ef, ef->root, &cluster, &offset, 1); | |
1291 | + rc = find_slot(ef, ef->root, &offset, 1); | |
1263 | 1292 | if (rc != 0) |
1264 | 1293 | return rc; |
1265 | 1294 |