Windowsでddコマンドと同じ処理をおこなう

# はじめに
Windowsでddコマンドと同じ処理を実行する方法を説明します。

# DeviceID
fopenしてfreadするだけですが、DeviceIDをfilenameとする必要があります。
次の方法でDeviceIDを知ることができます。

```
C:\WINDOWS\system32>wmic diskdrive get BytesPerSector,DeviceID,Model,Partitions,Size
BytesPerSector  DeviceID            Model                               Partitions  Size
512             \\.\PHYSICALDRIVE1  I-O DATA USB Flash Disk USB Device  1           115153920
512             \\.\PHYSICALDRIVE0  HGST HTS545050A7E660                4           500105249280
```

DeviceIDをfilenameとしてfopenします。
次にSample Codeを示します。

# Sample Code

```:makefile
CFLAGS=-I. -Wall -Werror -O0
OBJS= \
  dd.o \

TARGET=dd

%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $<

$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

clean:
	rm -rf $(TARGET) $(OBJS)
```

```c:dd.c
#define _FILE_OFFSET_BITS 64

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>

#define STR_IF    "if="
#define STR_OF    "of="
#define STR_BS    "bs="
#define STR_COUNT "count="
#define STR_SKIP  "skip="

static void usage()
{
  printf("usage:\n");
  printf("  dd if=[input] of=[output] bs=[bytes] count=[n] skip=[s]\n");
  printf("   ex. ./dd.exe if=\\\\.\\PHYSICALDRIVE1 of=./dump.bin bs=512 count=10 skip=0\n");
}

int main(int argc, char* argv[])
{
  FILE* input = 0, *output = 0;
  size_t bs, count, i, s;
  uint8_t* buf = 0;
  
  if (argc != 6) {
    usage();
    return -1;
  }
  
  if (strncmp(argv[1], STR_IF, strlen(STR_IF)) != 0) {
    usage();
    return -1;
  }
  input = fopen(argv[1]+ strlen(STR_IF), "rb");
  if (input == 0) {
    perror("error fopen");
    usage();
    return -1;
  }
  
  if (strncmp(argv[2], STR_OF, strlen(STR_OF)) != 0) {
    usage();
    return -1;
  }
  output = fopen(argv[2]+ strlen(STR_OF), "wb");
  if (output == 0) {
    perror("error fopen");
    usage();
    return -1;
  }
  
  sscanf(argv[3]+strlen(STR_BS), "%"PRIu64, &bs);
  sscanf(argv[4]+strlen(STR_COUNT), "%"PRIu64, &count);
  sscanf(argv[5]+strlen(STR_SKIP), "%"PRIu64, &s);
  
  buf = malloc(bs);
  
  fseeko(input, s*bs, SEEK_SET);
  
  for (i=0; i<count; i++) {
    if (fread(buf, bs, 1, input) != 1) {
      break;
    }
    if (fwrite(buf, bs, 1, output) != 1) {
      break;
    }
  }
  
  free(buf);
  
  fclose(input);
  fclose(output);
  
  return 0;
}
```

**管理者権限**でMSYS2 MINGW64 shell launcherを起動します。

```bash:console
$ gcc --version && make clean && make && ./dd.exe if=\\\\.\\PHYSICALDRIVE1 of=./dump.bin bs=512 count=1
gcc.exe (Rev2, Built by MSYS2 project) 6.2.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rm -rf dd dd.o
cc -I. -Wall -Werror -O0 -c -o dd.o dd.c
cc -I. -Wall -Werror -O0 -o dd dd.o

$ hexdump.exe -C ./dump.bin
00000000  33 c0 8e d0 bc 00 7c 8e  c0 8e d8 be 00 7c bf 00  |3.....|......|..|
00000010  06 b9 00 02 fc f3 a4 50  68 1c 06 cb fb b9 04 00  |.......Ph.......|
00000020  bd be 07 80 7e 00 00 7c  0b 0f 85 0e 01 83 c5 10  |....~..|........|
00000030  e2 f1 cd 18 88 56 00 55  c6 46 11 05 c6 46 10 00  |.....V.U.F...F..|
00000040  b4 41 bb aa 55 cd 13 5d  72 0f 81 fb 55 aa 75 09  |.A..U..]r...U.u.|
00000050  f7 c1 01 00 74 03 fe 46  10 66 60 80 7e 10 00 74  |....t..F.f`.~..t|
00000060  26 66 68 00 00 00 00 66  ff 76 08 68 00 00 68 00  |&fh....f.v.h..h.|
00000070  7c 68 01 00 68 10 00 b4  42 8a 56 00 8b f4 cd 13  ||h..h...B.V.....|
```

# References
- http://www.cplusplus.com/forum/general/209582/
- https://eijiyoshida.hatenablog.jp/entry/20150210/1423549903