/**************************************************************************** * examples/romfs/romfs_main.c * * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /* Mount the ROMFS image, Verifty that it contains the * following: * * testdir * |---------- [drwxr-xr-x 4096] adir * | |------ [-rw-r--r-- 21] anotherfile.txt * | |------ [drwxr-xr-x 4096] subdir * | | `-- [-rw-r--r-- 21] subdirfile.txt * | `------ [-rw-r--r-- 25] yafile.txt * |---------- [-rw-r--r-- 15] afile.txt * |---------- [-rw-r--r-- 21] hfile * `---------- [lrwxrwxrwx 11] ldir -> adir/subdir * * testdir/ldir is a soft-link and should not be detectable. * hfile is a hardlink to subdirfile and should be identical */ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "romfs_testdir.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Configuration settings */ #ifndef CONFIG_EXAMPLES_ROMFS_RAMDEVNO # define CONFIG_EXAMPLES_ROMFS_RAMDEVNO 1 #endif #ifndef CONFIG_EXAMPLES_ROMFS_SECTORSIZE # define CONFIG_EXAMPLES_ROMFS_SECTORSIZE 64 #endif #ifndef CONFIG_EXAMPLES_ROMFS_MOUNTPOINT # define CONFIG_EXAMPLES_ROMFS_MOUNTPOINT "/usr/local/share" #endif #ifdef CONFIG_DISABLE_MOUNTPOINT # error "Mountpoint support is disabled" #endif #if CONFIG_NFILE_DESCRIPTORS < 4 # error "Not enough file descriptors" #endif #ifndef CONFIG_FS_ROMFS # error "ROMFS support not enabled" #endif #define NSECTORS(b) (((b)+CONFIG_EXAMPLES_ROMFS_SECTORSIZE-1)/CONFIG_EXAMPLES_ROMFS_SECTORSIZE) #define STR_RAMDEVNO(m) #m #define MKMOUNT_DEVNAME(m) "/dev/ram" STR_RAMDEVNO(m) #define MOUNT_DEVNAME MKMOUNT_DEVNAME(CONFIG_EXAMPLES_ROMFS_RAMDEVNO) #define SCRATCHBUFFER_SIZE 1024 /* Test directory stuff */ #define WRITABLE_MODE (S_IWOTH|S_IWGRP|S_IWUSR) #define READABLE_MODE (S_IROTH|S_IRGRP|S_IRUSR) #define EXECUTABLE_MODE (S_IXOTH|S_IXGRP|S_IXUSR) #define DIRECTORY_MODE (S_IFDIR|READABLE_MODE|EXECUTABLE_MODE) #define FILE_MODE (S_IFREG|READABLE_MODE) /**************************************************************************** * Private Types ****************************************************************************/ struct node_s { struct node_s *peer; /* Next node in this directory */ bool directory; /* True: directory */ bool found; /* True: found and verified */ const char *name; /* Node name */ mode_t mode; /* Expected permissions */ size_t size; /* Expected size */ union { const char *filecontent; /* Context of text file */ struct node_s *child; /* Subdirectory start */ } u; }; /**************************************************************************** * Private Data ****************************************************************************/ static const char g_afilecontent[] = "This is a file\n"; static const char g_anotherfilecontent[] = "This is another file\n"; static const char g_yafilecontent[] = "This is yet another file\n"; static const char g_subdirfilecontent[] = "File in subdirectory\n"; #define g_hfilecontent g_subdirfilecontent static struct node_s g_adir; static struct node_s g_afile; static struct node_s g_hfile; static struct node_s g_anotherfile; static struct node_s g_subdir; static struct node_s g_yafile; static struct node_s g_subdirfile; static int g_nerrors = 0; static char g_scratchbuffer[SCRATCHBUFFER_SIZE]; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: ****************************************************************************/ static void connectem(void) { g_adir.peer = &g_afile; g_adir.directory = true; g_adir.found = false; g_adir.name = "adir"; g_adir.mode = DIRECTORY_MODE; g_adir.size = 0; g_adir.u.child = &g_anotherfile; g_afile.peer = &g_hfile; g_afile.directory = false; g_afile.found = false; g_afile.name = "afile.txt"; g_afile.mode = FILE_MODE; g_afile.size = strlen(g_afilecontent); g_afile.u.filecontent = g_afilecontent; g_hfile.peer = NULL; g_hfile.directory = false; /* Actually a hard link */ g_hfile.found = false; g_hfile.name = "hfile"; g_hfile.mode = FILE_MODE; g_hfile.size = strlen(g_hfilecontent); g_hfile.u.filecontent = g_hfilecontent; g_anotherfile.peer = &g_yafile; g_anotherfile.directory = false; g_anotherfile.found = false; g_anotherfile.name = "anotherfile.txt"; g_anotherfile.mode = FILE_MODE; g_anotherfile.size = strlen(g_anotherfilecontent); g_anotherfile.u.filecontent = g_anotherfilecontent; g_yafile.peer = &g_subdir; g_yafile.directory = false; g_yafile.found = false; g_yafile.name = "yafile.txt"; g_yafile.mode = FILE_MODE; g_yafile.size = strlen(g_yafilecontent); g_yafile.u.filecontent = g_yafilecontent; g_subdir.peer = NULL; g_subdir.directory = true; g_subdir.found = false; g_subdir.name = "subdir"; g_subdir.mode = DIRECTORY_MODE; g_subdir.size = 0; g_subdir.u.child = &g_subdirfile; g_subdirfile.peer = NULL; g_subdirfile.directory = false; g_subdirfile.found = false; g_subdirfile.name = "subdirfile.txt"; g_subdirfile.mode = FILE_MODE; g_subdirfile.size = strlen(g_subdirfilecontent); g_subdirfile.u.filecontent = g_subdirfilecontent; } /**************************************************************************** * Name: findindirectory ****************************************************************************/ static struct node_s *findindirectory(struct node_s *entry, const char *name) { for (; entry; entry = entry->peer) { if (!entry->found && strcmp(entry->name, name) == 0) { entry->found = true; return entry; } } return NULL; } /**************************************************************************** * Name: checkattributes ****************************************************************************/ static void checkattributes(const char *path, mode_t mode, size_t size) { struct stat buf; int ret; ret = stat(path, &buf); if (ret != 0) { printf(" -- ERROR: Failed to stat %s: %d\n", path, errno); g_nerrors++; return; } if (mode != buf.st_mode) { printf(" -- ERROR: Expected mode %08x, got %08x\n", mode, buf.st_mode); g_nerrors++; } if (size != buf.st_size) { printf(" -- ERROR: Expected size %d, got %d\n", mode, buf.st_size); g_nerrors++; } } /**************************************************************************** * Name: checkfile ****************************************************************************/ static void checkfile(const char *path, struct node_s *node) { ssize_t nbytesread; char *filedata; int fd; /* Open the file */ fd = open(path, O_RDONLY); if (fd < 0) { printf(" -- ERROR: Failed to open %s: %d\n", path, errno); g_nerrors++; return; } /* Read and verify the file contents */ nbytesread = read(fd, g_scratchbuffer, SCRATCHBUFFER_SIZE); if (nbytesread < 0) { printf(" -- ERROR: Failed to read from %s: %d\n", path, errno); g_nerrors++; } else if (nbytesread != node->size) { printf(" -- ERROR: Read %ld bytes, expected %lu\n", (long)nbytesread, (unsigned long)node->size); g_nerrors++; } else if (memcmp(g_scratchbuffer, node->u.filecontent, node->size) != 0) { g_scratchbuffer[nbytesread] = '\0'; printf(" -- ERROR: File content read does not match expectation:\n"); printf(" -- Read: [%s]\n", g_scratchbuffer); printf(" -- Expected: [%s]\n", node->u.filecontent); g_nerrors++; } /* Memory map and verify the file contents */ filedata = (char*)mmap(NULL, node->size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0); if (!filedata || filedata == (char*)MAP_FAILED) { printf(" -- ERROR: mmap of %s failed: %d\n", path, errno); g_nerrors++; } else { if (memcmp(filedata, node->u.filecontent, node->size) != 0) { memcpy(g_scratchbuffer, filedata, node->size); g_scratchbuffer[node->size] = '\0'; printf(" -- ERROR: Mapped file content read does not match expectation:\n"); printf(" -- Memory: [%s]\n", filedata); printf(" -- Expected: [%s]\n", node->u.filecontent); g_nerrors++; } munmap(filedata, node->size); } /* Close the file */ if (close(fd) != OK) { printf(" -- ERROR: Failed to close %s: %d\n", path, errno); g_nerrors++; } } /**************************************************************************** * Name: readdirectories ****************************************************************************/ static void readdirectories(const char *path, struct node_s *entry) { DIR *dirp; struct node_s *node; struct dirent *direntry; char *fullpath; printf("Traversing directory: %s\n", path); dirp = opendir(path); if (!dirp) { printf(" ERROR opendir(\"%s\") failed: %d\n", path, errno); g_nerrors++; return; } for (direntry = readdir(dirp); direntry; direntry = readdir(dirp)) { if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) { printf(" Skipping %s\n", direntry->d_name); continue; } node = findindirectory(entry, direntry->d_name); if (!node) { printf(" ERROR: No node found for %s\n", direntry->d_name); g_nerrors++; continue; } /* Get the full path to the entry */ sprintf(g_scratchbuffer, "%s/%s", path, direntry->d_name); fullpath = strdup(g_scratchbuffer); if (DIRENT_ISDIRECTORY(direntry->d_type)) { printf(" DIRECTORY: %s/\n", fullpath); if (!node->directory) { printf(" -- ERROR: Expected type directory\n"); g_nerrors++; } else { checkattributes(fullpath, node->mode, 0); readdirectories(fullpath, node->u.child); printf("Continuing directory: %s\n", path); } } else { printf(" FILE: %s/\n", fullpath); if (node->directory) { printf(" -- ERROR: Expected type file\n"); g_nerrors++; } else { checkattributes(fullpath, node->mode, node->size); checkfile(fullpath, node); } } free(fullpath); } closedir(dirp); } /**************************************************************************** * Name: checkdirectories ****************************************************************************/ static void checkdirectories(struct node_s *entry) { for (; entry; entry = entry->peer) { if (!entry->found ) { printf("ERROR: %s never found\n", entry->name); g_nerrors++; } if (entry->directory) { checkdirectories(entry->u.child); } } } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: romfs_main ****************************************************************************/ #ifdef CONFIG_BUILD_KERNEL int main(int argc, FAR char *argv[]) #else int romfs_main(int argc, char *argv[]) #endif { int ret; /* Create a RAM disk for the test */ ret = romdisk_register(CONFIG_EXAMPLES_ROMFS_RAMDEVNO, testdir_img, NSECTORS(testdir_img_len), CONFIG_EXAMPLES_ROMFS_SECTORSIZE); if (ret < 0) { printf("ERROR: Failed to create RAM disk\n"); return 1; } /* Mount the test file system */ printf("Mounting ROMFS filesystem at target=%s with source=%s\n", CONFIG_EXAMPLES_ROMFS_MOUNTPOINT, MOUNT_DEVNAME); ret = mount(MOUNT_DEVNAME, CONFIG_EXAMPLES_ROMFS_MOUNTPOINT, "romfs", MS_RDONLY, NULL); if (ret < 0) { printf("ERROR: Mount failed: %d\n", errno); return 1; } /* Perform the test */ connectem(); readdirectories(CONFIG_EXAMPLES_ROMFS_MOUNTPOINT, &g_adir); checkdirectories(&g_adir); if (g_nerrors) { printf("Finished with %d errors\n", g_nerrors); return g_nerrors; } printf("PASSED\n"); return 0; }