#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <sys/sysmacros.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include "libexfat.h"
#include "version.h"
+#define BITS_PER_LONG (sizeof(long) * CHAR_BIT)
+
#ifdef WORDS_BIGENDIAN
-#define BITOP_LE_SWIZZLE (~0x7)
+#define BITOP_LE_SWIZZLE ((BITS_PER_LONG - 1) & ~0x7)
#else
#define BITOP_LE_SWIZZLE 0
#endif
-#define BIT_MASK(nr) ((1) << ((nr) % 32))
-#define BIT_WORD(nr) ((nr) / 32)
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
unsigned int print_level = EXFAT_INFO;
-static inline void set_bit(int nr, unsigned int *addr)
+static inline void set_bit(int nr, void *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
-static inline void clear_bit(int nr, unsigned int *addr)
+static inline void clear_bit(int nr, void *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
{
int fd, ret = -1;
off_t blk_dev_size;
+ struct stat st;
+ unsigned long long blk_dev_offset = 0;
fd = open(ui->dev_name, ui->writeable ? O_RDWR|O_EXCL : O_RDONLY);
if (fd < 0) {
goto out;
}
+ if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) {
+ char pathname[sizeof("/sys/dev/block/4294967295:4294967295/start")];
+ FILE *fp;
+
+ snprintf(pathname, sizeof(pathname), "/sys/dev/block/%u:%u/start",
+ major(st.st_rdev), minor(st.st_rdev));
+ fp = fopen(pathname, "r");
+ if (fp != NULL) {
+ if (fscanf(fp, "%llu", &blk_dev_offset) == 1) {
+ /*
+ * Linux kernel always reports partition offset
+ * in 512-byte units, regardless of sector size
+ */
+ blk_dev_offset <<= 9;
+ }
+ fclose(fp);
+ }
+ }
+
bd->dev_fd = fd;
+ bd->offset = blk_dev_offset;
bd->size = blk_dev_size;
if (!ui->cluster_size)
exfat_set_default_cluster_size(bd, ui);
if (ioctl(fd, BLKSSZGET, &bd->sector_size) < 0)
bd->sector_size = DEFAULT_SECTOR_SIZE;
bd->sector_size_bits = sector_size_bits(bd->sector_size);
- bd->num_sectors = blk_dev_size / DEFAULT_SECTOR_SIZE;
+ bd->num_sectors = blk_dev_size / bd->sector_size;
bd->num_clusters = blk_dev_size / ui->cluster_size;
exfat_debug("Block device name : %s\n", ui->dev_name);
- exfat_debug("Block device size : %lld\n", bd->size);
+ exfat_debug("Block device offset : %llu\n", bd->offset);
+ exfat_debug("Block device size : %llu\n", bd->size);
exfat_debug("Block sector size : %u\n", bd->sector_size);
exfat_debug("Number of the sectors : %llu\n",
bd->num_sectors);
{
struct pbr *bs;
int nbytes;
- unsigned int cluster_size;
+ unsigned int cluster_size, sector_size;
off_t root_clu_off;
- bs = (struct pbr *)malloc(sizeof(struct pbr));
+ bs = (struct pbr *)malloc(EXFAT_MAX_SECTOR_SIZE);
if (!bs) {
exfat_err("failed to allocate memory\n");
return -ENOMEM;
}
- nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0);
- if (nbytes != sizeof(struct pbr)) {
+ nbytes = exfat_read(bd->dev_fd, bs, EXFAT_MAX_SECTOR_SIZE, 0);
+ if (nbytes != EXFAT_MAX_SECTOR_SIZE) {
exfat_err("boot sector read failed: %d\n", errno);
+ free(bs);
return -1;
}
- cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size;
- root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size +
- le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS)
- * cluster_size;
+ sector_size = 1 << bs->bsx.sect_size_bits;
+ cluster_size = (1 << bs->bsx.sect_per_clus_bits) * sector_size;
+ root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * sector_size +
+ (le32_to_cpu(bs->bsx.root_cluster) - EXFAT_RESERVED_CLUSTERS) *
+ cluster_size;
free(bs);
return root_clu_off;
}
-char *exfat_conv_volume_serial(struct exfat_dentry *vol_entry)
+char *exfat_conv_volume_label(struct exfat_dentry *vol_entry)
{
char *volume_label;
__le16 disk_label[VOLUME_LABEL_MAX_LEN];
if (exfat_utf16_dec(disk_label, vol_entry->vol_char_cnt*2,
volume_label, VOLUME_LABEL_BUFFER_SIZE) < 0) {
exfat_err("failed to decode volume label\n");
+ free(volume_label);
return NULL;
}
sizeof(struct exfat_dentry), root_clu_off);
if (nbytes != sizeof(struct exfat_dentry)) {
exfat_err("volume entry read failed: %d\n", errno);
+ free(vol_entry);
return -1;
}
- volume_label = exfat_conv_volume_serial(vol_entry);
- if (!volume_label)
+ volume_label = exfat_conv_volume_label(vol_entry);
+ if (!volume_label) {
+ free(vol_entry);
return -EINVAL;
+ }
exfat_info("label: %s\n", volume_label);
free(volume_label);
+ free(vol_entry);
return 0;
}
return ret;
}
-int exfat_show_volume_serial(struct exfat_blk_dev *bd,
- struct exfat_user_input *ui)
+int exfat_show_volume_serial(int fd)
{
struct pbr *ppbr;
int ret;
- ppbr = malloc(bd->sector_size);
+ ppbr = malloc(EXFAT_MAX_SECTOR_SIZE);
if (!ppbr) {
exfat_err("Cannot allocate pbr: out of memory\n");
return -1;
}
/* read main boot sector */
- ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX);
+ ret = exfat_read(fd, (char *)ppbr, EXFAT_MAX_SECTOR_SIZE, 0);
if (ret < 0) {
exfat_err("main boot sector read failed\n");
ret = -1;
{
unsigned int checksum = 0;
int ret, sec_idx, backup_sec_idx = 0;
- int sector_size = bd->sector_size;
unsigned char *buf;
buf = malloc(bd->sector_size);
goto free_buf;
}
- if (sec_idx == BOOT_SEC_IDX) {
+ if (sec_idx == BOOT_SEC_IDX)
is_boot_sec = true;
- sector_size = sizeof(struct pbr);
- } else if (sec_idx >= EXBOOT_SEC_IDX && sec_idx < OEM_SEC_IDX)
- sector_size = sizeof(struct exbs);
- boot_calc_checksum(buf, sector_size, is_boot_sec,
+ boot_calc_checksum(buf, bd->sector_size, is_boot_sec,
&checksum);
}
int ret;
struct pbr *ppbr;
- ppbr = malloc(bd->sector_size);
+ ppbr = malloc(EXFAT_MAX_SECTOR_SIZE);
if (!ppbr) {
exfat_err("Cannot allocate pbr: out of memory\n");
return -1;
}
/* read main boot sector */
- ret = exfat_read_sector(bd, (char *)ppbr, BOOT_SEC_IDX);
+ ret = exfat_read(bd->dev_fd, (char *)ppbr, EXFAT_MAX_SECTOR_SIZE,
+ BOOT_SEC_IDX);
if (ret < 0) {
exfat_err("main boot sector read failed\n");
ret = -1;
goto free_ppbr;
}
+ bd->sector_size = 1 << ppbr->bsx.sect_size_bits;
ppbr->bsx.vol_serial = ui->volume_serial;
/* update main boot sector */
unsigned int clu_off_sectnr, unsigned int clu)
{
return clu_off_sectnr * bd->sector_size +
- (clu - EXFAT_REVERVED_CLUSTERS) * bd->cluster_size;
+ (clu - EXFAT_RESERVED_CLUSTERS) * bd->cluster_size;
}