Rev 3505 | Rev 3513 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3505 | Rev 3506 | ||
---|---|---|---|
Line 52... | Line 52... | ||
52 | #include <assert.h> |
52 | #include <assert.h> |
53 | #include <futex.h> |
53 | #include <futex.h> |
54 | #include <sys/mman.h> |
54 | #include <sys/mman.h> |
55 | #include <align.h> |
55 | #include <align.h> |
56 | 56 | ||
57 | #define BS_BLOCK 0 |
- | |
58 | #define BS_SIZE 512 |
- | |
59 | - | ||
60 | /** Futex protecting the list of cached free FAT nodes. */ |
57 | /** Futex protecting the list of cached free FAT nodes. */ |
61 | static futex_t ffn_futex = FUTEX_INITIALIZER; |
58 | static futex_t ffn_futex = FUTEX_INITIALIZER; |
62 | 59 | ||
63 | /** List of cached free FAT nodes. */ |
60 | /** List of cached free FAT nodes. */ |
64 | static LIST_INITIALIZE(ffn_head); |
61 | static LIST_INITIALIZE(ffn_head); |
65 | 62 | ||
66 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
- | |
67 | - | ||
68 | static int dev_phone = -1; /* FIXME */ |
63 | static int dev_phone = -1; /* FIXME */ |
69 | static void *dev_buffer = NULL; /* FIXME */ |
64 | static void *dev_buffer = NULL; /* FIXME */ |
70 | 65 | ||
71 | /* TODO move somewhere else */ |
- | |
72 | typedef struct { |
- | |
73 | void *data; |
- | |
74 | size_t size; |
- | |
75 | bool dirty; |
- | |
76 | } block_t; |
- | |
77 | - | ||
78 | static block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs) |
66 | block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs) |
79 | { |
67 | { |
80 | /* FIXME */ |
68 | /* FIXME */ |
81 | block_t *b; |
69 | block_t *b; |
82 | off_t bufpos = 0; |
70 | off_t bufpos = 0; |
83 | size_t buflen = 0; |
71 | size_t buflen = 0; |
Line 105... | Line 93... | ||
105 | } |
93 | } |
106 | 94 | ||
107 | return b; |
95 | return b; |
108 | } |
96 | } |
109 | 97 | ||
110 | static void block_put(block_t *block) |
98 | void block_put(block_t *block) |
111 | { |
99 | { |
112 | /* FIXME */ |
100 | /* FIXME */ |
113 | free(block->data); |
101 | free(block->data); |
114 | free(block); |
102 | free(block); |
115 | } |
103 | } |
116 | 104 | ||
117 | #define FAT1 0 |
- | |
118 | - | ||
119 | #define FAT_BS(b) ((fat_bs_t *)((b)->data)) |
- | |
120 | - | ||
121 | #define FAT_CLST_RES0 0x0000 |
- | |
122 | #define FAT_CLST_RES1 0x0001 |
- | |
123 | #define FAT_CLST_FIRST 0x0002 |
- | |
124 | #define FAT_CLST_BAD 0xfff7 |
- | |
125 | #define FAT_CLST_LAST1 0xfff8 |
- | |
126 | #define FAT_CLST_LAST8 0xffff |
- | |
127 | - | ||
128 | /* internally used to mark root directory's parent */ |
- | |
129 | #define FAT_CLST_ROOTPAR FAT_CLST_RES0 |
- | |
130 | /* internally used to mark root directory */ |
- | |
131 | #define FAT_CLST_ROOT FAT_CLST_RES1 |
- | |
132 | - | ||
133 | #define fat_block_get(np, off) \ |
- | |
134 | _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off)) |
- | |
135 | - | ||
136 | static block_t * |
- | |
137 | _fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset) |
- | |
138 | { |
- | |
139 | block_t *bb; |
- | |
140 | block_t *b; |
- | |
141 | unsigned bps; |
- | |
142 | unsigned spc; |
- | |
143 | unsigned rscnt; /* block address of the first FAT */ |
- | |
144 | unsigned fatcnt; |
- | |
145 | unsigned rde; |
- | |
146 | unsigned rds; /* root directory size */ |
- | |
147 | unsigned sf; |
- | |
148 | unsigned ssa; /* size of the system area */ |
- | |
149 | unsigned clusters; |
- | |
150 | fat_cluster_t clst = firstc; |
- | |
151 | unsigned i; |
- | |
152 | - | ||
153 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
- | |
154 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
- | |
155 | spc = FAT_BS(bb)->spc; |
- | |
156 | rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
- | |
157 | fatcnt = FAT_BS(bb)->fatcnt; |
- | |
158 | rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max); |
- | |
159 | sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat); |
- | |
160 | block_put(bb); |
- | |
161 | - | ||
162 | rds = (sizeof(fat_dentry_t) * rde) / bps; |
- | |
163 | rds += ((sizeof(fat_dentry_t) * rde) % bps != 0); |
- | |
164 | ssa = rscnt + fatcnt * sf + rds; |
- | |
165 | - | ||
166 | if (firstc == FAT_CLST_ROOT) { |
- | |
167 | /* root directory special case */ |
- | |
168 | assert(offset < rds); |
- | |
169 | b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps); |
- | |
170 | return b; |
- | |
171 | } |
- | |
172 | - | ||
173 | clusters = offset / spc; |
- | |
174 | for (i = 0; i < clusters; i++) { |
- | |
175 | unsigned fsec; /* sector offset relative to FAT1 */ |
- | |
176 | unsigned fidx; /* FAT1 entry index */ |
- | |
177 | - | ||
178 | assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD); |
- | |
179 | fsec = (clst * sizeof(fat_cluster_t)) / bps; |
- | |
180 | fidx = clst % (bps / sizeof(fat_cluster_t)); |
- | |
181 | /* read FAT1 */ |
- | |
182 | b = block_get(dev_handle, rscnt + fsec, bps); |
- | |
183 | clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
- | |
184 | assert(clst != FAT_CLST_BAD); |
- | |
185 | assert(clst < FAT_CLST_LAST1); |
- | |
186 | block_put(b); |
- | |
187 | } |
- | |
188 | - | ||
189 | b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc + |
- | |
190 | offset % spc, bps); |
- | |
191 | - | ||
192 | return b; |
- | |
193 | } |
- | |
194 | - | ||
195 | /** Return number of blocks allocated to a file. |
- | |
196 | * |
- | |
197 | * @param dev_handle Device handle of the device with the file. |
- | |
198 | * @param firstc First cluster of the file. |
- | |
199 | * |
- | |
200 | * @return Number of blocks allocated to the file. |
- | |
201 | */ |
- | |
202 | static uint16_t |
- | |
203 | _fat_blcks_get(dev_handle_t dev_handle, fat_cluster_t firstc) |
- | |
204 | { |
- | |
205 | block_t *bb; |
- | |
206 | block_t *b; |
- | |
207 | unsigned bps; |
- | |
208 | unsigned spc; |
- | |
209 | unsigned rscnt; /* block address of the first FAT */ |
- | |
210 | unsigned clusters = 0; |
- | |
211 | fat_cluster_t clst = firstc; |
- | |
212 | - | ||
213 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
- | |
214 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
- | |
215 | spc = FAT_BS(bb)->spc; |
- | |
216 | rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
- | |
217 | block_put(bb); |
- | |
218 | - | ||
219 | if (firstc == FAT_CLST_RES0) { |
- | |
220 | /* No space allocated to the file. */ |
- | |
221 | return 0; |
- | |
222 | } |
- | |
223 | - | ||
224 | while (clst < FAT_CLST_LAST1) { |
- | |
225 | unsigned fsec; /* sector offset relative to FAT1 */ |
- | |
226 | unsigned fidx; /* FAT1 entry index */ |
- | |
227 | - | ||
228 | assert(clst >= FAT_CLST_FIRST); |
- | |
229 | fsec = (clst * sizeof(fat_cluster_t)) / bps; |
- | |
230 | fidx = clst % (bps / sizeof(fat_cluster_t)); |
- | |
231 | /* read FAT1 */ |
- | |
232 | b = block_get(dev_handle, rscnt + fsec, bps); |
- | |
233 | clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
- | |
234 | assert(clst != FAT_CLST_BAD); |
- | |
235 | block_put(b); |
- | |
236 | clusters++; |
- | |
237 | } |
- | |
238 | - | ||
239 | return clusters * spc; |
- | |
240 | } |
- | |
241 | - | ||
242 | static void fat_node_initialize(fat_node_t *node) |
105 | static void fat_node_initialize(fat_node_t *node) |
243 | { |
106 | { |
244 | futex_initialize(&node->lock, 1); |
107 | futex_initialize(&node->lock, 1); |
245 | node->idx = NULL; |
108 | node->idx = NULL; |
246 | node->type = 0; |
109 | node->type = 0; |
Line 249... | Line 112... | ||
249 | node->lnkcnt = 0; |
112 | node->lnkcnt = 0; |
250 | node->refcnt = 0; |
113 | node->refcnt = 0; |
251 | node->dirty = false; |
114 | node->dirty = false; |
252 | } |
115 | } |
253 | 116 | ||
254 | static uint16_t fat_bps_get(dev_handle_t dev_handle) |
- | |
255 | { |
- | |
256 | block_t *bb; |
- | |
257 | uint16_t bps; |
- | |
258 | - | ||
259 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
- | |
260 | assert(bb != NULL); |
- | |
261 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
- | |
262 | block_put(bb); |
- | |
263 | - | ||
264 | return bps; |
- | |
265 | } |
- | |
266 | - | ||
267 | static void fat_node_sync(fat_node_t *node) |
117 | static void fat_node_sync(fat_node_t *node) |
268 | { |
118 | { |
269 | /* TODO */ |
119 | /* TODO */ |
270 | } |
120 | } |
271 | 121 | ||
Line 784... | Line 634... | ||
784 | 634 | ||
785 | fat_node_put(nodep); |
635 | fat_node_put(nodep); |
786 | ipc_answer_1(rid, EOK, (ipcarg_t)bytes); |
636 | ipc_answer_1(rid, EOK, (ipcarg_t)bytes); |
787 | } |
637 | } |
788 | 638 | ||
789 | /** Fill the gap between EOF and a new file position. |
- | |
790 | * |
- | |
791 | * @param nodep FAT node with the gap. |
- | |
792 | * @param mcl First cluster in an independent cluster chain that will |
- | |
793 | * be later appended to the end of the node's own cluster |
- | |
794 | * chain. If pos is still in the last allocated cluster, |
- | |
795 | * this argument is ignored. |
- | |
796 | * @param pos Position in the last node block. |
- | |
797 | */ |
- | |
798 | static void |
- | |
799 | fat_fill_gap(fat_node_t *nodep, fat_cluster_t mcl, off_t pos) |
- | |
800 | { |
- | |
801 | uint16_t bps; |
- | |
802 | unsigned spc; |
- | |
803 | block_t *bb, *b; |
- | |
804 | off_t o, boundary; |
- | |
805 | - | ||
806 | bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE); |
- | |
807 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
- | |
808 | spc = FAT_BS(bb)->spc; |
- | |
809 | block_put(bb); |
- | |
810 | - | ||
811 | boundary = ROUND_UP(nodep->size, bps * spc); |
- | |
812 | - | ||
813 | /* zero out already allocated space */ |
- | |
814 | for (o = nodep->size - 1; o < pos && o < boundary; |
- | |
815 | o = ALIGN_DOWN(o + bps, bps)) { |
- | |
816 | b = fat_block_get(nodep, o / bps); |
- | |
817 | memset(b->data + o % bps, 0, bps - o % bps); |
- | |
818 | b->dirty = true; /* need to sync node */ |
- | |
819 | block_put(b); |
- | |
820 | } |
- | |
821 | - | ||
822 | if (o >= pos) |
- | |
823 | return; |
- | |
824 | - | ||
825 | /* zero out the initial part of the new cluster chain */ |
- | |
826 | for (o = boundary; o < pos; o += bps) { |
- | |
827 | b = _fat_block_get(nodep->idx->dev_handle, mcl, |
- | |
828 | (o - boundary) / bps); |
- | |
829 | memset(b->data, 0, min(bps, pos - o)); |
- | |
830 | b->dirty = true; /* need to sync node */ |
- | |
831 | block_put(b); |
- | |
832 | } |
- | |
833 | } |
- | |
834 | - | ||
835 | static void |
- | |
836 | fat_mark_cluster(dev_handle_t dev_handle, unsigned fatno, fat_cluster_t clst, |
- | |
837 | fat_cluster_t value) |
- | |
838 | { |
- | |
839 | /* TODO */ |
- | |
840 | } |
- | |
841 | - | ||
842 | static void |
- | |
843 | fat_alloc_shadow_clusters(dev_handle_t dev_handle, fat_cluster_t *lifo, |
- | |
844 | unsigned nclsts) |
- | |
845 | { |
- | |
846 | /* TODO */ |
- | |
847 | } |
- | |
848 | - | ||
849 | static int |
- | |
850 | fat_alloc_clusters(dev_handle_t dev_handle, unsigned nclsts, fat_cluster_t *mcl, |
- | |
851 | fat_cluster_t *lcl) |
- | |
852 | { |
- | |
853 | uint16_t bps; |
- | |
854 | uint16_t rscnt; |
- | |
855 | uint16_t sf; |
- | |
856 | block_t *bb, *blk; |
- | |
857 | fat_cluster_t *lifo; /* stack for storing free cluster numbers */ |
- | |
858 | unsigned found = 0; /* top of the free cluster number stack */ |
- | |
859 | unsigned b, c, cl; |
- | |
860 | - | ||
861 | lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t)); |
- | |
862 | if (lifo) |
- | |
863 | return ENOMEM; |
- | |
864 | - | ||
865 | bb = block_get(dev_handle, BS_BLOCK, BS_SIZE); |
- | |
866 | bps = uint16_t_le2host(FAT_BS(bb)->bps); |
- | |
867 | rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt); |
- | |
868 | sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat); |
- | |
869 | block_put(bb); |
- | |
870 | - | ||
871 | /* |
- | |
872 | * Search FAT1 for unused clusters. |
- | |
873 | */ |
- | |
874 | for (b = 0, cl = 0; b < sf; blk++) { |
- | |
875 | blk = block_get(dev_handle, rscnt + b, bps); |
- | |
876 | for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) { |
- | |
877 | fat_cluster_t *clst = (fat_cluster_t *)blk->data + c; |
- | |
878 | if (*clst == FAT_CLST_RES0) { |
- | |
879 | /* |
- | |
880 | * The cluster is free. Put it into our stack |
- | |
881 | * of found clusters and mark it as non-free. |
- | |
882 | */ |
- | |
883 | lifo[found] = cl; |
- | |
884 | if (found == 0) |
- | |
885 | *clst = FAT_CLST_LAST1; |
- | |
886 | else |
- | |
887 | *clst = lifo[found - 1]; |
- | |
888 | blk->dirty = true; /* need to sync block */ |
- | |
889 | if (++found == nclsts) { |
- | |
890 | /* we are almost done */ |
- | |
891 | block_put(blk); |
- | |
892 | /* update the shadow copies of FAT */ |
- | |
893 | fat_alloc_shadow_clusters(dev_handle, |
- | |
894 | lifo, nclsts); |
- | |
895 | *mcl = lifo[found - 1]; |
- | |
896 | *lcl = lifo[0]; |
- | |
897 | free(lifo); |
- | |
898 | return EOK; |
- | |
899 | } |
- | |
900 | } |
- | |
901 | } |
- | |
902 | block_put(blk); |
- | |
903 | } |
- | |
904 | - | ||
905 | /* |
- | |
906 | * We could not find enough clusters. Now we need to free the clusters |
- | |
907 | * we have allocated so far. |
- | |
908 | */ |
- | |
909 | while (found--) |
- | |
910 | fat_mark_cluster(dev_handle, FAT1, lifo[found], FAT_CLST_RES0); |
- | |
911 | - | ||
912 | free(lifo); |
- | |
913 | return ENOSPC; |
- | |
914 | } |
- | |
915 | - | ||
916 | static void |
- | |
917 | fat_append_clusters(fat_node_t *nodep, fat_cluster_t mcl) |
- | |
918 | { |
- | |
919 | } |
- | |
920 | - | ||
921 | void fat_write(ipc_callid_t rid, ipc_call_t *request) |
639 | void fat_write(ipc_callid_t rid, ipc_call_t *request) |
922 | { |
640 | { |
923 | dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
641 | dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
924 | fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); |
642 | fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); |
925 | off_t pos = (off_t)IPC_GET_ARG3(*request); |
643 | off_t pos = (off_t)IPC_GET_ARG3(*request); |