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