/* msdos_get_token -- * Routine to get a token (name or separator) from the path. * * PARAMETERS: * path - path to get token from * ret_token - returned token * token_len - length of returned token * * RETURNS: * token type, token and token length * */ msdos_token_types_t msdos_get_token(const char *path, char *ret_token, int *token_len) { int rc = RC_OK; register int i = 0; msdos_token_types_t type = MSDOS_NAME; char token[MSDOS_NAME_MAX_WITH_DOT+1]; register char c; /* * Copy a name into token. (Remember NULL is a token.) */ c = path[i]; while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) ) { token[i] = c; if ( i == MSDOS_NAME_MAX_WITH_DOT ) return MSDOS_INVALID_TOKEN; if ( !msdos_is_valid_name_char(c) ) return MSDOS_INVALID_TOKEN; c = path [++i]; } /* * Copy a seperator into token. */ if ( i == 0 ) { token[i] = c; if ( token[i] != '\0' ) { i++; type = MSDOS_CURRENT_DIR; } else type = MSDOS_NO_MORE_PATH; } else if (token[ i-1 ] != '\0') token[i] = '\0'; /* * Set token_len to the number of characters copied. */ *token_len = i; /* * If we copied something that was not a seperator see if * it was a special name. */ if ( type == MSDOS_NAME ) { if ( strcmp( token, "..") == 0 ) { strcpy(ret_token, MSDOS_DOTDOT_NAME); type = MSDOS_UP_DIR; return type; } if ( strcmp( token, "." ) == 0 ) { strcpy(ret_token, MSDOS_DOT_NAME); type = MSDOS_CURRENT_DIR; return type; } rc = msdos_filename_unix2dos(token, *token_len, ret_token); if ( rc != RC_OK ) return MSDOS_INVALID_TOKEN; } ret_token[MSDOS_NAME_MAX] = '\0'; return type; }
/* msdos_eval4make -- * The following routine evaluate path for a new node to be created. * 'pathloc' is returned with a pointer to the parent of the new node. * 'name' is returned with a pointer to the first character in the * new node name. The parent node is verified to be a directory. * * PARAMETERS: * path - path for evaluation * pathloc - IN/OUT (start point for evaluation/parent directory for * creation) * name - new node name * * RETURNS: * RC_OK, filled pathloc for parent directory and name of new node on * success, or -1 if error occured (errno set appropriately) */ int msdos_eval4make( const char *path, rtems_filesystem_location_info_t *pathloc, const char **name ) { int rc = RC_OK; rtems_status_code sc = RTEMS_SUCCESSFUL; msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info; fat_file_fd_t *fat_fd = NULL; rtems_filesystem_location_info_t newloc; msdos_token_types_t type; int i = 0; int token_len; const char *token; bool done = false; sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) rtems_set_errno_and_return_minus_one(EIO); if (!pathloc->node_access) { errno = ENOENT; rc = -1; goto err; } fat_fd = pathloc->node_access; rc = fat_file_reopen(fat_fd); if (rc != RC_OK) goto err; while (!done) { type = msdos_get_token(&path[i], strlen(&path[i]), &token, &token_len); i += token_len; fat_fd = pathloc->node_access; switch (type) { case MSDOS_UP_DIR: /* * Only a directory can be decended into. */ if (fat_fd->fat_file_type != FAT_DIRECTORY) { errno = ENOTDIR; rc = -1; goto error; } /* * Am I at the root of this mounted filesystem? */ if (pathloc->node_access == pathloc->mt_entry->mt_fs_root.node_access) { /* * Am I at the root of all filesystems? * XXX: MSDOS is not supposed to be base fs. */ if (pathloc->node_access == rtems_filesystem_root.node_access) { break; /* Throw out the .. in this case */ } else { newloc = pathloc->mt_entry->mt_point_node; *pathloc = newloc; rc = fat_file_close(pathloc->mt_entry, fat_fd); if (rc != RC_OK) goto err; rtems_semaphore_release(fs_info->vol_sema); return (*pathloc->ops->evalformake_h)(&path[i-token_len], pathloc, name); } } else { rc = msdos_find_name(pathloc, token, token_len); if (rc != RC_OK) { if (rc == MSDOS_NAME_NOT_FOUND_ERR) { errno = ENOENT; rc = -1; } goto error; } } break; case MSDOS_NAME: /* * Only a directory can be decended into. */ if (fat_fd->fat_file_type != FAT_DIRECTORY) { errno = ENOTDIR; rc = -1; goto error; } /* * Otherwise find the token name in the present location and * set the node access to the point we have found. */ rc = msdos_find_name(pathloc, token, token_len); if (rc) { if (rc != MSDOS_NAME_NOT_FOUND_ERR) { errno = ENOENT; rc = -1; goto error; } else done = true; } break; case MSDOS_NO_MORE_PATH: errno = EEXIST; rc = -1; goto error; break; case MSDOS_CURRENT_DIR: break; case MSDOS_INVALID_TOKEN: errno = ENAMETOOLONG; rc = -1; goto error; break; } } *name = &path[i - token_len]; /* * We have evaluated the path as far as we can. * Verify there is not any invalid stuff at the end of the name. */ for( ; path[i] != '\0'; i++) { if (!msdos_is_separator(path[i])) { errno = ENOENT; rc = -1; goto error; } } fat_fd = pathloc->node_access; if (fat_fd->fat_file_type != FAT_DIRECTORY) { errno = ENOTDIR; rc = -1; goto error; } msdos_set_handlers(pathloc); rtems_semaphore_release(fs_info->vol_sema); return RC_OK; error: fat_file_close(pathloc->mt_entry, fat_fd); err: rtems_semaphore_release(fs_info->vol_sema); return rc; }