]> git.sur5r.net Git - cc65/blobdiff - libsrc/cbm/cbm_dir.c
Protect random counter against ProDOS.
[cc65] / libsrc / cbm / cbm_dir.c
index b46df177a816086f4498574e4eeb7b8a8437bb00..8f31c502ad70a6ed0bf18931031161310d328d1a 100644 (file)
-/* This is very simplified version of POSIX opendir(), readdir() and closedir() */
-/* for Commodore computers.                                                     */
-/* Created by Josef Soucek, 2003    E-mail:josef.soucek@ct.cz                   */
+/* This is a very simplified version of the POSIX opendir(),  */
+/* readdir(), and closedir() -- for Commodore computers.      */
+/* Created by Josef Soucek, 2003.  E-mail: josef.soucek@ct.cz */
 
-/* Version 0.1 - 21.1.2003 */
-/* Tested with floppy drive and IDE64 devices                                   */
-/* Not tested with messed (buggy) directory listing                             */
-/* Limits filenames to 16 chars (VICE supports more in directory listing)       */
+/* 2003-01-21 -- Version 0.1 */
+/* 2009-10-10 -- Version 0.3 */
+/* 2011-04-07 -- Version 0.4, groepaz */
+/* 2011-04-14 -- Version 0.5, Greg King */
 
+/* Tested with floppy-drive and IDE64 devices.        */
+/* Not tested with messed (buggy) directory listings. */
+/* Limits filenames to 16 chars. (VICE supports more  */
+/* in directory listings).                            */
 
 
+#include <stdarg.h>
 #include <cbm.h>
+#include <errno.h>
 
 
 
-unsigned char __fastcall__ cbm_opendir (unsigned char lfn, unsigned char device)
+/* Opens directory listing. Returns 0 if opening directory was successful;
+** otherwise, an error-code corresponding to cbm_open(). As an optional
+** argument, the name of the directory may be passed to the function. If
+** no explicit name is specified, "$" is used.
+*/
+unsigned char cbm_opendir (unsigned char lfn, unsigned char device, ...)
 {
-    unsigned char status;
-    if ((status = cbm_open (lfn, device, CBM_READ, "$")) == 0) {
-        if (cbm_k_chkin (lfn) == 0) {
-            if (cbm_k_basin () == 0x01) {         /* Start address */
-                if (cbm_k_basin () == 0x04) {
-                    cbm_k_clrch ();
-                    return 0;
-                }
-            } else {
-                cbm_close (lfn);
-                cbm_k_clrch ();
-                return 2;
+    va_list ap;
+    const char* name = "$";
+
+    /* The name used in cbm_open may optionally be passed */
+    if (__argsize__ == 4) {
+        va_start (ap, device);
+        name = va_arg (ap, const char*);
+        va_end (ap);
+    }
+
+    /* Open the directory */
+    if (cbm_open (lfn, device, CBM_READ, name) == 0) {
+        if ((_oserror = cbm_k_chkin (lfn)) == 0) {
+            /* Ignore start address */
+            cbm_k_basin();
+            cbm_k_basin();
+            cbm_k_clrch();
+            if (cbm_k_readst()) {
+                cbm_close(lfn);
+                _oserror = 4;           /* directory cannot be read */
             }
         }
     }
-    return status;
+    return _oserror;
 }
 
 
 
+/* Reads one directory line into cbm_dirent structure.
+** Returns 0 if reading directory-line was successful.
+** Returns non-zero if reading directory failed, or no more file-names to read.
+** Returns 2 on last line.  Then, l_dirent->size = the number of "blocks free."
+*/
 unsigned char __fastcall__ cbm_readdir (unsigned char lfn, register struct cbm_dirent* l_dirent)
 {
-    unsigned char byte, i;
-    unsigned char rv;
-    unsigned char is_header;
-    static const unsigned char types[] = { 
-        CBM_T_OTHER, CBM_T_OTHER, CBM_T_CBM,   CBM_T_DIR,   /* a b c d */
-        CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, /* e f g h */
-        CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, /* i j k l */
-        CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, CBM_T_PRG,   /* m n o p */
-        CBM_T_OTHER, CBM_T_REL,   CBM_T_SEQ,   CBM_T_OTHER, /* q r s t */
-        CBM_T_USR,   CBM_T_VRP                              /* u v     */
-    };
-
-    rv = 1;
-    is_header = 0;
+    unsigned char byte, i = 0;
+    unsigned char is_header = 0;
+    unsigned char rv = 1;
 
     if (!cbm_k_chkin(lfn)) {
         if (!cbm_k_readst()) {
-            /* skip 2 bytes, next basic line pointer */
+            /* skip 2 bytes, next-BASIC-line pointer */
             cbm_k_basin();
             cbm_k_basin();
 
-            /* File-size */
-            l_dirent->size = cbm_k_basin() | ((cbm_k_basin()) << 8);
+            /* File-size or drive/partition number */
+            l_dirent->size = cbm_k_basin() | (cbm_k_basin() << 8);
 
             byte = cbm_k_basin();
+            switch (byte) {
 
-            /* "B" BLOCKS FREE. */
-            if (byte == 'b') {
-                /* Read until end, careless callers may call us again */
+                /* "B" BLOCKS FREE. */
+              case 'b':
+                /* Read until end; careless callers might call us again. */
                 while (!cbm_k_readst()) {
                     cbm_k_basin();
                 }
                 rv = 2; /* EOF */
                 goto ret_val;
-            }
 
-            /* reverse text shows that this is the directory header */
-            if (byte == 0x12) { /* RVS_ON */
+                /* Reverse-text shows when this is the directory header. */
+              case 0x12:  /* RVS_ON */
                 is_header = 1;
             }
 
             while (byte != '\"') {
-                byte = cbm_k_basin();
                 /* prevent endless loop */
                 if (cbm_k_readst()) {
                     rv = 3;
                     goto ret_val;
                 }
+                byte = cbm_k_basin();
             }
 
-            i = 0;
             while ((byte = cbm_k_basin()) != '\"') {
                 /* prevent endless loop */
                 if (cbm_k_readst()) {
@@ -102,39 +114,57 @@ unsigned char __fastcall__ cbm_readdir (unsigned char lfn, register struct cbm_d
             }
             l_dirent->name[i] = '\0';
 
-            while ((byte = cbm_k_basin()) == ' ') {
-                /* prevent endless loop */
-                if (cbm_k_readst()) {
-                    rv = 5;
-                    goto ret_val;
-                }
-            }
-
             if (is_header) {
                 l_dirent->type = CBM_T_HEADER;
+
+                /* Get the disk-format code. */
+                i = 6;
+                do {
+                    l_dirent->access = byte = cbm_k_basin();
+                } while (--i != 0);
+
             } else {
-                if (byte >= 'a' && byte < 'a' + sizeof(types)) {
-                    l_dirent->type = types[byte - 'a'];
-                } else {
-                    l_dirent->type = CBM_T_OTHER;
+                /* Go to the file-type column. */
+                while ((byte = cbm_k_basin()) == ' ') {
+                    /* prevent endless loop */
+                    if (cbm_k_readst()) {
+                        rv = 5;
+                        goto ret_val;
+                    }
                 }
 
-                cbm_k_basin();
-                cbm_k_basin();
+                l_dirent->access = CBM_A_RW;
 
-                byte = cbm_k_basin();
+                /* "Splat" files shouldn't be read. */
+                if (byte == '*') {
+                    l_dirent->access = CBM_A_WO;
+                    byte = cbm_k_basin();
+                }
+
+                /* Determine the file type */
+                l_dirent->type = _cbm_filetype (byte);
 
-                l_dirent->access = (byte == 0x3C)? CBM_A_RO : CBM_A_RW;
+                /* Notice whether it's a directory or a deleted file. */
+                if (cbm_k_basin() == 'i' && byte == 'd') {
+                    l_dirent->type = CBM_T_DIR;
+                }
+                cbm_k_basin();
+
+                /* Locked files shouldn't be written. */
+                if ((byte = cbm_k_basin()) == '<') {
+                    l_dirent->access = (l_dirent->access == CBM_A_WO)
+                        ? 0 : CBM_A_RO;
+                }
             }
 
-            /* read to end of line */
+            /* Read to the end of the line. */
             while (byte != 0) {
-                byte = cbm_k_basin();
                 /* prevent endless loop */
                 if (cbm_k_readst()) {
                     rv = 6;
                     goto ret_val;
                 }
+                byte = cbm_k_basin();
             }
 
             rv = 0;
@@ -148,7 +178,8 @@ ret_val:
 }
 
 
-void __fastcall__ cbm_closedir( unsigned char lfn)
+
+void __fastcall__ cbm_closedir (unsigned char lfn)
 {
     cbm_close(lfn);
 }