Пример #1
0
/**
 * Write a .spl text file to a file in preparation for pushing it
 * to the device.
 *
 * @param fd file descriptor to write to
 * @param p the text to output one line per string in the linked list
 * @see playlist_t_to_spl()
 */
static void write_from_spl_text_t(LIBMTP_mtpdevice_t *device,
                                  const int fd,
                                  text_t* p) {
  ssize_t ret;
  // write out BOM for utf16/ucs2 (byte order mark)
  ret = write(fd,"\xff\xfe",2);
  while(p != NULL) {
    char *const t = (char*) utf8_to_utf16(device, p->text);
    // note: 2 bytes per ucs2 character
    const size_t len = ucs2_strlen((uint16_t*)t)*sizeof(uint16_t);
    int i;

    IF_DEBUG() {
      printf("\nutf8=%s ",p->text);
      for(i=0;i<strlen(p->text);i++)
        printf("%02x ", p->text[i] & 0xff);
      printf("\n");
      printf("ucs2=");
      for(i=0;i<ucs2_strlen((uint16_t*)t)*sizeof(uint16_t);i++)
        printf("%02x ", t[i] & 0xff);
      printf("\n");
    }

    // write: utf8 -> utf16
    ret += write(fd, t, len);

    // release the converted string
    free(t);

    // check for failures
    if(ret < 0)
      printf("write spl file failed: %s\n", strerror(errno));
    else if(ret != len +2)
      printf("write spl file wrong number of bytes ret=%d len=%d '%s'\n", (int)ret, (int)len, p->text);

    // write carriage return, line feed in ucs2
    ret = write(fd, "\r\0\n\0", 4);
    if(ret < 0)
      printf("write spl file failed: %s\n", strerror(errno));
    else if(ret != 4)
      printf("failed to write the correct number of bytes '\\n'!\n");

    // fake out count (first time through has two extra bytes from BOM)
    ret = 2;

    // advance to the next line
    p = p->next;
  }
}
Пример #2
0
uint16_t *ucs2_strdup(const uint16_t *s)
{
	size_t len = ucs2_strlen(s);
	uint16_t *ret = calloc(len, sizeof (*ret));

	if (!ret)
		return NULL;

	memcpy(ret, s, len * sizeof (*ret));
	return ret;
}
/**
 * efivar_create_sysfs_entry - create a new entry in sysfs
 * @new_var: efivar entry to create
 *
 * Returns 0 on success, negative error code on failure
 */
static int
efivar_create_sysfs_entry(struct efivar_entry *new_var)
{
	int i, short_name_size;
	char *short_name;
	unsigned long variable_name_size;
	efi_char16_t *variable_name;
	int ret;

	variable_name = new_var->var.VariableName;
	variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);

	/*
	 * Length of the variable bytes in ASCII, plus the '-' separator,
	 * plus the GUID, plus trailing NUL
	 */
	short_name_size = variable_name_size / sizeof(efi_char16_t)
				+ 1 + EFI_VARIABLE_GUID_LEN + 1;

	short_name = kzalloc(short_name_size, GFP_KERNEL);

	if (!short_name)
		return -ENOMEM;

	/* Convert Unicode to normal chars (assume top bits are 0),
	   ala UTF-8 */
	for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
		short_name[i] = variable_name[i] & 0xFF;
	}
	/* This is ugly, but necessary to separate one vendor's
	   private variables from another's.         */

	*(short_name + strlen(short_name)) = '-';
	efi_guid_to_str(&new_var->var.VendorGuid,
			 short_name + strlen(short_name));

	new_var->kobj.kset = efivars_kset;

	ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
				   NULL, "%s", short_name);
	kfree(short_name);
	if (ret)
		return ret;

	kobject_uevent(&new_var->kobj, KOBJ_ADD);
	efivar_entry_add(new_var, &efivar_sysfs_list);

	return 0;
}
Пример #4
0
/*
 * Clean up an entry with the same name
 */
static int efi_pstore_erase_func(struct efivar_entry *entry, void *data)
{
	struct pstore_erase_data *ed = data;
	efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
	efi_char16_t efi_name_old[DUMP_NAME_LEN];
	efi_char16_t *efi_name = ed->name;
	unsigned long ucs2_len = ucs2_strlen(ed->name);
	char name_old[DUMP_NAME_LEN];
	int i;

	if (efi_guidcmp(entry->var.VendorGuid, vendor))
		return 0;

	if (ucs2_strncmp(entry->var.VariableName,
			  efi_name, (size_t)ucs2_len)) {
		/*
		 * Check if an old format, which doesn't support
		 * holding multiple logs, remains.
		 */
		sprintf(name_old, "dump-type%u-%u-%lu", ed->type,
			(unsigned int)ed->id, ed->time.tv_sec);

		for (i = 0; i < DUMP_NAME_LEN; i++)
			efi_name_old[i] = name_old[i];

		if (ucs2_strncmp(entry->var.VariableName, efi_name_old,
				  ucs2_strlen(efi_name_old)))
			return 0;
	}

	/* found */
	__efivar_entry_delete(entry);
	list_del(&entry->list);

	return 1;
}
Пример #5
0
/**
 * Load a file descriptor into a string.
 *
 * @param device a pointer to the current device.
 *               (needed for ucs2->utf8 charset conversion)
 * @param fd the file descriptor to load
 * @return text_t* a linked list of lines of text, id is left blank, NULL if nothing read in
 */
static text_t* read_into_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd)
{
    // set MAXREAD to match STRING_BUFFER_LENGTH in unicode.h conversion function
    const size_t MAXREAD = 1024*2;
    char t[MAXREAD];
    // upto 3 bytes per utf8 character, 2 bytes per ucs2 character,
    // +1 for '\0' at end of string
    const size_t WSIZE = MAXREAD/2*3+1;
    char w[WSIZE];
    char* it = t; // iterator on t
    char* iw = w;
    ssize_t rdcnt;
    off_t offcnt;
    text_t* head = NULL;
    text_t* tail = NULL;
    int eof = 0;
    
    // reset file descriptor (fd) to start of file
    offcnt = lseek(fd, 0, SEEK_SET);
    
    while(!eof) {
        // find the current offset in the file
        // to allow us to determine how many bytes we read if we hit the EOF
        // where returned rdcnt=0 from read()
        offcnt = lseek(fd, 0, SEEK_CUR);
        // read to refill buffer
        // (there might be data left from an incomplete last string in t,
        // hence start filling at it)
        it = t; // set ptr to start of buffer
        rdcnt = read(fd, it, sizeof(char)*MAXREAD);
        if(rdcnt < 0)
            LIBMTP_INFO("load_spl_fd read err %s\n", strerror(errno));
        else if(rdcnt == 0) { // for EOF, fix rdcnt
            if(it-t == MAXREAD)
                LIBMTP_ERROR("error -- buffer too small to read in .spl playlist entry\n");
            
            rdcnt = lseek(fd, 0, SEEK_CUR) - offcnt;
            eof = 1;
        }
        
        LIBMTP_PLST_DEBUG("read buff= {%dB new, %dB old/left-over}%s\n",(int)rdcnt, (int)(iw-w), eof?", EOF":"");
        
        // while more input bytes
        char* it_end = t + rdcnt;
        while(it < it_end) {
            // copy byte, unless EOL (then replace with end-of-string \0)
            if(*it == '\r' || *it == '\n')
                *iw = '\0';
            else
                *iw = *it;
            
            it++;
            iw++;
            
            // EOL -- store it
            if( (iw-w) >= 2 && // we must have at least two bytes
               *(iw-1) == '\0' && *(iw-2) == '\0' && // 0x0000 is end-of-string
               // but it must be aligned such that we have an {odd,even} set of
               // bytes since we are expecting to consume bytes two-at-a-time
               !((iw-w)%2) ) {
                
                // drop empty lines
                //  ... cast as a string of 2 byte characters
                if(ucs2_strlen((uint16_t*)w) == 0) {
                    iw = w;
                    continue;
                }
                
                // create a new node in the list
                if(head == NULL) {
                    head = malloc(sizeof(text_t));
                    tail = head;
                }
                else {
                    tail->next = malloc(sizeof(text_t));
                    tail = tail->next;
                }
                // fill in the data for the node
                //  ... cast as a string of 2 byte characters
                tail->text = utf16_to_utf8(device, (uint16_t*) w);
                iw = w; // start again
                
                LIBMTP_PLST_DEBUG("line: %s\n", tail->text);
            }
            
            // prevent buffer overflow
            if(iw >= w + WSIZE) {
                // if we ever see this error its BAD:
                //   we are dropping all the processed bytes for this line and
                //   proceeding on as if everything is okay, probably losing a track
                //   from the playlist
                LIBMTP_ERROR("ERROR %s:%u:%s(): buffer overflow! .spl line too long @ %zuB\n",
                             __FILE__, __LINE__, __func__, WSIZE);
                iw = w; // reset buffer
            }
        }
        
        // if the last thing we did was save our line, then we finished working
        // on the input buffer and we can start fresh
        // otherwise we need to save our partial work, if we're not quiting (eof).
        // there is nothing special we need to do, to achieve this since the
        // partially completed string will sit in 'w' until we return to complete
        // the line
        
    }
    
    // set the next pointer at the end
    // if there is any list
    if(head != NULL)
        tail->next = NULL;
    
    // return the head of the list (NULL if no list)
    return head;
}
Пример #6
0
static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
			     unsigned long name_size, void *data)
{
	struct super_block *sb = (struct super_block *)data;
	struct efivar_entry *entry;
	struct inode *inode = NULL;
	struct dentry *dentry, *root = sb->s_root;
	unsigned long size = 0;
	char *name;
	int len, i;
	int err = -ENOMEM;

	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
	if (!entry)
		return err;

	memcpy(entry->var.VariableName, name16, name_size);
	memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));

	len = ucs2_strlen(entry->var.VariableName);

	/* name, plus '-', plus GUID, plus NUL*/
	name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL);
	if (!name)
		goto fail;

	for (i = 0; i < len; i++)
		name[i] = entry->var.VariableName[i] & 0xFF;

	name[len] = '-';

	efi_guid_unparse(&entry->var.VendorGuid, name + len + 1);

	name[len + EFI_VARIABLE_GUID_LEN+1] = '\0';

	inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0);
	if (!inode)
		goto fail_name;

	dentry = efivarfs_alloc_dentry(root, name);
	if (IS_ERR(dentry)) {
		err = PTR_ERR(dentry);
		goto fail_inode;
	}

	/* copied by the above to local storage in the dentry. */
	kfree(name);

	efivar_entry_size(entry, &size);
	efivar_entry_add(entry, &efivarfs_list);

	mutex_lock(&inode->i_mutex);
	inode->i_private = entry;
	i_size_write(inode, size + sizeof(entry->var.Attributes));
	mutex_unlock(&inode->i_mutex);
	d_add(dentry, inode);

	return 0;

fail_inode:
	iput(inode);
fail_name:
	kfree(name);
fail:
	kfree(entry);
	return err;
}