1 | /* |
---|
2 | * Miscellaneous routines implementation for MSDOS filesystem |
---|
3 | * |
---|
4 | * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia |
---|
5 | * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru> |
---|
6 | * |
---|
7 | * The license and distribution terms for this file may be |
---|
8 | * found in the file LICENSE in this distribution or at |
---|
9 | * http://www.rtems.com/license/LICENSE. |
---|
10 | * |
---|
11 | * @(#) $Id$ |
---|
12 | */ |
---|
13 | |
---|
14 | #if HAVE_CONFIG_H |
---|
15 | #include "config.h" |
---|
16 | #endif |
---|
17 | |
---|
18 | #include <stdlib.h> |
---|
19 | #include <sys/time.h> |
---|
20 | #include <unistd.h> |
---|
21 | #include <string.h> |
---|
22 | #include <assert.h> |
---|
23 | #include <rtems/libio_.h> |
---|
24 | |
---|
25 | #include "fat.h" |
---|
26 | #include "fat_fat_operations.h" |
---|
27 | #include "fat_file.h" |
---|
28 | |
---|
29 | #include "msdos.h" |
---|
30 | |
---|
31 | /* msdos_get_token -- |
---|
32 | * Routine to get a token (name or separator) from the path. |
---|
33 | * |
---|
34 | * PARAMETERS: |
---|
35 | * path - path to get token from |
---|
36 | * ret_token - returned token |
---|
37 | * token_len - length of returned token |
---|
38 | * |
---|
39 | * RETURNS: |
---|
40 | * token type, token and token length |
---|
41 | * |
---|
42 | */ |
---|
43 | msdos_token_types_t |
---|
44 | msdos_get_token(const char *path, char *ret_token, int *token_len) |
---|
45 | { |
---|
46 | int rc = RC_OK; |
---|
47 | register int i = 0; |
---|
48 | msdos_token_types_t type = MSDOS_NAME; |
---|
49 | char token[MSDOS_NAME_MAX_WITH_DOT+1]; |
---|
50 | register char c; |
---|
51 | |
---|
52 | /* |
---|
53 | * Copy a name into token. (Remember NULL is a token.) |
---|
54 | */ |
---|
55 | c = path[i]; |
---|
56 | while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) ) |
---|
57 | { |
---|
58 | token[i] = c; |
---|
59 | if ( i == MSDOS_NAME_MAX_WITH_DOT ) |
---|
60 | return MSDOS_INVALID_TOKEN; |
---|
61 | if ( !msdos_is_valid_name_char(c) ) |
---|
62 | return MSDOS_INVALID_TOKEN; |
---|
63 | c = path [++i]; |
---|
64 | } |
---|
65 | |
---|
66 | /* |
---|
67 | * Copy a seperator into token. |
---|
68 | */ |
---|
69 | if ( i == 0 ) |
---|
70 | { |
---|
71 | token[i] = c; |
---|
72 | if ( token[i] != '\0' ) |
---|
73 | { |
---|
74 | i++; |
---|
75 | type = MSDOS_CURRENT_DIR; |
---|
76 | } |
---|
77 | else |
---|
78 | type = MSDOS_NO_MORE_PATH; |
---|
79 | } |
---|
80 | else if (token[ i-1 ] != '\0') |
---|
81 | token[i] = '\0'; |
---|
82 | |
---|
83 | /* |
---|
84 | * Set token_len to the number of characters copied. |
---|
85 | */ |
---|
86 | *token_len = i; |
---|
87 | |
---|
88 | /* |
---|
89 | * If we copied something that was not a seperator see if |
---|
90 | * it was a special name. |
---|
91 | */ |
---|
92 | if ( type == MSDOS_NAME ) |
---|
93 | { |
---|
94 | if ( strcmp( token, "..") == 0 ) |
---|
95 | { |
---|
96 | strcpy(ret_token, MSDOS_DOTDOT_NAME); |
---|
97 | type = MSDOS_UP_DIR; |
---|
98 | return type; |
---|
99 | } |
---|
100 | |
---|
101 | if ( strcmp( token, "." ) == 0 ) |
---|
102 | { |
---|
103 | strcpy(ret_token, MSDOS_DOT_NAME); |
---|
104 | type = MSDOS_CURRENT_DIR; |
---|
105 | return type; |
---|
106 | } |
---|
107 | |
---|
108 | rc = msdos_filename_unix2dos(token, *token_len, ret_token); |
---|
109 | if ( rc != RC_OK ) |
---|
110 | return MSDOS_INVALID_TOKEN; |
---|
111 | } |
---|
112 | ret_token[MSDOS_NAME_MAX] = '\0'; |
---|
113 | return type; |
---|
114 | } |
---|
115 | |
---|
116 | |
---|
117 | /* msdos_find_name -- |
---|
118 | * Find the node which correspondes to the name, open fat-file which |
---|
119 | * correspondes to the found node and close fat-file which correspondes |
---|
120 | * to the node we searched in. |
---|
121 | * |
---|
122 | * PARAMETERS: |
---|
123 | * parent_loc - parent node description |
---|
124 | * name - name to find |
---|
125 | * |
---|
126 | * RETURNS: |
---|
127 | * RC_OK and updated 'parent_loc' on success, or -1 if error |
---|
128 | * occured (errno set apropriately) |
---|
129 | * |
---|
130 | */ |
---|
131 | int |
---|
132 | msdos_find_name( |
---|
133 | rtems_filesystem_location_info_t *parent_loc, |
---|
134 | char *name |
---|
135 | ) |
---|
136 | { |
---|
137 | int rc = RC_OK; |
---|
138 | msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info; |
---|
139 | fat_file_fd_t *fat_fd = NULL; |
---|
140 | fat_auxiliary_t aux; |
---|
141 | unsigned short time_val = 0; |
---|
142 | unsigned short date = 0; |
---|
143 | char node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; |
---|
144 | |
---|
145 | memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); |
---|
146 | |
---|
147 | /* |
---|
148 | * find the node which correspondes to the name in the directory pointed by |
---|
149 | * 'parent_loc' |
---|
150 | */ |
---|
151 | rc = msdos_get_name_node(parent_loc, name, &aux, node_entry); |
---|
152 | if (rc != RC_OK) |
---|
153 | return rc; |
---|
154 | |
---|
155 | /* open fat-file corresponded to the found node */ |
---|
156 | rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd); |
---|
157 | if (rc != RC_OK) |
---|
158 | return rc; |
---|
159 | |
---|
160 | /* |
---|
161 | * I don't like this if, but: we should do it , or should write new file |
---|
162 | * size and first cluster num to the disk after each write operation |
---|
163 | * (even if one byte is written - that is TOO non-optimize) because |
---|
164 | * otherwise real values of these fields stored in fat-file descriptor |
---|
165 | * may be accidentely rewritten with wrong values stored on the disk |
---|
166 | */ |
---|
167 | if (fat_fd->links_num == 1) |
---|
168 | { |
---|
169 | fat_fd->info_cln = aux.cln; |
---|
170 | fat_fd->info_ofs = aux.ofs; |
---|
171 | fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry); |
---|
172 | fat_fd->first_char = *MSDOS_DIR_NAME(node_entry); |
---|
173 | |
---|
174 | time_val = *MSDOS_DIR_WRITE_TIME(node_entry); |
---|
175 | date = *MSDOS_DIR_WRITE_DATE(node_entry); |
---|
176 | |
---|
177 | fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(time_val), CF_LE_W(date)); |
---|
178 | |
---|
179 | if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY) |
---|
180 | { |
---|
181 | fat_fd->fat_file_type = FAT_DIRECTORY; |
---|
182 | fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT; |
---|
183 | |
---|
184 | rc = fat_file_size(parent_loc->mt_entry, fat_fd); |
---|
185 | if (rc != RC_OK) |
---|
186 | { |
---|
187 | fat_file_close(parent_loc->mt_entry, fat_fd); |
---|
188 | return rc; |
---|
189 | } |
---|
190 | } |
---|
191 | else |
---|
192 | { |
---|
193 | fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry)); |
---|
194 | fat_fd->fat_file_type = FAT_FILE; |
---|
195 | fat_fd->size_limit = MSDOS_MAX_FILE_SIZE; |
---|
196 | } |
---|
197 | |
---|
198 | /* these data is not actual for zero-length fat-file */ |
---|
199 | fat_fd->map.file_cln = 0; |
---|
200 | fat_fd->map.disk_cln = fat_fd->cln; |
---|
201 | |
---|
202 | if ((fat_fd->fat_file_size != 0) && |
---|
203 | (fat_fd->fat_file_size <= fs_info->fat.vol.bpc)) |
---|
204 | { |
---|
205 | fat_fd->map.last_cln = fat_fd->cln; |
---|
206 | } |
---|
207 | else |
---|
208 | { |
---|
209 | fat_fd->map.last_cln = FAT_UNDEFINED_VALUE; |
---|
210 | } |
---|
211 | } |
---|
212 | |
---|
213 | /* close fat-file corresponded to the node we searched in */ |
---|
214 | rc = fat_file_close(parent_loc->mt_entry, parent_loc->node_access); |
---|
215 | if (rc != RC_OK) |
---|
216 | { |
---|
217 | fat_file_close(parent_loc->mt_entry, fat_fd); |
---|
218 | return rc; |
---|
219 | } |
---|
220 | |
---|
221 | /* update node_info_ptr field */ |
---|
222 | parent_loc->node_access = fat_fd; |
---|
223 | |
---|
224 | return rc; |
---|
225 | } |
---|
226 | |
---|
227 | /* msdos_get_name_node -- |
---|
228 | * This routine is used in two ways: for a new mode creation (a) or for |
---|
229 | * search the node which correspondes to the name parameter (b). |
---|
230 | * In case (a) 'name' should be set up to NULL and 'name_dir_entry' should |
---|
231 | * point to initialized 32 bytes structure described a new node. |
---|
232 | * In case (b) 'name' should contain a valid string. |
---|
233 | * |
---|
234 | * (a): reading fat-file which correspondes to directory we are going to |
---|
235 | * create node in. If free slot is found write contents of |
---|
236 | * 'name_dir_entry' into it. If reach end of fat-file and no free |
---|
237 | * slot found, write 32 bytes to the end of fat-file. |
---|
238 | * |
---|
239 | * (b): reading fat-file which correspondes to directory and trying to |
---|
240 | * find slot with the name field == 'name' parameter |
---|
241 | * |
---|
242 | * |
---|
243 | * PARAMETERS: |
---|
244 | * parent_loc - node description to create node in or to find name in |
---|
245 | * name - NULL or name to find |
---|
246 | * paux - identify a node location on the disk - |
---|
247 | * cluster num and offset inside the cluster |
---|
248 | * name_dir_entry - node to create/placeholder for found node (IN/OUT) |
---|
249 | * |
---|
250 | * RETURNS: |
---|
251 | * RC_OK, filled aux_struct_ptr and name_dir_entry on success, or -1 if |
---|
252 | * error occured (errno set apropriately) |
---|
253 | * |
---|
254 | */ |
---|
255 | int |
---|
256 | msdos_get_name_node( |
---|
257 | rtems_filesystem_location_info_t *parent_loc, |
---|
258 | char *name, |
---|
259 | fat_auxiliary_t *paux, |
---|
260 | char *name_dir_entry |
---|
261 | ) |
---|
262 | { |
---|
263 | int rc = RC_OK; |
---|
264 | ssize_t ret = 0; |
---|
265 | msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info; |
---|
266 | fat_file_fd_t *fat_fd = parent_loc->node_access; |
---|
267 | uint32_t dotdot_cln = 0; |
---|
268 | |
---|
269 | /* find name in fat-file which correspondes to the directory */ |
---|
270 | rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd, name, paux, |
---|
271 | name_dir_entry); |
---|
272 | if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR)) |
---|
273 | return rc; |
---|
274 | |
---|
275 | /* if we search for valid name and name not found -> return */ |
---|
276 | if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name != NULL)) |
---|
277 | return rc; |
---|
278 | |
---|
279 | /* |
---|
280 | * if we try to create new entry and the directory is not big enough |
---|
281 | * currently - try to enlarge directory |
---|
282 | */ |
---|
283 | if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name == NULL)) |
---|
284 | { |
---|
285 | ret = fat_file_write(parent_loc->mt_entry, fat_fd, |
---|
286 | fat_fd->fat_file_size, |
---|
287 | MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE, |
---|
288 | name_dir_entry); |
---|
289 | if (ret == -1) |
---|
290 | return -1; |
---|
291 | |
---|
292 | /* on success directory is enlarged by a new cluster */ |
---|
293 | fat_fd->fat_file_size += fs_info->fat.vol.bpc; |
---|
294 | |
---|
295 | /* get cluster num where a new node located */ |
---|
296 | rc = fat_file_ioctl(parent_loc->mt_entry, fat_fd, F_CLU_NUM, |
---|
297 | fat_fd->fat_file_size - 1, &paux->cln); |
---|
298 | |
---|
299 | if (rc != RC_OK) |
---|
300 | return rc; |
---|
301 | |
---|
302 | /* |
---|
303 | * if new cluster allocated succesfully then new node is at very |
---|
304 | * beginning of the cluster (offset is computed in bytes) |
---|
305 | */ |
---|
306 | paux->ofs = 0; |
---|
307 | return RC_OK; |
---|
308 | } |
---|
309 | |
---|
310 | /* |
---|
311 | * if we have deal with ".." - it is a special case :((( |
---|
312 | * |
---|
313 | * Really, we should return cluster num and offset not of ".." slot, but |
---|
314 | * slot which correspondes to real directory name. |
---|
315 | */ |
---|
316 | if ((rc == RC_OK) && (name != NULL)) |
---|
317 | { |
---|
318 | if (strncmp(name, MSDOS_DOTDOT_NAME, MSDOS_SHORT_NAME_LEN) == 0) |
---|
319 | { |
---|
320 | dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry)); |
---|
321 | |
---|
322 | /* are we right under root dir ? */ |
---|
323 | if (dotdot_cln == 0) |
---|
324 | { |
---|
325 | /* |
---|
326 | * we can relax about first_char field - it never should be |
---|
327 | * used for root dir |
---|
328 | */ |
---|
329 | paux->cln = FAT_ROOTDIR_CLUSTER_NUM; |
---|
330 | paux->ofs = 0; |
---|
331 | } |
---|
332 | else |
---|
333 | { |
---|
334 | rc = msdos_get_dotdot_dir_info_cluster_num_and_offset( |
---|
335 | parent_loc->mt_entry, |
---|
336 | dotdot_cln, |
---|
337 | paux, |
---|
338 | name_dir_entry |
---|
339 | ); |
---|
340 | if (rc != RC_OK) |
---|
341 | return rc; |
---|
342 | } |
---|
343 | } |
---|
344 | } |
---|
345 | return rc; |
---|
346 | } |
---|
347 | |
---|
348 | /* |
---|
349 | * msdos_get_dotdot_dir_info_cluster_num_and_offset |
---|
350 | * |
---|
351 | * Unfortunately, in general, we cann't work here in fat-file ideologic |
---|
352 | * (open fat_file "..", get ".." and ".", open "..", find an entry ...) |
---|
353 | * because if we open |
---|
354 | * fat-file ".." it may happend that we have two different fat-file |
---|
355 | * descriptors ( for real name of directory and ".." name ) for a single |
---|
356 | * file ( cluster num of both pointers to the same cluster ) |
---|
357 | * But...we do it because we protected by semaphore |
---|
358 | * |
---|
359 | */ |
---|
360 | |
---|
361 | /* msdos_get_dotdot_dir_info_cluster_num_and_offset -- |
---|
362 | * Get cluster num and offset not of ".." slot, but slot which correspondes |
---|
363 | * to real directory name. |
---|
364 | * |
---|
365 | * PARAMETERS: |
---|
366 | * mt_entry - mount table entry |
---|
367 | * cln - data cluster num extracted drom ".." slot |
---|
368 | * paux - identify a node location on the disk - |
---|
369 | * number of cluster and offset inside the cluster |
---|
370 | * dir_entry - placeholder for found node |
---|
371 | * |
---|
372 | * RETURNS: |
---|
373 | * RC_OK, filled 'paux' and 'dir_entry' on success, or -1 if error occured |
---|
374 | * (errno set apropriately) |
---|
375 | * |
---|
376 | */ |
---|
377 | int |
---|
378 | msdos_get_dotdot_dir_info_cluster_num_and_offset( |
---|
379 | rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
380 | uint32_t cln, |
---|
381 | fat_auxiliary_t *paux, |
---|
382 | char *dir_entry |
---|
383 | ) |
---|
384 | { |
---|
385 | int rc = RC_OK; |
---|
386 | msdos_fs_info_t *fs_info = mt_entry->fs_info; |
---|
387 | fat_file_fd_t *fat_fd = NULL; |
---|
388 | char dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; |
---|
389 | char dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; |
---|
390 | uint32_t cl4find = 0; |
---|
391 | |
---|
392 | memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); |
---|
393 | memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); |
---|
394 | |
---|
395 | /* |
---|
396 | * open fat-file corresponded to ".." |
---|
397 | */ |
---|
398 | rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd); |
---|
399 | if (rc != RC_OK) |
---|
400 | return rc; |
---|
401 | |
---|
402 | fat_fd->info_cln = paux->cln; |
---|
403 | fat_fd->info_ofs = paux->ofs; |
---|
404 | fat_fd->cln = cln; |
---|
405 | fat_fd->fat_file_type = FAT_DIRECTORY; |
---|
406 | fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT; |
---|
407 | |
---|
408 | fat_fd->map.file_cln = 0; |
---|
409 | fat_fd->map.disk_cln = fat_fd->cln; |
---|
410 | |
---|
411 | rc = fat_file_size(mt_entry, fat_fd); |
---|
412 | if (rc != RC_OK) |
---|
413 | { |
---|
414 | fat_file_close(mt_entry, fat_fd); |
---|
415 | return rc; |
---|
416 | } |
---|
417 | |
---|
418 | /* find "." node in opened directory */ |
---|
419 | rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOT_NAME, paux, |
---|
420 | dot_node); |
---|
421 | |
---|
422 | if (rc != RC_OK) |
---|
423 | { |
---|
424 | fat_file_close(mt_entry, fat_fd); |
---|
425 | return rc; |
---|
426 | } |
---|
427 | |
---|
428 | /* find ".." node in opened directory */ |
---|
429 | rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOTDOT_NAME, paux, |
---|
430 | dotdot_node); |
---|
431 | |
---|
432 | if (rc != RC_OK) |
---|
433 | { |
---|
434 | fat_file_close(mt_entry, fat_fd); |
---|
435 | return rc; |
---|
436 | } |
---|
437 | |
---|
438 | cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node); |
---|
439 | |
---|
440 | /* close fat-file corresponded to ".." directory */ |
---|
441 | rc = fat_file_close(mt_entry, fat_fd); |
---|
442 | if ( rc != RC_OK ) |
---|
443 | return rc; |
---|
444 | |
---|
445 | if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0) |
---|
446 | { |
---|
447 | /* |
---|
448 | * we handle root dir for all FAT types in the same way with the |
---|
449 | * ordinary directories ( through fat_file_* calls ) |
---|
450 | */ |
---|
451 | paux->cln = FAT_ROOTDIR_CLUSTER_NUM; |
---|
452 | paux->ofs = 0; |
---|
453 | } |
---|
454 | |
---|
455 | /* open fat-file corresponded to second ".." */ |
---|
456 | rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd); |
---|
457 | if (rc != RC_OK) |
---|
458 | return rc; |
---|
459 | |
---|
460 | fat_fd->info_cln = paux->cln; |
---|
461 | fat_fd->info_ofs = paux->ofs; |
---|
462 | |
---|
463 | if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0) |
---|
464 | fat_fd->cln = fs_info->fat.vol.rdir_cl; |
---|
465 | else |
---|
466 | fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node); |
---|
467 | |
---|
468 | fat_fd->fat_file_type = FAT_DIRECTORY; |
---|
469 | fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT; |
---|
470 | |
---|
471 | fat_fd->map.file_cln = 0; |
---|
472 | fat_fd->map.disk_cln = fat_fd->cln; |
---|
473 | |
---|
474 | rc = fat_file_size(mt_entry, fat_fd); |
---|
475 | if (rc != RC_OK) |
---|
476 | { |
---|
477 | fat_file_close(mt_entry, fat_fd); |
---|
478 | return rc; |
---|
479 | } |
---|
480 | |
---|
481 | /* in this directory find slot with specified cluster num */ |
---|
482 | rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find, |
---|
483 | paux, dir_entry); |
---|
484 | if (rc != RC_OK) |
---|
485 | { |
---|
486 | fat_file_close(mt_entry, fat_fd); |
---|
487 | return rc; |
---|
488 | } |
---|
489 | rc = fat_file_close(mt_entry, fat_fd); |
---|
490 | return rc; |
---|
491 | } |
---|
492 | |
---|
493 | |
---|
494 | /* msdos_set_dir_wrt_time_and_date -- |
---|
495 | * Write last write date and time for a file to the disk (to corresponded |
---|
496 | * 32bytes node) |
---|
497 | * |
---|
498 | * PARAMETERS: |
---|
499 | * mt_entry - mount table entry |
---|
500 | * fat_fd - fat-file descriptor |
---|
501 | * |
---|
502 | * RETURNS: |
---|
503 | * RC_OK on success, or -1 if error occured (errno set apropriately). |
---|
504 | * |
---|
505 | */ |
---|
506 | int |
---|
507 | msdos_set_dir_wrt_time_and_date( |
---|
508 | rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
509 | fat_file_fd_t *fat_fd |
---|
510 | ) |
---|
511 | { |
---|
512 | ssize_t ret1 = 0, ret2 = 0; |
---|
513 | msdos_fs_info_t *fs_info = mt_entry->fs_info; |
---|
514 | unsigned short time_val; |
---|
515 | unsigned short date; |
---|
516 | uint32_t sec = 0; |
---|
517 | uint32_t byte = 0; |
---|
518 | |
---|
519 | msdos_date_unix2dos(fat_fd->mtime, &time_val, &date); |
---|
520 | |
---|
521 | /* |
---|
522 | * calculate input for _fat_block_write: convert (cluster num, offset) to |
---|
523 | * (sector num, new offset) |
---|
524 | */ |
---|
525 | sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln); |
---|
526 | sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2); |
---|
527 | /* byte points to start of 32bytes structure */ |
---|
528 | byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1); |
---|
529 | |
---|
530 | time_val = CT_LE_W(time_val); |
---|
531 | ret1 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WTIME_OFFSET, |
---|
532 | 2, (char *)(&time_val)); |
---|
533 | date = CT_LE_W(date); |
---|
534 | ret2 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WDATE_OFFSET, |
---|
535 | 2, (char *)(&date)); |
---|
536 | |
---|
537 | if ( (ret1 < 0) || (ret2 < 0) ) |
---|
538 | return -1; |
---|
539 | |
---|
540 | return RC_OK; |
---|
541 | } |
---|
542 | |
---|
543 | /* msdos_set_first_cluster_num -- |
---|
544 | * Write number of first cluster of the file to the disk (to corresponded |
---|
545 | * 32bytes slot) |
---|
546 | * |
---|
547 | * PARAMETERS: |
---|
548 | * mt_entry - mount table entry |
---|
549 | * fat_fd - fat-file descriptor |
---|
550 | * |
---|
551 | * RETURNS: |
---|
552 | * RC_OK on success, or -1 if error occured |
---|
553 | * |
---|
554 | */ |
---|
555 | int |
---|
556 | msdos_set_first_cluster_num( |
---|
557 | rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
558 | fat_file_fd_t *fat_fd |
---|
559 | ) |
---|
560 | { |
---|
561 | ssize_t ret1 = 0, ret2 = 0; |
---|
562 | msdos_fs_info_t *fs_info = mt_entry->fs_info; |
---|
563 | uint32_t new_cln = fat_fd->cln; |
---|
564 | uint16_t le_cl_low = 0; |
---|
565 | uint16_t le_cl_hi = 0; |
---|
566 | uint32_t sec = 0; |
---|
567 | uint32_t byte = 0; |
---|
568 | |
---|
569 | /* |
---|
570 | * calculate input for _fat_block_write: convert (cluster num, offset) to |
---|
571 | * (sector num, new offset) |
---|
572 | */ |
---|
573 | sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln); |
---|
574 | sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2); |
---|
575 | /* byte from points to start of 32bytes structure */ |
---|
576 | byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1); |
---|
577 | |
---|
578 | le_cl_low = CT_LE_W((uint16_t )(new_cln & 0x0000FFFF)); |
---|
579 | ret1 = _fat_block_write(mt_entry, sec, |
---|
580 | byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2, |
---|
581 | (char *)(&le_cl_low)); |
---|
582 | le_cl_hi = CT_LE_W((uint16_t )((new_cln & 0xFFFF0000) >> 16)); |
---|
583 | ret2 = _fat_block_write(mt_entry, sec, |
---|
584 | byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2, |
---|
585 | (char *)(&le_cl_hi)); |
---|
586 | if ( (ret1 < 0) || (ret2 < 0) ) |
---|
587 | return -1; |
---|
588 | |
---|
589 | return RC_OK; |
---|
590 | } |
---|
591 | |
---|
592 | |
---|
593 | /* msdos_set_file size -- |
---|
594 | * Write file size of the file to the disk (to corresponded 32bytes slot) |
---|
595 | * |
---|
596 | * PARAMETERS: |
---|
597 | * mt_entry - mount table entry |
---|
598 | * fat_fd - fat-file descriptor |
---|
599 | * |
---|
600 | * RETURNS: |
---|
601 | * RC_OK on success, or -1 if error occured (errno set apropriately). |
---|
602 | * |
---|
603 | */ |
---|
604 | int |
---|
605 | msdos_set_file_size( |
---|
606 | rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
607 | fat_file_fd_t *fat_fd |
---|
608 | ) |
---|
609 | { |
---|
610 | ssize_t ret = 0; |
---|
611 | msdos_fs_info_t *fs_info = mt_entry->fs_info; |
---|
612 | uint32_t le_new_length = 0; |
---|
613 | uint32_t sec = 0; |
---|
614 | uint32_t byte = 0; |
---|
615 | |
---|
616 | sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln); |
---|
617 | sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2); |
---|
618 | byte = (fat_fd->info_ofs & (fs_info->fat.vol.bps - 1)); |
---|
619 | |
---|
620 | le_new_length = CT_LE_L((fat_fd->fat_file_size)); |
---|
621 | ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4, |
---|
622 | (char *)(&le_new_length)); |
---|
623 | if ( ret < 0 ) |
---|
624 | return -1; |
---|
625 | |
---|
626 | return RC_OK; |
---|
627 | } |
---|
628 | |
---|
629 | /* |
---|
630 | * We should not check whether this routine is called for root dir - it |
---|
631 | * never can happend |
---|
632 | */ |
---|
633 | |
---|
634 | /* msdos_set_first_char4file_name -- |
---|
635 | * Write first character of the name of the file to the disk (to |
---|
636 | * corresponded 32bytes slot) |
---|
637 | * |
---|
638 | * PARAMETERS: |
---|
639 | * mt_entry - mount table entry |
---|
640 | * cl - number of cluster |
---|
641 | * ofs - offset inside cluster |
---|
642 | * fchar - character to set up |
---|
643 | * |
---|
644 | * RETURNS: |
---|
645 | * RC_OK on success, or -1 if error occured (errno set apropriately) |
---|
646 | * |
---|
647 | */ |
---|
648 | int |
---|
649 | msdos_set_first_char4file_name( |
---|
650 | rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
651 | uint32_t cl, |
---|
652 | uint32_t ofs, |
---|
653 | unsigned char fchar |
---|
654 | ) |
---|
655 | { |
---|
656 | ssize_t ret = 0; |
---|
657 | msdos_fs_info_t *fs_info = mt_entry->fs_info; |
---|
658 | uint32_t sec = 0; |
---|
659 | uint32_t byte = 0; |
---|
660 | |
---|
661 | sec = fat_cluster_num_to_sector_num(mt_entry, cl); |
---|
662 | sec += (ofs >> fs_info->fat.vol.sec_log2); |
---|
663 | byte = (ofs & (fs_info->fat.vol.bps - 1)); |
---|
664 | |
---|
665 | ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1, |
---|
666 | &fchar); |
---|
667 | if ( ret < 0) |
---|
668 | return -1; |
---|
669 | |
---|
670 | return RC_OK; |
---|
671 | } |
---|
672 | |
---|
673 | /* msdos_dir_is_empty -- |
---|
674 | * Check whether directory which correspondes to the fat-file descriptor is |
---|
675 | * empty. |
---|
676 | * |
---|
677 | * PARAMETERS: |
---|
678 | * mt_entry - mount table entry |
---|
679 | * fat_fd - fat-file descriptor |
---|
680 | * ret_val - placeholder for result |
---|
681 | * |
---|
682 | * RETURNS: |
---|
683 | * RC_OK on success, or -1 if error occured |
---|
684 | * |
---|
685 | */ |
---|
686 | int |
---|
687 | msdos_dir_is_empty( |
---|
688 | rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
689 | fat_file_fd_t *fat_fd, |
---|
690 | rtems_boolean *ret_val |
---|
691 | ) |
---|
692 | { |
---|
693 | ssize_t ret = 0; |
---|
694 | msdos_fs_info_t *fs_info = mt_entry->fs_info; |
---|
695 | uint32_t j = 0, i = 0; |
---|
696 | |
---|
697 | /* dir is not empty */ |
---|
698 | *ret_val = FALSE; |
---|
699 | |
---|
700 | while ((ret = fat_file_read(mt_entry, fat_fd, j * fs_info->fat.vol.bps, |
---|
701 | fs_info->fat.vol.bps, |
---|
702 | fs_info->cl_buf)) != FAT_EOF) |
---|
703 | { |
---|
704 | if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) |
---|
705 | return -1; |
---|
706 | |
---|
707 | assert(ret == fs_info->fat.vol.bps); |
---|
708 | |
---|
709 | for (i = 0; |
---|
710 | i < fs_info->fat.vol.bps; |
---|
711 | i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) |
---|
712 | { |
---|
713 | if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == |
---|
714 | MSDOS_THIS_DIR_ENTRY_EMPTY) || |
---|
715 | (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME, |
---|
716 | MSDOS_SHORT_NAME_LEN) == 0) || |
---|
717 | (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), |
---|
718 | MSDOS_DOTDOT_NAME, |
---|
719 | MSDOS_SHORT_NAME_LEN) == 0)) |
---|
720 | continue; |
---|
721 | |
---|
722 | if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == |
---|
723 | MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) |
---|
724 | { |
---|
725 | *ret_val = TRUE; |
---|
726 | return RC_OK; |
---|
727 | } |
---|
728 | return RC_OK; |
---|
729 | } |
---|
730 | j++; |
---|
731 | } |
---|
732 | *ret_val = TRUE; |
---|
733 | return RC_OK; |
---|
734 | } |
---|
735 | |
---|
736 | |
---|
737 | /* msdos_find_name_in_fat_file -- |
---|
738 | * This routine is used in two ways: for a new mode creation (a) or for |
---|
739 | * search the node which correspondes to the 'name' parameter (b). |
---|
740 | * In case (a) name should be set up to NULL and 'name_dir_entry' should |
---|
741 | * point to initialized 32 bytes structure described a new node. |
---|
742 | * In case (b) 'name' should contain a valid string. |
---|
743 | * |
---|
744 | * (a): reading fat-file corresponded to directory we are going to create |
---|
745 | * node in. If found free slot write contents of name_dir_entry into |
---|
746 | * it. |
---|
747 | * |
---|
748 | * (b): reading fat-file corresponded to directory and trying to find slot |
---|
749 | * with the name field == name parameter |
---|
750 | * |
---|
751 | * PARAMETERS: |
---|
752 | * mt_entry - mount table entry |
---|
753 | * fat_fd - fat-file descriptor |
---|
754 | * name - NULL or name to find |
---|
755 | * paux - identify a node location on the disk - |
---|
756 | * number of cluster and offset inside the cluster |
---|
757 | * name_dir_entry - node to create/placeholder for found node |
---|
758 | * |
---|
759 | * RETURNS: |
---|
760 | * RC_OK on success, or error code if error occured (errno set |
---|
761 | * appropriately) |
---|
762 | * |
---|
763 | */ |
---|
764 | int |
---|
765 | msdos_find_name_in_fat_file( |
---|
766 | rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
767 | fat_file_fd_t *fat_fd, |
---|
768 | char *name, |
---|
769 | fat_auxiliary_t *paux, |
---|
770 | char *name_dir_entry |
---|
771 | ) |
---|
772 | { |
---|
773 | int rc = RC_OK; |
---|
774 | ssize_t ret = 0; |
---|
775 | msdos_fs_info_t *fs_info = mt_entry->fs_info; |
---|
776 | uint32_t i = 0, j = 0; |
---|
777 | uint32_t bts2rd = 0; |
---|
778 | |
---|
779 | if (FAT_FD_OF_ROOT_DIR(fat_fd) && |
---|
780 | (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) |
---|
781 | bts2rd = fat_fd->fat_file_size; |
---|
782 | else |
---|
783 | bts2rd = fs_info->fat.vol.bpc; |
---|
784 | |
---|
785 | while ((ret = fat_file_read(mt_entry, fat_fd, (j * bts2rd), bts2rd, |
---|
786 | fs_info->cl_buf)) != FAT_EOF) |
---|
787 | { |
---|
788 | if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) |
---|
789 | set_errno_and_return_minus_one(EIO); |
---|
790 | |
---|
791 | assert(ret == bts2rd); |
---|
792 | |
---|
793 | for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) |
---|
794 | { |
---|
795 | /* is the entry empty ? */ |
---|
796 | if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == |
---|
797 | MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) || |
---|
798 | ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == |
---|
799 | MSDOS_THIS_DIR_ENTRY_EMPTY)) |
---|
800 | { |
---|
801 | /* whether we are looking for an empty entry */ |
---|
802 | if (name == NULL) |
---|
803 | { |
---|
804 | /* get current cluster number */ |
---|
805 | rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, |
---|
806 | j * bts2rd, &paux->cln); |
---|
807 | if (rc != RC_OK) |
---|
808 | return rc; |
---|
809 | |
---|
810 | /* offset is computed in bytes */ |
---|
811 | paux->ofs = i; |
---|
812 | |
---|
813 | /* write new node entry */ |
---|
814 | ret = fat_file_write(mt_entry, fat_fd, j * bts2rd + i, |
---|
815 | MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE, |
---|
816 | name_dir_entry); |
---|
817 | if (ret != MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) |
---|
818 | return -1; |
---|
819 | |
---|
820 | /* |
---|
821 | * we don't update fat_file_size here - it should not |
---|
822 | * increase |
---|
823 | */ |
---|
824 | return RC_OK; |
---|
825 | } |
---|
826 | |
---|
827 | /* |
---|
828 | * if name != NULL and there is no more entries in the |
---|
829 | * directory - return name-not-found |
---|
830 | */ |
---|
831 | if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == |
---|
832 | MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)) |
---|
833 | return MSDOS_NAME_NOT_FOUND_ERR; |
---|
834 | } |
---|
835 | else |
---|
836 | { |
---|
837 | /* entry not empty and name != NULL -> compare names */ |
---|
838 | if (name != NULL) |
---|
839 | { |
---|
840 | if (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), name, |
---|
841 | MSDOS_SHORT_NAME_LEN) == 0) |
---|
842 | { |
---|
843 | /* |
---|
844 | * we get the entry we looked for - fill auxiliary |
---|
845 | * structure and copy all 32 bytes of the entry |
---|
846 | */ |
---|
847 | rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, |
---|
848 | j * bts2rd, &paux->cln); |
---|
849 | if (rc != RC_OK) |
---|
850 | return rc; |
---|
851 | |
---|
852 | /* offset is computed in bytes */ |
---|
853 | paux->ofs = i; |
---|
854 | memcpy(name_dir_entry,(fs_info->cl_buf + i), |
---|
855 | MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); |
---|
856 | return RC_OK; |
---|
857 | } |
---|
858 | } |
---|
859 | } |
---|
860 | } |
---|
861 | j++; |
---|
862 | } |
---|
863 | return MSDOS_NAME_NOT_FOUND_ERR; |
---|
864 | } |
---|
865 | |
---|
866 | /* msdos_find_node_by_cluster_num_in_fat_file -- |
---|
867 | * Find node with specified number of cluster in fat-file. |
---|
868 | * |
---|
869 | * PARAMETERS: |
---|
870 | * mt_entry - mount table entry |
---|
871 | * fat_fd - fat-file descriptor |
---|
872 | * cl4find - number of cluster to find |
---|
873 | * paux - identify a node location on the disk - |
---|
874 | * cluster num and offset inside the cluster |
---|
875 | * dir_entry - placeholder for found node |
---|
876 | * |
---|
877 | * RETURNS: |
---|
878 | * RC_OK on success, or error code if error occured |
---|
879 | * |
---|
880 | */ |
---|
881 | int |
---|
882 | msdos_find_node_by_cluster_num_in_fat_file( |
---|
883 | rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
884 | fat_file_fd_t *fat_fd, |
---|
885 | uint32_t cl4find, |
---|
886 | fat_auxiliary_t *paux, |
---|
887 | char *dir_entry |
---|
888 | ) |
---|
889 | { |
---|
890 | int rc = RC_OK; |
---|
891 | ssize_t ret = 0; |
---|
892 | msdos_fs_info_t *fs_info = mt_entry->fs_info; |
---|
893 | uint32_t bts2rd = 0; |
---|
894 | uint32_t i = 0, j = 0; |
---|
895 | |
---|
896 | if (FAT_FD_OF_ROOT_DIR(fat_fd) && |
---|
897 | (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) |
---|
898 | bts2rd = fat_fd->fat_file_size; |
---|
899 | else |
---|
900 | bts2rd = fs_info->fat.vol.bpc; |
---|
901 | |
---|
902 | while ((ret = fat_file_read(mt_entry, fat_fd, j * bts2rd, bts2rd, |
---|
903 | fs_info->cl_buf)) != FAT_EOF) |
---|
904 | { |
---|
905 | if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE ) |
---|
906 | set_errno_and_return_minus_one( EIO ); |
---|
907 | |
---|
908 | assert(ret == bts2rd); |
---|
909 | |
---|
910 | for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) |
---|
911 | { |
---|
912 | /* if this and all rest entries are empty - return not-found */ |
---|
913 | if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == |
---|
914 | MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) |
---|
915 | return MSDOS_NAME_NOT_FOUND_ERR; |
---|
916 | |
---|
917 | /* if this entry is empty - skip it */ |
---|
918 | if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == |
---|
919 | MSDOS_THIS_DIR_ENTRY_EMPTY) |
---|
920 | continue; |
---|
921 | |
---|
922 | /* if get a non-empty entry - compare clusters num */ |
---|
923 | if (MSDOS_EXTRACT_CLUSTER_NUM((fs_info->cl_buf + i)) == cl4find) |
---|
924 | { |
---|
925 | /* on success fill aux structure and copy all 32 bytes */ |
---|
926 | rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, j * bts2rd, |
---|
927 | &paux->cln); |
---|
928 | if (rc != RC_OK) |
---|
929 | return rc; |
---|
930 | |
---|
931 | paux->ofs = i; |
---|
932 | memcpy(dir_entry, fs_info->cl_buf + i, |
---|
933 | MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); |
---|
934 | return RC_OK; |
---|
935 | } |
---|
936 | } |
---|
937 | j++; |
---|
938 | } |
---|
939 | return MSDOS_NAME_NOT_FOUND_ERR; |
---|
940 | } |
---|