int fs_ls(const char *directory, fs_ls_cb_t cb, void *arg) { DWORD result = 0; LPSTR expanded = NULL; LPSTR baseDirectory = NULL; char tempDirectory[FS_MAX_PATH]; _snprintf(tempDirectory, sizeof(tempDirectory), "%s", directory); /* * If there is not wildcard mask on the directory, create a version of the * directory with a mask appended */ if (strrchr(directory, '*') == NULL) { _snprintf(tempDirectory, sizeof(tempDirectory), "%s\\*", directory); baseDirectory = _strdup(directory); if (baseDirectory == NULL) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } } else { /* * Otherwise, if it does have an asterisk, we need to scan back * and find the base directory. If there is no slash, it means * we're listing the cwd. */ PCHAR slash = strrchr(directory, '\\'); if (slash) { *slash = 0; baseDirectory = _strdup(directory); if (baseDirectory == NULL) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } *slash = '\\'; } } expanded = fs_expand_path(tempDirectory); if (expanded == NULL) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } WIN32_FIND_DATAW data; wchar_t *path_w = utf8_to_wchar(expanded); if (path_w == NULL) { result = GetLastError(); goto out; } HANDLE ctx = FindFirstFileW(path_w, &data); if (ctx == NULL) { result = GetLastError(); goto out; } do { if (ctx == INVALID_HANDLE_VALUE) { result = GetLastError(); break; } char *filename = wchar_to_utf8(data.cFileName); char *short_filename = wchar_to_utf8(data.cAlternateFileName); char path[FS_MAX_PATH]; if (baseDirectory) { _snprintf(path, sizeof(path), "%s\\%s", baseDirectory, filename); } else { _snprintf(path, sizeof(path), "%s", filename); } cb(arg, filename, short_filename, path); free(filename); free(short_filename); } while (FindNextFileW(ctx, &data)); /* * Clean up resources */ FindClose(ctx); free(expanded); out: free(baseDirectory); free(path_w); return result; }
/* * Handles the open request for a file channel and returns a valid channel * identifier to the requestor if the file is opened successfully */ DWORD request_fs_file_channel_open(Remote *remote, Packet *packet) { Packet *response = NULL; PCHAR filePath, mode; DWORD res = ERROR_SUCCESS; DWORD flags = 0; Channel *newChannel = NULL; PoolChannelOps chops = { 0 }; FileContext *ctx; LPSTR expandedFilePath = NULL; do { // Allocate a response response = packet_create_response(packet); // Get the channel flags flags = packet_get_tlv_value_uint(packet, TLV_TYPE_FLAGS); // Allocate storage for the file context if (!(ctx = (FileContext *)malloc(sizeof(FileContext)))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } // Get the file path and the mode filePath = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_PATH); mode = packet_get_tlv_value_string(packet, TLV_TYPE_FILE_MODE); // No file path? bogus. if (!filePath) { res = ERROR_INVALID_PARAMETER; break; } // Expand the file path if (!(expandedFilePath = fs_expand_path(filePath))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } if (!mode) mode = "rb"; // Invalid file? if (!(ctx->fd = fopen(expandedFilePath, mode))) { res = GetLastError(); break; } memset(&chops, 0, sizeof(chops)); // Initialize the pool operation handlers chops.native.context = ctx; chops.native.write = file_channel_write; chops.native.close = file_channel_close; chops.read = file_channel_read; chops.eof = file_channel_eof; chops.seek = file_channel_seek; chops.tell = file_channel_tell; // Check the response allocation & allocate a un-connected // channel if ((!response) || (!(newChannel = channel_create_pool(0, flags, &chops)))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } // Add the channel identifier to the response packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel)); } while (0); // Transmit the packet if it's valid packet_transmit_response(res, remote, response); // Clean up on failure if (res != ERROR_SUCCESS) { if (newChannel) channel_destroy(newChannel, NULL); if (ctx) free(ctx); } // Free the expanded file path if it was allocated if (expandedFilePath) free(expandedFilePath); return res; }
/* * Gets the contents of a given directory path and returns the list of file * names to the requestor. * * TLVs: * * req: TLV_TYPE_DIRECTORY_PATH - The directory that should be listed */ DWORD request_fs_ls(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); LPCSTR directory; DWORD result = ERROR_SUCCESS; LPSTR expanded = NULL, tempFile = NULL; DWORD tempFileSize = 0; LPSTR baseDirectory = NULL; struct meterp_stat buf; directory = packet_get_tlv_value_string(packet, TLV_TYPE_DIRECTORY_PATH); // Enumerate the directory if one was provided if (!directory) result = ERROR_INVALID_PARAMETER; else { #ifdef _WIN32 WIN32_FIND_DATA data; HANDLE ctx = NULL; #else DIR *ctx; struct dirent *data; #endif BOOLEAN freeDirectory = FALSE; LPSTR tempDirectory = (LPSTR)directory; #ifdef _WIN32 // If there is not wildcard mask on the directory, create a version of the // directory with a mask appended if (!strrchr(directory, '*')) { if (!(tempDirectory = (LPSTR)malloc(strlen(directory) + 3))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } sprintf(tempDirectory, "%s\\*", directory); // Dupe! if (!(baseDirectory = _strdup(directory))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } } // Otherwise, if it does have an asterisk, we need to scan back and find // the base directory. If there is no slash, it means we're listing the // cwd. else { PCHAR slash = strrchr(directory, '\\'); if (slash) { *slash = 0; if (!(baseDirectory = _strdup(directory))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } *slash = '\\'; } } // Expand the path if (!(expanded = fs_expand_path(tempDirectory))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } // Start the find operation ctx = FindFirstFile(expanded, &data); #define DF_NAME data.cFileName #else expanded = 0; ctx = opendir(tempDirectory); if(ctx == NULL) { result = errno; goto out; } data = readdir(ctx); if (!(baseDirectory = _strdup(directory))) { result = ERROR_NOT_ENOUGH_MEMORY; goto out; } #define DF_NAME data->d_name #endif do { DWORD fullSize = (baseDirectory ? strlen(baseDirectory) : 0) + strlen(DF_NAME) + 2; // No context? Sucktastic if (ctx == INVALID_HANDLE_VALUE) { result = GetLastError(); break; } // Allocate temporary storage to stat the file if ((!tempFile) || (tempFileSize < fullSize)) { if (tempFile) free(tempFile); // No memory means we suck a lot like spoon's mom if (!(tempFile = (LPSTR)malloc(fullSize))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Update the tempFileSize so that we don't allocate if we don't // need to like a true efficient ninja tempFileSize = fullSize; } // Build the full path if (baseDirectory) #ifdef _WIN32 sprintf(tempFile, "%s\\%s", baseDirectory, DF_NAME); #else sprintf(tempFile, "%s/%s", baseDirectory, DF_NAME); #endif else sprintf(tempFile, "%s", DF_NAME); // Add the file name to the response packet_add_tlv_string(response, TLV_TYPE_FILE_NAME, DF_NAME); // Add the full path packet_add_tlv_string(response, TLV_TYPE_FILE_PATH, tempFile); // Stat the file to get more information about it. if (fs_stat(tempFile, &buf) >= 0) packet_add_tlv_raw(response, TLV_TYPE_STAT_BUF, &buf, sizeof(buf)); #ifdef _WIN32 } while (FindNextFile(ctx, &data)); #else } while (data = readdir(ctx));