changeset 1818:5663e2763ba6

* src/fatfs.c: * src/fatfs_supp.c: * include/fatfs.h (NEW): * tests/fileio1.c: * cdl/fatfs.cdl: Added configurable support for FAT filesystem attributes. * src/fatfs.c: Added code to setinfo to allow performing a file-system sync
author asl
date Fri, 22 Oct 2004 14:10:21 +0000
parents df5dcf4cdc1a
children 082e09d84412
files packages/fs/fat/current/ChangeLog packages/fs/fat/current/cdl/fatfs.cdl packages/fs/fat/current/include/fatfs.h packages/fs/fat/current/src/fatfs.c packages/fs/fat/current/src/fatfs.h packages/fs/fat/current/src/fatfs_supp.c packages/fs/fat/current/tests/fileio1.c
diffstat 7 files changed, 350 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/packages/fs/fat/current/ChangeLog
+++ b/packages/fs/fat/current/ChangeLog
@@ -1,3 +1,17 @@
+2004-10-17  David Brennan  <eCos@brennanhome.com>
+
+	* src/fatfs.c:
+	* src/fatfs_supp.c:
+	* include/fatfs.h (NEW):
+	* tests/fileio1.c:
+	* cdl/fatfs.cdl: Added configurable support for FAT filesystem
+	attributes.
+
+2004-10-13  David Brennan  <eCos@brennanhome.com>
+
+	* src/fatfs.c: Added code to setinfo to allow performing a
+	file-system sync
+
 2004-10-06  David Brennan  <eCos@brennanhome.com>
 
 	* tests/fileio1.c: Added include of <stdio.h> to fix compiler
--- a/packages/fs/fat/current/cdl/fatfs.cdl
+++ b/packages/fs/fat/current/cdl/fatfs.cdl
@@ -48,7 +48,7 @@
 
 cdl_package CYGPKG_FS_FAT {
     display         "FAT filesystem"
-    include_dir     cyg/fatfs
+    include_dir     cyg/fs
 
     requires        CYGPKG_IO_FILEIO
 
@@ -57,7 +57,6 @@ cdl_package CYGPKG_FS_FAT {
     requires        CYGINT_ISO_ERRNO_CODES
     requires        CYGPKG_MEMALLOC
     requires        CYGPKG_BLOCK_LIB
-#    requires        CYGFUN_LIBC_STRING_BSD_FUNCS
 
     implements      CYGINT_IO_FILEIO_FS
     
@@ -105,6 +104,14 @@ cdl_package CYGPKG_FS_FAT {
                          sanity checks in node cache code."
     }
     
+    cdl_option      CYGCFG_FS_FAT_USE_ATTRIBUTES {
+        display         "Support for FAT FS file attributes"
+        flavor          bool
+        default_value   0
+        description     "This option controls if the FAT filesystem supports
+                         or honors the FAT filesystem file attributes."
+    }
+    
     # --------------------------------------------------------------------
     
     cdl_option      CYGPKG_FS_FAT_TESTS {
new file mode 100644
--- /dev/null
+++ b/packages/fs/fat/current/include/fatfs.h
@@ -0,0 +1,84 @@
+#ifndef CYGONCE_CYG_FS_FAT_H
+#define CYGONCE_CYG_FS_FAT_H
+//=============================================================================
+//
+//      fatfs.h
+//
+//      FAT FS attributes and stat information
+//
+//=============================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//=============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     David Brennam <eCos@brennanhome.com>
+// Contributors:  
+// Date:          2004-10-22
+// Purpose:       
+// Description:   This header contains attributes and stat like mode
+//                information for FAT filesystems.
+//              
+// Usage:
+//              #include <cyg/fs/fatfs.h>
+//              
+//
+//####DESCRIPTIONEND####
+//
+//=============================================================================
+// -------------------------------------------------------------------------
+// FAT filesystem dir entry attributes
+
+#define S_FATFS_RDONLY  (0x01) // Read only
+#define S_FATFS_HIDDEN  (0x02) // Hidden
+#define S_FATFS_SYSTEM  (0x04) // System
+#define S_FATFS_VOLUME  (0x08) // Volume label
+#define S_FATFS_DIR     (0x10) // Subdirectory
+#define S_FATFS_ARCHIVE (0x20) // Needs archiving
+
+// Mode bits which are allowed to be changed by attrib
+#define S_FATFS_ATTRIB   (S_FATFS_RDONLY | S_FATFS_HIDDEN | S_FATFS_SYSTEM | \
+                          S_FATFS_ARCHIVE)
+// -------------------------------------------------------------------------
+// mode FAT dir entry attributes macros
+
+#define S_FATFS_ISRDONLY(__mode)  ((__mode) & S_FATFS_RDONLY)
+#define S_FATFS_ISHIDDEN(__mode)  ((__mode) & S_FATFS_HIDDEN)
+#define S_FATFS_ISSYSTEM(__mode)  ((__mode) & S_FATFS_SYSTEM)
+#define S_FATFS_ISVOLUME(__mode)  ((__mode) & S_FATFS_VOLUME)
+#define S_FATFS_ISDIR(__mode)     ((__mode) & S_FATFS_DIR)
+#define S_FATFS_ISARCHIVE(__mode) ((__mode) & S_FATFS_ARCHIVE)
+
+#endif // CYGONCE_CYG_FS_FAT_H
+// End of fatfs.h
+
--- a/packages/fs/fat/current/src/fatfs.c
+++ b/packages/fs/fat/current/src/fatfs.c
@@ -73,6 +73,7 @@
 #include <cyg/fileio/fileio.h>
 #include <cyg/io/io.h>
 #include <blib/blib.h>
+#include <cyg/fs/fatfs.h>
 
 #include "fatfs.h"
 
@@ -629,6 +630,13 @@ fatfs_open(cyg_mtab_entry *mte,
     if (S_ISDIR(node->dentry.mode))
         return EISDIR;
 
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    // if the file is read only and is opened for writing
+    // fail with permission error
+    if (S_FATFS_ISRDONLY(node->dentry.attrib) && (mode & O_WRONLY))
+        return EACCES;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
     // Allocate file object private data and
     // make a reference to this file node
 
@@ -678,6 +686,12 @@ fatfs_unlink(cyg_mtab_entry *mte,
     if (ds.node->refcnt > 0)
         return EBUSY;
     
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    // if the file is read only fail with permission error
+    if (S_FATFS_ISRDONLY(ds.node->dentry.attrib))
+        return EPERM;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
     err = fatfs_delete_file(disk, &ds.node->dentry);
     if (err == ENOERR)
         fatfs_node_free(disk, ds.node);
@@ -789,6 +803,12 @@ fatfs_rename(cyg_mtab_entry *mte,
     if (err != ENOERR)
         return err;
 
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    // if the file is read only fail with permission error
+    if (S_FATFS_ISRDONLY(ds1.node->dentry.attrib))
+        return EPERM;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
     // Protect the found nodes from being reused 
     // by the search for the ds2 dir/node pair 
     fatfs_node_ref(disk, ds1.dir);
@@ -983,6 +1003,10 @@ fatfs_stat(cyg_mtab_entry *mte,
     // Fill in the status
     
     buf->st_mode   = ds.node->dentry.mode;
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    if (!S_FATFS_ISRDONLY(ds.node->dentry.attrib))
+        buf->st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
     buf->st_ino    = (ino_t) ds.node->dentry.cluster;
     buf->st_dev    = 0;
     buf->st_nlink  = 1;
@@ -996,9 +1020,75 @@ fatfs_stat(cyg_mtab_entry *mte,
     return ENOERR;
 }
 
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+// -------------------------------------------------------------------------
+// fatfs_set_attrib()
+// Set FAT file system attributes for specified file
+
+static int
+fatfs_set_attrib(cyg_mtab_entry        *mte,
+                 cyg_dir                dir,
+                 const char            *name,
+                 const cyg_fs_attrib_t  new_attrib)
+{
+    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
+    fatfs_dirsearch_t  ds;
+    int                err;
+
+    CYG_TRACE4(TFS, "chmod mte=%p dir=%p name='%s' buf=%x", 
+                    mte, dir, name, new_attrib);
+
+    // Verify new_mode is valid
+    if ((new_attrib & S_FATFS_ATTRIB) != new_attrib)
+        return EINVAL;
+    
+    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
+
+    err = fatfs_find(&ds);
+    if (err != ENOERR)
+        return err;
+
+    // Change the "changeable" mode bits for the file.
+    ds.node->dentry.attrib = 
+      (ds.node->dentry.attrib & (~S_FATFS_ATTRIB)) | new_attrib;
+
+    return fatfs_write_dir_entry(disk,&ds.node->dentry);
+}
+
+// -------------------------------------------------------------------------
+// fatfs_get_attrib()
+// Set FAT file system attributes for specified file
+
+static int
+fatfs_get_attrib(cyg_mtab_entry  *mte,
+                 cyg_dir          dir,
+                 const char      *name,
+                 cyg_fs_attrib_t * const file_attrib)
+{
+    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
+    fatfs_dirsearch_t  ds;
+    int                err;
+
+    CYG_TRACE4(TFS, "chmod mte=%p dir=%p name='%s' buf=%x", 
+                    mte, dir, name, new_attrib);
+
+    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
+
+    err = fatfs_find(&ds);
+    if (err != ENOERR)
+        return err;
+
+    // Get the attribute field
+    CYG_CHECK_DATA_PTR(file_attrib,"Invalid destination attribute pointer");
+    *file_attrib = ds.node->dentry.attrib;
+
+    return ENOERR;
+}
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
 // -------------------------------------------------------------------------
 // fatfs_getinfo()
-// Getinfo. Nothing to support here at present.
+// Getinfo. Support for attrib
 
 static int 
 fatfs_getinfo(cyg_mtab_entry *mte, 
@@ -1008,14 +1098,27 @@ fatfs_getinfo(cyg_mtab_entry *mte,
               void           *buf, 
               int             len)
 {
+    int err = EINVAL;
+
     CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
                     mte, dir, name, key, buf, len);
-    return EINVAL;
+    switch( key )
+    {
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+        case FS_INFO_ATTRIB:
+            err = fatfs_get_attrib(mte, dir, name, (cyg_fs_attrib_t*)buf);
+            break;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+        default:
+            err = EINVAL;
+            break;
+    }
+    return err;
 }
 
 // -------------------------------------------------------------------------
 // fatfs_setinfo()
-// Setinfo. Nothing to support here at present.
+// Setinfo. Support for fssync and attrib
 
 static int 
 fatfs_setinfo(cyg_mtab_entry *mte, 
@@ -1025,9 +1128,26 @@ fatfs_setinfo(cyg_mtab_entry *mte,
               void           *buf, 
               int             len)
 {
-    CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
+    int err = EINVAL;
+
+    CYG_TRACE6(TFS, "setinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
                     mte, dir, name, key, buf, len);
-    return EINVAL;
+
+    switch( key )
+    {
+        case FS_INFO_SYNC:
+            err = cyg_blib_sync(&(((fatfs_disk_t *) mte->data)->blib));
+            break;
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+        case FS_INFO_ATTRIB:
+            err = fatfs_set_attrib(mte, dir, name, *(cyg_fs_attrib_t *)buf);
+            break;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+        default:
+            err = EINVAL;
+            break;
+    }
+    return err;
 }
 
 //==========================================================================
--- a/packages/fs/fat/current/src/fatfs.h
+++ b/packages/fs/fat/current/src/fatfs.h
@@ -124,6 +124,9 @@ typedef struct fatfs_dir_entry_s
     cyg_uint32        cluster;        // First cluster number
     cyg_uint32        parent_cluster; // First cluster of parent dentry
     fatfs_data_pos_t  disk_pos;       // Position of dir entry on disk
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    cyg_fs_attrib_t    attrib;     // Attribute bits for DOS compatability
+#endif //CYGCFG_FS_FAT_USE_ATTRIBUTES
 } fatfs_dir_entry_t;
 
 typedef struct fatfs_node_s
--- a/packages/fs/fat/current/src/fatfs_supp.c
+++ b/packages/fs/fat/current/src/fatfs_supp.c
@@ -53,6 +53,7 @@
 #include <cyg/infra/cyg_trac.h>
 #include <cyg/infra/diag.h>
 #include <cyg/io/io.h>
+#include <cyg/fs/fatfs.h>
 #include <blib/blib.h>
 
 #include <sys/types.h>
@@ -64,24 +65,14 @@
 // FAT defines & macros
 
 // -------------------------------------------------------------------------
-// FAT dir entry attributes
-
-#define DENTRY_ATTR_RDONLY  0x01 // Read only
-#define DENTRY_ATTR_HIDDEN  0x02 // Hidden
-#define DENTRY_ATTR_SYSTEM  0x04 // System
-#define DENTRY_ATTR_VOLUME  0x08 // Volume label
-#define DENTRY_ATTR_DIR     0x10 // Subdirectory
-#define DENTRY_ATTR_ARCHIVE 0x20 // Needs archiving
-
-// -------------------------------------------------------------------------
 // FAT dir entry attributes macros
 
-#define DENTRY_IS_RDONLY(_dentry_)  ((_dentry_)->attr & DENTRY_ATTR_RDONLY)
-#define DENTRY_IS_HIDDEN(_dentry_)  ((_dentry_)->attr & DENTRY_ATTR_HIDDEN)
-#define DENTRY_IS_SYSTEM(_dentry_)  ((_dentry_)->attr & DENTRY_ATTR_SYSTEM)
-#define DENTRY_IS_VOLUME(_dentry_)  ((_dentry_)->attr & DENTRY_ATTR_VOLUME)
-#define DENTRY_IS_DIR(_dentry_)     ((_dentry_)->attr & DENTRY_ATTR_DIR)
-#define DENTRY_IS_ARCHIVE(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_ARCHIVE)
+#define DENTRY_IS_RDONLY(_dentry_)  (S_FATFS_ISRDONLY((_dentry_)->attr))
+#define DENTRY_IS_HIDDEN(_dentry_)  (S_FATFS_ISHIDDEN((_dentry_)->attr))
+#define DENTRY_IS_SYSTEM(_dentry_)  (S_FATFS_ISSYSTEM((_dentry_)->attr))
+#define DENTRY_IS_VOLUME(_dentry_)  (S_FATFS_ISVOLUME((_dentry_)->attr))
+#define DENTRY_IS_DIR(_dentry_)     (S_FATFS_ISDIR((_dentry_)->attr))
+#define DENTRY_IS_ARCHIVE(_dentry_) (S_FATFS_ISARCHIVE((_dentry_)->attr))
 
 #define DENTRY_IS_DELETED(_dentry_) \
     (0xE5 == (cyg_uint8)((_dentry_)->name[0]))
@@ -1624,6 +1615,10 @@ raw_to_dentry(fat_raw_dir_entry_t *raw_d
     else
         dentry->mode = __stat_mode_REG;
     
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    dentry->attrib = raw_dentry->attr;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
     date_dos2unix(raw_dentry->crt_time, raw_dentry->crt_date, &dentry->ctime);
     date_dos2unix(0,                    raw_dentry->acc_date, &dentry->atime);
     date_dos2unix(raw_dentry->wrt_time, raw_dentry->wrt_date, &dentry->mtime);
@@ -1644,9 +1639,13 @@ dentry_to_raw(fatfs_dir_entry_t *dentry,
     set_raw_dentry_filename(raw_dentry, dentry->filename, 0);
 
     if (__stat_mode_DIR == dentry->mode)
-        raw_dentry->attr = DENTRY_ATTR_DIR;
+        raw_dentry->attr = S_FATFS_DIR;
     else
-        raw_dentry->attr = DENTRY_ATTR_ARCHIVE;
+        raw_dentry->attr = S_FATFS_ARCHIVE;
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    raw_dentry->attr = dentry->attrib;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
         
     date_unix2dos(dentry->ctime, &raw_dentry->crt_time, &raw_dentry->crt_date);
     date_unix2dos(dentry->atime, NULL,                  &raw_dentry->acc_date);
@@ -1808,6 +1807,14 @@ init_dir_entry(fatfs_dir_entry_t *dentry
     dentry->filename[namelen] = '\0';
     
     dentry->mode  = mode;
+
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    if (S_ISDIR(dentry->mode))
+        dentry->attrib = S_FATFS_DIR;
+    else
+        dentry->attrib = S_FATFS_ARCHIVE;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
     dentry->ctime = 
     dentry->atime =
     dentry->mtime = cyg_timestamp();
@@ -1939,6 +1946,9 @@ fatfs_get_root_dir_entry(fatfs_disk_t *d
     CYG_CHECK_DATA_PTRC(dentry);
     
     dentry->mode           = __stat_mode_DIR;
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    dentry->attrib         = S_FATFS_DIR;
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
     dentry->size           = disk->fat_root_dir_size;
     dentry->ctime          = 0;
     dentry->atime          = 0;
@@ -2389,7 +2399,7 @@ fatfs_rename_file(fatfs_disk_t      *dis
  
     // If we moved a directory, we also have to correct the '..' entry  
 
-    if (__stat_mode_DIR == target->mode)
+    if ( S_ISDIR(target->mode) )
     {
         fat_raw_dir_entry_t raw_cdentry;
         fatfs_data_pos_t    pos;
--- a/packages/fs/fat/current/tests/fileio1.c
+++ b/packages/fs/fat/current/tests/fileio1.c
@@ -60,6 +60,7 @@
 #include <pkgconf/hal.h>
 #include <pkgconf/kernel.h>
 #include <pkgconf/io_fileio.h>
+#include <pkgconf/fs_fat.h>
 
 #include <cyg/kernel/ktypes.h>         // base kernel types
 #include <cyg/infra/cyg_trac.h>        // tracing macros
@@ -77,6 +78,7 @@
 
 #include <cyg/infra/testcase.h>
 #include <cyg/infra/diag.h>            // HAL polled output
+#include <cyg/fs/fatfs.h>
 
 
 
@@ -288,6 +290,26 @@ static void checkfile( char *name )
     if( err < 0 ) SHOW_RESULT( close, err );
 }
 
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+//==========================================================================
+
+static void checkattrib(const char *name, 
+                        const cyg_fs_attrib_t test_attrib )
+{
+    int err;
+    cyg_fs_attrib_t file_attrib;
+
+    diag_printf("<INFO>: check attrib %s\n",name);
+
+    err = cyg_fs_get_attrib(name, &file_attrib);
+    if( err != 0 ) SHOW_RESULT( stat, err );
+
+    if ( (file_attrib & S_FATFS_ATTRIB) != test_attrib )
+        diag_printf("<FAIL>: attrib %s incorrect\n\tExpected %x Was %x\n",
+                    name,test_attrib,(file_attrib & S_FATFS_ATTRIB));
+}
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
 //==========================================================================
 
 static void copyfile( char *name2, char *name1 )
@@ -643,6 +665,70 @@ void fileio1_main( CYG_ADDRESS id )
     if( err < 0 ) SHOW_RESULT( umount, err );    
 #endif
     
+#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
+    // Create file
+    diag_printf("<INFO>: create /foo\n");
+    createfile( "/foo", 20257 );
+
+    // Verify it is created with archive bit set
+    checkattrib( "/foo", S_FATFS_ARCHIVE );
+
+    // Make it System
+    diag_printf("<INFO>: attrib -A+S /foo\n");
+    err = cyg_fs_set_attrib( "/foo", S_FATFS_SYSTEM );
+    if( err < 0 ) SHOW_RESULT( chmod system , err );
+
+    // Verify it is now System
+    checkattrib( "/foo", S_FATFS_SYSTEM );
+
+    // Make it Hidden
+    diag_printf("<INFO>: attrib -S+H /foo\n");
+    err = cyg_fs_set_attrib( "/foo", S_FATFS_HIDDEN );
+    if( err < 0 ) SHOW_RESULT( chmod system , err );
+
+    // Verify it is now Hidden
+    checkattrib( "/foo", S_FATFS_HIDDEN );
+
+    // Make it Read-only
+    diag_printf("<INFO>: attrib -H+R /foo\n");
+    err = cyg_fs_set_attrib( "/foo", S_FATFS_RDONLY );
+    if( err < 0 ) SHOW_RESULT( chmod system , err );
+
+    // Verify it is now Read-only
+    checkattrib( "/foo", S_FATFS_RDONLY );
+
+    // Verify we cannot unlink a read-only file
+    diag_printf("<INFO>: unlink /foo\n");
+    err = unlink( "/foo" );
+    if( err != -EPERM ) SHOW_RESULT( unlink, err );
+
+    // Verify we cannot rename a read-only file
+    diag_printf("<INFO>: rename /foo bundy\n");
+    err = rename( "/foo", "bundy" );
+    if( err != -EPERM ) SHOW_RESULT( rename, err );
+
+    // Verify we cannot open read-only file for writing
+    int fd;
+    diag_printf("<INFO>: create file /foo\n");
+    fd = open( "/foo", O_WRONLY );
+    if( err != -EPERM ) SHOW_RESULT( rename, err );
+    if( err > 0 ) close(fd);
+
+    // Make it Normal
+    diag_printf("<INFO>: attrib -H /foo\n");
+    err = cyg_fs_set_attrib( "/foo", 0 );
+    if( err < 0 ) SHOW_RESULT( chmod none , err );
+
+    // Verify it is now nothing
+    checkattrib( "/foo", 0 );
+
+    // Now delete our test file
+    diag_printf("<INFO>: unlink /foo\n");
+    err = unlink( "/foo" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+
     maxfile("file.max");
 
     listdir( "/", true, -1, NULL );    
@@ -650,7 +736,6 @@ void fileio1_main( CYG_ADDRESS id )
     diag_printf("<INFO>: unlink file.max\n");    
     err = unlink( "file.max" );
     if( err < 0 ) SHOW_RESULT( unlink, err );    
-
     diag_printf("<INFO>: umount /\n");    
     err = umount( "/" );
     if( err < 0 ) SHOW_RESULT( umount, err );