source: rtems/cpukit/libfs/src/dosfs/msdos_conv.c @ 07d6fd5

4.104.115
Last change on this file since 07d6fd5 was 07d6fd5, checked in by Chris Johns <chrisj@…>, on 04/29/09 at 08:31:27

2009-04-29 Chris Johns <chrisj@…>

  • libcsupport/include/rtems/libio.h: Add rtems_off64_t for internal use. Update the internal off_t to the 64bit offset.
  • libnetworking/lib/ftpfs.c, libnetworking/lib/tftpDriver.c, libfs/src/nfsclient/src/nfs.c, libfs/src/imfs/imfs_fifo.c, libfs/src/imfs/memfile.c, libfs/src/imfs/imfs_directory.c, libfs/src/imfs/imfs.h, libfs/src/imfs/deviceio.c: Change off_t to rtems_off64_t.
  • libmisc/shell/main_msdosfmt.c: Add an info level so the format code can tell the user what is happening. Add more options to control the format configuration.
  • libfs/src/dosfs/msdos_format.c: Add a print function to display the format progress and print statements. Select a better default cluster size depending on the size of the disk. This lowers the size of the FAT on large disks. Read and maintain the MRB partition information.
  • libfs/src/dosfs/dosfs.h, libfs/src/dosfs/fat.h, libfs/src/dosfs/fat_file.c, libfs/src/dosfs/fat_file.h, libfs/src/dosfs/msdos.h, libfs/src/dosfs/msdos_conv.c, libfs/src/dosfs/msdos_create.c, libfs/src/dosfs/msdos_file.c, libfs/src/dosfs/msdos_handlers_dir.c, libfs/src/dosfs/msdos_handlers_file.c, libfs/src/dosfs/msdos_init.c, libfs/src/dosfs/msdos_initsupp.c, libfs/src/dosfs/msdos_misc.c, libfs/src/dosfs/msdos_mknod.c: Add long file name support. Change off_t to rtems_off64_t.
  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 * Adaptation of NetBSD code for RTEMS by Victor V. Vengerov <vvv@oktet.ru>
3 */
4/*      $NetBSD: msdosfs_conv.c,v 1.10 1994/12/27 18:36:24 mycroft Exp $        */
5/*
6 * Written by Paul Popelka (paulp@uts.amdahl.com)
7 *
8 * You can do anything you want with this software, just don't say you wrote
9 * it, and don't remove this notice.
10 *
11 * This software is provided "as is".
12 *
13 * The author supplies this software to be publicly redistributed on the
14 * understanding that the author is not responsible for the correct
15 * functioning of this software in any circumstances and is not liable for
16 * any damages caused by this software.
17 *
18 * October 1992
19 */
20
21#if HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include <rtems.h>
26#include "msdos.h"
27
28/* #define SECONDSPERDAY (24 * 60 * 60) */
29#define SECONDSPERDAY ((uint32_t) 86400)
30
31/*
32 * Days in each month in a regular year.
33 */
34static uint16_t regyear[] = {
35        31, 28, 31, 30, 31, 30,
36        31, 31, 30, 31, 30, 31
37};
38
39/*
40 * Days in each month in a leap year.
41 */
42static uint16_t leapyear[] = {
43        31, 29, 31, 30, 31, 30,
44        31, 31, 30, 31, 30, 31
45};
46
47/*
48 * Variables used to remember parts of the last time conversion.  Maybe we
49 * can avoid a full conversion.
50 */
51static uint32_t lasttime;
52static uint32_t lastday;
53static uint16_t lastddate;
54static uint16_t lastdtime;
55
56/*
57 * Convert the unix version of time to dos's idea of time to be used in
58 * file timestamps. The passed in unix time is assumed to be in GMT.
59 */
60void
61msdos_date_unix2dos(unsigned int t, unsigned short *ddp,
62                    unsigned short *dtp)
63{
64        uint32_t days;
65        uint32_t inc;
66        uint32_t year;
67        uint32_t month;
68        uint16_t *months;
69
70        /*
71         * If the time from the last conversion is the same as now, then
72         * skip the computations and use the saved result.
73         */
74        if (lasttime != t) {
75                lasttime = t;
76                lastdtime = (((t % 60) >> 1) << MSDOS_DT_2SECONDS_SHIFT)
77                    + (((t / 60) % 60) << MSDOS_DT_MINUTES_SHIFT)
78                    + (((t / 3600) % 24) << MSDOS_DT_HOURS_SHIFT);
79
80                /*
81                 * If the number of days since 1970 is the same as the last
82                 * time we did the computation then skip all this leap year
83                 * and month stuff.
84                 */
85                days = t / (SECONDSPERDAY);
86                if (days != lastday) {
87                        lastday = days;
88                        for (year = 1970;; year++) {
89                                inc = year & 0x03 ? 365 : 366;
90                                if (days < inc)
91                                        break;
92                                days -= inc;
93                        }
94                        months = year & 0x03 ? regyear : leapyear;
95                        for (month = 0; month < 12; month++) {
96                                if (days < months[month])
97                                        break;
98                                days -= months[month];
99                        }
100                        lastddate = ((days + 1) << MSDOS_DD_DAY_SHIFT)
101                            + ((month + 1) << MSDOS_DD_MONTH_SHIFT);
102                        /*
103                         * Remember dos's idea of time is relative to 1980.
104                         * unix's is relative to 1970.  If somehow we get a
105                         * time before 1980 then don't give totally crazy
106                         * results.
107                         */
108                        if (year > 1980)
109                                lastddate += (year - 1980) <<
110                                             MSDOS_DD_YEAR_SHIFT;
111                }
112        }
113        *dtp = lastdtime;
114        *ddp = lastddate;
115}
116
117/*
118 * The number of days between Jan 1, 1970 and Jan 1, 1980. In that
119 * interval there were 8 regular years and 2 leap years.
120 */
121/* #define      DAYSTO1980      ((8 * 365) + (2 * 366)) */
122#define DAYSTO1980   ((uint32_t) 3652)
123
124static uint16_t lastdosdate;
125static uint32_t lastseconds;
126
127/*
128 * Convert from dos' idea of time to unix'. This will probably only be
129 * called from the stat(), and fstat() system calls and so probably need
130 * not be too efficient.
131 */
132unsigned int
133msdos_date_dos2unix(unsigned int dd, unsigned int dt)
134{
135        uint32_t seconds;
136        uint32_t m, month;
137        uint32_t y, year;
138        uint32_t days;
139        uint16_t *months;
140
141        seconds = ((dt & MSDOS_DT_2SECONDS_MASK) >> MSDOS_DT_2SECONDS_SHIFT)
142            + ((dt & MSDOS_DT_MINUTES_MASK) >> MSDOS_DT_MINUTES_SHIFT) * 60
143            + ((dt & MSDOS_DT_HOURS_MASK) >> MSDOS_DT_HOURS_SHIFT) * 3600;
144        /*
145         * If the year, month, and day from the last conversion are the
146         * same then use the saved value.
147         */
148        if (lastdosdate != dd) {
149                lastdosdate = dd;
150                days = 0;
151                year = (dd & MSDOS_DD_YEAR_MASK) >> MSDOS_DD_YEAR_SHIFT;
152                for (y = 0; y < year; y++)
153                        days += y & 0x03 ? 365 : 366;
154                months = year & 0x03 ? regyear : leapyear;
155                /*
156                 * Prevent going from 0 to 0xffffffff in the following
157                 * loop.
158                 */
159                month = (dd & MSDOS_DD_MONTH_MASK) >> MSDOS_DD_MONTH_SHIFT;
160                if (month == 0) {
161                        month = 1;
162                }
163                for (m = 0; m < month - 1; m++)
164                        days += months[m];
165                days += ((dd & MSDOS_DD_DAY_MASK) >> MSDOS_DD_DAY_SHIFT) - 1;
166                lastseconds = (days + DAYSTO1980) * SECONDSPERDAY;
167        }
168        return seconds + lastseconds;
169}
170
171static const uint8_t msdos_map[] = {
172    0,    0,    0,    0,    0,    0,    0,    0,    /* 00-07 */
173    0,    0,    0,    0,    0,    0,    0,    0,    /* 08-0f */
174    0,    0,    0,    0,    0,    0,    0,    0,    /* 10-17 */
175    0,    0,    0,    0,    0,    0,    0,    0,    /* 18-1f */
176    0,    '!',  0,    '#',  '$',  '%',  '&',  '\'', /* 20-27 */
177    '(',  ')',  0,    '+',  0,    '-',  0,    0,    /* 28-2f */
178    '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  /* 30-37 */
179    '8',  '9',  0,    0,    0,    0,    0,    0,    /* 38-3f */
180    '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  /* 40-47 */
181    'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  /* 48-4f */
182    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  /* 50-57 */
183    'X',  'Y',  'Z',  0,    0,    0,    '^',  '_',  /* 58-5f */
184    '`',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  /* 60-67 */
185    'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  /* 68-6f */
186    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  /* 70-77 */
187    'X',  'Y',  'Z',  '{',  0,    '}',  '~',  0,    /* 78-7f */
188    0,    0,    0,    0,    0,    0,    0,    0,    /* 80-87 */
189    0,    0,    0,    0,    0,    0,    0,    0,    /* 88-8f */
190    0,    0,    0,    0,    0,    0,    0,    0,    /* 90-97 */
191    0,    0,    0,    0,    0,    0,    0,    0,    /* 98-9f */
192    0,    0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */
193    0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */
194    0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */
195    0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */
196    0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */
197    0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */
198    0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */
199    0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */
200    0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */
201    0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */
202    0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */
203    0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */
204#if OLD_TABLE
205/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206/* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207/* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208/* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209/* 20 */ 0x00, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, /*  !"#$%&' */
210/* 28 */ 0x28, 0x29, 0x00, 0x00, 0x00, 0x2D, 0x2E, 0x00, /* ()*+,-./ */
211/* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 01234567 */
212/* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 89:;<=>? */
213/* 40 */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
214/* 48 */ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* HIJKLMNO */
215/* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* PQRSTUVW */
216/* 58 */ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x00, 0x5E, 0x5F, /* XYZ[\]^_ */
217/* 60 */ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */
218/* 68 */ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* hijklmno */
219/* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* pqrstuvw */
220/* 78 */ 0x58, 0x59, 0x5A, 0x5B, 0x7C, 0x00, 0x7E, 0x00, /* xyz{|}~  */
221/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222/* 88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223/* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224/* 98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225/* A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226/* A8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227/* B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228/* B8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229/* C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230/* C8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231/* D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232/* D8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233/* E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234/* E8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235/* F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236/* F8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237#endif
238};
239/*
240 * Convert a unix filename to a DOS filename. Return -1 if wrong name is
241 * supplied.
242 */
243int
244msdos_filename_unix2dos(const char *un, int unlen, char *dn)
245{
246        int i;
247        uint8_t c;
248
249        /*
250         * Fill the dos filename string with blanks. These are DOS's pad
251         * characters.
252         */
253        for (i = 0; i <= 10; i++)
254                dn[i] = ' ';
255
256        /*
257         * The filenames "." and ".." are handled specially, since they
258         * don't follow dos filename rules.
259         */
260        if (un[0] == '.' && unlen == 1) {
261                dn[0] = '.';
262                return 0;
263        }
264        if (un[0] == '.' && un[1] == '.' && unlen == 2) {
265                dn[0] = '.';
266                dn[1] = '.';
267                return 0;
268        }
269
270  /*
271   * Remove any dots from the start of a file name.
272   */
273        while (unlen && (*un == '.')) {
274                un++;
275                unlen--;
276        }
277 
278        /*
279         * Copy the unix filename into the dos filename string upto the end
280         * of string, a '.', or 8 characters. Whichever happens first stops
281         * us. This forms the name portion of the dos filename. Fold to
282         * upper case.
283         */
284        for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
285    if (msdos_map[c] == 0)
286      break;
287                dn[i] = msdos_map[c];
288                un++;
289                unlen--;
290        }
291
292        /*
293         * Strip any further characters up to a '.' or the end of the
294         * string.
295         */
296        while (unlen && (c = *un)) {
297                un++;
298                unlen--;
299                /* Make sure we've skipped over the dot before stopping. */
300                if (c == '.')
301                        break;
302        }
303
304        /*
305         * Copy in the extension part of the name, if any. Force to upper
306         * case. Note that the extension is allowed to contain '.'s.
307         * Filenames in this form are probably inaccessable under dos.
308         */
309        for (i = 8; i <= 10 && unlen && (c = *un); i++) {
310    if (msdos_map[c] == 0)
311      break;
312    dn[i] = msdos_map[c];
313                un++;
314                unlen--;
315        }
316        return 0;
317}
Note: See TracBrowser for help on using the repository browser.