"Fossies" - the Fresh Open Source Software Archive

Member "libcdio-2.1.0/lib/iso9660/rock.c" (13 Apr 2019, 17933 Bytes) of package /linux/privat/libcdio-2.1.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rock.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.0.0_vs_2.1.0.

    1 /*
    2   Copyright (C) 2005, 2008, 2010-2011, 2014, 2017 Rocky Bernstein
    3   <rocky@gnu.org>
    4 
    5   Adapted from GNU/Linux fs/isofs/rock.c (C) 1992, 1993 Eric Youngdale
    6 
    7   This program is free software: you can redistribute it and/or modify
    8   it under the terms of the GNU General Public License as published by
    9   the Free Software Foundation, either version 3 of the License, or
   10   (at your option) any later version.
   11 
   12   This program is distributed in the hope that it will be useful,
   13   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15   GNU General Public License for more details.
   16 
   17   You should have received a copy of the GNU General Public License
   18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   19 */
   20 /* Rock Ridge Extensions to iso9660 */
   21 
   22 
   23 #ifdef HAVE_CONFIG_H
   24 # include "config.h"
   25 #endif
   26 
   27 #ifdef HAVE_STRING_H
   28 # include <string.h>
   29 #endif
   30 
   31 #ifdef HAVE_STDLIB_H
   32 # include <stdlib.h>
   33 #endif
   34 
   35 #ifdef HAVE_SYS_STAT_H
   36 # include <sys/stat.h>
   37 #endif
   38 
   39 #include <cdio/iso9660.h>
   40 #include <cdio/logging.h>
   41 #include <cdio/bytesex.h>
   42 #include "filemode.h"
   43 
   44 #define CDIO_MKDEV(ma,mi)   ((ma)<<16 | (mi))
   45 
   46 enum iso_rock_enums iso_rock_enums;
   47 iso_rock_nm_flag_t iso_rock_nm_flag;
   48 iso_rock_sl_flag_t iso_rock_sl_flag;
   49 iso_rock_tf_flag_t iso_rock_tf_flag;
   50 
   51 /* Our own realloc routine tailored for the iso9660_stat_t symlink
   52    field.  I can't figure out how to make realloc() work without
   53    valgrind complaint.
   54 */
   55 static bool
   56 realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow)
   57 {
   58   if (!p_stat->rr.i_symlink) {
   59     const uint16_t i_max = 2*i_grow+1;
   60     p_stat->rr.psz_symlink = (char *) calloc(1, i_max);
   61     p_stat->rr.i_symlink_max = i_max;
   62     return (NULL != p_stat->rr.psz_symlink);
   63   } else {
   64     unsigned int i_needed = p_stat->rr.i_symlink + i_grow ;
   65     if ( i_needed <= p_stat->rr.i_symlink_max)
   66       return true;
   67     else {
   68       char * psz_newsymlink = (char *) calloc(1, 2*i_needed);
   69       if (!psz_newsymlink) return false;
   70       p_stat->rr.i_symlink_max = 2*i_needed;
   71       memcpy(psz_newsymlink, p_stat->rr.psz_symlink, p_stat->rr.i_symlink);
   72       free(p_stat->rr.psz_symlink);
   73       p_stat->rr.psz_symlink = psz_newsymlink;
   74       return true;
   75     }
   76   }
   77 }
   78 
   79 /* These functions are designed to read the system areas of a directory record
   80  * and extract relevant information.  There are different functions provided
   81  * depending upon what information we need at the time.  One function fills
   82  * out an inode structure, a second one extracts a filename, a third one
   83  * returns a symbolic link name, and a fourth one returns the extent number
   84  * for the file. */
   85 
   86 #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */
   87 
   88 
   89 /* This is a way of ensuring that we have something in the system
   90    use fields that is compatible with Rock Ridge */
   91 #define CHECK_SP(FAIL)                  \
   92       if(rr->u.SP.magic[0] != 0xbe) FAIL;   \
   93       if(rr->u.SP.magic[1] != 0xef) FAIL;       \
   94       p_stat->rr.s_rock_offset = rr->u.SP.skip;
   95 /* We define a series of macros because each function must do exactly the
   96    same thing in certain places.  We use the macros to ensure that everything
   97    is done correctly */
   98 
   99 #define CONTINUE_DECLS \
  100   int cont_extent = 0, cont_offset = 0, cont_size = 0;   \
  101   void *buffer = NULL
  102 
  103 #define CHECK_CE                 \
  104   { cont_extent = from_733(*rr->u.CE.extent);    \
  105     cont_offset = from_733(*rr->u.CE.offset);    \
  106     cont_size = from_733(*rr->u.CE.size);    \
  107     (void)cont_extent; (void)cont_offset, (void)cont_size; }
  108 
  109 #define SETUP_ROCK_RIDGE(DE,CHR,LEN)                        \
  110   {                             \
  111     LEN= sizeof(iso9660_dir_t) + DE->filename.len;      \
  112     if(LEN & 1) LEN++;                      \
  113     CHR = ((unsigned char *) DE) + LEN;             \
  114     LEN = *((unsigned char *) DE) - LEN;            \
  115     if (0xff != p_stat->rr.s_rock_offset)           \
  116       {                             \
  117     LEN -= p_stat->rr.s_rock_offset;                \
  118     CHR += p_stat->rr.s_rock_offset;                \
  119     if (LEN<0) LEN=0;                   \
  120       }                             \
  121   }
  122 
  123 /* Copy a long or short time from the iso_rock_tf_t into
  124    the specified field of a iso_rock_statbuf_t.
  125    non-paramater variables are p_stat, rr, and cnt.
  126 */
  127 #define add_time(FLAG, TIME_FIELD)                \
  128   if (rr->u.TF.flags & FLAG) {                    \
  129     p_stat->rr.TIME_FIELD.b_used = true;              \
  130     p_stat->rr.TIME_FIELD.b_longdate =                \
  131       (0 != (rr->u.TF.flags & ISO_ROCK_TF_LONG_FORM));        \
  132     if (p_stat->rr.TIME_FIELD.b_longdate) {           \
  133       memcpy(&(p_stat->rr.TIME_FIELD.t.ltime),            \
  134          &(rr->u.TF.time_bytes[cnt]),             \
  135          sizeof(iso9660_ltime_t));                \
  136       cnt += sizeof(iso9660_ltime_t);                 \
  137     } else {                              \
  138       memcpy(&(p_stat->rr.TIME_FIELD.t.dtime),            \
  139          &(rr->u.TF.time_bytes[cnt]),             \
  140          sizeof(iso9660_dtime_t));                \
  141       cnt += sizeof(iso9660_dtime_t);                 \
  142     }                                 \
  143   }
  144 
  145 /*!
  146   Get
  147   @return length of name field; 0: not found, -1: to be ignored
  148 */
  149 int
  150 get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir,
  151             /*out*/ char * psz_name,
  152             /*in/out*/ iso9660_stat_t *p_stat)
  153 {
  154   int len;
  155   unsigned char *chr;
  156   int symlink_len = 0;
  157   CONTINUE_DECLS;
  158   int i_namelen = 0;
  159   int truncate=0;
  160 
  161   if (!p_stat || nope == p_stat->rr.b3_rock) return 0;
  162   *psz_name = 0;
  163 
  164   SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len);
  165   /*repeat:*/
  166   {
  167     iso_extension_record_t * rr;
  168     int sig;
  169     int rootflag;
  170 
  171     while (len > 1){ /* There may be one byte for padding somewhere */
  172       rr = (iso_extension_record_t *) chr;
  173       sig = *chr+(*(chr+1) << 8);
  174 
  175       /* We used to check for some vaid values of SIG, specifically
  176      SP, CE, ER, RR, PX, PN, SL, NM, CL, PL, TF, and ZF.
  177      However there are various extensions to this set. So we
  178      skip checking now.
  179       */
  180 
  181       if (rr->len == 0) goto out; /* Something got screwed up here */
  182       chr += rr->len;
  183       len -= rr->len;
  184 
  185       switch(sig){
  186       case SIG('S','P'):
  187     CHECK_SP(goto out);
  188     break;
  189       case SIG('C','E'):
  190     {
  191       iso711_t i_fname = from_711(p_iso9660_dir->filename.len);
  192       if ('\0' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
  193         break;
  194       if ('\1' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
  195         break;
  196     }
  197     CHECK_CE;
  198     break;
  199       case SIG('E','R'):
  200     p_stat->rr.b3_rock = yep;
  201     cdio_debug("ISO 9660 Extensions: ");
  202     {
  203       int p;
  204       for(p=0;p<rr->u.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]);
  205     }
  206     break;
  207       case SIG('N','M'):
  208     /* Alternate name */
  209     p_stat->rr.b3_rock = yep;
  210     if (truncate) break;
  211     if (rr->u.NM.flags & ISO_ROCK_NM_PARENT) {
  212       i_namelen = sizeof("..");
  213       strncat(psz_name, "..", i_namelen);
  214       break;
  215     } else if (rr->u.NM.flags & ISO_ROCK_NM_CURRENT) {
  216       i_namelen = sizeof(".");
  217       strncat(psz_name, ".", i_namelen);
  218       break;
  219     }
  220 
  221     if (rr->u.NM.flags & ~1) {
  222       cdio_info("Unsupported NM flag settings (%d)",rr->u.NM.flags);
  223       break;
  224     }
  225     if((strlen(psz_name) + rr->len - 5) >= 254) {
  226       truncate = 1;
  227       break;
  228     }
  229     strncat(psz_name, rr->u.NM.name, rr->len - 5);
  230     i_namelen += rr->len - 5;
  231     break;
  232       case SIG('P','X'):
  233     /* POSIX file attributes */
  234     p_stat->rr.st_mode   = from_733(rr->u.PX.st_mode);
  235     p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks);
  236     p_stat->rr.st_uid    = from_733(rr->u.PX.st_uid);
  237     p_stat->rr.st_gid    = from_733(rr->u.PX.st_gid);
  238     p_stat->rr.b3_rock    = yep;
  239     break;
  240       case SIG('S','L'):
  241     {
  242       /* Symbolic link */
  243       uint8_t slen;
  244       iso_rock_sl_part_t * p_sl;
  245       iso_rock_sl_part_t * p_oldsl;
  246       slen = rr->len - 5;
  247       p_sl = &rr->u.SL.link;
  248       p_stat->rr.i_symlink = symlink_len;
  249       while (slen > 1){
  250         rootflag = 0;
  251         switch(p_sl->flags &~1){
  252         case 0:
  253           realloc_symlink(p_stat, p_sl->len);
  254           memcpy(&(p_stat->rr.psz_symlink[p_stat->rr.i_symlink]),
  255              p_sl->text, p_sl->len);
  256           p_stat->rr.i_symlink += p_sl->len;
  257           break;
  258         case 4:
  259           realloc_symlink(p_stat, 1);
  260           p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
  261           /* continue into next case. */
  262         case 2:
  263           realloc_symlink(p_stat, 1);
  264           p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
  265           break;
  266         case 8:
  267           rootflag = 1;
  268           realloc_symlink(p_stat, 1);
  269           p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
  270           break;
  271         default:
  272           cdio_warn("Symlink component flag not implemented");
  273         }
  274         slen -= p_sl->len + 2;
  275         p_oldsl = p_sl;
  276         p_sl = (iso_rock_sl_part_t *) (((char *) p_sl) + p_sl->len + 2);
  277 
  278         if (slen < 2) {
  279           if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0))
  280         p_stat->rr.i_symlink += 1;
  281           break;
  282         }
  283 
  284         /*
  285          * If this component record isn't continued, then append a '/'.
  286          */
  287         if (!rootflag && (p_oldsl->flags & 1) == 0) {
  288           realloc_symlink(p_stat, 1);
  289           p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
  290         }
  291       }
  292     }
  293     symlink_len = p_stat->rr.i_symlink;
  294     realloc_symlink(p_stat, 1);
  295     p_stat->rr.psz_symlink[symlink_len]='\0';
  296     break;
  297       case SIG('R','E'):
  298     free(buffer);
  299     return -1;
  300       case SIG('T','F'):
  301     /* Time stamp(s) for a file */
  302     {
  303       int cnt = 0;
  304       add_time(ISO_ROCK_TF_CREATE,     create);
  305       add_time(ISO_ROCK_TF_MODIFY,     modify);
  306       add_time(ISO_ROCK_TF_ACCESS,     access);
  307       add_time(ISO_ROCK_TF_ATTRIBUTES, attributes);
  308       add_time(ISO_ROCK_TF_BACKUP,     backup);
  309       add_time(ISO_ROCK_TF_EXPIRATION, expiration);
  310       add_time(ISO_ROCK_TF_EFFECTIVE,  effective);
  311       p_stat->rr.b3_rock = yep;
  312       break;
  313     }
  314       default:
  315     break;
  316       }
  317     }
  318   }
  319   free(buffer);
  320   return i_namelen; /* If 0, this file did not have a NM field */
  321  out:
  322   free(buffer);
  323   return 0;
  324 }
  325 
  326 static int
  327 parse_rock_ridge_stat_internal(iso9660_dir_t *p_iso9660_dir,
  328                    iso9660_stat_t *p_stat, int regard_xa)
  329 {
  330   int len;
  331   unsigned char * chr;
  332   int symlink_len = 0;
  333   CONTINUE_DECLS;
  334 
  335   if (nope == p_stat->rr.b3_rock) return 0;
  336 
  337   SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len);
  338   if (regard_xa)
  339     {
  340       chr+=14;
  341       len-=14;
  342       if (len<0) len=0;
  343     }
  344 
  345   /* repeat:*/
  346   {
  347     int sig;
  348     iso_extension_record_t * rr;
  349     int rootflag;
  350 
  351     while (len > 1){ /* There may be one byte for padding somewhere */
  352       rr = (iso_extension_record_t *) chr;
  353       if (rr->len == 0) goto out; /* Something got screwed up here */
  354       sig = from_721(*chr);
  355       chr += rr->len;
  356       len -= rr->len;
  357 
  358       switch(sig){
  359       case SIG('S','P'):
  360     CHECK_SP(goto out);
  361     break;
  362       case SIG('C','E'):
  363     CHECK_CE;
  364     break;
  365       case SIG('E','R'):
  366     p_stat->rr.b3_rock = yep;
  367     cdio_debug("ISO 9660 Extensions: ");
  368     { int p;
  369       for(p=0;p<rr->u.ER.len_id;p++) cdio_debug("%c",rr->u.ER.data[p]);
  370     }
  371     break;
  372       case SIG('P','X'):
  373     p_stat->rr.st_mode   = from_733(rr->u.PX.st_mode);
  374     p_stat->rr.st_nlinks = from_733(rr->u.PX.st_nlinks);
  375     p_stat->rr.st_uid    = from_733(rr->u.PX.st_uid);
  376     p_stat->rr.st_gid    = from_733(rr->u.PX.st_gid);
  377     break;
  378       case SIG('P','N'):
  379     /* Device major,minor number */
  380     { int32_t high, low;
  381       high = from_733(rr->u.PN.dev_high);
  382       low = from_733(rr->u.PN.dev_low);
  383       /*
  384        * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4,
  385        * then the high field is unused, and the device number is completely
  386        * stored in the low field.  Some writers may ignore this subtlety,
  387        * and as a result we test to see if the entire device number is
  388        * stored in the low field, and use that.
  389        */
  390       if((low & ~0xff) && high == 0) {
  391         p_stat->rr.i_rdev = CDIO_MKDEV(low >> 8, low & 0xff);
  392       } else {
  393         p_stat->rr.i_rdev = CDIO_MKDEV(high, low);
  394       }
  395     }
  396     break;
  397       case SIG('T','F'):
  398     /* Time stamp(s) for a file */
  399     {
  400       int cnt = 0;
  401       add_time(ISO_ROCK_TF_CREATE,     create);
  402       add_time(ISO_ROCK_TF_MODIFY,     modify);
  403       add_time(ISO_ROCK_TF_ACCESS,     access);
  404       add_time(ISO_ROCK_TF_ATTRIBUTES, attributes);
  405       add_time(ISO_ROCK_TF_BACKUP,     backup);
  406       add_time(ISO_ROCK_TF_EXPIRATION, expiration);
  407       add_time(ISO_ROCK_TF_EFFECTIVE,  effective);
  408       p_stat->rr.b3_rock = yep;
  409       break;
  410     }
  411       case SIG('S','L'):
  412     {
  413       /* Symbolic link */
  414       uint8_t slen;
  415       iso_rock_sl_part_t * p_sl;
  416       iso_rock_sl_part_t * p_oldsl;
  417       slen = rr->len - 5;
  418       p_sl = &rr->u.SL.link;
  419       p_stat->rr.i_symlink = symlink_len;
  420       while (slen > 1){
  421         rootflag = 0;
  422         switch(p_sl->flags &~1){
  423         case 0:
  424           realloc_symlink(p_stat, p_sl->len);
  425           if (p_sl->len)
  426         memcpy(&(p_stat->rr.psz_symlink[p_stat->rr.i_symlink]),
  427                p_sl->text, p_sl->len);
  428           p_stat->rr.i_symlink += p_sl->len;
  429           break;
  430         case 4:
  431           realloc_symlink(p_stat, 1);
  432           p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
  433           /* continue into next case. */
  434         case 2:
  435           realloc_symlink(p_stat, 1);
  436           p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '.';
  437           break;
  438         case 8:
  439           rootflag = 1;
  440           realloc_symlink(p_stat, 1);
  441           p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
  442           p_stat->rr.i_symlink++;
  443           break;
  444         default:
  445           cdio_warn("Symlink component flag not implemented");
  446         }
  447         slen -= p_sl->len + 2;
  448         p_oldsl = p_sl;
  449         p_sl = (iso_rock_sl_part_t *) (((char *) p_sl) + p_sl->len + 2);
  450 
  451         if (slen < 2) {
  452           if (((rr->u.SL.flags & 1) != 0) && ((p_oldsl->flags & 1) == 0))
  453         p_stat->rr.i_symlink += 1;
  454           break;
  455         }
  456 
  457         /*
  458          * If this component record isn't continued, then append a '/'.
  459          */
  460         if (!rootflag && (p_oldsl->flags & 1) == 0) {
  461           realloc_symlink(p_stat, 1);
  462           p_stat->rr.psz_symlink[p_stat->rr.i_symlink++] = '/';
  463         }
  464       }
  465     }
  466     symlink_len = p_stat->rr.i_symlink;
  467     realloc_symlink(p_stat, 1);
  468     p_stat->rr.psz_symlink[symlink_len]='\0';
  469     break;
  470       case SIG('R','E'):
  471     cdio_warn("Attempt to read p_stat for relocated directory");
  472     goto out;
  473 #ifdef FINISHED
  474       case SIG('C','L'):
  475     {
  476       iso9660_stat_t * reloc;
  477       ISOFS_I(p_stat)->i_first_extent = from_733(rr->u.CL.location);
  478       reloc = isofs_iget(p_stat->rr.i_sb, p_stat->rr.i_first_extent, 0);
  479       if (!reloc)
  480         goto out;
  481       p_stat->rr.st_mode   = reloc->st_mode;
  482       p_stat->rr.st_nlinks = reloc->st_nlinks;
  483       p_stat->rr.st_uid    = reloc->st_uid;
  484       p_stat->rr.st_gid    = reloc->st_gid;
  485       p_stat->rr.i_rdev    = reloc->i_rdev;
  486       p_stat->rr.i_symlink = reloc->i_symlink;
  487       p_stat->rr.i_blocks  = reloc->i_blocks;
  488       p_stat->rr.i_atime   = reloc->i_atime;
  489       p_stat->rr.i_ctime   = reloc->i_ctime;
  490       p_stat->rr.i_mtime   = reloc->i_mtime;
  491       iput(reloc);
  492     }
  493     break;
  494 #endif
  495       default:
  496     break;
  497       }
  498     }
  499   }
  500  out:
  501   free(buffer);
  502   return 0;
  503 }
  504 
  505 int
  506 parse_rock_ridge_stat(iso9660_dir_t *p_iso9660_dir,
  507               /*out*/ iso9660_stat_t *p_stat)
  508 {
  509   int result;
  510 
  511   if (!p_stat) return 0;
  512 
  513   result = parse_rock_ridge_stat_internal(p_iso9660_dir, p_stat, 0);
  514   /* if Rock-Ridge flag was reset and we didn't look for attributes
  515    * behind eventual XA attributes, have a look there */
  516   if (0xFF == p_stat->rr.s_rock_offset && nope != p_stat->rr.b3_rock) {
  517     result = parse_rock_ridge_stat_internal(p_iso9660_dir, p_stat, 14);
  518   }
  519   return result;
  520 }
  521 
  522 #define BUF_COUNT 16
  523 #define BUF_SIZE sizeof("drwxrwxrwx")
  524 
  525 /* Return a pointer to a internal free buffer */
  526 static char *
  527 _getbuf (void)
  528 {
  529   static char _buf[BUF_COUNT][BUF_SIZE];
  530   static int _i = -1;
  531 
  532   _i++;
  533   _i %= BUF_COUNT;
  534 
  535   memset (_buf[_i], 0, BUF_SIZE);
  536 
  537   return _buf[_i];
  538 }
  539 
  540 /*!
  541   Returns a string which interpreting the POSIX mode st_mode.
  542   For example:
  543   \verbatim
  544   drwxrws---
  545   -rw-rw-r--
  546   lrwxrwxrwx
  547   \endverbatim
  548 
  549   A description of the characters in the string follows
  550   The 1st character is either "b" for a block device,
  551   "c" for a character device, "d" if the entry is a directory, "l" for
  552   a symbolic link, "p" for a pipe or FIFO, "s" for a "socket",
  553   or "-" if none of the these.
  554 
  555   The 2nd to 4th characters refer to permissions for a user while the
  556   the 5th to 7th characters refer to permissions for a group while, and
  557   the 8th to 10h characters refer to permissions for everyone.
  558 
  559   In each of these triplets the first character (2, 5, 8) is "r" if
  560   the entry is allowed to be read.
  561 
  562   The second character of a triplet (3, 6, 9) is "w" if the entry is
  563   allowed to be written.
  564 
  565   The third character of a triplet (4, 7, 10) is "x" if the entry is
  566   executable but not user (for character 4) or group (for characters
  567   6) settable and "s" if the item has the corresponding user/group set.
  568 
  569   For a directory having an executable property on ("x" or "s") means
  570   the directory is allowed to be listed or "searched". If the execute
  571   property is not allowed for a group or user but the corresponding
  572   group/user is set "S" indicates this. If none of these properties
  573   holds the "-" indicates this.
  574 */
  575 const char *
  576 iso9660_get_rock_attr_str(posix_mode_t st_mode)
  577 {
  578   char *result = _getbuf();
  579 
  580   if (S_ISBLK(st_mode))
  581     result[ 0] = 'b';
  582   else if (S_ISDIR(st_mode))
  583     result[ 0] = 'd';
  584   else if (S_ISCHR(st_mode))
  585     result[ 0] = 'c';
  586   else if (S_ISLNK(st_mode))
  587     result[ 0] = 'l';
  588   else if (S_ISFIFO(st_mode))
  589     result[ 0] = 'p';
  590   else if (S_ISSOCK(st_mode))
  591     result[ 0] = 's';
  592   /* May eventually fill in others.. */
  593   else
  594     result[ 0] = '-';
  595 
  596   result[ 1] = (st_mode & ISO_ROCK_IRUSR) ? 'r' : '-';
  597   result[ 2] = (st_mode & ISO_ROCK_IWUSR) ? 'w' : '-';
  598 
  599   if (st_mode & ISO_ROCK_ISUID)
  600     result[ 3] = (st_mode & ISO_ROCK_IXUSR) ? 's' : 'S';
  601   else
  602     result[ 3] = (st_mode & ISO_ROCK_IXUSR) ? 'x' : '-';
  603 
  604   result[ 4] = (st_mode & ISO_ROCK_IRGRP) ? 'r' : '-';
  605   result[ 5] = (st_mode & ISO_ROCK_IWGRP) ? 'w' : '-';
  606 
  607   if (st_mode & ISO_ROCK_ISGID)
  608     result[ 6] = (st_mode & ISO_ROCK_IXGRP) ? 's' : 'S';
  609   else
  610     result[ 6] = (st_mode & ISO_ROCK_IXGRP) ? 'x' : '-';
  611 
  612   result[ 7] = (st_mode & ISO_ROCK_IROTH) ? 'r' : '-';
  613   result[ 8] = (st_mode & ISO_ROCK_IWOTH) ? 'w' : '-';
  614   result[ 9] = (st_mode & ISO_ROCK_IXOTH) ? 'x' : '-';
  615 
  616   result[11] = '\0';
  617 
  618   return result;
  619 }
  620 
  621 /*!
  622   Returns POSIX mode bitstring for a given file.
  623 */
  624 mode_t
  625 iso9660_get_posix_filemode_from_rock(const iso_rock_statbuf_t *rr)
  626 {
  627   return (mode_t) rr->st_mode;
  628 }