/* * $Id$ */ #if HAVE_CONFIG_H #include "config.h" #endif /************************************************************************** * This file implements the "mount" procedure for tar-based IMFS * extensions. The TAR is not actually mounted under the IMFS. * Directories from the TAR file are created as usual in the IMFS. * File entries are created as IMFS_LINEAR_FILE nodes with their nods * pointing to addresses in the TAR image. *************************************************************************/ #include #include #include #include #include #include #include #include /************************************************************************** * TAR file format: * * Offset Length Contents * 0 100 bytes File name ('\0' terminated, 99 maxmum length) * 100 8 bytes File mode (in octal ascii) * 108 8 bytes User ID (in octal ascii) * 116 8 bytes Group ID (in octal ascii) * 124 12 bytes File size (s) (in octal ascii) * 136 12 bytes Modify time (in octal ascii) * 148 8 bytes Header checksum (in octal ascii) * 156 1 bytes Link flag * 157 100 bytes Linkname ('\0' terminated, 99 maxmum length) * 257 8 bytes Magic ("ustar \0") * 265 32 bytes User name ('\0' terminated, 31 maxmum length) * 297 32 bytes Group name ('\0' terminated, 31 maxmum length) * 329 8 bytes Major device ID (in octal ascii) * 337 8 bytes Minor device ID (in octal ascii) * 345 167 bytes Padding * 512 (s+p)bytes File contents (s+p) := (((s) + 511) & ~511), * round up to 512 bytes * * Checksum: * int i, sum; * char* header = tar_header_pointer; * sum = 0; * for(i = 0; i < 512; i++) * sum += 0xFF & header[i]; *************************************************************************/ #define LF_OLDNORMAL '\0' /* Normal disk file, Unix compatible */ #define LF_NORMAL '0' /* Normal disk file */ #define LF_LINK '1' /* Link to previously dumped file */ #define LF_SYMLINK '2' /* Symbolic link */ #define LF_CHR '3' /* Character special file */ #define LF_BLK '4' /* Block special file */ #define LF_DIR '5' /* Directory */ #define LF_FIFO '6' /* FIFO special file */ #define LF_CONFIG '7' /* Contiguous file */ #define MAX_NAME_FIELD_SIZE 99 #define MIN(a,b) ((a)>(b)?(b):(a)) static unsigned long octal2ulong(char *octascii, int len); static int compute_tar_header_checksum(char *bufr); /************************************************************************** * rtems_tarfs_load * * Here we create the mountpoint directory and load the tarfs at * that node. Once the IMFS has been mounted, we work through the * tar image and perform as follows: * - For directories, simply call mkdir(). The IMFS creates nodes as * needed. * - For files, we make our own calls to IMFS eval_for_make and * create_node. *************************************************************************/ int rtems_tarfs_load(char *mountpoint, unsigned char *tar_image, unsigned long tar_size) { rtems_filesystem_location_info_t root_loc; rtems_filesystem_location_info_t loc; char *hdr_ptr; char filename[100]; char full_filename[256]; int hdr_chksum; unsigned char linkflag; unsigned long file_size; unsigned long file_mode; int offset; unsigned long nblocks; IMFS_jnode_t *node; int status; status = rtems_filesystem_evaluate_path(mountpoint, 0, &root_loc, 0); if (status != 0) return(-1); if (root_loc.ops != &IMFS_ops) return(-1); /*********************************************************************** * Create an IMFS node structure pointing to tar image memory. **********************************************************************/ offset = 0; while (1) { if (offset + 512 > tar_size) break; /****************************************************************** * Read a header. ******************************************************************/ hdr_ptr = &tar_image[offset]; offset += 512; if (strncmp(&hdr_ptr[257], "ustar ", 7)) break; strncpy(filename, hdr_ptr, MAX_NAME_FIELD_SIZE); filename[MAX_NAME_FIELD_SIZE] = '\0'; linkflag = hdr_ptr[156]; file_mode = octal2ulong(&hdr_ptr[100], 8); file_size = octal2ulong(&hdr_ptr[124], 12); hdr_chksum = (int)octal2ulong(&hdr_ptr[148], 8); if (compute_tar_header_checksum(hdr_ptr) != hdr_chksum) break; /****************************************************************** * Generate an IMFS node depending on the file type. * - For directories, just create directories as usual. IMFS * will take care of the rest. * - For files, create a file node with special tarfs properties. *****************************************************************/ if (linkflag == LF_DIR) { strcpy(full_filename, mountpoint); if (full_filename[strlen(full_filename)-1] != '/') strcat(full_filename, "/"); strcat(full_filename, filename); mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO); } /****************************************************************** * Create a LINEAR_FILE node if no user write permission. *****************************************************************/ else if ((linkflag == LF_NORMAL) && ((file_mode & 0200) == 0000)) { const char *name; loc = root_loc; if (IMFS_evaluate_for_make(filename, &loc, &name) == 0) { node = IMFS_create_node(&loc, IMFS_LINEAR_FILE, (char *)name, (S_IRUSR | S_IRGRP | S_IROTH) | S_IFREG, NULL); node->info.linearfile.size = file_size; node->info.linearfile.direct = &tar_image[offset]; } nblocks = (((file_size) + 511) & ~511) / 512; offset += 512 * nblocks; } /****************************************************************** * Create a regular MEMORY_FILE if write permission exists. *****************************************************************/ else if ((linkflag == LF_NORMAL) && ((file_mode & 0200) == 0200)) { int fd; int n, left, ptr; strcpy(full_filename, mountpoint); if (full_filename[strlen(full_filename)-1] != '/') strcat(full_filename, "/"); strcat(full_filename, filename); fd = creat(full_filename, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP); if (fd != -1) { left = file_size; ptr = offset; while ((n = write(fd, &tar_image[ptr], left)) > 0) { left -= n; ptr += n; } close(fd); } nblocks = (((file_size) + 511) & ~511) / 512; offset += 512 * nblocks; } } return(status); } /************************************************************************** * This converts octal ASCII number representations into an * unsigned long. Only support 32-bit numbers for now. *************************************************************************/ static unsigned long octal2ulong(char *octascii, int len) { int i; unsigned long num; unsigned long mult; num = 0; mult = 1; for (i=len-1; i>=0; i--) { if (octascii[i] < '0') continue; if (octascii[i] > '9') continue; num += mult*((unsigned long)(octascii[i] - '0')); mult *= 8; } return(num); } /************************************************************************ * Compute the TAR checksum and check with the value in * the archive. The checksum is computed over the entire * header, but the checksum field is substituted with blanks. ************************************************************************/ static int compute_tar_header_checksum(char *bufr) { int i, sum; sum = 0; for (i=0; i<512; i++) { if ((i >= 148) && (i < 156)) sum += 0xff & ' '; else sum += 0xff & bufr[i]; } return(sum); }