source: rtems/cpukit/libfs/src/dosfs/msdos_misc.c @ f36a7bfc

4.104.114.84.95
Last change on this file since f36a7bfc was f36a7bfc, checked in by Joel Sherrill <joel.sherrill@…>, on 02/28/02 at 20:43:50

2002-02-28 Victor V. Vengerov <vvv@…>

  • DOS filesystem including FAT12, FAT16, and FAT32 support submitted.
  • src/dosfs, src/dosfs/Makefile.am, src/dosfs/stamp-h2.in, src/dosfs/config.h.in, src/dosfs/dosfs.h, src/dosfs/fat.c, src/dosfs/fat.h, src/dosfs/fat_fat_operations.c, src/dosfs/fat_fat_operations.h, src/dosfs/fat_file.c, src/dosfs/fat_file.h, src/dosfs/msdos.h, src/dosfs/msdos_create.c, src/dosfs/msdos_dir.c, src/dosfs/msdos_eval.c, src/dosfs/msdos_file.c, src/dosfs/msdos_free.c, src/dosfs/msdos_fsunmount.c, src/dosfs/msdos_handlers_dir.c, src/dosfs/msdos_handlers_file.c, src/dosfs/msdos_init.c, src/dosfs/msdos_initsupp.c, src/dosfs/msdos_misc.c, src/dosfs/msdos_mknod.c, src/dosfs/msdos_node_type.c, src/dosfs/.cvsignore: New files.
  • configure.ac, src/Makefile.am, wrapup/Makefile.am: Modified to reflect addition.
  • Property mode set to 100644
File size: 34.1 KB
Line 
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 */
32static 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" */
38static 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
46static char bad_chars[] = "*?<>|\"";
47#ifdef CONFIG_ATARI
48/* GEMDOS is less restrictive */
49static char bad_if_strict[] = " ";
50#else
51static 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 */
62int
63msdos_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) */
133unsigned int
134msdos_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 */
151void 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 */
188msdos_token_types_t
189msdos_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 */
276int
277msdos_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 */
400int
401msdos_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 */
522int
523msdos_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 */
653int
654msdos_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 */
702int
703msdos_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 */
751int
752msdos_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 */
795int
796msdos_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 */
833int
834msdos_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 */
911int
912msdos_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 */
1028int
1029msdos_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}
Note: See TracBrowser for help on using the repository browser.