Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/fs/iso9660/fsys_iso9660.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "kernel.h"
0019 #include "mem/mem.h"
0020 #include "fs/filesys.h"
0021 #include "arch/i386.h"
0022 #include "util/printf.h"
0023 #include "drivers/ata/ata.h"
0024 
0025 void
0026 iso9660_date_record (uint8 * buf)
0027 {
0028   com1_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%.2s.%.2s %02d",
0029                buf, buf + 4, buf + 6,
0030                buf + 8, buf + 10, buf + 12, buf + 14,
0031                *((signed char *) buf + 16) / 4);
0032 }
0033 
0034 
0035 void
0036 iso9660_show_dir_record (uint8 * r)
0037 {
0038   iso9660_dir_record *d = (iso9660_dir_record *) r;
0039   int i;
0040   com1_printf ("dir_record\n  length=%d first_sector=%X data_length=%d\n",
0041                d->length, d->first_sector, d->data_length);
0042   com1_printf ("  %d-%02d-%02d %02d:%02d:%02d\n",
0043                d->years_since_1900 + 1900, d->month, d->day,
0044                d->hour, d->minute, d->second);
0045   com1_printf ("  flags: %s %s %s %s %s %s\n",
0046                d->flag_hidden ? "hidden" : "regular",
0047                d->flag_dir ? "dir" : "file",
0048                d->flag_assoc ? "assoc" : "noassoc",
0049                d->flag_recfmtspec ? "recfmtspec" : "norecfmtspec",
0050                d->flag_permspec ? "permspec" : "nopermspec",
0051                d->flag_notfinal ? "notfinal" : "final");
0052   com1_printf ("  id len=%d: ", d->identifier_length);
0053   for (i = 0; i < d->identifier_length; i++)
0054     if (d->identifier[i])
0055       com1_putc (d->identifier[i]);
0056   com1_putc ('\n');
0057 }
0058 
0059 void
0060 iso9660_walk_tree (uint32 bus, uint32 drive,
0061                    iso9660_dir_record * d, int depth)
0062 {
0063   int i, len;
0064 
0065   for (i = 0; i < depth; i++)
0066     com1_puts ("  ");
0067 
0068   if (d->identifier[0] == 0) {
0069     com1_puts (".\n");
0070     if (depth > 0)
0071       return;
0072   } else if (d->identifier[0] == 1) {
0073     com1_puts ("..\n");
0074     if (depth > 0)
0075       return;
0076   } else {
0077     for (i = 0; i < d->identifier_length; i++)
0078       if (d->identifier[i])
0079         com1_putc (d->identifier[i]);
0080     com1_puts ("\n");
0081   }
0082 
0083   if (d->flag_dir) {
0084     uint32 frame = alloc_phys_frame ();
0085     uint8 *sector = map_virtual_page (frame | 3);
0086 
0087     uint32 secnum = d->first_sector;
0088     uint32 num_bytes = d->data_length;
0089     uint32 count;
0090 
0091     for (count = 0; count < num_bytes;) {
0092       if (count % ATAPI_SECTOR_SIZE == 0) {
0093         // if 2048-byte aligned get next sector
0094         len = atapi_drive_read_sector (bus, drive, secnum, sector);
0095         if (len < 0) {
0096           panic ("CD ROM READ ERROR\n");
0097         }
0098         secnum++;
0099         d = (iso9660_dir_record *) sector;
0100       }
0101 
0102       iso9660_walk_tree (bus, drive, d, depth + 1);
0103 
0104       count += d->length;
0105       d = (iso9660_dir_record *) ((uint8 *) d + d->length);
0106 
0107       // skip zeroes
0108       while (*((uint8 *)d) == 0 && (count % ATAPI_SECTOR_SIZE) != 0) {
0109         d = (iso9660_dir_record *) (((uint8 *)d) + 1);
0110         count++;
0111       }
0112     }
0113     unmap_virtual_page (sector);
0114     free_phys_frame (frame);
0115   }
0116 }
0117 
0118 
0119 int
0120 iso9660_mount (uint32 bus, uint32 drive, iso9660_mounted_info * mi)
0121 {
0122   uint32 frame = alloc_phys_frame ();
0123   uint8 *page = map_virtual_page (frame | 3);
0124   int len;
0125 
0126   /* The first 16 sectors (0-15) are empty. */
0127 
0128   /* Primary Volume descriptor */
0129   len = atapi_drive_read_sector (bus, drive, 16, page);
0130 
0131   if (len < 0) {
0132     com1_printf ("CD-ROM read error\n");
0133     return -1;
0134   }
0135 #if 0
0136   {
0137     int i, j;
0138     com1_printf ("Read %d bytes.\n", len);
0139     /* dump to com1 */
0140     for (i = 0; i < 128; i++) {
0141       for (j = 0; j < 16; j++) {
0142         com1_printf ("%.2X ", page[i * 16 + j]);
0143       }
0144       com1_printf ("\n");
0145     }
0146   }
0147 
0148   com1_printf ("Sys ID: %.32s\n", page + 8);
0149   com1_printf ("Vol ID: %.32s\n", page + 40);
0150   com1_printf ("# Sectors: %.8X\n", *(uint32 *) (page + 80));
0151   com1_printf ("Path Table: len=%.8X fst=", *(uint32 *) (page + 132));
0152   com1_printf ("%.8X snd=%.8X\n", *(uint32 *) (page + 140),
0153                *(uint32 *) (page + 144));
0154   /* root dir @ 156 */
0155   iso9660_show_dir_record (page + 156);
0156   com1_printf ("Vol Set ID: %.128s\n", page + 190);
0157   com1_printf ("Pub ID: %.128s\n", page + 318);
0158   com1_printf ("Preparer ID: %.128s\n", page + 318 + 128);
0159   com1_printf ("Application ID: %.128s\n", page + 318 + 256);
0160   com1_printf ("Copyright File ID: %.37s\n", page + 318 + 384);
0161   com1_printf ("Abstract File ID: %.37s\n", page + 318 + 384 + 37);
0162   com1_printf ("Bib File ID: %.37s\n", page + 318 + 384 + 37 + 37);
0163   com1_printf ("Creation Date: ");
0164   iso9660_date_record (page + 318 + 384 + 37 + 37 + 37);
0165   com1_printf ("\n");
0166   com1_printf ("Modification Date: ");
0167   iso9660_date_record (page + 318 + 384 + 37 + 37 + 37 + 17);
0168   com1_printf ("\n");
0169   com1_printf ("Expiration Date: ");
0170   iso9660_date_record (page + 318 + 384 + 37 + 37 + 37 + 34);
0171   com1_printf ("\n");
0172   com1_printf ("Effective Date: ");
0173   iso9660_date_record (page + 318 + 384 + 37 + 37 + 37 + 51);
0174   com1_printf ("\n");
0175 
0176   iso9660_walk_tree (bus, drive, (iso9660_dir_record *) (page + 156), 0);
0177 
0178 #endif
0179 
0180   mi->bus = bus;
0181   mi->drive = drive;
0182   mi->root_dir_sector = ((iso9660_dir_record *) (page + 156))->first_sector;
0183   mi->root_dir_data_length =
0184     ((iso9660_dir_record *) (page + 156))->data_length;
0185 
0186   unmap_virtual_page (page);
0187   free_phys_frame (frame);
0188   return 0;
0189 }
0190 
0191 /* Parse out the first component of a pathname: the first string
0192  * portion between the (optional) first slash and the second slash.
0193  * Uses in/out parameters start and end.  On input they define the
0194  * bounds of the search.  On output they define the bounds of the
0195  * first component.  Return value is 0 if this is also the last
0196  * component, or 1 if there are other components remaining. */
0197 static int
0198 iso9660_parse_first_component (char *pathname, int *start, int *end)
0199 {
0200   int i;
0201 
0202   /* Skip leading slashes */
0203   for (; pathname[*start] == PATHSEP; (*start)++);
0204   /* Find next slash or nul within bounds */
0205   for (i = *start; pathname[i] != PATHSEP && pathname[i] != '\0' && i < *end;
0206        i++);
0207   *end = i;
0208 
0209   return (pathname[*end] == '\0' ? 0 : 1);
0210 }
0211 
0212 #define TOUPPER(c) ('a' <= c && c <= 'z' ? c + ('A' - 'a') : c)
0213 
0214 static int
0215 iso9660_filename_compare (char *a, int a_len, char *b, int b_len)
0216 {
0217   int i = 0;
0218   while (i < a_len && i < b_len) {
0219     if (TOUPPER (a[i]) != TOUPPER (b[i]))
0220       return -1;
0221     i++;
0222     if (a[i] == '.' && i == b_len)
0223       return 0;
0224     else if (i == a_len && b[i] == '.')
0225       return 0;
0226     else if (a[i] == ';' && i == b_len)
0227       return 0;
0228     else if (i == a_len && b[i] == ';')
0229       return 0;
0230     else if (i == a_len && i < b_len)
0231       return -1;
0232     else if (i < a_len && i == b_len)
0233       return -1;
0234   }
0235   return 0;
0236 }
0237 
0238 
0239 static int
0240 iso9660_search_dir (iso9660_mounted_info * mi,
0241                     iso9660_dir_record * d,
0242                     char *pathname, int start, int end,
0243                     iso9660_dir_record * de)
0244 {
0245   uint32 frame;
0246   uint8 *page;
0247   int len = end - start;
0248 
0249   frame = alloc_phys_frame ();
0250   page = map_virtual_page (frame | 3);
0251 
0252   uint32 secnum = d->first_sector;
0253   uint32 num_bytes = d->data_length;
0254   uint32 count;
0255 
0256   for (count = 0; count < num_bytes;) {
0257     if (count % ATAPI_SECTOR_SIZE == 0) {
0258       // if 2048-byte aligned get next sector
0259       if (atapi_drive_read_sector (mi->bus, mi->drive, secnum, page) < 0) {
0260         panic ("CD ROM READ ERROR\n");
0261       }
0262       secnum++;
0263       d = (iso9660_dir_record *) page;
0264     }
0265 
0266     if (iso9660_filename_compare (pathname + start, len,
0267                                   (char *) d->identifier,
0268                                   d->identifier_length) == 0)
0269       break;                    /* found it */
0270 
0271 
0272     count += d->length;
0273     d = (iso9660_dir_record *) ((uint8 *) d + d->length);
0274 
0275     // skip zeroes
0276     while (*((uint8 *)d) == 0 && (count % ATAPI_SECTOR_SIZE) != 0) {
0277       d = (iso9660_dir_record *) (((uint8 *)d) + 1);
0278       count++;
0279     }
0280   }
0281 
0282   if (count >= num_bytes)
0283     goto error;
0284 
0285   *de = *d;
0286 
0287   unmap_virtual_page (page);
0288   free_phys_frame (frame);
0289   return 0;
0290  error:
0291   unmap_virtual_page (page);
0292   free_phys_frame (frame);
0293   return -1;
0294 }
0295 
0296 
0297 int
0298 iso9660_open (iso9660_mounted_info * mi, char *pathname, iso9660_handle * h)
0299 {
0300   int len = 0, start = 0, end;
0301   iso9660_dir_record d, de;
0302   d.first_sector = mi->root_dir_sector;
0303   d.data_length = mi->root_dir_data_length;
0304 
0305   if (pathname[0] != PATHSEP)
0306     return -1;
0307   while (pathname[len])
0308     len++;
0309 
0310   for (;;) {
0311     end = len;
0312     if (iso9660_parse_first_component (pathname, &start, &end) == 0) {
0313       if (start == end)
0314         return -1;
0315 
0316       if ((iso9660_search_dir (mi, &d, pathname, start, end, &de)) < 0) {
0317         return -1;
0318       }
0319 
0320       h->mount = mi;
0321       h->sector = de.first_sector;
0322       h->offset = 0;
0323       h->length = de.data_length;
0324       return 0;
0325     } else {
0326       /* This component is a directory name. */
0327       if ((iso9660_search_dir (mi, &d, pathname, start, end, &de)) < 0) {
0328         return -1;
0329       } else {
0330         d = de;
0331       }
0332       start = end;              /* move forward to next component */
0333     }
0334   }
0335 }
0336 
0337 int
0338 iso9660_read (iso9660_handle * h, uint8 * buf, uint32 len)
0339 {
0340   int n, count = 0, rem = len, curlen;
0341   iso9660_mounted_info *mi = h->mount;
0342   uint32 frame;
0343   uint8 *page;
0344 
0345   frame = alloc_phys_frame ();
0346   page = map_virtual_page (frame | 3);
0347 
0348   while (count < len) {
0349     n = atapi_drive_read_sector (mi->bus, mi->drive, h->sector, page);
0350     if (n < 0)
0351       goto error;
0352 
0353     curlen = rem > (n - h->offset) ? (n - h->offset) : rem;
0354 
0355     memcpy (buf + count, page + h->offset, curlen);
0356 
0357     rem -= curlen;
0358     count += curlen;
0359     h->offset += curlen;
0360     h->length -= curlen;
0361     if (h->offset == 2048) {
0362       h->sector++;
0363       h->offset = 0;
0364     }
0365   }
0366 
0367 
0368   unmap_virtual_page (page);
0369   free_phys_frame (frame);
0370   return count;
0371 error:
0372   unmap_virtual_page (page);
0373   free_phys_frame (frame);
0374   return -1;
0375 }
0376 
0377 static iso9660_mounted_info eziso_mount_info;
0378 
0379 #if 0
0380 uint8 test1_buf[2958];
0381 #endif
0382 
0383 static bool mounted = FALSE;
0384 
0385 int
0386 eziso_mount (uint32 bus, uint32 drive)
0387 {
0388   int v;
0389 
0390   v = iso9660_mount (bus, drive, &eziso_mount_info);
0391 
0392 #if 0
0393   if (iso9660_open (&eziso_mount_info, "/boot/test1", &h) == 0) {
0394     int i, j;
0395     iso9660_handle h;
0396     com1_printf ("OPEN SUCCEEDED\n");
0397 
0398     if (iso9660_read (&h, test1_buf, 2958) < 0) {
0399       com1_printf ("READ FAILED\n");
0400     } else {
0401       for (i = 0; i < 8; i++) {
0402         for (j = 0; j < 8; j++)
0403           com1_printf (" %.2X", (test1_buf + (2958 - 64))[i * 8 + j]);
0404         com1_printf ("\n");
0405       }
0406     }
0407 
0408   } else
0409     com1_printf ("OPEN FAILED\n");
0410 #endif
0411 
0412   if (v == 0) {
0413     mounted = TRUE;
0414     return 1;
0415   } else
0416     return 0;
0417 }
0418 
0419 static iso9660_handle eziso_handle;
0420 int
0421 eziso_dir (char *pathname)
0422 {
0423   if (!mounted) {
0424     int i;
0425     for (i=0; i<4; i++) {
0426       if (pata_drives[i].ata_type == ATA_TYPE_PATAPI) {
0427         if (eziso_mount (pata_drives[i].ata_bus,
0428                          pata_drives[i].ata_drive))
0429           break;
0430       }
0431     }
0432   }
0433   if (iso9660_open (&eziso_mount_info, pathname, &eziso_handle) == 0)
0434     return eziso_handle.length;
0435   else
0436     return -1;
0437 }
0438 
0439 int
0440 eziso_read (char *buf, int len)
0441 {
0442   int n;
0443   if ((n = iso9660_read (&eziso_handle, (uint8 *) buf, len)) < 0)
0444     return 0;
0445   return n;
0446 }
0447 
0448 /* 
0449  * Local Variables:
0450  * indent-tabs-mode: nil
0451  * mode: C
0452  * c-file-style: "gnu"
0453  * c-basic-offset: 2
0454  * End: 
0455  */
0456 
0457 /* vi: set et sw=2 sts=2: */