Import upstream version 1.8.0+git20210122.1.2b5ad9c
Debian Janitor
2 years ago
0 | 0 | language: c |
1 | 1 | |
2 | compiler: | |
3 | - clang | |
4 | - gcc | |
2 | matrix: | |
3 | include: | |
4 | - os: windows | |
5 | compiler: | |
6 | - clang | |
7 | before_install: | |
8 | - mkdir build && cd build && wget "https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/libusb-win32-bin-1.2.6.0.zip" && 7z x libusb-win32-bin-1.2.6.0.zip -o"$PROGRAMFILES" && mv "$PROGRAMFILES/libusb-win32-bin-1.2.6.0" "$PROGRAMFILES/libusb-win32" | |
9 | install: | |
10 | choco install doxygen.install ninja | |
11 | script: | |
12 | cmake -GNinja .. && cmake --build . | |
5 | 13 | |
6 | env: | |
7 | - BLD=cmake | |
8 | - BLD=autoconf | |
14 | - os: linux | |
15 | dist: bionic | |
16 | compiler: | |
17 | - clang | |
18 | addons: | |
19 | apt: | |
20 | packages: | |
21 | - libusb-dev | |
22 | - doxygen | |
23 | - cmake | |
24 | script: | |
25 | - mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install | |
26 | ||
27 | - os: linux | |
28 | dist: bionic | |
29 | compiler: | |
30 | - clang | |
31 | addons: | |
32 | apt: | |
33 | packages: | |
34 | - libusb-dev | |
35 | - doxygen | |
36 | script: | |
37 | - autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install | |
9 | 38 | |
10 | addons: | |
11 | apt: | |
12 | packages: | |
13 | - libusb-dev | |
14 | - doxygen | |
15 | - cmake | |
39 | - os: linux | |
40 | dist: bionic | |
41 | compiler: | |
42 | - gcc | |
43 | addons: | |
44 | apt: | |
45 | packages: | |
46 | - libusb-dev | |
47 | - doxygen | |
48 | - cmake | |
49 | script: | |
50 | - mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install | |
16 | 51 | |
17 | script: | |
18 | - if [ $BLD == autoconf ]; then autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install; fi | |
19 | - if [ $BLD == cmake ]; then mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install; fi | |
52 | - os: linux | |
53 | dist: bionic | |
54 | compiler: | |
55 | - gcc | |
56 | addons: | |
57 | apt: | |
58 | packages: | |
59 | - libusb-dev | |
60 | - doxygen | |
61 | script: | |
62 | - autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install | |
63 | ||
64 | - os: osx | |
65 | osx_image: xcode12 | |
66 | compiler: | |
67 | - clang | |
68 | before_install: | |
69 | - brew install doxygen libusb-compat | |
70 | script: | |
71 | - mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install | |
72 | ||
73 | - os: osx | |
74 | osx_image: xcode12 | |
75 | compiler: | |
76 | - clang | |
77 | before_install: | |
78 | - brew install doxygen libusb-compat m4 | |
79 | script: | |
80 | - autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install |
17 | 17 | |
18 | 18 | # config.h |
19 | 19 | IF(WIN32) |
20 | SET(LIBNFC_SYSCONFDIR "./config" CACHE PATH "libnfc configuration directory") | |
20 | 21 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) |
21 | SET(LIBNFC_SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/config" CACHE PATH "libnfc configuration directory") | |
22 | 22 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32) |
23 | IF(NOT MINGW) | |
24 | SET(CMAKE_C_FLAGS "-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE ${CMAKE_C_FLAGS}") | |
25 | ENDIF(NOT MINGW) | |
23 | 26 | ELSE(WIN32) |
24 | 27 | SET(_XOPEN_SOURCE 600) |
25 | 28 | SET(SYSCONFDIR "/etc" CACHE PATH "System configuration directory") |
137 | 140 | IF(LIBNFC_DRIVER_PN53X_USB) |
138 | 141 | SET(PKG_REQ ${PKG_REQ} "libusb") |
139 | 142 | ENDIF(LIBNFC_DRIVER_PN53X_USB) |
143 | IF(LIBNFC_DRIVER_ACR122_USB) | |
144 | SET(PKG_REQ ${PKG_REQ} "libusb") | |
145 | ENDIF(LIBNFC_DRIVER_ACR122_USB) | |
140 | 146 | IF(LIBNFC_DRIVER_PCSC) |
141 | 147 | SET(PKG_REQ ${PKG_REQ} "libpcsclite") |
142 | ENDIF(LIBNFC_DRIVER_ACR122) | |
148 | ENDIF(LIBNFC_DRIVER_PCSC) | |
143 | 149 | IF(LIBNFC_DRIVER_ACR122_PCSC) |
144 | 150 | SET(PKG_REQ ${PKG_REQ} "libpcsclite") |
145 | 151 | ENDIF(LIBNFC_DRIVER_ACR122_PCSC) |
200 | 206 | SET(RC_COMMENT "${PACKAGE_NAME} library") |
201 | 207 | SET(RC_INTERNAL_NAME "${PACKAGE_NAME} ${WIN32_MODE}") |
202 | 208 | SET(RC_ORIGINAL_NAME ${PACKAGE_NAME}.dll) |
203 | SET(RC_FILE_TYPE VFT_DLL) | |
209 | # RC_FILE_TYPE: VFT_DLL | |
210 | SET(RC_FILE_TYPE 0x00000002L) | |
204 | 211 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windows/libnfc.rc @ONLY) |
205 | 212 | ENDIF(WIN32) |
206 | 213 |
1 | 1 | |
2 | 2 | AM_CFLAGS = $(LIBNFC_CFLAGS) |
3 | 3 | |
4 | SUBDIRS = libnfc utils examples include contrib cmake test | |
4 | SUBDIRS = libnfc utils | |
5 | ||
6 | if EXAMPLE_ENABLED | |
7 | SUBDIRS += examples | |
8 | endif | |
9 | ||
10 | SUBDIRS += include contrib cmake test | |
5 | 11 | |
6 | 12 | pkgconfigdir = $(libdir)/pkgconfig |
7 | 13 | pkgconfig_DATA = libnfc.pc |
39 | 39 | |
40 | 40 | * acr122_pcsc: |
41 | 41 | |
42 | - pcsc-lite http://pcsclite.alioth.debian.org/ | |
42 | - pcsc-lite https://pcsclite.apdu.fr/ | |
43 | 43 | - pcsc: |
44 | 44 | |
45 | 45 | - Support build with pcsc driver, which can be using all compatible readers, Feitian R502 and bR500 already passed the test. |
25 | 25 | |
26 | 26 | IF(NOT LIBUSB_FOUND) |
27 | 27 | IF(WIN32) |
28 | FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "$ENV{ProgramFiles}/LibUSB-Win32/include" NO_SYSTEM_ENVIRONMENT_PATH) | |
29 | FIND_LIBRARY(LIBUSB_LIBRARIES NAMES libusb PATHS "$ENV{ProgramFiles}/LibUSB-Win32/lib/gcc") | |
30 | SET(LIBUSB_LIBRARY_DIR "$ENV{ProgramFiles}/LibUSB-Win32/bin/x86/") | |
28 | IF(MINGW) | |
29 | FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/include" NO_SYSTEM_ENVIRONMENT_PATH) | |
30 | FIND_LIBRARY(LIBUSB_LIBRARIES NAMES libusb PATHS "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/lib/gcc") | |
31 | SET(LIBUSB_LIBRARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/bin/x86/") | |
32 | ELSE(MINGW) | |
33 | FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "$ENV{ProgramW6432}/libusb-win32/include" NO_SYSTEM_ENVIRONMENT_PATH) | |
34 | FIND_LIBRARY(LIBUSB_LIBRARIES NAMES libusb PATHS "$ENV{ProgramW6432}/libusb-win32/lib/msvc_x64") | |
35 | SET(LIBUSB_LIBRARY_DIR "$ENV{ProgramW6432}/libusb-win32/bin/amd64/") | |
36 | ENDIF(MINGW) | |
31 | 37 | # Must fix up variable to avoid backslashes during packaging |
32 | 38 | STRING(REGEX REPLACE "\\\\" "/" LIBUSB_LIBRARY_DIR ${LIBUSB_LIBRARY_DIR}) |
33 | 39 | ELSE(WIN32) |
2 | 2 | SET(LIBNFC_DRIVER_ACR122_USB ON CACHE BOOL "Enable ACR122 support (Direct USB connection)") |
3 | 3 | SET(LIBNFC_DRIVER_ACR122S ON CACHE BOOL "Enable ACR122S support (Use serial port)") |
4 | 4 | SET(LIBNFC_DRIVER_ARYGON ON CACHE BOOL "Enable ARYGON support (Use serial port)") |
5 | IF(WIN32) | |
5 | IF(UNIX AND NOT APPLE) | |
6 | SET(LIBNFC_DRIVER_PN532_I2C ON CACHE BOOL "Enable PN532 I2C support (Use I2C bus)") | |
7 | SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)") | |
8 | ELSE(UNIX AND NOT APPLE) | |
6 | 9 | SET(LIBNFC_DRIVER_PN532_I2C OFF CACHE BOOL "Enable PN532 I2C support (Use I2C bus)") |
7 | 10 | SET(LIBNFC_DRIVER_PN532_SPI OFF CACHE BOOL "Enable PN532 SPI support (Use SPI bus)") |
8 | ELSE(WIN32) | |
9 | SET(LIBNFC_DRIVER_PN532_I2C ON CACHE BOOL "Enable PN532 I2C support (Use I2C bus)") | |
10 | SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)") | |
11 | ENDIF(WIN32) | |
11 | ENDIF(UNIX AND NOT APPLE) | |
12 | 12 | SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)") |
13 | 13 | SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)") |
14 | 14 | |
67 | 67 | SET(USB_REQUIRED TRUE) |
68 | 68 | ENDIF(LIBNFC_DRIVER_PN53X_USB) |
69 | 69 | |
70 | IF(LIBNFC_DRIVER_ACR122_USB) | |
71 | FIND_PACKAGE(LIBUSB REQUIRED) | |
72 | ADD_DEFINITIONS("-DDRIVER_ACR122_USB_ENABLED") | |
73 | SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_usb") | |
74 | SET(USB_REQUIRED TRUE) | |
75 | ENDIF(LIBNFC_DRIVER_ACR122_USB) | |
76 | ||
70 | 77 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers) |
156 | 156 | fi |
157 | 157 | AM_CONDITIONAL(DOC_ENABLED, [test x"$enable_doc" = xyes]) |
158 | 158 | |
159 | # Example build (default: yes) | |
160 | AC_ARG_ENABLE([example],AS_HELP_STRING([--enable-example],[Enable example build.]),[enable_example=$enableval],[enable_example="yes"]) | |
161 | ||
162 | AC_MSG_CHECKING(for example build) | |
163 | AC_MSG_RESULT($enable_example) | |
164 | ||
165 | AM_CONDITIONAL(EXAMPLE_ENABLED, [test x"$enable_example" = xyes]) | |
166 | ||
159 | 167 | # Dependencies |
160 | 168 | PKG_CONFIG_REQUIRES="" |
161 | 169 | |
174 | 182 | fi |
175 | 183 | AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"]) |
176 | 184 | |
185 | if test x"$enable_example" = "xyes" | |
186 | then | |
177 | 187 | AC_CHECK_READLINE |
188 | fi | |
178 | 189 | |
179 | 190 | # Help us to write great code ;-) |
180 | 191 | CFLAGS="$CFLAGS -Wall -pedantic -Wextra" |
0 | /* | |
1 | * Dirent interface for Microsoft Visual Studio | |
2 | * | |
3 | * Copyright (C) 2006-2012 Toni Ronkko | |
4 | * This file is part of dirent. Dirent may be freely distributed | |
5 | * under the MIT license. For all details and documentation, see | |
6 | * https://github.com/tronkko/dirent | |
7 | */ | |
8 | #ifndef DIRENT_H | |
9 | #define DIRENT_H | |
10 | ||
11 | /* | |
12 | * Include windows.h without Windows Sockets 1.1 to prevent conflicts with | |
13 | * Windows Sockets 2.0. | |
14 | */ | |
15 | #ifndef WIN32_LEAN_AND_MEAN | |
16 | # define WIN32_LEAN_AND_MEAN | |
17 | #endif | |
18 | #include <windows.h> | |
19 | ||
20 | #include <stdio.h> | |
21 | #include <stdarg.h> | |
22 | #include <wchar.h> | |
23 | #include <string.h> | |
24 | #include <stdlib.h> | |
25 | #include <malloc.h> | |
26 | #include <sys/types.h> | |
27 | #include <sys/stat.h> | |
28 | #include <errno.h> | |
29 | ||
30 | /* Indicates that d_type field is available in dirent structure */ | |
31 | #define _DIRENT_HAVE_D_TYPE | |
32 | ||
33 | /* Indicates that d_namlen field is available in dirent structure */ | |
34 | #define _DIRENT_HAVE_D_NAMLEN | |
35 | ||
36 | /* Entries missing from MSVC 6.0 */ | |
37 | #if !defined(FILE_ATTRIBUTE_DEVICE) | |
38 | # define FILE_ATTRIBUTE_DEVICE 0x40 | |
39 | #endif | |
40 | ||
41 | /* File type and permission flags for stat(), general mask */ | |
42 | #if !defined(S_IFMT) | |
43 | # define S_IFMT _S_IFMT | |
44 | #endif | |
45 | ||
46 | /* Directory bit */ | |
47 | #if !defined(S_IFDIR) | |
48 | # define S_IFDIR _S_IFDIR | |
49 | #endif | |
50 | ||
51 | /* Character device bit */ | |
52 | #if !defined(S_IFCHR) | |
53 | # define S_IFCHR _S_IFCHR | |
54 | #endif | |
55 | ||
56 | /* Pipe bit */ | |
57 | #if !defined(S_IFFIFO) | |
58 | # define S_IFFIFO _S_IFFIFO | |
59 | #endif | |
60 | ||
61 | /* Regular file bit */ | |
62 | #if !defined(S_IFREG) | |
63 | # define S_IFREG _S_IFREG | |
64 | #endif | |
65 | ||
66 | /* Read permission */ | |
67 | #if !defined(S_IREAD) | |
68 | # define S_IREAD _S_IREAD | |
69 | #endif | |
70 | ||
71 | /* Write permission */ | |
72 | #if !defined(S_IWRITE) | |
73 | # define S_IWRITE _S_IWRITE | |
74 | #endif | |
75 | ||
76 | /* Execute permission */ | |
77 | #if !defined(S_IEXEC) | |
78 | # define S_IEXEC _S_IEXEC | |
79 | #endif | |
80 | ||
81 | /* Pipe */ | |
82 | #if !defined(S_IFIFO) | |
83 | # define S_IFIFO _S_IFIFO | |
84 | #endif | |
85 | ||
86 | /* Block device */ | |
87 | #if !defined(S_IFBLK) | |
88 | # define S_IFBLK 0 | |
89 | #endif | |
90 | ||
91 | /* Link */ | |
92 | #if !defined(S_IFLNK) | |
93 | # define S_IFLNK 0 | |
94 | #endif | |
95 | ||
96 | /* Socket */ | |
97 | #if !defined(S_IFSOCK) | |
98 | # define S_IFSOCK 0 | |
99 | #endif | |
100 | ||
101 | /* Read user permission */ | |
102 | #if !defined(S_IRUSR) | |
103 | # define S_IRUSR S_IREAD | |
104 | #endif | |
105 | ||
106 | /* Write user permission */ | |
107 | #if !defined(S_IWUSR) | |
108 | # define S_IWUSR S_IWRITE | |
109 | #endif | |
110 | ||
111 | /* Execute user permission */ | |
112 | #if !defined(S_IXUSR) | |
113 | # define S_IXUSR 0 | |
114 | #endif | |
115 | ||
116 | /* Read group permission */ | |
117 | #if !defined(S_IRGRP) | |
118 | # define S_IRGRP 0 | |
119 | #endif | |
120 | ||
121 | /* Write group permission */ | |
122 | #if !defined(S_IWGRP) | |
123 | # define S_IWGRP 0 | |
124 | #endif | |
125 | ||
126 | /* Execute group permission */ | |
127 | #if !defined(S_IXGRP) | |
128 | # define S_IXGRP 0 | |
129 | #endif | |
130 | ||
131 | /* Read others permission */ | |
132 | #if !defined(S_IROTH) | |
133 | # define S_IROTH 0 | |
134 | #endif | |
135 | ||
136 | /* Write others permission */ | |
137 | #if !defined(S_IWOTH) | |
138 | # define S_IWOTH 0 | |
139 | #endif | |
140 | ||
141 | /* Execute others permission */ | |
142 | #if !defined(S_IXOTH) | |
143 | # define S_IXOTH 0 | |
144 | #endif | |
145 | ||
146 | /* Maximum length of file name */ | |
147 | #if !defined(PATH_MAX) | |
148 | # define PATH_MAX MAX_PATH | |
149 | #endif | |
150 | #if !defined(FILENAME_MAX) | |
151 | # define FILENAME_MAX MAX_PATH | |
152 | #endif | |
153 | #if !defined(NAME_MAX) | |
154 | # define NAME_MAX FILENAME_MAX | |
155 | #endif | |
156 | ||
157 | /* File type flags for d_type */ | |
158 | #define DT_UNKNOWN 0 | |
159 | #define DT_REG S_IFREG | |
160 | #define DT_DIR S_IFDIR | |
161 | #define DT_FIFO S_IFIFO | |
162 | #define DT_SOCK S_IFSOCK | |
163 | #define DT_CHR S_IFCHR | |
164 | #define DT_BLK S_IFBLK | |
165 | #define DT_LNK S_IFLNK | |
166 | ||
167 | /* Macros for converting between st_mode and d_type */ | |
168 | #define IFTODT(mode) ((mode) & S_IFMT) | |
169 | #define DTTOIF(type) (type) | |
170 | ||
171 | /* | |
172 | * File type macros. Note that block devices, sockets and links cannot be | |
173 | * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are | |
174 | * only defined for compatibility. These macros should always return false | |
175 | * on Windows. | |
176 | */ | |
177 | #if !defined(S_ISFIFO) | |
178 | # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) | |
179 | #endif | |
180 | #if !defined(S_ISDIR) | |
181 | # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) | |
182 | #endif | |
183 | #if !defined(S_ISREG) | |
184 | # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) | |
185 | #endif | |
186 | #if !defined(S_ISLNK) | |
187 | # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) | |
188 | #endif | |
189 | #if !defined(S_ISSOCK) | |
190 | # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) | |
191 | #endif | |
192 | #if !defined(S_ISCHR) | |
193 | # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) | |
194 | #endif | |
195 | #if !defined(S_ISBLK) | |
196 | # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) | |
197 | #endif | |
198 | ||
199 | /* Return the exact length of the file name without zero terminator */ | |
200 | #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) | |
201 | ||
202 | /* Return the maximum size of a file name */ | |
203 | #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) | |
204 | ||
205 | ||
206 | #ifdef __cplusplus | |
207 | extern "C" { | |
208 | #endif | |
209 | ||
210 | ||
211 | /* Wide-character version */ | |
212 | struct _wdirent { | |
213 | /* Always zero */ | |
214 | long d_ino; | |
215 | ||
216 | /* File position within stream */ | |
217 | long d_off; | |
218 | ||
219 | /* Structure size */ | |
220 | unsigned short d_reclen; | |
221 | ||
222 | /* Length of name without \0 */ | |
223 | size_t d_namlen; | |
224 | ||
225 | /* File type */ | |
226 | int d_type; | |
227 | ||
228 | /* File name */ | |
229 | wchar_t d_name[PATH_MAX+1]; | |
230 | }; | |
231 | typedef struct _wdirent _wdirent; | |
232 | ||
233 | struct _WDIR { | |
234 | /* Current directory entry */ | |
235 | struct _wdirent ent; | |
236 | ||
237 | /* Private file data */ | |
238 | WIN32_FIND_DATAW data; | |
239 | ||
240 | /* True if data is valid */ | |
241 | int cached; | |
242 | ||
243 | /* Win32 search handle */ | |
244 | HANDLE handle; | |
245 | ||
246 | /* Initial directory name */ | |
247 | wchar_t *patt; | |
248 | }; | |
249 | typedef struct _WDIR _WDIR; | |
250 | ||
251 | /* Multi-byte character version */ | |
252 | struct dirent { | |
253 | /* Always zero */ | |
254 | long d_ino; | |
255 | ||
256 | /* File position within stream */ | |
257 | long d_off; | |
258 | ||
259 | /* Structure size */ | |
260 | unsigned short d_reclen; | |
261 | ||
262 | /* Length of name without \0 */ | |
263 | size_t d_namlen; | |
264 | ||
265 | /* File type */ | |
266 | int d_type; | |
267 | ||
268 | /* File name */ | |
269 | char d_name[PATH_MAX+1]; | |
270 | }; | |
271 | typedef struct dirent dirent; | |
272 | ||
273 | struct DIR { | |
274 | struct dirent ent; | |
275 | struct _WDIR *wdirp; | |
276 | }; | |
277 | typedef struct DIR DIR; | |
278 | ||
279 | ||
280 | /* Dirent functions */ | |
281 | static DIR *opendir (const char *dirname); | |
282 | static _WDIR *_wopendir (const wchar_t *dirname); | |
283 | ||
284 | static struct dirent *readdir (DIR *dirp); | |
285 | ||
286 | static int readdir_r( | |
287 | DIR *dirp, struct dirent *entry, struct dirent **result); | |
288 | ||
289 | static int closedir (DIR *dirp); | |
290 | static int _wclosedir (_WDIR *dirp); | |
291 | ||
292 | /* For compatibility with Symbian */ | |
293 | #define wdirent _wdirent | |
294 | #define WDIR _WDIR | |
295 | #define wopendir _wopendir | |
296 | #define wreaddir _wreaddir | |
297 | #define wclosedir _wclosedir | |
298 | #define wrewinddir _wrewinddir | |
299 | ||
300 | ||
301 | /* Internal utility functions */ | |
302 | static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); | |
303 | static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); | |
304 | ||
305 | static int dirent_mbstowcs_s( | |
306 | size_t *pReturnValue, | |
307 | wchar_t *wcstr, | |
308 | size_t sizeInWords, | |
309 | const char *mbstr, | |
310 | size_t count); | |
311 | ||
312 | static int dirent_wcstombs_s( | |
313 | size_t *pReturnValue, | |
314 | char *mbstr, | |
315 | size_t sizeInBytes, | |
316 | const wchar_t *wcstr, | |
317 | size_t count); | |
318 | ||
319 | static void dirent_set_errno (int error); | |
320 | ||
321 | ||
322 | /* | |
323 | * Open directory stream DIRNAME for read and return a pointer to the | |
324 | * internal working area that is used to retrieve individual directory | |
325 | * entries. | |
326 | */ | |
327 | static _WDIR* | |
328 | _wopendir( | |
329 | const wchar_t *dirname) | |
330 | { | |
331 | _WDIR *dirp = NULL; | |
332 | int error; | |
333 | ||
334 | /* Must have directory name */ | |
335 | if (dirname == NULL || dirname[0] == '\0') { | |
336 | dirent_set_errno (ENOENT); | |
337 | return NULL; | |
338 | } | |
339 | ||
340 | /* Allocate new _WDIR structure */ | |
341 | dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); | |
342 | if (dirp != NULL) { | |
343 | DWORD n; | |
344 | ||
345 | /* Reset _WDIR structure */ | |
346 | dirp->handle = INVALID_HANDLE_VALUE; | |
347 | dirp->patt = NULL; | |
348 | dirp->cached = 0; | |
349 | ||
350 | /* Compute the length of full path plus zero terminator | |
351 | * | |
352 | * Note that on WinRT there's no way to convert relative paths | |
353 | * into absolute paths, so just assume it is an absolute path. | |
354 | */ | |
355 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) | |
356 | n = wcslen(dirname); | |
357 | # else | |
358 | n = GetFullPathNameW (dirname, 0, NULL, NULL); | |
359 | # endif | |
360 | ||
361 | /* Allocate room for absolute directory name and search pattern */ | |
362 | dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); | |
363 | if (dirp->patt) { | |
364 | ||
365 | /* | |
366 | * Convert relative directory name to an absolute one. This | |
367 | * allows rewinddir() to function correctly even when current | |
368 | * working directory is changed between opendir() and rewinddir(). | |
369 | * | |
370 | * Note that on WinRT there's no way to convert relative paths | |
371 | * into absolute paths, so just assume it is an absolute path. | |
372 | */ | |
373 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) | |
374 | wcsncpy_s(dirp->patt, n+1, dirname, n); | |
375 | # else | |
376 | n = GetFullPathNameW (dirname, n, dirp->patt, NULL); | |
377 | # endif | |
378 | if (n > 0) { | |
379 | wchar_t *p; | |
380 | ||
381 | /* Append search pattern \* to the directory name */ | |
382 | p = dirp->patt + n; | |
383 | if (dirp->patt < p) { | |
384 | switch (p[-1]) { | |
385 | case '\\': | |
386 | case '/': | |
387 | case ':': | |
388 | /* Directory ends in path separator, e.g. c:\temp\ */ | |
389 | /*NOP*/; | |
390 | break; | |
391 | ||
392 | default: | |
393 | /* Directory name doesn't end in path separator */ | |
394 | *p++ = '\\'; | |
395 | } | |
396 | } | |
397 | *p++ = '*'; | |
398 | *p = '\0'; | |
399 | ||
400 | /* Open directory stream and retrieve the first entry */ | |
401 | if (dirent_first (dirp)) { | |
402 | /* Directory stream opened successfully */ | |
403 | error = 0; | |
404 | } else { | |
405 | /* Cannot retrieve first entry */ | |
406 | error = 1; | |
407 | dirent_set_errno (ENOENT); | |
408 | } | |
409 | ||
410 | } else { | |
411 | /* Cannot retrieve full path name */ | |
412 | dirent_set_errno (ENOENT); | |
413 | error = 1; | |
414 | } | |
415 | ||
416 | } else { | |
417 | /* Cannot allocate memory for search pattern */ | |
418 | error = 1; | |
419 | } | |
420 | ||
421 | } else { | |
422 | /* Cannot allocate _WDIR structure */ | |
423 | error = 1; | |
424 | } | |
425 | ||
426 | /* Clean up in case of error */ | |
427 | if (error && dirp) { | |
428 | _wclosedir (dirp); | |
429 | dirp = NULL; | |
430 | } | |
431 | ||
432 | return dirp; | |
433 | } | |
434 | ||
435 | /* | |
436 | * Close directory stream opened by opendir() function. This invalidates the | |
437 | * DIR structure as well as any directory entry read previously by | |
438 | * _wreaddir(). | |
439 | */ | |
440 | static int | |
441 | _wclosedir( | |
442 | _WDIR *dirp) | |
443 | { | |
444 | int ok; | |
445 | if (dirp) { | |
446 | ||
447 | /* Release search handle */ | |
448 | if (dirp->handle != INVALID_HANDLE_VALUE) { | |
449 | FindClose (dirp->handle); | |
450 | dirp->handle = INVALID_HANDLE_VALUE; | |
451 | } | |
452 | ||
453 | /* Release search pattern */ | |
454 | if (dirp->patt) { | |
455 | free (dirp->patt); | |
456 | dirp->patt = NULL; | |
457 | } | |
458 | ||
459 | /* Release directory structure */ | |
460 | free (dirp); | |
461 | ok = /*success*/0; | |
462 | ||
463 | } else { | |
464 | ||
465 | /* Invalid directory stream */ | |
466 | dirent_set_errno (EBADF); | |
467 | ok = /*failure*/-1; | |
468 | ||
469 | } | |
470 | return ok; | |
471 | } | |
472 | ||
473 | /* Get first directory entry (internal) */ | |
474 | static WIN32_FIND_DATAW* | |
475 | dirent_first( | |
476 | _WDIR *dirp) | |
477 | { | |
478 | WIN32_FIND_DATAW *datap; | |
479 | ||
480 | /* Open directory and retrieve the first entry */ | |
481 | dirp->handle = FindFirstFileExW( | |
482 | dirp->patt, FindExInfoStandard, &dirp->data, | |
483 | FindExSearchNameMatch, NULL, 0); | |
484 | if (dirp->handle != INVALID_HANDLE_VALUE) { | |
485 | ||
486 | /* a directory entry is now waiting in memory */ | |
487 | datap = &dirp->data; | |
488 | dirp->cached = 1; | |
489 | ||
490 | } else { | |
491 | ||
492 | /* Failed to re-open directory: no directory entry in memory */ | |
493 | dirp->cached = 0; | |
494 | datap = NULL; | |
495 | ||
496 | } | |
497 | return datap; | |
498 | } | |
499 | ||
500 | /* | |
501 | * Get next directory entry (internal). | |
502 | * | |
503 | * Returns | |
504 | */ | |
505 | static WIN32_FIND_DATAW* | |
506 | dirent_next( | |
507 | _WDIR *dirp) | |
508 | { | |
509 | WIN32_FIND_DATAW *p; | |
510 | ||
511 | /* Get next directory entry */ | |
512 | if (dirp->cached != 0) { | |
513 | ||
514 | /* A valid directory entry already in memory */ | |
515 | p = &dirp->data; | |
516 | dirp->cached = 0; | |
517 | ||
518 | } else if (dirp->handle != INVALID_HANDLE_VALUE) { | |
519 | ||
520 | /* Get the next directory entry from stream */ | |
521 | if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { | |
522 | /* Got a file */ | |
523 | p = &dirp->data; | |
524 | } else { | |
525 | /* The very last entry has been processed or an error occurred */ | |
526 | FindClose (dirp->handle); | |
527 | dirp->handle = INVALID_HANDLE_VALUE; | |
528 | p = NULL; | |
529 | } | |
530 | ||
531 | } else { | |
532 | ||
533 | /* End of directory stream reached */ | |
534 | p = NULL; | |
535 | ||
536 | } | |
537 | ||
538 | return p; | |
539 | } | |
540 | ||
541 | /* | |
542 | * Open directory stream using plain old C-string. | |
543 | */ | |
544 | static DIR* | |
545 | opendir( | |
546 | const char *dirname) | |
547 | { | |
548 | struct DIR *dirp; | |
549 | int error; | |
550 | ||
551 | /* Must have directory name */ | |
552 | if (dirname == NULL || dirname[0] == '\0') { | |
553 | dirent_set_errno (ENOENT); | |
554 | return NULL; | |
555 | } | |
556 | ||
557 | /* Allocate memory for DIR structure */ | |
558 | dirp = (DIR*) malloc (sizeof (struct DIR)); | |
559 | if (dirp) { | |
560 | wchar_t wname[PATH_MAX + 1]; | |
561 | size_t n; | |
562 | ||
563 | /* Convert directory name to wide-character string */ | |
564 | error = dirent_mbstowcs_s( | |
565 | &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); | |
566 | if (!error) { | |
567 | ||
568 | /* Open directory stream using wide-character name */ | |
569 | dirp->wdirp = _wopendir (wname); | |
570 | if (dirp->wdirp) { | |
571 | /* Directory stream opened */ | |
572 | error = 0; | |
573 | } else { | |
574 | /* Failed to open directory stream */ | |
575 | error = 1; | |
576 | } | |
577 | ||
578 | } else { | |
579 | /* | |
580 | * Cannot convert file name to wide-character string. This | |
581 | * occurs if the string contains invalid multi-byte sequences or | |
582 | * the output buffer is too small to contain the resulting | |
583 | * string. | |
584 | */ | |
585 | error = 1; | |
586 | } | |
587 | ||
588 | } else { | |
589 | /* Cannot allocate DIR structure */ | |
590 | error = 1; | |
591 | } | |
592 | ||
593 | /* Clean up in case of error */ | |
594 | if (error && dirp) { | |
595 | free (dirp); | |
596 | dirp = NULL; | |
597 | } | |
598 | ||
599 | return dirp; | |
600 | } | |
601 | ||
602 | /* | |
603 | * Read next directory entry. | |
604 | */ | |
605 | static struct dirent* | |
606 | readdir( | |
607 | DIR *dirp) | |
608 | { | |
609 | struct dirent *entry; | |
610 | ||
611 | /* | |
612 | * Read directory entry to buffer. We can safely ignore the return value | |
613 | * as entry will be set to NULL in case of error. | |
614 | */ | |
615 | (void) readdir_r (dirp, &dirp->ent, &entry); | |
616 | ||
617 | /* Return pointer to statically allocated directory entry */ | |
618 | return entry; | |
619 | } | |
620 | ||
621 | /* | |
622 | * Read next directory entry into called-allocated buffer. | |
623 | * | |
624 | * Returns zero on success. If the end of directory stream is reached, then | |
625 | * sets result to NULL and returns zero. | |
626 | */ | |
627 | static int | |
628 | readdir_r( | |
629 | DIR *dirp, | |
630 | struct dirent *entry, | |
631 | struct dirent **result) | |
632 | { | |
633 | WIN32_FIND_DATAW *datap; | |
634 | ||
635 | /* Read next directory entry */ | |
636 | datap = dirent_next (dirp->wdirp); | |
637 | if (datap) { | |
638 | size_t n; | |
639 | int error; | |
640 | ||
641 | /* Attempt to convert file name to multi-byte string */ | |
642 | error = dirent_wcstombs_s( | |
643 | &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); | |
644 | ||
645 | /* | |
646 | * If the file name cannot be represented by a multi-byte string, | |
647 | * then attempt to use old 8+3 file name. This allows traditional | |
648 | * Unix-code to access some file names despite of unicode | |
649 | * characters, although file names may seem unfamiliar to the user. | |
650 | * | |
651 | * Be ware that the code below cannot come up with a short file | |
652 | * name unless the file system provides one. At least | |
653 | * VirtualBox shared folders fail to do this. | |
654 | */ | |
655 | if (error && datap->cAlternateFileName[0] != '\0') { | |
656 | error = dirent_wcstombs_s( | |
657 | &n, entry->d_name, PATH_MAX + 1, | |
658 | datap->cAlternateFileName, PATH_MAX + 1); | |
659 | } | |
660 | ||
661 | if (!error) { | |
662 | DWORD attr; | |
663 | ||
664 | /* Length of file name excluding zero terminator */ | |
665 | entry->d_namlen = n - 1; | |
666 | ||
667 | /* File attributes */ | |
668 | attr = datap->dwFileAttributes; | |
669 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { | |
670 | entry->d_type = DT_CHR; | |
671 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { | |
672 | entry->d_type = DT_DIR; | |
673 | } else { | |
674 | entry->d_type = DT_REG; | |
675 | } | |
676 | ||
677 | /* Reset dummy fields */ | |
678 | entry->d_ino = 0; | |
679 | entry->d_off = 0; | |
680 | entry->d_reclen = sizeof (struct dirent); | |
681 | ||
682 | } else { | |
683 | ||
684 | /* | |
685 | * Cannot convert file name to multi-byte string so construct | |
686 | * an erroneous directory entry and return that. Note that | |
687 | * we cannot return NULL as that would stop the processing | |
688 | * of directory entries completely. | |
689 | */ | |
690 | entry->d_name[0] = '?'; | |
691 | entry->d_name[1] = '\0'; | |
692 | entry->d_namlen = 1; | |
693 | entry->d_type = DT_UNKNOWN; | |
694 | entry->d_ino = 0; | |
695 | entry->d_off = -1; | |
696 | entry->d_reclen = 0; | |
697 | ||
698 | } | |
699 | ||
700 | /* Return pointer to directory entry */ | |
701 | *result = entry; | |
702 | ||
703 | } else { | |
704 | ||
705 | /* No more directory entries */ | |
706 | *result = NULL; | |
707 | ||
708 | } | |
709 | ||
710 | return /*OK*/0; | |
711 | } | |
712 | ||
713 | /* | |
714 | * Close directory stream. | |
715 | */ | |
716 | static int | |
717 | closedir( | |
718 | DIR *dirp) | |
719 | { | |
720 | int ok; | |
721 | if (dirp) { | |
722 | ||
723 | /* Close wide-character directory stream */ | |
724 | ok = _wclosedir (dirp->wdirp); | |
725 | dirp->wdirp = NULL; | |
726 | ||
727 | /* Release multi-byte character version */ | |
728 | free (dirp); | |
729 | ||
730 | } else { | |
731 | ||
732 | /* Invalid directory stream */ | |
733 | dirent_set_errno (EBADF); | |
734 | ok = /*failure*/-1; | |
735 | ||
736 | } | |
737 | return ok; | |
738 | } | |
739 | ||
740 | /* Convert multi-byte string to wide character string */ | |
741 | static int | |
742 | dirent_mbstowcs_s( | |
743 | size_t *pReturnValue, | |
744 | wchar_t *wcstr, | |
745 | size_t sizeInWords, | |
746 | const char *mbstr, | |
747 | size_t count) | |
748 | { | |
749 | int error; | |
750 | ||
751 | #if defined(_MSC_VER) && _MSC_VER >= 1400 | |
752 | ||
753 | /* Microsoft Visual Studio 2005 or later */ | |
754 | error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); | |
755 | ||
756 | #else | |
757 | ||
758 | /* Older Visual Studio or non-Microsoft compiler */ | |
759 | size_t n; | |
760 | ||
761 | /* Convert to wide-character string (or count characters) */ | |
762 | n = mbstowcs (wcstr, mbstr, sizeInWords); | |
763 | if (!wcstr || n < count) { | |
764 | ||
765 | /* Zero-terminate output buffer */ | |
766 | if (wcstr && sizeInWords) { | |
767 | if (n >= sizeInWords) { | |
768 | n = sizeInWords - 1; | |
769 | } | |
770 | wcstr[n] = 0; | |
771 | } | |
772 | ||
773 | /* Length of resulting multi-byte string WITH zero terminator */ | |
774 | if (pReturnValue) { | |
775 | *pReturnValue = n + 1; | |
776 | } | |
777 | ||
778 | /* Success */ | |
779 | error = 0; | |
780 | ||
781 | } else { | |
782 | ||
783 | /* Could not convert string */ | |
784 | error = 1; | |
785 | ||
786 | } | |
787 | ||
788 | #endif | |
789 | ||
790 | return error; | |
791 | } | |
792 | ||
793 | /* Convert wide-character string to multi-byte string */ | |
794 | static int | |
795 | dirent_wcstombs_s( | |
796 | size_t *pReturnValue, | |
797 | char *mbstr, | |
798 | size_t sizeInBytes, /* max size of mbstr */ | |
799 | const wchar_t *wcstr, | |
800 | size_t count) | |
801 | { | |
802 | int error; | |
803 | ||
804 | #if defined(_MSC_VER) && _MSC_VER >= 1400 | |
805 | ||
806 | /* Microsoft Visual Studio 2005 or later */ | |
807 | error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); | |
808 | ||
809 | #else | |
810 | ||
811 | /* Older Visual Studio or non-Microsoft compiler */ | |
812 | size_t n; | |
813 | ||
814 | /* Convert to multi-byte string (or count the number of bytes needed) */ | |
815 | n = wcstombs (mbstr, wcstr, sizeInBytes); | |
816 | if (!mbstr || n < count) { | |
817 | ||
818 | /* Zero-terminate output buffer */ | |
819 | if (mbstr && sizeInBytes) { | |
820 | if (n >= sizeInBytes) { | |
821 | n = sizeInBytes - 1; | |
822 | } | |
823 | mbstr[n] = '\0'; | |
824 | } | |
825 | ||
826 | /* Length of resulting multi-bytes string WITH zero-terminator */ | |
827 | if (pReturnValue) { | |
828 | *pReturnValue = n + 1; | |
829 | } | |
830 | ||
831 | /* Success */ | |
832 | error = 0; | |
833 | ||
834 | } else { | |
835 | ||
836 | /* Cannot convert string */ | |
837 | error = 1; | |
838 | ||
839 | } | |
840 | ||
841 | #endif | |
842 | ||
843 | return error; | |
844 | } | |
845 | ||
846 | /* Set errno variable */ | |
847 | static void | |
848 | dirent_set_errno( | |
849 | int error) | |
850 | { | |
851 | #if defined(_MSC_VER) && _MSC_VER >= 1400 | |
852 | ||
853 | /* Microsoft Visual Studio 2005 and later */ | |
854 | _set_errno (error); | |
855 | ||
856 | #else | |
857 | ||
858 | /* Non-Microsoft compiler or older Microsoft compiler */ | |
859 | errno = error; | |
860 | ||
861 | #endif | |
862 | } | |
863 | ||
864 | ||
865 | #ifdef __cplusplus | |
866 | } | |
867 | #endif | |
868 | #endif /*DIRENT_H*/ | |
869 |
0 | #include "getopt.h" // make sure you construct the header file as dictated above | |
1 | ||
2 | /* | |
3 | * Copyright (c) 1987, 1993, 1994 | |
4 | * The Regents of the University of California. All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #include <string.h> | |
36 | #include <stdio.h> | |
37 | ||
38 | int opterr = 1, /* if error message should be printed */ | |
39 | optind = 1, /* index into parent argv vector */ | |
40 | optopt, /* character checked for validity */ | |
41 | optreset; /* reset getopt */ | |
42 | char *optarg; /* argument associated with option */ | |
43 | ||
44 | #define BADCH (int)'?' | |
45 | #define BADARG (int)':' | |
46 | #define EMSG "" | |
47 | ||
48 | /* | |
49 | * getopt -- | |
50 | * Parse argc/argv argument vector. | |
51 | */ | |
52 | int getopt(int nargc, char * const nargv[], const char *ostr) | |
53 | { | |
54 | static char *place = EMSG; /* option letter processing */ | |
55 | const char *oli; /* option letter list index */ | |
56 | ||
57 | if (optreset || !*place) { /* update scanning pointer */ | |
58 | optreset = 0; | |
59 | if (optind >= nargc || *(place = nargv[optind]) != '-') { | |
60 | place = EMSG; | |
61 | return (-1); | |
62 | } | |
63 | if (place[1] && *++place == '-') { /* found "--" */ | |
64 | ++optind; | |
65 | place = EMSG; | |
66 | return (-1); | |
67 | } | |
68 | } /* option letter okay? */ | |
69 | if ((optopt = (int)*place++) == (int)':' || | |
70 | !(oli = strchr(ostr, optopt))) { | |
71 | /* | |
72 | * if the user didn't specify '-' as an option, | |
73 | * assume it means -1. | |
74 | */ | |
75 | if (optopt == (int)'-') | |
76 | return (-1); | |
77 | if (!*place) | |
78 | ++optind; | |
79 | if (opterr && *ostr != ':') | |
80 | (void)printf("illegal option -- %c\n", optopt); | |
81 | return (BADCH); | |
82 | } | |
83 | if (*++oli != ':') { /* don't need argument */ | |
84 | optarg = NULL; | |
85 | if (!*place) | |
86 | ++optind; | |
87 | } | |
88 | else { /* need an argument */ | |
89 | if (*place) /* no white space */ | |
90 | optarg = place; | |
91 | else if (nargc <= ++optind) { /* no arg */ | |
92 | place = EMSG; | |
93 | if (*ostr == ':') | |
94 | return (BADARG); | |
95 | if (opterr) | |
96 | (void)printf("option requires an argument -- %c\n", optopt); | |
97 | return (BADCH); | |
98 | } | |
99 | else /* white space */ | |
100 | optarg = nargv[optind]; | |
101 | place = EMSG; | |
102 | ++optind; | |
103 | } | |
104 | return (optopt); /* dump back option letter */ | |
105 | } |
0 | #ifndef GETOPT_H | |
1 | ||
2 | #define GETOPT_H | |
3 | ||
4 | extern int opterr; /* if error message should be printed */ | |
5 | extern int optind; /* index into parent argv vector */ | |
6 | extern int optopt; /* character checked for validity */ | |
7 | extern int optreset; /* reset getopt */ | |
8 | extern char *optarg; /* argument associated with option */ | |
9 | ||
10 | int getopt(int nargc, char * const nargv[], const char *ostr); | |
11 | ||
12 | #endif |
182 | 182 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Timeouts are set to %lu ms", timeout_ms); |
183 | 183 | |
184 | 184 | // TODO Enhance the reception method |
185 | // - According to MSDN, it could be better to implement nfc_abort_command() mecanism using Cancello() | |
185 | // - According to MSDN, it could be better to implement nfc_abort_command() mechanism using Cancello() | |
186 | 186 | volatile bool *abort_flag_p = (volatile bool *)abort_p; |
187 | 187 | do { |
188 | 188 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ReadFile"); |
38 | 38 | nfc_device_get_supported_baud_rate_target_mode |
39 | 39 | nfc_device_set_property_int |
40 | 40 | nfc_device_set_property_bool |
41 | nfc_emulate_target | |
41 | 42 | iso14443a_crc |
42 | 43 | iso14443a_crc_append |
43 | 44 | iso14443b_crc |
49 | 50 | str_nfc_modulation_type |
50 | 51 | str_nfc_baud_rate |
51 | 52 | str_nfc_target |
53 | pn53x_transceive | |
54 | pn532_SAMConfiguration | |
55 | pn53x_read_register | |
56 | pn53x_write_register |
0 | LIBRARY nfc | |
1 | VERSION 1.7 | |
2 | ||
3 | EXPORTS | |
4 | nfc_init | |
5 | nfc_exit | |
6 | nfc_register_driver | |
7 | nfc_open | |
8 | nfc_close | |
9 | nfc_abort_command | |
10 | nfc_list_devices | |
11 | nfc_idle | |
12 | nfc_initiator_init | |
13 | nfc_initiator_init_secure_element | |
14 | nfc_initiator_select_passive_target | |
15 | nfc_initiator_list_passive_targets | |
16 | nfc_initiator_poll_target | |
17 | nfc_initiator_select_dep_target | |
18 | nfc_initiator_poll_dep_target | |
19 | nfc_initiator_deselect_target | |
20 | nfc_initiator_transceive_bytes | |
21 | nfc_initiator_transceive_bits | |
22 | nfc_initiator_transceive_bytes_timed | |
23 | nfc_initiator_transceive_bits_timed | |
24 | nfc_initiator_target_is_present | |
25 | nfc_target_init | |
26 | nfc_target_send_bytes | |
27 | nfc_target_receive_bytes | |
28 | nfc_target_send_bits | |
29 | nfc_target_receive_bits | |
30 | nfc_strerror | |
31 | nfc_strerror_r | |
32 | nfc_perror | |
33 | nfc_device_get_last_error | |
34 | nfc_device_get_name | |
35 | nfc_device_get_connstring | |
36 | nfc_device_get_supported_modulation | |
37 | nfc_device_get_supported_baud_rate | |
38 | nfc_device_get_supported_baud_rate_target_mode | |
39 | nfc_device_set_property_int | |
40 | nfc_device_set_property_bool | |
41 | nfc_emulate_target | |
42 | iso14443a_crc | |
43 | iso14443a_crc_append | |
44 | iso14443b_crc | |
45 | iso14443b_crc_append | |
46 | iso14443a_locate_historical_bytes | |
47 | nfc_free | |
48 | nfc_version | |
49 | nfc_device_get_information_about | |
50 | str_nfc_modulation_type | |
51 | str_nfc_baud_rate | |
52 | str_nfc_target | |
53 | pn53x_transceive | |
54 | pn532_SAMConfiguration | |
55 | pn53x_read_register | |
56 | pn53x_write_register |
0 | #include "windows.h" | |
1 | ||
2 | 0 | 1 VERSIONINFO |
3 | 1 | FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0 |
4 | 2 | PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0 |
5 | 3 | FILEFLAGSMASK 0x3fL |
6 | #ifdef _DEBUG | |
7 | FILEFLAGS VS_FF_DEBUG|VS_FF_PRERELEASE | |
8 | #else | |
9 | FILEFLAGS 0L | |
10 | #endif | |
11 | FILEOS VOS_NT_WINDOWS32 | |
4 | FILEFLAGS 0x0L | |
5 | FILEOS 0x00040004L | |
12 | 6 | FILETYPE @RC_FILE_TYPE@ |
13 | 7 | FILESUBTYPE 0x0L |
14 | 8 | BEGIN |
47 | 47 | # define ENOTSUP WSAEOPNOTSUPP |
48 | 48 | # define ECONNABORTED WSAECONNABORTED |
49 | 49 | # else |
50 | #ifndef _MSC_VER | |
50 | 51 | # define snprintf sprintf_s |
52 | #endif | |
51 | 53 | # define strdup _strdup |
52 | 54 | # endif |
53 | 55 |
22 | 22 | SET(RC_COMMENT "${PACKAGE_NAME} example") |
23 | 23 | SET(RC_INTERNAL_NAME ${source}) |
24 | 24 | SET(RC_ORIGINAL_NAME ${source}.exe) |
25 | SET(RC_FILE_TYPE VFT_APP) | |
25 | # RC_FILE_TYPE: VFT_APP | |
26 | SET(RC_FILE_TYPE 0x00000001L) | |
26 | 27 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY) |
27 | 28 | LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc) |
28 | 29 | ENDIF(WIN32) |
4 | 4 | |
5 | 5 | # Add in the rc for version information in the dll |
6 | 6 | LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../windows/libnfc.rc) |
7 | IF (NOT MINGW) | |
8 | LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc_msvc.def) | |
9 | ENDIF() | |
7 | 10 | ENDIF(WIN32) |
8 | 11 | |
9 | 12 | # Library's chips |
25 | 28 | ENDIF(UART_REQUIRED) |
26 | 29 | |
27 | 30 | IF(I2C_REQUIRED) |
28 | IF(WIN32) | |
29 | # Windows is not supported at the moment | |
31 | IF(UNIX AND NOT APPLE) | |
32 | LIST(APPEND BUSES_SOURCES buses/i2c) | |
33 | ELSE(UNIX AND NOT APPLE) | |
34 | # Only Linux is supported at the moment | |
30 | 35 | #LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/i2c) |
31 | MESSAGE( FATAL_ERROR "I2C not (yet) supported under Windows!" ) | |
32 | ELSE(WIN32) | |
33 | LIST(APPEND BUSES_SOURCES buses/i2c) | |
34 | ENDIF(WIN32) | |
36 | MESSAGE( FATAL_ERROR "I2C is only (yet) supported in Linux!" ) | |
37 | ENDIF(UNIX AND NOT APPLE) | |
35 | 38 | ENDIF(I2C_REQUIRED) |
36 | 39 | |
37 | 40 | IF(SPI_REQUIRED) |
38 | IF(WIN32) | |
39 | # Windows is not supported at the moment | |
41 | IF(UNIX AND NOT APPLE) | |
42 | LIST(APPEND BUSES_SOURCES buses/spi) | |
43 | ELSE(UNIX AND NOT APPLE) | |
44 | # Only Linux is supported at the moment | |
40 | 45 | #LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi) |
41 | MESSAGE( FATAL_ERROR "SPI not (yet) supported under Windows!" ) | |
42 | ELSE(WIN32) | |
43 | LIST(APPEND BUSES_SOURCES buses/spi) | |
44 | ENDIF(WIN32) | |
46 | MESSAGE( FATAL_ERROR "SPI is only (yet) supported in Linux!" ) | |
47 | ENDIF(UNIX AND NOT APPLE) | |
45 | 48 | ENDIF(SPI_REQUIRED) |
46 | 49 | |
47 | 50 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses) |
62 | 65 | |
63 | 66 | IF(LIBNFC_LOG) |
64 | 67 | IF(WIN32) |
65 | SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}") | |
68 | IF(MINGW) | |
69 | SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}") | |
70 | ENDIF(MINGW) | |
66 | 71 | LIST(APPEND LIBRARY_SOURCES log ../contrib/win32/libnfc/log-internal) |
67 | 72 | ELSE(WIN32) |
68 | 73 | LIST(APPEND LIBRARY_SOURCES log log-internal) |
87 | 92 | IF(WIN32) |
88 | 93 | # Libraries that are windows specific |
89 | 94 | TARGET_LINK_LIBRARIES(nfc wsock32) |
90 | ||
91 | ADD_CUSTOM_COMMAND( | |
92 | OUTPUT libnfc.lib | |
93 | COMMAND ${DLLTOOL} -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll | |
94 | DEPENDS nfc ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def | |
95 | ) | |
96 | ADD_CUSTOM_TARGET(win32lib ALL DEPENDS libnfc.lib) | |
95 | IF(MINGW) | |
96 | ADD_CUSTOM_COMMAND( | |
97 | OUTPUT libnfc.lib | |
98 | COMMAND ${DLLTOOL} -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll | |
99 | DEPENDS nfc ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def | |
100 | ) | |
101 | ADD_CUSTOM_TARGET(win32lib ALL DEPENDS libnfc.lib) | |
102 | ELSE() | |
103 | ADD_LIBRARY(win32lib ALIAS nfc) | |
104 | ENDIF() | |
97 | 105 | |
98 | 106 | # On Windows the shared (runtime) library should be either in the same |
99 | 107 | # directory as the excutables or in the path, we add it to same directory |
32 | 32 | #ifndef __NFC_BUS_UART_H__ |
33 | 33 | # define __NFC_BUS_UART_H__ |
34 | 34 | |
35 | #if !defined(_MSC_VER) | |
35 | 36 | # include <sys/time.h> |
37 | #endif | |
36 | 38 | |
37 | 39 | # include <stdio.h> |
38 | 40 | # include <string.h> |
1207 | 1207 | // send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response |
1208 | 1208 | uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL |
1209 | 1209 | uint8_t abtAnticol[11]; |
1210 | if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout)) < 0) { | |
1210 | if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) { | |
1211 | 1211 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all"); |
1212 | 1212 | //if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout |
1213 | 1213 | // continue; |
2063 | 2063 | } |
2064 | 2064 | uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; |
2065 | 2065 | uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; |
2066 | if ((ret = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 1) { | |
2066 | if (nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar) < 1) { | |
2067 | 2067 | failures++; |
2068 | 2068 | } else { |
2069 | 2069 | nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); |
194 | 194 | free(key); |
195 | 195 | free(value); |
196 | 196 | } else { |
197 | free(key); | |
198 | free(value); | |
197 | 199 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Parse error on line #%d: %s", lineno, line); |
198 | 200 | } |
199 | 201 | } |
59 | 59 | #include <sys/select.h> |
60 | 60 | #include <errno.h> |
61 | 61 | #include <string.h> |
62 | ||
62 | #ifdef _MSC_VER | |
63 | #include <sys/types.h> | |
64 | #endif | |
63 | 65 | #include <nfc/nfc.h> |
64 | 66 | |
65 | 67 | #include "nfc-internal.h" |
595 | 597 | if (timeout == USB_INFINITE_TIMEOUT) { |
596 | 598 | usb_timeout = USB_TIMEOUT_PER_PASS; |
597 | 599 | } else { |
598 | // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mecanism | |
600 | // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism | |
599 | 601 | remaining_time -= USB_TIMEOUT_PER_PASS; |
600 | 602 | if (remaining_time <= 0) { |
601 | 603 | pnd->last_error = NFC_ETIMEOUT; |
526 | 526 | uart_close(DRIVER_DATA(pnd)->port); |
527 | 527 | |
528 | 528 | #ifndef WIN32 |
529 | // Release file descriptors used for abort mecanism | |
529 | // Release file descriptors used for abort mechanism | |
530 | 530 | close(DRIVER_DATA(pnd)->abort_fds[0]); |
531 | 531 | close(DRIVER_DATA(pnd)->abort_fds[1]); |
532 | 532 | #endif |
157 | 157 | } |
158 | 158 | |
159 | 159 | #ifndef WIN32 |
160 | // pipe-based abort mecanism | |
160 | // pipe-based abort mechanism | |
161 | 161 | if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { |
162 | 162 | uart_close(DRIVER_DATA(pnd)->port); |
163 | 163 | pn53x_data_free(pnd); |
210 | 210 | uart_close(DRIVER_DATA(pnd)->port); |
211 | 211 | |
212 | 212 | #ifndef WIN32 |
213 | // Release file descriptors used for abort mecanism | |
213 | // Release file descriptors used for abort mechanism | |
214 | 214 | close(DRIVER_DATA(pnd)->iAbortFds[0]); |
215 | 215 | close(DRIVER_DATA(pnd)->iAbortFds[1]); |
216 | 216 | #endif |
303 | 303 | pnd->driver = &arygon_driver; |
304 | 304 | |
305 | 305 | #ifndef WIN32 |
306 | // pipe-based abort mecanism | |
306 | // pipe-based abort mechanism | |
307 | 307 | if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { |
308 | 308 | uart_close(DRIVER_DATA(pnd)->port); |
309 | 309 | pn53x_data_free(pnd); |
4 | 4 | * Copyright (C) 2019 Frank Morgner |
5 | 5 | * See AUTHORS file for a more comprehensive list of contributors. |
6 | 6 | * Additional contributors of this file: |
7 | * | |
7 | * Copyright (C) 2020 Feitian Technologies | |
8 | 8 | * This program is free software: you can redistribute it and/or modify it |
9 | 9 | * under the terms of the GNU Lesser General Public License as published by the |
10 | 10 | * Free Software Foundation, either version 3 of the License, or (at your |
71 | 71 | #include <winscard.h> |
72 | 72 | #endif |
73 | 73 | |
74 | #ifdef WIN32 | |
75 | #include <windows.h> | |
76 | #define usleep(x) Sleep((x + 999) / 1000) | |
77 | #endif | |
78 | ||
74 | 79 | #define PCSC_DRIVER_NAME "pcsc" |
75 | 80 | |
76 | 81 | #include <nfc/nfc.h> |
137 | 142 | DWORD dw_rx_len = *rx_len; |
138 | 143 | //in libfreefare, tx_len = 1, and it leads to 0x80100008 error, with PC/SC reader, the input tx_len at least two bytes for the SW value |
139 | 144 | //so if found the reader is Feitian reader, we set to 2 |
140 | if (dw_rx_len == 1 && is_pcsc_reader_vendor_feitian(pnd)) { | |
141 | dw_rx_len = 2; | |
145 | if (is_pcsc_reader_vendor_feitian(pnd)) | |
146 | { | |
147 | if (dw_rx_len == 1) | |
148 | { | |
149 | dw_rx_len = 2; | |
150 | } else { | |
151 | dw_rx_len += 2;//in libfreefare, some data length send not include sw1 and sw2, so add it. | |
152 | } | |
142 | 153 | } |
143 | 154 | |
144 | 155 | LOG_HEX(NFC_LOG_GROUP_COM, "TX", tx, tx_len); |
251 | 262 | if (pnd->last_error != NFC_SUCCESS) |
252 | 263 | return pnd->last_error; |
253 | 264 | |
254 | if (resp_len < 2) { | |
265 | if (resp_len <= 2) { | |
255 | 266 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for ATS"); |
256 | 267 | pnd->last_error = NFC_EDEVNOTSUPP; |
257 | 268 | return pnd->last_error; |
262 | 273 | return pnd->last_error; |
263 | 274 | } |
264 | 275 | |
265 | //memcpy(ats, resp + 1, resp_len - 2 - 1); | |
266 | memcpy(ats, resp + 1, resp[0] - 1); | |
276 | memcpy(ats, resp + 1, resp_len - 2 - 1);//data expect TL and SW1SW2 | |
267 | 277 | return resp_len - 2 - 1; |
268 | 278 | } |
269 | 279 | |
340 | 350 | if (is_pcsc_reader_vendor_feitian(pnd)) { |
341 | 351 | uint8_t atqa[2]; |
342 | 352 | pcsc_get_atqa(pnd, atqa, sizeof(atqa)); |
343 | //memcpy(pnt->nti.nai.abtAtqa,atqa,2); | |
344 | pnt->nti.nai.abtAtqa[0] = atqa[1]; | |
345 | pnt->nti.nai.abtAtqa[1] = atqa[0]; | |
353 | //ATQA Coding of NXP Contactless Card ICs | |
354 | if(atqa[0] = 0x00 || atqa[0] == 0x03) | |
355 | { | |
356 | memcpy(pnt->nti.nai.abtAtqa,atqa,2); | |
357 | }else { | |
358 | pnt->nti.nai.abtAtqa[0] = atqa[1]; | |
359 | pnt->nti.nai.abtAtqa[1] = atqa[0]; | |
360 | } | |
361 | ||
346 | 362 | uint8_t sak[1]; |
347 | 363 | pcsc_get_sak(pnd, sak, sizeof(sak)); |
348 | 364 | pnt->nti.nai.btSak = sak[0]; |
349 | 365 | uint8_t ats[256]; |
350 | 366 | int ats_len = pcsc_get_ats(pnd, ats, sizeof(ats)); |
367 | ats_len = (ats_len > 0 ? ats_len : 0);//The reader may not support to get ATS | |
351 | 368 | memcpy(pnt->nti.nai.abtAts, ats, ats_len); |
352 | //memcpy(pnt->nti.nai.abtAts + ats_len, patr + 4, (uint8_t)(szatr - 5)); | |
353 | pnt->nti.nai.szAtsLen = ats_len;// + szatr - 5; | |
369 | pnt->nti.nai.szAtsLen = ats_len; | |
354 | 370 | } else { |
355 | 371 | /* SAK_ISO14443_4_COMPLIANT */ |
356 | 372 | pnt->nti.nai.btSak = 0x20; |
520 | 536 | // Test if context succeeded |
521 | 537 | if (!(pscc = pcsc_get_scardcontext())) |
522 | 538 | goto error; |
523 | DRIVER_DATA(pnd)->last_error = SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)); | |
539 | DRIVER_DATA(pnd)->last_error = SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0 | 1, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)); | |
524 | 540 | if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) { |
525 | 541 | // We can not connect to this device. |
526 | 542 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC connect failed"); |
796 | 812 | memcpy(apdu_data + 5, pbtTx + 2, szTx - 2); |
797 | 813 | send_size = 5 + szTx - 2; |
798 | 814 | } else if (pbtTx[0] == 0x60 || pbtTx[0] == 0x61 || pbtTx[0] == 0x1A) { //Auth command |
815 | //load pin first | |
816 | { | |
817 | apdu_data[0] = 0xFF; | |
818 | apdu_data[1] = 0x82; | |
819 | apdu_data[2] = 0x00; | |
820 | apdu_data[3] = 0x01; | |
821 | apdu_data[4] = 0x06; | |
822 | memcpy(apdu_data + 5, pbtTx + 2, 6); | |
823 | send_size = 11; | |
824 | pnd->last_error = pcsc_transmit(pnd, apdu_data, send_size, resp, &resp_len); | |
825 | memset(apdu_data, 0, sizeof(apdu_data)); | |
826 | memset(resp, 0, sizeof(resp)); | |
827 | usleep(500000);//delay 500ms | |
828 | } | |
829 | // then auth | |
799 | 830 | apdu_data[0] = 0xFF; |
800 | 831 | apdu_data[1] = 0x86; |
801 | 832 | apdu_data[2] = 0x00; |
883 | 914 | // ignore |
884 | 915 | return NFC_SUCCESS; |
885 | 916 | case NP_AUTO_ISO14443_4: |
917 | if ((bEnable == true) || (is_pcsc_reader_vendor_feitian(pnd))) | |
918 | return NFC_SUCCESS; | |
919 | break; | |
886 | 920 | case NP_EASY_FRAMING: |
887 | 921 | if ((bEnable == true) || (is_pcsc_reader_vendor_feitian(pnd))) |
888 | 922 | return NFC_SUCCESS; |
935 | 969 | { |
936 | 970 | struct pcsc_data *data = pnd->driver_data; |
937 | 971 | LPBYTE name = NULL, version = NULL, type = NULL, serial = NULL; |
972 | #ifdef __APPLE__ | |
973 | DWORD name_len = 0, version_len = 0, | |
974 | type_len = 0, serial_len = 0; | |
975 | #else | |
938 | 976 | DWORD name_len = SCARD_AUTOALLOCATE, version_len = SCARD_AUTOALLOCATE, |
939 | 977 | type_len = SCARD_AUTOALLOCATE, serial_len = SCARD_AUTOALLOCATE; |
978 | #endif | |
940 | 979 | int res = NFC_SUCCESS; |
941 | 980 | SCARDCONTEXT *pscc; |
942 | 981 |
135 | 135 | CHIP_DATA(pnd)->power_mode = LOWVBAT; |
136 | 136 | |
137 | 137 | #ifndef WIN32 |
138 | // pipe-based abort mecanism | |
138 | // pipe-based abort mechanism | |
139 | 139 | if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { |
140 | 140 | uart_close(DRIVER_DATA(pnd)->port); |
141 | 141 | pn53x_data_free(pnd); |
190 | 190 | uart_close(DRIVER_DATA(pnd)->port); |
191 | 191 | |
192 | 192 | #ifndef WIN32 |
193 | // Release file descriptors used for abort mecanism | |
193 | // Release file descriptors used for abort mechanism | |
194 | 194 | close(DRIVER_DATA(pnd)->iAbortFds[0]); |
195 | 195 | close(DRIVER_DATA(pnd)->iAbortFds[1]); |
196 | 196 | #endif |
276 | 276 | pnd->driver = &pn532_uart_driver; |
277 | 277 | |
278 | 278 | #ifndef WIN32 |
279 | // pipe-based abort mecanism | |
279 | // pipe-based abort mechanism | |
280 | 280 | if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { |
281 | 281 | uart_close(DRIVER_DATA(pnd)->port); |
282 | 282 | pn53x_data_free(pnd); |
42 | 42 | #include <sys/select.h> |
43 | 43 | #include <errno.h> |
44 | 44 | #include <string.h> |
45 | ||
45 | #ifdef _MSC_VER | |
46 | #include <sys/types.h> | |
47 | #endif | |
46 | 48 | #include <nfc/nfc.h> |
47 | 49 | |
48 | 50 | #include "nfc-internal.h" |
620 | 622 | if (timeout == USB_INFINITE_TIMEOUT) { |
621 | 623 | usb_timeout = USB_TIMEOUT_PER_PASS; |
622 | 624 | } else { |
623 | // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mecanism | |
625 | // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism | |
624 | 626 | remaining_time -= USB_TIMEOUT_PER_PASS; |
625 | 627 | if (remaining_time <= 0) { |
626 | 628 | pnd->last_error = NFC_ETIMEOUT; |
816 | 818 | if (NP_ACTIVATE_FIELD == property) { |
817 | 819 | /* Switch on/off LED2 and Progressive Field GPIO according to ACTIVATE_FIELD option */ |
818 | 820 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Switch progressive field %s", bEnable ? "On" : "Off"); |
819 | if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31))) < 0) | |
821 | if (pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31)) < 0) | |
820 | 822 | return NFC_ECHIP; |
821 | 823 | } |
822 | 824 | break; |
33 | 33 | |
34 | 34 | #include <stdbool.h> |
35 | 35 | #include <err.h> |
36 | #if !defined(_MSC_VER) | |
36 | 37 | # include <sys/time.h> |
38 | #endif | |
37 | 39 | |
38 | 40 | #include "nfc/nfc.h" |
39 | 41 |
564 | 564 | nfc_target *pnt) |
565 | 565 | { |
566 | 566 | uint8_t *abtInit = NULL; |
567 | uint8_t abtTmpInit[MAX(12, szInitData)]; | |
567 | uint8_t maxAbt = MAX(12, szInitData); | |
568 | uint8_t *abtTmpInit = malloc(sizeof(uint8_t) * maxAbt); | |
568 | 569 | size_t szInit = 0; |
569 | 570 | int res; |
570 | if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS) | |
571 | return res; | |
571 | if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS) { | |
572 | free(abtTmpInit); | |
573 | return res; | |
574 | } | |
572 | 575 | if (szInitData == 0) { |
573 | 576 | // Provide default values, if any |
574 | 577 | prepare_initiator_data(nm, &abtInit, &szInit); |
578 | free(abtTmpInit); | |
575 | 579 | } else if (nm.nmt == NMT_ISO14443A) { |
576 | 580 | abtInit = abtTmpInit; |
577 | 581 | iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit); |
578 | 582 | } else { |
579 | 583 | abtInit = abtTmpInit; |
580 | 584 | memcpy(abtInit, pbtInitData, szInitData); |
585 | free(abtTmpInit); | |
581 | 586 | szInit = szInitData; |
582 | 587 | } |
583 | ||
584 | 588 | HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt); |
589 | ||
590 | free(abtTmpInit); | |
585 | 591 | } |
586 | 592 | |
587 | 593 | /** @ingroup initiator |
22 | 22 | SET(RC_COMMENT "${PACKAGE_NAME} utility") |
23 | 23 | SET(RC_INTERNAL_NAME ${source}) |
24 | 24 | SET(RC_ORIGINAL_NAME ${source}.exe) |
25 | SET(RC_FILE_TYPE VFT_APP) | |
25 | # RC_FILE_TYPE: VFT_APP | |
26 | SET(RC_FILE_TYPE 0x00000001L) | |
26 | 27 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY) |
27 | 28 | LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc) |
28 | 29 | ENDIF(WIN32) |
40 | 41 | LIST(APPEND TARGETS ../contrib/win32/stdlib) |
41 | 42 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32) |
42 | 43 | ENDIF(${source} MATCHES "nfc-scan-device") |
44 | IF(${source} MATCHES "nfc-read-forum-tag3") | |
45 | LIST(APPEND TARGETS ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/getopt.c) | |
46 | ENDIF() | |
43 | 47 | ENDIF(WIN32) |
44 | 48 | |
45 | 49 | ADD_EXECUTABLE(${source} ${TARGETS}) |
96 | 96 | exit(EXIT_FAILURE); |
97 | 97 | } |
98 | 98 | |
99 | // Display libnfc version | |
100 | acLibnfcVersion = nfc_version(); | |
101 | printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); | |
102 | ||
103 | 99 | // Get commandline options |
104 | 100 | for (arg = 1; arg < argc; arg++) { |
105 | 101 | if (0 == strcmp(argv[arg], "-h")) { |
125 | 121 | } |
126 | 122 | } |
127 | 123 | |
124 | // Display libnfc version | |
125 | if (verbose) { | |
126 | acLibnfcVersion = nfc_version(); | |
127 | printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); | |
128 | } | |
129 | ||
130 | ||
128 | 131 | /* Lazy way to open an NFC device */ |
129 | 132 | #if 0 |
130 | 133 | pnd = nfc_open(context, NULL); |
53 | 53 | #include <string.h> |
54 | 54 | #include <ctype.h> |
55 | 55 | |
56 | #ifndef _WIN32 | |
57 | #include <fcntl.h> | |
58 | #include <sys/stat.h> | |
59 | #include <unistd.h> | |
60 | #endif | |
61 | ||
56 | 62 | #include <nfc/nfc.h> |
57 | 63 | |
58 | 64 | #include "mifare.h" |
69 | 75 | static bool bForceKeyFile; |
70 | 76 | static bool bTolerateFailures; |
71 | 77 | static bool bFormatCard; |
72 | static bool magic2 = false; | |
73 | static bool magic3 = false; | |
78 | static bool dWrite = false; | |
74 | 79 | static bool unlocked = false; |
75 | 80 | static uint8_t uiBlocks; |
76 | 81 | static uint8_t keys[] = { |
210 | 215 | if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) |
211 | 216 | return true; |
212 | 217 | |
213 | } else if (magic3) { | |
214 | //If it's a One Time Write card, we're gonna authenticate with the default keys | |
215 | memcpy(mp.mpa.abtKey, default_key, sizeof(default_key)); | |
216 | ||
217 | ||
218 | // Try to authenticate for the current sector | |
219 | if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) { | |
220 | return true; | |
221 | } | |
222 | 218 | // If formatting or not using key file, try to guess the right key |
223 | 219 | } else if (bFormatCard || !bUseKeyFile) { |
224 | 220 | for (size_t key_index = 0; key_index < num_keys; key_index++) { |
241 | 237 | } |
242 | 238 | |
243 | 239 | static bool |
244 | unlock_card(void) | |
240 | unlock_card(bool write) | |
245 | 241 | { |
246 | 242 | // Configure the CRC |
247 | 243 | if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { |
259 | 255 | // now send unlock |
260 | 256 | if (!transmit_bits(abtUnlock1, 7)) { |
261 | 257 | printf("Warning: Unlock command [1/2]: failed / not acknowledged.\n"); |
258 | dWrite = true; | |
259 | if (write) { | |
260 | printf("Trying to rewrite block 0 on a direct write tag.\n"); | |
261 | } | |
262 | 262 | } else { |
263 | 263 | if (transmit_bytes(abtUnlock2, 1)) { |
264 | 264 | printf("Card unlocked\n"); |
269 | 269 | } |
270 | 270 | |
271 | 271 | // reset reader |
272 | if (!unlocked) { | |
273 | if (nfc_initiator_select_passive_target(pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL) <= 0) { | |
274 | printf("Error: tag was removed\n"); | |
275 | nfc_close(pnd); | |
276 | nfc_exit(context); | |
277 | exit(EXIT_FAILURE); | |
278 | } | |
279 | return true; | |
280 | } | |
272 | 281 | // Configure the CRC |
273 | 282 | if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) { |
274 | 283 | nfc_perror(pnd, "nfc_device_set_property_bool"); |
315 | 324 | } |
316 | 325 | |
317 | 326 | static bool |
318 | read_card(int read_unlocked) | |
327 | read_card(bool read_unlocked) | |
319 | 328 | { |
320 | 329 | int32_t iBlock; |
321 | 330 | bool bFailure = false; |
322 | 331 | uint32_t uiReadBlocks = 0; |
323 | 332 | |
324 | 333 | if (read_unlocked) { |
334 | unlock_card(false); | |
325 | 335 | //If the user is attempting an unlocked read, but has a direct-write type magic card, they don't |
326 | 336 | //need to use the R mode. We'll trigger a warning and let them proceed. |
327 | if (magic2) { | |
328 | printf("Note: This card does not require an unlocked read (R) \n"); | |
337 | if (dWrite) { | |
338 | printf("Note: This card can't do an unlocked read (R) \n"); | |
329 | 339 | read_unlocked = 0; |
330 | } else { | |
331 | //If User has requested an unlocked read, but we're unable to unlock the card, we'll error out. | |
332 | if (!unlock_card()) { | |
333 | return false; | |
334 | } | |
335 | 340 | } |
336 | 341 | } |
337 | 342 | |
361 | 366 | if (read_unlocked) { |
362 | 367 | memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, sizeof(mtDump.amb[iBlock].mbd.abtData)); |
363 | 368 | } else { |
364 | //If we're using a One Time Write ('Magic 3') Badge - we'll use default keys + ACL | |
365 | if (magic3) { | |
366 | memcpy(mtDump.amb[iBlock].mbt.abtKeyA, default_key, sizeof(default_key)); | |
367 | memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits)); | |
368 | memcpy(mtDump.amb[iBlock].mbt.abtKeyB, default_key, sizeof(default_key)); | |
369 | } else { | |
370 | // Copy the keys over from our key dump and store the retrieved access bits | |
371 | memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, sizeof(mtDump.amb[iBlock].mbt.abtKeyA)); | |
372 | memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits)); | |
373 | memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, sizeof(mtDump.amb[iBlock].mbt.abtKeyB)); | |
369 | // Copy the keys over from our key dump and store the retrieved access bits | |
370 | memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, sizeof(mtDump.amb[iBlock].mbt.abtKeyA)); | |
371 | memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits)); | |
372 | memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, sizeof(mtDump.amb[iBlock].mbt.abtKeyB)); | |
374 | 373 | } |
375 | } | |
376 | 374 | } else { |
377 | 375 | printf("!\nfailed to read trailer block 0x%02x\n", iBlock); |
378 | 376 | bFailure = true; |
402 | 400 | } |
403 | 401 | |
404 | 402 | static bool |
405 | write_card(int write_block_zero) | |
403 | write_card(bool write_block_zero) | |
406 | 404 | { |
407 | 405 | uint32_t uiBlock; |
408 | 406 | bool bFailure = false; |
410 | 408 | |
411 | 409 | //Determine if we have to unlock the card |
412 | 410 | if (write_block_zero) { |
413 | //If the user is attempting an unlocked write, but has a direct-write type magic card, they don't | |
414 | //need to use the W mode. We'll trigger a warning and let them proceed. | |
415 | if (magic2) { | |
416 | printf("Note: This card does not require an unlocked write (W) \n"); | |
417 | write_block_zero = 0; | |
418 | } else { | |
419 | //If User has requested an unlocked write, but we're unable to unlock the card, we'll error out. | |
420 | if (!unlock_card()) { | |
421 | return false; | |
422 | } | |
423 | } | |
424 | } | |
425 | ||
426 | printf("Writing %d blocks |", uiBlocks + 1); | |
427 | // Completely write the card, end to start, but skipping block 0 | |
428 | for (uiBlock = 4; uiBlock <= uiBlocks; uiBlock++) { | |
411 | unlock_card(true); | |
412 | } | |
413 | ||
414 | printf("Writing %d blocks |", uiBlocks + write_block_zero); | |
415 | // Completely write the card, but skipping block 0 if we don't need to write on it | |
416 | for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) { | |
417 | //Determine if we have to write block 0 | |
418 | if (!write_block_zero && uiBlock == 0) { | |
419 | continue; | |
420 | } | |
429 | 421 | // Authenticate everytime we reach the first sector of a new block |
430 | if (is_first_block(uiBlock)) { | |
422 | if (uiBlock == 1 || is_first_block(uiBlock)) { | |
431 | 423 | if (bFailure) { |
432 | 424 | // When a failure occured we need to redo the anti-collision |
433 | 425 | if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { |
441 | 433 | |
442 | 434 | // Try to authenticate for the current sector |
443 | 435 | // If we are are writing to a chinese magic card, we've already unlocked |
444 | // If we're writing to a One Time Write card, we need to authenticate | |
436 | // If we're writing to a direct write card, we need to authenticate | |
445 | 437 | // If we're writing something else, we'll need to authenticate |
446 | if ((write_block_zero && magic3) || !write_block_zero) { | |
438 | if ((write_block_zero && dWrite) || !write_block_zero) { | |
447 | 439 | if (!authenticate(uiBlock) && !bTolerateFailures) { |
448 | 440 | printf("!\nError: authentication failed for block %02x\n", uiBlock); |
449 | 441 | return false; |
450 | 442 | } |
451 | 443 | } |
444 | } | |
452 | 445 | |
453 | 446 | if (is_trailer_block(uiBlock)) { |
454 | 447 | if (bFormatCard) { |
469 | 462 | bFailure = true; |
470 | 463 | } |
471 | 464 | } else { |
472 | // The first block 0x00 is read only, skip this | |
473 | if (uiBlock == 0 && !write_block_zero && !magic2) | |
474 | continue; | |
475 | ||
476 | 465 | // Make sure a earlier write did not fail |
477 | 466 | if (!bFailure) { |
478 | 467 | // Try to write the data block |
483 | 472 | memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData)); |
484 | 473 | // do not write a block 0 with incorrect BCC - card will be made invalid! |
485 | 474 | if (uiBlock == 0) { |
486 | if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) { | |
475 | if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00) { | |
487 | 476 | printf("!\nError: incorrect BCC in MFD file!\n"); |
488 | 477 | printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]); |
489 | 478 | return false; |
493 | 482 | bFailure = true; |
494 | 483 | printf("Failure to write to data block %i\n", uiBlock); |
495 | 484 | } |
496 | ||
485 | if (uiBlock == 0 && dWrite) { | |
486 | if (nfc_initiator_init(pnd) < 0) { | |
487 | nfc_perror(pnd, "nfc_initiator_init"); | |
488 | nfc_close(pnd); | |
489 | nfc_exit(context); | |
490 | exit(EXIT_FAILURE); | |
491 | }; | |
492 | if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { | |
493 | printf("!\nError: tag was removed\n"); | |
494 | return false; | |
495 | } | |
496 | } | |
497 | 497 | } else { |
498 | 498 | printf("Failure during write process.\n"); |
499 | 499 | } |
500 | 500 | } |
501 | } | |
501 | //} | |
502 | 502 | // Show if the write went well for each block |
503 | 503 | print_success_or_failure(bFailure, &uiWriteBlocks); |
504 | 504 | if ((! bTolerateFailures) && bFailure) |
505 | 505 | return false; |
506 | } | |
507 | ||
508 | //Write Block 0 if necessary | |
509 | if (write_block_zero || magic2 || magic3) { | |
510 | for (uiBlock = 0; uiBlock < 4; uiBlock++) { | |
511 | ||
512 | // The first block 0x00 is read only, skip this | |
513 | if (uiBlock == 0) { | |
514 | //If the card is not magic, we're gonna skip over | |
515 | if (write_block_zero || magic2 || magic3) { | |
516 | //NOP | |
517 | } else { | |
518 | continue; | |
519 | } | |
520 | } | |
521 | ||
522 | if (is_first_block(uiBlock)) { | |
523 | if (bFailure) { | |
524 | // When a failure occured we need to redo the anti-collision | |
525 | if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { | |
526 | printf("!\nError: tag was removed\n"); | |
527 | return false; | |
528 | } | |
529 | bFailure = false; | |
530 | } | |
531 | ||
532 | fflush(stdout); | |
533 | // Try to authenticate for the current sector | |
534 | // If we are are writing to a chinese magic card, we've already unlocked | |
535 | // If we're writing to a One Time Write, we need to authenticate | |
536 | // If we're writing something else, we'll need to authenticate | |
537 | if ((write_block_zero && magic3) || !write_block_zero) { | |
538 | if (!authenticate(uiBlock) && !bTolerateFailures) { | |
539 | printf("!\nError: authentication failed for block %02x\n", uiBlock); | |
540 | return false; | |
541 | } | |
542 | } | |
543 | } | |
544 | ||
545 | // Make sure a earlier write did not fail | |
546 | if (!bFailure) { | |
547 | // Try to write the data block | |
548 | if (bFormatCard && uiBlock) | |
549 | memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData)); | |
550 | else | |
551 | memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData)); | |
552 | // do not write a block 0 with incorrect BCC - card will be made invalid! | |
553 | if (uiBlock == 0) { | |
554 | if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) { | |
555 | printf("!\nError: incorrect BCC in MFD file!\n"); | |
556 | printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]); | |
557 | return false; | |
558 | } | |
559 | } | |
560 | if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) { | |
561 | bFailure = true; | |
562 | printf("Failure to write to data block %i\n", uiBlock); | |
563 | } | |
564 | ||
565 | } else { | |
566 | printf("Failure during write process.\n"); | |
567 | } | |
568 | ||
569 | // Show if the write went well for each block | |
570 | print_success_or_failure(bFailure, &uiWriteBlocks); | |
571 | if ((! bTolerateFailures) && bFailure) | |
572 | return false; | |
573 | ||
574 | } | |
575 | ||
576 | 506 | } |
577 | 507 | |
578 | 508 | printf("|\n"); |
592 | 522 | print_usage(const char *pcProgramName) |
593 | 523 | { |
594 | 524 | printf("Usage: "); |
525 | #ifndef _WIN32 | |
526 | printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f] [v]]\n", pcProgramName); | |
527 | #else | |
595 | 528 | printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName); |
596 | printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n"); | |
529 | #endif | |
530 | printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or block 0 write to (W) card\n"); | |
597 | 531 | printf(" *** format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\n"); |
598 | 532 | printf(" *** unlocked read does not require authentication and will reveal A and B keys\n"); |
599 | printf(" *** note that unlocked write will attempt to overwrite block 0 including UID\n"); | |
600 | printf(" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n"); | |
533 | printf(" *** note that block 0 write will attempt to overwrite block 0 including UID\n"); | |
534 | printf(" *** block 0 write only works with special Mifare cards (Chinese clones)\n"); | |
601 | 535 | printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n"); |
602 | 536 | printf(" u|U - Use any (u) uid or supply a uid specifically as U01ab23cd.\n"); |
603 | 537 | printf(" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); |
604 | 538 | printf(" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n"); |
605 | 539 | printf(" f - Force using the keyfile even if UID does not match (optional)\n"); |
606 | ||
540 | #ifndef _WIN32 | |
541 | printf(" v - Sends libnfc log output to console (optional)\n"); | |
542 | #endif | |
607 | 543 | printf("Examples: \n\n"); |
608 | 544 | printf(" Read card to file, using key A:\n\n"); |
609 | 545 | printf(" %s r a u mycard.mfd\n\n", pcProgramName); |
619 | 555 | } |
620 | 556 | |
621 | 557 | |
622 | static bool is_directwrite(void) | |
623 | { | |
624 | printf("Checking if Badge is DirectWrite...\n"); | |
625 | ||
626 | // Set default keys | |
627 | memcpy(mtDump.amb[0].mbt.abtKeyA, default_key, sizeof(default_key)); | |
628 | memcpy(mtDump.amb[0].mbt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits)); | |
629 | memcpy(mtDump.amb[0].mbt.abtKeyB, default_key, sizeof(default_key)); | |
630 | ||
631 | // Temporarly override bUseKeyFile | |
632 | bool orig_bUseKeyFile = bUseKeyFile; | |
633 | bUseKeyFile = false; | |
634 | // Try to authenticate for the current sector | |
635 | if (!authenticate(0)) { | |
636 | printf("!\nError: authentication failed for block 0x%02x\n", 0); | |
637 | bUseKeyFile = orig_bUseKeyFile; | |
638 | return false; | |
639 | } | |
640 | // restore bUseKeyFile | |
641 | bUseKeyFile = orig_bUseKeyFile; | |
642 | ||
643 | // Try to read block 0 | |
644 | uint8_t original_b0[16]; | |
645 | if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) { | |
646 | memcpy(original_b0, mp.mpd.abtData, sizeof(mp.mpd.abtData)); | |
647 | printf(" Original Block 0: "); | |
648 | for (int i = 0; i < 16; i++) { | |
649 | printf("%02x", original_b0[i]); | |
650 | } | |
651 | printf("\n"); | |
652 | printf(" Original UID: %02x%02x%02x%02x\n", | |
653 | original_b0[0], original_b0[1], original_b0[2], original_b0[3]); | |
654 | } else { | |
655 | printf("!\nError: unable to read block 0x%02x\n", 0); | |
656 | return false; | |
657 | } | |
658 | ||
659 | printf(" Attempt to write Block 0 ...\n"); | |
660 | memcpy(mp.mpd.abtData, original_b0, sizeof(original_b0)); | |
661 | if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, 0, &mp)) { | |
662 | printf("Failure to write to data block %i\n", 0); | |
663 | return false; | |
664 | } | |
665 | printf(" Block 0 written successfully\n"); | |
666 | ||
667 | return true; | |
668 | } | |
669 | ||
670 | 558 | int |
671 | 559 | main(int argc, const char *argv[]) |
672 | 560 | { |
675 | 563 | uint8_t _tag_uid[4]; |
676 | 564 | uint8_t *tag_uid = _tag_uid; |
677 | 565 | |
678 | int unlock = 0; | |
566 | bool unlock = false; | |
679 | 567 | |
680 | 568 | if (argc < 2) { |
681 | 569 | print_usage(argv[0]); |
690 | 578 | if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) { |
691 | 579 | atAction = ACTION_READ; |
692 | 580 | if (strcmp(command, "R") == 0) |
693 | unlock = 1; | |
581 | unlock = true; | |
694 | 582 | bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; |
695 | 583 | bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); |
696 | bUseKeyFile = (argc > 5); | |
584 | bUseKeyFile = (argc > 5) && strcmp(argv[5], "v"); | |
697 | 585 | bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0)); |
698 | 586 | } else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) { |
699 | 587 | atAction = ACTION_WRITE; |
700 | 588 | if (strcmp(command, "W") == 0) |
701 | unlock = 1; | |
589 | unlock = true; | |
702 | 590 | bFormatCard = (strcmp(command, "f") == 0); |
703 | 591 | bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; |
704 | 592 | bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); |
705 | bUseKeyFile = (argc > 5); | |
593 | bUseKeyFile = (argc > 5) && strcmp(argv[5], "v"); | |
706 | 594 | bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0)); |
707 | 595 | } |
708 | 596 | if (argv[3][0] == 'U') { |
724 | 612 | tag_uid = NULL; |
725 | 613 | } |
726 | 614 | |
615 | #ifndef _WIN32 | |
616 | // Send noise from lib to /dev/null | |
617 | bool verbose = false; | |
618 | if (argv[7]) { | |
619 | if (strcmp(argv[7], "v") == 0) verbose = true; | |
620 | } else { | |
621 | if ((strcmp(argv[6], "v")) || (strcmp(argv[5], "v")) == 0) verbose = true; | |
622 | } | |
623 | if (!verbose) { | |
624 | int fd = open("/dev/null", O_WRONLY); | |
625 | dup2(fd, 2); | |
626 | close(fd); | |
627 | } | |
628 | #endif | |
629 | ||
727 | 630 | if (atAction == ACTION_USAGE) { |
728 | 631 | print_usage(argv[0]); |
729 | 632 | exit(EXIT_FAILURE); |
763 | 666 | exit(EXIT_FAILURE); |
764 | 667 | }; |
765 | 668 | |
669 | // Drop the field for a while, so can be reset | |
670 | if (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true) < 0) { | |
671 | nfc_perror(pnd, "nfc_device_set_property_bool activate field"); | |
672 | nfc_close(pnd); | |
673 | nfc_exit(context); | |
674 | exit(EXIT_FAILURE); | |
675 | } | |
676 | ||
766 | 677 | // Let the reader only try once to find a tag |
767 | 678 | if (nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false) < 0) { |
768 | 679 | nfc_perror(pnd, "nfc_device_set_property_bool"); |
778 | 689 | exit(EXIT_FAILURE); |
779 | 690 | } |
780 | 691 | |
692 | // Configure the CRC and Parity settings | |
693 | if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) { | |
694 | nfc_perror(pnd, "nfc_device_set_property_bool crc"); | |
695 | nfc_close(pnd); | |
696 | nfc_exit(context); | |
697 | exit(EXIT_FAILURE); | |
698 | } | |
699 | if (nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true) < 0) { | |
700 | nfc_perror(pnd, "nfc_device_set_property_bool parity"); | |
701 | nfc_close(pnd); | |
702 | nfc_exit(context); | |
703 | exit(EXIT_FAILURE); | |
704 | } | |
705 | ||
781 | 706 | printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); |
782 | 707 | |
783 | 708 | // Try to find a MIFARE Classic tag |
784 | 709 | int tags; |
785 | ||
786 | 710 | tags = nfc_initiator_select_passive_target(pnd, nmMifare, tag_uid, tag_uid == NULL ? 0 : 4, &nt); |
787 | 711 | if (tags <= 0) { |
788 | 712 | printf("Error: no tag was found\n"); |
791 | 715 | exit(EXIT_FAILURE); |
792 | 716 | } |
793 | 717 | // Test if we are dealing with a MIFARE compatible tag |
794 | if ((nt.nti.nai.btSak & 0x08) == 0) { | |
718 | if (((nt.nti.nai.btSak & 0x08) == 0) && (nt.nti.nai.btSak != 0x01)) { | |
719 | // if ((nt.nti.nai.btSak & 0x08) == 0) { | |
795 | 720 | printf("Warning: tag is probably not a MFC!\n"); |
796 | 721 | } |
797 | 722 | |
838 | 763 | // MIFARE Plus 2K |
839 | 764 | uiBlocks = 0x7f; |
840 | 765 | } |
841 | // Chinese magic emulation card, ATS=0978009102:dabc1910 | |
842 | if ((res == 9) && (abtRx[5] == 0xda) && (abtRx[6] == 0xbc) | |
843 | && (abtRx[7] == 0x19) && (abtRx[8] == 0x10)) { | |
844 | magic2 = true; | |
845 | } | |
846 | 766 | } else |
847 | 767 | printf("RATS support: no\n"); |
848 | 768 | printf("Guessing size: seems to be a %lu-byte card\n", (unsigned long)((uiBlocks + 1) * sizeof(mifare_classic_block))); |
849 | ||
850 | //If size is 4k check for direct-write card | |
851 | if (uiBlocks == 0xff) { | |
852 | if (is_directwrite()) { | |
853 | printf("Card is DirectWrite\n"); | |
854 | magic3 = true; | |
855 | unlock = 0; | |
856 | } else { | |
857 | printf("Card is not DirectWrite\n"); | |
858 | } | |
859 | } | |
860 | ||
861 | //Check to see if we have a One Time Write badge (magic3) | |
862 | if (pbtUID[0] == 0xaa && pbtUID[1] == 0x55 && | |
863 | pbtUID[2] == 0xc3 && pbtUID[3] == 0x96) { | |
864 | printf("Card appears to be a One Time Write Card..\n"); | |
865 | magic3 = true; | |
866 | unlock = 0; | |
867 | } | |
868 | ||
869 | 769 | |
870 | 770 | if (bUseKeyFile) { |
871 | 771 | FILE *pfKeys = fopen(argv[5], "rb"); |
921 | 821 | } |
922 | 822 | printf("Done.\n"); |
923 | 823 | fclose(pfDump); |
824 | } else { | |
825 | nfc_close(pnd); | |
826 | nfc_exit(context); | |
827 | exit(EXIT_FAILURE); | |
924 | 828 | } |
925 | 829 | } else if (atAction == ACTION_WRITE) { |
926 | write_card(unlock); | |
830 | if (!write_card(unlock)) { | |
831 | nfc_close(pnd); | |
832 | nfc_exit(context); | |
833 | exit(EXIT_FAILURE); | |
834 | } | |
927 | 835 | } |
928 | 836 | |
929 | 837 | nfc_close(pnd); |