Esempio n. 1
0
/**
 * Given a CCNxName, a directory path, a file name, and a requested chunk number, return a new CCNxContentObject
 * with that CCNxName and containing the specified chunk of the file. The new CCNxContentObject will also
 * contain the number of the last chunk required to transfer the complete file. Note that the last chunk of the
 * file being retrieved is calculated each time we retrieve a chunk so the file can be growing in size as we
 * transfer it.
 * The new CCnxContentObject must eventually be released by calling ccnxContentObject_Release().
 *
 * @param [in] name The CCNxName to use when creating the new CCNxContentObject.
 * @param [in] directoryPath The directory in which to find the specified file.
 * @param [in] fileName The name of the file.
 * @param [in] requestedChunkNumber The number of the requested chunk from the file.
 *
 * @return A new CCNxContentObject instance containing the request chunk of the specified file, or NULL if
 *         the file did not exist or was otherwise unavailable.
 */
static CCNxContentObject *
_createFetchResponse(const CCNxName *name, const char *directoryPath, const char *fileName, uint64_t requestedChunkNumber)
{
    CCNxContentObject *result = NULL;
    uint64_t finalChunkNumber = 0;

    // Combine the directoryPath and fileName into the full path name of the desired file
    size_t filePathBufferSize = strlen(fileName) + strlen(directoryPath) + 2; // +2 for '/' and trailing null.
    char *fullFilePath = parcMemory_Allocate(filePathBufferSize);
    assertNotNull(fullFilePath, "parcMemory_Allocate(%zu) returned NULL", filePathBufferSize);
    snprintf(fullFilePath, filePathBufferSize, "%s/%s", directoryPath, fileName);

    // Make sure the file exists and is accessible before creating a ContentObject response.
    if (tutorialFileIO_IsFileAvailable(fullFilePath)) {
        // Since the file's length can change (e.g. if it is being written to while we're fetching
        // it), the final chunk number can change between requests for content chunks. So, update
        // it each time this function is called.
        finalChunkNumber = _getFinalChunkNumberOfFile(fullFilePath, tutorialCommon_ChunkSize);

        // Get the actual contents of the specified chunk of the file.
        PARCBuffer *payload = tutorialFileIO_GetFileChunk(fullFilePath, tutorialCommon_ChunkSize, requestedChunkNumber);

        if (payload != NULL) {
            result = _createContentObject(name, payload, finalChunkNumber);
            parcBuffer_Release(&payload);
        }
    }

    parcMemory_Deallocate((void **) &fullFilePath);

    return result; // Could be NULL if there was no payload
}
Esempio n. 2
0
PARCBuffer *
tutorialFileIO_CreateDirectoryListing(const char *directoryName)
{
    DIR *directory = opendir(directoryName);

    assertNotNull(directory, "Couldn't open directory '%s' for reading.", directoryName);

    PARCBufferComposer *directoryListing = parcBufferComposer_Create();

    struct dirent *entry;
    while ((entry = readdir(directory)) != NULL) {
        switch (entry->d_type) {
            case DT_REG: {
                // a regular file

                // We need the full file path to check its size.
                PARCBufferComposer *fullFilePath = parcBufferComposer_Create();
                parcBufferComposer_Format(fullFilePath, "%s/%s", directoryName, entry->d_name);

                PARCBuffer *fileNameBuffer = parcBufferComposer_ProduceBuffer(fullFilePath);
                char *fullFilePathString = parcBuffer_ToString(fileNameBuffer);
                parcBuffer_Release(&fileNameBuffer);

                if (tutorialFileIO_IsFileAvailable(fullFilePathString)) {
                    parcBufferComposer_Format(directoryListing, "  %s  (%zu bytes)\n",
                                              entry->d_name, tutorialFileIO_GetFileSize(fullFilePathString));
                }

                parcBufferComposer_Release(&fullFilePath);
                parcMemory_Deallocate((void **) &fullFilePathString);

                break;
            }

            case DT_LNK:
            case DT_DIR:
            default:
                // ignore everything but regular files
                break;
        }
    }

    closedir(directory);

    PARCBuffer *result = parcBufferComposer_ProduceBuffer(directoryListing);
    parcBufferComposer_Release(&directoryListing);

    return result;
}