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

4.115
Last change on this file since d2e0bb3 was d2e0bb3, checked in by Ralf Kirchner <ralf.kirchner@…>, on May 22, 2013 at 10:16:18 AM

dosfs: UTF-8 Support: UI, backwards compatibility

User interface and backwards compatibility for UTF-8 support in the FAT
file system. Purpose of UTF-8 support is to permit file names and
directory names with characters from all kinds of languages (Czech,
Chinese, Arabian, Hebrew, Korean, ...). This commit does not yet
support multibyte characters. It only contains the user interface and
the backwards compatibility.

  • Property mode set to 100644
File size: 19.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief MDOS Date Conversion
5 * @ingroup libfs_msdos MSDOS FileSystem
6 */
7
8/*
9 * Written by Paul Popelka (paulp@uts.amdahl.com)
10 *
11 * You can do anything you want with this software, just don't say you wrote
12 * it, and don't remove this notice.
13 *
14 * This software is provided "as is".
15 *
16 * The author supplies this software to be publicly redistributed on the
17 * understanding that the author is not responsible for the correct
18 * functioning of this software in any circumstances and is not liable for
19 * any damages caused by this software.
20 *
21 * Adaptation of NetBSD code for RTEMS by Victor V. Vengerov <vvv@oktet.ru>
22 * $NetBSD: msdosfs_conv.c,v 1.10 1994/12/27 18:36:24 mycroft Exp $
23 *
24 * October 1992
25 *
26 * Modifications to support UTF-8 in the file system are
27 * Copyright (c) 2013 embedded brains GmbH.
28 */
29
30#if HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include <ctype.h>
35#include <rtems.h>
36#include "msdos.h"
37
38/* #define SECONDSPERDAY (24 * 60 * 60) */
39#define SECONDSPERDAY ((uint32_t) 86400)
40
41#define UTF8_MAX_CHAR_SIZE    4
42#define UTF8_NULL             0x00
43#define UTF8_NULL_SIZE        1
44#define UTF8_BLANK            0x20
45#define UTF8_BLANK_SIZE       1
46#define UTF8_FULL_STOP        0x2e
47#define UTF8_FULL_STOP_SIZE   1
48
49#define UTF16_MAX_CHAR_SIZE   4
50#define UTF16_NULL            CT_LE_W( 0x0000 )
51#define UTF16_NULL_SIZE       2
52#define UTF16_BLANK           CT_LE_W( 0x0020 )
53#define UTF16_BLANK_SIZE      2
54#define UTF16_FULL_STOP       CT_LE_W( 0x002e )
55#define UTF16_FULL_STOP_SIZE  2
56
57/*
58 * Days in each month in a regular year.
59 */
60static uint16_t regyear[] = {
61        31, 28, 31, 30, 31, 30,
62        31, 31, 30, 31, 30, 31
63};
64
65/*
66 * Days in each month in a leap year.
67 */
68static uint16_t leapyear[] = {
69        31, 29, 31, 30, 31, 30,
70        31, 31, 30, 31, 30, 31
71};
72
73/*
74 * Variables used to remember parts of the last time conversion.  Maybe we
75 * can avoid a full conversion.
76 */
77static uint32_t lasttime;
78static uint32_t lastday;
79static uint16_t lastddate;
80static uint16_t lastdtime;
81
82/*
83 * Convert the unix version of time to dos's idea of time to be used in
84 * file timestamps. The passed in unix time is assumed to be in GMT.
85 */
86void
87msdos_date_unix2dos(unsigned int t, uint16_t *ddp,
88                    uint16_t *dtp)
89{
90        uint32_t days;
91        uint32_t inc;
92        uint32_t year;
93        uint32_t month;
94        uint16_t *months;
95
96        /*
97         * If the time from the last conversion is the same as now, then
98         * skip the computations and use the saved result.
99         */
100        if (lasttime != t) {
101                lasttime = t;
102                lastdtime = (((t % 60) >> 1) << MSDOS_DT_2SECONDS_SHIFT)
103                    + (((t / 60) % 60) << MSDOS_DT_MINUTES_SHIFT)
104                    + (((t / 3600) % 24) << MSDOS_DT_HOURS_SHIFT);
105
106                /*
107                 * If the number of days since 1970 is the same as the last
108                 * time we did the computation then skip all this leap year
109                 * and month stuff.
110                 */
111                days = t / (SECONDSPERDAY);
112                if (days != lastday) {
113                        lastday = days;
114                        for (year = 1970;; year++) {
115                                inc = year & 0x03 ? 365 : 366;
116                                if (days < inc)
117                                        break;
118                                days -= inc;
119                        }
120                        months = year & 0x03 ? regyear : leapyear;
121                        for (month = 0; month < 12; month++) {
122                                if (days < months[month])
123                                        break;
124                                days -= months[month];
125                        }
126                        lastddate = ((days + 1) << MSDOS_DD_DAY_SHIFT)
127                            + ((month + 1) << MSDOS_DD_MONTH_SHIFT);
128                        /*
129                         * Remember dos's idea of time is relative to 1980.
130                         * unix's is relative to 1970.  If somehow we get a
131                         * time before 1980 then don't give totally crazy
132                         * results.
133                         */
134                        if (year > 1980)
135                                lastddate += (year - 1980) <<
136                                             MSDOS_DD_YEAR_SHIFT;
137                }
138        }
139        *dtp = lastdtime;
140        *ddp = lastddate;
141}
142
143/*
144 * The number of days between Jan 1, 1970 and Jan 1, 1980. In that
145 * interval there were 8 regular years and 2 leap years.
146 */
147/* #define      DAYSTO1980      ((8 * 365) + (2 * 366)) */
148#define DAYSTO1980   ((uint32_t) 3652)
149
150static uint16_t lastdosdate;
151static uint32_t lastseconds;
152
153/*
154 * Convert from dos' idea of time to unix'. This will probably only be
155 * called from the stat(), and fstat() system calls and so probably need
156 * not be too efficient.
157 */
158unsigned int
159msdos_date_dos2unix(unsigned int dd, unsigned int dt)
160{
161        uint32_t seconds;
162        uint32_t m, month;
163        uint32_t y, year;
164        uint32_t days;
165        uint16_t *months;
166
167        seconds = 2 * ((dt & MSDOS_DT_2SECONDS_MASK) >> MSDOS_DT_2SECONDS_SHIFT)
168            + ((dt & MSDOS_DT_MINUTES_MASK) >> MSDOS_DT_MINUTES_SHIFT) * 60
169            + ((dt & MSDOS_DT_HOURS_MASK) >> MSDOS_DT_HOURS_SHIFT) * 3600;
170        /*
171         * If the year, month, and day from the last conversion are the
172         * same then use the saved value.
173         */
174        if (lastdosdate != dd) {
175                lastdosdate = dd;
176                days = 0;
177                year = (dd & MSDOS_DD_YEAR_MASK) >> MSDOS_DD_YEAR_SHIFT;
178                for (y = 0; y < year; y++)
179                        days += y & 0x03 ? 365 : 366;
180                months = year & 0x03 ? regyear : leapyear;
181                /*
182                 * Prevent going from 0 to 0xffffffff in the following
183                 * loop.
184                 */
185                month = (dd & MSDOS_DD_MONTH_MASK) >> MSDOS_DD_MONTH_SHIFT;
186                if (month == 0) {
187                        month = 1;
188                }
189                for (m = 0; m < month - 1; m++)
190                        days += months[m];
191                days += ((dd & MSDOS_DD_DAY_MASK) >> MSDOS_DD_DAY_SHIFT) - 1;
192                lastseconds = (days + DAYSTO1980) * SECONDSPERDAY;
193        }
194        return seconds + lastseconds;
195}
196
197
198static const uint8_t codepage_valid_char_map[] = {
199    0,    0,    0,    0,    0,    0,    0,    0,    /* 00-07 */
200    0,    0,    0,    0,    0,    0,    0,    0,    /* 08-0f */
201    0,    0,    0,    0,    0,    0,    0,    0,    /* 10-17 */
202    0,    0,    0,    0,    0,    0,    0,    0,    /* 18-1f */
203    0x20, 0x21, 0,    0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
204    0x28, 0x29, 0,    0,    0,    0x2d,  0,    0,   /* 28-2f */
205    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
206    0x38, 0x39, 0,    0,    0,    0,    0,    0,    /* 38-3f */
207    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
208    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
209    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
210    0x58, 0x59, 0x5a, 0,    0,    0,    0x5e, 0x5f, /* 58-5f */
211    0x60, 0,    0,    0,    0,    0,    0,    0,    /* 60-67 */
212    0,    0,    0,    0,    0,    0,    0,    0,    /* 68-6f */
213    0,    0,    0,    0,    0,    0,    0,    0,    /* 70-77 */
214    0,    0,    0,    0x7b, 0,    0x7d, 0x7e, 0,    /* 78-7f */
215    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */
216    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */
217    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */
218    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */
219    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */
220    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */
221    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */
222    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */
223    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* c0-c7 */
224    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* c8-cf */
225    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* d0-d7 */
226    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* d8-df */
227    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */
228    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */
229    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */
230    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff  /* f8-ff */
231};
232
233static uint16_t
234msdos_get_valid_utf16_filename_character (const uint16_t utf16_character)
235{
236  uint16_t retval    = 0x0000;
237  uint16_t char_num  = CF_LE_W( utf16_character );
238
239  if ( char_num <= 0x00ff ) {
240    switch ( char_num )
241    {
242      case 0x002b: /* '+' */
243      case 0x002c: /* ',' */
244      case 0x002e: /* '.' */
245      case 0x003b: /* ';' */
246      case 0x003d: /* '=' */
247      case 0x005b: /* '[' */
248      case 0x005d: /* ']' */
249      case 0x0061: /* 'a' */
250      case 0x0062: /* 'b' */
251      case 0x0063: /* 'c' */
252      case 0x0064: /* 'd' */
253      case 0x0065: /* 'e' */
254      case 0x0066: /* 'f' */
255      case 0x0067: /* 'g' */
256      case 0x0068: /* 'h' */
257      case 0x0069: /* 'i' */
258      case 0x006a: /* 'j' */
259      case 0x006b: /* 'k' */
260      case 0x006c: /* 'l' */
261      case 0x006d: /* 'm' */
262      case 0x006e: /* 'n' */
263      case 0x006f: /* 'o' */
264      case 0x0070: /* 'p' */
265      case 0x0071: /* 'q' */
266      case 0x0072: /* 'r' */
267      case 0x0073: /* 's' */
268      case 0x0074: /* 't' */
269      case 0x0075: /* 'u' */
270      case 0x0076: /* 'v' */
271      case 0x0077: /* 'w' */
272      case 0x0078: /* 'x' */
273      case 0x0079: /* 'y' */
274      case 0x007a: /* 'z' */
275        retval = char_num;
276      break;
277      default:
278        retval = codepage_valid_char_map[char_num];
279      break;
280    }
281  }
282  else
283    retval = char_num;
284
285  return CT_LE_W( retval );
286}
287
288static char
289msdos_get_valid_codepage_filename_character (const uint8_t character)
290{
291  return codepage_valid_char_map[(unsigned int)character];
292}
293
294static ssize_t
295msdos_filename_process_dot_names (const uint8_t *src_name,
296                                  const size_t   src_size,
297                                  uint8_t       *dest_name,
298                                  const size_t   dest_size)
299{
300  ssize_t returned_size = 0;
301  int     eno           = 0;
302  /*
303    * The filenames "." and ".." are handled specially, since they
304    * don't follow dos filename rules.
305    */
306   if (    src_name[0] == UTF8_FULL_STOP
307        && src_size    == UTF8_FULL_STOP_SIZE) {
308     if (dest_size >= UTF8_FULL_STOP_SIZE) {
309       dest_name[0]  = UTF8_FULL_STOP;
310       returned_size = UTF8_FULL_STOP_SIZE;
311     }
312     else
313       eno = ENAMETOOLONG;
314   }
315   else if (    eno           == 0
316             && src_name[0]   == UTF8_FULL_STOP
317             && src_name[1]   == UTF8_FULL_STOP
318             && src_size      == ( 2 * UTF8_FULL_STOP_SIZE ) ) {
319     if (dest_size >= 2 * UTF8_FULL_STOP_SIZE) {
320       dest_name[0]  = UTF8_FULL_STOP;
321       dest_name[1]  = UTF8_FULL_STOP;
322       returned_size = 2 * UTF8_FULL_STOP_SIZE;
323     }
324     else
325       eno = ENAMETOOLONG;
326   }
327
328   if (eno != 0) {
329     errno         = eno;
330     returned_size = -1;
331   }
332
333   return returned_size;
334}
335
336static ssize_t
337msdos_filename_delete_trailing_dots (const uint8_t *filename_utf8,
338                                     const size_t   filename_size)
339{
340  ssize_t      size_returned = filename_size;
341  unsigned int i;
342
343  /*
344   * Remove any dots from the end of a file name.
345   */
346  for ( i = size_returned - UTF8_FULL_STOP_SIZE;
347           size_returned >= UTF8_FULL_STOP_SIZE
348        && filename_utf8[i] == UTF8_FULL_STOP;) {
349    size_returned -= UTF8_FULL_STOP_SIZE;
350    i             -= UTF8_FULL_STOP_SIZE;
351  }
352
353  return size_returned;
354}
355
356ssize_t
357msdos_filename_utf8_to_long_name_for_compare (
358    rtems_dosfs_convert_control     *converter,
359    const uint8_t                   *utf8_name,
360    const size_t                     utf8_name_size,
361    uint8_t                         *long_name,
362    const size_t                     long_name_size)
363  {
364    ssize_t        returned_size = 0;
365    int            eno           = 0;
366    size_t         name_size;
367    size_t         dest_size     = long_name_size;
368
369    returned_size = msdos_filename_process_dot_names (
370      utf8_name,
371      utf8_name_size,
372      long_name,
373      long_name_size);
374
375    if (returned_size == 0) {
376      name_size = msdos_filename_delete_trailing_dots (
377        &utf8_name[0],
378        utf8_name_size);
379      if (name_size > 0) {
380        eno = (*converter->handler->utf8_normalize_and_fold) (
381          converter,
382          utf8_name,
383          name_size,
384          long_name,
385          &dest_size);
386        if (eno == 0) {
387          returned_size = (ssize_t)dest_size;
388        }
389      } else {
390        eno = EINVAL;
391      }
392    }
393
394    if ( eno != 0 ) {
395      errno         = eno;
396      returned_size = -1;
397    }
398
399    return returned_size;
400  }
401
402ssize_t
403msdos_filename_utf8_to_long_name_for_save (
404    rtems_dosfs_convert_control     *converter,
405    const uint8_t                   *utf8_name,
406    const size_t                     utf8_name_size,
407    uint16_t                        *long_name,
408    const size_t                     long_name_size)
409{
410    ssize_t      returned_size = 0;
411    int          eno           = 0;
412    size_t       name_size     = utf8_name_size;
413    size_t       name_size_tmp = long_name_size / MSDOS_NAME_LFN_BYTES_PER_CHAR;
414    int          i;
415    uint16_t     c;
416    unsigned int chars_written;
417
418    name_size_tmp = long_name_size;
419    name_size = msdos_filename_delete_trailing_dots (
420      &utf8_name[0],
421      utf8_name_size);
422    if (name_size > 0) {
423      /*
424       * Finally convert from UTF-8 to UTF-16
425       */
426      eno = (*converter->handler->utf8_to_utf16) (
427          converter,
428          utf8_name,
429          name_size,
430          &long_name[0],
431          &name_size_tmp);
432      if (eno == 0) {
433        if (name_size_tmp <= (MSDOS_NAME_MAX_LNF_LEN * MSDOS_NAME_LFN_BYTES_PER_CHAR))
434          name_size = name_size_tmp;
435        else
436          eno = ENAMETOOLONG;
437      }
438
439      if ( eno == 0 )
440      {
441        /*
442         * Validate the characters and assign them to the UTF-16 file name
443         */
444        for ( i = 0;
445                 name_size
446              && (c = msdos_get_valid_utf16_filename_character ( long_name[i]) );
447              ++i ) {
448          long_name[i]   = c;
449          returned_size += MSDOS_NAME_LFN_BYTES_PER_CHAR;
450          name_size     -= MSDOS_NAME_LFN_BYTES_PER_CHAR;
451        }
452        if ( name_size == UTF16_NULL_SIZE && c == UTF16_NULL ) {
453          long_name[i]   = c;
454          returned_size += MSDOS_NAME_LFN_BYTES_PER_CHAR;
455          name_size     -= MSDOS_NAME_LFN_BYTES_PER_CHAR;
456        }
457        else if ( name_size != 0 )
458          eno = EINVAL;
459        chars_written = returned_size / MSDOS_NAME_LFN_BYTES_PER_CHAR;
460        if (   long_name [chars_written - 1] != UTF16_NULL
461            && (returned_size + UTF16_NULL_SIZE ) <= long_name_size ) {
462          long_name[chars_written] = UTF16_NULL;
463        }
464      }
465    }
466    else
467      eno = EINVAL;
468
469    if ( eno != 0 ) {
470      errno         = eno;
471      returned_size = -1;
472    }
473
474    return returned_size;
475  }
476
477/*
478 * Remove any dots from the start of a file name.
479 */
480static void msdos_filename_remove_prepended_dots (const uint8_t **name_utf8,
481                                                  size_t         *name_size)
482{
483  while (    *name_size >= UTF8_FULL_STOP_SIZE
484         && **name_utf8 == UTF8_FULL_STOP) {
485    *name_utf8  += UTF8_FULL_STOP_SIZE;
486    *name_size  -= UTF8_FULL_STOP_SIZE;
487  }
488}
489
490ssize_t
491msdos_filename_utf8_to_short_name_for_compare (
492    rtems_dosfs_convert_control     *converter,
493    const uint8_t                   *utf8_name,
494    const size_t                     utf8_name_size,
495    void                            *short_name,
496    const size_t                     short_name_size)
497{
498  ssize_t        returned_size           = 0;
499  int            eno                     = 0;
500  const uint8_t *name_ptr                = utf8_name;
501  char          *dest_ptr                = (char*)short_name;
502  size_t         name_size               = utf8_name_size;
503  uint8_t        name_normalized_buf[(MSDOS_SHORT_NAME_LEN +1) * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR];
504  size_t         name_size_tmp           = sizeof(name_normalized_buf);
505
506  returned_size = msdos_filename_process_dot_names (
507    utf8_name,
508    utf8_name_size,
509    short_name,
510    short_name_size);
511
512  if (returned_size == 0) {
513    msdos_filename_remove_prepended_dots (&name_ptr,
514                                          &name_size);
515    if (name_size > 0) {
516      /*
517       * Normalize the name and convert to lower case
518       */
519      eno = (*converter->handler->utf8_normalize_and_fold) (
520        converter,
521        name_ptr,
522        name_size,
523        &name_normalized_buf[0],
524        &name_size_tmp);
525      name_ptr  = &name_normalized_buf[0];
526      name_size = name_size_tmp;
527      if ( eno == ENOMEM ) {
528        eno = 0;
529      }
530      if ( eno == 0 ) {
531        memcpy (&dest_ptr[0], &name_ptr[0], name_size);
532        returned_size = name_size;
533      }
534    } else
535      eno = EINVAL;
536  }
537
538  if ( eno != 0 ) {
539    errno         = eno;
540    returned_size = -1;
541  }
542
543  return returned_size;
544}
545
546ssize_t
547msdos_filename_utf8_to_short_name_for_save (
548    rtems_dosfs_convert_control     *converter,
549    const uint8_t                   *utf8_name,
550    const size_t                     utf8_name_size,
551    void                            *short_name,
552    const size_t                     short_name_size)
553{
554  ssize_t        returned_size           = 0;
555  int            eno                     = 0;
556  const uint8_t *name_ptr                = utf8_name;
557  size_t         name_size               = utf8_name_size;
558  char          *dest_ptr                = (char*)short_name;
559  unsigned int   i;
560  char           c;
561  size_t         name_size_tmp;
562  char           name_to_format_buf[MSDOS_SHORT_NAME_LEN +1];
563
564  returned_size = msdos_filename_process_dot_names (
565    utf8_name,
566    utf8_name_size,
567    short_name,
568    short_name_size);
569
570  if (returned_size == 0) {
571    msdos_filename_remove_prepended_dots (&name_ptr,
572                                          &name_size);
573
574    if (name_size > 0) {
575      /*
576       * Finally convert from UTF-8 to codepage
577       */
578      name_size_tmp = sizeof ( name_to_format_buf );
579      eno = (*converter->handler->utf8_to_codepage) (
580        converter,
581        name_ptr,
582        name_size,
583        &name_to_format_buf[0],
584        &name_size_tmp);
585      if ( eno != 0 ) {
586        /* The UTF-8 name my well be long name, for which we now want to
587         * generate the corresponding short name. Under these circumstances
588         * eno != 0 likely simply means that the UTF-8 name is longer than 11 characters
589         * or that it contains unicode characters which can not be converted to the code page
590         * in a reversible way. Non-reversible characters will be represented by question mark
591         * characters. Later in this method they will get replaced by underline characters.
592         */
593        eno = 0;
594      }
595      name_ptr  = (const uint8_t *)(&name_to_format_buf[0]);
596      name_size = name_size_tmp;
597      for (i = 0; i < name_size; ++i)
598        name_to_format_buf[i] = toupper ( (unsigned char)(name_to_format_buf[i]) );
599      /*
600       * Validate the characters and assign them to the codepage file name
601       */
602      if ( name_size > 0 ) {
603        /*
604         * The first character needs some special treatment
605         */
606        if ( 0x20 == *name_ptr )
607          dest_ptr[0] = '_';
608        else if ( 0xE5 == *name_ptr )
609          dest_ptr[0] = 0x05;
610        else if (0 != (c = msdos_get_valid_codepage_filename_character( *name_ptr ) ) )
611          dest_ptr[0] = c;
612        else
613          dest_ptr[0] = '_';
614        ++name_ptr;
615        ++returned_size;
616        --name_size;
617        /*
618         * Validate and assign all other characters of the name part
619         */
620        for (i = 1; i <= 7 && name_size && *name_ptr != '.'; ++i) {
621          c = msdos_get_valid_codepage_filename_character ( *name_ptr );
622          if (c != 0)
623            dest_ptr[i] = c;
624          else
625            dest_ptr[i] = '_';
626          ++name_ptr;
627          ++returned_size;
628          --name_size;
629        }
630        /*
631         * Strip any further characters up to a '.' or the end of the
632         * string.
633         */
634        if ( *name_ptr == '.' ) {
635          ++name_ptr;
636          --name_size;
637        }
638
639        for (; i < 8; ++i) {
640          dest_ptr[i] = ' ';
641          ++returned_size;
642        }
643
644        /*
645         * Copy in the extension part of the name, if any.
646         */
647        for (; i <= 10 && name_size ; i++) {
648          c = msdos_get_valid_codepage_filename_character ( *name_ptr);
649          if (c != 0)
650            dest_ptr[i] = c;
651          else
652            dest_ptr[i] = '_';
653          ++name_ptr;
654          ++returned_size;
655          name_size--;
656        }
657        /*
658         * Fill up with blanks. These are DOS's pad characters.
659         */
660        for ( ; i < short_name_size; ++i ) {
661          dest_ptr[i] = ' ';
662          ++returned_size;
663        }
664      }
665    }
666    else
667      eno = EINVAL;
668  }
669
670  if ( eno != 0 ) {
671    errno = eno;
672    return -1;
673  }
674
675  return returned_size;
676}
677
678
Note: See TracBrowser for help on using the repository browser.